1fee41517SMatt Arsenault //=== lib/CodeGen/GlobalISel/AMDGPUPostLegalizerCombiner.cpp ---------------===//
2fee41517SMatt Arsenault //
3fee41517SMatt Arsenault // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fee41517SMatt Arsenault // See https://llvm.org/LICENSE.txt for license information.
5fee41517SMatt Arsenault // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fee41517SMatt Arsenault //
7fee41517SMatt Arsenault //===----------------------------------------------------------------------===//
8fee41517SMatt Arsenault //
9fee41517SMatt Arsenault // This pass does combining of machine instructions at the generic MI level,
10fee41517SMatt Arsenault // after the legalizer.
11fee41517SMatt Arsenault //
12fee41517SMatt Arsenault //===----------------------------------------------------------------------===//
13fee41517SMatt Arsenault 
146a87e9b0Sdfukalov #include "AMDGPU.h"
15fee41517SMatt Arsenault #include "AMDGPULegalizerInfo.h"
16560d7e04Sdfukalov #include "GCNSubtarget.h"
17560d7e04Sdfukalov #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
18fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/Combiner.h"
19fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
20fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
21fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
22fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
23fee41517SMatt Arsenault #include "llvm/CodeGen/MachineDominators.h"
24fee41517SMatt Arsenault #include "llvm/CodeGen/TargetPassConfig.h"
256a87e9b0Sdfukalov #include "llvm/Target/TargetMachine.h"
26fee41517SMatt Arsenault 
27fee41517SMatt Arsenault #define DEBUG_TYPE "amdgpu-postlegalizer-combiner"
28fee41517SMatt Arsenault 
29fee41517SMatt Arsenault using namespace llvm;
30fee41517SMatt Arsenault using namespace MIPatternMatch;
31fee41517SMatt Arsenault 
320031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelper {
330031418dSPetar Avramovic protected:
340031418dSPetar Avramovic   MachineIRBuilder &B;
350031418dSPetar Avramovic   MachineFunction &MF;
360031418dSPetar Avramovic   MachineRegisterInfo &MRI;
370031418dSPetar Avramovic   CombinerHelper &Helper;
380031418dSPetar Avramovic 
390031418dSPetar Avramovic public:
400031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper(MachineIRBuilder &B, CombinerHelper &Helper)
410031418dSPetar Avramovic       : B(B), MF(B.getMF()), MRI(*B.getMRI()), Helper(Helper){};
420031418dSPetar Avramovic 
43fee41517SMatt Arsenault   struct FMinFMaxLegacyInfo {
44fee41517SMatt Arsenault     Register LHS;
45fee41517SMatt Arsenault     Register RHS;
46fee41517SMatt Arsenault     Register True;
47fee41517SMatt Arsenault     Register False;
48fee41517SMatt Arsenault     CmpInst::Predicate Pred;
49fee41517SMatt Arsenault   };
50fee41517SMatt Arsenault 
51fee41517SMatt Arsenault   // TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize
520031418dSPetar Avramovic   bool matchFMinFMaxLegacy(MachineInstr &MI, FMinFMaxLegacyInfo &Info);
530031418dSPetar Avramovic   void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI,
540031418dSPetar Avramovic                                          const FMinFMaxLegacyInfo &Info);
550031418dSPetar Avramovic 
560031418dSPetar Avramovic   bool matchUCharToFloat(MachineInstr &MI);
570031418dSPetar Avramovic   void applyUCharToFloat(MachineInstr &MI);
580031418dSPetar Avramovic 
590031418dSPetar Avramovic   // FIXME: Should be able to have 2 separate matchdatas rather than custom
600031418dSPetar Avramovic   // struct boilerplate.
610031418dSPetar Avramovic   struct CvtF32UByteMatchInfo {
620031418dSPetar Avramovic     Register CvtVal;
630031418dSPetar Avramovic     unsigned ShiftOffset;
640031418dSPetar Avramovic   };
650031418dSPetar Avramovic 
660031418dSPetar Avramovic   bool matchCvtF32UByteN(MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo);
670031418dSPetar Avramovic   void applyCvtF32UByteN(MachineInstr &MI,
680031418dSPetar Avramovic                          const CvtF32UByteMatchInfo &MatchInfo);
69*62af0305SThomas Symalla 
70*62af0305SThomas Symalla   struct ClampI64ToI16MatchInfo {
71*62af0305SThomas Symalla     int64_t Cmp1;
72*62af0305SThomas Symalla     int64_t Cmp2;
73*62af0305SThomas Symalla     Register Origin;
74*62af0305SThomas Symalla   };
75*62af0305SThomas Symalla 
76*62af0305SThomas Symalla   bool matchClampI64ToI16(MachineInstr &MI, MachineRegisterInfo &MRI,
77*62af0305SThomas Symalla                                 MachineFunction &MF,
78*62af0305SThomas Symalla                                 ClampI64ToI16MatchInfo &MatchInfo);
79*62af0305SThomas Symalla 
80*62af0305SThomas Symalla   void applyClampI64ToI16(MachineInstr &MI,
81*62af0305SThomas Symalla                           const ClampI64ToI16MatchInfo &MatchInfo);
820031418dSPetar Avramovic };
830031418dSPetar Avramovic 
840031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy(
850031418dSPetar Avramovic     MachineInstr &MI, FMinFMaxLegacyInfo &Info) {
86fee41517SMatt Arsenault   // FIXME: Combines should have subtarget predicates, and we shouldn't need
87fee41517SMatt Arsenault   // this here.
88fee41517SMatt Arsenault   if (!MF.getSubtarget<GCNSubtarget>().hasFminFmaxLegacy())
89fee41517SMatt Arsenault     return false;
90fee41517SMatt Arsenault 
91fee41517SMatt Arsenault   // FIXME: Type predicate on pattern
92fee41517SMatt Arsenault   if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(32))
93fee41517SMatt Arsenault     return false;
94fee41517SMatt Arsenault 
95fee41517SMatt Arsenault   Register Cond = MI.getOperand(1).getReg();
96fee41517SMatt Arsenault   if (!MRI.hasOneNonDBGUse(Cond) ||
97fee41517SMatt Arsenault       !mi_match(Cond, MRI,
98fee41517SMatt Arsenault                 m_GFCmp(m_Pred(Info.Pred), m_Reg(Info.LHS), m_Reg(Info.RHS))))
99fee41517SMatt Arsenault     return false;
100fee41517SMatt Arsenault 
101fee41517SMatt Arsenault   Info.True = MI.getOperand(2).getReg();
102fee41517SMatt Arsenault   Info.False = MI.getOperand(3).getReg();
103fee41517SMatt Arsenault 
104fee41517SMatt Arsenault   if (!(Info.LHS == Info.True && Info.RHS == Info.False) &&
105fee41517SMatt Arsenault       !(Info.LHS == Info.False && Info.RHS == Info.True))
106fee41517SMatt Arsenault     return false;
107fee41517SMatt Arsenault 
108fee41517SMatt Arsenault   switch (Info.Pred) {
109fee41517SMatt Arsenault   case CmpInst::FCMP_FALSE:
110fee41517SMatt Arsenault   case CmpInst::FCMP_OEQ:
111fee41517SMatt Arsenault   case CmpInst::FCMP_ONE:
112fee41517SMatt Arsenault   case CmpInst::FCMP_ORD:
113fee41517SMatt Arsenault   case CmpInst::FCMP_UNO:
114fee41517SMatt Arsenault   case CmpInst::FCMP_UEQ:
115fee41517SMatt Arsenault   case CmpInst::FCMP_UNE:
116fee41517SMatt Arsenault   case CmpInst::FCMP_TRUE:
117fee41517SMatt Arsenault     return false;
118fee41517SMatt Arsenault   default:
119fee41517SMatt Arsenault     return true;
120fee41517SMatt Arsenault   }
121fee41517SMatt Arsenault }
122fee41517SMatt Arsenault 
1230031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applySelectFCmpToFMinToFMaxLegacy(
1240031418dSPetar Avramovic     MachineInstr &MI, const FMinFMaxLegacyInfo &Info) {
1250031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
1260031418dSPetar Avramovic   auto buildNewInst = [&MI, this](unsigned Opc, Register X, Register Y) {
1270031418dSPetar Avramovic     B.buildInstr(Opc, {MI.getOperand(0)}, {X, Y}, MI.getFlags());
128fee41517SMatt Arsenault   };
129fee41517SMatt Arsenault 
130fee41517SMatt Arsenault   switch (Info.Pred) {
131fee41517SMatt Arsenault   case CmpInst::FCMP_ULT:
132fee41517SMatt Arsenault   case CmpInst::FCMP_ULE:
133fee41517SMatt Arsenault     if (Info.LHS == Info.True)
134fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS);
135fee41517SMatt Arsenault     else
136fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS);
137fee41517SMatt Arsenault     break;
138fee41517SMatt Arsenault   case CmpInst::FCMP_OLE:
139fee41517SMatt Arsenault   case CmpInst::FCMP_OLT: {
140fee41517SMatt Arsenault     // We need to permute the operands to get the correct NaN behavior. The
141fee41517SMatt Arsenault     // selected operand is the second one based on the failing compare with NaN,
142fee41517SMatt Arsenault     // so permute it based on the compare type the hardware uses.
143fee41517SMatt Arsenault     if (Info.LHS == Info.True)
144fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS);
145fee41517SMatt Arsenault     else
146fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS);
147fee41517SMatt Arsenault     break;
148fee41517SMatt Arsenault   }
149fee41517SMatt Arsenault   case CmpInst::FCMP_UGE:
150fee41517SMatt Arsenault   case CmpInst::FCMP_UGT: {
151fee41517SMatt Arsenault     if (Info.LHS == Info.True)
152fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS);
153fee41517SMatt Arsenault     else
154fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS);
155fee41517SMatt Arsenault     break;
156fee41517SMatt Arsenault   }
157fee41517SMatt Arsenault   case CmpInst::FCMP_OGT:
158fee41517SMatt Arsenault   case CmpInst::FCMP_OGE: {
159fee41517SMatt Arsenault     if (Info.LHS == Info.True)
160fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS);
161fee41517SMatt Arsenault     else
162fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS);
163fee41517SMatt Arsenault     break;
164fee41517SMatt Arsenault   }
165fee41517SMatt Arsenault   default:
166fee41517SMatt Arsenault     llvm_unreachable("predicate should not have matched");
167fee41517SMatt Arsenault   }
168fee41517SMatt Arsenault 
169fee41517SMatt Arsenault   MI.eraseFromParent();
170fee41517SMatt Arsenault }
171fee41517SMatt Arsenault 
1720031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchUCharToFloat(MachineInstr &MI) {
173b27d255eSMatt Arsenault   Register DstReg = MI.getOperand(0).getReg();
174b27d255eSMatt Arsenault 
175b27d255eSMatt Arsenault   // TODO: We could try to match extracting the higher bytes, which would be
176b27d255eSMatt Arsenault   // easier if i8 vectors weren't promoted to i32 vectors, particularly after
177b27d255eSMatt Arsenault   // types are legalized. v4i8 -> v4f32 is probably the only case to worry
178b27d255eSMatt Arsenault   // about in practice.
179b27d255eSMatt Arsenault   LLT Ty = MRI.getType(DstReg);
180b27d255eSMatt Arsenault   if (Ty == LLT::scalar(32) || Ty == LLT::scalar(16)) {
181db777eaeSMatt Arsenault     Register SrcReg = MI.getOperand(1).getReg();
182db777eaeSMatt Arsenault     unsigned SrcSize = MRI.getType(SrcReg).getSizeInBits();
183db777eaeSMatt Arsenault     assert(SrcSize == 16 || SrcSize == 32 || SrcSize == 64);
184db777eaeSMatt Arsenault     const APInt Mask = APInt::getHighBitsSet(SrcSize, SrcSize - 8);
185db777eaeSMatt Arsenault     return Helper.getKnownBits()->maskedValueIsZero(SrcReg, Mask);
186b27d255eSMatt Arsenault   }
187b27d255eSMatt Arsenault 
188b27d255eSMatt Arsenault   return false;
189b27d255eSMatt Arsenault }
190b27d255eSMatt Arsenault 
1910031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyUCharToFloat(MachineInstr &MI) {
1920031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
193b27d255eSMatt Arsenault 
194b27d255eSMatt Arsenault   const LLT S32 = LLT::scalar(32);
195b27d255eSMatt Arsenault 
196b27d255eSMatt Arsenault   Register DstReg = MI.getOperand(0).getReg();
197db777eaeSMatt Arsenault   Register SrcReg = MI.getOperand(1).getReg();
1980031418dSPetar Avramovic   LLT Ty = MRI.getType(DstReg);
1990031418dSPetar Avramovic   LLT SrcTy = MRI.getType(SrcReg);
200db777eaeSMatt Arsenault   if (SrcTy != S32)
201db777eaeSMatt Arsenault     SrcReg = B.buildAnyExtOrTrunc(S32, SrcReg).getReg(0);
202b27d255eSMatt Arsenault 
203b27d255eSMatt Arsenault   if (Ty == S32) {
204b27d255eSMatt Arsenault     B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {DstReg},
205db777eaeSMatt Arsenault                    {SrcReg}, MI.getFlags());
206b27d255eSMatt Arsenault   } else {
207b27d255eSMatt Arsenault     auto Cvt0 = B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {S32},
208db777eaeSMatt Arsenault                              {SrcReg}, MI.getFlags());
209b27d255eSMatt Arsenault     B.buildFPTrunc(DstReg, Cvt0, MI.getFlags());
210b27d255eSMatt Arsenault   }
211b27d255eSMatt Arsenault 
212b27d255eSMatt Arsenault   MI.eraseFromParent();
213b27d255eSMatt Arsenault }
214fee41517SMatt Arsenault 
2150031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchCvtF32UByteN(
2160031418dSPetar Avramovic     MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) {
2170ba40d4cSMatt Arsenault   Register SrcReg = MI.getOperand(1).getReg();
2180ba40d4cSMatt Arsenault 
2190ba40d4cSMatt Arsenault   // Look through G_ZEXT.
2200ba40d4cSMatt Arsenault   mi_match(SrcReg, MRI, m_GZExt(m_Reg(SrcReg)));
2210ba40d4cSMatt Arsenault 
2220ba40d4cSMatt Arsenault   Register Src0;
2230ba40d4cSMatt Arsenault   int64_t ShiftAmt;
2240ba40d4cSMatt Arsenault   bool IsShr = mi_match(SrcReg, MRI, m_GLShr(m_Reg(Src0), m_ICst(ShiftAmt)));
2250ba40d4cSMatt Arsenault   if (IsShr || mi_match(SrcReg, MRI, m_GShl(m_Reg(Src0), m_ICst(ShiftAmt)))) {
2260ba40d4cSMatt Arsenault     const unsigned Offset = MI.getOpcode() - AMDGPU::G_AMDGPU_CVT_F32_UBYTE0;
2270ba40d4cSMatt Arsenault 
2280ba40d4cSMatt Arsenault     unsigned ShiftOffset = 8 * Offset;
2290ba40d4cSMatt Arsenault     if (IsShr)
2300ba40d4cSMatt Arsenault       ShiftOffset += ShiftAmt;
2310ba40d4cSMatt Arsenault     else
2320ba40d4cSMatt Arsenault       ShiftOffset -= ShiftAmt;
2330ba40d4cSMatt Arsenault 
2340ba40d4cSMatt Arsenault     MatchInfo.CvtVal = Src0;
2350ba40d4cSMatt Arsenault     MatchInfo.ShiftOffset = ShiftOffset;
2360ba40d4cSMatt Arsenault     return ShiftOffset < 32 && ShiftOffset >= 8 && (ShiftOffset % 8) == 0;
2370ba40d4cSMatt Arsenault   }
2380ba40d4cSMatt Arsenault 
2390ba40d4cSMatt Arsenault   // TODO: Simplify demanded bits.
2400ba40d4cSMatt Arsenault   return false;
2410ba40d4cSMatt Arsenault }
2420ba40d4cSMatt Arsenault 
2430031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyCvtF32UByteN(
2440031418dSPetar Avramovic     MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) {
2450031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
2460ba40d4cSMatt Arsenault   unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8;
2470ba40d4cSMatt Arsenault 
2480ba40d4cSMatt Arsenault   const LLT S32 = LLT::scalar(32);
2490ba40d4cSMatt Arsenault   Register CvtSrc = MatchInfo.CvtVal;
2500031418dSPetar Avramovic   LLT SrcTy = MRI.getType(MatchInfo.CvtVal);
2510ba40d4cSMatt Arsenault   if (SrcTy != S32) {
2520ba40d4cSMatt Arsenault     assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8);
2530ba40d4cSMatt Arsenault     CvtSrc = B.buildAnyExt(S32, CvtSrc).getReg(0);
2540ba40d4cSMatt Arsenault   }
2550ba40d4cSMatt Arsenault 
2560ba40d4cSMatt Arsenault   assert(MI.getOpcode() != NewOpc);
2570ba40d4cSMatt Arsenault   B.buildInstr(NewOpc, {MI.getOperand(0)}, {CvtSrc}, MI.getFlags());
2580ba40d4cSMatt Arsenault   MI.eraseFromParent();
2590ba40d4cSMatt Arsenault }
2600ba40d4cSMatt Arsenault 
261*62af0305SThomas Symalla bool AMDGPUPostLegalizerCombinerHelper::matchClampI64ToI16(MachineInstr &MI, MachineRegisterInfo &MRI,
262*62af0305SThomas Symalla                                MachineFunction &MF,
263*62af0305SThomas Symalla                                ClampI64ToI16MatchInfo &MatchInfo) {
264*62af0305SThomas Symalla   assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Invalid instruction!");
265*62af0305SThomas Symalla   const LLT SrcType = MRI.getType(MI.getOperand(1).getReg());
266*62af0305SThomas Symalla   if (SrcType != LLT::scalar(64))
267*62af0305SThomas Symalla     return false;
268*62af0305SThomas Symalla 
269*62af0305SThomas Symalla   MachineIRBuilder B(MI);
270*62af0305SThomas Symalla 
271*62af0305SThomas Symalla   LLVM_DEBUG(dbgs() << "Matching Clamp i64 to i16");
272*62af0305SThomas Symalla 
273*62af0305SThomas Symalla   if (mi_match(MI.getOperand(1).getReg(), MRI,
274*62af0305SThomas Symalla                m_MaxMin(m_ICst(MatchInfo.Cmp1),
275*62af0305SThomas Symalla                         m_ICst(MatchInfo.Cmp2),
276*62af0305SThomas Symalla                         m_Reg(MatchInfo.Origin)))) {
277*62af0305SThomas Symalla     const auto Cmp1 = static_cast<int64_t>(MatchInfo.Cmp1);
278*62af0305SThomas Symalla     const auto Cmp2 = static_cast<int64_t>(MatchInfo.Cmp2);
279*62af0305SThomas Symalla 
280*62af0305SThomas Symalla     const int64_t Min = static_cast<int64_t>(std::numeric_limits<int16_t>::min());
281*62af0305SThomas Symalla     const int64_t Max = static_cast<int64_t>(std::numeric_limits<int16_t>::max());
282*62af0305SThomas Symalla 
283*62af0305SThomas Symalla     // are we really trying to clamp against short boundaries?
284*62af0305SThomas Symalla     return ((Cmp2 >= Cmp1 && Cmp1 >= Min && Cmp2 <= Max) ||
285*62af0305SThomas Symalla             (Cmp1 >= Cmp2 && Cmp1 <= Max && Cmp2 >= Min));
286*62af0305SThomas Symalla   }
287*62af0305SThomas Symalla 
288*62af0305SThomas Symalla   return false;
289*62af0305SThomas Symalla }
290*62af0305SThomas Symalla 
291*62af0305SThomas Symalla void AMDGPUPostLegalizerCombinerHelper::applyClampI64ToI16(MachineInstr &MI,
292*62af0305SThomas Symalla                                const ClampI64ToI16MatchInfo &MatchInfo) {
293*62af0305SThomas Symalla   LLVM_DEBUG(dbgs() << "Combining MI");
294*62af0305SThomas Symalla 
295*62af0305SThomas Symalla   MachineIRBuilder B(MI);
296*62af0305SThomas Symalla   MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo();
297*62af0305SThomas Symalla 
298*62af0305SThomas Symalla   Register Src = MatchInfo.Origin;
299*62af0305SThomas Symalla   assert(MRI.getType(Src) == LLT::scalar(64));
300*62af0305SThomas Symalla   const LLT S32 = LLT::scalar(32);
301*62af0305SThomas Symalla 
302*62af0305SThomas Symalla   auto Unmerge = B.buildUnmerge(S32, Src);
303*62af0305SThomas Symalla   Register Hi32 = Unmerge->getOperand(0).getReg();
304*62af0305SThomas Symalla   Register Lo32 = Unmerge->getOperand(1).getReg();
305*62af0305SThomas Symalla   MRI.setRegClass(Hi32, &AMDGPU::VGPR_32RegClass);
306*62af0305SThomas Symalla   MRI.setRegClass(Lo32, &AMDGPU::VGPR_32RegClass);
307*62af0305SThomas Symalla 
308*62af0305SThomas Symalla   constexpr unsigned int CvtOpcode = AMDGPU::V_CVT_PK_I16_I32_e64;
309*62af0305SThomas Symalla   assert(MI.getOpcode() != CvtOpcode);
310*62af0305SThomas Symalla 
311*62af0305SThomas Symalla   Register CvtDst = MRI.createGenericVirtualRegister(S32);
312*62af0305SThomas Symalla   MRI.setRegClass(CvtDst, &AMDGPU::VGPR_32RegClass);
313*62af0305SThomas Symalla 
314*62af0305SThomas Symalla   auto CvtPk = B.buildInstr(CvtOpcode);
315*62af0305SThomas Symalla   CvtPk.addDef(CvtDst);
316*62af0305SThomas Symalla   CvtPk.addReg(Hi32);
317*62af0305SThomas Symalla   CvtPk.addReg(Lo32);
318*62af0305SThomas Symalla   CvtPk.setMIFlags(MI.getFlags());
319*62af0305SThomas Symalla 
320*62af0305SThomas Symalla   auto min = std::min(MatchInfo.Cmp1, MatchInfo.Cmp2);
321*62af0305SThomas Symalla   auto max = std::max(MatchInfo.Cmp1, MatchInfo.Cmp2);
322*62af0305SThomas Symalla 
323*62af0305SThomas Symalla   Register MinBoundaryDst = MRI.createGenericVirtualRegister(S32);
324*62af0305SThomas Symalla   MRI.setRegClass(MinBoundaryDst, &AMDGPU::VGPR_32RegClass);
325*62af0305SThomas Symalla   B.buildConstant(MinBoundaryDst, min);
326*62af0305SThomas Symalla 
327*62af0305SThomas Symalla   Register MaxBoundaryDst = MRI.createGenericVirtualRegister(S32);
328*62af0305SThomas Symalla   MRI.setRegClass(MaxBoundaryDst, &AMDGPU::VGPR_32RegClass);
329*62af0305SThomas Symalla   B.buildConstant(MaxBoundaryDst, max);
330*62af0305SThomas Symalla 
331*62af0305SThomas Symalla   Register MedDst = MRI.createGenericVirtualRegister(S32);
332*62af0305SThomas Symalla   MRI.setRegClass(MedDst, &AMDGPU::VGPR_32RegClass);
333*62af0305SThomas Symalla 
334*62af0305SThomas Symalla   auto Med = B.buildInstr(AMDGPU::V_MED3_I32);
335*62af0305SThomas Symalla   Med.addDef(MedDst);
336*62af0305SThomas Symalla   Med.addReg(MinBoundaryDst);
337*62af0305SThomas Symalla   Med.addReg(CvtDst);
338*62af0305SThomas Symalla   Med.addReg(MaxBoundaryDst);
339*62af0305SThomas Symalla   Med.setMIFlags(MI.getFlags());
340*62af0305SThomas Symalla 
341*62af0305SThomas Symalla   B.buildCopy(MI.getOperand(0).getReg(), MedDst);
342*62af0305SThomas Symalla 
343*62af0305SThomas Symalla   MI.eraseFromParent();
344*62af0305SThomas Symalla }
345*62af0305SThomas Symalla 
3460031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelperState {
3470031418dSPetar Avramovic protected:
3480031418dSPetar Avramovic   CombinerHelper &Helper;
3490031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper;
3500031418dSPetar Avramovic 
3510031418dSPetar Avramovic public:
3520031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelperState(
3530031418dSPetar Avramovic       CombinerHelper &Helper,
3540031418dSPetar Avramovic       AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper)
3550031418dSPetar Avramovic       : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper) {}
3560031418dSPetar Avramovic };
3570031418dSPetar Avramovic 
358fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
359fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
360fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
361fee41517SMatt Arsenault 
362fee41517SMatt Arsenault namespace {
363fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
364fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
365fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
366fee41517SMatt Arsenault 
36716bcd545SMatt Arsenault class AMDGPUPostLegalizerCombinerInfo final : public CombinerInfo {
368fee41517SMatt Arsenault   GISelKnownBits *KB;
369fee41517SMatt Arsenault   MachineDominatorTree *MDT;
370fee41517SMatt Arsenault 
371fee41517SMatt Arsenault public:
372e35ba099SDaniel Sanders   AMDGPUGenPostLegalizerCombinerHelperRuleConfig GeneratedRuleCfg;
373fee41517SMatt Arsenault 
374fee41517SMatt Arsenault   AMDGPUPostLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize,
375fee41517SMatt Arsenault                                   const AMDGPULegalizerInfo *LI,
376fee41517SMatt Arsenault                                   GISelKnownBits *KB, MachineDominatorTree *MDT)
377fee41517SMatt Arsenault       : CombinerInfo(/*AllowIllegalOps*/ false, /*ShouldLegalizeIllegal*/ true,
378fee41517SMatt Arsenault                      /*LegalizerInfo*/ LI, EnableOpt, OptSize, MinSize),
379fee41517SMatt Arsenault         KB(KB), MDT(MDT) {
380e35ba099SDaniel Sanders     if (!GeneratedRuleCfg.parseCommandLineOption())
381fee41517SMatt Arsenault       report_fatal_error("Invalid rule identifier");
382fee41517SMatt Arsenault   }
383fee41517SMatt Arsenault 
384d15723efSMatt Arsenault   bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
385fee41517SMatt Arsenault                MachineIRBuilder &B) const override;
386fee41517SMatt Arsenault };
387fee41517SMatt Arsenault 
388fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
389fee41517SMatt Arsenault                                               MachineInstr &MI,
390fee41517SMatt Arsenault                                               MachineIRBuilder &B) const {
39166ffa0e9SMatt Arsenault   CombinerHelper Helper(Observer, B, KB, MDT, LInfo);
3920031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper PostLegalizerHelper(B, Helper);
3930031418dSPetar Avramovic   AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper,
3940031418dSPetar Avramovic                                                  PostLegalizerHelper);
395fee41517SMatt Arsenault 
3960031418dSPetar Avramovic   if (Generated.tryCombineAll(Observer, MI, B))
397fee41517SMatt Arsenault     return true;
398fee41517SMatt Arsenault 
399fee41517SMatt Arsenault   switch (MI.getOpcode()) {
400fee41517SMatt Arsenault   case TargetOpcode::G_SHL:
401fee41517SMatt Arsenault   case TargetOpcode::G_LSHR:
402fee41517SMatt Arsenault   case TargetOpcode::G_ASHR:
403fee41517SMatt Arsenault     // On some subtargets, 64-bit shift is a quarter rate instruction. In the
404fee41517SMatt Arsenault     // common case, splitting this into a move and a 32-bit shift is faster and
405fee41517SMatt Arsenault     // the same code size.
406fee41517SMatt Arsenault     return Helper.tryCombineShiftToUnmerge(MI, 32);
407fee41517SMatt Arsenault   }
408fee41517SMatt Arsenault 
409fee41517SMatt Arsenault   return false;
410fee41517SMatt Arsenault }
411fee41517SMatt Arsenault 
412fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
413fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
414fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
415fee41517SMatt Arsenault 
416fee41517SMatt Arsenault // Pass boilerplate
417fee41517SMatt Arsenault // ================
418fee41517SMatt Arsenault 
419fee41517SMatt Arsenault class AMDGPUPostLegalizerCombiner : public MachineFunctionPass {
420fee41517SMatt Arsenault public:
421fee41517SMatt Arsenault   static char ID;
422fee41517SMatt Arsenault 
423fee41517SMatt Arsenault   AMDGPUPostLegalizerCombiner(bool IsOptNone = false);
424fee41517SMatt Arsenault 
425fee41517SMatt Arsenault   StringRef getPassName() const override {
426fee41517SMatt Arsenault     return "AMDGPUPostLegalizerCombiner";
427fee41517SMatt Arsenault   }
428fee41517SMatt Arsenault 
429fee41517SMatt Arsenault   bool runOnMachineFunction(MachineFunction &MF) override;
430fee41517SMatt Arsenault 
431fee41517SMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override;
432fee41517SMatt Arsenault private:
433fee41517SMatt Arsenault   bool IsOptNone;
434fee41517SMatt Arsenault };
435fee41517SMatt Arsenault } // end anonymous namespace
436fee41517SMatt Arsenault 
437fee41517SMatt Arsenault void AMDGPUPostLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
438fee41517SMatt Arsenault   AU.addRequired<TargetPassConfig>();
439fee41517SMatt Arsenault   AU.setPreservesCFG();
440fee41517SMatt Arsenault   getSelectionDAGFallbackAnalysisUsage(AU);
441fee41517SMatt Arsenault   AU.addRequired<GISelKnownBitsAnalysis>();
442fee41517SMatt Arsenault   AU.addPreserved<GISelKnownBitsAnalysis>();
443fee41517SMatt Arsenault   if (!IsOptNone) {
444fee41517SMatt Arsenault     AU.addRequired<MachineDominatorTree>();
445fee41517SMatt Arsenault     AU.addPreserved<MachineDominatorTree>();
446fee41517SMatt Arsenault   }
447fee41517SMatt Arsenault   MachineFunctionPass::getAnalysisUsage(AU);
448fee41517SMatt Arsenault }
449fee41517SMatt Arsenault 
450fee41517SMatt Arsenault AMDGPUPostLegalizerCombiner::AMDGPUPostLegalizerCombiner(bool IsOptNone)
451fee41517SMatt Arsenault   : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
452fee41517SMatt Arsenault   initializeAMDGPUPostLegalizerCombinerPass(*PassRegistry::getPassRegistry());
453fee41517SMatt Arsenault }
454fee41517SMatt Arsenault 
455fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
456fee41517SMatt Arsenault   if (MF.getProperties().hasProperty(
457fee41517SMatt Arsenault           MachineFunctionProperties::Property::FailedISel))
458fee41517SMatt Arsenault     return false;
459fee41517SMatt Arsenault   auto *TPC = &getAnalysis<TargetPassConfig>();
460fee41517SMatt Arsenault   const Function &F = MF.getFunction();
461fee41517SMatt Arsenault   bool EnableOpt =
462fee41517SMatt Arsenault       MF.getTarget().getOptLevel() != CodeGenOpt::None && !skipFunction(F);
463fee41517SMatt Arsenault 
464fee41517SMatt Arsenault   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
465fee41517SMatt Arsenault   const AMDGPULegalizerInfo *LI
466fee41517SMatt Arsenault     = static_cast<const AMDGPULegalizerInfo *>(ST.getLegalizerInfo());
467fee41517SMatt Arsenault 
468fee41517SMatt Arsenault   GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF);
469fee41517SMatt Arsenault   MachineDominatorTree *MDT =
470fee41517SMatt Arsenault       IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>();
471fee41517SMatt Arsenault   AMDGPUPostLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(),
472fee41517SMatt Arsenault                                          F.hasMinSize(), LI, KB, MDT);
473fee41517SMatt Arsenault   Combiner C(PCInfo, TPC);
474fee41517SMatt Arsenault   return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr);
475fee41517SMatt Arsenault }
476fee41517SMatt Arsenault 
477fee41517SMatt Arsenault char AMDGPUPostLegalizerCombiner::ID = 0;
478fee41517SMatt Arsenault INITIALIZE_PASS_BEGIN(AMDGPUPostLegalizerCombiner, DEBUG_TYPE,
479fee41517SMatt Arsenault                       "Combine AMDGPU machine instrs after legalization",
480fee41517SMatt Arsenault                       false, false)
481fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
482fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis)
483fee41517SMatt Arsenault INITIALIZE_PASS_END(AMDGPUPostLegalizerCombiner, DEBUG_TYPE,
484fee41517SMatt Arsenault                     "Combine AMDGPU machine instrs after legalization", false,
485fee41517SMatt Arsenault                     false)
486fee41517SMatt Arsenault 
487fee41517SMatt Arsenault namespace llvm {
488fee41517SMatt Arsenault FunctionPass *createAMDGPUPostLegalizeCombiner(bool IsOptNone) {
489fee41517SMatt Arsenault   return new AMDGPUPostLegalizerCombiner(IsOptNone);
490fee41517SMatt Arsenault }
491fee41517SMatt Arsenault } // end namespace llvm
492