- Start moving target-dependent nodes that could be represented by an
instruction sequence and cannot ordinarily be simplified by DAGcombine
into the various target description files or SPUDAGToDAGISel.cpp.
This makes some 64-bit operations legal.
- Eliminate target-dependent ISD enums.
- Update tests.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@61508 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/CellSPU/SPUISelDAGToDAG.cpp b/lib/Target/CellSPU/SPUISelDAGToDAG.cpp
index f51aba2..76b2284 100644
--- a/lib/Target/CellSPU/SPUISelDAGToDAG.cpp
+++ b/lib/Target/CellSPU/SPUISelDAGToDAG.cpp
@@ -149,7 +149,7 @@
}
bool
- isHighLow(const SDValue &Op)
+ isHighLow(const SDValue &Op)
{
return (Op.getOpcode() == SPUISD::IndirectAddr
&& ((Op.getOperand(0).getOpcode() == SPUISD::Hi
@@ -229,14 +229,14 @@
TM(tm),
SPUtli(*tm.getTargetLowering())
{}
-
+
virtual bool runOnFunction(Function &Fn) {
// Make sure we re-emit a set of the global base reg if necessary
GlobalBaseReg = 0;
SelectionDAGISel::runOnFunction(Fn);
return true;
}
-
+
/// getI32Imm - Return a target constant with the specified value, of type
/// i32.
inline SDValue getI32Imm(uint32_t Imm) {
@@ -248,7 +248,7 @@
inline SDValue getI64Imm(uint64_t Imm) {
return CurDAG->getTargetConstant(Imm, MVT::i64);
}
-
+
/// getSmallIPtrImm - Return a target constant of pointer type.
inline SDValue getSmallIPtrImm(unsigned Imm) {
return CurDAG->getTargetConstant(Imm, SPUtli.getPointerTy());
@@ -258,6 +258,15 @@
/// target-specific node if it hasn't already been changed.
SDNode *Select(SDValue Op);
+ //! Emit the instruction sequence for i64 shl
+ SDNode *SelectSHLi64(SDValue &Op, MVT OpVT);
+
+ //! Emit the instruction sequence for i64 srl
+ SDNode *SelectSRLi64(SDValue &Op, MVT OpVT);
+
+ //! Emit the instruction sequence for i64 sra
+ SDNode *SelectSRAi64(SDValue &Op, MVT OpVT);
+
//! Returns true if the address N is an A-form (local store) address
bool SelectAFormAddr(SDValue Op, SDValue N, SDValue &Base,
SDValue &Index);
@@ -287,7 +296,7 @@
switch (ConstraintCode) {
default: return true;
case 'm': // memory
- if (!SelectDFormAddr(Op, Op, Op0, Op1)
+ if (!SelectDFormAddr(Op, Op, Op0, Op1)
&& !SelectAFormAddr(Op, Op, Op0, Op1))
SelectXFormAddr(Op, Op, Op0, Op1);
break;
@@ -306,7 +315,7 @@
#endif
break;
}
-
+
OutOps.push_back(Op0);
OutOps.push_back(Op1);
return false;
@@ -318,14 +327,14 @@
virtual const char *getPassName() const {
return "Cell SPU DAG->DAG Pattern Instruction Selection";
- }
-
+ }
+
/// CreateTargetHazardRecognizer - Return the hazard recognizer to use for
/// this target when scheduling the DAG.
virtual HazardRecognizer *CreateTargetHazardRecognizer() {
const TargetInstrInfo *II = TM.getInstrInfo();
assert(II && "No InstrInfo?");
- return new SPUHazardRecognizer(*II);
+ return new SPUHazardRecognizer(*II);
}
// Include the pieces autogenerated from the target description.
@@ -375,7 +384,7 @@
abort();
/*NOTREACHED*/
- case SPUISD::AFormAddr:
+ case SPUISD::AFormAddr:
// Just load from memory if there's only a single use of the location,
// otherwise, this will get handled below with D-form offset addresses
if (N.hasOneUse()) {
@@ -404,7 +413,7 @@
return false;
}
-bool
+bool
SPUDAGToDAGISel::SelectDForm2Addr(SDValue Op, SDValue N, SDValue &Disp,
SDValue &Base) {
const int minDForm2Offset = -(1 << 7);
@@ -527,7 +536,7 @@
ConstantSDNode *CN = cast<ConstantSDNode>(Op0);
offset = int32_t(CN->getSExtValue());
idxOp = Op1;
- }
+ }
if (offset >= minOffset && offset <= maxOffset) {
Base = CurDAG->getTargetConstant(offset, PtrTy);
@@ -622,27 +631,20 @@
if (N->isMachineOpcode()) {
return NULL; // Already selected.
} else if (Opc == ISD::FrameIndex) {
- // Selects to (add $sp, FI * stackSlotSize)
- int FI =
- SPUFrameInfo::FItoStackOffset(cast<FrameIndexSDNode>(N)->getIndex());
- MVT PtrVT = SPUtli.getPointerTy();
+ int FI = cast<FrameIndexSDNode>(N)->getIndex();
+ SDValue TFI = CurDAG->getTargetFrameIndex(FI, Op.getValueType());
+ SDValue Imm0 = CurDAG->getTargetConstant(0, Op.getValueType());
- // Adjust stack slot to actual offset in frame:
- if (isS10Constant(FI)) {
- DEBUG(cerr << "SPUDAGToDAGISel: Replacing FrameIndex with AIr32 $sp, "
- << FI
- << "\n");
+ if (FI < 128) {
NewOpc = SPU::AIr32;
- Ops[0] = CurDAG->getRegister(SPU::R1, PtrVT);
- Ops[1] = CurDAG->getTargetConstant(FI, PtrVT);
+ Ops[0] = TFI;
+ Ops[1] = Imm0;
n_ops = 2;
} else {
- DEBUG(cerr << "SPUDAGToDAGISel: Replacing FrameIndex with Ar32 $sp, "
- << FI
- << "\n");
NewOpc = SPU::Ar32;
- Ops[0] = CurDAG->getRegister(SPU::R1, PtrVT);
- Ops[1] = CurDAG->getConstant(FI, PtrVT);
+ Ops[0] = CurDAG->getRegister(SPU::R1, Op.getValueType());
+ Ops[1] = SDValue(CurDAG->getTargetNode(SPU::ILAr32, Op.getValueType(),
+ TFI, Imm0), 0);
n_ops = 2;
}
} else if (Opc == ISD::ZERO_EXTEND) {
@@ -661,6 +663,18 @@
n_ops = 2;
}
}
+ } else if (Opc == ISD::SHL) {
+ if (OpVT == MVT::i64) {
+ return SelectSHLi64(Op, OpVT);
+ }
+ } else if (Opc == ISD::SRL) {
+ if (OpVT == MVT::i64) {
+ return SelectSRLi64(Op, OpVT);
+ }
+ } else if (Opc == ISD::SRA) {
+ if (OpVT == MVT::i64) {
+ return SelectSRAi64(Op, OpVT);
+ }
} else if (Opc == SPUISD::LDRESULT) {
// Custom select instructions for LDRESULT
MVT VT = N->getValueType(0);
@@ -713,7 +727,7 @@
n_ops = 2;
}
}
-
+
if (n_ops > 0) {
if (N->hasOneUse())
return CurDAG->SelectNodeTo(N, NewOpc, OpVT, Ops, n_ops);
@@ -723,7 +737,213 @@
return SelectCode(Op);
}
-/// createPPCISelDag - This pass converts a legalized DAG into a
+/*!
+ * Emit the instruction sequence for i64 left shifts. The basic algorithm
+ * is to fill the bottom two word slots with zeros so that zeros are shifted
+ * in as the entire quadword is shifted left.
+ *
+ * \note This code could also be used to implement v2i64 shl.
+ *
+ * @param Op The shl operand
+ * @param OpVT Op's machine value value type (doesn't need to be passed, but
+ * makes life easier.)
+ * @return The SDNode with the entire instruction sequence
+ */
+SDNode *
+SPUDAGToDAGISel::SelectSHLi64(SDValue &Op, MVT OpVT) {
+ SDValue Op0 = Op.getOperand(0);
+ MVT VecVT = MVT::getVectorVT(OpVT, (128 / OpVT.getSizeInBits()));
+ SDValue ShiftAmt = Op.getOperand(1);
+ MVT ShiftAmtVT = ShiftAmt.getValueType();
+ SDNode *VecOp0, *SelMask, *ZeroFill, *Shift = 0;
+ SDValue SelMaskVal;
+
+ VecOp0 = CurDAG->getTargetNode(SPU::ORv2i64_i64, VecVT, Op0);
+ SelMaskVal = CurDAG->getTargetConstant(0xff00ULL, MVT::i16);
+ SelMask = CurDAG->getTargetNode(SPU::FSMBIv2i64, VecVT, SelMaskVal);
+ ZeroFill = CurDAG->getTargetNode(SPU::ILv2i64, VecVT,
+ CurDAG->getTargetConstant(0, OpVT));
+ VecOp0 = CurDAG->getTargetNode(SPU::SELBv2i64, VecVT,
+ SDValue(ZeroFill, 0),
+ SDValue(VecOp0, 0),
+ SDValue(SelMask, 0));
+
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(ShiftAmt)) {
+ unsigned bytes = unsigned(CN->getZExtValue()) >> 3;
+ unsigned bits = unsigned(CN->getZExtValue()) & 7;
+
+ if (bytes > 0) {
+ Shift =
+ CurDAG->getTargetNode(SPU::SHLQBYIv2i64, VecVT,
+ SDValue(VecOp0, 0),
+ CurDAG->getTargetConstant(bytes, ShiftAmtVT));
+ }
+
+ if (bits > 0) {
+ Shift =
+ CurDAG->getTargetNode(SPU::SHLQBIIv2i64, VecVT,
+ SDValue((Shift != 0 ? Shift : VecOp0), 0),
+ CurDAG->getTargetConstant(bits, ShiftAmtVT));
+ }
+ } else {
+ SDNode *Bytes =
+ CurDAG->getTargetNode(SPU::ROTMIr32, ShiftAmtVT,
+ ShiftAmt,
+ CurDAG->getTargetConstant(3, ShiftAmtVT));
+ SDNode *Bits =
+ CurDAG->getTargetNode(SPU::ANDIr32, ShiftAmtVT,
+ ShiftAmt,
+ CurDAG->getTargetConstant(7, ShiftAmtVT));
+ Shift =
+ CurDAG->getTargetNode(SPU::SHLQBYv2i64, VecVT,
+ SDValue(VecOp0, 0), SDValue(Bytes, 0));
+ Shift =
+ CurDAG->getTargetNode(SPU::SHLQBIv2i64, VecVT,
+ SDValue(Shift, 0), SDValue(Bits, 0));
+ }
+
+ return CurDAG->getTargetNode(SPU::ORi64_v2i64, OpVT, SDValue(Shift, 0));
+}
+
+/*!
+ * Emit the instruction sequence for i64 logical right shifts.
+ *
+ * @param Op The shl operand
+ * @param OpVT Op's machine value value type (doesn't need to be passed, but
+ * makes life easier.)
+ * @return The SDNode with the entire instruction sequence
+ */
+SDNode *
+SPUDAGToDAGISel::SelectSRLi64(SDValue &Op, MVT OpVT) {
+ SDValue Op0 = Op.getOperand(0);
+ MVT VecVT = MVT::getVectorVT(OpVT, (128 / OpVT.getSizeInBits()));
+ SDValue ShiftAmt = Op.getOperand(1);
+ MVT ShiftAmtVT = ShiftAmt.getValueType();
+ SDNode *VecOp0, *Shift = 0;
+
+ VecOp0 = CurDAG->getTargetNode(SPU::ORv2i64_i64, VecVT, Op0);
+
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(ShiftAmt)) {
+ unsigned bytes = unsigned(CN->getZExtValue()) >> 3;
+ unsigned bits = unsigned(CN->getZExtValue()) & 7;
+
+ if (bytes > 0) {
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQMBYIv2i64, VecVT,
+ SDValue(VecOp0, 0),
+ CurDAG->getTargetConstant(bytes, ShiftAmtVT));
+ }
+
+ if (bits > 0) {
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQMBIIv2i64, VecVT,
+ SDValue((Shift != 0 ? Shift : VecOp0), 0),
+ CurDAG->getTargetConstant(bits, ShiftAmtVT));
+ }
+ } else {
+ SDNode *Bytes =
+ CurDAG->getTargetNode(SPU::ROTMIr32, ShiftAmtVT,
+ ShiftAmt,
+ CurDAG->getTargetConstant(3, ShiftAmtVT));
+ SDNode *Bits =
+ CurDAG->getTargetNode(SPU::ANDIr32, ShiftAmtVT,
+ ShiftAmt,
+ CurDAG->getTargetConstant(7, ShiftAmtVT));
+
+ // Ensure that the shift amounts are negated!
+ Bytes = CurDAG->getTargetNode(SPU::SFIr32, ShiftAmtVT,
+ SDValue(Bytes, 0),
+ CurDAG->getTargetConstant(0, ShiftAmtVT));
+
+ Bits = CurDAG->getTargetNode(SPU::SFIr32, ShiftAmtVT,
+ SDValue(Bits, 0),
+ CurDAG->getTargetConstant(0, ShiftAmtVT));
+
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQMBYv2i64, VecVT,
+ SDValue(VecOp0, 0), SDValue(Bytes, 0));
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQMBIv2i64, VecVT,
+ SDValue(Shift, 0), SDValue(Bits, 0));
+ }
+
+ return CurDAG->getTargetNode(SPU::ORi64_v2i64, OpVT, SDValue(Shift, 0));
+}
+
+/*!
+ * Emit the instruction sequence for i64 arithmetic right shifts.
+ *
+ * @param Op The shl operand
+ * @param OpVT Op's machine value value type (doesn't need to be passed, but
+ * makes life easier.)
+ * @return The SDNode with the entire instruction sequence
+ */
+SDNode *
+SPUDAGToDAGISel::SelectSRAi64(SDValue &Op, MVT OpVT) {
+ // Promote Op0 to vector
+ MVT VecVT = MVT::getVectorVT(OpVT, (128 / OpVT.getSizeInBits()));
+ SDValue ShiftAmt = Op.getOperand(1);
+ MVT ShiftAmtVT = ShiftAmt.getValueType();
+
+ SDNode *VecOp0 =
+ CurDAG->getTargetNode(SPU::ORv2i64_i64, VecVT, Op.getOperand(0));
+
+ SDValue SignRotAmt = CurDAG->getTargetConstant(31, ShiftAmtVT);
+ SDNode *SignRot =
+ CurDAG->getTargetNode(SPU::ROTMAIv2i64_i32, MVT::v2i64,
+ SDValue(VecOp0, 0), SignRotAmt);
+ SDNode *UpperHalfSign =
+ CurDAG->getTargetNode(SPU::ORi32_v4i32, MVT::i32, SDValue(SignRot, 0));
+
+ SDNode *UpperHalfSignMask =
+ CurDAG->getTargetNode(SPU::FSM64r32, VecVT, SDValue(UpperHalfSign, 0));
+ SDNode *UpperLowerMask =
+ CurDAG->getTargetNode(SPU::FSMBIv2i64, VecVT,
+ CurDAG->getTargetConstant(0xff00ULL, MVT::i16));
+ SDNode *UpperLowerSelect =
+ CurDAG->getTargetNode(SPU::SELBv2i64, VecVT,
+ SDValue(UpperHalfSignMask, 0),
+ SDValue(VecOp0, 0),
+ SDValue(UpperLowerMask, 0));
+
+ SDNode *Shift = 0;
+
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(ShiftAmt)) {
+ unsigned bytes = unsigned(CN->getZExtValue()) >> 3;
+ unsigned bits = unsigned(CN->getZExtValue()) & 7;
+
+ if (bytes > 0) {
+ bytes = 31 - bytes;
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQBYIv2i64, VecVT,
+ SDValue(UpperLowerSelect, 0),
+ CurDAG->getTargetConstant(bytes, ShiftAmtVT));
+ }
+
+ if (bits > 0) {
+ bits = 8 - bits;
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQBIIv2i64, VecVT,
+ SDValue((Shift != 0 ? Shift : UpperLowerSelect), 0),
+ CurDAG->getTargetConstant(bits, ShiftAmtVT));
+ }
+ } else {
+ SDNode *NegShift =
+ CurDAG->getTargetNode(SPU::SFIr32, ShiftAmtVT,
+ ShiftAmt, CurDAG->getTargetConstant(0, ShiftAmtVT));
+
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQBYBIv2i64_r32, VecVT,
+ SDValue(UpperLowerSelect, 0), SDValue(NegShift, 0));
+ Shift =
+ CurDAG->getTargetNode(SPU::ROTQBIv2i64, VecVT,
+ SDValue(Shift, 0), SDValue(NegShift, 0));
+ }
+
+ return CurDAG->getTargetNode(SPU::ORi64_v2i64, OpVT, SDValue(Shift, 0));
+}
+
+/// createSPUISelDag - This pass converts a legalized DAG into a
/// SPU-specific DAG, ready for instruction scheduling.
///
FunctionPass *llvm::createSPUISelDag(SPUTargetMachine &TM) {