diff options
author | Daniel Sanders <daniel.sanders@imgtec.com> | 2013-11-15 12:56:49 +0000 |
---|---|---|
committer | Daniel Sanders <daniel.sanders@imgtec.com> | 2013-11-15 12:56:49 +0000 |
commit | ea28aafa83fc2b6dd632041278c9a18e5a2b2b41 (patch) | |
tree | dc86c580e1a9b669264065be2c0fa94ca4da0d02 /lib/Target | |
parent | 4d748eb0e4b55262619305c96a89c55c30bffe6c (diff) | |
download | llvm-ea28aafa83fc2b6dd632041278c9a18e5a2b2b41.tar.gz llvm-ea28aafa83fc2b6dd632041278c9a18e5a2b2b41.tar.bz2 llvm-ea28aafa83fc2b6dd632041278c9a18e5a2b2b41.tar.xz |
Fix illegal DAG produced by SelectionDAG::getConstant() for v2i64 type
Summary:
When getConstant() is called for an expanded vector type, it is split into
multiple scalar constants which are then combined using appropriate build_vector
and bitcast operations.
In addition to the usual big/little endian differences, the case where the
element-order of the vector does not have the same endianness as the elements
themselves is also accounted for. For example, for v4i32 on big-endian MIPS,
the byte-order of the vector is <3210,7654,BA98,FEDC>. For little-endian, it is
<0123,4567,89AB,CDEF>.
Handling this case turns out to be a nop since getConstant() returns a splatted
vector (so reversing the element order doesn't change the value)
This fixes a number of cases in MIPS MSA where calling getConstant() during
operation legalization introduces illegal types (e.g. to legalize v2i64 UNDEF
into a v2i64 BUILD_VECTOR of illegal i64 zeros). It should also handle bigger
differences between illegal and legal types such as legalizing v2i64 into v8i16.
lowerMSASplatImm() in the MIPS backend no longer needs to avoid calling
getConstant() so this function has been updated in the same patch.
For the sake of transparency, the steps I've taken since the review are:
* Added 'virtual' to isVectorEltOrderLittleEndian() as requested. This revealed
that the MIPS tests were falsely passing because a polymorphic function was
not actually polymorphic in the reviewed patch.
* Fixed the tests that were now failing. This involved deleting the code to
handle the MIPS MSA element-order (which was previously doing an byte-order
swap instead of an element-order swap). This left
isVectorEltOrderLittleEndian() unused and it was deleted.
* Fixed build failures caused by rebasing beyond r194467-r194472. These build
failures involved the bset, bneg, and bclr instructions added in these commits
using lowerMSASplatImm() in a way that was no longer valid after this patch.
Some of these were fixed by calling SelectionDAG::getConstant() instead,
others were fixed by a new function getBuildVectorSplat() that provided the
removed functionality of lowerMSASplatImm() in a more sensible way.
Reviewers: bkramer
Reviewed By: bkramer
CC: llvm-commits
Differential Revision: http://llvm-reviews.chandlerc.com/D1973
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@194811 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target')
-rw-r--r-- | lib/Target/Mips/MipsSEISelLowering.cpp | 150 |
1 files changed, 91 insertions, 59 deletions
diff --git a/lib/Target/Mips/MipsSEISelLowering.cpp b/lib/Target/Mips/MipsSEISelLowering.cpp index 9585efb272..e2ea629d95 100644 --- a/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/lib/Target/Mips/MipsSEISelLowering.cpp @@ -1254,38 +1254,73 @@ static SDValue lowerMSACopyIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { return Result; } -static SDValue -lowerMSASplatImm(SDLoc DL, EVT ResTy, SDValue ImmOp, SelectionDAG &DAG) { - EVT ViaVecTy = ResTy; - SmallVector<SDValue, 16> Ops; - SDValue ImmHiOp; - - if (ViaVecTy == MVT::v2i64) { - ImmHiOp = DAG.getNode(ISD::SRA, DL, MVT::i32, ImmOp, - DAG.getConstant(31, MVT::i32)); - for (unsigned i = 0; i < ViaVecTy.getVectorNumElements(); ++i) { - Ops.push_back(ImmHiOp); - Ops.push_back(ImmOp); - } +static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) { + EVT ResVecTy = Op->getValueType(0); + EVT ViaVecTy = ResVecTy; + SDLoc DL(Op); + + // When ResVecTy == MVT::v2i64, LaneA is the upper 32 bits of the lane and + // LaneB is the lower 32-bits. Otherwise LaneA and LaneB are alternating + // lanes. + SDValue LaneA; + SDValue LaneB = Op->getOperand(2); + + if (ResVecTy == MVT::v2i64) { + LaneA = DAG.getConstant(0, MVT::i32); ViaVecTy = MVT::v4i32; - } else { - for (unsigned i = 0; i < ResTy.getVectorNumElements(); ++i) - Ops.push_back(ImmOp); - } + } else + LaneA = LaneB; - SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, &Ops[0], - Ops.size()); + SDValue Ops[16] = { LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, + LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB }; - if (ResTy != ViaVecTy) - Result = DAG.getNode(ISD::BITCAST, DL, ResTy, Result); + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, Ops, + ViaVecTy.getVectorNumElements()); + + if (ViaVecTy != ResVecTy) + Result = DAG.getNode(ISD::BITCAST, DL, ResVecTy, Result); return Result; } -static SDValue -lowerMSASplatImm(SDValue Op, unsigned ImmOp, SelectionDAG &DAG) { - return lowerMSASplatImm(SDLoc(Op), Op->getValueType(0), - Op->getOperand(ImmOp), DAG); +static SDValue lowerMSASplatImm(SDValue Op, unsigned ImmOp, SelectionDAG &DAG) { + return DAG.getConstant(Op->getConstantOperandVal(ImmOp), Op->getValueType(0)); +} + +static SDValue getBuildVectorSplat(EVT VecTy, SDValue SplatValue, + bool BigEndian, SelectionDAG &DAG) { + EVT ViaVecTy = VecTy; + SDValue SplatValueA = SplatValue; + SDValue SplatValueB = SplatValue; + SDLoc DL(SplatValue); + + if (VecTy == MVT::v2i64) { + // v2i64 BUILD_VECTOR must be performed via v4i32 so split into i32's. + ViaVecTy = MVT::v4i32; + + SplatValueA = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValue); + SplatValueB = DAG.getNode(ISD::SRL, DL, MVT::i64, SplatValue, + DAG.getConstant(32, MVT::i32)); + SplatValueB = DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, SplatValueB); + } + + // We currently hold the parts in little endian order. Swap them if + // necessary. + if (BigEndian) + std::swap(SplatValueA, SplatValueB); + + SDValue Ops[16] = { SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB, + SplatValueA, SplatValueB, SplatValueA, SplatValueB }; + + SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, DL, ViaVecTy, Ops, + ViaVecTy.getVectorNumElements()); + + if (VecTy != ViaVecTy) + Result = DAG.getNode(ISD::BITCAST, DL, VecTy, Result); + + return Result; } static SDValue lowerMSABinaryBitImmIntr(SDValue Op, SelectionDAG &DAG, @@ -1295,27 +1330,37 @@ static SDValue lowerMSABinaryBitImmIntr(SDValue Op, SelectionDAG &DAG, SDValue Exp2Imm; SDLoc DL(Op); - // The DAG Combiner can't constant fold bitcasted vectors so we must do it - // here. + // The DAG Combiner can't constant fold bitcasted vectors yet so we must do it + // here for now. if (VecTy == MVT::v2i64) { if (ConstantSDNode *CImm = dyn_cast<ConstantSDNode>(Imm)) { APInt BitImm = APInt(64, 1) << CImm->getAPIntValue(); SDValue BitImmHiOp = DAG.getConstant(BitImm.lshr(32).trunc(32), MVT::i32); - SDValue BitImmOp = DAG.getConstant(BitImm.trunc(32), MVT::i32); - Exp2Imm = DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, - DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v4i32, - BitImmHiOp, BitImmOp, - BitImmHiOp, BitImmOp)); + SDValue BitImmLoOp = DAG.getConstant(BitImm.trunc(32), MVT::i32); + + if (BigEndian) + std::swap(BitImmLoOp, BitImmHiOp); + + Exp2Imm = + DAG.getNode(ISD::BITCAST, DL, MVT::v2i64, + DAG.getNode(ISD::BUILD_VECTOR, DL, MVT::v4i32, BitImmLoOp, + BitImmHiOp, BitImmLoOp, BitImmHiOp)); } } if (Exp2Imm.getNode() == NULL) { // We couldnt constant fold, do a vector shift instead - SDValue One = lowerMSASplatImm(DL, VecTy, DAG.getConstant(1, MVT::i32), - DAG); - Exp2Imm = lowerMSASplatImm(DL, VecTy, Imm, DAG); - Exp2Imm = DAG.getNode(ISD::SHL, DL, VecTy, One, Exp2Imm); + + // Extend i32 to i64 if necessary. Sign or zero extend doesn't matter since + // only values 0-63 are valid. + if (VecTy == MVT::v2i64) + Imm = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, Imm); + + Exp2Imm = getBuildVectorSplat(VecTy, Imm, BigEndian, DAG); + + Exp2Imm = + DAG.getNode(ISD::SHL, DL, VecTy, DAG.getConstant(1, VecTy), Exp2Imm); } return DAG.getNode(Opc, DL, VecTy, Op->getOperand(1), Exp2Imm); @@ -1325,7 +1370,7 @@ static SDValue lowerMSABitClear(SDValue Op, SelectionDAG &DAG) { EVT ResTy = Op->getValueType(0); EVT ViaVecTy = ResTy == MVT::v2i64 ? MVT::v4i32 : ResTy; SDLoc DL(Op); - SDValue One = lowerMSASplatImm(DL, ResTy, DAG.getConstant(1, MVT::i32), DAG); + SDValue One = DAG.getConstant(1, ResTy); SDValue Bit = DAG.getNode(ISD::SHL, DL, ResTy, One, Op->getOperand(2)); SDValue AllOnes = DAG.getConstant(-1, MVT::i32); @@ -1346,15 +1391,9 @@ static SDValue lowerMSABitClear(SDValue Op, SelectionDAG &DAG) { static SDValue lowerMSABitClearImm(SDValue Op, SelectionDAG &DAG) { SDLoc DL(Op); EVT ResTy = Op->getValueType(0); - SDValue SHAmount = Op->getOperand(2); - EVT ImmTy = SHAmount->getValueType(0); - SDValue Bit = - DAG.getNode(ISD::SHL, DL, ImmTy, DAG.getConstant(1, ImmTy), SHAmount); - SDValue BitMask = DAG.getNOT(DL, Bit, ImmTy); - - assert(ResTy.getVectorNumElements() <= 16); - - BitMask = lowerMSASplatImm(DL, ResTy, BitMask, DAG); + APInt BitImm = APInt(ResTy.getVectorElementType().getSizeInBits(), 1) + << cast<ConstantSDNode>(Op->getOperand(2))->getAPIntValue(); + SDValue BitMask = DAG.getConstant(~BitImm, ResTy); return DAG.getNode(ISD::AND, DL, ResTy, Op->getOperand(1), BitMask); } @@ -1469,8 +1508,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::mips_bneg_w: case Intrinsic::mips_bneg_d: { EVT VecTy = Op->getValueType(0); - SDValue One = lowerMSASplatImm(DL, VecTy, DAG.getConstant(1, MVT::i32), - DAG); + SDValue One = DAG.getConstant(1, VecTy); return DAG.getNode(ISD::XOR, DL, VecTy, Op->getOperand(1), DAG.getNode(ISD::SHL, DL, VecTy, One, @@ -1504,8 +1542,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, case Intrinsic::mips_bset_w: case Intrinsic::mips_bset_d: { EVT VecTy = Op->getValueType(0); - SDValue One = lowerMSASplatImm(DL, VecTy, DAG.getConstant(1, MVT::i32), - DAG); + SDValue One = DAG.getConstant(1, VecTy); return DAG.getNode(ISD::OR, DL, VecTy, Op->getOperand(1), DAG.getNode(ISD::SHL, DL, VecTy, One, @@ -1926,7 +1963,7 @@ SDValue MipsSETargetLowering::lowerINTRINSIC_WO_CHAIN(SDValue Op, // EXTRACT_VECTOR_ELT can't extract i64's on MIPS32. // Instead we lower to MipsISD::VSHF and match from there. return DAG.getNode(MipsISD::VSHF, DL, Op->getValueType(0), - lowerMSASplatImm(Op, 2, DAG), Op->getOperand(1), + lowerMSASplatZExt(Op, 2, DAG), Op->getOperand(1), Op->getOperand(1)); case Intrinsic::mips_splati_b: case Intrinsic::mips_splati_h: @@ -2200,15 +2237,10 @@ SDValue MipsSETargetLowering::lowerBUILD_VECTOR(SDValue Op, return SDValue(); } - SmallVector<SDValue, 16> Ops; - SDValue Constant = DAG.getConstant(SplatValue.sextOrSelf(32), MVT::i32); - - for (unsigned i = 0; i < ViaVecTy.getVectorNumElements(); ++i) - Ops.push_back(Constant); - - SDValue Result = DAG.getNode(ISD::BUILD_VECTOR, SDLoc(Node), ViaVecTy, - &Ops[0], Ops.size()); + // SelectionDAG::getConstant will promote SplatValue appropriately. + SDValue Result = DAG.getConstant(SplatValue, ViaVecTy); + // Bitcast to the type we originally wanted if (ViaVecTy != ResTy) Result = DAG.getNode(ISD::BITCAST, SDLoc(Node), ResTy, Result); |