From 701bcdfccb0335d4dfcd107ac4e66d2c03b659a6 Mon Sep 17 00:00:00 2001 From: "Jian1.Guan" Date: Mon, 1 Dec 2025 13:10:49 +0800 Subject: [PATCH 1/5] [SelectionDAG] Lowering usub.sat(a, 1) to a - (a != 0) --- .../CodeGen/SelectionDAG/TargetLowering.cpp | 10 +++++++ llvm/test/CodeGen/AArch64/and-mask-removal.ll | 6 ++-- llvm/test/CodeGen/RISCV/usub_sat.ll | 28 +++++++++++++++++++ 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index c65ddc6c28986..1afbad048f9b4 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -10877,6 +10877,16 @@ SDValue TargetLowering::expandAddSubSat(SDNode *Node, SelectionDAG &DAG) const { assert(VT == RHS.getValueType() && "Expected operands to be the same type"); assert(VT.isInteger() && "Expected operands to be integers"); + // usub.sat(a, 1) -> a - zext(a != 0) + if (Opcode == ISD::USUBSAT && !VT.isVector() && isOneConstant(RHS)) { + SDValue Zero = DAG.getConstant(0, dl, VT); + EVT BoolVT = + getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); + SDValue IsNonZero = DAG.getSetCC(dl, BoolVT, LHS, Zero, ISD::SETNE); + SDValue Subtrahend = DAG.getBoolExtOrTrunc(IsNonZero, dl, VT, BoolVT); + return DAG.getNode(ISD::SUB, dl, VT, LHS, Subtrahend); + } + // usub.sat(a, b) -> umax(a, b) - b if (Opcode == ISD::USUBSAT && isOperationLegal(ISD::UMAX, VT)) { SDValue Max = DAG.getNode(ISD::UMAX, dl, VT, LHS, RHS); diff --git a/llvm/test/CodeGen/AArch64/and-mask-removal.ll b/llvm/test/CodeGen/AArch64/and-mask-removal.ll index 5046c0571ad2b..855fe5caf97b2 100644 --- a/llvm/test/CodeGen/AArch64/and-mask-removal.ll +++ b/llvm/test/CodeGen/AArch64/and-mask-removal.ll @@ -483,9 +483,9 @@ define i64 @pr58109(i8 signext %0) { ; CHECK-SD-LABEL: pr58109: ; CHECK-SD: ; %bb.0: ; CHECK-SD-NEXT: add w8, w0, #1 -; CHECK-SD-NEXT: and w8, w8, #0xff -; CHECK-SD-NEXT: subs w8, w8, #1 -; CHECK-SD-NEXT: csel w0, wzr, w8, lo +; CHECK-SD-NEXT: ands w8, w8, #0xff +; CHECK-SD-NEXT: cset w9, ne +; CHECK-SD-NEXT: sub w0, w8, w9 ; CHECK-SD-NEXT: ret ; ; CHECK-GI-LABEL: pr58109: diff --git a/llvm/test/CodeGen/RISCV/usub_sat.ll b/llvm/test/CodeGen/RISCV/usub_sat.ll index 33056682dcc79..7084885a0ee2c 100644 --- a/llvm/test/CodeGen/RISCV/usub_sat.ll +++ b/llvm/test/CodeGen/RISCV/usub_sat.ll @@ -185,3 +185,31 @@ define zeroext i4 @func3(i4 zeroext %x, i4 zeroext %y) nounwind { %tmp = call i4 @llvm.usub.sat.i4(i4 %x, i4 %y); ret i4 %tmp; } + +define signext i32 @sat_dec_i32(i32 signext %x) nounwind { +; RV32I-LABEL: sat_dec_i32: +; RV32I: # %bb.0: +; RV32I-NEXT: snez a1, a0 +; RV32I-NEXT: sub a0, a0, a1 +; RV32I-NEXT: ret +; +; RV64I-LABEL: sat_dec_i32: +; RV64I: # %bb.0: +; RV64I-NEXT: snez a1, a0 +; RV64I-NEXT: subw a0, a0, a1 +; RV64I-NEXT: ret +; +; RV32IZbb-LABEL: sat_dec_i32: +; RV32IZbb: # %bb.0: +; RV32IZbb-NEXT: snez a1, a0 +; RV32IZbb-NEXT: sub a0, a0, a1 +; RV32IZbb-NEXT: ret +; +; RV64IZbb-LABEL: sat_dec_i32: +; RV64IZbb: # %bb.0: +; RV64IZbb-NEXT: snez a1, a0 +; RV64IZbb-NEXT: subw a0, a0, a1 +; RV64IZbb-NEXT: ret + %tmp = call i32 @llvm.usub.sat.i32(i32 %x, i32 1) + ret i32 %tmp +} From 2cc21b2a3dafdfdaad00f5afa2acab71316a8514 Mon Sep 17 00:00:00 2001 From: guan jian <2023020923@stu.cdut.edu.cn> Date: Wed, 3 Dec 2025 22:22:51 +0800 Subject: [PATCH 2/5] Update llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp Co-authored-by: Simon Pilgrim --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 1afbad048f9b4..5b9a1c6138e3f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -10877,7 +10877,7 @@ SDValue TargetLowering::expandAddSubSat(SDNode *Node, SelectionDAG &DAG) const { assert(VT == RHS.getValueType() && "Expected operands to be the same type"); assert(VT.isInteger() && "Expected operands to be integers"); - // usub.sat(a, 1) -> a - zext(a != 0) + // usub.sat(a, 1) -> sub(a, zext(a != 0)) if (Opcode == ISD::USUBSAT && !VT.isVector() && isOneConstant(RHS)) { SDValue Zero = DAG.getConstant(0, dl, VT); EVT BoolVT = From 87c6428f5608b7c66a98e4e9155f7df5ff1c9911 Mon Sep 17 00:00:00 2001 From: rez5427 Date: Thu, 4 Dec 2025 22:03:59 +0800 Subject: [PATCH 3/5] Use getZExtOrTrunc --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 5b9a1c6138e3f..1d3846c54bce4 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -10878,12 +10878,11 @@ SDValue TargetLowering::expandAddSubSat(SDNode *Node, SelectionDAG &DAG) const { assert(VT.isInteger() && "Expected operands to be integers"); // usub.sat(a, 1) -> sub(a, zext(a != 0)) - if (Opcode == ISD::USUBSAT && !VT.isVector() && isOneConstant(RHS)) { + if (Opcode == ISD::USUBSAT && isOneConstant(RHS)) { SDValue Zero = DAG.getConstant(0, dl, VT); - EVT BoolVT = - getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); + EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); SDValue IsNonZero = DAG.getSetCC(dl, BoolVT, LHS, Zero, ISD::SETNE); - SDValue Subtrahend = DAG.getBoolExtOrTrunc(IsNonZero, dl, VT, BoolVT); + SDValue Subtrahend = DAG.getZExtOrTrunc(IsNonZero, dl, VT); return DAG.getNode(ISD::SUB, dl, VT, LHS, Subtrahend); } From 0c20d337bfe8e1a7d43248dcbcd7b7a5f8595892 Mon Sep 17 00:00:00 2001 From: rez5427 Date: Thu, 4 Dec 2025 23:39:06 +0800 Subject: [PATCH 4/5] Add getBoolExtOrTrunc and and --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 1d3846c54bce4..966cb8e71d4f2 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -10882,7 +10882,8 @@ SDValue TargetLowering::expandAddSubSat(SDNode *Node, SelectionDAG &DAG) const { SDValue Zero = DAG.getConstant(0, dl, VT); EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); SDValue IsNonZero = DAG.getSetCC(dl, BoolVT, LHS, Zero, ISD::SETNE); - SDValue Subtrahend = DAG.getZExtOrTrunc(IsNonZero, dl, VT); + SDValue Subtrahend = DAG.getBoolExtOrTrunc(IsNonZero, dl, VT, BoolVT); + Subtrahend = DAG.getNode(ISD::AND, dl, VT, Subtrahend, DAG.getConstant(1, dl, VT)); return DAG.getNode(ISD::SUB, dl, VT, LHS, Subtrahend); } From ae1bccfe8227a6d1a87279a3297bcf83b5674b9a Mon Sep 17 00:00:00 2001 From: rez5427 Date: Sat, 6 Dec 2025 20:09:06 +0800 Subject: [PATCH 5/5] Add freeze, ban vector --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 6 ++++-- llvm/test/CodeGen/X86/combine-sub-usat.ll | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 966cb8e71d4f2..1b25d91d9a316 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -10878,12 +10878,14 @@ SDValue TargetLowering::expandAddSubSat(SDNode *Node, SelectionDAG &DAG) const { assert(VT.isInteger() && "Expected operands to be integers"); // usub.sat(a, 1) -> sub(a, zext(a != 0)) - if (Opcode == ISD::USUBSAT && isOneConstant(RHS)) { + if (Opcode == ISD::USUBSAT && !VT.isVector() && isOneConstant(RHS)) { + LHS = DAG.getFreeze(LHS); SDValue Zero = DAG.getConstant(0, dl, VT); EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); SDValue IsNonZero = DAG.getSetCC(dl, BoolVT, LHS, Zero, ISD::SETNE); SDValue Subtrahend = DAG.getBoolExtOrTrunc(IsNonZero, dl, VT, BoolVT); - Subtrahend = DAG.getNode(ISD::AND, dl, VT, Subtrahend, DAG.getConstant(1, dl, VT)); + Subtrahend = + DAG.getNode(ISD::AND, dl, VT, Subtrahend, DAG.getConstant(1, dl, VT)); return DAG.getNode(ISD::SUB, dl, VT, LHS, Subtrahend); } diff --git a/llvm/test/CodeGen/X86/combine-sub-usat.ll b/llvm/test/CodeGen/X86/combine-sub-usat.ll index e601c5733bd42..7ec4e062930db 100644 --- a/llvm/test/CodeGen/X86/combine-sub-usat.ll +++ b/llvm/test/CodeGen/X86/combine-sub-usat.ll @@ -116,9 +116,9 @@ define <8 x i16> @combine_zero_v8i16(<8 x i16> %a0) { define i32 @combine_dec_i32(i32 %a0) { ; CHECK-LABEL: combine_dec_i32: ; CHECK: # %bb.0: -; CHECK-NEXT: xorl %eax, %eax -; CHECK-NEXT: subl $1, %edi -; CHECK-NEXT: cmovael %edi, %eax +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: cmpl $1, %edi +; CHECK-NEXT: adcl $-1, %eax ; CHECK-NEXT: retq %1 = call i32 @llvm.usub.sat.i32(i32 %a0, i32 1) ret i32 %1