[llvm] [AMDGPU] Fold saddsat(x, -C) to ssubsat(x, C) when C is an inline constant (PR #216592)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 16 12:02:10 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-amdgpu

Author: Madhur Kumar (MadhurKumar004)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/216592.diff


3 Files Affected:

- (modified) llvm/lib/Target/AMDGPU/VOP3Instructions.td (+4) 
- (modified) llvm/lib/Target/AMDGPU/VOPInstructions.td (-1) 
- (modified) llvm/test/CodeGen/AMDGPU/saddsat.ll (+209) 


``````````diff
diff --git a/llvm/lib/Target/AMDGPU/VOP3Instructions.td b/llvm/lib/Target/AMDGPU/VOP3Instructions.td
index 7fc252a65d065..afc47c8bd50ba 100644
--- a/llvm/lib/Target/AMDGPU/VOP3Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP3Instructions.td
@@ -1002,6 +1002,10 @@ def : ThreeOp_i32_Pats<uaddsat, umin, V_ADD_MIN_U32_e64>;
 def : VOPBinOpClampPat<saddsat, V_ADD_I32_e64, i32>;
 def : VOPBinOpClampPat<ssubsat, V_SUB_I32_e64, i32>;
 
+def : GCNPat<
+  (saddsat i32:$src0, (i32 NegSubInlineConst32:$src1)),
+  (V_SUB_I32_e64 VSrc_b32:$src0, NegSubInlineConst32:$src1, DSTCLAMP.ENABLE)>;
+
 def : GCNPat<(DivergentBinFrag<or> (or_oneuse i64:$src0, i64:$src1), i64:$src2),
              (REG_SEQUENCE VReg_64,
                (V_OR3_B32_e64 (i32 (EXTRACT_SUBREG $src0, sub0)),
diff --git a/llvm/lib/Target/AMDGPU/VOPInstructions.td b/llvm/lib/Target/AMDGPU/VOPInstructions.td
index a379785616c6c..b64165748eb98 100644
--- a/llvm/lib/Target/AMDGPU/VOPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPInstructions.td
@@ -1365,7 +1365,6 @@ class getVSrcOp<ValueType vt> {
 }
 
 // Class for binary integer operations with the clamp bit set for saturation
-// TODO: Add sub with negated inline constant pattern.
 class VOPBinOpClampPat<SDPatternOperator node, Instruction inst, ValueType vt> :
   GCNPat<(node vt:$src0, vt:$src1),
          (inst getVSrcOp<vt>.ret:$src0, getVSrcOp<vt>.ret:$src1,
diff --git a/llvm/test/CodeGen/AMDGPU/saddsat.ll b/llvm/test/CodeGen/AMDGPU/saddsat.ll
index 0dbcd70bcad2c..e5636a84aa5da 100644
--- a/llvm/test/CodeGen/AMDGPU/saddsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/saddsat.ll
@@ -492,6 +492,215 @@ define i64 @v_saddsat_i64(i64 %lhs, i64 %rhs) {
   ret i64 %result
 }
 
+define i32 @saddsat_neg32(i32 %x) {
+; GFX6-LABEL: saddsat_neg32:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_subrev_i32_e32 v1, vcc, 32, v0
+; GFX6-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX6-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX6-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_neg32:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_subrev_u32_e32 v1, vcc, 32, v0
+; GFX8-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX8-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX8-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: saddsat_neg32:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_sub_i32 v0, v0, 32 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_neg32:
+; GFX10PLUS:       ; %bb.0:
+; GFX10PLUS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT:    v_sub_nc_i32 v0, v0, 32 clamp
+; GFX10PLUS-NEXT:    s_setpc_b64 s[30:31]
+  %r = call i32 @llvm.sadd.sat.i32(i32 %x, i32 -32)
+  ret i32 %r
+}
+
+define i32 @saddsat_neg64(i32 %x) {
+; GFX6-LABEL: saddsat_neg64:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_subrev_i32_e32 v1, vcc, 64, v0
+; GFX6-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX6-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX6-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_neg64:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_subrev_u32_e32 v1, vcc, 64, v0
+; GFX8-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX8-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX8-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: saddsat_neg64:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_sub_i32 v0, v0, 64 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_neg64:
+; GFX10PLUS:       ; %bb.0:
+; GFX10PLUS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT:    v_sub_nc_i32 v0, v0, 64 clamp
+; GFX10PLUS-NEXT:    s_setpc_b64 s[30:31]
+  %r = call i32 @llvm.sadd.sat.i32(i32 %x, i32 -64)
+  ret i32 %r
+}
+
+define i32 @saddsat_neg17(i32 %x) {
+; GFX6-LABEL: saddsat_neg17:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_subrev_i32_e32 v1, vcc, 17, v0
+; GFX6-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX6-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX6-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_neg17:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_subrev_u32_e32 v1, vcc, 17, v0
+; GFX8-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX8-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX8-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: saddsat_neg17:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_sub_i32 v0, v0, 17 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_neg17:
+; GFX10PLUS:       ; %bb.0:
+; GFX10PLUS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT:    v_sub_nc_i32 v0, v0, 17 clamp
+; GFX10PLUS-NEXT:    s_setpc_b64 s[30:31]
+  %r = call i32 @llvm.sadd.sat.i32(i32 %x, i32 -17)
+  ret i32 %r
+}
+
+define i32 @saddsat_neg16(i32 %x) {
+; GFX6-LABEL: saddsat_neg16:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_add_i32_e32 v1, vcc, -16, v0
+; GFX6-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX6-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX6-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_neg16:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_u32_e32 v1, vcc, -16, v0
+; GFX8-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX8-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX8-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: saddsat_neg16:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_i32 v0, v0, -16 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_neg16:
+; GFX10PLUS:       ; %bb.0:
+; GFX10PLUS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT:    v_add_nc_i32 v0, v0, -16 clamp
+; GFX10PLUS-NEXT:    s_setpc_b64 s[30:31]
+  %r = call i32 @llvm.sadd.sat.i32(i32 %x, i32 -16)
+  ret i32 %r
+}
+
+define i32 @saddsat_neg65(i32 %x) {
+; GFX6-LABEL: saddsat_neg65:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_add_i32_e32 v1, vcc, 0xffffffbf, v0
+; GFX6-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX6-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX6-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_neg65:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_add_u32_e32 v1, vcc, 0xffffffbf, v0
+; GFX8-NEXT:    v_bfrev_b32_e32 v2, 1
+; GFX8-NEXT:    v_cmp_lt_i32_e32 vcc, v1, v0
+; GFX8-NEXT:    v_cndmask_b32_e32 v0, v2, v1, vcc
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: saddsat_neg65:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    s_movk_i32 s4, 0xffbf
+; GFX9-NEXT:    v_add_i32 v0, v0, s4 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_neg65:
+; GFX10PLUS:       ; %bb.0:
+; GFX10PLUS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT:    v_add_nc_i32 v0, 0xffffffbf, v0 clamp
+; GFX10PLUS-NEXT:    s_setpc_b64 s[30:31]
+  %r = call i32 @llvm.sadd.sat.i32(i32 %x, i32 -65)
+  ret i32 %r
+}
+
+define i32 @saddsat_reg(i32 %x, i32 %y) {
+; GFX6-LABEL: saddsat_reg:
+; GFX6:       ; %bb.0:
+; GFX6-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT:    v_cmp_gt_i32_e32 vcc, 0, v1
+; GFX6-NEXT:    v_add_i32_e64 v1, s[4:5], v0, v1
+; GFX6-NEXT:    v_cmp_lt_i32_e64 s[4:5], v1, v0
+; GFX6-NEXT:    v_ashrrev_i32_e32 v0, 31, v1
+; GFX6-NEXT:    s_xor_b64 s[4:5], vcc, s[4:5]
+; GFX6-NEXT:    v_cndmask_b32_e64 v0, v1, -v0, s[4:5]
+; GFX6-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_reg:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_cmp_gt_i32_e32 vcc, 0, v1
+; GFX8-NEXT:    v_add_u32_e64 v1, s[4:5], v0, v1
+; GFX8-NEXT:    v_cmp_lt_i32_e64 s[4:5], v1, v0
+; GFX8-NEXT:    v_ashrrev_i32_e32 v0, 31, v1
+; GFX8-NEXT:    s_xor_b64 s[4:5], vcc, s[4:5]
+; GFX8-NEXT:    v_cndmask_b32_e64 v0, v1, -v0, s[4:5]
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: saddsat_reg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_add_i32 v0, v0, v1 clamp
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_reg:
+; GFX10PLUS:       ; %bb.0:
+; GFX10PLUS-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT:    v_add_nc_i32 v0, v0, v1 clamp
+; GFX10PLUS-NEXT:    s_setpc_b64 s[30:31]
+  %r = call i32 @llvm.sadd.sat.i32(i32 %x, i32 %y)
+  ret i32 %r
+}
+
 declare i8 @llvm.sadd.sat.i8(i8, i8) #0
 declare i16 @llvm.sadd.sat.i16(i16, i16) #0
 declare <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16>, <2 x i16>) #0

``````````

</details>


https://github.com/llvm/llvm-project/pull/216592


More information about the llvm-commits mailing list