1 | //===------ RegisterPasses.cpp - Add the Polly Passes to default passes --===// |
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 file composes the individual LLVM-IR passes provided by Polly to a |
10 | // functional polyhedral optimizer. The polyhedral optimizer is automatically |
11 | // made available to LLVM based compilers by loading the Polly shared library |
12 | // into such a compiler. |
13 | // |
14 | // The Polly optimizer is made available by executing a static constructor that |
15 | // registers the individual Polly passes in the LLVM pass manager builder. The |
16 | // passes are registered such that the default behaviour of the compiler is not |
17 | // changed, but that the flag '-polly' provided at optimization level '-O3' |
18 | // enables additional polyhedral optimizations. |
19 | //===----------------------------------------------------------------------===// |
20 | |
21 | #include "polly/RegisterPasses.h" |
22 | #include "polly/Canonicalization.h" |
23 | #include "polly/CodeGen/CodeGeneration.h" |
24 | #include "polly/CodeGen/IslAst.h" |
25 | #include "polly/CodePreparation.h" |
26 | #include "polly/DeLICM.h" |
27 | #include "polly/DeadCodeElimination.h" |
28 | #include "polly/DependenceInfo.h" |
29 | #include "polly/ForwardOpTree.h" |
30 | #include "polly/JSONExporter.h" |
31 | #include "polly/LinkAllPasses.h" |
32 | #include "polly/MaximalStaticExpansion.h" |
33 | #include "polly/PolyhedralInfo.h" |
34 | #include "polly/PruneUnprofitable.h" |
35 | #include "polly/ScheduleOptimizer.h" |
36 | #include "polly/ScopDetection.h" |
37 | #include "polly/ScopGraphPrinter.h" |
38 | #include "polly/ScopInfo.h" |
39 | #include "polly/Simplify.h" |
40 | #include "polly/Support/DumpFunctionPass.h" |
41 | #include "polly/Support/DumpModulePass.h" |
42 | #include "llvm/Analysis/CFGPrinter.h" |
43 | #include "llvm/IR/LegacyPassManager.h" |
44 | #include "llvm/IR/PassManager.h" |
45 | #include "llvm/IR/Verifier.h" |
46 | #include "llvm/Passes/PassBuilder.h" |
47 | #include "llvm/Passes/PassPlugin.h" |
48 | #include "llvm/Support/CommandLine.h" |
49 | #include "llvm/Support/TargetSelect.h" |
50 | #include "llvm/Transforms/IPO.h" |
51 | |
52 | namespace cl = llvm::cl; |
53 | |
54 | using llvm::FunctionPassManager; |
55 | using llvm::OptimizationLevel; |
56 | using llvm::PassBuilder; |
57 | using llvm::PassInstrumentationCallbacks; |
58 | |
59 | cl::OptionCategory PollyCategory("Polly Options" , |
60 | "Configure the polly loop optimizer" ); |
61 | |
62 | namespace polly { |
63 | static cl::opt<bool> |
64 | PollyEnabled("polly" , |
65 | cl::desc("Enable the polly optimizer (with -O1, -O2 or -O3)" ), |
66 | cl::cat(PollyCategory)); |
67 | |
68 | static cl::opt<bool> PollyDetectOnly( |
69 | "polly-only-scop-detection" , |
70 | cl::desc("Only run scop detection, but no other optimizations" ), |
71 | cl::cat(PollyCategory)); |
72 | |
73 | enum PassPositionChoice { POSITION_EARLY, POSITION_BEFORE_VECTORIZER }; |
74 | |
75 | enum OptimizerChoice { OPTIMIZER_NONE, OPTIMIZER_ISL }; |
76 | |
77 | static cl::opt<PassPositionChoice> PassPosition( |
78 | "polly-position" , cl::desc("Where to run polly in the pass pipeline" ), |
79 | cl::values(clEnumValN(POSITION_EARLY, "early" , "Before everything" ), |
80 | clEnumValN(POSITION_BEFORE_VECTORIZER, "before-vectorizer" , |
81 | "Right before the vectorizer" )), |
82 | cl::Hidden, cl::init(Val: POSITION_BEFORE_VECTORIZER), cl::cat(PollyCategory)); |
83 | |
84 | static cl::opt<OptimizerChoice> |
85 | Optimizer("polly-optimizer" , cl::desc("Select the scheduling optimizer" ), |
86 | cl::values(clEnumValN(OPTIMIZER_NONE, "none" , "No optimizer" ), |
87 | clEnumValN(OPTIMIZER_ISL, "isl" , |
88 | "The isl scheduling optimizer" )), |
89 | cl::Hidden, cl::init(Val: OPTIMIZER_ISL), cl::cat(PollyCategory)); |
90 | |
91 | enum CodeGenChoice { CODEGEN_FULL, CODEGEN_AST, CODEGEN_NONE }; |
92 | static cl::opt<CodeGenChoice> CodeGeneration( |
93 | "polly-code-generation" , cl::desc("How much code-generation to perform" ), |
94 | cl::values(clEnumValN(CODEGEN_FULL, "full" , "AST and IR generation" ), |
95 | clEnumValN(CODEGEN_AST, "ast" , "Only AST generation" ), |
96 | clEnumValN(CODEGEN_NONE, "none" , "No code generation" )), |
97 | cl::Hidden, cl::init(Val: CODEGEN_FULL), cl::cat(PollyCategory)); |
98 | |
99 | VectorizerChoice PollyVectorizerChoice; |
100 | |
101 | static cl::opt<VectorizerChoice, true> Vectorizer( |
102 | "polly-vectorizer" , cl::desc("Select the vectorization strategy" ), |
103 | cl::values( |
104 | clEnumValN(VECTORIZER_NONE, "none" , "No Vectorization" ), |
105 | clEnumValN( |
106 | VECTORIZER_STRIPMINE, "stripmine" , |
107 | "Strip-mine outer loops for the loop-vectorizer to trigger" )), |
108 | cl::location(L&: PollyVectorizerChoice), cl::init(Val: VECTORIZER_NONE), |
109 | cl::cat(PollyCategory)); |
110 | |
111 | static cl::opt<bool> ImportJScop( |
112 | "polly-import" , |
113 | cl::desc("Import the polyhedral description of the detected Scops" ), |
114 | cl::Hidden, cl::cat(PollyCategory)); |
115 | |
116 | static cl::opt<bool> FullyIndexedStaticExpansion( |
117 | "polly-enable-mse" , |
118 | cl::desc("Fully expand the memory accesses of the detected Scops" ), |
119 | cl::Hidden, cl::cat(PollyCategory)); |
120 | |
121 | static cl::opt<bool> ExportJScop( |
122 | "polly-export" , |
123 | cl::desc("Export the polyhedral description of the detected Scops" ), |
124 | cl::Hidden, cl::cat(PollyCategory)); |
125 | |
126 | static cl::opt<bool> DeadCodeElim("polly-run-dce" , |
127 | cl::desc("Run the dead code elimination" ), |
128 | cl::Hidden, cl::cat(PollyCategory)); |
129 | |
130 | static cl::opt<bool> PollyViewer( |
131 | "polly-show" , |
132 | cl::desc("Highlight the code regions that will be optimized in a " |
133 | "(CFG BBs and LLVM-IR instructions)" ), |
134 | cl::cat(PollyCategory)); |
135 | |
136 | static cl::opt<bool> PollyOnlyViewer( |
137 | "polly-show-only" , |
138 | cl::desc("Highlight the code regions that will be optimized in " |
139 | "a (CFG only BBs)" ), |
140 | cl::init(Val: false), cl::cat(PollyCategory)); |
141 | |
142 | static cl::opt<bool> |
143 | PollyPrinter("polly-dot" , cl::desc("Enable the Polly DOT printer in -O3" ), |
144 | cl::Hidden, cl::value_desc("Run the Polly DOT printer at -O3" ), |
145 | cl::init(Val: false), cl::cat(PollyCategory)); |
146 | |
147 | static cl::opt<bool> PollyOnlyPrinter( |
148 | "polly-dot-only" , |
149 | cl::desc("Enable the Polly DOT printer in -O3 (no BB content)" ), cl::Hidden, |
150 | cl::value_desc("Run the Polly DOT printer at -O3 (no BB content" ), |
151 | cl::init(Val: false), cl::cat(PollyCategory)); |
152 | |
153 | static cl::opt<bool> |
154 | CFGPrinter("polly-view-cfg" , |
155 | cl::desc("Show the Polly CFG right after code generation" ), |
156 | cl::Hidden, cl::init(Val: false), cl::cat(PollyCategory)); |
157 | |
158 | static cl::opt<bool> |
159 | EnableForwardOpTree("polly-enable-optree" , |
160 | cl::desc("Enable operand tree forwarding" ), cl::Hidden, |
161 | cl::init(Val: true), cl::cat(PollyCategory)); |
162 | |
163 | static cl::opt<bool> |
164 | DumpBefore("polly-dump-before" , |
165 | cl::desc("Dump module before Polly transformations into a file " |
166 | "suffixed with \"-before\"" ), |
167 | cl::init(Val: false), cl::cat(PollyCategory)); |
168 | |
169 | static cl::list<std::string> DumpBeforeFile( |
170 | "polly-dump-before-file" , |
171 | cl::desc("Dump module before Polly transformations to the given file" ), |
172 | cl::cat(PollyCategory)); |
173 | |
174 | static cl::opt<bool> |
175 | DumpAfter("polly-dump-after" , |
176 | cl::desc("Dump module after Polly transformations into a file " |
177 | "suffixed with \"-after\"" ), |
178 | cl::init(Val: false), cl::cat(PollyCategory)); |
179 | |
180 | static cl::list<std::string> DumpAfterFile( |
181 | "polly-dump-after-file" , |
182 | cl::desc("Dump module after Polly transformations to the given file" ), |
183 | cl::cat(PollyCategory)); |
184 | |
185 | static cl::opt<bool> |
186 | EnableDeLICM("polly-enable-delicm" , |
187 | cl::desc("Eliminate scalar loop carried dependences" ), |
188 | cl::Hidden, cl::init(Val: true), cl::cat(PollyCategory)); |
189 | |
190 | static cl::opt<bool> |
191 | EnableSimplify("polly-enable-simplify" , |
192 | cl::desc("Simplify SCoP after optimizations" ), |
193 | cl::init(Val: true), cl::cat(PollyCategory)); |
194 | |
195 | static cl::opt<bool> EnablePruneUnprofitable( |
196 | "polly-enable-prune-unprofitable" , |
197 | cl::desc("Bail out on unprofitable SCoPs before rescheduling" ), cl::Hidden, |
198 | cl::init(Val: true), cl::cat(PollyCategory)); |
199 | |
200 | namespace { |
201 | |
202 | /// Initialize Polly passes when library is loaded. |
203 | /// |
204 | /// We use the constructor of a statically declared object to initialize the |
205 | /// different Polly passes right after the Polly library is loaded. This ensures |
206 | /// that the Polly passes are available e.g. in the 'opt' tool. |
207 | struct StaticInitializer { |
208 | StaticInitializer() { |
209 | llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry(); |
210 | polly::initializePollyPasses(Registry); |
211 | } |
212 | }; |
213 | static StaticInitializer InitializeEverything; |
214 | } // end of anonymous namespace. |
215 | |
216 | void initializePollyPasses(llvm::PassRegistry &Registry) { |
217 | initializeCodeGenerationPass(Registry); |
218 | |
219 | initializeCodePreparationPass(Registry); |
220 | initializeDeadCodeElimWrapperPassPass(Registry); |
221 | initializeDependenceInfoPass(Registry); |
222 | initializeDependenceInfoPrinterLegacyPassPass(Registry); |
223 | initializeDependenceInfoWrapperPassPass(Registry); |
224 | initializeDependenceInfoPrinterLegacyFunctionPassPass(Registry); |
225 | initializeJSONExporterPass(Registry); |
226 | initializeJSONImporterPass(Registry); |
227 | initializeJSONImporterPrinterLegacyPassPass(Registry); |
228 | initializeMaximalStaticExpanderWrapperPassPass(Registry); |
229 | initializeIslAstInfoWrapperPassPass(Registry); |
230 | initializeIslAstInfoPrinterLegacyPassPass(Registry); |
231 | initializeIslScheduleOptimizerWrapperPassPass(Registry); |
232 | initializeIslScheduleOptimizerPrinterLegacyPassPass(Registry); |
233 | initializePollyCanonicalizePass(Registry); |
234 | initializePolyhedralInfoPass(Registry); |
235 | initializePolyhedralInfoPrinterLegacyPassPass(Registry); |
236 | initializeScopDetectionWrapperPassPass(Registry); |
237 | initializeScopDetectionPrinterLegacyPassPass(Registry); |
238 | initializeScopInlinerPass(Registry); |
239 | initializeScopInfoRegionPassPass(Registry); |
240 | initializeScopInfoPrinterLegacyRegionPassPass(Registry); |
241 | initializeScopInfoWrapperPassPass(Registry); |
242 | initializeScopInfoPrinterLegacyFunctionPassPass(Registry); |
243 | initializeFlattenSchedulePass(Registry); |
244 | initializeFlattenSchedulePrinterLegacyPassPass(Registry); |
245 | initializeForwardOpTreeWrapperPassPass(Registry); |
246 | initializeForwardOpTreePrinterLegacyPassPass(Registry); |
247 | initializeDeLICMWrapperPassPass(Registry); |
248 | initializeDeLICMPrinterLegacyPassPass(Registry); |
249 | initializeSimplifyWrapperPassPass(Registry); |
250 | initializeSimplifyPrinterLegacyPassPass(Registry); |
251 | initializeDumpModuleWrapperPassPass(Registry); |
252 | initializePruneUnprofitableWrapperPassPass(Registry); |
253 | } |
254 | |
255 | static bool shouldEnablePollyForOptimization() { return PollyEnabled; } |
256 | |
257 | static bool shouldEnablePollyForDiagnostic() { |
258 | // FIXME: PollyTrackFailures is user-controlled, should not be set |
259 | // programmatically. |
260 | if (PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer) |
261 | PollyTrackFailures = true; |
262 | |
263 | return PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer || |
264 | ExportJScop; |
265 | } |
266 | |
267 | /// Register Polly passes such that they form a polyhedral optimizer. |
268 | /// |
269 | /// The individual Polly passes are registered in the pass manager such that |
270 | /// they form a full polyhedral optimizer. The flow of the optimizer starts with |
271 | /// a set of preparing transformations that canonicalize the LLVM-IR such that |
272 | /// the LLVM-IR is easier for us to understand and to optimizes. On the |
273 | /// canonicalized LLVM-IR we first run the ScopDetection pass, which detects |
274 | /// static control flow regions. Those regions are then translated by the |
275 | /// ScopInfo pass into a polyhedral representation. As a next step, a scheduling |
276 | /// optimizer is run on the polyhedral representation and finally the optimized |
277 | /// polyhedral representation is code generated back to LLVM-IR. |
278 | /// |
279 | /// Besides this core functionality, we optionally schedule passes that provide |
280 | /// a graphical view of the scops (Polly[Only]Viewer, Polly[Only]Printer), that |
281 | /// allow the export/import of the polyhedral representation |
282 | /// (JSCON[Exporter|Importer]) or that show the cfg after code generation. |
283 | /// |
284 | /// For certain parts of the Polly optimizer, several alternatives are provided: |
285 | /// |
286 | /// As scheduling optimizer we support the isl scheduling optimizer |
287 | /// (http://freecode.com/projects/isl). |
288 | /// It is also possible to run Polly with no optimizer. This mode is mainly |
289 | /// provided to analyze the run and compile time changes caused by the |
290 | /// scheduling optimizer. |
291 | /// |
292 | /// Polly supports the isl internal code generator. |
293 | |
294 | /// Add the pass sequence required for Polly to the New Pass Manager. |
295 | /// |
296 | /// @param PM The pass manager itself. |
297 | /// @param Level The optimization level. Used for the cleanup of Polly's |
298 | /// output. |
299 | /// @param EnableForOpt Whether to add Polly IR transformations. If False, only |
300 | /// the analysis passes are added, skipping Polly itself. |
301 | /// The IR may still be modified. |
302 | static void buildCommonPollyPipeline(FunctionPassManager &PM, |
303 | OptimizationLevel Level, |
304 | bool EnableForOpt) { |
305 | PassBuilder PB; |
306 | ScopPassManager SPM; |
307 | |
308 | PM.addPass(Pass: CodePreparationPass()); |
309 | |
310 | // TODO add utility passes for the various command line options, once they're |
311 | // ported |
312 | |
313 | if (PollyDetectOnly) { |
314 | // Don't add more passes other than the ScopPassManager's detection passes. |
315 | PM.addPass(Pass: createFunctionToScopPassAdaptor(Pass: std::move(SPM))); |
316 | return; |
317 | } |
318 | |
319 | if (PollyViewer) |
320 | PM.addPass(Pass: ScopViewer()); |
321 | if (PollyOnlyViewer) |
322 | PM.addPass(Pass: ScopOnlyViewer()); |
323 | if (PollyPrinter) |
324 | PM.addPass(Pass: ScopPrinter()); |
325 | if (PollyOnlyPrinter) |
326 | PM.addPass(Pass: ScopOnlyPrinter()); |
327 | if (EnableSimplify) |
328 | SPM.addPass(Pass: SimplifyPass(0)); |
329 | if (EnableForwardOpTree) |
330 | SPM.addPass(Pass: ForwardOpTreePass()); |
331 | if (EnableDeLICM) |
332 | SPM.addPass(Pass: DeLICMPass()); |
333 | if (EnableSimplify) |
334 | SPM.addPass(Pass: SimplifyPass(1)); |
335 | |
336 | if (ImportJScop) |
337 | SPM.addPass(Pass: JSONImportPass()); |
338 | |
339 | if (DeadCodeElim) |
340 | SPM.addPass(Pass: DeadCodeElimPass()); |
341 | |
342 | if (FullyIndexedStaticExpansion) |
343 | SPM.addPass(Pass: MaximalStaticExpansionPass()); |
344 | |
345 | if (EnablePruneUnprofitable) |
346 | SPM.addPass(Pass: PruneUnprofitablePass()); |
347 | |
348 | switch (Optimizer) { |
349 | case OPTIMIZER_NONE: |
350 | break; /* Do nothing */ |
351 | case OPTIMIZER_ISL: |
352 | SPM.addPass(Pass: IslScheduleOptimizerPass()); |
353 | break; |
354 | } |
355 | |
356 | if (ExportJScop) |
357 | SPM.addPass(Pass: JSONExportPass()); |
358 | |
359 | if (!EnableForOpt) |
360 | return; |
361 | |
362 | switch (CodeGeneration) { |
363 | case CODEGEN_AST: |
364 | SPM.addPass( |
365 | Pass: llvm::RequireAnalysisPass<IslAstAnalysis, Scop, ScopAnalysisManager, |
366 | ScopStandardAnalysisResults &, |
367 | SPMUpdater &>()); |
368 | break; |
369 | case CODEGEN_FULL: |
370 | SPM.addPass(Pass: CodeGenerationPass()); |
371 | break; |
372 | case CODEGEN_NONE: |
373 | break; |
374 | } |
375 | |
376 | PM.addPass(Pass: createFunctionToScopPassAdaptor(Pass: std::move(SPM))); |
377 | PM.addPass(Pass: PB.buildFunctionSimplificationPipeline( |
378 | Level, Phase: llvm::ThinOrFullLTOPhase::None)); // Cleanup |
379 | |
380 | if (CFGPrinter) |
381 | PM.addPass(Pass: llvm::CFGPrinterPass()); |
382 | } |
383 | |
384 | static void buildEarlyPollyPipeline(llvm::ModulePassManager &MPM, |
385 | llvm::OptimizationLevel Level) { |
386 | bool EnableForOpt = |
387 | shouldEnablePollyForOptimization() && Level.isOptimizingForSpeed(); |
388 | if (!shouldEnablePollyForDiagnostic() && !EnableForOpt) |
389 | return; |
390 | |
391 | FunctionPassManager FPM = buildCanonicalicationPassesForNPM(MPM, Level); |
392 | |
393 | if (DumpBefore || !DumpBeforeFile.empty()) { |
394 | MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM))); |
395 | |
396 | if (DumpBefore) |
397 | MPM.addPass(Pass: DumpModulePass("-before" , true)); |
398 | for (auto &Filename : DumpBeforeFile) |
399 | MPM.addPass(Pass: DumpModulePass(Filename, false)); |
400 | |
401 | FPM = FunctionPassManager(); |
402 | } |
403 | |
404 | buildCommonPollyPipeline(PM&: FPM, Level, EnableForOpt); |
405 | MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM))); |
406 | |
407 | if (DumpAfter) |
408 | MPM.addPass(Pass: DumpModulePass("-after" , true)); |
409 | for (auto &Filename : DumpAfterFile) |
410 | MPM.addPass(Pass: DumpModulePass(Filename, false)); |
411 | } |
412 | |
413 | static void buildLatePollyPipeline(FunctionPassManager &PM, |
414 | llvm::OptimizationLevel Level) { |
415 | bool EnableForOpt = |
416 | shouldEnablePollyForOptimization() && Level.isOptimizingForSpeed(); |
417 | if (!shouldEnablePollyForDiagnostic() && !EnableForOpt) |
418 | return; |
419 | |
420 | if (DumpBefore) |
421 | PM.addPass(Pass: DumpFunctionPass("-before" )); |
422 | if (!DumpBeforeFile.empty()) |
423 | llvm::report_fatal_error( |
424 | reason: "Option -polly-dump-before-file at -polly-position=late " |
425 | "not supported with NPM" , |
426 | gen_crash_diag: false); |
427 | |
428 | buildCommonPollyPipeline(PM, Level, EnableForOpt); |
429 | |
430 | if (DumpAfter) |
431 | PM.addPass(Pass: DumpFunctionPass("-after" )); |
432 | if (!DumpAfterFile.empty()) |
433 | llvm::report_fatal_error( |
434 | reason: "Option -polly-dump-after-file at -polly-position=late " |
435 | "not supported with NPM" , |
436 | gen_crash_diag: false); |
437 | } |
438 | |
439 | static OwningScopAnalysisManagerFunctionProxy |
440 | createScopAnalyses(FunctionAnalysisManager &FAM, |
441 | PassInstrumentationCallbacks *PIC) { |
442 | OwningScopAnalysisManagerFunctionProxy Proxy; |
443 | #define SCOP_ANALYSIS(NAME, CREATE_PASS) \ |
444 | Proxy.getManager().registerPass([PIC] { \ |
445 | (void)PIC; \ |
446 | return CREATE_PASS; \ |
447 | }); |
448 | #include "PollyPasses.def" |
449 | |
450 | Proxy.getManager().registerPass( |
451 | PassBuilder: [&FAM] { return FunctionAnalysisManagerScopProxy(FAM); }); |
452 | return Proxy; |
453 | } |
454 | |
455 | static void registerFunctionAnalyses(FunctionAnalysisManager &FAM, |
456 | PassInstrumentationCallbacks *PIC) { |
457 | |
458 | #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ |
459 | FAM.registerPass([] { return CREATE_PASS; }); |
460 | |
461 | #include "PollyPasses.def" |
462 | |
463 | FAM.registerPass(PassBuilder: [&FAM, PIC] { return createScopAnalyses(FAM, PIC); }); |
464 | } |
465 | |
466 | static bool |
467 | parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM, |
468 | ArrayRef<PassBuilder::PipelineElement> Pipeline) { |
469 | if (llvm::parseAnalysisUtilityPasses<OwningScopAnalysisManagerFunctionProxy>( |
470 | AnalysisName: "polly-scop-analyses" , PipelineName: Name, PM&: FPM)) |
471 | return true; |
472 | |
473 | #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ |
474 | if (llvm::parseAnalysisUtilityPasses< \ |
475 | std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name, \ |
476 | FPM)) \ |
477 | return true; |
478 | |
479 | #define FUNCTION_PASS(NAME, CREATE_PASS) \ |
480 | if (Name == NAME) { \ |
481 | FPM.addPass(CREATE_PASS); \ |
482 | return true; \ |
483 | } |
484 | |
485 | #include "PollyPasses.def" |
486 | return false; |
487 | } |
488 | |
489 | static bool parseScopPass(StringRef Name, ScopPassManager &SPM, |
490 | PassInstrumentationCallbacks *PIC) { |
491 | #define SCOP_ANALYSIS(NAME, CREATE_PASS) \ |
492 | if (llvm::parseAnalysisUtilityPasses< \ |
493 | std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name, \ |
494 | SPM)) \ |
495 | return true; |
496 | |
497 | #define SCOP_PASS(NAME, CREATE_PASS) \ |
498 | if (Name == NAME) { \ |
499 | SPM.addPass(CREATE_PASS); \ |
500 | return true; \ |
501 | } |
502 | |
503 | #include "PollyPasses.def" |
504 | |
505 | return false; |
506 | } |
507 | |
508 | static bool parseScopPipeline(StringRef Name, FunctionPassManager &FPM, |
509 | PassInstrumentationCallbacks *PIC, |
510 | ArrayRef<PassBuilder::PipelineElement> Pipeline) { |
511 | if (Name != "scop" ) |
512 | return false; |
513 | if (!Pipeline.empty()) { |
514 | ScopPassManager SPM; |
515 | for (const auto &E : Pipeline) |
516 | if (!parseScopPass(Name: E.Name, SPM, PIC)) |
517 | return false; |
518 | FPM.addPass(Pass: createFunctionToScopPassAdaptor(Pass: std::move(SPM))); |
519 | } |
520 | return true; |
521 | } |
522 | |
523 | static bool isScopPassName(StringRef Name) { |
524 | #define SCOP_ANALYSIS(NAME, CREATE_PASS) \ |
525 | if (Name == "require<" NAME ">") \ |
526 | return true; \ |
527 | if (Name == "invalidate<" NAME ">") \ |
528 | return true; |
529 | |
530 | #define SCOP_PASS(NAME, CREATE_PASS) \ |
531 | if (Name == NAME) \ |
532 | return true; |
533 | |
534 | #include "PollyPasses.def" |
535 | |
536 | return false; |
537 | } |
538 | |
539 | static bool |
540 | parseTopLevelPipeline(llvm::ModulePassManager &MPM, |
541 | PassInstrumentationCallbacks *PIC, |
542 | ArrayRef<PassBuilder::PipelineElement> Pipeline) { |
543 | std::vector<PassBuilder::PipelineElement> FullPipeline; |
544 | StringRef FirstName = Pipeline.front().Name; |
545 | |
546 | if (!isScopPassName(Name: FirstName)) |
547 | return false; |
548 | |
549 | FunctionPassManager FPM; |
550 | ScopPassManager SPM; |
551 | |
552 | for (auto &Element : Pipeline) { |
553 | auto &Name = Element.Name; |
554 | auto &InnerPipeline = Element.InnerPipeline; |
555 | if (!InnerPipeline.empty()) // Scop passes don't have inner pipelines |
556 | return false; |
557 | if (!parseScopPass(Name, SPM, PIC)) |
558 | return false; |
559 | } |
560 | |
561 | FPM.addPass(Pass: createFunctionToScopPassAdaptor(Pass: std::move(SPM))); |
562 | MPM.addPass(Pass: createModuleToFunctionPassAdaptor(Pass: std::move(FPM))); |
563 | |
564 | return true; |
565 | } |
566 | |
567 | /// Register Polly to be available as an optimizer |
568 | /// |
569 | /// |
570 | /// We can currently run Polly at two different points int the pass manager. |
571 | /// a) very early, b) right before the vectorizer. |
572 | /// |
573 | /// The default is currently a), to register Polly such that it runs as early as |
574 | /// possible. This has several implications: |
575 | /// |
576 | /// 1) We need to schedule more canonicalization passes |
577 | /// |
578 | /// As nothing is run before Polly, it is necessary to run a set of preparing |
579 | /// transformations before Polly to canonicalize the LLVM-IR and to allow |
580 | /// Polly to detect and understand the code. |
581 | /// |
582 | /// 2) We get the full -O3 optimization sequence after Polly |
583 | /// |
584 | /// The LLVM-IR that is generated by Polly has been optimized on a high level, |
585 | /// but it may be rather inefficient on the lower/scalar level. By scheduling |
586 | /// Polly before all other passes, we have the full sequence of -O3 |
587 | /// optimizations behind us, such that inefficiencies on the low level can |
588 | /// be optimized away. |
589 | /// |
590 | /// We are currently evaluating the benefit or running Polly at b). b) is nice |
591 | /// as everything is fully inlined and canonicalized, but we need to be able to |
592 | /// handle LICMed code to make it useful. |
593 | void registerPollyPasses(PassBuilder &PB) { |
594 | PassInstrumentationCallbacks *PIC = PB.getPassInstrumentationCallbacks(); |
595 | PB.registerAnalysisRegistrationCallback(C: [PIC](FunctionAnalysisManager &FAM) { |
596 | registerFunctionAnalyses(FAM, PIC); |
597 | }); |
598 | PB.registerPipelineParsingCallback(C: parseFunctionPipeline); |
599 | PB.registerPipelineParsingCallback( |
600 | C: [PIC](StringRef Name, FunctionPassManager &FPM, |
601 | ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool { |
602 | return parseScopPipeline(Name, FPM, PIC, Pipeline); |
603 | }); |
604 | PB.registerParseTopLevelPipelineCallback( |
605 | C: [PIC](llvm::ModulePassManager &MPM, |
606 | ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool { |
607 | return parseTopLevelPipeline(MPM, PIC, Pipeline); |
608 | }); |
609 | |
610 | switch (PassPosition) { |
611 | case POSITION_EARLY: |
612 | PB.registerPipelineStartEPCallback(C: buildEarlyPollyPipeline); |
613 | break; |
614 | case POSITION_BEFORE_VECTORIZER: |
615 | PB.registerVectorizerStartEPCallback(C: buildLatePollyPipeline); |
616 | break; |
617 | } |
618 | } |
619 | } // namespace polly |
620 | |
621 | llvm::PassPluginLibraryInfo getPollyPluginInfo() { |
622 | return {LLVM_PLUGIN_API_VERSION, .PluginName: "Polly" , LLVM_VERSION_STRING, |
623 | .RegisterPassBuilderCallbacks: polly::registerPollyPasses}; |
624 | } |
625 | |