summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target')
-rw-r--r--llvm/lib/Target/ARM/ARMISelLowering.cpp81
1 files changed, 81 insertions, 0 deletions
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 2e0f6096e43..47222a66f79 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -10676,6 +10676,83 @@ static SDValue PerformMULCombine(SDNode *N,
return SDValue();
}
+static SDValue CombineANDShift(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const ARMSubtarget *Subtarget) {
+ // Allow DAGCombine to pattern-match before we touch the canonical form.
+ if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer())
+ return SDValue();
+
+ if (N->getValueType(0) != MVT::i32)
+ return SDValue();
+
+ ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1));
+ if (!N1C)
+ return SDValue();
+
+ uint32_t C1 = (uint32_t)N1C->getZExtValue();
+ // Don't transform uxtb/uxth.
+ if (C1 == 255 || C1 == 65535)
+ return SDValue();
+
+ SDNode *N0 = N->getOperand(0).getNode();
+ if (!N0->hasOneUse())
+ return SDValue();
+
+ if (N0->getOpcode() != ISD::SHL && N0->getOpcode() != ISD::SRL)
+ return SDValue();
+
+ bool LeftShift = N0->getOpcode() == ISD::SHL;
+
+ ConstantSDNode *N01C = dyn_cast<ConstantSDNode>(N0->getOperand(1));
+ if (!N01C)
+ return SDValue();
+
+ uint32_t C2 = (uint32_t)N01C->getZExtValue();
+ if (!C2 || C2 >= 32)
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ SDLoc DL(N);
+
+ // We have a pattern of the form "(and (shl x, c2) c1)" or
+ // "(and (srl x, c2) c1)", where c1 is a shifted mask. Try to
+ // transform to a pair of shifts, to save materializing c1.
+
+ // First pattern: right shift, and c1+1 is a power of two.
+ // FIXME: Also check reversed pattern (left shift, and ~c1+1 is a power
+ // of two).
+ // FIXME: Use demanded bits?
+ if (!LeftShift && isMask_32(C1)) {
+ uint32_t C3 = countLeadingZeros(C1);
+ if (C2 < C3) {
+ SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, N0->getOperand(0),
+ DAG.getConstant(C3 - C2, DL, MVT::i32));
+ return DAG.getNode(ISD::SRL, DL, MVT::i32, SHL,
+ DAG.getConstant(C3, DL, MVT::i32));
+ }
+ }
+
+ // Second pattern: left shift, and (c1>>c2)+1 is a power of two.
+ // FIXME: Also check reversed pattern (right shift, and ~(c1<<c2)+1
+ // is a power of two).
+ // FIXME: Use demanded bits?
+ if (LeftShift && isShiftedMask_32(C1)) {
+ uint32_t C3 = countLeadingZeros(C1);
+ if (C2 + C3 < 32 && C1 == ((-1U << (C2 + C3)) >> C3)) {
+ SDValue SHL = DAG.getNode(ISD::SHL, DL, MVT::i32, N0->getOperand(0),
+ DAG.getConstant(C2 + C3, DL, MVT::i32));
+ return DAG.getNode(ISD::SRL, DL, MVT::i32, SHL,
+ DAG.getConstant(C3, DL, MVT::i32));
+ }
+ }
+
+ // FIXME: Transform "(and (shl x, c2) c1)" ->
+ // "(shl (and x, c1>>c2), c2)" if "c1 >> c2" is a cheaper immediate than
+ // c1.
+ return SDValue();
+}
+
static SDValue PerformANDCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
@@ -10717,6 +10794,10 @@ static SDValue PerformANDCombine(SDNode *N,
return Result;
}
+ if (Subtarget->isThumb1Only())
+ if (SDValue Result = CombineANDShift(N, DCI, Subtarget))
+ return Result;
+
return SDValue();
}
OpenPOWER on IntegriCloud