}
SDNode *getGlobalBaseReg();
- SDNode *Select(SDValue N);
+ SDNode *Select(SDNode *N);
// Complex Pattern.
- bool SelectAddr(SDValue Op, SDValue N,
+ bool SelectAddr(SDNode *Op, SDValue N,
SDValue &Base, SDValue &Offset);
+ SDNode *SelectLoadFp64(SDNode *N);
+ SDNode *SelectStoreFp64(SDNode *N);
// getI32Imm - Return a target constant with the specified
// value, of type i32.
/// ComplexPattern used on MipsInstrInfo
/// Used on Mips Load/Store instructions
bool MipsDAGToDAGISel::
-SelectAddr(SDValue Op, SDValue Addr, SDValue &Offset, SDValue &Base)
+SelectAddr(SDNode *Op, SDValue Addr, SDValue &Offset, SDValue &Base)
{
// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
// on PIC code Load GA
if (TM.getRelocationModel() == Reloc::PIC_) {
if ((Addr.getOpcode() == ISD::TargetGlobalAddress) ||
+ (Addr.getOpcode() == ISD::TargetConstantPool) ||
(Addr.getOpcode() == ISD::TargetJumpTable)){
Base = CurDAG->getRegister(Mips::GP, MVT::i32);
Offset = Addr;
return true;
}
}
+
+ // When loading from constant pools, load the lower address part in
+ // the instruction itself. Example, instead of:
+ // lui $2, %hi($CPI1_0)
+ // addiu $2, $2, %lo($CPI1_0)
+ // lwc1 $f0, 0($2)
+ // Generate:
+ // lui $2, %hi($CPI1_0)
+ // lwc1 $f0, %lo($CPI1_0)($2)
+ if ((Addr.getOperand(0).getOpcode() == MipsISD::Hi ||
+ Addr.getOperand(0).getOpcode() == ISD::LOAD) &&
+ Addr.getOperand(1).getOpcode() == MipsISD::Lo) {
+ SDValue LoVal = Addr.getOperand(1);
+ if (dyn_cast<ConstantPoolSDNode>(LoVal.getOperand(0))) {
+ Base = Addr.getOperand(0);
+ Offset = LoVal.getOperand(0);
+ return true;
+ }
+ }
}
Base = Addr;
return true;
}
+SDNode *MipsDAGToDAGISel::SelectLoadFp64(SDNode *N) {
+ MVT::SimpleValueType NVT =
+ N->getValueType(0).getSimpleVT().SimpleTy;
+
+ if (!Subtarget.isMips1() || NVT != MVT::f64)
+ return NULL;
+
+ if (!Predicate_unindexedload(N) ||
+ !Predicate_load(N))
+ return NULL;
+
+ SDValue Chain = N->getOperand(0);
+ SDValue N1 = N->getOperand(1);
+ SDValue Offset0, Offset1, Base;
+
+ if (!SelectAddr(N, N1, Offset0, Base) ||
+ N1.getValueType() != MVT::i32)
+ return NULL;
+
+ MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1);
+ MemRefs0[0] = cast<MemSDNode>(N)->getMemOperand();
+ DebugLoc dl = N->getDebugLoc();
+
+ // The second load should start after for 4 bytes.
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Offset0))
+ Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32);
+ else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Offset0))
+ Offset1 = CurDAG->getTargetConstantPool(CP->getConstVal(),
+ MVT::i32,
+ CP->getAlignment(),
+ CP->getOffset()+4,
+ CP->getTargetFlags());
+ else
+ return NULL;
+
+ // Choose the offsets depending on the endianess
+ if (TM.getTargetData()->isBigEndian())
+ std::swap(Offset0, Offset1);
+
+ // Instead of:
+ // ldc $f0, X($3)
+ // Generate:
+ // lwc $f0, X($3)
+ // lwc $f1, X+4($3)
+ SDNode *LD0 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32,
+ MVT::Other, Offset0, Base, Chain);
+ SDValue Undef = SDValue(CurDAG->getMachineNode(TargetInstrInfo::IMPLICIT_DEF,
+ dl, NVT), 0);
+ SDValue I0 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPEVEN, dl,
+ MVT::f64, Undef, SDValue(LD0, 0));
+
+ SDNode *LD1 = CurDAG->getMachineNode(Mips::LWC1, dl, MVT::f32,
+ MVT::Other, Offset1, Base, SDValue(LD0, 1));
+ SDValue I1 = CurDAG->getTargetInsertSubreg(Mips::SUBREG_FPODD, dl,
+ MVT::f64, I0, SDValue(LD1, 0));
+
+ ReplaceUses(SDValue(N, 0), I1);
+ ReplaceUses(SDValue(N, 1), Chain);
+ cast<MachineSDNode>(LD0)->setMemRefs(MemRefs0, MemRefs0 + 1);
+ cast<MachineSDNode>(LD1)->setMemRefs(MemRefs0, MemRefs0 + 1);
+ return I1.getNode();
+}
+
+SDNode *MipsDAGToDAGISel::SelectStoreFp64(SDNode *N) {
+
+ if (!Subtarget.isMips1() ||
+ N->getOperand(1).getValueType() != MVT::f64)
+ return NULL;
+
+ SDValue Chain = N->getOperand(0);
+
+ if (!Predicate_unindexedstore(N) ||
+ !Predicate_store(N))
+ return NULL;
+
+ SDValue N1 = N->getOperand(1);
+ SDValue N2 = N->getOperand(2);
+ SDValue Offset0, Offset1, Base;
+
+ if (!SelectAddr(N, N2, Offset0, Base) ||
+ N1.getValueType() != MVT::f64 ||
+ N2.getValueType() != MVT::i32)
+ return NULL;
+
+ MachineSDNode::mmo_iterator MemRefs0 = MF->allocateMemRefsArray(1);
+ MemRefs0[0] = cast<MemSDNode>(N)->getMemOperand();
+ DebugLoc dl = N->getDebugLoc();
+
+ // Get the even and odd part from the f64 register
+ SDValue FPOdd = CurDAG->getTargetExtractSubreg(Mips::SUBREG_FPODD,
+ dl, MVT::f32, N1);
+ SDValue FPEven = CurDAG->getTargetExtractSubreg(Mips::SUBREG_FPEVEN,
+ dl, MVT::f32, N1);
+
+ // The second store should start after for 4 bytes.
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Offset0))
+ Offset1 = CurDAG->getTargetConstant(C->getSExtValue()+4, MVT::i32);
+ else
+ return NULL;
+
+ // Choose the offsets depending on the endianess
+ if (TM.getTargetData()->isBigEndian())
+ std::swap(Offset0, Offset1);
+
+ // Instead of:
+ // sdc $f0, X($3)
+ // Generate:
+ // swc $f0, X($3)
+ // swc $f1, X+4($3)
+ SDValue Ops0[] = { FPEven, Offset0, Base, Chain };
+ Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl,
+ MVT::Other, Ops0, 4), 0);
+ cast<MachineSDNode>(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1);
+
+ SDValue Ops1[] = { FPOdd, Offset1, Base, Chain };
+ Chain = SDValue(CurDAG->getMachineNode(Mips::SWC1, dl,
+ MVT::Other, Ops1, 4), 0);
+ cast<MachineSDNode>(Chain.getNode())->setMemRefs(MemRefs0, MemRefs0 + 1);
+
+ ReplaceUses(SDValue(N, 0), Chain);
+ return Chain.getNode();
+}
+
/// Select instructions not customized! Used for
/// expanded, promoted and normal instructions
-SDNode* MipsDAGToDAGISel::Select(SDValue N) {
- SDNode *Node = N.getNode();
+SDNode* MipsDAGToDAGISel::Select(SDNode *Node) {
unsigned Opcode = Node->getOpcode();
DebugLoc dl = Node->getDebugLoc();
SDNode *AddCarry = CurDAG->getMachineNode(Mips::ADDu, dl, VT,
SDValue(Carry,0), RHS);
- return CurDAG->SelectNodeTo(N.getNode(), MOp, VT, MVT::Flag,
+ return CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Flag,
LHS, SDValue(AddCarry,0));
}
InFlag = SDValue(Lo,1);
SDNode *Hi = CurDAG->getMachineNode(Mips::MFHI, dl, MVT::i32, InFlag);
- if (!N.getValue(0).use_empty())
- ReplaceUses(N.getValue(0), SDValue(Lo,0));
+ if (!SDValue(Node, 0).use_empty())
+ ReplaceUses(SDValue(Node, 0), SDValue(Lo,0));
- if (!N.getValue(1).use_empty())
- ReplaceUses(N.getValue(1), SDValue(Hi,0));
+ if (!SDValue(Node, 1).use_empty())
+ ReplaceUses(SDValue(Node, 1), SDValue(Hi,0));
return NULL;
}
case ISD::GLOBAL_OFFSET_TABLE:
return getGlobalBaseReg();
+ case ISD::ConstantFP: {
+ ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node);
+ if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) {
+ SDValue Zero = CurDAG->getRegister(Mips::ZERO, MVT::i32);
+ ReplaceUses(SDValue(Node, 0), Zero);
+ return Zero.getNode();
+ }
+ break;
+ }
+
+ case ISD::LOAD:
+ if (SDNode *ResNode = SelectLoadFp64(Node))
+ return ResNode;
+ // Other cases are autogenerated.
+ break;
+
+ case ISD::STORE:
+ if (SDNode *ResNode = SelectStoreFp64(Node))
+ return ResNode;
+ // Other cases are autogenerated.
+ break;
+
/// Handle direct and indirect calls when using PIC. On PIC, when
/// GOT is smaller than about 64k (small code) the GA target is
/// loaded with only one instruction. Otherwise GA's target must
}
// Select the default instruction
- SDNode *ResNode = SelectCode(N);
+ SDNode *ResNode = SelectCode(Node);
DEBUG(errs().indent(Indent-2) << "=> ");
- if (ResNode == NULL || ResNode == N.getNode())
- DEBUG(N.getNode()->dump(CurDAG));
+ if (ResNode == NULL || ResNode == Node)
+ DEBUG(Node->dump(CurDAG));
else
DEBUG(ResNode->dump(CurDAG));
DEBUG(errs() << "\n");