[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