File: | src/gnu/usr.bin/clang/libLLVM/../../../llvm/llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h |
Warning: | line 35, column 40 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||
15 | #include "llvm/CodeGen/GlobalISel/Legalizer.h" | ||||
16 | #include "llvm/ADT/PostOrderIterator.h" | ||||
17 | #include "llvm/ADT/SetVector.h" | ||||
18 | #include "llvm/CodeGen/GlobalISel/CSEInfo.h" | ||||
19 | #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" | ||||
20 | #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" | ||||
21 | #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" | ||||
22 | #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h" | ||||
23 | #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h" | ||||
24 | #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h" | ||||
25 | #include "llvm/CodeGen/GlobalISel/Utils.h" | ||||
26 | #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" | ||||
27 | #include "llvm/CodeGen/MachineRegisterInfo.h" | ||||
28 | #include "llvm/CodeGen/TargetPassConfig.h" | ||||
29 | #include "llvm/CodeGen/TargetSubtargetInfo.h" | ||||
30 | #include "llvm/InitializePasses.h" | ||||
31 | #include "llvm/Support/Debug.h" | ||||
32 | #include "llvm/Support/Error.h" | ||||
33 | #include "llvm/Target/TargetMachine.h" | ||||
34 | |||||
35 | #include <iterator> | ||||
36 | |||||
37 | #define DEBUG_TYPE"legalizer" "legalizer" | ||||
38 | |||||
39 | using namespace llvm; | ||||
40 | |||||
41 | static cl::opt<bool> | ||||
42 | EnableCSEInLegalizer("enable-cse-in-legalizer", | ||||
43 | cl::desc("Should enable CSE in Legalizer"), | ||||
44 | cl::Optional, cl::init(false)); | ||||
45 | |||||
46 | // This is a temporary hack, should be removed soon. | ||||
47 | static cl::opt<bool> AllowGInsertAsArtifact( | ||||
48 | "allow-ginsert-as-artifact", | ||||
49 | cl::desc("Allow G_INSERT to be considered an artifact. Hack around AMDGPU " | ||||
50 | "test infinite loops."), | ||||
51 | cl::Optional, cl::init(true)); | ||||
52 | |||||
53 | enum class DebugLocVerifyLevel { | ||||
54 | None, | ||||
55 | Legalizations, | ||||
56 | LegalizationsAndArtifactCombiners, | ||||
57 | }; | ||||
58 | #ifndef NDEBUG1 | ||||
59 | static cl::opt<DebugLocVerifyLevel> VerifyDebugLocs( | ||||
60 | "verify-legalizer-debug-locs", | ||||
61 | cl::desc("Verify that debug locations are handled"), | ||||
62 | cl::values( | ||||
63 | clEnumValN(DebugLocVerifyLevel::None, "none", "No verification")llvm::cl::OptionEnumValue { "none", int(DebugLocVerifyLevel:: None), "No verification" }, | ||||
64 | clEnumValN(DebugLocVerifyLevel::Legalizations, "legalizations",llvm::cl::OptionEnumValue { "legalizations", int(DebugLocVerifyLevel ::Legalizations), "Verify legalizations" } | ||||
65 | "Verify legalizations")llvm::cl::OptionEnumValue { "legalizations", int(DebugLocVerifyLevel ::Legalizations), "Verify legalizations" }, | ||||
66 | clEnumValN(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners,llvm::cl::OptionEnumValue { "legalizations+artifactcombiners" , int(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners) , "Verify legalizations and artifact combines" } | ||||
67 | "legalizations+artifactcombiners",llvm::cl::OptionEnumValue { "legalizations+artifactcombiners" , int(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners) , "Verify legalizations and artifact combines" } | ||||
68 | "Verify legalizations and artifact combines")llvm::cl::OptionEnumValue { "legalizations+artifactcombiners" , int(DebugLocVerifyLevel::LegalizationsAndArtifactCombiners) , "Verify legalizations and artifact combines" }), | ||||
69 | cl::init(DebugLocVerifyLevel::Legalizations)); | ||||
70 | #else | ||||
71 | // Always disable it for release builds by preventing the observer from being | ||||
72 | // installed. | ||||
73 | static const DebugLocVerifyLevel VerifyDebugLocs = DebugLocVerifyLevel::None; | ||||
74 | #endif | ||||
75 | |||||
76 | char Legalizer::ID = 0; | ||||
77 | INITIALIZE_PASS_BEGIN(Legalizer, DEBUG_TYPE,static void *initializeLegalizerPassOnce(PassRegistry &Registry ) { | ||||
78 | "Legalize the Machine IR a function's Machine IR", false,static void *initializeLegalizerPassOnce(PassRegistry &Registry ) { | ||||
79 | false)static void *initializeLegalizerPassOnce(PassRegistry &Registry ) { | ||||
80 | INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)initializeTargetPassConfigPass(Registry); | ||||
81 | INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)initializeGISelCSEAnalysisWrapperPassPass(Registry); | ||||
82 | INITIALIZE_PASS_END(Legalizer, DEBUG_TYPE,PassInfo *PI = new PassInfo( "Legalize the Machine IR a function's Machine IR" , "legalizer", &Legalizer::ID, PassInfo::NormalCtor_t(callDefaultCtor <Legalizer>), false, false); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeLegalizerPassFlag ; void llvm::initializeLegalizerPass(PassRegistry &Registry ) { llvm::call_once(InitializeLegalizerPassFlag, initializeLegalizerPassOnce , std::ref(Registry)); } | ||||
83 | "Legalize the Machine IR a function's Machine IR", false,PassInfo *PI = new PassInfo( "Legalize the Machine IR a function's Machine IR" , "legalizer", &Legalizer::ID, PassInfo::NormalCtor_t(callDefaultCtor <Legalizer>), false, false); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeLegalizerPassFlag ; void llvm::initializeLegalizerPass(PassRegistry &Registry ) { llvm::call_once(InitializeLegalizerPassFlag, initializeLegalizerPassOnce , std::ref(Registry)); } | ||||
84 | false)PassInfo *PI = new PassInfo( "Legalize the Machine IR a function's Machine IR" , "legalizer", &Legalizer::ID, PassInfo::NormalCtor_t(callDefaultCtor <Legalizer>), false, false); Registry.registerPass(*PI, true); return PI; } static llvm::once_flag InitializeLegalizerPassFlag ; void llvm::initializeLegalizerPass(PassRegistry &Registry ) { llvm::call_once(InitializeLegalizerPassFlag, initializeLegalizerPassOnce , std::ref(Registry)); } | ||||
85 | |||||
86 | Legalizer::Legalizer() : MachineFunctionPass(ID) { } | ||||
87 | |||||
88 | void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const { | ||||
89 | AU.addRequired<TargetPassConfig>(); | ||||
90 | AU.addRequired<GISelCSEAnalysisWrapperPass>(); | ||||
91 | AU.addPreserved<GISelCSEAnalysisWrapperPass>(); | ||||
92 | getSelectionDAGFallbackAnalysisUsage(AU); | ||||
93 | MachineFunctionPass::getAnalysisUsage(AU); | ||||
94 | } | ||||
95 | |||||
96 | void Legalizer::init(MachineFunction &MF) { | ||||
97 | } | ||||
98 | |||||
99 | static bool isArtifact(const MachineInstr &MI) { | ||||
100 | switch (MI.getOpcode()) { | ||||
101 | default: | ||||
102 | return false; | ||||
103 | case TargetOpcode::G_TRUNC: | ||||
104 | case TargetOpcode::G_ZEXT: | ||||
105 | case TargetOpcode::G_ANYEXT: | ||||
106 | case TargetOpcode::G_SEXT: | ||||
107 | case TargetOpcode::G_MERGE_VALUES: | ||||
108 | case TargetOpcode::G_UNMERGE_VALUES: | ||||
109 | case TargetOpcode::G_CONCAT_VECTORS: | ||||
110 | case TargetOpcode::G_BUILD_VECTOR: | ||||
111 | case TargetOpcode::G_EXTRACT: | ||||
112 | return true; | ||||
113 | case TargetOpcode::G_INSERT: | ||||
114 | return AllowGInsertAsArtifact; | ||||
115 | } | ||||
116 | } | ||||
117 | using InstListTy = GISelWorkList<256>; | ||||
118 | using ArtifactListTy = GISelWorkList<128>; | ||||
119 | |||||
120 | namespace { | ||||
121 | class LegalizerWorkListManager : public GISelChangeObserver { | ||||
122 | InstListTy &InstList; | ||||
123 | ArtifactListTy &ArtifactList; | ||||
124 | #ifndef NDEBUG1 | ||||
125 | SmallVector<MachineInstr *, 4> NewMIs; | ||||
126 | #endif | ||||
127 | |||||
128 | public: | ||||
129 | LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts) | ||||
130 | : InstList(Insts), ArtifactList(Arts) {} | ||||
131 | |||||
132 | void createdOrChangedInstr(MachineInstr &MI) { | ||||
133 | // Only legalize pre-isel generic instructions. | ||||
134 | // Legalization process could generate Target specific pseudo | ||||
135 | // instructions with generic types. Don't record them | ||||
136 | if (isPreISelGenericOpcode(MI.getOpcode())) { | ||||
137 | if (isArtifact(MI)) | ||||
138 | ArtifactList.insert(&MI); | ||||
139 | else | ||||
140 | InstList.insert(&MI); | ||||
141 | } | ||||
142 | } | ||||
143 | |||||
144 | void createdInstr(MachineInstr &MI) override { | ||||
145 | LLVM_DEBUG(NewMIs.push_back(&MI))do { } while (false); | ||||
146 | createdOrChangedInstr(MI); | ||||
147 | } | ||||
148 | |||||
149 | void printNewInstrs() { | ||||
150 | LLVM_DEBUG({do { } while (false) | ||||
151 | for (const auto *MI : NewMIs)do { } while (false) | ||||
152 | dbgs() << ".. .. New MI: " << *MI;do { } while (false) | ||||
153 | NewMIs.clear();do { } while (false) | ||||
154 | })do { } while (false); | ||||
155 | } | ||||
156 | |||||
157 | void erasingInstr(MachineInstr &MI) override { | ||||
158 | LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI)do { } while (false); | ||||
159 | InstList.remove(&MI); | ||||
160 | ArtifactList.remove(&MI); | ||||
161 | } | ||||
162 | |||||
163 | void changingInstr(MachineInstr &MI) override { | ||||
164 | LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI)do { } while (false); | ||||
165 | } | ||||
166 | |||||
167 | void changedInstr(MachineInstr &MI) override { | ||||
168 | // When insts change, we want to revisit them to legalize them again. | ||||
169 | // We'll consider them the same as created. | ||||
170 | LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI)do { } while (false); | ||||
171 | createdOrChangedInstr(MI); | ||||
172 | } | ||||
173 | }; | ||||
174 | } // namespace | ||||
175 | |||||
176 | Legalizer::MFResult | ||||
177 | Legalizer::legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI, | ||||
178 | ArrayRef<GISelChangeObserver *> AuxObservers, | ||||
179 | LostDebugLocObserver &LocObserver, | ||||
180 | MachineIRBuilder &MIRBuilder) { | ||||
181 | MIRBuilder.setMF(MF); | ||||
182 | MachineRegisterInfo &MRI = MF.getRegInfo(); | ||||
183 | |||||
184 | // Populate worklists. | ||||
185 | InstListTy InstList; | ||||
186 | ArtifactListTy ArtifactList; | ||||
187 | ReversePostOrderTraversal<MachineFunction *> RPOT(&MF); | ||||
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); | ||||
220 | LegalizationArtifactCombiner ArtCombiner(MIRBuilder, MRI, LI); | ||||
221 | auto RemoveDeadInstFromLists = [&WrapperObserver](MachineInstr *DeadMI) { | ||||
222 | WrapperObserver.erasingInstr(*DeadMI); | ||||
223 | }; | ||||
224 | bool Changed = false; | ||||
225 | SmallVector<MachineInstr *, 128> RetryList; | ||||
226 | do { | ||||
227 | LLVM_DEBUG(dbgs() << "=== New Iteration ===\n")do { } while (false); | ||||
228 | assert(RetryList.empty() && "Expected no instructions in RetryList")((void)0); | ||||
229 | unsigned NumArtifacts = ArtifactList.size(); | ||||
230 | while (!InstList.empty()) { | ||||
231 | MachineInstr &MI = *InstList.pop_back_val(); | ||||
232 | assert(isPreISelGenericOpcode(MI.getOpcode()) &&((void)0) | ||||
233 | "Expecting generic opcode")((void)0); | ||||
234 | if (isTriviallyDead(MI, MRI)) { | ||||
235 | LLVM_DEBUG(dbgs() << MI << "Is dead; erasing.\n")do { } while (false); | ||||
236 | MI.eraseFromParentAndMarkDBGValuesForRemoval(); | ||||
237 | LocObserver.checkpoint(false); | ||||
238 | continue; | ||||
239 | } | ||||
240 | |||||
241 | // Do the legalization for this instruction. | ||||
242 | auto Res = Helper.legalizeInstrStep(MI, LocObserver); | ||||
243 | // Error out if we couldn't legalize this instruction. We may want to | ||||
244 | // fall back to DAG ISel instead in the future. | ||||
245 | if (Res == LegalizerHelper::UnableToLegalize) { | ||||
246 | // Move illegal artifacts to RetryList instead of aborting because | ||||
247 | // legalizing InstList may generate artifacts that allow | ||||
248 | // ArtifactCombiner to combine away them. | ||||
249 | if (isArtifact(MI)) { | ||||
250 | LLVM_DEBUG(dbgs() << ".. Not legalized, moving to artifacts retry\n")do { } while (false); | ||||
251 | assert(NumArtifacts == 0 &&((void)0) | ||||
252 | "Artifacts are only expected in instruction list starting the "((void)0) | ||||
253 | "second iteration, but each iteration starting second must "((void)0) | ||||
254 | "start with an empty artifacts list")((void)0); | ||||
255 | (void)NumArtifacts; | ||||
256 | RetryList.push_back(&MI); | ||||
257 | continue; | ||||
258 | } | ||||
259 | Helper.MIRBuilder.stopObservingChanges(); | ||||
260 | return {Changed, &MI}; | ||||
261 | } | ||||
262 | WorkListObserver.printNewInstrs(); | ||||
263 | LocObserver.checkpoint(); | ||||
264 | Changed |= Res == LegalizerHelper::Legalized; | ||||
265 | } | ||||
266 | // Try to combine the instructions in RetryList again if there | ||||
267 | // are new artifacts. If not, stop legalizing. | ||||
268 | if (!RetryList.empty()) { | ||||
269 | if (!ArtifactList.empty()) { | ||||
270 | while (!RetryList.empty()) | ||||
271 | ArtifactList.insert(RetryList.pop_back_val()); | ||||
272 | } else { | ||||
273 | LLVM_DEBUG(dbgs() << "No new artifacts created, not retrying!\n")do { } while (false); | ||||
274 | Helper.MIRBuilder.stopObservingChanges(); | ||||
275 | return {Changed, RetryList.front()}; | ||||
276 | } | ||||
277 | } | ||||
278 | LocObserver.checkpoint(); | ||||
279 | while (!ArtifactList.empty()) { | ||||
280 | MachineInstr &MI = *ArtifactList.pop_back_val(); | ||||
281 | assert(isPreISelGenericOpcode(MI.getOpcode()) &&((void)0) | ||||
282 | "Expecting generic opcode")((void)0); | ||||
283 | if (isTriviallyDead(MI, MRI)) { | ||||
284 | LLVM_DEBUG(dbgs() << MI << "Is dead\n")do { } while (false); | ||||
285 | RemoveDeadInstFromLists(&MI); | ||||
286 | MI.eraseFromParentAndMarkDBGValuesForRemoval(); | ||||
287 | LocObserver.checkpoint(false); | ||||
288 | continue; | ||||
289 | } | ||||
290 | SmallVector<MachineInstr *, 4> DeadInstructions; | ||||
291 | LLVM_DEBUG(dbgs() << "Trying to combine: " << MI)do { } while (false); | ||||
292 | if (ArtCombiner.tryCombineInstruction(MI, DeadInstructions, | ||||
293 | WrapperObserver)) { | ||||
294 | WorkListObserver.printNewInstrs(); | ||||
295 | for (auto *DeadMI : DeadInstructions) { | ||||
296 | LLVM_DEBUG(dbgs() << "Is dead: " << *DeadMI)do { } while (false); | ||||
297 | RemoveDeadInstFromLists(DeadMI); | ||||
298 | DeadMI->eraseFromParentAndMarkDBGValuesForRemoval(); | ||||
299 | } | ||||
300 | LocObserver.checkpoint( | ||||
301 | VerifyDebugLocs == | ||||
302 | DebugLocVerifyLevel::LegalizationsAndArtifactCombiners); | ||||
303 | Changed = true; | ||||
304 | continue; | ||||
305 | } | ||||
306 | // If this was not an artifact (that could be combined away), this might | ||||
307 | // need special handling. Add it to InstList, so when it's processed | ||||
308 | // there, it has to be legal or specially handled. | ||||
309 | else { | ||||
310 | LLVM_DEBUG(dbgs() << ".. Not combined, moving to instructions list\n")do { } while (false); | ||||
311 | InstList.insert(&MI); | ||||
312 | } | ||||
313 | } | ||||
314 | } while (!InstList.empty()); | ||||
315 | |||||
316 | return {Changed, /*FailedOn*/ nullptr}; | ||||
317 | } | ||||
318 | |||||
319 | bool Legalizer::runOnMachineFunction(MachineFunction &MF) { | ||||
320 | // If the ISel pipeline failed, do not bother running that pass. | ||||
321 | if (MF.getProperties().hasProperty( | ||||
| |||||
322 | MachineFunctionProperties::Property::FailedISel)) | ||||
323 | return false; | ||||
324 | LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n')do { } while (false); | ||||
325 | init(MF); | ||||
326 | const TargetPassConfig &TPC = getAnalysis<TargetPassConfig>(); | ||||
327 | GISelCSEAnalysisWrapper &Wrapper = | ||||
328 | getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper(); | ||||
329 | MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); | ||||
330 | |||||
331 | const size_t NumBlocks = MF.size(); | ||||
332 | |||||
333 | std::unique_ptr<MachineIRBuilder> MIRBuilder; | ||||
334 | GISelCSEInfo *CSEInfo = nullptr; | ||||
335 | bool EnableCSE = EnableCSEInLegalizer.getNumOccurrences() | ||||
336 | ? EnableCSEInLegalizer | ||||
337 | : TPC.isGISelCSEEnabled(); | ||||
338 | if (EnableCSE) { | ||||
339 | MIRBuilder = std::make_unique<CSEMIRBuilder>(); | ||||
340 | CSEInfo = &Wrapper.get(TPC.getCSEConfig()); | ||||
341 | MIRBuilder->setCSEInfo(CSEInfo); | ||||
342 | } else | ||||
343 | MIRBuilder = std::make_unique<MachineIRBuilder>(); | ||||
344 | |||||
345 | SmallVector<GISelChangeObserver *, 1> AuxObservers; | ||||
346 | if (EnableCSE
| ||||
347 | // We want CSEInfo in addition to WorkListObserver to observe all changes. | ||||
348 | AuxObservers.push_back(CSEInfo); | ||||
349 | } | ||||
350 | assert(!CSEInfo || !errorToBool(CSEInfo->verify()))((void)0); | ||||
351 | LostDebugLocObserver LocObserver(DEBUG_TYPE"legalizer"); | ||||
352 | if (VerifyDebugLocs
| ||||
353 | AuxObservers.push_back(&LocObserver); | ||||
354 | |||||
355 | const LegalizerInfo &LI = *MF.getSubtarget().getLegalizerInfo(); | ||||
356 | MFResult Result = | ||||
357 | legalizeMachineFunction(MF, LI, AuxObservers, LocObserver, *MIRBuilder); | ||||
358 | |||||
359 | if (Result.FailedOn) { | ||||
360 | reportGISelFailure(MF, TPC, MORE, "gisel-legalize", | ||||
361 | "unable to legalize instruction", *Result.FailedOn); | ||||
362 | return false; | ||||
363 | } | ||||
364 | // For now don't support if new blocks are inserted - we would need to fix the | ||||
365 | // outer loop for that. | ||||
366 | if (MF.size() != NumBlocks) { | ||||
367 | MachineOptimizationRemarkMissed R("gisel-legalize", "GISelFailure", | ||||
368 | MF.getFunction().getSubprogram(), | ||||
369 | /*MBB=*/nullptr); | ||||
370 | R << "inserting blocks is not supported yet"; | ||||
371 | reportGISelFailure(MF, TPC, MORE, R); | ||||
372 | return false; | ||||
373 | } | ||||
374 | |||||
375 | if (LocObserver.getNumLostDebugLocs()) { | ||||
376 | MachineOptimizationRemarkMissed R("gisel-legalize", "LostDebugLoc", | ||||
377 | MF.getFunction().getSubprogram(), | ||||
378 | /*MBB=*/&*MF.begin()); | ||||
379 | R << "lost " | ||||
380 | << ore::NV("NumLostDebugLocs", LocObserver.getNumLostDebugLocs()) | ||||
381 | << " debug locations during pass"; | ||||
382 | reportGISelWarning(MF, TPC, MORE, R); | ||||
383 | // Example remark: | ||||
384 | // --- !Missed | ||||
385 | // Pass: gisel-legalize | ||||
386 | // Name: GISelFailure | ||||
387 | // DebugLoc: { File: '.../legalize-urem.mir', Line: 1, Column: 0 } | ||||
388 | // Function: test_urem_s32 | ||||
389 | // Args: | ||||
390 | // - String: 'lost ' | ||||
391 | // - NumLostDebugLocs: '1' | ||||
392 | // - String: ' debug locations during pass' | ||||
393 | // ... | ||||
394 | } | ||||
395 | |||||
396 | // If for some reason CSE was not enabled, make sure that we invalidate the | ||||
397 | // CSEInfo object (as we currently declare that the analysis is preserved). | ||||
398 | // The next time get on the wrapper is called, it will force it to recompute | ||||
399 | // the analysis. | ||||
400 | if (!EnableCSE) | ||||
401 | Wrapper.setComputed(false); | ||||
402 | return Result.Changed; | ||||
403 | } |
1 | ///===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*----===// | |||
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 | /// Optimization diagnostic interfaces for machine passes. It's packaged as an | |||
10 | /// analysis pass so that by using this service passes become dependent on MBFI | |||
11 | /// as well. MBFI is used to compute the "hotness" of the diagnostic message. | |||
12 | /// | |||
13 | ///===---------------------------------------------------------------------===// | |||
14 | ||||
15 | #ifndef LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H | |||
16 | #define LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H | |||
17 | ||||
18 | #include "llvm/Analysis/OptimizationRemarkEmitter.h" | |||
19 | #include "llvm/CodeGen/MachineFunctionPass.h" | |||
20 | ||||
21 | namespace llvm { | |||
22 | class MachineBasicBlock; | |||
23 | class MachineBlockFrequencyInfo; | |||
24 | class MachineInstr; | |||
25 | ||||
26 | /// Common features for diagnostics dealing with optimization remarks | |||
27 | /// that are used by machine passes. | |||
28 | class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase { | |||
29 | public: | |||
30 | DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName, | |||
31 | StringRef RemarkName, | |||
32 | const DiagnosticLocation &Loc, | |||
33 | const MachineBasicBlock *MBB) | |||
34 | : DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, RemarkName, | |||
35 | MBB->getParent()->getFunction(), Loc), | |||
| ||||
36 | MBB(MBB) {} | |||
37 | ||||
38 | /// MI-specific kinds of diagnostic Arguments. | |||
39 | struct MachineArgument : public DiagnosticInfoOptimizationBase::Argument { | |||
40 | /// Print an entire MachineInstr. | |||
41 | MachineArgument(StringRef Key, const MachineInstr &MI); | |||
42 | }; | |||
43 | ||||
44 | static bool classof(const DiagnosticInfo *DI) { | |||
45 | return DI->getKind() >= DK_FirstMachineRemark && | |||
46 | DI->getKind() <= DK_LastMachineRemark; | |||
47 | } | |||
48 | ||||
49 | const MachineBasicBlock *getBlock() const { return MBB; } | |||
50 | ||||
51 | private: | |||
52 | const MachineBasicBlock *MBB; | |||
53 | }; | |||
54 | ||||
55 | /// Diagnostic information for applied optimization remarks. | |||
56 | class MachineOptimizationRemark : public DiagnosticInfoMIROptimization { | |||
57 | public: | |||
58 | /// \p PassName is the name of the pass emitting this diagnostic. If this name | |||
59 | /// matches the regular expression given in -Rpass=, then the diagnostic will | |||
60 | /// be emitted. \p RemarkName is a textual identifier for the remark. \p | |||
61 | /// Loc is the debug location and \p MBB is the block that the optimization | |||
62 | /// operates in. | |||
63 | MachineOptimizationRemark(const char *PassName, StringRef RemarkName, | |||
64 | const DiagnosticLocation &Loc, | |||
65 | const MachineBasicBlock *MBB) | |||
66 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName, | |||
67 | RemarkName, Loc, MBB) {} | |||
68 | ||||
69 | static bool classof(const DiagnosticInfo *DI) { | |||
70 | return DI->getKind() == DK_MachineOptimizationRemark; | |||
71 | } | |||
72 | ||||
73 | /// \see DiagnosticInfoOptimizationBase::isEnabled. | |||
74 | bool isEnabled() const override { | |||
75 | const Function &Fn = getFunction(); | |||
76 | LLVMContext &Ctx = Fn.getContext(); | |||
77 | return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(getPassName()); | |||
78 | } | |||
79 | }; | |||
80 | ||||
81 | /// Diagnostic information for missed-optimization remarks. | |||
82 | class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization { | |||
83 | public: | |||
84 | /// \p PassName is the name of the pass emitting this diagnostic. If this name | |||
85 | /// matches the regular expression given in -Rpass-missed=, then the | |||
86 | /// diagnostic will be emitted. \p RemarkName is a textual identifier for the | |||
87 | /// remark. \p Loc is the debug location and \p MBB is the block that the | |||
88 | /// optimization operates in. | |||
89 | MachineOptimizationRemarkMissed(const char *PassName, StringRef RemarkName, | |||
90 | const DiagnosticLocation &Loc, | |||
91 | const MachineBasicBlock *MBB) | |||
92 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed, | |||
93 | PassName, RemarkName, Loc, MBB) {} | |||
94 | ||||
95 | static bool classof(const DiagnosticInfo *DI) { | |||
96 | return DI->getKind() == DK_MachineOptimizationRemarkMissed; | |||
97 | } | |||
98 | ||||
99 | /// \see DiagnosticInfoOptimizationBase::isEnabled. | |||
100 | bool isEnabled() const override { | |||
101 | const Function &Fn = getFunction(); | |||
102 | LLVMContext &Ctx = Fn.getContext(); | |||
103 | return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(getPassName()); | |||
104 | } | |||
105 | }; | |||
106 | ||||
107 | /// Diagnostic information for optimization analysis remarks. | |||
108 | class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization { | |||
109 | public: | |||
110 | /// \p PassName is the name of the pass emitting this diagnostic. If this name | |||
111 | /// matches the regular expression given in -Rpass-analysis=, then the | |||
112 | /// diagnostic will be emitted. \p RemarkName is a textual identifier for the | |||
113 | /// remark. \p Loc is the debug location and \p MBB is the block that the | |||
114 | /// optimization operates in. | |||
115 | MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, | |||
116 | const DiagnosticLocation &Loc, | |||
117 | const MachineBasicBlock *MBB) | |||
118 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, | |||
119 | PassName, RemarkName, Loc, MBB) {} | |||
120 | ||||
121 | static bool classof(const DiagnosticInfo *DI) { | |||
122 | return DI->getKind() == DK_MachineOptimizationRemarkAnalysis; | |||
123 | } | |||
124 | ||||
125 | /// \see DiagnosticInfoOptimizationBase::isEnabled. | |||
126 | bool isEnabled() const override { | |||
127 | const Function &Fn = getFunction(); | |||
128 | LLVMContext &Ctx = Fn.getContext(); | |||
129 | return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(getPassName()); | |||
130 | } | |||
131 | }; | |||
132 | ||||
133 | /// Extend llvm::ore:: with MI-specific helper names. | |||
134 | namespace ore { | |||
135 | using MNV = DiagnosticInfoMIROptimization::MachineArgument; | |||
136 | } | |||
137 | ||||
138 | /// The optimization diagnostic interface. | |||
139 | /// | |||
140 | /// It allows reporting when optimizations are performed and when they are not | |||
141 | /// along with the reasons for it. Hotness information of the corresponding | |||
142 | /// code region can be included in the remark if DiagnosticsHotnessRequested is | |||
143 | /// enabled in the LLVM context. | |||
144 | class MachineOptimizationRemarkEmitter { | |||
145 | public: | |||
146 | MachineOptimizationRemarkEmitter(MachineFunction &MF, | |||
147 | MachineBlockFrequencyInfo *MBFI) | |||
148 | : MF(MF), MBFI(MBFI) {} | |||
149 | ||||
150 | /// Emit an optimization remark. | |||
151 | void emit(DiagnosticInfoOptimizationBase &OptDiag); | |||
152 | ||||
153 | /// Whether we allow for extra compile-time budget to perform more | |||
154 | /// analysis to be more informative. | |||
155 | /// | |||
156 | /// This is useful to enable additional missed optimizations to be reported | |||
157 | /// that are normally too noisy. In this mode, we can use the extra analysis | |||
158 | /// (1) to filter trivial false positives or (2) to provide more context so | |||
159 | /// that non-trivial false positives can be quickly detected by the user. | |||
160 | bool allowExtraAnalysis(StringRef PassName) const { | |||
161 | return ( | |||
162 | MF.getFunction().getContext().getLLVMRemarkStreamer() || | |||
163 | MF.getFunction().getContext().getDiagHandlerPtr()->isAnyRemarkEnabled( | |||
164 | PassName)); | |||
165 | } | |||
166 | ||||
167 | /// Take a lambda that returns a remark which will be emitted. Second | |||
168 | /// argument is only used to restrict this to functions. | |||
169 | template <typename T> | |||
170 | void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) { | |||
171 | // Avoid building the remark unless we know there are at least *some* | |||
172 | // remarks enabled. We can't currently check whether remarks are requested | |||
173 | // for the calling pass since that requires actually building the remark. | |||
174 | ||||
175 | if (MF.getFunction().getContext().getLLVMRemarkStreamer() || | |||
176 | MF.getFunction() | |||
177 | .getContext() | |||
178 | .getDiagHandlerPtr() | |||
179 | ->isAnyRemarkEnabled()) { | |||
180 | auto R = RemarkBuilder(); | |||
181 | emit((DiagnosticInfoOptimizationBase &)R); | |||
182 | } | |||
183 | } | |||
184 | ||||
185 | MachineBlockFrequencyInfo *getBFI() { | |||
186 | return MBFI; | |||
187 | } | |||
188 | ||||
189 | private: | |||
190 | MachineFunction &MF; | |||
191 | ||||
192 | /// MBFI is only set if hotness is requested. | |||
193 | MachineBlockFrequencyInfo *MBFI; | |||
194 | ||||
195 | /// Compute hotness from IR value (currently assumed to be a block) if PGO is | |||
196 | /// available. | |||
197 | Optional<uint64_t> computeHotness(const MachineBasicBlock &MBB); | |||
198 | ||||
199 | /// Similar but use value from \p OptDiag and update hotness there. | |||
200 | void computeHotness(DiagnosticInfoMIROptimization &Remark); | |||
201 | ||||
202 | /// Only allow verbose messages if we know we're filtering by hotness | |||
203 | /// (BFI is only set in this case). | |||
204 | bool shouldEmitVerbose() { return MBFI != nullptr; } | |||
205 | }; | |||
206 | ||||
207 | /// The analysis pass | |||
208 | /// | |||
209 | /// Note that this pass shouldn't generally be marked as preserved by other | |||
210 | /// passes. It's holding onto BFI, so if the pass does not preserve BFI, BFI | |||
211 | /// could be freed. | |||
212 | class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass { | |||
213 | std::unique_ptr<MachineOptimizationRemarkEmitter> ORE; | |||
214 | ||||
215 | public: | |||
216 | MachineOptimizationRemarkEmitterPass(); | |||
217 | ||||
218 | bool runOnMachineFunction(MachineFunction &MF) override; | |||
219 | ||||
220 | void getAnalysisUsage(AnalysisUsage &AU) const override; | |||
221 | ||||
222 | MachineOptimizationRemarkEmitter &getORE() { | |||
223 | assert(ORE && "pass not run yet")((void)0); | |||
224 | return *ORE; | |||
225 | } | |||
226 | ||||
227 | static char ID; | |||
228 | }; | |||
229 | } | |||
230 | ||||
231 | #endif |