[llvm] [X86][APX] Optimize usub.sat(X, 1) to cmp+adc with NDD (PR #208475)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 9 09:23:18 PDT 2026
https://github.com/AntonyCJ30 updated https://github.com/llvm/llvm-project/pull/208475
>From 469ad1a8ed6608d6a26a01513603349d7047aeb4 Mon Sep 17 00:00:00 2001
From: AntonyCJ30 <cj6186609 at gmail@gmail.com>
Date: Thu, 9 Jul 2026 19:46:47 +0530
Subject: [PATCH] [X86][APX] Optimize usub.sat(X,1) to cmp+adc with NDD
---
llvm/lib/Target/X86/X86ISelLowering.cpp | 26 ++++-
llvm/test/CodeGen/X86/apx/sub.ll | 125 ++++++++++++++++++++++++
2 files changed, 149 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 2032370a3221b..93f292ae534b3 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -1394,7 +1394,14 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::SUB, MVT::i16, Custom);
setOperationAction(ISD::SUB, MVT::i32, Custom);
}
-
+ if (Subtarget.hasNDD()) {
+ // Enable custom lowering for scalar USUBSAT to optimize usub.sat(X,1)
+ // with cmp+adc when NDD is available.
+ setOperationAction(ISD::USUBSAT, MVT::i8, Custom);
+ setOperationAction(ISD::USUBSAT, MVT::i16, Custom);
+ setOperationAction(ISD::USUBSAT, MVT::i32, Custom);
+ setOperationAction(ISD::USUBSAT, MVT::i64, Custom);
+ }
if (!Subtarget.useSoftFloat() && Subtarget.hasSSE41()) {
for (MVT RoundedTy : {MVT::f32, MVT::f64, MVT::v4f32, MVT::v2f64}) {
setOperationAction(ISD::FFLOOR, RoundedTy, Legal);
@@ -29618,7 +29625,6 @@ static SDValue lowerAddSub(SDValue Op, SelectionDAG &DAG,
const X86Subtarget &Subtarget) {
MVT VT = Op.getSimpleValueType();
SDLoc DL(Op);
-
if (VT == MVT::i16 || VT == MVT::i32)
return lowerAddSubToHorizontalOp(Op, DL, DAG, Subtarget);
@@ -29638,6 +29644,22 @@ static SDValue LowerADDSAT_SUBSAT(SDValue Op, SelectionDAG &DAG,
unsigned Opcode = Op.getOpcode();
SDLoc DL(Op);
+ if (Opcode == ISD::USUBSAT && !VT.isVector() && Subtarget.hasNDD()) {
+ if (auto *C = dyn_cast<ConstantSDNode>(Y)) {
+ if (C->isOne()) {
+ // usub.sat(X,1) == (X==0 ? 0 : X-1). Lower to cmp+adc with NDD.
+ SDValue Sub = DAG.getNode(X86ISD::SUB, DL, DAG.getVTList(VT, MVT::i32),
+ X, DAG.getConstant(1, DL, VT));
+ SDValue EFLAGS = Sub.getValue(1);
+ SDValue MinusOne = DAG.getAllOnesConstant(DL, VT);
+ return DAG.getNode(X86ISD::ADC, DL, DAG.getVTList(VT, MVT::i32), X,
+ MinusOne, EFLAGS);
+ }
+ }
+ // Scalar USUBSAT was previously Expand. Don't fall through to vector path.
+ return SDValue();
+ }
+
if (VT == MVT::v32i16 || VT == MVT::v64i8 ||
(VT.is256BitVector() && !Subtarget.hasInt256())) {
assert(Op.getSimpleValueType().isInteger() &&
diff --git a/llvm/test/CodeGen/X86/apx/sub.ll b/llvm/test/CodeGen/X86/apx/sub.ll
index 34af966465d93..1e287c992160d 100644
--- a/llvm/test/CodeGen/X86/apx/sub.ll
+++ b/llvm/test/CodeGen/X86/apx/sub.ll
@@ -1238,3 +1238,128 @@ bb2: ; preds = %bb2, %bb1
store ptr null, ptr %arg2, align 8
br i1 %arg3, label %bb1, label %bb2
}
+;
+define i8 @usubsat8_const1(i8 noundef %a) {
+; CHECK-LABEL: usubsat8_const1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: cmpb $1, %dil # encoding: [0x40,0x80,0xff,0x01]
+; CHECK-NEXT: adcb $-1, %dil, %al # encoding: [0x62,0xf4,0x7c,0x18,0x80,0xd7,0xff]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NF-LABEL: usubsat8_const1:
+; NF: # %bb.0: # %entry
+; NF-NEXT: cmpb $1, %dil # encoding: [0x40,0x80,0xff,0x01]
+; NF-NEXT: adcb $-1, %dil, %al # encoding: [0x62,0xf4,0x7c,0x18,0x80,0xd7,0xff]
+; NF-NEXT: retq # encoding: [0xc3]
+entry:
+ %sub = call i8 @llvm.usub.sat.i8(i8 %a, i8 1)
+ ret i8 %sub
+}
+
+define i16 @usubsat16_const1(i16 noundef %a) {
+; CHECK-LABEL: usubsat16_const1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: cmpw $1, %di # encoding: [0x66,0x83,0xff,0x01]
+; CHECK-NEXT: adcw $-1, %di, %ax # encoding: [0x62,0xf4,0x7d,0x18,0x83,0xd7,0xff]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NF-LABEL: usubsat16_const1:
+; NF: # %bb.0: # %entry
+; NF-NEXT: cmpw $1, %di # encoding: [0x66,0x83,0xff,0x01]
+; NF-NEXT: adcw $-1, %di, %ax # encoding: [0x62,0xf4,0x7d,0x18,0x83,0xd7,0xff]
+; NF-NEXT: retq # encoding: [0xc3]
+entry:
+ %sub = call i16 @llvm.usub.sat.i16(i16 %a, i16 1)
+ ret i16 %sub
+}
+
+define i32 @usubsat32_const1(i32 noundef %a) {
+; CHECK-LABEL: usubsat32_const1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: cmpl $1, %edi # encoding: [0x83,0xff,0x01]
+; CHECK-NEXT: adcl $-1, %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0x83,0xd7,0xff]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NF-LABEL: usubsat32_const1:
+; NF: # %bb.0: # %entry
+; NF-NEXT: cmpl $1, %edi # encoding: [0x83,0xff,0x01]
+; NF-NEXT: adcl $-1, %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0x83,0xd7,0xff]
+; NF-NEXT: retq # encoding: [0xc3]
+entry:
+ %sub = call i32 @llvm.usub.sat.i32(i32 %a, i32 1)
+ ret i32 %sub
+}
+
+define i64 @usubsat64_const1(i64 noundef %a) {
+; CHECK-LABEL: usubsat64_const1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: cmpq $1, %rdi # encoding: [0x48,0x83,0xff,0x01]
+; CHECK-NEXT: adcq $-1, %rdi, %rax # encoding: [0x62,0xf4,0xfc,0x18,0x83,0xd7,0xff]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NF-LABEL: usubsat64_const1:
+; NF: # %bb.0: # %entry
+; NF-NEXT: cmpq $1, %rdi # encoding: [0x48,0x83,0xff,0x01]
+; NF-NEXT: adcq $-1, %rdi, %rax # encoding: [0x62,0xf4,0xfc,0x18,0x83,0xd7,0xff]
+; NF-NEXT: retq # encoding: [0xc3]
+entry:
+ %sub = call i64 @llvm.usub.sat.i64(i64 %a, i64 1)
+ ret i64 %sub
+}
+
+define i32 @usubsat32_var(i32 noundef %a, i32 noundef %b) {
+; CHECK-LABEL: usubsat32_var:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0]
+; CHECK-NEXT: subl %esi, %edi # EVEX TO LEGACY Compression encoding: [0x29,0xf7]
+; CHECK-NEXT: cmovael %edi, %eax # EVEX TO LEGACY Compression encoding: [0x0f,0x43,0xc7]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NF-LABEL: usubsat32_var:
+; NF: # %bb.0: # %entry
+; NF-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0]
+; NF-NEXT: subl %esi, %edi # EVEX TO LEGACY Compression encoding: [0x29,0xf7]
+; NF-NEXT: cmovael %edi, %eax # EVEX TO LEGACY Compression encoding: [0x0f,0x43,0xc7]
+; NF-NEXT: retq # encoding: [0xc3]
+entry:
+ %sub = call i32 @llvm.usub.sat.i32(i32 %a, i32 %b)
+ ret i32 %sub
+}
+
+define i32 @usubsat32_const123(i32 noundef %a) {
+; CHECK-LABEL: usubsat32_const123:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0]
+; CHECK-NEXT: subl $123, %edi # EVEX TO LEGACY Compression encoding: [0x83,0xef,0x7b]
+; CHECK-NEXT: cmovael %edi, %eax # EVEX TO LEGACY Compression encoding: [0x0f,0x43,0xc7]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NF-LABEL: usubsat32_const123:
+; NF: # %bb.0: # %entry
+; NF-NEXT: xorl %eax, %eax # encoding: [0x31,0xc0]
+; NF-NEXT: subl $123, %edi # EVEX TO LEGACY Compression encoding: [0x83,0xef,0x7b]
+; NF-NEXT: cmovael %edi, %eax # EVEX TO LEGACY Compression encoding: [0x0f,0x43,0xc7]
+; NF-NEXT: retq # encoding: [0xc3]
+entry:
+ %sub = call i32 @llvm.usub.sat.i32(i32 %a, i32 123)
+ ret i32 %sub
+}
+
+define i32 @uaddsat32_const1(i32 noundef %a) {
+; CHECK-LABEL: uaddsat32_const1:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: incl %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0xff,0xc7]
+; CHECK-NEXT: movl $-1, %ecx # encoding: [0xb9,0xff,0xff,0xff,0xff]
+; CHECK-NEXT: cmovel %ecx, %eax # EVEX TO LEGACY Compression encoding: [0x0f,0x44,0xc1]
+; CHECK-NEXT: retq # encoding: [0xc3]
+;
+; NF-LABEL: uaddsat32_const1:
+; NF: # %bb.0: # %entry
+; NF-NEXT: incl %edi, %eax # encoding: [0x62,0xf4,0x7c,0x18,0xff,0xc7]
+; NF-NEXT: movl $-1, %ecx # encoding: [0xb9,0xff,0xff,0xff,0xff]
+; NF-NEXT: cmovel %ecx, %eax # EVEX TO LEGACY Compression encoding: [0x0f,0x44,0xc1]
+; NF-NEXT: retq # encoding: [0xc3]
+entry:
+ %add = call i32 @llvm.uadd.sat.i32(i32 %a, i32 1)
+ ret i32 %add
+}
More information about the llvm-commits
mailing list