[llvm] [X86] Optimized ADC + ADD to ADC (PR #176713)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jan 23 00:27:18 PST 2026
https://github.com/JaydeepChauhan14 updated https://github.com/llvm/llvm-project/pull/176713
>From 241a0004e1659757bd305219c5accd88429c79f2 Mon Sep 17 00:00:00 2001
From: Chauhan Jaydeep Ashwinbhai <chauhan.jaydeep.ashwinbhai at intel.com>
Date: Mon, 19 Jan 2026 01:18:15 -0800
Subject: [PATCH 1/2] [X86] Optimized ADC + ADD to ADC
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 8 ++-
llvm/test/CodeGen/X86/combine-add.ll | 96 +++++++++++++++++++++++++
2 files changed, 102 insertions(+), 2 deletions(-)
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
+}
>From f4a638b436fe7191be1d98fec7a3057fd790bcd3 Mon Sep 17 00:00:00 2001
From: Chauhan Jaydeep Ashwinbhai <chauhan.jaydeep.ashwinbhai at intel.com>
Date: Fri, 23 Jan 2026 00:27:04 -0800
Subject: [PATCH 2/2] Removed testcases
---
llvm/test/CodeGen/X86/combine-add.ll | 96 ----------------------------
1 file changed, 96 deletions(-)
diff --git a/llvm/test/CodeGen/X86/combine-add.ll b/llvm/test/CodeGen/X86/combine-add.ll
index 7bacb3c495b50..51a8bf5b48415 100644
--- a/llvm/test/CodeGen/X86/combine-add.ll
+++ b/llvm/test/CodeGen/X86/combine-add.ll
@@ -561,99 +561,3 @@ 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
-}
More information about the llvm-commits
mailing list