diff options
Diffstat (limited to 'lib/Target/ARM/ARMISelDAGToDAG.cpp')
-rw-r--r-- | lib/Target/ARM/ARMISelDAGToDAG.cpp | 81 |
1 files changed, 72 insertions, 9 deletions
diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index 1ed9e80..ee9dadf 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -32,6 +32,9 @@ #include "llvm/Support/Debug.h" using namespace llvm; +static const unsigned arm_dsubreg_0 = 5; +static const unsigned arm_dsubreg_1 = 6; + //===--------------------------------------------------------------------===// /// ARMDAGToDAGISel - ARM specific code to select ARM machine /// instructions for SelectionDAG operations. @@ -579,17 +582,18 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { switch (N->getOpcode()) { default: break; case ISD::Constant: { - // ARMv6T2 and later should materialize imms via MOV / MOVT pair. - if (Subtarget->hasV6T2Ops() || Subtarget->hasThumb2()) - break; - unsigned Val = cast<ConstantSDNode>(N)->getZExtValue(); bool UseCP = true; - if (Subtarget->isThumb()) - UseCP = (Val > 255 && // MOV - ~Val > 255 && // MOV + MVN - !ARM_AM::isThumbImmShiftedVal(Val)); // MOV + LSL - else + if (Subtarget->isThumb()) { + if (Subtarget->hasThumb2()) + // Thumb2 has the MOVT instruction, so all immediates can + // be done with MOV + MOVT, at worst. + UseCP = 0; + else + UseCP = (Val > 255 && // MOV + ~Val > 255 && // MOV + MVN + !ARM_AM::isThumbImmShiftedVal(Val)); // MOV + LSL + } else UseCP = (ARM_AM::getSOImmVal(Val) == -1 && // MOV ARM_AM::getSOImmVal(~Val) == -1 && // MVN !ARM_AM::isSOImmTwoPartVal(Val)); // two instrs. @@ -917,6 +921,65 @@ SDNode *ARMDAGToDAGISel::Select(SDValue Op) { return CurDAG->getTargetNode(TargetInstrInfo::DECLARE, dl, MVT::Other, Ops, 3); } + + case ISD::CONCAT_VECTORS: { + MVT VT = Op.getValueType(); + assert(VT.is128BitVector() && Op.getNumOperands() == 2 && + "unexpected CONCAT_VECTORS"); + SDValue N0 = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDNode *Result = + CurDAG->getTargetNode(TargetInstrInfo::IMPLICIT_DEF, dl, VT); + if (N0.getOpcode() != ISD::UNDEF) + Result = CurDAG->getTargetNode(TargetInstrInfo::INSERT_SUBREG, dl, VT, + SDValue(Result, 0), N0, + CurDAG->getTargetConstant(arm_dsubreg_0, + MVT::i32)); + if (N1.getOpcode() != ISD::UNDEF) + Result = CurDAG->getTargetNode(TargetInstrInfo::INSERT_SUBREG, dl, VT, + SDValue(Result, 0), N1, + CurDAG->getTargetConstant(arm_dsubreg_1, + MVT::i32)); + return Result; + } + + case ISD::VECTOR_SHUFFLE: { + MVT VT = Op.getValueType(); + + // Match 128-bit splat to VDUPLANEQ. (This could be done with a Pat in + // ARMInstrNEON.td but it is awkward because the shuffle mask needs to be + // transformed first into a lane number and then to both a subregister + // index and an adjusted lane number.) If the source operand is a + // SCALAR_TO_VECTOR, leave it so it will be matched later as a VDUP. + ShuffleVectorSDNode *SVOp = cast<ShuffleVectorSDNode>(N); + if (VT.is128BitVector() && SVOp->isSplat() && + Op.getOperand(0).getOpcode() != ISD::SCALAR_TO_VECTOR && + Op.getOperand(1).getOpcode() == ISD::UNDEF) { + unsigned LaneVal = SVOp->getSplatIndex(); + + MVT HalfVT; + unsigned Opc = 0; + switch (VT.getVectorElementType().getSimpleVT()) { + default: assert(false && "unhandled VDUP splat type"); + case MVT::i8: Opc = ARM::VDUPLN8q; HalfVT = MVT::v8i8; break; + case MVT::i16: Opc = ARM::VDUPLN16q; HalfVT = MVT::v4i16; break; + case MVT::i32: Opc = ARM::VDUPLN32q; HalfVT = MVT::v2i32; break; + case MVT::f32: Opc = ARM::VDUPLNfq; HalfVT = MVT::v2f32; break; + } + + // The source operand needs to be changed to a subreg of the original + // 128-bit operand, and the lane number needs to be adjusted accordingly. + unsigned NumElts = VT.getVectorNumElements() / 2; + unsigned SRVal = (LaneVal < NumElts ? arm_dsubreg_0 : arm_dsubreg_1); + SDValue SR = CurDAG->getTargetConstant(SRVal, MVT::i32); + SDValue NewLane = CurDAG->getTargetConstant(LaneVal % NumElts, MVT::i32); + SDNode *SubReg = CurDAG->getTargetNode(TargetInstrInfo::EXTRACT_SUBREG, + dl, HalfVT, N->getOperand(0), SR); + return CurDAG->SelectNodeTo(N, Opc, VT, SDValue(SubReg, 0), NewLane); + } + + break; + } } return SelectCode(Op); |