[llvm] b142e77 - [AMDGPU][GlobalISel] Don't combine uniform fmin/max into clamp/fmed3 (#211456)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 23 06:33:39 PDT 2026
Author: Syadus Sefat
Date: 2026-07-23T08:33:34-05:00
New Revision: b142e77672d2992640e4f31c54d771191a0b8610
URL: https://github.com/llvm/llvm-project/commit/b142e77672d2992640e4f31c54d771191a0b8610
DIFF: https://github.com/llvm/llvm-project/commit/b142e77672d2992640e4f31c54d771191a0b8610.diff
LOG: [AMDGPU][GlobalISel] Don't combine uniform fmin/max into clamp/fmed3 (#211456)
Uniform fmin/fmax/fmed3 makes the reg-bank combiner produce a
clamp/fmed3 with an sgpr-banked destination. As these clamp/fmed3 only
have VALU selection patterns, the sgpr bank cannot be selected. Only
combine when the destination is vgpr-banked.
Added:
Modified:
llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
Removed:
################################################################################
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
index baf83e7f7762a..4cd7577e83e82 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
@@ -251,6 +251,10 @@ bool AMDGPURegBankCombinerImpl::matchIntMinMaxToMed3(
bool AMDGPURegBankCombinerImpl::matchFPMinMaxToMed3(
MachineInstr &MI, Med3MatchInfo &MatchInfo) const {
Register Dst = MI.getOperand(0).getReg();
+ // Perform combine only when the destination is a VGPR.
+ if (!isVgprRegBank(Dst))
+ return false;
+
LLT Ty = MRI.getType(Dst);
// med3 for f16 is only available on gfx9+, and not available for v2f16.
@@ -289,6 +293,10 @@ bool AMDGPURegBankCombinerImpl::matchFPMinMaxToMed3(
bool AMDGPURegBankCombinerImpl::matchFPMinMaxToClamp(MachineInstr &MI,
Register &Reg) const {
+ // Perform combine only when the destination is a VGPR.
+ if (!isVgprRegBank(MI.getOperand(0).getReg()))
+ return false;
+
// Clamp is available on all types after regbankselect (f16, f32, f64, v2f16).
auto OpcodeTriple = getMinMaxPair(MI.getOpcode());
Register Val;
@@ -325,6 +333,10 @@ bool AMDGPURegBankCombinerImpl::matchFPMinMaxToClamp(MachineInstr &MI,
// min(min(0.0, 1.0), NaN) = min(0.0, NaN) = 0.0
bool AMDGPURegBankCombinerImpl::matchFPMed3ToClamp(MachineInstr &MI,
Register &Reg) const {
+ // Perform combine only when the destination is a VGPR.
+ if (!isVgprRegBank(MI.getOperand(0).getReg()))
+ return false;
+
// In llvm-ir, clamp is often represented as an intrinsic call to
// @llvm.amdgcn.fmed3.f32(%Val, 0.0, 1.0). Check for other operand orders.
MachineInstr *Src0 = getDefIgnoringCopies(MI.getOperand(1).getReg(), MRI);
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
index 3ffaaa6376baa..03f0d12722310 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/clamp-minmax-const-combine.ll
@@ -516,6 +516,98 @@ define float @test_max_min_maybe_NaN_input_ieee_false(float %a) #1 {
ret float %fmed
}
+define amdgpu_ps float @test_min_max_f32_sgpr(float inreg %a) {
+; GFX10-LABEL: test_min_max_f32_sgpr:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: v_max_f32_e64 v0, s2, s2 clamp
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX1170-LABEL: test_min_max_f32_sgpr:
+; GFX1170: ; %bb.0:
+; GFX1170-NEXT: s_max_f32 s0, s2, 0
+; GFX1170-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX1170-NEXT: s_min_f32 s0, s0, 1.0
+; GFX1170-NEXT: v_mov_b32_e32 v0, s0
+; GFX1170-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: test_min_max_f32_sgpr:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_max_num_f32 s0, s2, 0
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX12-NEXT: s_min_num_f32 s0, s0, 1.0
+; GFX12-NEXT: v_mov_b32_e32 v0, s0
+; GFX12-NEXT: ; return to shader part epilog
+ %mx = call float @llvm.maxnum.f32(float %a, float 0.000000e+00)
+ %mn = call float @llvm.minnum.f32(float %mx, float 1.000000e+00)
+ ret float %mn
+}
+
+define amdgpu_ps float @test_min_max_f32_sgpr_1(float inreg %a) {
+; GFX10-LABEL: test_min_max_f32_sgpr_1:
+; GFX10: ; %bb.0: ; %.entry
+; GFX10-NEXT: v_max_f32_e64 v0, s2, s2 clamp
+; GFX10-NEXT: v_fma_f32 v0, v0, 0, 0
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX1170-LABEL: test_min_max_f32_sgpr_1:
+; GFX1170: ; %bb.0: ; %.entry
+; GFX1170-NEXT: s_max_f32 s0, s2, 0
+; GFX1170-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX1170-NEXT: s_min_f32 s0, s0, 1.0
+; GFX1170-NEXT: s_fmaak_f32 s0, s0, 0, 0x0
+; GFX1170-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; GFX1170-NEXT: v_mov_b32_e32 v0, s0
+; GFX1170-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: test_min_max_f32_sgpr_1:
+; GFX12: ; %bb.0: ; %.entry
+; GFX12-NEXT: s_max_num_f32 s0, s2, 0
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX12-NEXT: s_min_num_f32 s0, s0, 1.0
+; GFX12-NEXT: s_fmaak_f32 s0, s0, 0, 0x0
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; GFX12-NEXT: v_mov_b32_e32 v0, s0
+; GFX12-NEXT: ; return to shader part epilog
+.entry:
+ %.i09 = call float @llvm.maxnum.f32(float %a, float 0.000000e+00)
+ %.i013 = call float @llvm.minnum.f32(float %.i09, float 1.000000e+00)
+ %.i021 = fmul contract float %.i013, 0.000000e+00
+ %.i025 = fadd contract float %.i021, 0.000000e+00
+ ret float %.i025
+}
+
+define amdgpu_ps float @test_min_max_f32_sgpr_fma_user(float inreg %a, float inreg %b, float inreg %c) {
+; GFX10-LABEL: test_min_max_f32_sgpr_fma_user:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: v_max_f32_e64 v0, s2, s2 clamp
+; GFX10-NEXT: v_fma_f32 v0, v0, s3, s4
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX1170-LABEL: test_min_max_f32_sgpr_fma_user:
+; GFX1170: ; %bb.0:
+; GFX1170-NEXT: s_max_f32 s0, s2, 0
+; GFX1170-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX1170-NEXT: s_min_f32 s0, s0, 1.0
+; GFX1170-NEXT: s_fmac_f32 s4, s0, s3
+; GFX1170-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; GFX1170-NEXT: v_mov_b32_e32 v0, s4
+; GFX1170-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: test_min_max_f32_sgpr_fma_user:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_max_num_f32 s0, s2, 0
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX12-NEXT: s_min_num_f32 s0, s0, 1.0
+; GFX12-NEXT: s_fmac_f32 s4, s0, s3
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3)
+; GFX12-NEXT: v_mov_b32_e32 v0, s4
+; GFX12-NEXT: ; return to shader part epilog
+ %mx = call float @llvm.maxnum.f32(float %a, float 0.000000e+00)
+ %mn = call float @llvm.minnum.f32(float %mx, float 1.000000e+00)
+ %f = call float @llvm.fma.f32(float %mn, float %b, float %c)
+ ret float %f
+}
+
declare half @llvm.minnum.f16(half, half)
declare half @llvm.maxnum.f16(half, half)
declare float @llvm.minnum.f32(float, float)
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
index bbaa9d9a9ac76..277a6016e5bf6 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/regbankcombiner-clamp-minmax-const.mir
@@ -564,3 +564,67 @@ body: |
%7:vgpr(s32) = G_FMAXNUM %5, %11
$vgpr0 = COPY %7(s32)
...
+
+---
+name: test_min_max_f32_sgpr
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+machineFunctionInfo:
+ mode:
+ ieee: false
+ dx10-clamp: true
+body: |
+ bb.0:
+ liveins: $sgpr0
+ ; CHECK-LABEL: name: test_min_max_f32_sgpr
+ ; CHECK: liveins: $sgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 0.000000e+00
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 1.000000e+00
+ ; CHECK-NEXT: [[FMAXNUM:%[0-9]+]]:sgpr(s32) = nnan G_FMAXNUM [[COPY]], [[C]]
+ ; CHECK-NEXT: [[FMINNUM:%[0-9]+]]:sgpr(s32) = nnan G_FMINNUM [[FMAXNUM]], [[C1]]
+ ; CHECK-NEXT: $sgpr0 = COPY [[FMINNUM]](s32)
+ %0:sgpr(s32) = COPY $sgpr0
+ %1:sgpr(s32) = G_FCONSTANT float 0.000000e+00
+ %2:sgpr(s32) = G_FCONSTANT float 1.000000e+00
+ %3:sgpr(s32) = nnan G_FMAXNUM %0, %1
+ %4:sgpr(s32) = nnan G_FMINNUM %3, %2
+ $sgpr0 = COPY %4(s32)
+...
+
+---
+name: test_min_max_f32_sgpr_fma_user
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+machineFunctionInfo:
+ mode:
+ ieee: false
+ dx10-clamp: true
+body: |
+ bb.0:
+ liveins: $sgpr0, $sgpr1, $sgpr2
+ ; CHECK-LABEL: name: test_min_max_f32_sgpr_fma_user
+ ; CHECK: liveins: $sgpr0, $sgpr1, $sgpr2
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:sgpr(s32) = COPY $sgpr0
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:sgpr(s32) = COPY $sgpr1
+ ; CHECK-NEXT: [[COPY2:%[0-9]+]]:sgpr(s32) = COPY $sgpr2
+ ; CHECK-NEXT: [[C:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 0.000000e+00
+ ; CHECK-NEXT: [[C1:%[0-9]+]]:sgpr(s32) = G_FCONSTANT float 1.000000e+00
+ ; CHECK-NEXT: [[FMAXNUM:%[0-9]+]]:sgpr(s32) = nnan G_FMAXNUM [[COPY]], [[C]]
+ ; CHECK-NEXT: [[FMINNUM:%[0-9]+]]:sgpr(s32) = nnan G_FMINNUM [[FMAXNUM]], [[C1]]
+ ; CHECK-NEXT: [[FMA:%[0-9]+]]:sgpr(s32) = G_FMA [[FMINNUM]], [[COPY1]], [[COPY2]]
+ ; CHECK-NEXT: $sgpr0 = COPY [[FMA]](s32)
+ %0:sgpr(s32) = COPY $sgpr0
+ %1:sgpr(s32) = COPY $sgpr1
+ %2:sgpr(s32) = COPY $sgpr2
+ %3:sgpr(s32) = G_FCONSTANT float 0.000000e+00
+ %4:sgpr(s32) = G_FCONSTANT float 1.000000e+00
+ %5:sgpr(s32) = nnan G_FMAXNUM %0, %3
+ %6:sgpr(s32) = nnan G_FMINNUM %5, %4
+ %7:sgpr(s32) = G_FMA %6, %1, %2
+ $sgpr0 = COPY %7(s32)
+...
More information about the llvm-commits
mailing list