1*ec043967SThomas Symalla //=== lib/CodeGen/GlobalISel/AMDGPUPostLegalizerCombiner.cpp
2*ec043967SThomas Symalla //---------------===//
3fee41517SMatt Arsenault //
4fee41517SMatt Arsenault // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5fee41517SMatt Arsenault // See https://llvm.org/LICENSE.txt for license information.
6fee41517SMatt Arsenault // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7fee41517SMatt Arsenault //
8fee41517SMatt Arsenault //===----------------------------------------------------------------------===//
9fee41517SMatt Arsenault //
10fee41517SMatt Arsenault // This pass does combining of machine instructions at the generic MI level,
11fee41517SMatt Arsenault // after the legalizer.
12fee41517SMatt Arsenault //
13fee41517SMatt Arsenault //===----------------------------------------------------------------------===//
14fee41517SMatt Arsenault 
15*ec043967SThomas Symalla <<<<<<< HEAD
166a87e9b0Sdfukalov #include "AMDGPU.h"
17fee41517SMatt Arsenault #include "AMDGPULegalizerInfo.h"
18560d7e04Sdfukalov #include "GCNSubtarget.h"
19*ec043967SThomas Symalla =======
20*ec043967SThomas Symalla #include "AMDGPULegalizerInfo.h"
21*ec043967SThomas Symalla #include "AMDGPUTargetMachine.h"
22*ec043967SThomas Symalla >>>>>>> clang-format
23560d7e04Sdfukalov #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
24fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/Combiner.h"
25fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
26fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
27fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
28fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
29fee41517SMatt Arsenault #include "llvm/CodeGen/MachineDominators.h"
30fee41517SMatt Arsenault #include "llvm/CodeGen/TargetPassConfig.h"
31*ec043967SThomas Symalla <<<<<<< HEAD
326a87e9b0Sdfukalov #include "llvm/Target/TargetMachine.h"
33*ec043967SThomas Symalla =======
34*ec043967SThomas Symalla #include "llvm/Support/Debug.h"
35*ec043967SThomas Symalla >>>>>>> clang-format
36fee41517SMatt Arsenault 
37fee41517SMatt Arsenault #define DEBUG_TYPE "amdgpu-postlegalizer-combiner"
38fee41517SMatt Arsenault 
39fee41517SMatt Arsenault using namespace llvm;
40fee41517SMatt Arsenault using namespace MIPatternMatch;
41fee41517SMatt Arsenault 
420031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelper {
430031418dSPetar Avramovic protected:
440031418dSPetar Avramovic   MachineIRBuilder &B;
450031418dSPetar Avramovic   MachineFunction &MF;
460031418dSPetar Avramovic   MachineRegisterInfo &MRI;
470031418dSPetar Avramovic   CombinerHelper &Helper;
480031418dSPetar Avramovic 
490031418dSPetar Avramovic public:
500031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper(MachineIRBuilder &B, CombinerHelper &Helper)
510031418dSPetar Avramovic       : B(B), MF(B.getMF()), MRI(*B.getMRI()), Helper(Helper){};
520031418dSPetar Avramovic 
53fee41517SMatt Arsenault   struct FMinFMaxLegacyInfo {
54fee41517SMatt Arsenault     Register LHS;
55fee41517SMatt Arsenault     Register RHS;
56fee41517SMatt Arsenault     Register True;
57fee41517SMatt Arsenault     Register False;
58fee41517SMatt Arsenault     CmpInst::Predicate Pred;
59fee41517SMatt Arsenault   };
60fee41517SMatt Arsenault 
61fee41517SMatt Arsenault   // TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize
620031418dSPetar Avramovic   bool matchFMinFMaxLegacy(MachineInstr &MI, FMinFMaxLegacyInfo &Info);
630031418dSPetar Avramovic   void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI,
640031418dSPetar Avramovic                                          const FMinFMaxLegacyInfo &Info);
650031418dSPetar Avramovic 
660031418dSPetar Avramovic   bool matchUCharToFloat(MachineInstr &MI);
670031418dSPetar Avramovic   void applyUCharToFloat(MachineInstr &MI);
680031418dSPetar Avramovic 
690031418dSPetar Avramovic   // FIXME: Should be able to have 2 separate matchdatas rather than custom
700031418dSPetar Avramovic   // struct boilerplate.
710031418dSPetar Avramovic   struct CvtF32UByteMatchInfo {
720031418dSPetar Avramovic     Register CvtVal;
730031418dSPetar Avramovic     unsigned ShiftOffset;
740031418dSPetar Avramovic   };
750031418dSPetar Avramovic 
760031418dSPetar Avramovic   bool matchCvtF32UByteN(MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo);
770031418dSPetar Avramovic   void applyCvtF32UByteN(MachineInstr &MI,
780031418dSPetar Avramovic                          const CvtF32UByteMatchInfo &MatchInfo);
7962af0305SThomas Symalla 
8062af0305SThomas Symalla   struct ClampI64ToI16MatchInfo {
8162af0305SThomas Symalla     int64_t Cmp1;
8262af0305SThomas Symalla     int64_t Cmp2;
8362af0305SThomas Symalla     Register Origin;
8462af0305SThomas Symalla   };
8562af0305SThomas Symalla 
8662af0305SThomas Symalla   bool matchClampI64ToI16(MachineInstr &MI, MachineRegisterInfo &MRI,
8762af0305SThomas Symalla                           MachineFunction &MF,
8862af0305SThomas Symalla                           ClampI64ToI16MatchInfo &MatchInfo);
8962af0305SThomas Symalla 
9062af0305SThomas Symalla   void applyClampI64ToI16(MachineInstr &MI,
9162af0305SThomas Symalla                           const ClampI64ToI16MatchInfo &MatchInfo);
920031418dSPetar Avramovic };
930031418dSPetar Avramovic 
940031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy(
950031418dSPetar Avramovic     MachineInstr &MI, FMinFMaxLegacyInfo &Info) {
96fee41517SMatt Arsenault   // FIXME: Combines should have subtarget predicates, and we shouldn't need
97fee41517SMatt Arsenault   // this here.
98fee41517SMatt Arsenault   if (!MF.getSubtarget<GCNSubtarget>().hasFminFmaxLegacy())
99fee41517SMatt Arsenault     return false;
100fee41517SMatt Arsenault 
101fee41517SMatt Arsenault   // FIXME: Type predicate on pattern
102fee41517SMatt Arsenault   if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(32))
103fee41517SMatt Arsenault     return false;
104fee41517SMatt Arsenault 
105fee41517SMatt Arsenault   Register Cond = MI.getOperand(1).getReg();
106fee41517SMatt Arsenault   if (!MRI.hasOneNonDBGUse(Cond) ||
107fee41517SMatt Arsenault       !mi_match(Cond, MRI,
108fee41517SMatt Arsenault                 m_GFCmp(m_Pred(Info.Pred), m_Reg(Info.LHS), m_Reg(Info.RHS))))
109fee41517SMatt Arsenault     return false;
110fee41517SMatt Arsenault 
111fee41517SMatt Arsenault   Info.True = MI.getOperand(2).getReg();
112fee41517SMatt Arsenault   Info.False = MI.getOperand(3).getReg();
113fee41517SMatt Arsenault 
114fee41517SMatt Arsenault   if (!(Info.LHS == Info.True && Info.RHS == Info.False) &&
115fee41517SMatt Arsenault       !(Info.LHS == Info.False && Info.RHS == Info.True))
116fee41517SMatt Arsenault     return false;
117fee41517SMatt Arsenault 
118fee41517SMatt Arsenault   switch (Info.Pred) {
119fee41517SMatt Arsenault   case CmpInst::FCMP_FALSE:
120fee41517SMatt Arsenault   case CmpInst::FCMP_OEQ:
121fee41517SMatt Arsenault   case CmpInst::FCMP_ONE:
122fee41517SMatt Arsenault   case CmpInst::FCMP_ORD:
123fee41517SMatt Arsenault   case CmpInst::FCMP_UNO:
124fee41517SMatt Arsenault   case CmpInst::FCMP_UEQ:
125fee41517SMatt Arsenault   case CmpInst::FCMP_UNE:
126fee41517SMatt Arsenault   case CmpInst::FCMP_TRUE:
127fee41517SMatt Arsenault     return false;
128fee41517SMatt Arsenault   default:
129fee41517SMatt Arsenault     return true;
130fee41517SMatt Arsenault   }
131fee41517SMatt Arsenault }
132fee41517SMatt Arsenault 
1330031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applySelectFCmpToFMinToFMaxLegacy(
1340031418dSPetar Avramovic     MachineInstr &MI, const FMinFMaxLegacyInfo &Info) {
1350031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
1360031418dSPetar Avramovic   auto buildNewInst = [&MI, this](unsigned Opc, Register X, Register Y) {
1370031418dSPetar Avramovic     B.buildInstr(Opc, {MI.getOperand(0)}, {X, Y}, MI.getFlags());
138fee41517SMatt Arsenault   };
139fee41517SMatt Arsenault 
140fee41517SMatt Arsenault   switch (Info.Pred) {
141fee41517SMatt Arsenault   case CmpInst::FCMP_ULT:
142fee41517SMatt Arsenault   case CmpInst::FCMP_ULE:
143fee41517SMatt Arsenault     if (Info.LHS == Info.True)
144fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS);
145fee41517SMatt Arsenault     else
146fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS);
147fee41517SMatt Arsenault     break;
148fee41517SMatt Arsenault   case CmpInst::FCMP_OLE:
149fee41517SMatt Arsenault   case CmpInst::FCMP_OLT: {
150fee41517SMatt Arsenault     // We need to permute the operands to get the correct NaN behavior. The
151fee41517SMatt Arsenault     // selected operand is the second one based on the failing compare with NaN,
152fee41517SMatt Arsenault     // so permute it based on the compare type the hardware uses.
153fee41517SMatt Arsenault     if (Info.LHS == Info.True)
154fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS);
155fee41517SMatt Arsenault     else
156fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS);
157fee41517SMatt Arsenault     break;
158fee41517SMatt Arsenault   }
159fee41517SMatt Arsenault   case CmpInst::FCMP_UGE:
160fee41517SMatt Arsenault   case CmpInst::FCMP_UGT: {
161fee41517SMatt Arsenault     if (Info.LHS == Info.True)
162fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS);
163fee41517SMatt Arsenault     else
164fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS);
165fee41517SMatt Arsenault     break;
166fee41517SMatt Arsenault   }
167fee41517SMatt Arsenault   case CmpInst::FCMP_OGT:
168fee41517SMatt Arsenault   case CmpInst::FCMP_OGE: {
169fee41517SMatt Arsenault     if (Info.LHS == Info.True)
170fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS);
171fee41517SMatt Arsenault     else
172fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS);
173fee41517SMatt Arsenault     break;
174fee41517SMatt Arsenault   }
175fee41517SMatt Arsenault   default:
176fee41517SMatt Arsenault     llvm_unreachable("predicate should not have matched");
177fee41517SMatt Arsenault   }
178fee41517SMatt Arsenault 
179fee41517SMatt Arsenault   MI.eraseFromParent();
180fee41517SMatt Arsenault }
181fee41517SMatt Arsenault 
1820031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchUCharToFloat(MachineInstr &MI) {
183b27d255eSMatt Arsenault   Register DstReg = MI.getOperand(0).getReg();
184b27d255eSMatt Arsenault 
185b27d255eSMatt Arsenault   // TODO: We could try to match extracting the higher bytes, which would be
186b27d255eSMatt Arsenault   // easier if i8 vectors weren't promoted to i32 vectors, particularly after
187b27d255eSMatt Arsenault   // types are legalized. v4i8 -> v4f32 is probably the only case to worry
188b27d255eSMatt Arsenault   // about in practice.
189b27d255eSMatt Arsenault   LLT Ty = MRI.getType(DstReg);
190b27d255eSMatt Arsenault   if (Ty == LLT::scalar(32) || Ty == LLT::scalar(16)) {
191db777eaeSMatt Arsenault     Register SrcReg = MI.getOperand(1).getReg();
192db777eaeSMatt Arsenault     unsigned SrcSize = MRI.getType(SrcReg).getSizeInBits();
193db777eaeSMatt Arsenault     assert(SrcSize == 16 || SrcSize == 32 || SrcSize == 64);
194db777eaeSMatt Arsenault     const APInt Mask = APInt::getHighBitsSet(SrcSize, SrcSize - 8);
195db777eaeSMatt Arsenault     return Helper.getKnownBits()->maskedValueIsZero(SrcReg, Mask);
196b27d255eSMatt Arsenault   }
197b27d255eSMatt Arsenault 
198b27d255eSMatt Arsenault   return false;
199b27d255eSMatt Arsenault }
200b27d255eSMatt Arsenault 
2010031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyUCharToFloat(MachineInstr &MI) {
2020031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
203b27d255eSMatt Arsenault 
204b27d255eSMatt Arsenault   const LLT S32 = LLT::scalar(32);
205b27d255eSMatt Arsenault 
206b27d255eSMatt Arsenault   Register DstReg = MI.getOperand(0).getReg();
207db777eaeSMatt Arsenault   Register SrcReg = MI.getOperand(1).getReg();
2080031418dSPetar Avramovic   LLT Ty = MRI.getType(DstReg);
2090031418dSPetar Avramovic   LLT SrcTy = MRI.getType(SrcReg);
210db777eaeSMatt Arsenault   if (SrcTy != S32)
211db777eaeSMatt Arsenault     SrcReg = B.buildAnyExtOrTrunc(S32, SrcReg).getReg(0);
212b27d255eSMatt Arsenault 
213b27d255eSMatt Arsenault   if (Ty == S32) {
214*ec043967SThomas Symalla     B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {DstReg}, {SrcReg},
215*ec043967SThomas Symalla                  MI.getFlags());
216b27d255eSMatt Arsenault   } else {
217*ec043967SThomas Symalla     auto Cvt0 = B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {S32}, {SrcReg},
218*ec043967SThomas Symalla                              MI.getFlags());
219b27d255eSMatt Arsenault     B.buildFPTrunc(DstReg, Cvt0, MI.getFlags());
220b27d255eSMatt Arsenault   }
221b27d255eSMatt Arsenault 
222b27d255eSMatt Arsenault   MI.eraseFromParent();
223b27d255eSMatt Arsenault }
224fee41517SMatt Arsenault 
2250031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchCvtF32UByteN(
2260031418dSPetar Avramovic     MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) {
2270ba40d4cSMatt Arsenault   Register SrcReg = MI.getOperand(1).getReg();
2280ba40d4cSMatt Arsenault 
2290ba40d4cSMatt Arsenault   // Look through G_ZEXT.
2300ba40d4cSMatt Arsenault   mi_match(SrcReg, MRI, m_GZExt(m_Reg(SrcReg)));
2310ba40d4cSMatt Arsenault 
2320ba40d4cSMatt Arsenault   Register Src0;
2330ba40d4cSMatt Arsenault   int64_t ShiftAmt;
2340ba40d4cSMatt Arsenault   bool IsShr = mi_match(SrcReg, MRI, m_GLShr(m_Reg(Src0), m_ICst(ShiftAmt)));
2350ba40d4cSMatt Arsenault   if (IsShr || mi_match(SrcReg, MRI, m_GShl(m_Reg(Src0), m_ICst(ShiftAmt)))) {
2360ba40d4cSMatt Arsenault     const unsigned Offset = MI.getOpcode() - AMDGPU::G_AMDGPU_CVT_F32_UBYTE0;
2370ba40d4cSMatt Arsenault 
2380ba40d4cSMatt Arsenault     unsigned ShiftOffset = 8 * Offset;
2390ba40d4cSMatt Arsenault     if (IsShr)
2400ba40d4cSMatt Arsenault       ShiftOffset += ShiftAmt;
2410ba40d4cSMatt Arsenault     else
2420ba40d4cSMatt Arsenault       ShiftOffset -= ShiftAmt;
2430ba40d4cSMatt Arsenault 
2440ba40d4cSMatt Arsenault     MatchInfo.CvtVal = Src0;
2450ba40d4cSMatt Arsenault     MatchInfo.ShiftOffset = ShiftOffset;
2460ba40d4cSMatt Arsenault     return ShiftOffset < 32 && ShiftOffset >= 8 && (ShiftOffset % 8) == 0;
2470ba40d4cSMatt Arsenault   }
2480ba40d4cSMatt Arsenault 
2490ba40d4cSMatt Arsenault   // TODO: Simplify demanded bits.
2500ba40d4cSMatt Arsenault   return false;
2510ba40d4cSMatt Arsenault }
2520ba40d4cSMatt Arsenault 
2530031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyCvtF32UByteN(
2540031418dSPetar Avramovic     MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) {
2550031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
2560ba40d4cSMatt Arsenault   unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8;
2570ba40d4cSMatt Arsenault 
2580ba40d4cSMatt Arsenault   const LLT S32 = LLT::scalar(32);
2590ba40d4cSMatt Arsenault   Register CvtSrc = MatchInfo.CvtVal;
2600031418dSPetar Avramovic   LLT SrcTy = MRI.getType(MatchInfo.CvtVal);
2610ba40d4cSMatt Arsenault   if (SrcTy != S32) {
2620ba40d4cSMatt Arsenault     assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8);
2630ba40d4cSMatt Arsenault     CvtSrc = B.buildAnyExt(S32, CvtSrc).getReg(0);
2640ba40d4cSMatt Arsenault   }
2650ba40d4cSMatt Arsenault 
2660ba40d4cSMatt Arsenault   assert(MI.getOpcode() != NewOpc);
2670ba40d4cSMatt Arsenault   B.buildInstr(NewOpc, {MI.getOperand(0)}, {CvtSrc}, MI.getFlags());
2680ba40d4cSMatt Arsenault   MI.eraseFromParent();
2690ba40d4cSMatt Arsenault }
2700ba40d4cSMatt Arsenault 
271*ec043967SThomas Symalla bool AMDGPUPostLegalizerCombinerHelper::matchClampI64ToI16(
272*ec043967SThomas Symalla     MachineInstr &MI, MachineRegisterInfo &MRI, MachineFunction &MF,
27362af0305SThomas Symalla     ClampI64ToI16MatchInfo &MatchInfo) {
27462af0305SThomas Symalla   assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Invalid instruction!");
27562af0305SThomas Symalla   const LLT SrcType = MRI.getType(MI.getOperand(1).getReg());
27662af0305SThomas Symalla   if (SrcType != LLT::scalar(64))
27762af0305SThomas Symalla     return false;
27862af0305SThomas Symalla 
27962af0305SThomas Symalla   MachineIRBuilder B(MI);
28062af0305SThomas Symalla 
28162af0305SThomas Symalla   LLVM_DEBUG(dbgs() << "Matching Clamp i64 to i16");
28262af0305SThomas Symalla 
28362af0305SThomas Symalla   if (mi_match(MI.getOperand(1).getReg(), MRI,
284*ec043967SThomas Symalla                m_MaxMin(m_ICst(MatchInfo.Cmp1), m_ICst(MatchInfo.Cmp2),
28562af0305SThomas Symalla                         m_Reg(MatchInfo.Origin)))) {
28662af0305SThomas Symalla     const auto Cmp1 = static_cast<int64_t>(MatchInfo.Cmp1);
28762af0305SThomas Symalla     const auto Cmp2 = static_cast<int64_t>(MatchInfo.Cmp2);
28862af0305SThomas Symalla 
289*ec043967SThomas Symalla     const int64_t Min =
290*ec043967SThomas Symalla         static_cast<int64_t>(std::numeric_limits<int16_t>::min());
291*ec043967SThomas Symalla     const int64_t Max =
292*ec043967SThomas Symalla         static_cast<int64_t>(std::numeric_limits<int16_t>::max());
29362af0305SThomas Symalla 
29462af0305SThomas Symalla     // are we really trying to clamp against short boundaries?
29562af0305SThomas Symalla     return ((Cmp2 >= Cmp1 && Cmp1 >= Min && Cmp2 <= Max) ||
29662af0305SThomas Symalla             (Cmp1 >= Cmp2 && Cmp1 <= Max && Cmp2 >= Min));
29762af0305SThomas Symalla   }
29862af0305SThomas Symalla 
29962af0305SThomas Symalla   return false;
30062af0305SThomas Symalla }
30162af0305SThomas Symalla 
302*ec043967SThomas Symalla void AMDGPUPostLegalizerCombinerHelper::applyClampI64ToI16(
303*ec043967SThomas Symalla     MachineInstr &MI, const ClampI64ToI16MatchInfo &MatchInfo) {
30462af0305SThomas Symalla   LLVM_DEBUG(dbgs() << "Combining MI");
30562af0305SThomas Symalla 
30662af0305SThomas Symalla   MachineIRBuilder B(MI);
30762af0305SThomas Symalla   MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
30862af0305SThomas Symalla 
30962af0305SThomas Symalla   Register Src = MatchInfo.Origin;
31062af0305SThomas Symalla   assert(MRI.getType(Src) == LLT::scalar(64));
31162af0305SThomas Symalla   const LLT S32 = LLT::scalar(32);
31262af0305SThomas Symalla 
31362af0305SThomas Symalla   auto Unmerge = B.buildUnmerge(S32, Src);
31462af0305SThomas Symalla   Register Hi32 = Unmerge->getOperand(0).getReg();
31562af0305SThomas Symalla   Register Lo32 = Unmerge->getOperand(1).getReg();
31662af0305SThomas Symalla   MRI.setRegClass(Hi32, &AMDGPU::VGPR_32RegClass);
31762af0305SThomas Symalla   MRI.setRegClass(Lo32, &AMDGPU::VGPR_32RegClass);
31862af0305SThomas Symalla 
31962af0305SThomas Symalla   constexpr unsigned int CvtOpcode = AMDGPU::V_CVT_PK_I16_I32_e64;
32062af0305SThomas Symalla   assert(MI.getOpcode() != CvtOpcode);
32162af0305SThomas Symalla 
32262af0305SThomas Symalla   Register CvtDst = MRI.createGenericVirtualRegister(S32);
32362af0305SThomas Symalla   MRI.setRegClass(CvtDst, &AMDGPU::VGPR_32RegClass);
32462af0305SThomas Symalla 
32562af0305SThomas Symalla   auto CvtPk = B.buildInstr(CvtOpcode);
32662af0305SThomas Symalla   CvtPk.addDef(CvtDst);
32762af0305SThomas Symalla   CvtPk.addReg(Hi32);
32862af0305SThomas Symalla   CvtPk.addReg(Lo32);
32962af0305SThomas Symalla   CvtPk.setMIFlags(MI.getFlags());
33062af0305SThomas Symalla 
33162af0305SThomas Symalla   auto min = std::min(MatchInfo.Cmp1, MatchInfo.Cmp2);
33262af0305SThomas Symalla   auto max = std::max(MatchInfo.Cmp1, MatchInfo.Cmp2);
33362af0305SThomas Symalla 
33462af0305SThomas Symalla   Register MinBoundaryDst = MRI.createGenericVirtualRegister(S32);
33562af0305SThomas Symalla   MRI.setRegClass(MinBoundaryDst, &AMDGPU::VGPR_32RegClass);
33662af0305SThomas Symalla   B.buildConstant(MinBoundaryDst, min);
33762af0305SThomas Symalla 
33862af0305SThomas Symalla   Register MaxBoundaryDst = MRI.createGenericVirtualRegister(S32);
33962af0305SThomas Symalla   MRI.setRegClass(MaxBoundaryDst, &AMDGPU::VGPR_32RegClass);
34062af0305SThomas Symalla   B.buildConstant(MaxBoundaryDst, max);
34162af0305SThomas Symalla 
34262af0305SThomas Symalla   Register MedDst = MRI.createGenericVirtualRegister(S32);
34362af0305SThomas Symalla   MRI.setRegClass(MedDst, &AMDGPU::VGPR_32RegClass);
34462af0305SThomas Symalla 
34562af0305SThomas Symalla   auto Med = B.buildInstr(AMDGPU::V_MED3_I32);
34662af0305SThomas Symalla   Med.addDef(MedDst);
34762af0305SThomas Symalla   Med.addReg(MinBoundaryDst);
34862af0305SThomas Symalla   Med.addReg(CvtDst);
34962af0305SThomas Symalla   Med.addReg(MaxBoundaryDst);
35062af0305SThomas Symalla   Med.setMIFlags(MI.getFlags());
35162af0305SThomas Symalla 
35262af0305SThomas Symalla   B.buildCopy(MI.getOperand(0).getReg(), MedDst);
35362af0305SThomas Symalla 
35462af0305SThomas Symalla   MI.eraseFromParent();
35562af0305SThomas Symalla }
35662af0305SThomas Symalla 
3570031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelperState {
3580031418dSPetar Avramovic protected:
3590031418dSPetar Avramovic   CombinerHelper &Helper;
3600031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper;
3610031418dSPetar Avramovic 
3620031418dSPetar Avramovic public:
3630031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelperState(
3640031418dSPetar Avramovic       CombinerHelper &Helper,
3650031418dSPetar Avramovic       AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper)
3660031418dSPetar Avramovic       : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper) {}
3670031418dSPetar Avramovic };
3680031418dSPetar Avramovic 
369fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
370fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
371fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
372fee41517SMatt Arsenault 
373fee41517SMatt Arsenault namespace {
374fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
375fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
376fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
377fee41517SMatt Arsenault 
37816bcd545SMatt Arsenault class AMDGPUPostLegalizerCombinerInfo final : public CombinerInfo {
379fee41517SMatt Arsenault   GISelKnownBits *KB;
380fee41517SMatt Arsenault   MachineDominatorTree *MDT;
381fee41517SMatt Arsenault 
382fee41517SMatt Arsenault public:
383e35ba099SDaniel Sanders   AMDGPUGenPostLegalizerCombinerHelperRuleConfig GeneratedRuleCfg;
384fee41517SMatt Arsenault 
385fee41517SMatt Arsenault   AMDGPUPostLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize,
386fee41517SMatt Arsenault                                   const AMDGPULegalizerInfo *LI,
387fee41517SMatt Arsenault                                   GISelKnownBits *KB, MachineDominatorTree *MDT)
388fee41517SMatt Arsenault       : CombinerInfo(/*AllowIllegalOps*/ false, /*ShouldLegalizeIllegal*/ true,
389fee41517SMatt Arsenault                      /*LegalizerInfo*/ LI, EnableOpt, OptSize, MinSize),
390fee41517SMatt Arsenault         KB(KB), MDT(MDT) {
391e35ba099SDaniel Sanders     if (!GeneratedRuleCfg.parseCommandLineOption())
392fee41517SMatt Arsenault       report_fatal_error("Invalid rule identifier");
393fee41517SMatt Arsenault   }
394fee41517SMatt Arsenault 
395d15723efSMatt Arsenault   bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
396fee41517SMatt Arsenault                MachineIRBuilder &B) const override;
397fee41517SMatt Arsenault };
398fee41517SMatt Arsenault 
399fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
400fee41517SMatt Arsenault                                               MachineInstr &MI,
401fee41517SMatt Arsenault                                               MachineIRBuilder &B) const {
40266ffa0e9SMatt Arsenault   CombinerHelper Helper(Observer, B, KB, MDT, LInfo);
4030031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper PostLegalizerHelper(B, Helper);
4040031418dSPetar Avramovic   AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper,
4050031418dSPetar Avramovic                                                  PostLegalizerHelper);
406fee41517SMatt Arsenault 
4070031418dSPetar Avramovic   if (Generated.tryCombineAll(Observer, MI, B))
408fee41517SMatt Arsenault     return true;
409fee41517SMatt Arsenault 
410fee41517SMatt Arsenault   switch (MI.getOpcode()) {
411fee41517SMatt Arsenault   case TargetOpcode::G_SHL:
412fee41517SMatt Arsenault   case TargetOpcode::G_LSHR:
413fee41517SMatt Arsenault   case TargetOpcode::G_ASHR:
414fee41517SMatt Arsenault     // On some subtargets, 64-bit shift is a quarter rate instruction. In the
415fee41517SMatt Arsenault     // common case, splitting this into a move and a 32-bit shift is faster and
416fee41517SMatt Arsenault     // the same code size.
417fee41517SMatt Arsenault     return Helper.tryCombineShiftToUnmerge(MI, 32);
418fee41517SMatt Arsenault   }
419fee41517SMatt Arsenault 
420fee41517SMatt Arsenault   return false;
421fee41517SMatt Arsenault }
422fee41517SMatt Arsenault 
423fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
424fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
425fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
426fee41517SMatt Arsenault 
427fee41517SMatt Arsenault // Pass boilerplate
428fee41517SMatt Arsenault // ================
429fee41517SMatt Arsenault 
430fee41517SMatt Arsenault class AMDGPUPostLegalizerCombiner : public MachineFunctionPass {
431fee41517SMatt Arsenault public:
432fee41517SMatt Arsenault   static char ID;
433fee41517SMatt Arsenault 
434fee41517SMatt Arsenault   AMDGPUPostLegalizerCombiner(bool IsOptNone = false);
435fee41517SMatt Arsenault 
436fee41517SMatt Arsenault   StringRef getPassName() const override {
437fee41517SMatt Arsenault     return "AMDGPUPostLegalizerCombiner";
438fee41517SMatt Arsenault   }
439fee41517SMatt Arsenault 
440fee41517SMatt Arsenault   bool runOnMachineFunction(MachineFunction &MF) override;
441fee41517SMatt Arsenault 
442fee41517SMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override;
443*ec043967SThomas Symalla 
444fee41517SMatt Arsenault private:
445fee41517SMatt Arsenault   bool IsOptNone;
446fee41517SMatt Arsenault };
447fee41517SMatt Arsenault } // end anonymous namespace
448fee41517SMatt Arsenault 
449fee41517SMatt Arsenault void AMDGPUPostLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
450fee41517SMatt Arsenault   AU.addRequired<TargetPassConfig>();
451fee41517SMatt Arsenault   AU.setPreservesCFG();
452fee41517SMatt Arsenault   getSelectionDAGFallbackAnalysisUsage(AU);
453fee41517SMatt Arsenault   AU.addRequired<GISelKnownBitsAnalysis>();
454fee41517SMatt Arsenault   AU.addPreserved<GISelKnownBitsAnalysis>();
455fee41517SMatt Arsenault   if (!IsOptNone) {
456fee41517SMatt Arsenault     AU.addRequired<MachineDominatorTree>();
457fee41517SMatt Arsenault     AU.addPreserved<MachineDominatorTree>();
458fee41517SMatt Arsenault   }
459fee41517SMatt Arsenault   MachineFunctionPass::getAnalysisUsage(AU);
460fee41517SMatt Arsenault }
461fee41517SMatt Arsenault 
462fee41517SMatt Arsenault AMDGPUPostLegalizerCombiner::AMDGPUPostLegalizerCombiner(bool IsOptNone)
463fee41517SMatt Arsenault     : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
464fee41517SMatt Arsenault   initializeAMDGPUPostLegalizerCombinerPass(*PassRegistry::getPassRegistry());
465fee41517SMatt Arsenault }
466fee41517SMatt Arsenault 
467fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
468fee41517SMatt Arsenault   if (MF.getProperties().hasProperty(
469fee41517SMatt Arsenault           MachineFunctionProperties::Property::FailedISel))
470fee41517SMatt Arsenault     return false;
471fee41517SMatt Arsenault   auto *TPC = &getAnalysis<TargetPassConfig>();
472fee41517SMatt Arsenault   const Function &F = MF.getFunction();
473fee41517SMatt Arsenault   bool EnableOpt =
474fee41517SMatt Arsenault       MF.getTarget().getOptLevel() != CodeGenOpt::None && !skipFunction(F);
475fee41517SMatt Arsenault 
476fee41517SMatt Arsenault   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
477*ec043967SThomas Symalla   const AMDGPULegalizerInfo *LI =
478*ec043967SThomas Symalla       static_cast<const AMDGPULegalizerInfo *>(ST.getLegalizerInfo());
479fee41517SMatt Arsenault 
480fee41517SMatt Arsenault   GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF);
481fee41517SMatt Arsenault   MachineDominatorTree *MDT =
482fee41517SMatt Arsenault       IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>();
483fee41517SMatt Arsenault   AMDGPUPostLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(),
484fee41517SMatt Arsenault                                          F.hasMinSize(), LI, KB, MDT);
485fee41517SMatt Arsenault   Combiner C(PCInfo, TPC);
486fee41517SMatt Arsenault   return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr);
487fee41517SMatt Arsenault }
488fee41517SMatt Arsenault 
489fee41517SMatt Arsenault char AMDGPUPostLegalizerCombiner::ID = 0;
490fee41517SMatt Arsenault INITIALIZE_PASS_BEGIN(AMDGPUPostLegalizerCombiner, DEBUG_TYPE,
491*ec043967SThomas Symalla                       "Combine AMDGPU machine instrs after legalization", false,
492*ec043967SThomas Symalla                       false)
493fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
494fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis)
495fee41517SMatt Arsenault INITIALIZE_PASS_END(AMDGPUPostLegalizerCombiner, DEBUG_TYPE,
496fee41517SMatt Arsenault                     "Combine AMDGPU machine instrs after legalization", false,
497fee41517SMatt Arsenault                     false)
498fee41517SMatt Arsenault 
499fee41517SMatt Arsenault namespace llvm {
500fee41517SMatt Arsenault FunctionPass *createAMDGPUPostLegalizeCombiner(bool IsOptNone) {
501fee41517SMatt Arsenault   return new AMDGPUPostLegalizerCombiner(IsOptNone);
502fee41517SMatt Arsenault }
503fee41517SMatt Arsenault } // end namespace llvm
504