[llvm] [AMDGPU] Adjust amdgpu fmax/fmin legalization (PR #202917)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 05:06:41 PDT 2026


================
@@ -10322,6 +10324,121 @@ void SIInstrInfo::fixImplicitOperands(MachineInstr &MI) const {
   }
 }
 
+// fcanonicalize is selected as a self-max (SelectCanonicalizeAsMax), i.e.
+// V_MAX_F{16,32} src, src, so only these max opcodes can define a canonicalize.
+static bool isFPSelfMaxCanonicalizeOpc(unsigned Opc) {
+  switch (Opc) {
+  case AMDGPU::V_MAX_F16_e32:
+  case AMDGPU::V_MAX_F16_e64:
+  case AMDGPU::V_MAX_F16_t16_e32:
+  case AMDGPU::V_MAX_F16_t16_e64:
+  case AMDGPU::V_MAX_F16_fake16_e32:
+  case AMDGPU::V_MAX_F16_fake16_e64:
+  case AMDGPU::V_MAX_F32_e32:
+  case AMDGPU::V_MAX_F32_e64:
+    return true;
+  default:
+    return false;
+  }
+}
+
+// VALU FP min/max (f16/f32). On FeatureIEEEMinimumMaximumInsts targets these
+// print as v_{min,max}_num_f*, which canonicalize their inputs internally.
+static bool isFPMinMaxNumOpc(unsigned Opc) {
+  switch (Opc) {
+  case AMDGPU::V_MIN_F16_e32:
+  case AMDGPU::V_MIN_F16_e64:
+  case AMDGPU::V_MIN_F16_t16_e32:
+  case AMDGPU::V_MIN_F16_t16_e64:
+  case AMDGPU::V_MIN_F16_fake16_e32:
+  case AMDGPU::V_MIN_F16_fake16_e64:
+  case AMDGPU::V_MIN_F32_e32:
+  case AMDGPU::V_MIN_F32_e64:
+    return true;
+  default:
+    return isFPSelfMaxCanonicalizeOpc(Opc);
+  }
+}
+
+static bool isFPCanonicalizeSrcModifier(unsigned Mod) {
+  return !(Mod & ~(SISrcMods::NEG | SISrcMods::ABS));
+}
+
+/// On FeatureIEEEMinimumMaximumInsts targets a VALU FP min/max is printed as
+/// v_{min,max}_num_f*, which already canonicalizes its inputs, so feeding it an
+/// explicitly canonicalized operand is redundant.
+///
+/// A uniform llvm.minnum/maxnum on a target without scalar _num_ min/max is
+/// lowered to fcanonicalize(x)/fcanonicalize(y) feeding S_{MIN,MAX}_F*, where
+/// each fcanonicalize is selected as a self-max V_MAX_F*_e64 src_mods:src,
+/// src_mods:src. When SIFixSGPRCopies later moves that scalar op back to a
+/// VALU min/max, e.g.:
+///
+///   %10 = V_MAX_F32_e64 0, %9, 0, %9, 0, 0    ; fcanonicalize %9
+///   %11 = V_MAX_F32_e64 1, %8, 1, %8, 0, 0    ; fcanonicalize -%8
+///   %13 = COPY %11
+///   %14 = COPY %10
+///   %12 = S_MAX_F32 %13, %14   -->   V_MAX_F32_e64 %10, %11
+///
+/// the self-max inputs become redundant once the user is a v_max_num, so fold
+/// them back to %9/-%8 and drop the now-dead canonicalizes.
+void SIInstrInfo::removeFcanonicalize(MachineInstr &MI) const {
+  if (!ST.hasIEEEMinimumMaximumInsts() || !isFPMinMaxNumOpc(MI.getOpcode()))
+    return;
+
+  MachineBasicBlock *MBB = MI.getParent();
+  if (!MBB)
+    return;
----------------
arsenm wrote:

Cannot happen 

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


More information about the llvm-commits mailing list