LLVM 22.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
50 None,
53};
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 false)
82
84
93}
94
95void Legalizer::init(MachineFunction &MF) {
96}
97
98static bool isArtifact(const MachineInstr &MI) {
99 switch (MI.getOpcode()) {
100 default:
101 return false;
102 case TargetOpcode::G_TRUNC:
103 case TargetOpcode::G_ZEXT:
104 case TargetOpcode::G_ANYEXT:
105 case TargetOpcode::G_SEXT:
106 case TargetOpcode::G_MERGE_VALUES:
107 case TargetOpcode::G_UNMERGE_VALUES:
108 case TargetOpcode::G_CONCAT_VECTORS:
109 case TargetOpcode::G_BUILD_VECTOR:
110 case TargetOpcode::G_EXTRACT:
111 return true;
112 case TargetOpcode::G_INSERT:
114 }
115}
118
119namespace {
120class LegalizerWorkListManager : public GISelChangeObserver {
121 InstListTy &InstList;
122 ArtifactListTy &ArtifactList;
123#ifndef NDEBUG
125#endif
126
127public:
128 LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts)
129 : InstList(Insts), ArtifactList(Arts) {}
130
131 void createdOrChangedInstr(MachineInstr &MI) {
132 // Only legalize pre-isel generic instructions.
133 // Legalization process could generate Target specific pseudo
134 // instructions with generic types. Don't record them
135 if (isPreISelGenericOpcode(MI.getOpcode())) {
136 if (isArtifact(MI))
137 ArtifactList.insert(&MI);
138 else
139 InstList.insert(&MI);
140 }
141 }
142
143 void createdInstr(MachineInstr &MI) override {
144 LLVM_DEBUG(NewMIs.push_back(&MI));
145 createdOrChangedInstr(MI);
146 }
147
148 void printNewInstrs() {
149 LLVM_DEBUG({
150 for (const auto *MI : NewMIs)
151 dbgs() << ".. .. New MI: " << *MI;
152 NewMIs.clear();
153 });
154 }
155
156 void erasingInstr(MachineInstr &MI) override {
157 LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI);
158 InstList.remove(&MI);
159 ArtifactList.remove(&MI);
160 }
161
162 void changingInstr(MachineInstr &MI) override {
163 LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI);
164 }
165
166 void changedInstr(MachineInstr &MI) override {
167 // When insts change, we want to revisit them to legalize them again.
168 // We'll consider them the same as created.
169 LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI);
170 createdOrChangedInstr(MI);
171 }
172};
173} // namespace
174
178 LostDebugLocObserver &LocObserver,
179 MachineIRBuilder &MIRBuilder,
180 GISelValueTracking *VT) {
181 MIRBuilder.setMF(MF);
183
184 // Populate worklists.
185 InstListTy InstList;
186 ArtifactListTy ArtifactList;
188 // Perform legalization bottom up so we can DCE as we legalize.
189 // Traverse BB in RPOT and within each basic block, add insts top down,
190 // so when we pop_back_val in the legalization process, we traverse bottom-up.
191 for (auto *MBB : RPOT) {
192 if (MBB->empty())
193 continue;
194 for (MachineInstr &MI : *MBB) {
195 // Only legalize pre-isel generic instructions: others don't have types
196 // and are assumed to be legal.
197 if (!isPreISelGenericOpcode(MI.getOpcode()))
198 continue;
199 if (isArtifact(MI))
200 ArtifactList.deferred_insert(&MI);
201 else
202 InstList.deferred_insert(&MI);
203 }
204 }
205 ArtifactList.finalize();
206 InstList.finalize();
207
208 // This observer keeps the worklists updated.
209 LegalizerWorkListManager WorkListObserver(InstList, ArtifactList);
210 // We want both WorkListObserver as well as all the auxiliary observers (e.g.
211 // CSEInfo) to observe all changes. Use the wrapper observer.
212 GISelObserverWrapper WrapperObserver(&WorkListObserver);
213 for (GISelChangeObserver *Observer : AuxObservers)
214 WrapperObserver.addObserver(Observer);
215
216 // Now install the observer as the delegate to MF.
217 // This will keep all the observers notified about new insertions/deletions.
218 RAIIMFObsDelInstaller Installer(MF, WrapperObserver);
219 LegalizerHelper Helper(MF, LI, WrapperObserver, MIRBuilder, VT);
220 LegalizationArtifactCombiner ArtCombiner(MIRBuilder, MRI, LI, VT);
221 bool Changed = false;
223 do {
224 LLVM_DEBUG(dbgs() << "=== New Iteration ===\n");
225 assert(RetryList.empty() && "Expected no instructions in RetryList");
226 unsigned NumArtifacts = ArtifactList.size();
227 while (!InstList.empty()) {
228 MachineInstr &MI = *InstList.pop_back_val();
229 assert(isPreISelGenericOpcode(MI.getOpcode()) &&
230 "Expecting generic opcode");
231 if (isTriviallyDead(MI, MRI)) {
233 eraseInstr(MI, MRI, &LocObserver);
234 continue;
235 }
236
237 // Do the legalization for this instruction.
238 auto Res = Helper.legalizeInstrStep(MI, LocObserver);
239 // Error out if we couldn't legalize this instruction. We may want to
240 // fall back to DAG ISel instead in the future.
242 // Move illegal artifacts to RetryList instead of aborting because
243 // legalizing InstList may generate artifacts that allow
244 // ArtifactCombiner to combine away them.
245 if (isArtifact(MI)) {
246 LLVM_DEBUG(dbgs() << ".. Not legalized, moving to artifacts retry\n");
247 assert(NumArtifacts == 0 &&
248 "Artifacts are only expected in instruction list starting the "
249 "second iteration, but each iteration starting second must "
250 "start with an empty artifacts list");
251 (void)NumArtifacts;
252 RetryList.push_back(&MI);
253 continue;
254 }
256 return {Changed, &MI};
257 }
258 WorkListObserver.printNewInstrs();
259 LocObserver.checkpoint();
260 Changed |= Res == LegalizerHelper::Legalized;
261 }
262 // Try to combine the instructions in RetryList again if there
263 // are new artifacts. If not, stop legalizing.
264 if (!RetryList.empty()) {
265 if (!ArtifactList.empty()) {
266 while (!RetryList.empty())
267 ArtifactList.insert(RetryList.pop_back_val());
268 } else {
269 LLVM_DEBUG(dbgs() << "No new artifacts created, not retrying!\n");
271 return {Changed, RetryList.front()};
272 }
273 }
274 LocObserver.checkpoint();
275 while (!ArtifactList.empty()) {
276 MachineInstr &MI = *ArtifactList.pop_back_val();
277 assert(isPreISelGenericOpcode(MI.getOpcode()) &&
278 "Expecting generic opcode");
279 if (isTriviallyDead(MI, MRI)) {
281 eraseInstr(MI, MRI, &LocObserver);
282 continue;
283 }
284 SmallVector<MachineInstr *, 4> DeadInstructions;
285 LLVM_DEBUG(dbgs() << "Trying to combine: " << MI);
286 if (ArtCombiner.tryCombineInstruction(MI, DeadInstructions,
287 WrapperObserver)) {
288 WorkListObserver.printNewInstrs();
289 eraseInstrs(DeadInstructions, MRI, &LocObserver);
290 LocObserver.checkpoint(
292 DebugLocVerifyLevel::LegalizationsAndArtifactCombiners);
293 Changed = true;
294 continue;
295 }
296 // If this was not an artifact (that could be combined away), this might
297 // need special handling. Add it to InstList, so when it's processed
298 // there, it has to be legal or specially handled.
299 else {
300 LLVM_DEBUG(dbgs() << ".. Not combined, moving to instructions list\n");
301 InstList.insert(&MI);
302 }
303 }
304 } while (!InstList.empty());
305
306 return {Changed, /*FailedOn*/ nullptr};
307}
308
310 // If the ISel pipeline failed, do not bother running that pass.
311 if (MF.getProperties().hasFailedISel())
312 return false;
313 LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n');
314 init(MF);
315 const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
317 getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
318 MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
319
320 std::unique_ptr<MachineIRBuilder> MIRBuilder;
321 GISelCSEInfo *CSEInfo = nullptr;
322 bool EnableCSE = EnableCSEInLegalizer.getNumOccurrences()
324 : TPC.isGISelCSEEnabled();
325 if (EnableCSE) {
326 MIRBuilder = std::make_unique<CSEMIRBuilder>();
327 CSEInfo = &Wrapper.get(TPC.getCSEConfig());
328 MIRBuilder->setCSEInfo(CSEInfo);
329 } else
330 MIRBuilder = std::make_unique<MachineIRBuilder>();
331
333 if (EnableCSE && CSEInfo) {
334 // We want CSEInfo in addition to WorkListObserver to observe all changes.
335 AuxObservers.push_back(CSEInfo);
336 }
337 assert(!CSEInfo || !errorToBool(CSEInfo->verify()));
338 LostDebugLocObserver LocObserver(DEBUG_TYPE);
339 if (VerifyDebugLocs > DebugLocVerifyLevel::None)
340 AuxObservers.push_back(&LocObserver);
341
342 // This allows Known Bits Analysis in the legalizer.
344 &getAnalysis<GISelValueTrackingAnalysisLegacy>().get(MF);
345
346 const LegalizerInfo &LI = *MF.getSubtarget().getLegalizerInfo();
347 MFResult Result = legalizeMachineFunction(MF, LI, AuxObservers, LocObserver,
348 *MIRBuilder, VT);
349
350 if (Result.FailedOn) {
351 reportGISelFailure(MF, TPC, MORE, "gisel-legalize",
352 "unable to legalize instruction", *Result.FailedOn);
353 return false;
354 }
355
356 if (LocObserver.getNumLostDebugLocs()) {
357 MachineOptimizationRemarkMissed R("gisel-legalize", "LostDebugLoc",
359 /*MBB=*/&*MF.begin());
360 R << "lost "
361 << ore::NV("NumLostDebugLocs", LocObserver.getNumLostDebugLocs())
362 << " debug locations during pass";
363 reportGISelWarning(MF, TPC, MORE, R);
364 // Example remark:
365 // --- !Missed
366 // Pass: gisel-legalize
367 // Name: GISelFailure
368 // DebugLoc: { File: '.../legalize-urem.mir', Line: 1, Column: 0 }
369 // Function: test_urem_s32
370 // Args:
371 // - String: 'lost '
372 // - NumLostDebugLocs: '1'
373 // - String: ' debug locations during pass'
374 // ...
375 }
376
377 // If for some reason CSE was not enabled, make sure that we invalidate the
378 // CSEInfo object (as we currently declare that the analysis is preserved).
379 // The next time get on the wrapper is called, it will force it to recompute
380 // the analysis.
381 if (!EnableCSE)
382 Wrapper.setComputed(false);
383 return Result.Changed;
384}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu aa AMDGPU Address space based Alias Analysis Wrapper
AMDGPU Register Bank Legalize
MachineBasicBlock & MBB
COFF::MachineTypes Machine
Definition: COFFYAML.cpp:390
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)
Definition: CommandLine.h:687
Performs the initial survey of the specified function
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
Legalize the Machine IR a function s Machine IR
Definition: Legalizer.cpp:80
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))
#define DEBUG_TYPE
Definition: Legalizer.cpp:33
static bool isArtifact(const MachineInstr &MI)
Definition: Legalizer.cpp:98
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:119
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:41
DISubprogram * getSubprogram() const
Get the attached subprogram.
Definition: Metadata.cpp:1915
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.
Definition: GISelWorkList.h:74
MachineInstr * pop_back_val()
unsigned size() const
Definition: GISelWorkList.h:40
void deferred_insert(MachineInstr *I)
Definition: GISelWorkList.h:50
bool empty() const
Definition: GISelWorkList.h:38
void remove(const MachineInstr *I)
Remove I from the worklist if it exists.
Definition: GISelWorkList.h:83
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...
Definition: Legalizer.cpp:309
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Legalizer.cpp:85
static char ID
Definition: Legalizer.h:40
static MFResult legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI, ArrayRef< GISelChangeObserver * > AuxObservers, LostDebugLocObserver &LocObserver, MachineIRBuilder &MIRBuilder, GISelValueTracking *VT)
Definition: Legalizer.cpp:176
void checkpoint(bool CheckDebugLocs=true)
Call this to indicate that it's a good point to assess whether locations have been lost.
unsigned getNumLostDebugLocs() const
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
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.
Definition: MachineInstr.h:72
Diagnostic information for missed-optimization remarks.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Class to install both of the above.
bool empty() const
Definition: SmallVector.h:82
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
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.
virtual const LegalizerInfo * getLegalizerInfo() const
int getNumOccurrences() const
Definition: CommandLine.h:400
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
Definition: CommandLine.h:712
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:444
DiagnosticInfoOptimizationBase::Argument NV
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
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:1723
bool isPreISelGenericOpcode(unsigned Opcode)
Check whether the given Opcode is a generic opcode that is not supposed to appear after ISel.
Definition: TargetOpcodes.h:30
LLVM_ABI void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC, 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 raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207
LLVM_ABI void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU)
Modify analysis usage so it preserves passes required for the SelectionDAG fallback.
Definition: Utils.cpp:1185
LLVM_ABI void eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver=nullptr)
Definition: Utils.cpp:1718
LLVM_ABI void eraseInstrs(ArrayRef< MachineInstr * > DeadInstrs, MachineRegisterInfo &MRI, LostDebugLocObserver *LocObserver=nullptr)
Definition: Utils.cpp:1703
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
LLVM_ABI void reportGISelWarning(MachineFunction &MF, const TargetPassConfig &TPC, MachineOptimizationRemarkEmitter &MORE, MachineOptimizationRemarkMissed &R)
Report an ISel warning as a missed optimization remark to the LLVMContext's diagnostic stream.
Definition: Utils.cpp:253
#define MORE()
Definition: regcomp.c:246