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
114 /// Check if register is carry-out (operand 1) of a carry-producing add/sub
115 bool isCarryOut(Register Reg) const;
116
117 bool shouldFoldCarryIntoAdd(Register Src) const;
118
119private:
120#define GET_GICOMBINER_CLASS_MEMBERS
121#define AMDGPUSubtarget GCNSubtarget
122#include "AMDGPUGenPostLegalizeGICombiner.inc"
123#undef GET_GICOMBINER_CLASS_MEMBERS
124#undef AMDGPUSubtarget
125};
126
127#define GET_GICOMBINER_IMPL
128#define AMDGPUSubtarget GCNSubtarget
129#include "AMDGPUGenPostLegalizeGICombiner.inc"
130#undef AMDGPUSubtarget
131#undef GET_GICOMBINER_IMPL
132
133AMDGPUPostLegalizerCombinerImpl::AMDGPUPostLegalizerCombinerImpl(
134 MachineFunction &MF, CombinerInfo &CInfo, GISelValueTracking &VT,
135 GISelCSEInfo *CSEInfo,
136 const AMDGPUPostLegalizerCombinerImplRuleConfig &RuleConfig,
137 const GCNSubtarget &STI, MachineDominatorTree *MDT, const LegalizerInfo *LI)
138 : Combiner(MF, CInfo, &VT, CSEInfo), RuleConfig(RuleConfig), STI(STI),
139 TII(*STI.getInstrInfo()),
140 Helper(Observer, B, /*IsPreLegalize*/ false, &VT, MDT, LI, STI),
141#define GET_GICOMBINER_CONSTRUCTOR_INITS
142#include "AMDGPUGenPostLegalizeGICombiner.inc"
143#undef GET_GICOMBINER_CONSTRUCTOR_INITS
144{
145}
146
147bool AMDGPUPostLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const {
148 if (tryCombineAllImpl(I&: MI))
149 return true;
150
151 switch (MI.getOpcode()) {
152 case TargetOpcode::G_SHL:
153 case TargetOpcode::G_LSHR:
154 case TargetOpcode::G_ASHR:
155 // On some subtargets, 64-bit shift is a quarter rate instruction. In the
156 // common case, splitting this into a move and a 32-bit shift is faster and
157 // the same code size.
158 return Helper.tryCombineShiftToUnmerge(MI, TargetShiftAmount: 32);
159 }
160
161 return false;
162}
163
164bool AMDGPUPostLegalizerCombinerImpl::matchFMinFMaxLegacy(
165 MachineInstr &MI, MachineInstr &FCmp, FMinFMaxLegacyInfo &Info) const {
166 if (!MRI.hasOneNonDBGUse(RegNo: FCmp.getOperand(i: 0).getReg()))
167 return false;
168
169 Info.Pred =
170 static_cast<CmpInst::Predicate>(FCmp.getOperand(i: 1).getPredicate());
171 Info.LHS = FCmp.getOperand(i: 2).getReg();
172 Info.RHS = FCmp.getOperand(i: 3).getReg();
173 Register True = MI.getOperand(i: 2).getReg();
174 Register False = MI.getOperand(i: 3).getReg();
175
176 // TODO: Handle case where the the selected value is an fneg and the compared
177 // constant is the negation of the selected value.
178 if ((Info.LHS != True || Info.RHS != False) &&
179 (Info.LHS != False || Info.RHS != True))
180 return false;
181
182 // Invert the predicate if necessary so that the apply function can assume
183 // that the select operands are the same as the fcmp operands.
184 // (select (fcmp P, L, R), R, L) -> (select (fcmp !P, L, R), L, R)
185 if (Info.LHS != True)
186 Info.Pred = CmpInst::getInversePredicate(pred: Info.Pred);
187
188 // Only match </<=/>=/> not ==/!= etc.
189 if (Info.Pred == CmpInst::getSwappedPredicate(pred: Info.Pred))
190 return false;
191
192 // These predicates pick the signed zero tie-incorrect operand order.
193 if (Info.Pred == CmpInst::FCMP_OLE || Info.Pred == CmpInst::FCMP_ULT ||
194 Info.Pred == CmpInst::FCMP_OGT || Info.Pred == CmpInst::FCMP_UGE)
195 return Helper.canIgnoreLegacyMinMaxTies(MI, LHS: Info.LHS, RHS: Info.RHS);
196
197 return true;
198}
199
200void AMDGPUPostLegalizerCombinerImpl::applySelectFCmpToFMinFMaxLegacy(
201 MachineInstr &MI, const FMinFMaxLegacyInfo &Info) const {
202 unsigned Opc = (Info.Pred & CmpInst::FCMP_OGT) ? AMDGPU::G_AMDGPU_FMAX_LEGACY
203 : AMDGPU::G_AMDGPU_FMIN_LEGACY;
204 Register X = Info.LHS;
205 Register Y = Info.RHS;
206 if (Info.Pred == CmpInst::getUnorderedPredicate(Pred: Info.Pred)) {
207 // We need to permute the operands to get the correct NaN behavior. The
208 // selected operand is the second one based on the failing compare with NaN,
209 // so permute it based on the compare type the hardware uses.
210 std::swap(a&: X, b&: Y);
211 }
212
213 B.buildInstr(Opc, DstOps: {MI.getOperand(i: 0)}, SrcOps: {X, Y}, Flags: MI.getFlags());
214
215 MI.eraseFromParent();
216}
217
218bool AMDGPUPostLegalizerCombinerImpl::matchUCharToFloat(
219 MachineInstr &MI) const {
220 Register DstReg = MI.getOperand(i: 0).getReg();
221
222 // TODO: We could try to match extracting the higher bytes, which would be
223 // easier if i8 vectors weren't promoted to i32 vectors, particularly after
224 // types are legalized. v4i8 -> v4f32 is probably the only case to worry
225 // about in practice.
226 LLT Ty = MRI.getType(Reg: DstReg);
227 if (Ty == LLT::scalar(SizeInBits: 32) || Ty == LLT::scalar(SizeInBits: 16)) {
228 Register SrcReg = MI.getOperand(i: 1).getReg();
229 unsigned SrcSize = MRI.getType(Reg: SrcReg).getSizeInBits();
230 assert(SrcSize == 16 || SrcSize == 32 || SrcSize == 64);
231 const APInt Mask = APInt::getHighBitsSet(numBits: SrcSize, hiBitsSet: SrcSize - 8);
232 return Helper.getValueTracking()->maskedValueIsZero(Val: SrcReg, Mask);
233 }
234
235 return false;
236}
237
238void AMDGPUPostLegalizerCombinerImpl::applyUCharToFloat(
239 MachineInstr &MI) const {
240 const LLT S32 = LLT::scalar(SizeInBits: 32);
241
242 Register DstReg = MI.getOperand(i: 0).getReg();
243 Register SrcReg = MI.getOperand(i: 1).getReg();
244 LLT Ty = MRI.getType(Reg: DstReg);
245 LLT SrcTy = MRI.getType(Reg: SrcReg);
246 if (SrcTy != S32)
247 SrcReg = B.buildAnyExtOrTrunc(Res: S32, Op: SrcReg).getReg(Idx: 0);
248
249 if (Ty == S32) {
250 B.buildInstr(Opc: AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, DstOps: {DstReg}, SrcOps: {SrcReg},
251 Flags: MI.getFlags());
252 } else {
253 auto Cvt0 = B.buildInstr(Opc: AMDGPU::G_AMDGPU_CVT_F32_UBYTE0, DstOps: {S32}, SrcOps: {SrcReg},
254 Flags: MI.getFlags());
255 B.buildFPTrunc(Res: DstReg, Op: Cvt0, Flags: MI.getFlags());
256 }
257
258 MI.eraseFromParent();
259}
260
261bool AMDGPUPostLegalizerCombinerImpl::matchFDivSqrtToRsqF16(
262 MachineInstr &MI) const {
263 Register Sqrt = MI.getOperand(i: 2).getReg();
264 return MRI.hasOneNonDBGUse(RegNo: Sqrt);
265}
266
267void AMDGPUPostLegalizerCombinerImpl::applyFDivSqrtToRsqF16(
268 MachineInstr &MI, const Register &X) const {
269 Register Dst = MI.getOperand(i: 0).getReg();
270 Register Y = MI.getOperand(i: 1).getReg();
271 LLT DstTy = MRI.getType(Reg: Dst);
272 uint32_t Flags = MI.getFlags();
273 Register RSQ = B.buildIntrinsic(ID: Intrinsic::amdgcn_rsq, Res: {DstTy})
274 .addUse(RegNo: X)
275 .setMIFlags(Flags)
276 .getReg(Idx: 0);
277 B.buildFMul(Dst, Src0: RSQ, Src1: Y, Flags);
278 MI.eraseFromParent();
279}
280
281bool AMDGPUPostLegalizerCombinerImpl::matchCvtF32UByteN(
282 MachineInstr &MI, CvtF32UByteMatchInfo &MatchInfo) const {
283 Register SrcReg = MI.getOperand(i: 1).getReg();
284
285 // Look through G_ZEXT.
286 bool IsShr = mi_match(R: SrcReg, MRI, P: m_GZExt(Src: m_Reg(R&: SrcReg)));
287
288 Register Src0;
289 int64_t ShiftAmt;
290 IsShr = mi_match(R: SrcReg, MRI, P: m_GLShr(L: m_Reg(R&: Src0), R: m_ICst(Cst&: ShiftAmt)));
291 if (IsShr || mi_match(R: SrcReg, MRI, P: m_GShl(L: m_Reg(R&: Src0), R: m_ICst(Cst&: ShiftAmt)))) {
292 const unsigned Offset = MI.getOpcode() - AMDGPU::G_AMDGPU_CVT_F32_UBYTE0;
293
294 unsigned ShiftOffset = 8 * Offset;
295 if (IsShr)
296 ShiftOffset += ShiftAmt;
297 else
298 ShiftOffset -= ShiftAmt;
299
300 MatchInfo.CvtVal = Src0;
301 MatchInfo.ShiftOffset = ShiftOffset;
302 return ShiftOffset < 32 && ShiftOffset >= 8 && (ShiftOffset % 8) == 0;
303 }
304
305 // TODO: Simplify demanded bits.
306 return false;
307}
308
309void AMDGPUPostLegalizerCombinerImpl::applyCvtF32UByteN(
310 MachineInstr &MI, const CvtF32UByteMatchInfo &MatchInfo) const {
311 unsigned NewOpc = AMDGPU::G_AMDGPU_CVT_F32_UBYTE0 + MatchInfo.ShiftOffset / 8;
312
313 const LLT S32 = LLT::scalar(SizeInBits: 32);
314 Register CvtSrc = MatchInfo.CvtVal;
315 LLT SrcTy = MRI.getType(Reg: MatchInfo.CvtVal);
316 if (SrcTy != S32) {
317 assert(SrcTy.isScalar() && SrcTy.getSizeInBits() >= 8);
318 CvtSrc = B.buildAnyExt(Res: S32, Op: CvtSrc).getReg(Idx: 0);
319 }
320
321 assert(MI.getOpcode() != NewOpc);
322 B.buildInstr(Opc: NewOpc, DstOps: {MI.getOperand(i: 0)}, SrcOps: {CvtSrc}, Flags: MI.getFlags());
323 MI.eraseFromParent();
324}
325
326bool AMDGPUPostLegalizerCombinerImpl::matchRemoveFcanonicalize(
327 MachineInstr &MI) const {
328 const SITargetLowering *TLI = static_cast<const SITargetLowering *>(
329 MF.getSubtarget().getTargetLowering());
330 return TLI->isCanonicalized(Reg: MI.getOperand(i: 1).getReg(), MF);
331}
332
333// The buffer_load_{i8, i16} intrinsics are initially lowered as
334// buffer_load_{u8, u16} instructions. Here, the buffer_load_{u8, u16}
335// instructions are combined with sign extension instrucions in order to
336// generate buffer_load_{i8, i16} instructions.
337
338// Identify buffer_load_{u8, u16}.
339bool AMDGPUPostLegalizerCombinerImpl::matchCombineSignExtendInReg(
340 MachineInstr &MI, std::pair<MachineInstr *, unsigned> &MatchData) const {
341 Register LoadReg = MI.getOperand(i: 1).getReg();
342 if (!MRI.hasOneNonDBGUse(RegNo: LoadReg))
343 return false;
344
345 // Check if the first operand of the sign extension is a subword buffer load
346 // instruction.
347 MachineInstr *LoadMI = MRI.getVRegDef(Reg: LoadReg);
348 int64_t Width = MI.getOperand(i: 2).getImm();
349 switch (LoadMI->getOpcode()) {
350 case AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE:
351 MatchData = {LoadMI, AMDGPU::G_AMDGPU_BUFFER_LOAD_SBYTE};
352 return Width == 8;
353 case AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT:
354 MatchData = {LoadMI, AMDGPU::G_AMDGPU_BUFFER_LOAD_SSHORT};
355 return Width == 16;
356 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_UBYTE:
357 MatchData = {LoadMI, AMDGPU::G_AMDGPU_S_BUFFER_LOAD_SBYTE};
358 return Width == 8;
359 case AMDGPU::G_AMDGPU_S_BUFFER_LOAD_USHORT:
360 MatchData = {LoadMI, AMDGPU::G_AMDGPU_S_BUFFER_LOAD_SSHORT};
361 return Width == 16;
362 }
363 return false;
364}
365
366// Combine buffer_load_{u8, u16} and the sign extension instruction to generate
367// buffer_load_{i8, i16}.
368void AMDGPUPostLegalizerCombinerImpl::applyCombineSignExtendInReg(
369 MachineInstr &MI, std::pair<MachineInstr *, unsigned> &MatchData) const {
370 auto [LoadMI, NewOpcode] = MatchData;
371 LoadMI->setDesc(TII.get(Opcode: NewOpcode));
372 // Update the destination register of the load with the destination register
373 // of the sign extension.
374 Register SignExtendInsnDst = MI.getOperand(i: 0).getReg();
375 LoadMI->getOperand(i: 0).setReg(SignExtendInsnDst);
376 // Remove the sign extension.
377 MI.eraseFromParent();
378}
379
380bool AMDGPUPostLegalizerCombinerImpl::matchCombine_s_mul_u64(
381 MachineInstr &MI, unsigned &NewOpcode) const {
382 Register Src0 = MI.getOperand(i: 1).getReg();
383 Register Src1 = MI.getOperand(i: 2).getReg();
384 if (MRI.getType(Reg: Src0) != LLT::scalar(SizeInBits: 64))
385 return false;
386
387 if (VT->getKnownBits(R: Src1).countMinLeadingZeros() >= 32 &&
388 VT->getKnownBits(R: Src0).countMinLeadingZeros() >= 32) {
389 NewOpcode = AMDGPU::G_AMDGPU_S_MUL_U64_U32;
390 return true;
391 }
392
393 if (VT->computeNumSignBits(R: Src1) >= 33 &&
394 VT->computeNumSignBits(R: Src0) >= 33) {
395 NewOpcode = AMDGPU::G_AMDGPU_S_MUL_I64_I32;
396 return true;
397 }
398 return false;
399}
400
401bool AMDGPUPostLegalizerCombinerImpl::isCarryOut(Register Reg) const {
402 const MachineInstr *Def = MRI.getVRegDef(Reg);
403 if (!Def)
404 return false;
405
406 switch (Def->getOpcode()) {
407 case TargetOpcode::G_UADDO:
408 case TargetOpcode::G_UADDE:
409 case TargetOpcode::G_USUBO:
410 case TargetOpcode::G_USUBE:
411 return Def->getOperand(i: 1).getReg() == Reg;
412 default:
413 return false;
414 }
415}
416
417bool AMDGPUPostLegalizerCombinerImpl::shouldFoldCarryIntoAdd(
418 Register Src) const {
419 // Let right_identity_zero combine delete this instead.
420 if (mi_match(R: Src, MRI, P: m_SpecificICst(RequestedValue: 0)))
421 return false;
422
423 // When both operands are a carry only the right hand one is folded, so that
424 // the two carries never have to be live at the same time.
425 Register Carry;
426 return !mi_match(R: Src, MRI, P: m_GZExt(Src: m_Reg(R&: Carry))) ||
427 !MRI.hasOneNonDBGUse(RegNo: Src) || !isCarryOut(Reg: Carry);
428}
429
430// Pass boilerplate
431// ================
432
433static bool
434runCombiner(MachineFunction &MF, GISelValueTracking *VT, GISelCSEInfo *CSEInfo,
435 MachineDominatorTree *MDT,
436 const AMDGPUPostLegalizerCombinerImplRuleConfig &RuleConfig,
437 bool EnableOpt) {
438 const Function &F = MF.getFunction();
439 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
440 const LegalizerInfo *LI = ST.getLegalizerInfo();
441
442 CombinerInfo CInfo(/*AllowIllegalOps=*/false,
443 /*ShouldLegalizeIllegal=*/true, LI, EnableOpt,
444 F.hasOptSize(), F.hasMinSize());
445 // Disable fixed-point iteration to reduce compile-time
446 CInfo.MaxIterations = 1;
447 CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass;
448 // Legalizer performs DCE, so a full DCE pass is unnecessary.
449 CInfo.EnableFullDCE = false;
450 AMDGPUPostLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST,
451 MDT, LI);
452 return Impl.combineMachineInstrs();
453}
454
455class AMDGPUPostLegalizerCombinerLegacy : public MachineFunctionPass {
456public:
457 static char ID;
458
459 AMDGPUPostLegalizerCombinerLegacy(bool IsOptNone = false);
460
461 StringRef getPassName() const override {
462 return "AMDGPUPostLegalizerCombiner";
463 }
464
465 bool runOnMachineFunction(MachineFunction &MF) override;
466
467 void getAnalysisUsage(AnalysisUsage &AU) const override;
468
469private:
470 bool IsOptNone;
471 AMDGPUPostLegalizerCombinerImplRuleConfig RuleConfig;
472};
473} // end anonymous namespace
474
475void AMDGPUPostLegalizerCombinerLegacy::getAnalysisUsage(
476 AnalysisUsage &AU) const {
477 AU.setPreservesCFG();
478 getSelectionDAGFallbackAnalysisUsage(AU);
479 AU.addRequired<GISelValueTrackingAnalysisLegacy>();
480 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
481 AU.addRequired<GISelCSEAnalysisWrapperPass>();
482 AU.addPreserved<GISelCSEAnalysisWrapperPass>();
483 if (!IsOptNone) {
484 AU.addRequired<MachineDominatorTreeWrapperPass>();
485 }
486 MachineFunctionPass::getAnalysisUsage(AU);
487}
488
489AMDGPUPostLegalizerCombinerLegacy::AMDGPUPostLegalizerCombinerLegacy(
490 bool IsOptNone)
491 : MachineFunctionPass(ID), IsOptNone(IsOptNone) {
492 if (!RuleConfig.parseCommandLineOption())
493 report_fatal_error(reason: "Invalid rule identifier");
494}
495
496bool AMDGPUPostLegalizerCombinerLegacy::runOnMachineFunction(
497 MachineFunction &MF) {
498 if (MF.getProperties().hasFailedISel())
499 return false;
500 const Function &F = MF.getFunction();
501 bool EnableOpt =
502 MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F);
503
504 GISelValueTracking *VT =
505 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
506 GISelCSEAnalysisWrapper &Wrapper =
507 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
508 GISelCSEInfo *CSEInfo =
509 &Wrapper.get(CSEOpt: getStandardCSEConfigForOpt(Level: MF.getTarget().getOptLevel()));
510 MachineDominatorTree *MDT =
511 IsOptNone ? nullptr
512 : &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
513
514 return runCombiner(MF, VT, CSEInfo, MDT, RuleConfig, EnableOpt);
515}
516
517char AMDGPUPostLegalizerCombinerLegacy::ID = 0;
518INITIALIZE_PASS_BEGIN(AMDGPUPostLegalizerCombinerLegacy, DEBUG_TYPE,
519 "Combine AMDGPU machine instrs after legalization", false,
520 false)
521INITIALIZE_PASS_DEPENDENCY(GISelValueTrackingAnalysisLegacy)
522INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
523INITIALIZE_PASS_END(AMDGPUPostLegalizerCombinerLegacy, DEBUG_TYPE,
524 "Combine AMDGPU machine instrs after legalization", false,
525 false)
526
527FunctionPass *llvm::createAMDGPUPostLegalizeCombinerLegacy(bool IsOptNone) {
528 return new AMDGPUPostLegalizerCombinerLegacy(IsOptNone);
529}
530
531PreservedAnalyses
532AMDGPUPostLegalizerCombinerPass::run(MachineFunction &MF,
533 MachineFunctionAnalysisManager &MFAM) {
534 if (MF.getProperties().hasFailedISel())
535 return PreservedAnalyses::all();
536
537 AMDGPUPostLegalizerCombinerImplRuleConfig RuleConfig;
538 if (!RuleConfig.parseCommandLineOption())
539 report_fatal_error(reason: "Invalid rule identifier");
540
541 bool IsOptNone = MF.getTarget().getOptLevel() == CodeGenOptLevel::None ||
542 shouldSkipOptimizationForOptBisect(IR: MF.getFunction());
543
544 GISelValueTracking &VT = MFAM.getResult<GISelValueTrackingAnalysis>(IR&: MF);
545 GISelCSEInfo *CSEInfo = MFAM.getResult<GISelCSEAnalysis>(IR&: MF).get();
546 MachineDominatorTree *MDT =
547 IsOptNone ? nullptr : &MFAM.getResult<MachineDominatorTreeAnalysis>(IR&: MF);
548
549 if (!runCombiner(MF, VT: &VT, CSEInfo, MDT, RuleConfig,
550 /*EnableOpt=*/!IsOptNone))
551 return PreservedAnalyses::all();
552
553 PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
554 PA.preserveSet<CFGAnalyses>();
555 PA.preserve<GISelValueTrackingAnalysis>();
556 PA.preserve<GISelCSEAnalysis>();
557 return PA;
558}
559