[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