19a8da909SThomas Symalla //=== 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 
14ec043967SThomas Symalla <<<<<<< HEAD
156a87e9b0Sdfukalov #include "AMDGPU.h"
16fee41517SMatt Arsenault #include "AMDGPULegalizerInfo.h"
17560d7e04Sdfukalov #include "GCNSubtarget.h"
18ec043967SThomas Symalla =======
19ec043967SThomas Symalla #include "AMDGPULegalizerInfo.h"
20ec043967SThomas Symalla #include "AMDGPUTargetMachine.h"
21ec043967SThomas Symalla >>>>>>> clang-format
22560d7e04Sdfukalov #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
23fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/Combiner.h"
24fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
25fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
26fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
27fee41517SMatt Arsenault #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
28fee41517SMatt Arsenault #include "llvm/CodeGen/MachineDominators.h"
29fee41517SMatt Arsenault #include "llvm/CodeGen/TargetPassConfig.h"
30ec043967SThomas Symalla <<<<<<< HEAD
316a87e9b0Sdfukalov #include "llvm/Target/TargetMachine.h"
32ec043967SThomas Symalla =======
33ec043967SThomas Symalla #include "llvm/Support/Debug.h"
34ec043967SThomas Symalla >>>>>>> clang-format
35fee41517SMatt Arsenault 
36fee41517SMatt Arsenault #define DEBUG_TYPE "amdgpu-postlegalizer-combiner"
37fee41517SMatt Arsenault 
38fee41517SMatt Arsenault using namespace llvm;
39fee41517SMatt Arsenault using namespace MIPatternMatch;
40fee41517SMatt Arsenault 
410031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelper {
420031418dSPetar Avramovic protected:
430031418dSPetar Avramovic   MachineIRBuilder &B;
440031418dSPetar Avramovic   MachineFunction &MF;
450031418dSPetar Avramovic   MachineRegisterInfo &MRI;
460031418dSPetar Avramovic   CombinerHelper &Helper;
470031418dSPetar Avramovic 
480031418dSPetar Avramovic public:
490031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper(MachineIRBuilder &B, CombinerHelper &Helper)
500031418dSPetar Avramovic       : B(B), MF(B.getMF()), MRI(*B.getMRI()), Helper(Helper){};
510031418dSPetar Avramovic 
52fee41517SMatt Arsenault   struct FMinFMaxLegacyInfo {
53fee41517SMatt Arsenault     Register LHS;
54fee41517SMatt Arsenault     Register RHS;
55fee41517SMatt Arsenault     Register True;
56fee41517SMatt Arsenault     Register False;
57fee41517SMatt Arsenault     CmpInst::Predicate Pred;
58fee41517SMatt Arsenault   };
59fee41517SMatt Arsenault 
60fee41517SMatt Arsenault   // TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize
610031418dSPetar Avramovic   bool matchFMinFMaxLegacy(MachineInstr &MI, FMinFMaxLegacyInfo &Info);
620031418dSPetar Avramovic   void applySelectFCmpToFMinToFMaxLegacy(MachineInstr &MI,
630031418dSPetar Avramovic                                          const FMinFMaxLegacyInfo &Info);
640031418dSPetar Avramovic 
650031418dSPetar Avramovic   bool matchUCharToFloat(MachineInstr &MI);
660031418dSPetar Avramovic   void applyUCharToFloat(MachineInstr &MI);
670031418dSPetar Avramovic 
680031418dSPetar Avramovic   // FIXME: Should be able to have 2 separate matchdatas rather than custom
690031418dSPetar Avramovic   // struct boilerplate.
700031418dSPetar Avramovic   struct CvtF32UByteMatchInfo {
710031418dSPetar Avramovic     Register CvtVal;
720031418dSPetar Avramovic     unsigned ShiftOffset;
730031418dSPetar Avramovic   };
740031418dSPetar Avramovic 
750031418dSPetar Avramovic   bool matchCvtF32UByteN(MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo);
760031418dSPetar Avramovic   void applyCvtF32UByteN(MachineInstr &MI,
770031418dSPetar Avramovic                          const CvtF32UByteMatchInfo &MatchInfo);
780031418dSPetar Avramovic };
790031418dSPetar Avramovic 
800031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchFMinFMaxLegacy(
810031418dSPetar Avramovic     MachineInstr &MI, FMinFMaxLegacyInfo &Info) {
82fee41517SMatt Arsenault   // FIXME: Combines should have subtarget predicates, and we shouldn't need
83fee41517SMatt Arsenault   // this here.
84fee41517SMatt Arsenault   if (!MF.getSubtarget<GCNSubtarget>().hasFminFmaxLegacy())
85fee41517SMatt Arsenault     return false;
86fee41517SMatt Arsenault 
87fee41517SMatt Arsenault   // FIXME: Type predicate on pattern
88fee41517SMatt Arsenault   if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(32))
89fee41517SMatt Arsenault     return false;
90fee41517SMatt Arsenault 
91fee41517SMatt Arsenault   Register Cond = MI.getOperand(1).getReg();
92fee41517SMatt Arsenault   if (!MRI.hasOneNonDBGUse(Cond) ||
93fee41517SMatt Arsenault       !mi_match(Cond, MRI,
94fee41517SMatt Arsenault                 m_GFCmp(m_Pred(Info.Pred), m_Reg(Info.LHS), m_Reg(Info.RHS))))
95fee41517SMatt Arsenault     return false;
96fee41517SMatt Arsenault 
97fee41517SMatt Arsenault   Info.True = MI.getOperand(2).getReg();
98fee41517SMatt Arsenault   Info.False = MI.getOperand(3).getReg();
99fee41517SMatt Arsenault 
100fee41517SMatt Arsenault   if (!(Info.LHS == Info.True && Info.RHS == Info.False) &&
101fee41517SMatt Arsenault       !(Info.LHS == Info.False && Info.RHS == Info.True))
102fee41517SMatt Arsenault     return false;
103fee41517SMatt Arsenault 
104fee41517SMatt Arsenault   switch (Info.Pred) {
105fee41517SMatt Arsenault   case CmpInst::FCMP_FALSE:
106fee41517SMatt Arsenault   case CmpInst::FCMP_OEQ:
107fee41517SMatt Arsenault   case CmpInst::FCMP_ONE:
108fee41517SMatt Arsenault   case CmpInst::FCMP_ORD:
109fee41517SMatt Arsenault   case CmpInst::FCMP_UNO:
110fee41517SMatt Arsenault   case CmpInst::FCMP_UEQ:
111fee41517SMatt Arsenault   case CmpInst::FCMP_UNE:
112fee41517SMatt Arsenault   case CmpInst::FCMP_TRUE:
113fee41517SMatt Arsenault     return false;
114fee41517SMatt Arsenault   default:
115fee41517SMatt Arsenault     return true;
116fee41517SMatt Arsenault   }
117fee41517SMatt Arsenault }
118fee41517SMatt Arsenault 
1190031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applySelectFCmpToFMinToFMaxLegacy(
1200031418dSPetar Avramovic     MachineInstr &MI, const FMinFMaxLegacyInfo &Info) {
1210031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
1220031418dSPetar Avramovic   auto buildNewInst = [&MI, this](unsigned Opc, Register X, Register Y) {
1230031418dSPetar Avramovic     B.buildInstr(Opc, {MI.getOperand(0)}, {X, Y}, MI.getFlags());
124fee41517SMatt Arsenault   };
125fee41517SMatt Arsenault 
126fee41517SMatt Arsenault   switch (Info.Pred) {
127fee41517SMatt Arsenault   case CmpInst::FCMP_ULT:
128fee41517SMatt Arsenault   case CmpInst::FCMP_ULE:
129fee41517SMatt Arsenault     if (Info.LHS == Info.True)
130fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS);
131fee41517SMatt Arsenault     else
132fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS);
133fee41517SMatt Arsenault     break;
134fee41517SMatt Arsenault   case CmpInst::FCMP_OLE:
135fee41517SMatt Arsenault   case CmpInst::FCMP_OLT: {
136fee41517SMatt Arsenault     // We need to permute the operands to get the correct NaN behavior. The
137fee41517SMatt Arsenault     // selected operand is the second one based on the failing compare with NaN,
138fee41517SMatt Arsenault     // so permute it based on the compare type the hardware uses.
139fee41517SMatt Arsenault     if (Info.LHS == Info.True)
140fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS);
141fee41517SMatt Arsenault     else
142fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS);
143fee41517SMatt Arsenault     break;
144fee41517SMatt Arsenault   }
145fee41517SMatt Arsenault   case CmpInst::FCMP_UGE:
146fee41517SMatt Arsenault   case CmpInst::FCMP_UGT: {
147fee41517SMatt Arsenault     if (Info.LHS == Info.True)
148fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.RHS, Info.LHS);
149fee41517SMatt Arsenault     else
150fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.LHS, Info.RHS);
151fee41517SMatt Arsenault     break;
152fee41517SMatt Arsenault   }
153fee41517SMatt Arsenault   case CmpInst::FCMP_OGT:
154fee41517SMatt Arsenault   case CmpInst::FCMP_OGE: {
155fee41517SMatt Arsenault     if (Info.LHS == Info.True)
156fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMAX_LEGACY, Info.LHS, Info.RHS);
157fee41517SMatt Arsenault     else
158fee41517SMatt Arsenault       buildNewInst(AMDGPU::G_AMDGPU_FMIN_LEGACY, Info.RHS, Info.LHS);
159fee41517SMatt Arsenault     break;
160fee41517SMatt Arsenault   }
161fee41517SMatt Arsenault   default:
162fee41517SMatt Arsenault     llvm_unreachable("predicate should not have matched");
163fee41517SMatt Arsenault   }
164fee41517SMatt Arsenault 
165fee41517SMatt Arsenault   MI.eraseFromParent();
166fee41517SMatt Arsenault }
167fee41517SMatt Arsenault 
1680031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchUCharToFloat(MachineInstr &MI) {
169b27d255eSMatt Arsenault   Register DstReg = MI.getOperand(0).getReg();
170b27d255eSMatt Arsenault 
171b27d255eSMatt Arsenault   // TODO: We could try to match extracting the higher bytes, which would be
172b27d255eSMatt Arsenault   // easier if i8 vectors weren't promoted to i32 vectors, particularly after
173b27d255eSMatt Arsenault   // types are legalized. v4i8 -> v4f32 is probably the only case to worry
174b27d255eSMatt Arsenault   // about in practice.
175b27d255eSMatt Arsenault   LLT Ty = MRI.getType(DstReg);
176b27d255eSMatt Arsenault   if (Ty == LLT::scalar(32) || Ty == LLT::scalar(16)) {
177db777eaeSMatt Arsenault     Register SrcReg = MI.getOperand(1).getReg();
178db777eaeSMatt Arsenault     unsigned SrcSize = MRI.getType(SrcReg).getSizeInBits();
179db777eaeSMatt Arsenault     assert(SrcSize == 16 || SrcSize == 32 || SrcSize == 64);
180db777eaeSMatt Arsenault     const APInt Mask = APInt::getHighBitsSet(SrcSize, SrcSize - 8);
181db777eaeSMatt Arsenault     return Helper.getKnownBits()->maskedValueIsZero(SrcReg, Mask);
182b27d255eSMatt Arsenault   }
183b27d255eSMatt Arsenault 
184b27d255eSMatt Arsenault   return false;
185b27d255eSMatt Arsenault }
186b27d255eSMatt Arsenault 
1870031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyUCharToFloat(MachineInstr &MI) {
1880031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
189b27d255eSMatt Arsenault 
190b27d255eSMatt Arsenault   const LLT S32 = LLT::scalar(32);
191b27d255eSMatt Arsenault 
192b27d255eSMatt Arsenault   Register DstReg = MI.getOperand(0).getReg();
193db777eaeSMatt Arsenault   Register SrcReg = MI.getOperand(1).getReg();
1940031418dSPetar Avramovic   LLT Ty = MRI.getType(DstReg);
1950031418dSPetar Avramovic   LLT SrcTy = MRI.getType(SrcReg);
196db777eaeSMatt Arsenault   if (SrcTy != S32)
197db777eaeSMatt Arsenault     SrcReg = B.buildAnyExtOrTrunc(S32, SrcReg).getReg(0);
198b27d255eSMatt Arsenault 
199b27d255eSMatt Arsenault   if (Ty == S32) {
200*ecbed4e0SThomas Symalla     B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {DstReg},
201*ecbed4e0SThomas Symalla                    {SrcReg}, MI.getFlags());
202b27d255eSMatt Arsenault   } else {
203*ecbed4e0SThomas Symalla     auto Cvt0 = B.buildInstr(AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, {S32},
204*ecbed4e0SThomas Symalla                              {SrcReg}, MI.getFlags());
205b27d255eSMatt Arsenault     B.buildFPTrunc(DstReg, Cvt0, MI.getFlags());
206b27d255eSMatt Arsenault   }
207b27d255eSMatt Arsenault 
208b27d255eSMatt Arsenault   MI.eraseFromParent();
209b27d255eSMatt Arsenault }
210fee41517SMatt Arsenault 
2110031418dSPetar Avramovic bool AMDGPUPostLegalizerCombinerHelper::matchCvtF32UByteN(
2120031418dSPetar Avramovic     MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) {
2130ba40d4cSMatt Arsenault   Register SrcReg = MI.getOperand(1).getReg();
2140ba40d4cSMatt Arsenault 
2150ba40d4cSMatt Arsenault   // Look through G_ZEXT.
2160ba40d4cSMatt Arsenault   mi_match(SrcReg, MRI, m_GZExt(m_Reg(SrcReg)));
2170ba40d4cSMatt Arsenault 
2180ba40d4cSMatt Arsenault   Register Src0;
2190ba40d4cSMatt Arsenault   int64_t ShiftAmt;
2200ba40d4cSMatt Arsenault   bool IsShr = mi_match(SrcReg, MRI, m_GLShr(m_Reg(Src0), m_ICst(ShiftAmt)));
2210ba40d4cSMatt Arsenault   if (IsShr || mi_match(SrcReg, MRI, m_GShl(m_Reg(Src0), m_ICst(ShiftAmt)))) {
2220ba40d4cSMatt Arsenault     const unsigned Offset = MI.getOpcode() - AMDGPU::G_AMDGPU_CVT_F32_UBYTE0;
2230ba40d4cSMatt Arsenault 
2240ba40d4cSMatt Arsenault     unsigned ShiftOffset = 8 * Offset;
2250ba40d4cSMatt Arsenault     if (IsShr)
2260ba40d4cSMatt Arsenault       ShiftOffset += ShiftAmt;
2270ba40d4cSMatt Arsenault     else
2280ba40d4cSMatt Arsenault       ShiftOffset -= ShiftAmt;
2290ba40d4cSMatt Arsenault 
2300ba40d4cSMatt Arsenault     MatchInfo.CvtVal = Src0;
2310ba40d4cSMatt Arsenault     MatchInfo.ShiftOffset = ShiftOffset;
2320ba40d4cSMatt Arsenault     return ShiftOffset < 32 && ShiftOffset >= 8 && (ShiftOffset % 8) == 0;
2330ba40d4cSMatt Arsenault   }
2340ba40d4cSMatt Arsenault 
2350ba40d4cSMatt Arsenault   // TODO: Simplify demanded bits.
2360ba40d4cSMatt Arsenault   return false;
2370ba40d4cSMatt Arsenault }
2380ba40d4cSMatt Arsenault 
2390031418dSPetar Avramovic void AMDGPUPostLegalizerCombinerHelper::applyCvtF32UByteN(
2400031418dSPetar Avramovic     MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) {
2410031418dSPetar Avramovic   B.setInstrAndDebugLoc(MI);
2420ba40d4cSMatt Arsenault   unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8;
2430ba40d4cSMatt Arsenault 
2440ba40d4cSMatt Arsenault   const LLT S32 = LLT::scalar(32);
2450ba40d4cSMatt Arsenault   Register CvtSrc = MatchInfo.CvtVal;
2460031418dSPetar Avramovic   LLT SrcTy = MRI.getType(MatchInfo.CvtVal);
2470ba40d4cSMatt Arsenault   if (SrcTy != S32) {
2480ba40d4cSMatt Arsenault     assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8);
2490ba40d4cSMatt Arsenault     CvtSrc = B.buildAnyExt(S32, CvtSrc).getReg(0);
2500ba40d4cSMatt Arsenault   }
2510ba40d4cSMatt Arsenault 
2520ba40d4cSMatt Arsenault   assert(MI.getOpcode() != NewOpc);
2530ba40d4cSMatt Arsenault   B.buildInstr(NewOpc, {MI.getOperand(0)}, {CvtSrc}, MI.getFlags());
2540ba40d4cSMatt Arsenault   MI.eraseFromParent();
2550ba40d4cSMatt Arsenault }
2560ba40d4cSMatt Arsenault 
2570031418dSPetar Avramovic class AMDGPUPostLegalizerCombinerHelperState {
2580031418dSPetar Avramovic protected:
2590031418dSPetar Avramovic   CombinerHelper &Helper;
2600031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper;
2610031418dSPetar Avramovic 
2620031418dSPetar Avramovic public:
2630031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelperState(
2640031418dSPetar Avramovic       CombinerHelper &Helper,
2650031418dSPetar Avramovic       AMDGPUPostLegalizerCombinerHelper &PostLegalizerHelper)
2660031418dSPetar Avramovic       : Helper(Helper), PostLegalizerHelper(PostLegalizerHelper) {}
2670031418dSPetar Avramovic };
2680031418dSPetar Avramovic 
269fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
270fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
271fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_DEPS
272fee41517SMatt Arsenault 
273fee41517SMatt Arsenault namespace {
274fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
275fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
276fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_H
277fee41517SMatt Arsenault 
27816bcd545SMatt Arsenault class AMDGPUPostLegalizerCombinerInfo final : public CombinerInfo {
279fee41517SMatt Arsenault   GISelKnownBits *KB;
280fee41517SMatt Arsenault   MachineDominatorTree *MDT;
281fee41517SMatt Arsenault 
282fee41517SMatt Arsenault public:
283e35ba099SDaniel Sanders   AMDGPUGenPostLegalizerCombinerHelperRuleConfig GeneratedRuleCfg;
284fee41517SMatt Arsenault 
285fee41517SMatt Arsenault   AMDGPUPostLegalizerCombinerInfo(bool EnableOpt, bool OptSize, bool MinSize,
286fee41517SMatt Arsenault                                   const AMDGPULegalizerInfo *LI,
287fee41517SMatt Arsenault                                   GISelKnownBits *KB, MachineDominatorTree *MDT)
288fee41517SMatt Arsenault       : CombinerInfo(/*AllowIllegalOps*/ false, /*ShouldLegalizeIllegal*/ true,
289fee41517SMatt Arsenault                      /*LegalizerInfo*/ LI, EnableOpt, OptSize, MinSize),
290fee41517SMatt Arsenault         KB(KB), MDT(MDT) {
291e35ba099SDaniel Sanders     if (!GeneratedRuleCfg.parseCommandLineOption())
292fee41517SMatt Arsenault       report_fatal_error("Invalid rule identifier");
293fee41517SMatt Arsenault   }
294fee41517SMatt Arsenault 
295d15723efSMatt Arsenault   bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
296fee41517SMatt Arsenault                MachineIRBuilder &B) const override;
297fee41517SMatt Arsenault };
298fee41517SMatt Arsenault 
299fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombinerInfo::combine(GISelChangeObserver &Observer,
300fee41517SMatt Arsenault                                               MachineInstr &MI,
301fee41517SMatt Arsenault                                               MachineIRBuilder &B) const {
30266ffa0e9SMatt Arsenault   CombinerHelper Helper(Observer, B, KB, MDT, LInfo);
3030031418dSPetar Avramovic   AMDGPUPostLegalizerCombinerHelper PostLegalizerHelper(B, Helper);
3040031418dSPetar Avramovic   AMDGPUGenPostLegalizerCombinerHelper Generated(GeneratedRuleCfg, Helper,
3050031418dSPetar Avramovic                                                  PostLegalizerHelper);
306fee41517SMatt Arsenault 
3070031418dSPetar Avramovic   if (Generated.tryCombineAll(Observer, MI, B))
308fee41517SMatt Arsenault     return true;
309fee41517SMatt Arsenault 
310fee41517SMatt Arsenault   switch (MI.getOpcode()) {
311fee41517SMatt Arsenault   case TargetOpcode::G_SHL:
312fee41517SMatt Arsenault   case TargetOpcode::G_LSHR:
313fee41517SMatt Arsenault   case TargetOpcode::G_ASHR:
314fee41517SMatt Arsenault     // On some subtargets, 64-bit shift is a quarter rate instruction. In the
315fee41517SMatt Arsenault     // common case, splitting this into a move and a 32-bit shift is faster and
316fee41517SMatt Arsenault     // the same code size.
317fee41517SMatt Arsenault     return Helper.tryCombineShiftToUnmerge(MI, 32);
318fee41517SMatt Arsenault   }
319fee41517SMatt Arsenault 
320fee41517SMatt Arsenault   return false;
321fee41517SMatt Arsenault }
322fee41517SMatt Arsenault 
323fee41517SMatt Arsenault #define AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
324fee41517SMatt Arsenault #include "AMDGPUGenPostLegalizeGICombiner.inc"
325fee41517SMatt Arsenault #undef AMDGPUPOSTLEGALIZERCOMBINERHELPER_GENCOMBINERHELPER_CPP
326fee41517SMatt Arsenault 
327fee41517SMatt Arsenault // Pass boilerplate
328fee41517SMatt Arsenault // ================
329fee41517SMatt Arsenault 
330fee41517SMatt Arsenault class AMDGPUPostLegalizerCombiner : public MachineFunctionPass {
331fee41517SMatt Arsenault public:
332fee41517SMatt Arsenault   static char ID;
333fee41517SMatt Arsenault 
334fee41517SMatt Arsenault   AMDGPUPostLegalizerCombiner(bool IsOptNone = false);
335fee41517SMatt Arsenault 
336fee41517SMatt Arsenault   StringRef getPassName() const override {
337fee41517SMatt Arsenault     return "AMDGPUPostLegalizerCombiner";
338fee41517SMatt Arsenault   }
339fee41517SMatt Arsenault 
340fee41517SMatt Arsenault   bool runOnMachineFunction(MachineFunction &MF) override;
341fee41517SMatt Arsenault 
342fee41517SMatt Arsenault   void getAnalysisUsage(AnalysisUsage &AU) const override;
343ec043967SThomas Symalla 
344fee41517SMatt Arsenault private:
345fee41517SMatt Arsenault   bool IsOptNone;
346fee41517SMatt Arsenault };
347fee41517SMatt Arsenault } // end anonymous namespace
348fee41517SMatt Arsenault 
349fee41517SMatt Arsenault void AMDGPUPostLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const {
350fee41517SMatt Arsenault   AU.addRequired<TargetPassConfig>();
351fee41517SMatt Arsenault   AU.setPreservesCFG();
352fee41517SMatt Arsenault   getSelectionDAGFallbackAnalysisUsage(AU);
353fee41517SMatt Arsenault   AU.addRequired<GISelKnownBitsAnalysis>();
354fee41517SMatt Arsenault   AU.addPreserved<GISelKnownBitsAnalysis>();
355fee41517SMatt Arsenault   if (!IsOptNone) {
356fee41517SMatt Arsenault     AU.addRequired<MachineDominatorTree>();
357fee41517SMatt Arsenault     AU.addPreserved<MachineDominatorTree>();
358fee41517SMatt Arsenault   }
359fee41517SMatt Arsenault   MachineFunctionPass::getAnalysisUsage(AU);
360fee41517SMatt Arsenault }
361fee41517SMatt Arsenault 
362fee41517SMatt Arsenault AMDGPUPostLegalizerCombiner::AMDGPUPostLegalizerCombiner(bool IsOptNone)
363fee41517SMatt Arsenault     : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
364fee41517SMatt Arsenault   initializeAMDGPUPostLegalizerCombinerPass(*PassRegistry::getPassRegistry());
365fee41517SMatt Arsenault }
366fee41517SMatt Arsenault 
367fee41517SMatt Arsenault bool AMDGPUPostLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) {
368fee41517SMatt Arsenault   if (MF.getProperties().hasProperty(
369fee41517SMatt Arsenault           MachineFunctionProperties::Property::FailedISel))
370fee41517SMatt Arsenault     return false;
371fee41517SMatt Arsenault   auto *TPC = &getAnalysis<TargetPassConfig>();
372fee41517SMatt Arsenault   const Function &F = MF.getFunction();
373fee41517SMatt Arsenault   bool EnableOpt =
374fee41517SMatt Arsenault       MF.getTarget().getOptLevel() != CodeGenOpt::None && !skipFunction(F);
375fee41517SMatt Arsenault 
376fee41517SMatt Arsenault   const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
377ec043967SThomas Symalla   const AMDGPULegalizerInfo *LI =
378ec043967SThomas Symalla       static_cast<const AMDGPULegalizerInfo *>(ST.getLegalizerInfo());
379fee41517SMatt Arsenault 
380fee41517SMatt Arsenault   GISelKnownBits *KB = &getAnalysis<GISelKnownBitsAnalysis>().get(MF);
381fee41517SMatt Arsenault   MachineDominatorTree *MDT =
382fee41517SMatt Arsenault       IsOptNone ? nullptr : &getAnalysis<MachineDominatorTree>();
383fee41517SMatt Arsenault   AMDGPUPostLegalizerCombinerInfo PCInfo(EnableOpt, F.hasOptSize(),
384fee41517SMatt Arsenault                                          F.hasMinSize(), LI, KB, MDT);
385fee41517SMatt Arsenault   Combiner C(PCInfo, TPC);
386fee41517SMatt Arsenault   return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr);
387fee41517SMatt Arsenault }
388fee41517SMatt Arsenault 
389fee41517SMatt Arsenault char AMDGPUPostLegalizerCombiner::ID = 0;
390fee41517SMatt Arsenault INITIALIZE_PASS_BEGIN(AMDGPUPostLegalizerCombiner, DEBUG_TYPE,
391ec043967SThomas Symalla                       "Combine AMDGPU machine instrs after legalization", false,
392ec043967SThomas Symalla                       false)
393fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
394fee41517SMatt Arsenault INITIALIZE_PASS_DEPENDENCY(GISelKnownBitsAnalysis)
395fee41517SMatt Arsenault INITIALIZE_PASS_END(AMDGPUPostLegalizerCombiner, DEBUG_TYPE,
396fee41517SMatt Arsenault                     "Combine AMDGPU machine instrs after legalization", false,
397fee41517SMatt Arsenault                     false)
398fee41517SMatt Arsenault 
399fee41517SMatt Arsenault namespace llvm {
400fee41517SMatt Arsenault FunctionPass *createAMDGPUPostLegalizeCombiner(bool IsOptNone) {
401fee41517SMatt Arsenault   return new AMDGPUPostLegalizerCombiner(IsOptNone);
402fee41517SMatt Arsenault }
403fee41517SMatt Arsenault } // end namespace llvm
404