[llvm] [X86] Fold X - (!OF) into ADOX (PR #220455)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 1 19:00:44 PDT 2026


https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/220455

Add support for inversion of OF

>From d16e063b52aeae92fb22adc56669644c973068ce Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Tue, 1 Sep 2026 20:08:16 -0400
Subject: [PATCH 1/2] [X86][test] Pre-commit test for adox with -= !OF

---
 llvm/test/CodeGen/X86/adox.ll | 77 +++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/llvm/test/CodeGen/X86/adox.ll b/llvm/test/CodeGen/X86/adox.ll
index d8b833ced37fb..b2ac76d18598b 100644
--- a/llvm/test/CodeGen/X86/adox.ll
+++ b/llvm/test/CodeGen/X86/adox.ll
@@ -330,5 +330,82 @@ nonzero:
   ret i32 222
 }
 
+
+define i32 @adox_test_sub_not_ov_i32(i32 %a, i32 %b, i8 %c, i8 %d) {
+; NDD-LABEL: adox_test_sub_not_ov_i32:
+; NDD:       # %bb.0:
+; NDD-NEXT:    xorl %eax, %eax
+; NDD-NEXT:    cmpb %cl, %dl
+; NDD-NEXT:    setno %al
+; NDD-NEXT:    subl %esi, %edi
+; NDD-NEXT:    subl %eax, %edi, %eax
+; NDD-NEXT:    retq
+;
+; ADX-LABEL: adox_test_sub_not_ov_i32:
+; ADX:       # %bb.0:
+; ADX-NEXT:    movl %edi, %eax
+; ADX-NEXT:    xorl %edi, %edi
+; ADX-NEXT:    cmpb %cl, %dl
+; ADX-NEXT:    setno %dil
+; ADX-NEXT:    subl %esi, %eax
+; ADX-NEXT:    subl %edi, %eax
+; ADX-NEXT:    retq
+;
+; NOADX-LABEL: adox_test_sub_not_ov_i32:
+; NOADX:       # %bb.0:
+; NOADX-NEXT:    movl %edi, %eax
+; NOADX-NEXT:    xorl %edi, %edi
+; NOADX-NEXT:    cmpb %cl, %dl
+; NOADX-NEXT:    setno %dil
+; NOADX-NEXT:    subl %esi, %eax
+; NOADX-NEXT:    subl %edi, %eax
+; NOADX-NEXT:    retq
+  %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d)
+  %ov = extractvalue { i8, i1 } %ssub, 1
+  %not.ov = xor i1 %ov, true
+  %not.ov.ext = zext i1 %not.ov to i32
+  %sum = sub i32 %a, %b
+  %res = sub i32 %sum, %not.ov.ext
+  ret i32 %res
+}
+
+define i64 @adox_test_sub_not_ov_i64(i64 %a, i64 %b, i8 %c, i8 %d) {
+; NDD-LABEL: adox_test_sub_not_ov_i64:
+; NDD:       # %bb.0:
+; NDD-NEXT:    xorl %eax, %eax
+; NDD-NEXT:    cmpb %cl, %dl
+; NDD-NEXT:    setno %al
+; NDD-NEXT:    subq %rsi, %rdi
+; NDD-NEXT:    subq %rax, %rdi, %rax
+; NDD-NEXT:    retq
+;
+; ADX-LABEL: adox_test_sub_not_ov_i64:
+; ADX:       # %bb.0:
+; ADX-NEXT:    movq %rdi, %rax
+; ADX-NEXT:    xorl %edi, %edi
+; ADX-NEXT:    cmpb %cl, %dl
+; ADX-NEXT:    setno %dil
+; ADX-NEXT:    subq %rsi, %rax
+; ADX-NEXT:    subq %rdi, %rax
+; ADX-NEXT:    retq
+;
+; NOADX-LABEL: adox_test_sub_not_ov_i64:
+; NOADX:       # %bb.0:
+; NOADX-NEXT:    movq %rdi, %rax
+; NOADX-NEXT:    xorl %edi, %edi
+; NOADX-NEXT:    cmpb %cl, %dl
+; NOADX-NEXT:    setno %dil
+; NOADX-NEXT:    subq %rsi, %rax
+; NOADX-NEXT:    subq %rdi, %rax
+; NOADX-NEXT:    retq
+  %ssub = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %c, i8 %d)
+  %ov = extractvalue { i8, i1 } %ssub, 1
+  %not.ov = xor i1 %ov, true
+  %not.ov.ext = zext i1 %not.ov to i64
+  %sum = sub i64 %a, %b
+  %res = sub i64 %sum, %not.ov.ext
+  ret i64 %res
+}
+
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
 ; CHECK: {{.*}}

>From ee5bbc506323a755ac0cbb4bae699f48b41b42cd Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Tue, 1 Sep 2026 21:59:11 -0400
Subject: [PATCH 2/2] [X86] Fold X - (!OF) into ADOX

---
 llvm/lib/Target/X86/X86ISelLowering.cpp | 21 +++++++++++++++----
 llvm/test/CodeGen/X86/adox.ll           | 28 +++++++++++--------------
 2 files changed, 29 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 71cba0b21af82..622376a8fa0e8 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -53525,11 +53525,20 @@ static SDValue combineAddOrSubToADCOrSBB(bool IsSub, const SDLoc &DL, EVT VT,
 
   X86::CondCode CC;
   SDValue EFLAGS;
+  bool InvertCC = false;
+  if (Y.getOpcode() == ISD::XOR && isOneConstant(Y.getOperand(1)) &&
+      Y.hasOneUse()) {
+    InvertCC = true;
+    Y = Y.getOperand(0);
+  }
+
   if (Y.getOpcode() == X86ISD::SETCC && Y.hasOneUse()) {
     CC = (X86::CondCode)Y.getConstantOperandVal(0);
+    if (InvertCC)
+      CC = X86::GetOppositeBranchCondition(CC);
     EFLAGS = Y.getOperand(1);
-  } else if (Y.getOpcode() == ISD::AND && isOneConstant(Y.getOperand(1)) &&
-             Y.hasOneUse()) {
+  } else if (!InvertCC && Y.getOpcode() == ISD::AND &&
+             isOneConstant(Y.getOperand(1)) && Y.hasOneUse()) {
     EFLAGS = LowerAndToBT(Y, ISD::SETNE, DL, DAG, CC);
   }
 
@@ -53576,10 +53585,12 @@ static SDValue combineAddOrSubToADCOrSBB(bool IsSub, const SDLoc &DL, EVT VT,
                        DAG.getVTList(VT, MVT::i32), X,
                        DAG.getConstant(0, DL, VT), EFLAGS);
   }
-  if (!IsSub && CC == X86::COND_O && !FlagsUsed &&
+  if (((!IsSub && CC == X86::COND_O) || (IsSub && CC == X86::COND_NO)) &&
+      !FlagsUsed &&
       (VT == MVT::i8 || VT == MVT::i16 || VT == MVT::i32 || VT == MVT::i64) &&
       DAG.getSubtarget<X86Subtarget>().hasADX()) {
     // X + (overflow_from_OF ? 1 : 0) --> adox X, 0
+    // X - (!overflow_from_OF ? 1 : 0) --> adox X, -1
     // NOTE: For i8/i16, ADOX32's OF output does not match the original iN
     // overflow. This is safe because this ADOX replaces an ISD::ADD, so its OF
     // output is natively dead. Its ANY_EXTEND operands ensure future transforms
@@ -53588,7 +53599,9 @@ static SDValue combineAddOrSubToADCOrSBB(bool IsSub, const SDLoc &DL, EVT VT,
     SDValue AdoxX = DAG.getAnyExtOrTrunc(X, DL, AdoxVT);
     SDValue Adox =
         DAG.getNode(X86ISD::ADOX, DL, DAG.getVTList(AdoxVT, MVT::i32), AdoxX,
-                    DAG.getConstant(0, DL, AdoxVT), EFLAGS);
+                    IsSub ? DAG.getAllOnesConstant(DL, AdoxVT)
+                          : DAG.getConstant(0, DL, AdoxVT),
+                    EFLAGS);
     return DAG.getAnyExtOrTrunc(Adox, DL, VT);
   }
 
diff --git a/llvm/test/CodeGen/X86/adox.ll b/llvm/test/CodeGen/X86/adox.ll
index b2ac76d18598b..9d2b92761d7f0 100644
--- a/llvm/test/CodeGen/X86/adox.ll
+++ b/llvm/test/CodeGen/X86/adox.ll
@@ -334,21 +334,19 @@ nonzero:
 define i32 @adox_test_sub_not_ov_i32(i32 %a, i32 %b, i8 %c, i8 %d) {
 ; NDD-LABEL: adox_test_sub_not_ov_i32:
 ; NDD:       # %bb.0:
-; NDD-NEXT:    xorl %eax, %eax
+; NDD-NEXT:    subl %esi, %edi, %eax
 ; NDD-NEXT:    cmpb %cl, %dl
-; NDD-NEXT:    setno %al
-; NDD-NEXT:    subl %esi, %edi
-; NDD-NEXT:    subl %eax, %edi, %eax
+; NDD-NEXT:    movl $-1, %ecx
+; NDD-NEXT:    adoxl %ecx, %eax
 ; NDD-NEXT:    retq
 ;
 ; ADX-LABEL: adox_test_sub_not_ov_i32:
 ; ADX:       # %bb.0:
 ; ADX-NEXT:    movl %edi, %eax
-; ADX-NEXT:    xorl %edi, %edi
-; ADX-NEXT:    cmpb %cl, %dl
-; ADX-NEXT:    setno %dil
 ; ADX-NEXT:    subl %esi, %eax
-; ADX-NEXT:    subl %edi, %eax
+; ADX-NEXT:    cmpb %cl, %dl
+; ADX-NEXT:    movl $-1, %ecx
+; ADX-NEXT:    adoxl %ecx, %eax
 ; ADX-NEXT:    retq
 ;
 ; NOADX-LABEL: adox_test_sub_not_ov_i32:
@@ -372,21 +370,19 @@ define i32 @adox_test_sub_not_ov_i32(i32 %a, i32 %b, i8 %c, i8 %d) {
 define i64 @adox_test_sub_not_ov_i64(i64 %a, i64 %b, i8 %c, i8 %d) {
 ; NDD-LABEL: adox_test_sub_not_ov_i64:
 ; NDD:       # %bb.0:
-; NDD-NEXT:    xorl %eax, %eax
+; NDD-NEXT:    subq %rsi, %rdi, %rax
 ; NDD-NEXT:    cmpb %cl, %dl
-; NDD-NEXT:    setno %al
-; NDD-NEXT:    subq %rsi, %rdi
-; NDD-NEXT:    subq %rax, %rdi, %rax
+; NDD-NEXT:    movq $-1, %rcx
+; NDD-NEXT:    adoxq %rcx, %rax
 ; NDD-NEXT:    retq
 ;
 ; ADX-LABEL: adox_test_sub_not_ov_i64:
 ; ADX:       # %bb.0:
 ; ADX-NEXT:    movq %rdi, %rax
-; ADX-NEXT:    xorl %edi, %edi
-; ADX-NEXT:    cmpb %cl, %dl
-; ADX-NEXT:    setno %dil
 ; ADX-NEXT:    subq %rsi, %rax
-; ADX-NEXT:    subq %rdi, %rax
+; ADX-NEXT:    cmpb %cl, %dl
+; ADX-NEXT:    movq $-1, %rcx
+; ADX-NEXT:    adoxq %rcx, %rax
 ; ADX-NEXT:    retq
 ;
 ; NOADX-LABEL: adox_test_sub_not_ov_i64:



More information about the llvm-commits mailing list