[llvm] [X86] Optimized ADC + ADD to ADC (PR #176713)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 21 21:04:39 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: None (JaydeepChauhan14)
<details>
<summary>Changes</summary>
---
Full diff: https://github.com/llvm/llvm-project/pull/176713.diff
2 Files Affected:
- (modified) llvm/lib/Target/X86/X86ISelLowering.cpp (+6-2)
- (modified) llvm/test/CodeGen/X86/combine-add.ll (+96)
``````````diff
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 640d9c5f5bc07..d0f59fb95eec0 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -58197,7 +58197,11 @@ static SDValue combineFunnelShift(SDNode *N, SelectionDAG &DAG,
static bool needCarryOrOverflowFlag(SDValue Flags) {
assert(Flags.getValueType() == MVT::i32 && "Unexpected VT!");
- for (const SDNode *User : Flags->users()) {
+ for (const SDUse &Use : Flags->uses()) {
+ // Only check things that use the flags.
+ if (Use.getResNo() != Flags.getResNo())
+ continue;
+ const SDNode *User = Use.getUser();
X86::CondCode CC;
switch (User->getOpcode()) {
default:
@@ -58541,7 +58545,7 @@ static SDValue combineADC(SDNode *N, SelectionDAG &DAG,
// Fold ADC(ADD(X,Y),0,Carry) -> ADC(X,Y,Carry)
// iff the flag result is dead.
if (LHS.getOpcode() == ISD::ADD && RHSC && RHSC->isZero() &&
- !N->hasAnyUseOfValue(1))
+ !needCarryOrOverflowFlag(SDValue(N, 1)))
return DAG.getNode(X86ISD::ADC, SDLoc(N), N->getVTList(), LHS.getOperand(0),
LHS.getOperand(1), CarryIn);
diff --git a/llvm/test/CodeGen/X86/combine-add.ll b/llvm/test/CodeGen/X86/combine-add.ll
index 51a8bf5b48415..7bacb3c495b50 100644
--- a/llvm/test/CodeGen/X86/combine-add.ll
+++ b/llvm/test/CodeGen/X86/combine-add.ll
@@ -561,3 +561,99 @@ define i64 @add_notx_x(i64 %v0) nounwind {
%y = add i64 %x, %v0
ret i64 %y
}
+
+; Basic positive test
+define i32 @add_adc(i32 %0, i32 %1, i32 %2) {
+; CHECK-LABEL: add_adc:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %edi, %eax
+; CHECK-NEXT: cmpl %esi, %edi
+; CHECK-NEXT: adcl %edi, %edx
+; CHECK-NEXT: cmovsl %esi, %eax
+; CHECK-NEXT: retq
+ %4 = icmp ult i32 %0, %1
+ %5 = zext i1 %4 to i32
+ %6 = add i32 %2, %0
+ %7 = add i32 %6, %5
+ %8 = icmp slt i32 %7, 0
+ %9 = select i1 %8, i32 %1, i32 %0
+ ret i32 %9
+}
+
+; Negative test: Carry or overflow flag is used
+define i32 @add_adc_wrong_flags(i32 %0, i32 %1, i32 %2, i32 %3) {
+; CHECK-LABEL: add_adc_wrong_flags:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %eax
+; CHECK-NEXT: cmpl %esi, %edi
+; CHECK-NEXT: adcl $0, %edx
+; CHECK-NEXT: addl %ecx, %edx
+; CHECK-NEXT: cmovbl %edi, %eax
+; CHECK-NEXT: retq
+ %5 = icmp ult i32 %0, %1
+ %6 = zext i1 %5 to i32
+ %7 = add i32 %2, %6
+ %8 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %7, i32 %3)
+ %9 = extractvalue { i32, i1 } %8, 1
+ %10 = select i1 %9, i32 %0, i32 %1
+ ret i32 %10
+}
+
+; Negative test: Multi-use
+define i32 @add_adc_multi_use(i32 %0, i32 %1, i32 %2, i32 %3, ptr %4) {
+; CHECK-LABEL: add_adc_multi_use:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %eax
+; CHECK-NEXT: cmpl %esi, %edi
+; CHECK-NEXT: adcl $0, %edx
+; CHECK-NEXT: movl %edx, (%r8)
+; CHECK-NEXT: addl %ecx, %edx
+; CHECK-NEXT: cmovsl %edi, %eax
+; CHECK-NEXT: retq
+ %6 = icmp ult i32 %0, %1
+ %7 = zext i1 %6 to i32
+ %8 = add i32 %2, %7
+ store i32 %8, ptr %4, align 4
+ %9 = add i32 %8, %3
+ %10 = icmp slt i32 %9, 0
+ %11 = select i1 %10, i32 %0, i32 %1
+ ret i32 %11
+}
+
+; Positive test: Both adc operands are constants
+define i32 @add_adc_constants(i32 %0, i32 %1, i32 %2) {
+; CHECK-LABEL: add_adc_constants:
+; CHECK: # %bb.0:
+; CHECK-NEXT: xorl %eax, %eax
+; CHECK-NEXT: cmpl %esi, %edi
+; CHECK-NEXT: adcl $42, %eax
+; CHECK-NEXT: addl %edx, %eax
+; CHECK-NEXT: retq
+ %4 = icmp ult i32 %0, %1
+ %5 = zext i1 %4 to i8
+ %6 = tail call { i8, i32 } @llvm.x86.addcarry.32(i8 %5, i32 0, i32 42)
+ %7 = extractvalue { i8, i32 } %6, 1
+ %8 = add i32 %7, %2
+ ret i32 %8
+}
+
+; Negative test: Multi-use
+define i32 @add_adc_constants_multi_use(i32 %0, i32 %1, i32 %2, ptr %3) {
+; CHECK-LABEL: add_adc_constants_multi_use:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movl %esi, %eax
+; CHECK-NEXT: xorl %esi, %esi
+; CHECK-NEXT: cmpl %eax, %edi
+; CHECK-NEXT: adcl $42, %esi
+; CHECK-NEXT: movl %esi, (%rcx)
+; CHECK-NEXT: addl %edx, %esi
+; CHECK-NEXT: cmovsl %edi, %eax
+; CHECK-NEXT: retq
+ %5 = icmp ult i32 %0, %1
+ %6 = select i1 %5, i32 43, i32 42
+ store i32 %6, ptr %3, align 4
+ %7 = add i32 %6, %2
+ %8 = icmp slt i32 %7, 0
+ %9 = select i1 %8, i32 %0, i32 %1
+ ret i32 %9
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/176713
More information about the llvm-commits
mailing list