aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target
diff options
context:
space:
mode:
authorOwen Anderson <resistor@mac.com>2010-09-21 18:41:19 +0000
committerOwen Anderson <resistor@mac.com>2010-09-21 18:41:19 +0000
commit0caaab0a26180e1a06e64e1440214def8c2272c6 (patch)
tree23a74efbf817f08bb796242ade0c68d03bf68c17 /lib/Target
parent3c843c5a0bb2fe0ef15c568f170e483ff47403ec (diff)
downloadexternal_llvm-0caaab0a26180e1a06e64e1440214def8c2272c6.zip
external_llvm-0caaab0a26180e1a06e64e1440214def8c2272c6.tar.gz
external_llvm-0caaab0a26180e1a06e64e1440214def8c2272c6.tar.bz2
When adding the carry bit to another value on X86, exploit the fact that the carry-materialization
(sbbl x, x) sets the registers to 0 or ~0. Combined with two's complement arithmetic, we can fold the intermediate AND and the ADD into a single SUB. This fixes <rdar://problem/8449754>. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@114460 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target')
-rw-r--r--lib/Target/X86/X86ISelLowering.cpp23
1 files changed, 23 insertions, 0 deletions
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index aaf91a8..8d52f8c 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -1021,6 +1021,7 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM)
setTargetDAGCombine(ISD::OR);
setTargetDAGCombine(ISD::STORE);
setTargetDAGCombine(ISD::ZERO_EXTEND);
+ setTargetDAGCombine(ISD::ADD);
if (Subtarget->is64Bit())
setTargetDAGCombine(ISD::MUL);
@@ -10452,6 +10453,27 @@ static SDValue PerformCMOVCombine(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
+/// PerformAddCombine - Optimize ADD when combined with X86 opcodes.
+static SDValue PerformAddCombine(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI) {
+ if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer())
+ return SDValue();
+
+ EVT VT = N->getValueType(0);
+ SDValue Op1 = N->getOperand(1);
+ if (Op1->getOpcode() == ISD::AND) {
+ SDValue AndOp0 = Op1->getOperand(0);
+ ConstantSDNode *AndOp1 = dyn_cast<ConstantSDNode>(Op1->getOperand(1));
+ // (add z, (and (sbbl x, x), 1)) -> (sub z, (sbbl x, x))
+ if (AndOp0->getOpcode() == X86ISD::SETCC_CARRY &&
+ AndOp1 && AndOp1->getZExtValue() == 1) {
+ DebugLoc DL = N->getDebugLoc();
+ return DAG.getNode(ISD::SUB, DL, VT, N->getOperand(0), AndOp0);
+ }
+ }
+
+ return SDValue();
+}
/// PerformMulCombine - Optimize a single multiply with constant into two
/// in order to implement it with two cheaper instructions, e.g.
@@ -10938,6 +10960,7 @@ SDValue X86TargetLowering::PerformDAGCombine(SDNode *N,
return PerformEXTRACT_VECTOR_ELTCombine(N, DAG, *this);
case ISD::SELECT: return PerformSELECTCombine(N, DAG, Subtarget);
case X86ISD::CMOV: return PerformCMOVCombine(N, DAG, DCI);
+ case ISD::ADD: return PerformAddCombine(N, DAG, DCI);
case ISD::MUL: return PerformMulCombine(N, DAG, DCI);
case ISD::SHL:
case ISD::SRA: