Skip to content

Commit

Permalink
[SDag] Fold saddo[_carry] with bitwise-not argument to ssubo[_carry] (#…
Browse files Browse the repository at this point in the history
…66571)

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.
  • Loading branch information
s-barannikov committed Sep 18, 2023
1 parent 102838d commit caaf61e
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
27 changes: 26 additions & 1 deletion llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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);
Expand All @@ -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();
}

Expand Down
25 changes: 25 additions & 0 deletions llvm/test/CodeGen/AArch64/i128-math.ll
Expand Up @@ -430,3 +430,28 @@ 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: negs x0, x0
; CHECK-NEXT: ngcs x1, x1
; 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: negs x0, x0
; CHECK-NEXT: sbcs x1, x8, x1
; 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
}
29 changes: 29 additions & 0 deletions llvm/test/CodeGen/X86/addcarry.ll
Expand Up @@ -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:
Expand Down Expand Up @@ -388,6 +389,34 @@ 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 %rdi, %rax
; CHECK-NEXT: xorl %edx, %edx
; CHECK-NEXT: negq %rax
; CHECK-NEXT: sbbq %rsi, %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 %rdi, %rax
; CHECK-NEXT: negq %rax
; CHECK-NEXT: movl $1, %edx
; CHECK-NEXT: sbbq %rsi, %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:
Expand Down

0 comments on commit caaf61e

Please sign in to comment.