[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