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

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 24 19:11:36 PST 2025


https://github.com/Ruhung updated https://github.com/llvm/llvm-project/pull/124263

>From a308dac4370db8cb9a8b69eedfc8ebca5190d146 Mon Sep 17 00:00:00 2001
From: Ruhung <jhlee at pllab.cs.nthu.edu.tw>
Date: Fri, 24 Jan 2025 11:17:37 +0800
Subject: [PATCH 1/2] [AMDGPU][GISel] Fold 'min(min(x,y),z)' and
 'max(max(x,y),z)' into min3 and max3.

---
 llvm/lib/Target/AMDGPU/AMDGPUCombine.td       | 23 ++++--
 llvm/lib/Target/AMDGPU/AMDGPUGISel.td         |  7 ++
 .../Target/AMDGPU/AMDGPURegBankCombiner.cpp   | 70 +++++++++++++++++++
 llvm/lib/Target/AMDGPU/SIInstructions.td      | 36 ++++++++++
 llvm/test/CodeGen/AMDGPU/ctlz.ll              |  6 +-
 llvm/test/CodeGen/AMDGPU/cttz.ll              |  6 +-
 6 files changed, 133 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td
index da47aaf8a3b5c9..477ecbfe97b4a2 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUCombine.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUCombine.td
@@ -71,6 +71,16 @@ def int_minmax_to_med3 : GICombineRule<
          [{ return matchIntMinMaxToMed3(*${min_or_max}, ${matchinfo}); }]),
   (apply [{ applyMed3(*${min_or_max}, ${matchinfo}); }])>;
 
+def minmax3_matchdata : GIDefMatchData<"VOP3MatchInfo">;
+
+def minmax_to_minmax3
+    : GICombineRule<
+          (defs root:$min_or_max, minmax3_matchdata:$matchinfo),
+          (match(wip_match_opcode G_SMAX, G_SMIN, G_UMAX, G_UMIN, G_FMAXNUM,
+               G_FMINNUM, G_FMAXNUM_IEEE, G_FMINNUM_IEEE):$min_or_max,
+              [{ return matchMinMaxToMinMax3(*${min_or_max}, ${matchinfo}); }]),
+          (apply [{ applyVOP3(*${min_or_max}, ${matchinfo}); }])>;
+
 def fp_minmax_to_med3 : GICombineRule<
   (defs root:$min_or_max, med3_matchdata:$matchinfo),
   (match (wip_match_opcode G_FMAXNUM,
@@ -175,10 +185,9 @@ def AMDGPUPostLegalizerCombiner: GICombiner<
   let CombineAllMethodName = "tryCombineAllImpl";
 }
 
-def AMDGPURegBankCombiner : GICombiner<
-  "AMDGPURegBankCombinerImpl",
-  [unmerge_merge, unmerge_cst, unmerge_undef,
-   zext_trunc_fold, int_minmax_to_med3, ptr_add_immed_chain,
-   fp_minmax_to_clamp, fp_minmax_to_med3, fmed3_intrinsic_to_clamp,
-   redundant_and]> {
-}
+def AMDGPURegBankCombiner
+    : GICombiner<"AMDGPURegBankCombinerImpl",
+                 [unmerge_merge, unmerge_cst, unmerge_undef, zext_trunc_fold,
+                  int_minmax_to_med3, ptr_add_immed_chain, fp_minmax_to_clamp,
+                  fp_minmax_to_med3, fmed3_intrinsic_to_clamp,
+                  minmax_to_minmax3, redundant_and]> {}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td
index 1b909568fc555c..0038d9942a3201 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPUGISel.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPUGISel.td
@@ -244,6 +244,13 @@ def : GINodeEquiv<G_AMDGPU_CVT_PK_I16_I32, AMDGPUpk_i16_i32_impl>;
 def : GINodeEquiv<G_AMDGPU_SMED3, AMDGPUsmed3>;
 def : GINodeEquiv<G_AMDGPU_UMED3, AMDGPUumed3>;
 def : GINodeEquiv<G_AMDGPU_FMED3, AMDGPUfmed3_impl>;
+def : GINodeEquiv<G_AMDGPU_SMAX3, AMDGPUsmax3>;
+def : GINodeEquiv<G_AMDGPU_UMAX3, AMDGPUumax3>;
+def : GINodeEquiv<G_AMDGPU_FMAX3, AMDGPUfmax3>;
+def : GINodeEquiv<G_AMDGPU_SMIN3, AMDGPUsmin3>;
+def : GINodeEquiv<G_AMDGPU_UMIN3, AMDGPUumin3>;
+def : GINodeEquiv<G_AMDGPU_FMIN3, AMDGPUfmin3>;
+
 def : GINodeEquiv<G_AMDGPU_CLAMP, AMDGPUclamp>;
 
 def : GINodeEquiv<G_AMDGPU_ATOMIC_CMPXCHG, AMDGPUatomic_cmp_swap>;
diff --git a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
index 98c48f4fe3705b..5af2663397fb75 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
+++ b/llvm/lib/Target/AMDGPU/AMDGPURegBankCombiner.cpp
@@ -74,17 +74,27 @@ class AMDGPURegBankCombinerImpl : public Combiner {
     Register Val0, Val1, Val2;
   };
 
+  struct VOP3MatchInfo {
+    unsigned Opc;
+    Register Val0, Val1, Val2;
+  };
+
   MinMaxMedOpc getMinMaxPair(unsigned Opc) const;
+  unsigned getMinMax3(unsigned Opc) const;
 
   template <class m_Cst, typename CstTy>
   bool matchMed(MachineInstr &MI, MachineRegisterInfo &MRI, MinMaxMedOpc MMMOpc,
                 Register &Val, CstTy &K0, CstTy &K1) const;
+  bool matchVOP3(MachineInstr &MI, MachineRegisterInfo &MRI, unsigned Opc,
+                 Register &A, Register &B, Register &C) const;
 
   bool matchIntMinMaxToMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
   bool matchFPMinMaxToMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
+  bool matchMinMaxToMinMax3(MachineInstr &MI, VOP3MatchInfo &MatchInfo) const;
   bool matchFPMinMaxToClamp(MachineInstr &MI, Register &Reg) const;
   bool matchFPMed3ToClamp(MachineInstr &MI, Register &Reg) const;
   void applyMed3(MachineInstr &MI, Med3MatchInfo &MatchInfo) const;
+  void applyVOP3(MachineInstr &MI, VOP3MatchInfo &MatchInfo) const;
   void applyClamp(MachineInstr &MI, Register &Reg) const;
 
 private:
@@ -165,6 +175,27 @@ AMDGPURegBankCombinerImpl::getMinMaxPair(unsigned Opc) const {
   }
 }
 
+unsigned AMDGPURegBankCombinerImpl::getMinMax3(unsigned Opc) const {
+  switch (Opc) {
+  default:
+    llvm_unreachable("Unsupported opcode");
+  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;
+  }
+}
+
 template <class m_Cst, typename CstTy>
 bool AMDGPURegBankCombinerImpl::matchMed(MachineInstr &MI,
                                          MachineRegisterInfo &MRI,
@@ -187,6 +218,36 @@ bool AMDGPURegBankCombinerImpl::matchMed(MachineInstr &MI,
               m_Cst(K0))));
 }
 
+bool AMDGPURegBankCombinerImpl::matchVOP3(MachineInstr &MI,
+                                          MachineRegisterInfo &MRI,
+                                          unsigned Opc, Register &A,
+                                          Register &B, Register &C) const {
+  return mi_match(
+      MI, MRI,
+      m_any_of(m_BinOp(Opc, m_OneNonDBGUse(m_BinOp(Opc, m_Reg(A), m_Reg(B))),
+                       m_Reg(C)),
+               m_BinOp(Opc, m_Reg(A),
+                       m_OneNonDBGUse(m_BinOp(Opc, m_Reg(B), m_Reg(C))))));
+}
+
+bool AMDGPURegBankCombinerImpl::matchMinMaxToMinMax3(
+    MachineInstr &MI, VOP3MatchInfo &MatchInfo) const {
+  Register Dst = MI.getOperand(0).getReg();
+  if (!isVgprRegBank(Dst))
+    return false;
+
+  LLT Ty = MRI.getType(Dst);
+  if ((Ty != LLT::scalar(16) || !STI.hasMin3Max3_16()) && Ty != LLT::scalar(32))
+    return false;
+
+  unsigned Opc = MI.getOpcode();
+  Register R0, R1, R2;
+  if (!matchVOP3(MI, MRI, Opc, R0, R1, R2))
+    return false;
+  MatchInfo = {getMinMax3(Opc), R0, R1, R2};
+  return true;
+}
+
 bool AMDGPURegBankCombinerImpl::matchIntMinMaxToMed3(
     MachineInstr &MI, Med3MatchInfo &MatchInfo) const {
   Register Dst = MI.getOperand(0).getReg();
@@ -362,6 +423,15 @@ void AMDGPURegBankCombinerImpl::applyMed3(MachineInstr &MI,
   MI.eraseFromParent();
 }
 
+void AMDGPURegBankCombinerImpl::applyVOP3(MachineInstr &MI,
+                                          VOP3MatchInfo &MatchInfo) const {
+  B.buildInstr(MatchInfo.Opc, {MI.getOperand(0)},
+               {getAsVgpr(MatchInfo.Val0), getAsVgpr(MatchInfo.Val1),
+                getAsVgpr(MatchInfo.Val2)},
+               MI.getFlags());
+  MI.eraseFromParent();
+}
+
 SIModeRegisterDefaults AMDGPURegBankCombinerImpl::getMode() const {
   return MF.getInfo<SIMachineFunctionInfo>()->getMode();
 }
diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index 4325ab448e5815..b5b4b8cf91db8f 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -3955,6 +3955,42 @@ def G_AMDGPU_FMED3 : AMDGPUGenericInstruction {
   let hasSideEffects = 0;
 }
 
+def G_AMDGPU_SMIN3 : AMDGPUGenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src0, type0:$src1, type0:$src2);
+  let hasSideEffects = 0;
+}
+
+def G_AMDGPU_UMIN3 : AMDGPUGenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src0, type0:$src1, type0:$src2);
+  let hasSideEffects = 0;
+}
+
+def G_AMDGPU_FMIN3 : AMDGPUGenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src0, type0:$src1, type0:$src2);
+  let hasSideEffects = 0;
+}
+
+def G_AMDGPU_SMAX3 : AMDGPUGenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src0, type0:$src1, type0:$src2);
+  let hasSideEffects = 0;
+}
+
+def G_AMDGPU_UMAX3 : AMDGPUGenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src0, type0:$src1, type0:$src2);
+  let hasSideEffects = 0;
+}
+
+def G_AMDGPU_FMAX3 : AMDGPUGenericInstruction {
+  let OutOperandList = (outs type0:$dst);
+  let InOperandList = (ins type0:$src0, type0:$src1, type0:$src2);
+  let hasSideEffects = 0;
+}
+
 def G_AMDGPU_CLAMP : AMDGPUGenericInstruction {
   let OutOperandList = (outs type0:$dst);
   let InOperandList = (ins type0:$src);
diff --git a/llvm/test/CodeGen/AMDGPU/ctlz.ll b/llvm/test/CodeGen/AMDGPU/ctlz.ll
index 3019d4d298eb45..1b71bfd0c3e297 100644
--- a/llvm/test/CodeGen/AMDGPU/ctlz.ll
+++ b/llvm/test/CodeGen/AMDGPU/ctlz.ll
@@ -861,9 +861,8 @@ define amdgpu_kernel void @v_ctlz_i64(ptr addrspace(1) noalias %out, ptr addrspa
 ; GFX10-GISEL-NEXT:    v_ffbh_u32_e32 v0, v0
 ; GFX10-GISEL-NEXT:    v_ffbh_u32_e32 v1, v1
 ; GFX10-GISEL-NEXT:    v_add_nc_u32_e64 v0, v0, 32 clamp
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v0, v1, v0
+; GFX10-GISEL-NEXT:    v_min3_u32 v0, v1, v0, 64
 ; GFX10-GISEL-NEXT:    v_mov_b32_e32 v1, 0
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v0, 64, v0
 ; GFX10-GISEL-NEXT:    global_store_dwordx2 v2, v[0:1], s[0:1]
 ; GFX10-GISEL-NEXT:    s_endpgm
 ;
@@ -989,8 +988,7 @@ define amdgpu_kernel void @v_ctlz_i64_trunc(ptr addrspace(1) noalias %out, ptr a
 ; GFX10-GISEL-NEXT:    v_ffbh_u32_e32 v1, v1
 ; GFX10-GISEL-NEXT:    v_ffbh_u32_e32 v2, v2
 ; GFX10-GISEL-NEXT:    v_add_nc_u32_e64 v1, v1, 32 clamp
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v1, v2, v1
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v1, 64, v1
+; GFX10-GISEL-NEXT:    v_min3_u32 v1, v2, v1, 64
 ; GFX10-GISEL-NEXT:    global_store_dword v0, v1, s[0:1]
 ; GFX10-GISEL-NEXT:    s_endpgm
 ;
diff --git a/llvm/test/CodeGen/AMDGPU/cttz.ll b/llvm/test/CodeGen/AMDGPU/cttz.ll
index f0c278a67c8bcc..3ebaf864683da6 100644
--- a/llvm/test/CodeGen/AMDGPU/cttz.ll
+++ b/llvm/test/CodeGen/AMDGPU/cttz.ll
@@ -749,9 +749,8 @@ define amdgpu_kernel void @v_cttz_i64(ptr addrspace(1) noalias %out, ptr addrspa
 ; GFX10-GISEL-NEXT:    v_ffbl_b32_e32 v1, v1
 ; GFX10-GISEL-NEXT:    v_ffbl_b32_e32 v0, v0
 ; GFX10-GISEL-NEXT:    v_add_nc_u32_e64 v1, v1, 32 clamp
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v0, v0, v1
+; GFX10-GISEL-NEXT:    v_min3_u32 v0, v0, v1, 64
 ; GFX10-GISEL-NEXT:    v_mov_b32_e32 v1, 0
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v0, 64, v0
 ; GFX10-GISEL-NEXT:    global_store_dwordx2 v2, v[0:1], s[0:1]
 ; GFX10-GISEL-NEXT:    s_endpgm
   %tid = call i32 @llvm.amdgcn.workitem.id.x()
@@ -859,8 +858,7 @@ define amdgpu_kernel void @v_cttz_i64_trunc(ptr addrspace(1) noalias %out, ptr a
 ; GFX10-GISEL-NEXT:    v_ffbl_b32_e32 v2, v2
 ; GFX10-GISEL-NEXT:    v_ffbl_b32_e32 v1, v1
 ; GFX10-GISEL-NEXT:    v_add_nc_u32_e64 v2, v2, 32 clamp
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v1, v1, v2
-; GFX10-GISEL-NEXT:    v_min_u32_e32 v1, 64, v1
+; GFX10-GISEL-NEXT:    v_min3_u32 v1, v1, v2, 64
 ; GFX10-GISEL-NEXT:    global_store_dword v0, v1, s[0:1]
 ; GFX10-GISEL-NEXT:    s_endpgm
   %tid = call i32 @llvm.amdgcn.workitem.id.x()

>From 5d08a16c8b58acc4d535940451a29471af31ab52 Mon Sep 17 00:00:00 2001
From: Ruhung <jhlee at pllab.cs.nthu.edu.tw>
Date: Sat, 25 Jan 2025 11:10:11 +0800
Subject: [PATCH 2/2] Add integer testing.

---
 .../AMDGPU/GlobalISel/min3-max3-combine.ll    | 172 ++++++++++++++++++
 1 file changed, 172 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/GlobalISel/min3-max3-combine.ll

diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/min3-max3-combine.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/min3-max3-combine.ll
new file mode 100644
index 00000000000000..dfd2cba580e735
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/min3-max3-combine.ll
@@ -0,0 +1,172 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -global-isel -mtriple=amdgcn-amd-mesa3d -mcpu=gfx1010 -verify-machineinstrs < %s | FileCheck -check-prefix=GFX10 %s
+
+define i32 @test_smin3(i32 %a, i32 %b, i32 %c) {
+; GFX10-LABEL: test_smin3:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_min3_i32 v0, v0, v1, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
+  %min2 = call i32 @llvm.smin.i32(i32 %min1, i32 %c)
+  ret i32 %min2
+}
+
+define i32 @test_smin3_with_constants(i32 %a, i32 %b) {
+; GFX10-LABEL: test_smin3_with_constants:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_min3_i32 v0, v0, v1, 7
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
+  %min2 = call i32 @llvm.smin.i32(i32 %min1, i32 7)
+  ret i32 %min2
+}
+
+define i32 @test_smin3_smin_umin(i32 %a, i32 %b) {
+; GFX10-LABEL: test_smin3_smin_umin:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_min_i32_e32 v0, v0, v1
+; GFX10-NEXT:    v_min_u32_e32 v0, 7, v0
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
+  %min2 = call i32 @llvm.umin.i32(i32 %min1, i32 7)
+  ret i32 %min2
+}
+
+define <2 x i16> @test_smin3_v2i16(<2 x i16> %a, <2 x i16> %b, <2 x i16> %c) {
+; GFX10-LABEL: test_smin3_v2i16:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_pk_min_i16 v0, v0, v1
+; GFX10-NEXT:    v_pk_min_i16 v0, v0, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call <2 x i16> @llvm.smin.v2i16(<2 x i16> %a, <2 x i16> %b)
+  %min2 = call <2 x i16> @llvm.smin.v2i16(<2 x i16> %min1, <2 x i16> %c)
+  ret <2 x i16> %min2
+}
+
+define i32 @test_smax3(i32 %a, i32 %b, i32 %c) {
+; GFX10-LABEL: test_smax3:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_max3_i32 v0, v0, v1, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %max1 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
+  %max2 = call i32 @llvm.smax.i32(i32 %max1, i32 %c)
+  ret i32 %max2
+}
+
+define i32 @test_smax3_with_constants(i32 %a, i32 %b) {
+; GFX10-LABEL: test_smax3_with_constants:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_max3_i32 v0, v0, v1, 7
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
+  %min2 = call i32 @llvm.smax.i32(i32 %min1, i32 7)
+  ret i32 %min2
+}
+
+define i32 @test_smin3_smax_umax(i32 %a, i32 %b) {
+; GFX10-LABEL: test_smin3_smax_umax:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_max_i32_e32 v0, v0, v1
+; GFX10-NEXT:    v_max_u32_e32 v0, 7, v0
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
+  %min2 = call i32 @llvm.umax.i32(i32 %min1, i32 7)
+  ret i32 %min2
+}
+
+define <2 x i16> @test_smax3_v2i16(<2 x i16> %a, <2 x i16> %b, <2 x i16> %c) {
+; GFX10-LABEL: test_smax3_v2i16:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_pk_max_i16 v0, v0, v1
+; GFX10-NEXT:    v_pk_max_i16 v0, v0, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %max1 = call <2 x i16> @llvm.smax.v2i16(<2 x i16> %a, <2 x i16> %b)
+  %max2 = call <2 x i16> @llvm.smax.v2i16(<2 x i16> %max1, <2 x i16> %c)
+  ret <2 x i16> %max2
+}
+
+define i32 @test_umin3(i32 %a, i32 %b, i32 %c) {
+; GFX10-LABEL: test_umin3:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_min3_u32 v0, v0, v1, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
+  %min2 = call i32 @llvm.umin.i32(i32 %min1, i32 %c)
+  ret i32 %min2
+}
+
+define i32 @test_umin3_with_constants(i32 %a, i32 %b) {
+; GFX10-LABEL: test_umin3_with_constants:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_min3_u32 v0, v0, v1, 7
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
+  %min2 = call i32 @llvm.umin.i32(i32 %min1, i32 7)
+  ret i32 %min2
+}
+
+define <2 x i16> @test_umin3_v2i16(<2 x i16> %a, <2 x i16> %b, <2 x i16> %c) {
+; GFX10-LABEL: test_umin3_v2i16:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_pk_min_u16 v0, v0, v1
+; GFX10-NEXT:    v_pk_min_u16 v0, v0, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %min1 = call <2 x i16> @llvm.umin.v2i16(<2 x i16> %a, <2 x i16> %b)
+  %min2 = call <2 x i16> @llvm.umin.v2i16(<2 x i16> %min1, <2 x i16> %c)
+  ret <2 x i16> %min2
+}
+
+define i32 @test_umax3(i32 %a, i32 %b, i32 %c) {
+; GFX10-LABEL: test_umax3:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_max3_u32 v0, v0, v1, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %max1 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
+  %max2 = call i32 @llvm.umax.i32(i32 %max1, i32 %c)
+  ret i32 %max2
+}
+
+define i32 @test_umax3_with_constants(i32 %a, i32 %b) {
+; GFX10-LABEL: test_umax3_with_constants:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_max3_u32 v0, v0, v1, 7
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %max1 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
+  %max2 = call i32 @llvm.umax.i32(i32 %max1, i32 7)
+  ret i32 %max2
+}
+
+define <2 x i16> @test_umax3_v2i16(<2 x i16> %a, <2 x i16> %b, <2 x i16> %c) {
+; GFX10-LABEL: test_umax3_v2i16:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_pk_max_u16 v0, v0, v1
+; GFX10-NEXT:    v_pk_max_u16 v0, v0, v2
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+  %max1 = call <2 x i16> @llvm.umax.v2i16(<2 x i16> %a, <2 x i16> %b)
+  %max2 = call <2 x i16> @llvm.umax.v2i16(<2 x i16> %max1, <2 x i16> %c)
+  ret <2 x i16> %max2
+}
+
+declare i32 @llvm.smin.i32(i32, i32)
+declare i32 @llvm.umin.i32(i32, i32)
+declare i32 @llvm.smax.i32(i32, i32)
+declare i32 @llvm.umax.i32(i32, i32)
+declare <2 x i16> @llvm.smin.v2i16(<2 x i16>, <2 x i16>)
+declare <2 x i16> @llvm.umin.v2i16(<2 x i16>, <2 x i16>)
+declare <2 x i16> @llvm.smax.v2i16(<2 x i16>, <2 x i16>)
+declare <2 x i16> @llvm.umax.v2i16(<2 x i16>, <2 x i16>)
+



More information about the llvm-commits mailing list