summaryrefslogtreecommitdiffstats
path: root/lib/Target/ARM/ARMISelDAGToDAG.cpp
diff options
context:
space:
mode:
authored <ed@FreeBSD.org>2009-06-23 14:50:01 +0000
committered <ed@FreeBSD.org>2009-06-23 14:50:01 +0000
commit4d74f68bdcfeab629970a41b69b96ac709b08a2b (patch)
tree6be075b410677415707e0987e3a49123130cef22 /lib/Target/ARM/ARMISelDAGToDAG.cpp
parenta4c19d68f13cf0a83bc0da53bd6d547fcaf635fe (diff)
downloadFreeBSD-src-4d74f68bdcfeab629970a41b69b96ac709b08a2b.zip
FreeBSD-src-4d74f68bdcfeab629970a41b69b96ac709b08a2b.tar.gz
Import LLVM r73954.
Diffstat (limited to 'lib/Target/ARM/ARMISelDAGToDAG.cpp')
-rw-r--r--lib/Target/ARM/ARMISelDAGToDAG.cpp81
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);
OpenPOWER on IntegriCloud