diff options
| author | Scott Michel <scottm@aero.org> | 2009-08-24 22:28:53 +0000 |
|---|---|---|
| committer | Scott Michel <scottm@aero.org> | 2009-08-24 22:28:53 +0000 |
| commit | 8d1602af864c2ea820ef95b2fbd9638e3473ae30 (patch) | |
| tree | d546b6db0cf842004d7adb93f75e56fe7834f471 /llvm/lib/Target/CellSPU/SPUISelDAGToDAG.cpp | |
| parent | a6b4a3d646319636cf6be0b291e7172fe60b4cb5 (diff) | |
| download | bcm5719-llvm-8d1602af864c2ea820ef95b2fbd9638e3473ae30.tar.gz bcm5719-llvm-8d1602af864c2ea820ef95b2fbd9638e3473ae30.zip | |
128-bit sign extension and vector shift cleanups, contributed by Ken Werner
(IBM).
llvm-svn: 79949
Diffstat (limited to 'llvm/lib/Target/CellSPU/SPUISelDAGToDAG.cpp')
| -rw-r--r-- | llvm/lib/Target/CellSPU/SPUISelDAGToDAG.cpp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/llvm/lib/Target/CellSPU/SPUISelDAGToDAG.cpp b/llvm/lib/Target/CellSPU/SPUISelDAGToDAG.cpp index 1c5e739ef84..8b418a08cbe 100644 --- a/llvm/lib/Target/CellSPU/SPUISelDAGToDAG.cpp +++ b/llvm/lib/Target/CellSPU/SPUISelDAGToDAG.cpp @@ -322,6 +322,9 @@ namespace { /// target-specific node if it hasn't already been changed. SDNode *Select(SDValue Op); + //! Emit the instruction sequence for i128 sext + SDNode *SelectSEXTi128(SDValue &Op, EVT OpVT); + //! Emit the instruction sequence for i64 shl SDNode *SelectSHLi64(SDValue &Op, EVT OpVT); @@ -833,6 +836,10 @@ SPUDAGToDAGISel::Select(SDValue Op) { } } } + } else if (Opc == ISD::SIGN_EXTEND) { + if (OpVT == MVT::i128) { + return SelectSEXTi128(Op, OpVT); + } } else if (Opc == ISD::SHL) { if (OpVT == MVT::i64) { return SelectSHLi64(Op, OpVT); @@ -957,6 +964,58 @@ SPUDAGToDAGISel::Select(SDValue Op) { } /*! + * Emit the instruction sequence for i64 -> i128 sign extend. The basic + * algorithm is to duplicate the sign bit using rotmai to generate at + * least one byte full of sign bits. Then propagate the "sign-byte" into + * theleftmost words and the i64 into the rightmost words using shufb. + * + * @param Op The sext operand + * @param OpVT The type to extend to + * @return The SDNode with the entire instruction sequence + */ +SDNode * +SPUDAGToDAGISel::SelectSEXTi128(SDValue &Op, EVT OpVT) +{ + DebugLoc dl = Op.getDebugLoc(); + + // Type to extend from + SDValue Op0 = Op.getOperand(0); + EVT Op0VT = Op0.getValueType(); + + assert((OpVT == MVT::i128 && Op0VT == MVT::i64) && + "LowerSIGN_EXTEND: input and/or output operand have wrong size"); + + // Create shuffle mask + unsigned mask1 = 0x10101010; // byte 0 - 3 and 4 - 7 + unsigned mask2 = 0x01020304; // byte 8 - 11 + unsigned mask3 = 0x05060708; // byte 12 - 15 + SDValue shufMask = CurDAG->getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, + CurDAG->getConstant(mask1, MVT::i32), + CurDAG->getConstant(mask1, MVT::i32), + CurDAG->getConstant(mask2, MVT::i32), + CurDAG->getConstant(mask3, MVT::i32)); + SDNode *shufMaskLoad = emitBuildVector(shufMask); + + // Word wise arithmetic right shift to generate at least one byte + // that contains sign bits. + SDNode *PromoteScalar = SelectCode(CurDAG->getNode(SPUISD::PREFSLOT2VEC, dl, + MVT::v2i64, Op0, Op0)); + SDNode *sraVal = SelectCode(CurDAG->getNode(ISD::SRA, dl, MVT::v2i64, + SDValue(PromoteScalar, 0), + CurDAG->getConstant(31, MVT::i32))); + + // Shuffle bytes - Copy the sign bits into the upper 64 bits + // and the input value into the lower 64 bits. + SDNode *extShuffle = SelectCode(CurDAG->getNode(SPUISD::SHUFB, dl, + MVT::v2i64, Op0, + SDValue(sraVal, 0), + SDValue(shufMaskLoad, 0))); + + return SelectCode(CurDAG->getNode(ISD::BIT_CONVERT, dl, MVT::i128, + SDValue(extShuffle, 0))); +} + +/*! * 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. |

