LLVM 23.0.0git
Legalizer.cpp
Go to the documentation of this file.
1//===-- llvm/CodeGen/GlobalISel/Legalizer.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/// \file This file implements the LegalizerHelper class to legalize individual
10/// instructions and the LegalizePass wrapper pass for the primary
11/// legalization.
12//
13//===----------------------------------------------------------------------===//
14
30#include "llvm/Support/Debug.h"
31#include "llvm/Support/Error.h"
32
33#define DEBUG_TYPE "legalizer"
34
35using namespace llvm;
36
37static cl::opt<bool>
38 EnableCSEInLegalizer("enable-cse-in-legalizer",
39 cl::desc("Should enable CSE in Legalizer"),
40 cl::Optional, cl::init(false));
41
42// This is a temporary hack, should be removed soon.
44 "allow-ginsert-as-artifact",
45 cl::desc("Allow G_INSERT to be considered an artifact. Hack around AMDGPU "
46 "test infinite loops."),
47 cl::Optional, cl::init(true));
48
54#ifndef NDEBUG
56 "verify-legalizer-debug-locs",
57 cl::desc("Verify that debug locations are handled"),
59 clEnumValN(DebugLocVerifyLevel::None, "none", "No verification"),
61 "Verify legalizations"),
63 "legalizations+artifactcombiners",
64 "Verify legalizations and artifact combines")),
66#else
67// Always disable it for release builds by preventing the observer from being
68// installed.
70#endif
71
72char Legalizer::ID = 0;
74 "Legalize the Machine IR a function's Machine IR", false,
75 false)
81 "Legalize the Machine IR a function's Machine IR", false,
82 false)
83
85
96
97void Legalizer::init(MachineFunction &MF) {
98}
99
100static bool isArtifact(const MachineInstr &MI) {
101 switch (MI.getOpcode()) {
102 default:
103 return false;
104 case TargetOpcode::G_TRUNC:
105 case TargetOpcode::G_ZEXT:
106 case TargetOpcode::G_ANYEXT:
107 case TargetOpcode::G_SEXT:
108 case TargetOpcode::G_MERGE_VALUES:
109 case TargetOpcode::G_UNMERGE_VALUES:
110 case TargetOpcode::G_CONCAT_VECTORS:
111 case TargetOpcode::G_BUILD_VECTOR:
112 case TargetOpcode::G_EXTRACT:
113 return true;
114 case TargetOpcode::G_INSERT:
116 }
117}
120
121namespace {
122class LegalizerWorkListManager : public GISelChangeObserver {
123 InstListTy &InstList;
124 ArtifactListTy &ArtifactList;
125#ifndef NDEBUG
127#endif
128
129public:
130 LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts)
131 : InstList(Insts), ArtifactList(Arts) {}
132
133 void createdOrChangedInstr(MachineInstr &MI) {
134 // Only legalize pre-isel generic instructions.
135 // Legalization process could generate Target specific pseudo
136 // instructions with generic types. Don't record them
137 if (isPreISelGenericOpcode(MI.getOpcode())) {
138 if (isArtifact(MI))
139 ArtifactList.insert(&MI);
140 else
141 InstList.insert(&MI);
142 }
143 }
144
145 void createdInstr(MachineInstr &MI) override {
146 LLVM_DEBUG(NewMIs.push_back(&MI));
147 createdOrChangedInstr(MI);
148 }
149
150 void printNewInstrs() {
151 LLVM_DEBUG({
152 for (const auto *MI : NewMIs)
153 dbgs() << ".. .. New MI: " << *MI;
154 NewMIs.clear();
155 });
156 }
157
158 void erasingInstr(MachineInstr &MI) override {
159 LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI);
160 InstList.remove(&MI);
161 ArtifactList.remove(&MI);
162 }
163
164 void changingInstr(MachineInstr &MI) override {
165 LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI);
166 }
167
168 void changedInstr(MachineInstr &MI) override {
169 // When insts change, we want to revisit them to legalize them again.
170 // We'll consider them the same as created.
171 LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI);
172 createdOrChangedInstr(MI);
173 }
174};
175} // namespace
176
178 MachineFunction &MF, const LegalizerInfo &LI,
180 LostDebugLocObserver &LocObserver, MachineIRBuilder &MIRBuilder,
181 const LibcallLoweringInfo *Libcalls, GISelValueTracking *VT) {
182 MIRBuilder.setMF(MF);
184
185 // Populate worklists.
186 InstListTy InstList;
187 ArtifactListTy ArtifactList;
189 // Perform legalization bottom up so we can DCE as we legalize.
190 // Traverse BB in RPOT and within each basic block, add insts top down,
191 // so when we pop_back_val in the legalization process, we traverse bottom-up.
192 for (auto *MBB : RPOT) {
193 if (MBB->empty())
194 continue;
195 for (MachineInstr &MI : *MBB) {
196 // Only legalize pre-isel generic instructions: others don't have types
197 // and are assumed to be legal.
198 if (!isPreISelGenericOpcode(MI.getOpcode()))
199 continue;
200 if (isArtifact(MI))
201 ArtifactList.deferred_insert(&MI);
202 else
203 InstList.deferred_insert(&MI);
204 }
205 }
206 ArtifactList.finalize();
207 InstList.finalize();
208
209 // This observer keeps the worklists updated.
210 LegalizerWorkListManager WorkListObserver(InstList, ArtifactList);
211 // We want both WorkListObserver as well as all the auxiliary observers (e.g.
212 // CSEInfo) to observe all changes. Use the wrapper observer.
213 GISelObserverWrapper WrapperObserver(&WorkListObserver);
214 for (GISelChangeObserver *Observer : AuxObservers)
215 WrapperObserver.addObserver(Observer);
216
217 // Now install the observer as the delegate to MF.
218 // This will keep all the observers notified about new insertions/deletions.
219 RAIIMFObsDelInstaller Installer(MF, WrapperObserver);
220 LegalizerHelper Helper(MF, LI, WrapperObserver, MIRBuilder, Libcalls, VT);
221 LegalizationArtifactCombiner ArtCombiner(MIRBuilder, MRI, LI, VT);
222 bool Changed = false;
224 do {
225 LLVM_DEBUG(dbgs() << "=== New Iteration ===\n");
226 assert(RetryList.empty() && "Expected no instructions in RetryList");
227 unsigned NumArtifacts = ArtifactList.size();
228 while (!InstList.empty()) {
229 MachineInstr &MI = *InstList.pop_back_val();
230 assert(isPreISelGenericOpcode(MI.getOpcode()) &&
231 "Expecting generic opcode");
232 if (isTriviallyDead(MI, MRI)) {
234 eraseInstr(MI, MRI, &LocObserver);
235 continue;
236 }
237
238 // Do the legalization for this instruction.
239 auto Res = Helper.legalizeInstrStep(MI, LocObserver);
240 // Error out if we couldn't legalize this instruction. We may want to
241 // fall back to DAG ISel instead in the future.
243 // Move illegal artifacts to RetryList instead of aborting because
244 // legalizing InstList may generate artifacts that allow
245 // ArtifactCombiner to combine away them.
246 if (isArtifact(MI)) {
247 LLVM_DEBUG(dbgs() << ".. Not legalized, moving to artifacts retry\n");
248 assert(NumArtifacts == 0 &&
249 "Artifacts are only expected in instruction list starting the "
250 "second iteration, but each iteration starting second must "
251 "start with an empty artifacts list");
252 (void)NumArtifacts;
253 RetryList.push_back(&MI);
254 continue;
255 }
257 return {Changed, &MI};
258 }
259 WorkListObserver.printNewInstrs();
260 LocObserver.checkpoint();
262 }
263 // Try to combine the instructions in RetryList again if there
264 // are new artifacts. If not, stop legalizing.
265 if (!RetryList.empty()) {
266 if (!ArtifactList.empty()) {
267 while (!RetryList.empty())
268 ArtifactList.insert(RetryList.pop_back_val());
269 } else {
270 LLVM_DEBUG(dbgs() << "No new artifacts created, not retrying!\n");
272 return {Changed, RetryList.front()};
273 }
274 }
275 LocObserver.checkpoint();
276 while (!ArtifactList.empty()) {
277 MachineInstr &MI = *ArtifactList.pop_back_val();
278 assert(isPreISelGenericOpcode(MI.getOpcode()) &&
279 "Expecting generic opcode");
280 if (isTriviallyDead(MI, MRI)) {
282 eraseInstr(MI, MRI, &LocObserver);
283 continue;
284 }
285 SmallVector<MachineInstr *, 4> DeadInstructions;
286 LLVM_DEBUG(dbgs() << "Trying to combine: " << MI);
287 if (ArtCombiner.tryCombineInstruction(MI, DeadInstructions,
288 WrapperObserver)) {
289 WorkListObserver.printNewInstrs();
290 eraseInstrs(DeadInstructions, MRI, &LocObserver);
291 LocObserver.checkpoint(
294 Changed = true;
295 continue;
296 }
297 // If this was not an artifact (that could be combined away), this might
298 // need special handling. Add it to InstList, so when it's processed
299 // there, it has to be legal or specially handled.
300 else {
301 LLVM_DEBUG(dbgs() << ".. Not combined, moving to instructions list\n");
302 InstList.insert(&MI);
303 }
304 }
305 } while (!InstList.empty());
306
307 return {Changed, /*FailedOn*/ nullptr};
308}
309
311 // If the ISel pipeline failed, do not bother running that pass.
312 if (MF.getProperties().hasFailedISel())
313 return false;
314 LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n');
315 init(MF);
319 MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
320
321 std::unique_ptr<MachineIRBuilder> MIRBuilder;
322 GISelCSEInfo *CSEInfo = nullptr;
323 bool EnableCSE = EnableCSEInLegalizer.getNumOccurrences()
325 : TPC.isGISelCSEEnabled();
326 if (EnableCSE) {
327 MIRBuilder = std::make_unique<CSEMIRBuilder>();
328 CSEInfo = &Wrapper.get(TPC.getCSEConfig());
329 MIRBuilder->setCSEInfo(CSEInfo);
330 } else
331 MIRBuilder = std::make_unique<MachineIRBuilder>();
332
334 if (EnableCSE && CSEInfo) {
335 // We want CSEInfo in addition to WorkListObserver to observe all changes.
336 AuxObservers.push_back(CSEInfo);
337 }
338 assert(!CSEInfo || !errorToBool(CSEInfo->verify()));
339 LostDebugLocObserver LocObserver(DEBUG_TYPE);
341 AuxObservers.push_back(&LocObserver);
342
343 const TargetSubtargetInfo &Subtarget = MF.getSubtarget();
344
345 const LibcallLoweringInfo &Libcalls =
346 getAnalysis<LibcallLoweringInfoWrapper>().getLibcallLowering(
347 *MF.getFunction().getParent(), Subtarget);
348
349 // This allows Known Bits Analysis in the legalizer.
352
353 const LegalizerInfo &LI = *Subtarget.getLegalizerInfo();
354 MFResult Result = legalizeMachineFunction(MF, LI, AuxObservers, LocObserver,
355 *MIRBuilder, &Libcalls, VT);
356
357 if (Result.FailedOn) {
358 reportGISelFailure(MF, MORE, "gisel-legalize",
359 "unable to legalize instruction", *Result.FailedOn);
360 return false;
361 }
362
363 if (LocObserver.getNumLostDebugLocs()) {
364 MachineOptimizationRemarkMissed R("gisel-legalize", "LostDebugLoc",
366 /*MBB=*/&*MF.begin());
367 R << "lost "
368 << ore::NV("NumLostDebugLocs", LocObserver.getNumLostDebugLocs())
369 << " debug locations during pass";
370 reportGISelWarning(MF, MORE, R);
371 // Example remark:
372 // --- !Missed
373 // Pass: gisel-legalize
374 // Name: GISelFailure
375 // DebugLoc: { File: '.../legalize-urem.mir', Line: 1, Column: 0 }
376 // Function: test_urem_s32
377 // Args:
378 // - String: 'lost '
379 // - NumLostDebugLocs: '1'
380 // - String: ' debug locations during pass'
381 // ...
382 }
383
384 // If for some reason CSE was not enabled, make sure that we invalidate the
385 // CSEInfo object (as we currently declare that the analysis is preserved).
386 // The next time get on the wrapper is called, it will force it to recompute
387 // the analysis.
388 if (!EnableCSE)
389 Wrapper.setComputed(false);
390 return Result.Changed;
391}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
MachineBasicBlock & MBB
Provides analysis for continuously CSEing during GISel passes.
This file implements a version of MachineIRBuilder which CSEs insts within a MachineBasicBlock.
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
GISelWorkList< 128 > ArtifactListTy
DebugLocVerifyLevel
Definition Legalizer.cpp:49
static cl::opt< DebugLocVerifyLevel > VerifyDebugLocs("verify-legalizer-debug-locs", cl::desc("Verify that debug locations are handled"), cl::values(clEnumValN(DebugLocVerifyLevel::None, "none", "No verification"), clEnumValN(DebugLocVerifyLevel::Legalizations, "legalizations", "Verify legalizations"), clEnumValN(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners, "legalizations+artifactcombiners", "Verify legalizations and artifact combines")), cl::init(DebugLocVerifyLevel::Legalizations))
static cl::opt< bool > EnableCSEInLegalizer("enable-cse-in-legalizer", cl::desc("Should enable CSE in Legalizer"), cl::Optional, cl::init(false))
static cl::opt< bool > AllowGInsertAsArtifact("allow-ginsert-as-artifact", cl::desc("Allow G_INSERT to be considered an artifact. Hack around AMDGPU " "test infinite loops."), cl::Optional, cl::init(true))
GISelWorkList< 256 > InstListTy
static bool isArtifact(const MachineInstr &MI)
Tracks DebugLocs between checkpoints and verifies that they are transferred.
===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*-—===//
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
#define LLVM_DEBUG(...)
Definition Debug.h:114
Target-Independent Code Generator Pass Configuration Options pass.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
DISubprogram * getSubprogram() const
Get the attached subprogram.
The actual analysis pass wrapper.
Definition CSEInfo.h:229
Simple wrapper that does the following.
Definition CSEInfo.h:211
The CSE Analysis object.
Definition CSEInfo.h:71
Abstract class that contains various methods for clients to notify about changes.
Simple wrapper observer that takes several observers, and calls each one for each event.
void addObserver(GISelChangeObserver *O)
To use KnownBitsInfo analysis in a pass, KnownBitsInfo &Info = getAnalysis<GISelValueTrackingInfoAnal...
void insert(MachineInstr *I)
Add the specified instruction to the worklist if it isn't already in it.
MachineInstr * pop_back_val()
unsigned size() const
void deferred_insert(MachineInstr *I)
void remove(const MachineInstr *I)
Remove I from the worklist if it exists.
Module * getParent()
Get the module that this global value is contained inside of...
bool tryCombineInstruction(MachineInstr &MI, SmallVectorImpl< MachineInstr * > &DeadInsts, GISelObserverWrapper &WrapperObserver)
Try to combine away MI.
@ Legalized
Instruction has been legalized and the MachineFunction changed.
@ UnableToLegalize
Some kind of error has occurred and we could not legalize this instruction.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI LegalizeResult legalizeInstrStep(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Replace MI by a sequence of legal instructions that can implement the same operation.
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition Legalizer.cpp:86
static char ID
Definition Legalizer.h:41
static MFResult legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI, ArrayRef< GISelChangeObserver * > AuxObservers, LostDebugLocObserver &LocObserver, MachineIRBuilder &MIRBuilder, const LibcallLoweringInfo *Libcalls, GISelValueTracking *VT)
Tracks which library functions to use for a particular subtarget.
void checkpoint(bool CheckDebugLocs=true)
Call this to indicate that it's a good point to assess whether locations have been lost.
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineFunctionProperties & getProperties() const
Get the function properties.
Helper class to build MachineInstr.
void setMF(MachineFunction &MF)
Representation of each machine instruction.
Diagnostic information for missed-optimization remarks.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
Class to install both of the above.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Target-Independent Code Generator Pass Configuration Options.
virtual std::unique_ptr< CSEConfigBase > getCSEConfig() const
Returns the CSEConfig object to use for the current optimization level.
virtual bool isGISelCSEEnabled() const
Check whether continuous CSE should be enabled in GISel passes.
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const LegalizerInfo * getLegalizerInfo() const
Changed
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
DiagnosticInfoOptimizationBase::Argument NV
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
bool errorToBool(Error Err)
Helper for converting an Error to a bool.
Definition Error.h:1113
LLVM_ABI void salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI)
Assuming the instruction MI is going to be deleted, attempt to salvage debug users of MI by writing t...
Definition Utils.cpp:1731
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
LLVM_ABI void reportGISelWarning(MachineFunction &MF, MachineOptimizationRemarkEmitter &MORE, MachineOptimizationRemarkMissed &R)
Report an ISel warning as a missed optimization remark to the LLVMContext's diagnostic stream.
Definition Utils.cpp:253
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
LLVM_ABI void reportGISelFailure(MachineFunction &MF, MachineOptimizationRemarkEmitter &MORE, MachineOptimizationRemarkMissed &R)
Report an ISel error as a missed optimization remark to the LLVMContext's diagnostic stream.
Definition Utils.cpp:259
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition Utils.cpp:1191
LLVM_ABI void eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver=nullptr)
Definition Utils.cpp:1726
LLVM_ABI void eraseInstrs(ArrayRef< MachineInstr * > DeadInstrs, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver=nullptr)
Definition Utils.cpp:1711
LLVM_ABI bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Check whether an instruction MI is dead: it only defines dead virtual registers, and doesn't have oth...
Definition Utils.cpp:222
#define MORE()
Definition regcomp.c:246