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

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 01:29:00 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 {
----------------
Shoreshen wrote:

Hi @arsenm , removed and plan a new pr to do:
1. Take this to si-fold-operands.
2. Make it be general, recognizing both v_mul and v_max canonicalization
3. take count in `isCanonicalized` and remove canonicalize MI if op already canonicalized
4. If all user will canonicalize operand, also remove remove canonicalize

The PR will have similar case change comparing to this PR, plus some more. So will start after this PR merged.

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


More information about the llvm-commits mailing list