[llvm] [SDag] Fold saddo[_carry] with bitwise-not argument to ssubo[_carry] (PR #66571)

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 17 07:35:33 PDT 2023


https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/66571

>From f728cc8b5dd479944087a16e409ce482c9556200 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sat, 16 Sep 2023 06:06:01 +0300
Subject: [PATCH 1/2] Tests

---
 llvm/test/CodeGen/AArch64/i128-math.ll | 27 ++++++++++++++++++++
 llvm/test/CodeGen/X86/addcarry.ll      | 35 ++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/llvm/test/CodeGen/AArch64/i128-math.ll b/llvm/test/CodeGen/AArch64/i128-math.ll
index 2f7848de82274e8..e71b30fdc08b0e3 100644
--- a/llvm/test/CodeGen/AArch64/i128-math.ll
+++ b/llvm/test/CodeGen/AArch64/i128-math.ll
@@ -430,3 +430,30 @@ define i128 @i128_saturating_mul(i128 %x, i128 %y) {
   %7 = select i1 %3, i128 %6, i128 %2
   ret i128 %7
 }
+
+define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
+; CHECK-LABEL: saddo_not_1:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mvn x8, x1
+; CHECK-NEXT:    negs x0, x0
+; CHECK-NEXT:    adcs x1, x8, xzr
+; CHECK-NEXT:    cset w2, vs
+; CHECK-NEXT:    ret
+  %not = xor i128 %x, -1
+  %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 1)
+  ret { i128, i1 } %r
+}
+
+define { i128, i1 } @saddo_carry_not_1(i128 %x) nounwind {
+; CHECK-LABEL: saddo_carry_not_1:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    mov w8, #1 // =0x1
+; CHECK-NEXT:    mvn x9, x1
+; CHECK-NEXT:    negs x0, x0
+; CHECK-NEXT:    adcs x1, x9, x8
+; CHECK-NEXT:    cset w2, vs
+; CHECK-NEXT:    ret
+  %not = xor i128 %x, -1
+  %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 u0x10000000000000001)
+  ret { i128, i1 } %r
+}
diff --git a/llvm/test/CodeGen/X86/addcarry.ll b/llvm/test/CodeGen/X86/addcarry.ll
index 231645f6415919c..e0d2ca66b81a7dc 100644
--- a/llvm/test/CodeGen/X86/addcarry.ll
+++ b/llvm/test/CodeGen/X86/addcarry.ll
@@ -4,6 +4,7 @@
 declare { i8, i64 } @llvm.x86.addcarry.64(i8, i64, i64)
 declare { i64, i1 } @llvm.uadd.with.overflow.i64(i64, i64) #1
 declare { i64, i1 } @llvm.usub.with.overflow.i64(i64, i64) #1
+declare { i128, i1 } @llvm.sadd.with.overflow.i128(i128, i128)
 
 define i128 @add128(i128 %a, i128 %b) nounwind {
 ; CHECK-LABEL: add128:
@@ -388,6 +389,40 @@ define i128 @addcarry1_not(i128 %n) nounwind {
   ret i128 %2
 }
 
+define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
+; CHECK-LABEL: saddo_not_1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq %rsi, %rdx
+; CHECK-NEXT:    movq %rdi, %rax
+; CHECK-NEXT:    notq %rdx
+; CHECK-NEXT:    negq %rax
+; CHECK-NEXT:    setae %cl
+; CHECK-NEXT:    addb $-1, %cl
+; CHECK-NEXT:    adcq $0, %rdx
+; CHECK-NEXT:    seto %cl
+; CHECK-NEXT:    retq
+  %not = xor i128 %x, -1
+  %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 1)
+  ret { i128, i1 } %r
+}
+
+define { i128, i1 } @saddo_carry_not_1(i128 %x) nounwind {
+; CHECK-LABEL: saddo_carry_not_1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movq %rsi, %rdx
+; CHECK-NEXT:    movq %rdi, %rax
+; CHECK-NEXT:    notq %rdx
+; CHECK-NEXT:    negq %rax
+; CHECK-NEXT:    setae %cl
+; CHECK-NEXT:    addb $-1, %cl
+; CHECK-NEXT:    adcq $1, %rdx
+; CHECK-NEXT:    seto %cl
+; CHECK-NEXT:    retq
+  %not = xor i128 %x, -1
+  %r = call { i128, i1 } @llvm.sadd.with.overflow.i128(i128 %not, i128 u0x10000000000000001)
+  ret { i128, i1 } %r
+}
+
 define i128 @addcarry_to_subcarry(i64 %a, i64 %b) nounwind {
 ; CHECK-LABEL: addcarry_to_subcarry:
 ; CHECK:       # %bb.0:

>From 432abae94a585756591b4282d5f0ad3a73319808 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sat, 16 Sep 2023 09:08:25 +0300
Subject: [PATCH 2/2] [SDag] Fold saddo[_carry] with bitwise-not argument to
 ssubo[_carry]

Fold `(saddo (not a), 1)` to `(ssubo 0, a)` and
`(saddo_carry (not a), b, c)` to `(ssubo_carry b, a, !c)`.

Proof: https://alive2.llvm.org/ce/z/Lj49YM

This is the same as https://reviews.llvm.org/D46505 and
https://reviews.llvm.org/D59208, but for signed opcodes.
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 27 ++++++++++++++++++-
 llvm/test/CodeGen/AArch64/i128-math.ll        |  6 ++---
 llvm/test/CodeGen/X86/addcarry.ll             | 14 +++-------
 3 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index be654b1d6591b20..484a6231b7f65fe 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -430,6 +430,8 @@ namespace {
     SDValue visitSADDO_CARRY(SDNode *N);
     SDValue visitUADDO_CARRYLike(SDValue N0, SDValue N1, SDValue CarryIn,
                                  SDNode *N);
+    SDValue visitSADDO_CARRYLike(SDValue N0, SDValue N1, SDValue CarryIn,
+                                 SDNode *N);
     SDValue visitSUBE(SDNode *N);
     SDValue visitUSUBO_CARRY(SDNode *N);
     SDValue visitSSUBO_CARRY(SDNode *N);
@@ -3305,7 +3307,12 @@ SDValue DAGCombiner::visitADDO(SDNode *N) {
     return CombineTo(N, DAG.getNode(ISD::ADD, DL, VT, N0, N1),
                      DAG.getConstant(0, DL, CarryVT));
 
-  if (!IsSigned) {
+  if (IsSigned) {
+    // fold (saddo (xor a, -1), 1) -> (ssub 0, a).
+    if (isBitwiseNot(N0) && isOneOrOneSplat(N1))
+      return DAG.getNode(ISD::SSUBO, DL, N->getVTList(),
+                         DAG.getConstant(0, DL, VT), N0.getOperand(0));
+  } else {
     // fold (uaddo (xor a, -1), 1) -> (usub 0, a) and flip carry.
     if (isBitwiseNot(N0) && isOneOrOneSplat(N1)) {
       SDValue Sub = DAG.getNode(ISD::USUBO, DL, N->getVTList(),
@@ -3637,6 +3644,18 @@ SDValue DAGCombiner::visitUADDO_CARRYLike(SDValue N0, SDValue N1,
   return SDValue();
 }
 
+SDValue DAGCombiner::visitSADDO_CARRYLike(SDValue N0, SDValue N1,
+                                          SDValue CarryIn, SDNode *N) {
+  // fold (saddo_carry (xor a, -1), b, c) -> (ssubo_carry b, a, !c)
+  if (isBitwiseNot(N0)) {
+    if (SDValue NotC = extractBooleanFlip(CarryIn, DAG, TLI, true))
+      return DAG.getNode(ISD::SSUBO_CARRY, SDLoc(N), N->getVTList(), N1,
+                         N0.getOperand(0), NotC);
+  }
+
+  return SDValue();
+}
+
 SDValue DAGCombiner::visitSADDO_CARRY(SDNode *N) {
   SDValue N0 = N->getOperand(0);
   SDValue N1 = N->getOperand(1);
@@ -3656,6 +3675,12 @@ SDValue DAGCombiner::visitSADDO_CARRY(SDNode *N) {
       return DAG.getNode(ISD::SADDO, DL, N->getVTList(), N0, N1);
   }
 
+  if (SDValue Combined = visitSADDO_CARRYLike(N0, N1, CarryIn, N))
+    return Combined;
+
+  if (SDValue Combined = visitSADDO_CARRYLike(N1, N0, CarryIn, N))
+    return Combined;
+
   return SDValue();
 }
 
diff --git a/llvm/test/CodeGen/AArch64/i128-math.ll b/llvm/test/CodeGen/AArch64/i128-math.ll
index e71b30fdc08b0e3..7c1d9141421fd33 100644
--- a/llvm/test/CodeGen/AArch64/i128-math.ll
+++ b/llvm/test/CodeGen/AArch64/i128-math.ll
@@ -434,9 +434,8 @@ define i128 @i128_saturating_mul(i128 %x, i128 %y) {
 define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
 ; CHECK-LABEL: saddo_not_1:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    mvn x8, x1
 ; CHECK-NEXT:    negs x0, x0
-; CHECK-NEXT:    adcs x1, x8, xzr
+; CHECK-NEXT:    ngcs x1, x1
 ; CHECK-NEXT:    cset w2, vs
 ; CHECK-NEXT:    ret
   %not = xor i128 %x, -1
@@ -448,9 +447,8 @@ define { i128, i1 } @saddo_carry_not_1(i128 %x) nounwind {
 ; CHECK-LABEL: saddo_carry_not_1:
 ; CHECK:       // %bb.0:
 ; CHECK-NEXT:    mov w8, #1 // =0x1
-; CHECK-NEXT:    mvn x9, x1
 ; CHECK-NEXT:    negs x0, x0
-; CHECK-NEXT:    adcs x1, x9, x8
+; CHECK-NEXT:    sbcs x1, x8, x1
 ; CHECK-NEXT:    cset w2, vs
 ; CHECK-NEXT:    ret
   %not = xor i128 %x, -1
diff --git a/llvm/test/CodeGen/X86/addcarry.ll b/llvm/test/CodeGen/X86/addcarry.ll
index e0d2ca66b81a7dc..3fc4ed99fad0fa8 100644
--- a/llvm/test/CodeGen/X86/addcarry.ll
+++ b/llvm/test/CodeGen/X86/addcarry.ll
@@ -392,13 +392,10 @@ define i128 @addcarry1_not(i128 %n) nounwind {
 define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
 ; CHECK-LABEL: saddo_not_1:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq %rsi, %rdx
 ; CHECK-NEXT:    movq %rdi, %rax
-; CHECK-NEXT:    notq %rdx
+; CHECK-NEXT:    xorl %edx, %edx
 ; CHECK-NEXT:    negq %rax
-; CHECK-NEXT:    setae %cl
-; CHECK-NEXT:    addb $-1, %cl
-; CHECK-NEXT:    adcq $0, %rdx
+; CHECK-NEXT:    sbbq %rsi, %rdx
 ; CHECK-NEXT:    seto %cl
 ; CHECK-NEXT:    retq
   %not = xor i128 %x, -1
@@ -409,13 +406,10 @@ define { i128, i1 } @saddo_not_1(i128 %x) nounwind {
 define { i128, i1 } @saddo_carry_not_1(i128 %x) nounwind {
 ; CHECK-LABEL: saddo_carry_not_1:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    movq %rsi, %rdx
 ; CHECK-NEXT:    movq %rdi, %rax
-; CHECK-NEXT:    notq %rdx
 ; CHECK-NEXT:    negq %rax
-; CHECK-NEXT:    setae %cl
-; CHECK-NEXT:    addb $-1, %cl
-; CHECK-NEXT:    adcq $1, %rdx
+; CHECK-NEXT:    movl $1, %edx
+; CHECK-NEXT:    sbbq %rsi, %rdx
 ; CHECK-NEXT:    seto %cl
 ; CHECK-NEXT:    retq
   %not = xor i128 %x, -1



More information about the llvm-commits mailing list