[llvm] [AMDGPU][GISel] Fold 'min(min(x,y),z)' and 'max(max(x,y),z)' into min3 and max3 (PR #200410)

Petar Avramovic via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 4 09:23:09 PDT 2026


================
@@ -481,6 +491,97 @@ bool AMDGPURegBankCombinerImpl::combineD16Load(MachineInstr &MI) const {
   return false;
 }
 
+void AMDGPURegBankCombinerImpl::applyMinMaxToMinMax3(
+    MachineInstr &MI, MinMaxToMinMax3MatchInfo &MatchInfo) const {
+  B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
+               {MatchInfo.Val0, MatchInfo.Val1, MatchInfo.Val2}, MI.getFlags());
+  MI.eraseFromParent();
+  return;
+}
+
+bool AMDGPURegBankCombinerImpl::matchMinMaxToMinMax3(
+    MachineInstr &MI, MinMaxToMinMax3MatchInfo &MatchInfo) const {
+  Register Dst = MI.getOperand(0).getReg();
+  Register Src1 = MI.getOperand(1).getReg();
+  Register Src2 = MI.getOperand(2).getReg();
+  // If the register is SGPR, don't optimize it.
+  if (!(isVgprRegBank(Dst) && isVgprRegBank(Src1) && isVgprRegBank(Src2))) {
+    return false;
+  }
+
+  LLT Ty = MRI.getType(Dst);
+  unsigned Opc = MI.getOpcode();
+  bool IsFPOp = Opc == AMDGPU::G_FMAXNUM || Opc == AMDGPU::G_FMAXNUM_IEEE ||
+                Opc == AMDGPU::G_FMINNUM || Opc == AMDGPU::G_FMINNUM_IEEE;
+  bool IsSupportedTy = Ty == LLT::scalar(32) ||
+                       (Ty == LLT::scalar(16) && STI.hasMin3Max3_16()) ||
+                       (IsFPOp && Ty == LLT::fixed_vector(2, 32));
+  if (!IsSupportedTy)
+    return false;
+
+  Register R0, R1, R2;
+  if (!mi_match(MI, MRI,
+                m_CommutativeBinOp(
+                    Opc, m_OneNonDBGUse(m_BinOp(Opc, m_Reg(R0), m_Reg(R1))),
+                    m_Reg(R2)))) {
+    return false;
+  }
+
+  auto GetAMDGPUOp = [](unsigned Opc) -> unsigned {
+    switch (Opc) {
+    case AMDGPU::G_SMAX:
+      return AMDGPU::G_AMDGPU_SMAX3;
+    case AMDGPU::G_SMIN:
+      return AMDGPU::G_AMDGPU_SMIN3;
+    case AMDGPU::G_UMAX:
+      return AMDGPU::G_AMDGPU_UMAX3;
+    case AMDGPU::G_UMIN:
+      return AMDGPU::G_AMDGPU_UMIN3;
+    case AMDGPU::G_FMAXNUM:
+    case AMDGPU::G_FMAXNUM_IEEE:
+      return AMDGPU::G_AMDGPU_FMAX3;
+    case AMDGPU::G_FMINNUM:
+    case AMDGPU::G_FMINNUM_IEEE:
+      return AMDGPU::G_AMDGPU_FMIN3;
+    case AMDGPU::G_FMAXIMUM:
+      return AMDGPU::G_AMDGPU_FMAXIMUM3;
+    case AMDGPU::G_FMINIMUM:
+      return AMDGPU::G_AMDGPU_FMINIMUM3;
+    default:
+      return 0;
+    }
+  };
+  unsigned AMDGPUOpc = GetAMDGPUOp(Opc);
+  if (!AMDGPUOpc)
+    return false;
+  // remove canonicalize
+  auto RewriteR = [&](Register &R, Register &R1, Register &R2, bool isLeft) {
----------------
petar-avramovic wrote:

what is this meant to do?
what looked correct to me was to ask if R0, R1are defined with G_FCANONICALIZE, replace with G_FCANONICALIZE src. can't do that for R2 because then if R2 was SNaN result would be QNaN not result of inner max/min.
Just pay attention R0 and R1 are inner src operands for you

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


More information about the llvm-commits mailing list