[llvm] [AMDGPU] Fold saddsat(x, -C) to ssubsat(x, C) when C is an inline constant (PR #216592)
Madhur Kumar via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 16 14:12:42 PDT 2026
https://github.com/MadhurKumar004 updated https://github.com/llvm/llvm-project/pull/216592
>From 834d52e6e4610405a1442ef4800636c5ffa167e5 Mon Sep 17 00:00:00 2001
From: Madhur Kumar <madhurkumar004 at gmail.com>
Date: Mon, 17 Aug 2026 00:18:40 +0530
Subject: [PATCH 1/2] Pre-commit test
---
llvm/test/CodeGen/AMDGPU/saddsat.ll | 413 ++++++++++++++++++++++++++++
1 file changed, 413 insertions(+)
diff --git a/llvm/test/CodeGen/AMDGPU/saddsat.ll b/llvm/test/CodeGen/AMDGPU/saddsat.ll
index 0dbcd70bcad2c..d7804af84af70 100644
--- a/llvm/test/CodeGen/AMDGPU/saddsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/saddsat.ll
@@ -116,6 +116,245 @@ define i16 @v_saddsat_i16(i16 %lhs, i16 %rhs) {
ret i16 %result
}
+define i16 @saddsat_i16_neg32(i16 %lhs) {
+; GFX6-LABEL: saddsat_i16_neg32:
+; GFX6: ; %bb.0:
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_bfe_i32 v0, v0, 0, 16
+; GFX6-NEXT: v_subrev_i32_e32 v0, vcc, 32, v0
+; GFX6-NEXT: s_movk_i32 s4, 0x8000
+; GFX6-NEXT: v_mov_b32_e32 v1, 0x7fff
+; GFX6-NEXT: v_med3_i32 v0, v0, s4, v1
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_i16_neg32:
+; GFX8: ; %bb.0:
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_subrev_u16_e32 v1, 32, v0
+; GFX8-NEXT: v_mov_b32_e32 v2, 0xffff8000
+; GFX8-NEXT: v_cmp_lt_i16_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_i16_neg32:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_movk_i32 s4, 0xffe0
+; GFX9-NEXT: v_add_i16 v0, v0, s4 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: saddsat_i16_neg32:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: v_add_nc_i16 v0, v0, 0xffe0 clamp
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: saddsat_i16_neg32:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, 0xffe0 clamp
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: saddsat_i16_neg32:
+; GFX11-FAKE16: ; %bb.0:
+; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, 0xffe0 clamp
+; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+ %result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -32)
+ ret i16 %result
+}
+
+define i16 @saddsat_i16_neg64(i16 %lhs) {
+; GFX6-LABEL: saddsat_i16_neg64:
+; GFX6: ; %bb.0:
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_bfe_i32 v0, v0, 0, 16
+; GFX6-NEXT: v_subrev_i32_e32 v0, vcc, 64, v0
+; GFX6-NEXT: s_movk_i32 s4, 0x8000
+; GFX6-NEXT: v_mov_b32_e32 v1, 0x7fff
+; GFX6-NEXT: v_med3_i32 v0, v0, s4, v1
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_i16_neg64:
+; GFX8: ; %bb.0:
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_subrev_u16_e32 v1, 64, v0
+; GFX8-NEXT: v_mov_b32_e32 v2, 0xffff8000
+; GFX8-NEXT: v_cmp_lt_i16_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_i16_neg64:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_movk_i32 s4, 0xffc0
+; GFX9-NEXT: v_add_i16 v0, v0, s4 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: saddsat_i16_neg64:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: v_add_nc_i16 v0, v0, 0xffc0 clamp
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: saddsat_i16_neg64:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, 0xffc0 clamp
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: saddsat_i16_neg64:
+; GFX11-FAKE16: ; %bb.0:
+; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, 0xffc0 clamp
+; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+ %result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -64)
+ ret i16 %result
+}
+
+define i16 @saddsat_i16_neg17(i16 %lhs) {
+; GFX6-LABEL: saddsat_i16_neg17:
+; GFX6: ; %bb.0:
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_bfe_i32 v0, v0, 0, 16
+; GFX6-NEXT: v_subrev_i32_e32 v0, vcc, 17, v0
+; GFX6-NEXT: s_movk_i32 s4, 0x8000
+; GFX6-NEXT: v_mov_b32_e32 v1, 0x7fff
+; GFX6-NEXT: v_med3_i32 v0, v0, s4, v1
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_i16_neg17:
+; GFX8: ; %bb.0:
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_subrev_u16_e32 v1, 17, v0
+; GFX8-NEXT: v_mov_b32_e32 v2, 0xffff8000
+; GFX8-NEXT: v_cmp_lt_i16_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_i16_neg17:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_movk_i32 s4, 0xffef
+; GFX9-NEXT: v_add_i16 v0, v0, s4 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: saddsat_i16_neg17:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: v_add_nc_i16 v0, v0, 0xffef clamp
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: saddsat_i16_neg17:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, 0xffef clamp
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: saddsat_i16_neg17:
+; GFX11-FAKE16: ; %bb.0:
+; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, 0xffef clamp
+; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+ %result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -17)
+ ret i16 %result
+}
+
+define i16 @saddsat_i16_neg16(i16 %lhs) {
+; GFX6-LABEL: saddsat_i16_neg16:
+; GFX6: ; %bb.0:
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_bfe_i32 v0, v0, 0, 16
+; GFX6-NEXT: v_add_i32_e32 v0, vcc, -16, v0
+; GFX6-NEXT: s_movk_i32 s4, 0x8000
+; GFX6-NEXT: v_mov_b32_e32 v1, 0x7fff
+; GFX6-NEXT: v_med3_i32 v0, v0, s4, v1
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_i16_neg16:
+; GFX8: ; %bb.0:
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_add_u16_e32 v1, -16, v0
+; GFX8-NEXT: v_mov_b32_e32 v2, 0xffff8000
+; GFX8-NEXT: v_cmp_lt_i16_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_i16_neg16:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_add_i16 v0, v0, -16 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: saddsat_i16_neg16:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: v_add_nc_i16 v0, v0, -16 clamp
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: saddsat_i16_neg16:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, -16 clamp
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: saddsat_i16_neg16:
+; GFX11-FAKE16: ; %bb.0:
+; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, -16 clamp
+; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+ %result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -16)
+ ret i16 %result
+}
+
+define i16 @saddsat_i16_neg65(i16 %lhs) {
+; GFX6-LABEL: saddsat_i16_neg65:
+; GFX6: ; %bb.0:
+; GFX6-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX6-NEXT: v_bfe_i32 v0, v0, 0, 16
+; GFX6-NEXT: v_add_i32_e32 v0, vcc, 0xffffffbf, v0
+; GFX6-NEXT: s_movk_i32 s4, 0x8000
+; GFX6-NEXT: v_mov_b32_e32 v1, 0x7fff
+; GFX6-NEXT: v_med3_i32 v0, v0, s4, v1
+; GFX6-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: saddsat_i16_neg65:
+; GFX8: ; %bb.0:
+; GFX8-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT: v_add_u16_e32 v1, 0xffbf, v0
+; GFX8-NEXT: v_mov_b32_e32 v2, 0xffff8000
+; GFX8-NEXT: v_cmp_lt_i16_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_i16_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_i16 v0, v0, s4 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: saddsat_i16_neg65:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: v_add_nc_i16 v0, v0, 0xffbf clamp
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: saddsat_i16_neg65:
+; GFX11-TRUE16: ; %bb.0:
+; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, 0xffbf clamp
+; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: saddsat_i16_neg65:
+; GFX11-FAKE16: ; %bb.0:
+; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, 0xffbf clamp
+; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
+ %result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -65)
+ ret i16 %result
+}
+
define i32 @v_saddsat_i32(i32 %lhs, i32 %rhs) {
; GFX6-LABEL: v_saddsat_i32:
; GFX6: ; %bb.0:
@@ -154,6 +393,180 @@ define i32 @v_saddsat_i32(i32 %lhs, i32 %rhs) {
ret i32 %result
}
+define i32 @saddsat_i32_neg32(i32 %x) {
+; GFX6-LABEL: saddsat_i32_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_i32_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_i32_neg32:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_movk_i32 s4, 0xffe0
+; GFX9-NEXT: v_add_i32 v0, v0, s4 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_i32_neg32:
+; GFX10PLUS: ; %bb.0:
+; GFX10PLUS-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT: v_add_nc_i32 v0, 0xffffffe0, v0 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_i32_neg64(i32 %x) {
+; GFX6-LABEL: saddsat_i32_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_i32_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_i32_neg64:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_movk_i32 s4, 0xffc0
+; GFX9-NEXT: v_add_i32 v0, v0, s4 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_i32_neg64:
+; GFX10PLUS: ; %bb.0:
+; GFX10PLUS-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT: v_add_nc_i32 v0, 0xffffffc0, v0 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_i32_neg17(i32 %x) {
+; GFX6-LABEL: saddsat_i32_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_i32_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_i32_neg17:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_movk_i32 s4, 0xffef
+; GFX9-NEXT: v_add_i32 v0, v0, s4 clamp
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10PLUS-LABEL: saddsat_i32_neg17:
+; GFX10PLUS: ; %bb.0:
+; GFX10PLUS-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10PLUS-NEXT: v_add_nc_i32 v0, 0xffffffef, v0 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_i32_neg16(i32 %x) {
+; GFX6-LABEL: saddsat_i32_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_i32_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_i32_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_i32_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_i32_neg65(i32 %x) {
+; GFX6-LABEL: saddsat_i32_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_i32_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_i32_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_i32_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 <2 x i16> @v_saddsat_v2i16(<2 x i16> %lhs, <2 x i16> %rhs) {
; GFX6-LABEL: v_saddsat_v2i16:
; GFX6: ; %bb.0:
>From 2d34eba1ef7962e611800c3261eeb6c859aec1c8 Mon Sep 17 00:00:00 2001
From: Madhur Kumar <madhurkumar004 at gmail.com>
Date: Mon, 17 Aug 2026 02:42:21 +0530
Subject: [PATCH 2/2] [AMDGPU] Fold saddsat(x, -C) to ssubsat(x, C) when C is
an inline constant
---
llvm/lib/Target/AMDGPU/VOP3Instructions.td | 25 +++++++++++++
llvm/lib/Target/AMDGPU/VOPInstructions.td | 1 -
llvm/test/CodeGen/AMDGPU/saddsat.ll | 42 ++++++++++------------
3 files changed, 43 insertions(+), 25 deletions(-)
diff --git a/llvm/lib/Target/AMDGPU/VOP3Instructions.td b/llvm/lib/Target/AMDGPU/VOP3Instructions.td
index 7fc252a65d065..eea542cf5eac3 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)),
@@ -1029,14 +1033,35 @@ class OpSelBinOpClampPat<SDPatternOperator node,
let SubtargetPredicate = isGFX9Plus, True16Predicate = NotHasTrue16BitInsts in {
def : OpSelBinOpClampPat<saddsat, V_ADD_I16_e64>;
def : OpSelBinOpClampPat<ssubsat, V_SUB_I16_e64>;
+
+ let AddedComplexity = 15 in {
+ def : GCNPat<
+ (saddsat i16:$src0, (i16 NegSubInlineIntConst16:$src1)),
+ (V_SUB_I16_e64 (i32 0), VSrc_b16:$src0, (i32 0),
+ NegSubInlineIntConst16:$src1, DSTCLAMP.ENABLE, (i32 0))>;
+ }
} // End SubtargetPredicate = isGFX9Plus, True16Predicate = NotHasTrue16BitInsts
let True16Predicate = UseRealTrue16Insts in {
def : OpSelBinOpClampPat<saddsat, V_ADD_I16_t16_e64>;
def : OpSelBinOpClampPat<ssubsat, V_SUB_I16_t16_e64>;
+
+ let AddedComplexity = 15 in {
+ def : GCNPat<
+ (saddsat i16:$src0, (i16 NegSubInlineIntConst16:$src1)),
+ (V_SUB_I16_t16_e64 (i32 0), VSrcT_b16:$src0, (i32 0),
+ NegSubInlineIntConst16:$src1, DSTCLAMP.ENABLE, (i32 0))>;
+ }
} // End True16Predicate = UseRealTrue16Insts
let True16Predicate = UseFakeTrue16Insts in {
def : OpSelBinOpClampPat<saddsat, V_ADD_I16_fake16_e64>;
def : OpSelBinOpClampPat<ssubsat, V_SUB_I16_fake16_e64>;
+
+ let AddedComplexity = 15 in {
+ def : GCNPat<
+ (saddsat i16:$src0, (i16 NegSubInlineIntConst16:$src1)),
+ (V_SUB_I16_fake16_e64 (i32 0), VSrc_b16:$src0, (i32 0),
+ NegSubInlineIntConst16:$src1, DSTCLAMP.ENABLE, (i32 0))>;
+ }
} // End True16Predicate = UseFakeTrue16Insts
multiclass IMAD32_Pats <VOP3_Pseudo inst> {
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 d7804af84af70..5823fbaa8ce9c 100644
--- a/llvm/test/CodeGen/AMDGPU/saddsat.ll
+++ b/llvm/test/CodeGen/AMDGPU/saddsat.ll
@@ -139,26 +139,25 @@ define i16 @saddsat_i16_neg32(i16 %lhs) {
; GFX9-LABEL: saddsat_i16_neg32:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT: s_movk_i32 s4, 0xffe0
-; GFX9-NEXT: v_add_i16 v0, v0, s4 clamp
+; GFX9-NEXT: v_sub_i16 v0, v0, 32 clamp
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
; GFX10-LABEL: saddsat_i16_neg32:
; GFX10: ; %bb.0:
; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT: v_add_nc_i16 v0, v0, 0xffe0 clamp
+; GFX10-NEXT: v_sub_nc_i16 v0, v0, 32 clamp
; GFX10-NEXT: s_setpc_b64 s[30:31]
;
; GFX11-TRUE16-LABEL: saddsat_i16_neg32:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, 0xffe0 clamp
+; GFX11-TRUE16-NEXT: v_sub_nc_i16 v0.l, v0.l, 32 clamp
; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
;
; GFX11-FAKE16-LABEL: saddsat_i16_neg32:
; GFX11-FAKE16: ; %bb.0:
; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, 0xffe0 clamp
+; GFX11-FAKE16-NEXT: v_sub_nc_i16 v0, v0, 32 clamp
; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
%result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -32)
ret i16 %result
@@ -187,26 +186,25 @@ define i16 @saddsat_i16_neg64(i16 %lhs) {
; GFX9-LABEL: saddsat_i16_neg64:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT: s_movk_i32 s4, 0xffc0
-; GFX9-NEXT: v_add_i16 v0, v0, s4 clamp
+; GFX9-NEXT: v_sub_i16 v0, v0, 64 clamp
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
; GFX10-LABEL: saddsat_i16_neg64:
; GFX10: ; %bb.0:
; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT: v_add_nc_i16 v0, v0, 0xffc0 clamp
+; GFX10-NEXT: v_sub_nc_i16 v0, v0, 64 clamp
; GFX10-NEXT: s_setpc_b64 s[30:31]
;
; GFX11-TRUE16-LABEL: saddsat_i16_neg64:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, 0xffc0 clamp
+; GFX11-TRUE16-NEXT: v_sub_nc_i16 v0.l, v0.l, 64 clamp
; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
;
; GFX11-FAKE16-LABEL: saddsat_i16_neg64:
; GFX11-FAKE16: ; %bb.0:
; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, 0xffc0 clamp
+; GFX11-FAKE16-NEXT: v_sub_nc_i16 v0, v0, 64 clamp
; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
%result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -64)
ret i16 %result
@@ -235,26 +233,25 @@ define i16 @saddsat_i16_neg17(i16 %lhs) {
; GFX9-LABEL: saddsat_i16_neg17:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT: s_movk_i32 s4, 0xffef
-; GFX9-NEXT: v_add_i16 v0, v0, s4 clamp
+; GFX9-NEXT: v_sub_i16 v0, v0, 17 clamp
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
; GFX10-LABEL: saddsat_i16_neg17:
; GFX10: ; %bb.0:
; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT: v_add_nc_i16 v0, v0, 0xffef clamp
+; GFX10-NEXT: v_sub_nc_i16 v0, v0, 17 clamp
; GFX10-NEXT: s_setpc_b64 s[30:31]
;
; GFX11-TRUE16-LABEL: saddsat_i16_neg17:
; GFX11-TRUE16: ; %bb.0:
; GFX11-TRUE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-TRUE16-NEXT: v_add_nc_i16 v0.l, v0.l, 0xffef clamp
+; GFX11-TRUE16-NEXT: v_sub_nc_i16 v0.l, v0.l, 17 clamp
; GFX11-TRUE16-NEXT: s_setpc_b64 s[30:31]
;
; GFX11-FAKE16-LABEL: saddsat_i16_neg17:
; GFX11-FAKE16: ; %bb.0:
; GFX11-FAKE16-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-FAKE16-NEXT: v_add_nc_i16 v0, v0, 0xffef clamp
+; GFX11-FAKE16-NEXT: v_sub_nc_i16 v0, v0, 17 clamp
; GFX11-FAKE16-NEXT: s_setpc_b64 s[30:31]
%result = call i16 @llvm.sadd.sat.i16(i16 %lhs, i16 -17)
ret i16 %result
@@ -415,14 +412,13 @@ define i32 @saddsat_i32_neg32(i32 %x) {
; GFX9-LABEL: saddsat_i32_neg32:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT: s_movk_i32 s4, 0xffe0
-; GFX9-NEXT: v_add_i32 v0, v0, s4 clamp
+; GFX9-NEXT: v_sub_i32 v0, v0, 32 clamp
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
; GFX10PLUS-LABEL: saddsat_i32_neg32:
; GFX10PLUS: ; %bb.0:
; GFX10PLUS-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10PLUS-NEXT: v_add_nc_i32 v0, 0xffffffe0, v0 clamp
+; 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
@@ -450,14 +446,13 @@ define i32 @saddsat_i32_neg64(i32 %x) {
; GFX9-LABEL: saddsat_i32_neg64:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT: s_movk_i32 s4, 0xffc0
-; GFX9-NEXT: v_add_i32 v0, v0, s4 clamp
+; GFX9-NEXT: v_sub_i32 v0, v0, 64 clamp
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
; GFX10PLUS-LABEL: saddsat_i32_neg64:
; GFX10PLUS: ; %bb.0:
; GFX10PLUS-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10PLUS-NEXT: v_add_nc_i32 v0, 0xffffffc0, v0 clamp
+; 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
@@ -485,14 +480,13 @@ define i32 @saddsat_i32_neg17(i32 %x) {
; GFX9-LABEL: saddsat_i32_neg17:
; GFX9: ; %bb.0:
; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT: s_movk_i32 s4, 0xffef
-; GFX9-NEXT: v_add_i32 v0, v0, s4 clamp
+; GFX9-NEXT: v_sub_i32 v0, v0, 17 clamp
; GFX9-NEXT: s_setpc_b64 s[30:31]
;
; GFX10PLUS-LABEL: saddsat_i32_neg17:
; GFX10PLUS: ; %bb.0:
; GFX10PLUS-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10PLUS-NEXT: v_add_nc_i32 v0, 0xffffffef, v0 clamp
+; 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
More information about the llvm-commits
mailing list