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