LLVM 24.0.0git
NVPTXCodeGenPassBuilder.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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/// \file
9/// This file contains the NVPTX CodeGen pipeline builder. It mirrors
10/// NVPTXPassConfig in NVPTXTargetMachine.cpp; the two must be kept in sync
11/// until the legacy pass manager path is removed.
12//===----------------------------------------------------------------------===//
13
14#include "NVPTX.h"
15#include "NVPTXAliasAnalysis.h"
16#include "NVPTXAsmPrinter.h"
17#include "NVPTXSubtarget.h"
18#include "NVPTXTargetMachine.h"
27#include "llvm/CodeGen/PEI.h"
41#include "llvm/MC/MCStreamer.h"
55
56using namespace llvm;
57
60
61// byval arguments in NVPTX are special. We're only allowed to read from them
62// using a special instruction, and if we ever need to write to them or take an
63// address, we must make a local copy and use it, instead.
64//
65// The problem is that local copies are very expensive, and we create them very
66// late in the compilation pipeline, so LLVM does not have much of a chance to
67// eliminate them, if they turn out to be unnecessary.
68//
69// One way around that is to create such copies early on, and let them percolate
70// through the optimizations. The copying itself will never trigger creation of
71// another copy later on, as the reads are allowed. If LLVM can eliminate it,
72// it's a win. It the full optimization pipeline can't remove the copy, that's
73// as good as it gets in terms of the effort we could've done, and it's
74// certainly a much better effort than what we do now.
75//
76// This early injection of the copies has potential to create undesireable
77// side-effects, so it's disabled by default, for now, until it sees more
78// testing.
80 "nvptx-early-byval-copy",
81 cl::desc("Create a copy of byval function arguments early."),
82 cl::init(false), cl::Hidden);
83
84namespace {
85
86class NVPTXCodeGenPassBuilder : public CodeGenPassBuilder {
88
89 NVPTXTargetMachine &getTM() const {
90 return static_cast<NVPTXTargetMachine &>(TM);
91 }
92
93public:
94 explicit NVPTXCodeGenPassBuilder(NVPTXTargetMachine &TM,
95 const CGPassBuilderOption &Opts,
96 PassInstrumentationCallbacks *PIC)
97 : CodeGenPassBuilder(TM, Opts, PIC) {
98 // The following passes are known to not play well with virtual regs
99 // hanging around after register allocation (which in our case, is *all*
100 // registers). We explicitly disable them here. We do, however, need some
101 // functionality of the PrologEpilogCodeInserter pass, so we emulate that
102 // behavior in the NVPTXPrologEpilog pass (see NVPTXPrologEpilogPass.cpp).
103 disablePass<PrologEpilogInserterPass, MachineLateInstrsCleanupPass,
104 MachineCopyPropagationPass, TailDuplicatePass,
105 StackMapLivenessPass, PostRAMachineSinkingPass,
106 PostRASchedulerPass, FuncletLayoutPass, PatchableFunctionPass,
107 ShrinkWrapPass, RemoveLoadsIntoFakeUsesPass,
108 MachineBlockPlacementPass>();
109 }
110
111 void addIRPasses(PassManagerWrapper &PMW) override;
112 Error addInstSelector(PassManagerWrapper &PMW) override;
113 void addPreRegAlloc(PassManagerWrapper &PMW) override;
114 void addPostRegAlloc(PassManagerWrapper &PMW) override;
115
116 // NVPTX has no register allocation; virtual registers are emitted directly.
117 void addTargetRegisterAllocator(PassManagerWrapper &PMW, bool) override {}
118 Error addFastRegAlloc(PassManagerWrapper &PMW) override;
119 Error addOptimizedRegAlloc(PassManagerWrapper &PMW) override;
120
121 void addAsmPrinterBegin(PassManagerWrapper &PMW) override;
122 void addAsmPrinter(PassManagerWrapper &PMW) override;
123 void addAsmPrinterEnd(PassManagerWrapper &PMW) override;
124
125private:
126 // If the opt level is aggressive, add GVN; otherwise, add EarlyCSE.
127 void addEarlyCSEOrGVNPass(PassManagerWrapper &PMW);
128
129 // Add passes that propagate special memory spaces.
130 void addAddressSpaceInferencePasses(PassManagerWrapper &PMW);
131
132 // Add passes that perform straight-line scalar optimizations.
133 void addStraightLineScalarOptimizationPasses(PassManagerWrapper &PMW);
134};
135
136void NVPTXCodeGenPassBuilder::addEarlyCSEOrGVNPass(PassManagerWrapper &PMW) {
137 if (getOptLevel() == CodeGenOptLevel::Aggressive)
138 // Disable scalar PRE due to Register Pressure increase
139 addFunctionPass(GVNPass(GVNOptions().setScalarPRE(false)), PMW);
140 else
141 addFunctionPass(EarlyCSEPass(), PMW);
142}
143
144void NVPTXCodeGenPassBuilder::addAddressSpaceInferencePasses(
145 PassManagerWrapper &PMW) {
146 // NVPTXLowerArgs emits alloca for byval parameters which can often
147 // be eliminated by SROA.
148 addFunctionPass(SROAPass(SROAOptions(SROAOptions::PreserveCFG,
149 /*AggregateToVector=*/true)),
150 PMW);
151 addFunctionPass(NVPTXLowerAllocaPass(), PMW);
152 // TODO: Consider running InferAddressSpaces during opt, earlier in the
153 // compilation flow.
154 addFunctionPass(InferAddressSpacesPass(), PMW);
155 addFunctionPass(NVPTXAtomicLowerPass(), PMW);
156}
157
158void NVPTXCodeGenPassBuilder::addStraightLineScalarOptimizationPasses(
159 PassManagerWrapper &PMW) {
160 addFunctionPass(SeparateConstOffsetFromGEPPass(), PMW);
161 addFunctionPass(SpeculativeExecutionPass(), PMW);
162 // ReassociateGEPs exposes more opportunites for SLSR. See
163 // the example in reassociate-geps-and-slsr.ll.
164 addFunctionPass(StraightLineStrengthReducePass(), PMW);
165 // SeparateConstOffsetFromGEP and SLSR creates common expressions which GVN
166 // or EarlyCSE can reuse. GVN generates significantly better code than
167 // EarlyCSE for some of our benchmarks.
168 addEarlyCSEOrGVNPass(PMW);
169 // Run NaryReassociate after EarlyCSE/GVN to be more effective.
170 addFunctionPass(NaryReassociatePass(), PMW);
171 // NaryReassociate on GEPs creates redundant common expressions, so run
172 // EarlyCSE after it.
173 addFunctionPass(EarlyCSEPass(), PMW);
174}
175
176void NVPTXCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) {
177 const NVPTXSubtarget &ST = *getTM().getSubtargetImpl();
178
179 // NVVMReflectPass is added in the pipeline-start extension point, so
180 // hopefully running it here does nothing. But since we need it for
181 // correctness when lowering to NVPTX, run it here too, in case whoever built
182 // our pass pipeline didn't add it.
183 flushFPMsToMPM(PMW);
184 addModulePass(NVVMReflectPass(ST.getSmVersion()), PMW);
185
186 if (getOptLevel() != CodeGenOptLevel::None)
187 addFunctionPass(NVPTXImageOptimizerPass(), PMW);
188 flushFPMsToMPM(PMW);
189 addModulePass(NVPTXAssignValidGlobalNamesPass(), PMW);
190 addModulePass(GenericToNVVMPass(), PMW);
191
192 // Lower variadic calls before address space inference.
193 addModulePass(ExpandVariadicsPass(ExpandVariadicsMode::Lowering), PMW);
194
195 // NVPTXLowerArgs is required for correctness and should be run right
196 // before the address space inference passes.
197 if (getTM().getDrvInterface() == NVPTX::CUDA) {
198 addFunctionPass(NVPTXMarkKernelPtrsGlobalPass(), PMW);
199 flushFPMsToMPM(PMW);
200 }
201 addModulePass(NVPTXPromoteParamAlignPass(), PMW);
202 addModulePass(NVPTXLowerArgsPass(TM), PMW);
203 if (getOptLevel() != CodeGenOptLevel::None) {
204 addAddressSpaceInferencePasses(PMW);
205 addStraightLineScalarOptimizationPasses(PMW);
206 } else {
207 // Required for correct stack lowering
208 addFunctionPass(NVPTXLowerAllocaPass(), PMW);
209 }
210
211 addFunctionPass(AtomicExpandPass(TM), PMW);
212 flushFPMsToMPM(PMW);
213 addModulePass(NVPTXCtorDtorLoweringPass(), PMW);
214
215 // === LSR and other generic IR passes ===
216 Base::addIRPasses(PMW);
217 // EarlyCSE is not always strong enough to clean up what LSR produces. For
218 // example, GVN can combine
219 //
220 // %0 = add %a, %b
221 // %1 = add %b, %a
222 //
223 // and
224 //
225 // %0 = shl nsw %a, 2
226 // %1 = shl %a, 2
227 //
228 // but EarlyCSE can do neither of them.
229 if (getOptLevel() != CodeGenOptLevel::None) {
230 addEarlyCSEOrGVNPass(PMW);
232 addFunctionPass(LoadStoreVectorizerPass(), PMW);
233 addFunctionPass(SROAPass(SROAOptions(SROAOptions::PreserveCFG,
234 /*AggregateToVector=*/true)),
235 PMW);
236 addFunctionPass(NVPTXTagInvariantLoadsPass(), PMW);
238 addFunctionPass(NVPTXIRPeepholePass(), PMW);
239 }
240
241 if (ST.hasPTXASUnreachableBug()) {
242 // Run LowerUnreachable to WAR a ptxas bug. See the commit description of
243 // 1ee4d880e8760256c606fe55b7af85a4f70d006d for more details.
244 addFunctionPass(NVPTXLowerUnreachablePass(TM.Options.TrapUnreachable,
245 TM.Options.NoTrapAfterNoreturn),
246 PMW);
247 }
248}
249
250Error NVPTXCodeGenPassBuilder::addInstSelector(PassManagerWrapper &PMW) {
251 addFunctionPass(NVPTXLowerAggrCopiesPass(), PMW);
252 addFunctionPass(NVPTXAllocaHoistingPass(), PMW);
253 addMachineFunctionPass(NVPTXISelDAGToDAGPass(getTM(), getOptLevel()), PMW);
254 addMachineFunctionPass(NVPTXReplaceImageHandlesPass(), PMW);
255 return Error::success();
256}
257
258void NVPTXCodeGenPassBuilder::addPreRegAlloc(PassManagerWrapper &PMW) {
259 addMachineFunctionPass(NVPTXForwardParamsPass(), PMW);
260 if (getOptLevel() != CodeGenOptLevel::None)
261 addMachineFunctionPass(NVPTXAddressFolderPass(), PMW);
262 // Remove Proxy Register pseudo instructions used to keep `callseq_end` alive.
263 addMachineFunctionPass(NVPTXProxyRegErasurePass(), PMW);
264}
265
266void NVPTXCodeGenPassBuilder::addPostRegAlloc(PassManagerWrapper &PMW) {
267 addMachineFunctionPass(NVPTXPrologEpilogPass(), PMW);
268 if (getOptLevel() != CodeGenOptLevel::None) {
269 // NVPTXPrologEpilogPass calculates frame object offset and replaces frame
270 // index with VRFrame register. NVPTXPeephole needs to be run after that
271 // and will replace VRFrame with VRFrameLocal when possible.
272 addMachineFunctionPass(NVPTXPeepholePass(), PMW);
273 }
274}
275
276Error NVPTXCodeGenPassBuilder::addFastRegAlloc(PassManagerWrapper &PMW) {
277 addMachineFunctionPass(PHIEliminationPass(), PMW);
278 addMachineFunctionPass(TwoAddressInstructionPass(), PMW);
279 return Error::success();
280}
281
282Error NVPTXCodeGenPassBuilder::addOptimizedRegAlloc(PassManagerWrapper &PMW) {
283 addMachineFunctionPass(ProcessImplicitDefsPass(), PMW);
284 addMachineFunctionPass(
285 RequireAnalysisPass<MachineLoopAnalysis, MachineFunction>(), PMW);
286 addMachineFunctionPass(PHIEliminationPass(), PMW);
287
288 addMachineFunctionPass(TwoAddressInstructionPass(), PMW);
289 addMachineFunctionPass(RegisterCoalescerPass(), PMW);
290
291 // PreRA instruction scheduling.
292 addMachineFunctionPass(MachineSchedulerPass(&TM), PMW);
293
294 addMachineFunctionPass(StackSlotColoringPass(), PMW);
295
296 // FIXME: Needs physical registers
297 // addMachineFunctionPass(MachineLICMPass(), PMW);
298
299 return Error::success();
300}
301
302void NVPTXCodeGenPassBuilder::addAsmPrinterBegin(PassManagerWrapper &PMW) {
303 addModulePass(NVPTXAsmPrinterBeginPass(), PMW, /*Force=*/true);
304}
305
306void NVPTXCodeGenPassBuilder::addAsmPrinter(PassManagerWrapper &PMW) {
307 addMachineFunctionPass(NVPTXAsmPrinterPass(), PMW);
308}
309
310void NVPTXCodeGenPassBuilder::addAsmPrinterEnd(PassManagerWrapper &PMW) {
311 addModulePass(NVPTXAsmPrinterEndPass(), PMW);
312}
313
314} // namespace
315
317#define GET_PASS_REGISTRY "NVPTXPassRegistry.def"
319
320 PB.registerPipelineStartEPCallback(
321 [this](ModulePassManager &PM, OptimizationLevel Level) {
322 // We do not want to fold out calls to nvvm.reflect early if the user
323 // has not provided a target architecture just yet.
324 if (Subtarget.hasTargetName())
325 PM.addPass(NVVMReflectPass(Subtarget.getSmVersion()));
326
328 // Note: NVVMIntrRangePass was causing numerical discrepancies at one
329 // point, if issues crop up, consider disabling.
333 PM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
334 });
335
336 if (!NoKernelInfoEndLTO) {
337 PB.registerFullLinkTimeOptimizationLastEPCallback(
338 [this](ModulePassManager &PM, OptimizationLevel Level) {
340 FPM.addPass(KernelInfoPrinter(this));
341 PM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
342 });
343 }
344}
345
348 raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
349 const CGPassBuilderOption &Opt, MCContext &Ctx,
351 auto CGPB = NVPTXCodeGenPassBuilder(*this, Opt, PIC);
352 return CGPB.buildPipeline(MPM, MAM, Out, DwoOut, FileType, Ctx);
353}
Interfaces for producing common pass manager configurations.
This file provides the interface for a simple, fast CSE pass.
This file provides the interface for LLVM's Global Value Numbering pass which eliminates fully redund...
This is the NVPTX address space based alias analysis pass.
cl::opt< bool > DisableNVPTXIRPeephole
static cl::opt< bool > EarlyByValArgsCopy("nvptx-early-byval-copy", cl::desc("Create a copy of byval function arguments early."), cl::init(false), cl::Hidden)
cl::opt< bool > DisableLoadStoreVectorizer
ModuleAnalysisManager MAM
PassBuilder PB(Mod->getContext(), Machine, PassOpts->PTO, std::nullopt, &PIC)
PassInstrumentationCallbacks PIC
This file defines the Pass Instrumentation classes that provide instrumentation points into the pass ...
const GCNTargetMachine & getTM(const GCNSubtarget *STI)
This file provides the interface for LLVM's Scalar Replacement of Aggregates pass.
This class provides access to building LLVM's passes.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
const TargetSubtargetInfo * getSubtargetImpl(const Function &) const override
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Context object for machine code objects.
Definition MCContext.h:83
void registerPassBuilderCallbacks(PassBuilder &PB) override
Allow the target to modify the pass pipeline.
Error buildCodeGenPipeline(ModulePassManager &MPM, ModuleAnalysisManager &MAM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut, CodeGenFileType FileType, const CGPassBuilderOption &Opt, MCContext &Ctx, PassInstrumentationCallbacks *PIC) override
This class provides access to building LLVM's passes.
This class manages callbacks registration, as well as provides a way for PassInstrumentation to pass ...
LLVM_ATTRIBUTE_MINSIZE std::enable_if_t<!std::is_same_v< PassT, PassManager > > addPass(PassT &&Pass)
An abstract base class for streams implementations that also support a pwrite operation.
Interfaces for registering analysis passes, producing common pass manager configurations,...
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
ModuleToFunctionPassAdaptor createModuleToFunctionPassAdaptor(FunctionPassT &&Pass, bool EagerlyInvalidate=false)
A function to deduce a function pass type and wrap it in the templated adaptor.
CodeGenFileType
These enums are meant to be passed into addPassesToEmitFile to indicate what type of file to emit,...
Definition CodeGen.h:309
PassManager< Module > ModulePassManager
Convenience typedef for a pass manager over modules.
PassManager< Function > FunctionPassManager
Convenience typedef for a pass manager over functions.
LLVM_ABI llvm::cl::opt< bool > NoKernelInfoEndLTO
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39