1//=== lib/CodeGen/GlobalISel/AMDGPUPostLegalizerCombiner.cpp --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass does combining of machine instructions at the generic MI level,
10// after the legalizer.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AMDGPU.h"
15#include "AMDGPUCombinerHelper.h"
16#include "AMDGPULegalizerInfo.h"
17#include "GCNSubtarget.h"
18#include "MCTargetDesc/AMDGPUMCTargetDesc.h"
19#include "llvm/CodeGen/GlobalISel/CSEInfo.h"
20#include "llvm/CodeGen/GlobalISel/Combiner.h"
21#include "llvm/CodeGen/GlobalISel/CombinerHelper.h"
22#include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
23#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"
24#include "llvm/CodeGen/GlobalISel/GISelValueTracking.h"
25#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
26#include "llvm/CodeGen/MachineDominators.h"
27#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
28#include "llvm/CodeGen/MachinePassManager.h"
29#include "llvm/CodeGen/TargetPassConfig.h"
30#include "llvm/IR/IntrinsicsAMDGPU.h"
31#include "llvm/Target/TargetMachine.h"
32
33#define GET_GICOMBINER_DEPS
34#include "AMDGPUGenPreLegalizeGICombiner.inc"
35#undef GET_GICOMBINER_DEPS
36
37#define DEBUG_TYPE "amdgpu-postlegalizer-combiner"
38
39using namespace llvm;
40using namespace MIPatternMatch;
41
42namespace {
43#define GET_GICOMBINER_TYPES
44#include "AMDGPUGenPostLegalizeGICombiner.inc"
45#undef GET_GICOMBINER_TYPES
46
47class AMDGPUPostLegalizerCombinerImpl : public Combiner {
48protected:
49 const AMDGPUPostLegalizerCombinerImplRuleConfig &RuleConfig;
50 const GCNSubtarget &STI;
51 const SIInstrInfo &TII;
52 // TODO: Make CombinerHelper methods const.
53 mutable AMDGPUCombinerHelper Helper;
54
55public:
56 AMDGPUPostLegalizerCombinerImpl(
57 MachineFunction &MF, CombinerInfo &CInfo, GISelValueTracking &VT,
58 GISelCSEInfo *CSEInfo,
59 const AMDGPUPostLegalizerCombinerImplRuleConfig &RuleConfig,
60 const GCNSubtarget &STI, MachineDominatorTree *MDT,
61 const LegalizerInfo *LI);
62
63 static const char *getName() { return "AMDGPUPostLegalizerCombinerImpl"; }
64
65 bool tryCombineAllImpl(MachineInstr &I) const;
66 bool tryCombineAll(MachineInstr &I) const override;
67
68 struct FMinFMaxLegacyInfo {
69 Register LHS;
70 Register RHS;
71 CmpInst::Predicate Pred;
72 };
73
74 // TODO: Make sure fmin_legacy/fmax_legacy don't canonicalize
75 bool matchFMinFMaxLegacy(MachineInstr &MI, MachineInstr &FCmp,
76 FMinFMaxLegacyInfo &Info) const;
77 void applySelectFCmpToFMinFMaxLegacy(MachineInstr &MI,
78 const FMinFMaxLegacyInfo &Info) const;
79
80 bool matchUCharToFloat(MachineInstr &MI) const;
81 void applyUCharToFloat(MachineInstr &MI) const;
82
83 bool matchFDivSqrtToRsqF16(MachineInstr &MI) const;
84 void applyFDivSqrtToRsqF16(MachineInstr &MI, const Register &X) const;
85
86 // FIXME: Should be able to have 2 separate matchdatas rather than custom
87 // struct boilerplate.
88 struct CvtF32UByteMatchInfo {
89 Register CvtVal;
90 unsigned ShiftOffset;
91 };
92
93 bool matchCvtF32UByteN(MachineInstr &MI,
94 CvtF32UByteMatchInfo &MatchInfo) const;
95 void applyCvtF32UByteN(MachineInstr &MI,
96 const CvtF32UByteMatchInfo &MatchInfo) const;
97
98 bool matchRemoveFcanonicalize(MachineInstr &MI) const;
99
100 // Combine unsigned buffer load and signed extension instructions to generate
101 // signed buffer load instructions.
102 bool matchCombineSignExtendInReg(
103 MachineInstr &MI, std::pair<MachineInstr *, unsigned> &MatchInfo) const;
104 void applyCombineSignExtendInReg(
105 MachineInstr &MI, std::pair<MachineInstr *, unsigned> &MatchInfo) const;
106
107 // Find the s_mul_u64 instructions where the higher bits are either
108 // zero-extended or sign-extended.
109 // Replace the s_mul_u64 instructions with S_MUL_I64_I32_PSEUDO if the higher
110 // 33 bits are sign extended and with S_MUL_U64_U32_PSEUDO if the higher 32
111 // bits are zero extended.
112 bool matchCombine_s_mul_u64(MachineInstr &MI, unsigned &NewOpcode) const;
113
114private:
115#define GET_GICOMBINER_CLASS_MEMBERS
116#define AMDGPUSubtarget GCNSubtarget
117#include "AMDGPUGenPostLegalizeGICombiner.inc"
118#undef GET_GICOMBINER_CLASS_MEMBERS
119#undef AMDGPUSubtarget
120};
121
122#define GET_GICOMBINER_IMPL
123#define AMDGPUSubtarget GCNSubtarget
124#include "AMDGPUGenPostLegalizeGICombiner.inc"
125#undef AMDGPUSubtarget
126#undef GET_GICOMBINER_IMPL
127
128AMDGPUPostLegalizerCombinerImpl::AMDGPUPostLegalizerCombinerImpl(
129 MachineFunction &MF, CombinerInfo &CInfo, GISelValueTracking &VT,
130 GISelCSEInfo *CSEInfo,
131 const AMDGPUPostLegalizerCombinerImplRuleConfig &RuleConfig,
132 const GCNSubtarget &STI, MachineDominatorTree *MDT, const LegalizerInfo *LI)
133 : Combiner(MF, CInfo, &VT, CSEInfo), RuleConfig(RuleConfig), STI(STI),
134 TII(*STI.getInstrInfo()),
135 Helper(Observer, B, /*IsPreLegalize*/ false, &VT, MDT, LI, STI),
136#define GET_GICOMBINER_CONSTRUCTOR_INITS
137#include "AMDGPUGenPostLegalizeGICombiner.inc"
138#undef GET_GICOMBINER_CONSTRUCTOR_INITS
139{
140}
141
142bool AMDGPUPostLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
143 if (tryCombineAllImpl(I&: MI))
144 return true;
145
146 switch (MI.getOpcode()) {
147 case TargetOpcode::G_SHL:
148 case TargetOpcode::G_LSHR:
149 case TargetOpcode::G_ASHR:
150 // On some subtargets, 64-bit shift is a quarter rate instruction. In the
151 // common case, splitting this into a move and a 32-bit shift is faster and
152 // the same code size.
153 return Helper.tryCombineShiftToUnmerge(MI, TargetShiftAmount: 32);
154 }
155
156 return false;
157}
158
159bool AMDGPUPostLegalizerCombinerImpl::matchFMinFMaxLegacy(
160 MachineInstr &MI, MachineInstr &FCmp, FMinFMaxLegacyInfo &Info) const {
161 if (!MRI.hasOneNonDBGUse(RegNo: FCmp.getOperand(i: 0).getReg()))
162 return false;
163
164 Info.Pred =
165 static_cast<CmpInst::Predicate>(FCmp.getOperand(i: 1).getPredicate());
166 Info.LHS = FCmp.getOperand(i: 2).getReg();
167 Info.RHS = FCmp.getOperand(i: 3).getReg();
168 Register True = MI.getOperand(i: 2).getReg();
169 Register False = MI.getOperand(i: 3).getReg();
170
171 // TODO: Handle case where the the selected value is an fneg and the compared
172 // constant is the negation of the selected value.
173 if ((Info.LHS != True || Info.RHS != False) &&
174 (Info.LHS != False || Info.RHS != True))
175 return false;
176
177 // Invert the predicate if necessary so that the apply function can assume
178 // that the select operands are the same as the fcmp operands.
179 // (select (fcmp P, L, R), R, L) -> (select (fcmp !P, L, R), L, R)
180 if (Info.LHS != True)
181 Info.Pred = CmpInst::getInversePredicate(pred: Info.Pred);
182
183 // Only match </<=/>=/> not ==/!= etc.
184 if (Info.Pred == CmpInst::getSwappedPredicate(pred: Info.Pred))
185 return false;
186
187 // These predicates pick the signed zero tie-incorrect operand order.
188 if (Info.Pred == CmpInst::FCMP_OLE || Info.Pred == CmpInst::FCMP_ULT ||
189 Info.Pred == CmpInst::FCMP_OGT || Info.Pred == CmpInst::FCMP_UGE)
190 return Helper.canIgnoreLegacyMinMaxTies(MI, LHS: Info.LHS, RHS: Info.RHS);
191
192 return true;
193}
194
195void AMDGPUPostLegalizerCombinerImpl::applySelectFCmpToFMinFMaxLegacy(
196 MachineInstr &MI, const FMinFMaxLegacyInfo &Info) const {
197 unsigned Opc = (Info.Pred & CmpInst::FCMP_OGT) ? AMDGPU::G_AMDGPU_FMAX_LEGACY
198 : AMDGPU::G_AMDGPU_FMIN_LEGACY;
199 Register X = Info.LHS;
200 Register Y = Info.RHS;
201 if (Info.Pred == CmpInst::getUnorderedPredicate(Pred: Info.Pred)) {
202 // We need to permute the operands to get the correct NaN behavior. The
203 // selected operand is the second one based on the failing compare with NaN,
204 // so permute it based on the compare type the hardware uses.
205 std::swap(a&: X, b&: Y);
206 }
207
208 B.buildInstr(Opc, DstOps: {MI.getOperand(i: 0)}, SrcOps: {X, Y}, Flags: MI.getFlags());
209
210 MI.eraseFromParent();
211}
212
213bool AMDGPUPostLegalizerCombinerImpl::matchUCharToFloat(
214 MachineInstr &MI) const {
215 Register DstReg = MI.getOperand(i: 0).getReg();
216
217 // TODO: We could try to match extracting the higher bytes, which would be
218 // easier if i8 vectors weren't promoted to i32 vectors, particularly after
219 // types are legalized. v4i8 -> v4f32 is probably the only case to worry
220 // about in practice.
221 LLT Ty = MRI.getType(Reg: DstReg);
222 if (Ty == LLT::scalar(SizeInBits: 32) || Ty == LLT::scalar(SizeInBits: 16)) {
223 Register SrcReg = MI.getOperand(i: 1).getReg();
224 unsigned SrcSize = MRI.getType(Reg: SrcReg).getSizeInBits();
225 assert(SrcSize == 16 || SrcSize == 32 || SrcSize == 64);
226 const APInt Mask = APInt::getHighBitsSet(numBits: SrcSize, hiBitsSet: SrcSize - 8);
227 return Helper.getValueTracking()->maskedValueIsZero(Val: SrcReg, Mask);
228 }
229
230 return false;
231}
232
233void AMDGPUPostLegalizerCombinerImpl::applyUCharToFloat(
234 MachineInstr &MI) const {
235 const LLT S32 = LLT::scalar(SizeInBits: 32);
236
237 Register DstReg = MI.getOperand(i: 0).getReg();
238 Register SrcReg = MI.getOperand(i: 1).getReg();
239 LLT Ty = MRI.getType(Reg: DstReg);
240 LLT SrcTy = MRI.getType(Reg: SrcReg);
241 if (SrcTy != S32)
242 SrcReg = B.buildAnyExtOrTrunc(Res: S32, Op: SrcReg).getReg(Idx: 0);
243
244 if (Ty == S32) {
245 B.buildInstr(Opc: AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, DstOps: {DstReg}, SrcOps: {SrcReg},
246 Flags: MI.getFlags());
247 } else {
248 auto Cvt0 = B.buildInstr(Opc: AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, DstOps: {S32}, SrcOps: {SrcReg},
249 Flags: MI.getFlags());
250 B.buildFPTrunc(Res: DstReg, Op: Cvt0, Flags: MI.getFlags());
251 }
252
253 MI.eraseFromParent();
254}
255
256bool AMDGPUPostLegalizerCombinerImpl::matchFDivSqrtToRsqF16(
257 MachineInstr &MI) const {
258 Register Sqrt = MI.getOperand(i: 2).getReg();
259 return MRI.hasOneNonDBGUse(RegNo: Sqrt);
260}
261
262void AMDGPUPostLegalizerCombinerImpl::applyFDivSqrtToRsqF16(
263 MachineInstr &MI, const Register &X) const {
264 Register Dst = MI.getOperand(i: 0).getReg();
265 Register Y = MI.getOperand(i: 1).getReg();
266 LLT DstTy = MRI.getType(Reg: Dst);
267 uint32_t Flags = MI.getFlags();
268 Register RSQ = B.buildIntrinsic(ID: Intrinsic::amdgcn_rsq, Res: {DstTy})
269 .addUse(RegNo: X)
270 .setMIFlags(Flags)
271 .getReg(Idx: 0);
272 B.buildFMul(Dst, Src0: RSQ, Src1: Y, Flags);
273 MI.eraseFromParent();
274}
275
276bool AMDGPUPostLegalizerCombinerImpl::matchCvtF32UByteN(
277 MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) const {
278 Register SrcReg = MI.getOperand(i: 1).getReg();
279
280 // Look through G_ZEXT.
281 bool IsShr = mi_match(R: SrcReg, MRI, P: m_GZExt(Src: m_Reg(R&: SrcReg)));
282
283 Register Src0;
284 int64_t ShiftAmt;
285 IsShr = mi_match(R: SrcReg, MRI, P: m_GLShr(L: m_Reg(R&: Src0), R: m_ICst(Cst&: ShiftAmt)));
286 if (IsShr || mi_match(R: SrcReg, MRI, P: m_GShl(L: m_Reg(R&: Src0), R: m_ICst(Cst&: ShiftAmt)))) {
287 const unsigned Offset = MI.getOpcode() - AMDGPU::G_AMDGPU_CVT_F32_UBYTE0;
288
289 unsigned ShiftOffset = 8 * Offset;
290 if (IsShr)
291 ShiftOffset += ShiftAmt;
292 else
293 ShiftOffset -= ShiftAmt;
294
295 MatchInfo.CvtVal = Src0;
296 MatchInfo.ShiftOffset = ShiftOffset;
297 return ShiftOffset < 32 && ShiftOffset >= 8 && (ShiftOffset % 8) == 0;
298 }
299
300 // TODO: Simplify demanded bits.
301 return false;
302}
303
304void AMDGPUPostLegalizerCombinerImpl::applyCvtF32UByteN(
305 MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) const {
306 unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8;
307
308 const LLT S32 = LLT::scalar(SizeInBits: 32);
309 Register CvtSrc = MatchInfo.CvtVal;
310 LLT SrcTy = MRI.getType(Reg: MatchInfo.CvtVal);
311 if (SrcTy != S32) {
312 assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8);
313 CvtSrc = B.buildAnyExt(Res: S32, Op: CvtSrc).getReg(Idx: 0);
314 }
315
316 assert(MI.getOpcode() != NewOpc);
317 B.buildInstr(Opc: NewOpc, DstOps: {MI.getOperand(i: 0)}, SrcOps: {CvtSrc}, Flags: MI.getFlags());
318 MI.eraseFromParent();
319}
320
321bool AMDGPUPostLegalizerCombinerImpl::matchRemoveFcanonicalize(
322 MachineInstr &MI) const {
323 const SITargetLowering *TLI = static_cast<const SITargetLowering *>(
324 MF.getSubtarget().getTargetLowering());
325 return TLI->isCanonicalized(Reg: MI.getOperand(i: 1).getReg(), MF);
326}
327
328// The buffer_load_{i8, i16} intrinsics are initially lowered as
329// buffer_load_{u8, u16} instructions. Here, the buffer_load_{u8, u16}
330// instructions are combined with sign extension instrucions in order to
331// generate buffer_load_{i8, i16} instructions.
332
333// Identify buffer_load_{u8, u16}.
334bool AMDGPUPostLegalizerCombinerImpl::matchCombineSignExtendInReg(
335 MachineInstr &MI, std::pair<MachineInstr *, unsigned> &MatchData) const {
336 Register LoadReg = MI.getOperand(i: 1).getReg();
337 if (!MRI.hasOneNonDBGUse(RegNo: LoadReg))
338 return false;
339
340 // Check if the first operand of the sign extension is a subword buffer load
341 // instruction.
342 MachineInstr *LoadMI = MRI.getVRegDef(Reg: LoadReg);
343 int64_t Width = MI.getOperand(i: 2).getImm();
344 switch (LoadMI->getOpcode()) {
345 case AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE:
346 MatchData = {LoadMI, AMDGPU::G_AMDGPU_BUFFER_LOAD_SBYTE};
347 return Width == 8;
348 case AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT:
349 MatchData = {LoadMI, AMDGPU::G_AMDGPU_BUFFER_LOAD_SSHORT};
350 return Width == 16;
351 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_UBYTE:
352 MatchData = {LoadMI, AMDGPU::G_AMDGPU_S_BUFFER_LOAD_SBYTE};
353 return Width == 8;
354 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_USHORT:
355 MatchData = {LoadMI, AMDGPU::G_AMDGPU_S_BUFFER_LOAD_SSHORT};
356 return Width == 16;
357 }
358 return false;
359}
360
361// Combine buffer_load_{u8, u16} and the sign extension instruction to generate
362// buffer_load_{i8, i16}.
363void AMDGPUPostLegalizerCombinerImpl::applyCombineSignExtendInReg(
364 MachineInstr &MI, std::pair<MachineInstr *, unsigned> &MatchData) const {
365 auto [LoadMI, NewOpcode] = MatchData;
366 LoadMI->setDesc(TII.get(Opcode: NewOpcode));
367 // Update the destination register of the load with the destination register
368 // of the sign extension.
369 Register SignExtendInsnDst = MI.getOperand(i: 0).getReg();
370 LoadMI->getOperand(i: 0).setReg(SignExtendInsnDst);
371 // Remove the sign extension.
372 MI.eraseFromParent();
373}
374
375bool AMDGPUPostLegalizerCombinerImpl::matchCombine_s_mul_u64(
376 MachineInstr &MI, unsigned &NewOpcode) const {
377 Register Src0 = MI.getOperand(i: 1).getReg();
378 Register Src1 = MI.getOperand(i: 2).getReg();
379 if (MRI.getType(Reg: Src0) != LLT::scalar(SizeInBits: 64))
380 return false;
381
382 if (VT->getKnownBits(R: Src1).countMinLeadingZeros() >= 32 &&
383 VT->getKnownBits(R: Src0).countMinLeadingZeros() >= 32) {
384 NewOpcode = AMDGPU::G_AMDGPU_S_MUL_U64_U32;
385 return true;
386 }
387
388 if (VT->computeNumSignBits(R: Src1) >= 33 &&
389 VT->computeNumSignBits(R: Src0) >= 33) {
390 NewOpcode = AMDGPU::G_AMDGPU_S_MUL_I64_I32;
391 return true;
392 }
393 return false;
394}
395
396// Pass boilerplate
397// ================
398
399static bool
400runCombiner(MachineFunction &MF, GISelValueTracking *VT, GISelCSEInfo *CSEInfo,
401 MachineDominatorTree *MDT,
402 const AMDGPUPostLegalizerCombinerImplRuleConfig &RuleConfig,
403 bool EnableOpt) {
404 const Function &F = MF.getFunction();
405 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
406 const LegalizerInfo *LI = ST.getLegalizerInfo();
407
408 CombinerInfo CInfo(/*AllowIllegalOps=*/false,
409 /*ShouldLegalizeIllegal=*/true, LI, EnableOpt,
410 F.hasOptSize(), F.hasMinSize());
411 // Disable fixed-point iteration to reduce compile-time
412 CInfo.MaxIterations = 1;
413 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
414 // Legalizer performs DCE, so a full DCE pass is unnecessary.
415 CInfo.EnableFullDCE = false;
416 AMDGPUPostLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST,
417 MDT, LI);
418 return Impl.combineMachineInstrs();
419}
420
421class AMDGPUPostLegalizerCombinerLegacy : public MachineFunctionPass {
422public:
423 static char ID;
424
425 AMDGPUPostLegalizerCombinerLegacy(bool IsOptNone = false);
426
427 StringRef getPassName() const override {
428 return "AMDGPUPostLegalizerCombiner";
429 }
430
431 bool runOnMachineFunction(MachineFunction &MF) override;
432
433 void getAnalysisUsage(AnalysisUsage &AU) const override;
434
435private:
436 bool IsOptNone;
437 AMDGPUPostLegalizerCombinerImplRuleConfig RuleConfig;
438};
439} // end anonymous namespace
440
441void AMDGPUPostLegalizerCombinerLegacy::getAnalysisUsage(
442 AnalysisUsage &AU) const {
443 AU.setPreservesCFG();
444 getSelectionDAGFallbackAnalysisUsage(AU);
445 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
446 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
447 AU.addRequired<GISelCSEAnalysisWrapperPass>();
448 AU.addPreserved<GISelCSEAnalysisWrapperPass>();
449 if (!IsOptNone) {
450 AU.addRequired<MachineDominatorTreeWrapperPass>();
451 }
452 MachineFunctionPass::getAnalysisUsage(AU);
453}
454
455AMDGPUPostLegalizerCombinerLegacy::AMDGPUPostLegalizerCombinerLegacy(
456 bool IsOptNone)
457 : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
458 if (!RuleConfig.parseCommandLineOption())
459 report_fatal_error(reason: "Invalid rule identifier");
460}
461
462bool AMDGPUPostLegalizerCombinerLegacy::runOnMachineFunction(
463 MachineFunction &MF) {
464 if (MF.getProperties().hasFailedISel())
465 return false;
466 const Function &F = MF.getFunction();
467 bool EnableOpt =
468 MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);
469
470 GISelValueTracking *VT =
471 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
472 GISelCSEAnalysisWrapper &Wrapper =
473 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
474 GISelCSEInfo *CSEInfo =
475 &Wrapper.get(CSEOpt: getStandardCSEConfigForOpt(Level: MF.getTarget().getOptLevel()));
476 MachineDominatorTree *MDT =
477 IsOptNone ? nullptr
478 : &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
479
480 return runCombiner(MF, VT, CSEInfo, MDT, RuleConfig, EnableOpt);
481}
482
483char AMDGPUPostLegalizerCombinerLegacy::ID = 0;
484INITIALIZE_PASS_BEGIN(AMDGPUPostLegalizerCombinerLegacy, DEBUG_TYPE,
485 "Combine AMDGPU machine instrs after legalization", false,
486 false)
487INITIALIZE_PASS_DEPENDENCY(GISelValueTrackingAnalysisLegacy)
488INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
489INITIALIZE_PASS_END(AMDGPUPostLegalizerCombinerLegacy, DEBUG_TYPE,
490 "Combine AMDGPU machine instrs after legalization", false,
491 false)
492
493FunctionPass *llvm::createAMDGPUPostLegalizeCombinerLegacy(bool IsOptNone) {
494 return new AMDGPUPostLegalizerCombinerLegacy(IsOptNone);
495}
496
497PreservedAnalyses
498AMDGPUPostLegalizerCombinerPass::run(MachineFunction &MF,
499 MachineFunctionAnalysisManager &MFAM) {
500 if (MF.getProperties().hasFailedISel())
501 return PreservedAnalyses::all();
502
503 AMDGPUPostLegalizerCombinerImplRuleConfig RuleConfig;
504 if (!RuleConfig.parseCommandLineOption())
505 report_fatal_error(reason: "Invalid rule identifier");
506
507 bool IsOptNone = MF.getTarget().getOptLevel() == CodeGenOptLevel::None;
508
509 GISelValueTracking &VT = MFAM.getResult<GISelValueTrackingAnalysis>(IR&: MF);
510 GISelCSEInfo *CSEInfo = MFAM.getResult<GISelCSEAnalysis>(IR&: MF).get();
511 MachineDominatorTree *MDT =
512 IsOptNone ? nullptr : &MFAM.getResult<MachineDominatorTreeAnalysis>(IR&: MF);
513
514 if (!runCombiner(MF, VT: &VT, CSEInfo, MDT, RuleConfig,
515 /*EnableOpt=*/!IsOptNone))
516 return PreservedAnalyses::all();
517
518 PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
519 PA.preserveSet<CFGAnalyses>();
520 PA.preserve<GISelValueTrackingAnalysis>();
521 PA.preserve<GISelCSEAnalysis>();
522 return PA;
523}
524