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/CodegenCleanup.h"
25 #include "polly/CodeGen/IslAst.h"
26 #include "polly/CodePreparation.h"
27 #include "polly/DeLICM.h"
28 #include "polly/DependenceInfo.h"
29 #include "polly/ForwardOpTree.h"
30 #include "polly/JSONExporter.h"
31 #include "polly/LinkAllPasses.h"
32 #include "polly/PolyhedralInfo.h"
33 #include "polly/PruneUnprofitable.h"
34 #include "polly/ScheduleOptimizer.h"
35 #include "polly/ScopDetection.h"
36 #include "polly/ScopInfo.h"
37 #include "polly/Simplify.h"
38 #include "polly/Support/DumpModulePass.h"
39 #include "llvm/Analysis/CFGPrinter.h"
40 #include "llvm/IR/LegacyPassManager.h"
41 #include "llvm/IR/Verifier.h"
42 #include "llvm/Passes/PassBuilder.h"
43 #include "llvm/Passes/PassPlugin.h"
44 #include "llvm/Support/CommandLine.h"
45 #include "llvm/Support/TargetSelect.h"
46 #include "llvm/Transforms/IPO.h"
47 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
48 
49 using namespace llvm;
50 using namespace polly;
51 
52 cl::OptionCategory PollyCategory("Polly Options",
53                                  "Configure the polly loop optimizer");
54 
55 static cl::opt<bool>
56     PollyEnabled("polly", cl::desc("Enable the polly optimizer (only at -O3)"),
57                  cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
58 
59 static cl::opt<bool> PollyDetectOnly(
60     "polly-only-scop-detection",
61     cl::desc("Only run scop detection, but no other optimizations"),
62     cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
63 
64 enum PassPositionChoice {
65   POSITION_EARLY,
66   POSITION_AFTER_LOOPOPT,
67   POSITION_BEFORE_VECTORIZER
68 };
69 
70 enum OptimizerChoice { OPTIMIZER_NONE, OPTIMIZER_ISL };
71 
72 static cl::opt<PassPositionChoice> PassPosition(
73     "polly-position", cl::desc("Where to run polly in the pass pipeline"),
74     cl::values(
75         clEnumValN(POSITION_EARLY, "early", "Before everything"),
76         clEnumValN(POSITION_AFTER_LOOPOPT, "after-loopopt",
77                    "After the loop optimizer (but within the inline cycle)"),
78         clEnumValN(POSITION_BEFORE_VECTORIZER, "before-vectorizer",
79                    "Right before the vectorizer")),
80     cl::Hidden, cl::init(POSITION_BEFORE_VECTORIZER), cl::ZeroOrMore,
81     cl::cat(PollyCategory));
82 
83 static cl::opt<OptimizerChoice>
84     Optimizer("polly-optimizer", cl::desc("Select the scheduling optimizer"),
85               cl::values(clEnumValN(OPTIMIZER_NONE, "none", "No optimizer"),
86                          clEnumValN(OPTIMIZER_ISL, "isl",
87                                     "The isl scheduling optimizer")),
88               cl::Hidden, cl::init(OPTIMIZER_ISL), cl::ZeroOrMore,
89               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(CODEGEN_FULL), cl::ZeroOrMore, cl::cat(PollyCategory));
98 
99 enum TargetChoice { TARGET_CPU, TARGET_GPU, TARGET_HYBRID };
100 static cl::opt<TargetChoice>
101     Target("polly-target", cl::desc("The hardware to target"),
102            cl::values(clEnumValN(TARGET_CPU, "cpu", "generate CPU code")
103 #ifdef GPU_CODEGEN
104                           ,
105                       clEnumValN(TARGET_GPU, "gpu", "generate GPU code"),
106                       clEnumValN(TARGET_HYBRID, "hybrid",
107                                  "generate GPU code (preferably) or CPU code")
108 #endif
109                           ),
110            cl::init(TARGET_CPU), cl::ZeroOrMore, cl::cat(PollyCategory));
111 
112 VectorizerChoice polly::PollyVectorizerChoice;
113 static cl::opt<polly::VectorizerChoice, true> Vectorizer(
114     "polly-vectorizer", cl::desc("Select the vectorization strategy"),
115     cl::values(
116         clEnumValN(polly::VECTORIZER_NONE, "none", "No Vectorization"),
117         clEnumValN(polly::VECTORIZER_POLLY, "polly",
118                    "Polly internal vectorizer"),
119         clEnumValN(
120             polly::VECTORIZER_STRIPMINE, "stripmine",
121             "Strip-mine outer loops for the loop-vectorizer to trigger")),
122     cl::location(PollyVectorizerChoice), cl::init(polly::VECTORIZER_NONE),
123     cl::ZeroOrMore, cl::cat(PollyCategory));
124 
125 static cl::opt<bool> ImportJScop(
126     "polly-import",
127     cl::desc("Import the polyhedral description of the detected Scops"),
128     cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
129 
130 static cl::opt<bool> FullyIndexedStaticExpansion(
131     "polly-enable-mse",
132     cl::desc("Fully expand the memory accesses of the detected Scops"),
133     cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
134 
135 static cl::opt<bool> ExportJScop(
136     "polly-export",
137     cl::desc("Export the polyhedral description of the detected Scops"),
138     cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
139 
140 static cl::opt<bool> DeadCodeElim("polly-run-dce",
141                                   cl::desc("Run the dead code elimination"),
142                                   cl::Hidden, cl::init(false), cl::ZeroOrMore,
143                                   cl::cat(PollyCategory));
144 
145 static cl::opt<bool> PollyViewer(
146     "polly-show",
147     cl::desc("Highlight the code regions that will be optimized in a "
148              "(CFG BBs and LLVM-IR instructions)"),
149     cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
150 
151 static cl::opt<bool> PollyOnlyViewer(
152     "polly-show-only",
153     cl::desc("Highlight the code regions that will be optimized in "
154              "a (CFG only BBs)"),
155     cl::init(false), cl::cat(PollyCategory));
156 
157 static cl::opt<bool>
158     PollyPrinter("polly-dot", cl::desc("Enable the Polly DOT printer in -O3"),
159                  cl::Hidden, cl::value_desc("Run the Polly DOT printer at -O3"),
160                  cl::init(false), cl::cat(PollyCategory));
161 
162 static cl::opt<bool> PollyOnlyPrinter(
163     "polly-dot-only",
164     cl::desc("Enable the Polly DOT printer in -O3 (no BB content)"), cl::Hidden,
165     cl::value_desc("Run the Polly DOT printer at -O3 (no BB content"),
166     cl::init(false), cl::cat(PollyCategory));
167 
168 static cl::opt<bool>
169     CFGPrinter("polly-view-cfg",
170                cl::desc("Show the Polly CFG right after code generation"),
171                cl::Hidden, cl::init(false), cl::cat(PollyCategory));
172 
173 static cl::opt<bool>
174     EnablePolyhedralInfo("polly-enable-polyhedralinfo",
175                          cl::desc("Enable polyhedral interface of Polly"),
176                          cl::Hidden, cl::init(false), cl::cat(PollyCategory));
177 
178 static cl::opt<bool>
179     EnableForwardOpTree("polly-enable-optree",
180                         cl::desc("Enable operand tree forwarding"), cl::Hidden,
181                         cl::init(true), cl::cat(PollyCategory));
182 
183 static cl::opt<bool>
184     DumpBefore("polly-dump-before",
185                cl::desc("Dump module before Polly transformations into a file "
186                         "suffixed with \"-before\""),
187                cl::init(false), cl::cat(PollyCategory));
188 
189 static cl::list<std::string> DumpBeforeFile(
190     "polly-dump-before-file",
191     cl::desc("Dump module before Polly transformations to the given file"),
192     cl::cat(PollyCategory));
193 
194 static cl::opt<bool>
195     DumpAfter("polly-dump-after",
196               cl::desc("Dump module after Polly transformations into a file "
197                        "suffixed with \"-after\""),
198               cl::init(false), cl::cat(PollyCategory));
199 
200 static cl::list<std::string> DumpAfterFile(
201     "polly-dump-after-file",
202     cl::desc("Dump module after Polly transformations to the given file"),
203     cl::ZeroOrMore, cl::cat(PollyCategory));
204 
205 static cl::opt<bool>
206     EnableDeLICM("polly-enable-delicm",
207                  cl::desc("Eliminate scalar loop carried dependences"),
208                  cl::Hidden, cl::init(true), cl::cat(PollyCategory));
209 
210 static cl::opt<bool>
211     EnableSimplify("polly-enable-simplify",
212                    cl::desc("Simplify SCoP after optimizations"),
213                    cl::init(true), cl::cat(PollyCategory));
214 
215 static cl::opt<bool> EnablePruneUnprofitable(
216     "polly-enable-prune-unprofitable",
217     cl::desc("Bail out on unprofitable SCoPs before rescheduling"), cl::Hidden,
218     cl::init(true), cl::cat(PollyCategory));
219 
220 namespace {
221 
222 /// Initialize Polly passes when library is loaded.
223 ///
224 /// We use the constructor of a statically declared object to initialize the
225 /// different Polly passes right after the Polly library is loaded. This ensures
226 /// that the Polly passes are available e.g. in the 'opt' tool.
227 class StaticInitializer {
228 public:
229   StaticInitializer() {
230     llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
231     polly::initializePollyPasses(Registry);
232   }
233 };
234 static StaticInitializer InitializeEverything;
235 } // end of anonymous namespace.
236 
237 namespace polly {
238 void initializePollyPasses(PassRegistry &Registry) {
239   initializeCodeGenerationPass(Registry);
240 
241 #ifdef GPU_CODEGEN
242   initializePPCGCodeGenerationPass(Registry);
243   initializeManagedMemoryRewritePassPass(Registry);
244   LLVMInitializeNVPTXTarget();
245   LLVMInitializeNVPTXTargetInfo();
246   LLVMInitializeNVPTXTargetMC();
247   LLVMInitializeNVPTXAsmPrinter();
248 #endif
249   initializeCodePreparationPass(Registry);
250   initializeDeadCodeElimPass(Registry);
251   initializeDependenceInfoPass(Registry);
252   initializeDependenceInfoWrapperPassPass(Registry);
253   initializeJSONExporterPass(Registry);
254   initializeJSONImporterPass(Registry);
255   initializeMaximalStaticExpanderPass(Registry);
256   initializeIslAstInfoWrapperPassPass(Registry);
257   initializeIslScheduleOptimizerWrapperPassPass(Registry);
258   initializePollyCanonicalizePass(Registry);
259   initializePolyhedralInfoPass(Registry);
260   initializeScopDetectionWrapperPassPass(Registry);
261   initializeScopInlinerPass(Registry);
262   initializeScopInfoRegionPassPass(Registry);
263   initializeScopInfoWrapperPassPass(Registry);
264   initializeRewriteByrefParamsPass(Registry);
265   initializeCodegenCleanupPass(Registry);
266   initializeFlattenSchedulePass(Registry);
267   initializeForwardOpTreeWrapperPassPass(Registry);
268   initializeDeLICMWrapperPassPass(Registry);
269   initializeSimplifyWrapperPassPass(Registry);
270   initializeDumpModulePass(Registry);
271   initializePruneUnprofitableWrapperPassPass(Registry);
272 }
273 
274 /// Register Polly passes such that they form a polyhedral optimizer.
275 ///
276 /// The individual Polly passes are registered in the pass manager such that
277 /// they form a full polyhedral optimizer. The flow of the optimizer starts with
278 /// a set of preparing transformations that canonicalize the LLVM-IR such that
279 /// the LLVM-IR is easier for us to understand and to optimizes. On the
280 /// canonicalized LLVM-IR we first run the ScopDetection pass, which detects
281 /// static control flow regions. Those regions are then translated by the
282 /// ScopInfo pass into a polyhedral representation. As a next step, a scheduling
283 /// optimizer is run on the polyhedral representation and finally the optimized
284 /// polyhedral representation is code generated back to LLVM-IR.
285 ///
286 /// Besides this core functionality, we optionally schedule passes that provide
287 /// a graphical view of the scops (Polly[Only]Viewer, Polly[Only]Printer), that
288 /// allow the export/import of the polyhedral representation
289 /// (JSCON[Exporter|Importer]) or that show the cfg after code generation.
290 ///
291 /// For certain parts of the Polly optimizer, several alternatives are provided:
292 ///
293 /// As scheduling optimizer we support the isl scheduling optimizer
294 /// (http://freecode.com/projects/isl).
295 /// It is also possible to run Polly with no optimizer. This mode is mainly
296 /// provided to analyze the run and compile time changes caused by the
297 /// scheduling optimizer.
298 ///
299 /// Polly supports the isl internal code generator.
300 void registerPollyPasses(llvm::legacy::PassManagerBase &PM) {
301   if (DumpBefore)
302     PM.add(polly::createDumpModulePass("-before", true));
303   for (auto &Filename : DumpBeforeFile)
304     PM.add(polly::createDumpModulePass(Filename, false));
305 
306   PM.add(polly::createScopDetectionWrapperPassPass());
307 
308   if (PollyDetectOnly)
309     return;
310 
311   if (PollyViewer)
312     PM.add(polly::createDOTViewerPass());
313   if (PollyOnlyViewer)
314     PM.add(polly::createDOTOnlyViewerPass());
315   if (PollyPrinter)
316     PM.add(polly::createDOTPrinterPass());
317   if (PollyOnlyPrinter)
318     PM.add(polly::createDOTOnlyPrinterPass());
319 
320   PM.add(polly::createScopInfoRegionPassPass());
321   if (EnablePolyhedralInfo)
322     PM.add(polly::createPolyhedralInfoPass());
323 
324   if (EnableSimplify)
325     PM.add(polly::createSimplifyWrapperPass(0));
326   if (EnableForwardOpTree)
327     PM.add(polly::createForwardOpTreeWrapperPass());
328   if (EnableDeLICM)
329     PM.add(polly::createDeLICMWrapperPass());
330   if (EnableSimplify)
331     PM.add(polly::createSimplifyWrapperPass(1));
332 
333   if (ImportJScop)
334     PM.add(polly::createJSONImporterPass());
335 
336   if (DeadCodeElim)
337     PM.add(polly::createDeadCodeElimPass());
338 
339   if (FullyIndexedStaticExpansion)
340     PM.add(polly::createMaximalStaticExpansionPass());
341 
342   if (EnablePruneUnprofitable)
343     PM.add(polly::createPruneUnprofitableWrapperPass());
344 
345 #ifdef GPU_CODEGEN
346   if (Target == TARGET_HYBRID)
347     PM.add(
348         polly::createPPCGCodeGenerationPass(GPUArchChoice, GPURuntimeChoice));
349 #endif
350   if (Target == TARGET_CPU || Target == TARGET_HYBRID)
351     switch (Optimizer) {
352     case OPTIMIZER_NONE:
353       break; /* Do nothing */
354 
355     case OPTIMIZER_ISL:
356       PM.add(polly::createIslScheduleOptimizerWrapperPass());
357       break;
358     }
359 
360   if (ExportJScop)
361     PM.add(polly::createJSONExporterPass());
362 
363   if (Target == TARGET_CPU || Target == TARGET_HYBRID)
364     switch (CodeGeneration) {
365     case CODEGEN_AST:
366       PM.add(polly::createIslAstInfoWrapperPassPass());
367       break;
368     case CODEGEN_FULL:
369       PM.add(polly::createCodeGenerationPass());
370       break;
371     case CODEGEN_NONE:
372       break;
373     }
374 #ifdef GPU_CODEGEN
375   else {
376     PM.add(
377         polly::createPPCGCodeGenerationPass(GPUArchChoice, GPURuntimeChoice));
378     PM.add(polly::createManagedMemoryRewritePassPass());
379   }
380 #endif
381 
382 #ifdef GPU_CODEGEN
383   if (Target == TARGET_HYBRID)
384     PM.add(polly::createManagedMemoryRewritePassPass(GPUArchChoice,
385                                                      GPURuntimeChoice));
386 #endif
387 
388   // FIXME: This dummy ModulePass keeps some programs from miscompiling,
389   // probably some not correctly preserved analyses. It acts as a barrier to
390   // force all analysis results to be recomputed.
391   PM.add(createBarrierNoopPass());
392 
393   if (DumpAfter)
394     PM.add(polly::createDumpModulePass("-after", true));
395   for (auto &Filename : DumpAfterFile)
396     PM.add(polly::createDumpModulePass(Filename, false));
397 
398   if (CFGPrinter)
399     PM.add(llvm::createCFGPrinterLegacyPassPass());
400 }
401 
402 static bool shouldEnablePolly() {
403   if (PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer)
404     PollyTrackFailures = true;
405 
406   if (PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer ||
407       ExportJScop || ImportJScop)
408     PollyEnabled = true;
409 
410   return PollyEnabled;
411 }
412 
413 static void
414 registerPollyEarlyAsPossiblePasses(const llvm::PassManagerBuilder &Builder,
415                                    llvm::legacy::PassManagerBase &PM) {
416   if (!polly::shouldEnablePolly())
417     return;
418 
419   if (PassPosition != POSITION_EARLY)
420     return;
421 
422   registerCanonicalicationPasses(PM);
423   polly::registerPollyPasses(PM);
424 }
425 
426 static void
427 registerPollyLoopOptimizerEndPasses(const llvm::PassManagerBuilder &Builder,
428                                     llvm::legacy::PassManagerBase &PM) {
429   if (!polly::shouldEnablePolly())
430     return;
431 
432   if (PassPosition != POSITION_AFTER_LOOPOPT)
433     return;
434 
435   PM.add(polly::createCodePreparationPass());
436   polly::registerPollyPasses(PM);
437   PM.add(createCodegenCleanupPass());
438 }
439 
440 static void
441 registerPollyScalarOptimizerLatePasses(const llvm::PassManagerBuilder &Builder,
442                                        llvm::legacy::PassManagerBase &PM) {
443   if (!polly::shouldEnablePolly())
444     return;
445 
446   if (PassPosition != POSITION_BEFORE_VECTORIZER)
447     return;
448 
449   PM.add(polly::createCodePreparationPass());
450   polly::registerPollyPasses(PM);
451   PM.add(createCodegenCleanupPass());
452 }
453 
454 static void buildDefaultPollyPipeline(FunctionPassManager &PM,
455                                       PassBuilder::OptimizationLevel Level) {
456   if (!polly::shouldEnablePolly())
457     return;
458   PassBuilder PB;
459   ScopPassManager SPM;
460 
461   PM.addPass(CodePreparationPass());
462 
463   // TODO add utility passes for the various command line options, once they're
464   // ported
465   if (DumpBefore)
466     report_fatal_error("Option -polly-dump-before not supported with NPM",
467                        false);
468   if (!DumpBeforeFile.empty())
469     report_fatal_error("Option -polly-dump-before-file not supported with NPM",
470                        false);
471 
472   if (PollyDetectOnly) {
473     // Don't add more passes other than the ScopPassManager's detection passes.
474     PM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
475     return;
476   }
477 
478   if (PollyViewer)
479     report_fatal_error("Option -polly-show not supported with NPM", false);
480   if (PollyOnlyViewer)
481     report_fatal_error("Option -polly-show-only not supported with NPM", false);
482   if (PollyPrinter)
483     report_fatal_error("Option -polly-dot not supported with NPM", false);
484   if (PollyOnlyPrinter)
485     report_fatal_error("Option -polly-dot-only not supported with NPM", false);
486   if (EnablePolyhedralInfo)
487     report_fatal_error(
488         "Option -polly-enable-polyhedralinfo not supported with NPM", false);
489 
490   if (EnableSimplify)
491     SPM.addPass(SimplifyPass(0));
492   if (EnableForwardOpTree)
493     SPM.addPass(ForwardOpTreePass());
494   if (EnableDeLICM)
495     SPM.addPass(DeLICMPass());
496   if (EnableSimplify)
497     SPM.addPass(SimplifyPass(1));
498 
499   if (ImportJScop)
500     SPM.addPass(JSONImportPass());
501 
502   if (DeadCodeElim)
503     report_fatal_error("Option -polly-run-dce not supported with NPM", false);
504 
505   if (FullyIndexedStaticExpansion)
506     report_fatal_error("Option -polly-enable-mse not supported with NPM",
507                        false);
508 
509   if (EnablePruneUnprofitable)
510     SPM.addPass(PruneUnprofitablePass());
511 
512   if (Target == TARGET_CPU || Target == TARGET_HYBRID) {
513     switch (Optimizer) {
514     case OPTIMIZER_NONE:
515       break; /* Do nothing */
516     case OPTIMIZER_ISL:
517       SPM.addPass(IslScheduleOptimizerPass());
518       break;
519     }
520   }
521 
522   if (ExportJScop)
523     report_fatal_error("Option -polly-export not supported with NPM", false);
524 
525   if (Target == TARGET_CPU || Target == TARGET_HYBRID) {
526     switch (CodeGeneration) {
527     case CODEGEN_AST:
528       SPM.addPass(
529           RequireAnalysisPass<IslAstAnalysis, Scop, ScopAnalysisManager,
530                               ScopStandardAnalysisResults &, SPMUpdater &>());
531       break;
532     case CODEGEN_FULL:
533       SPM.addPass(CodeGenerationPass());
534       break;
535     case CODEGEN_NONE:
536       break;
537     }
538 #ifdef GPU_CODEGEN
539   } else
540     report_fatal_error("Option -polly-target=gpu not supported for NPM", false);
541 #endif
542 
543 #ifdef GPU_CODEGEN
544   if (Target == TARGET_HYBRID)
545     report_fatal_error("Option -polly-target=hybrid not supported for NPM",
546                        false);
547 #endif
548 
549   PM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
550   PM.addPass(PB.buildFunctionSimplificationPipeline(
551       Level, ThinOrFullLTOPhase::None)); // Cleanup
552 
553   if (DumpAfter)
554     report_fatal_error("Option -polly-dump-after not supported with NPM",
555                        false);
556   if (!DumpAfterFile.empty())
557     report_fatal_error("Option -polly-dump-after-file not supported with NPM",
558                        false);
559 
560   if (CFGPrinter)
561     PM.addPass(llvm::CFGPrinterPass());
562 }
563 
564 /// Register Polly to be available as an optimizer
565 ///
566 ///
567 /// We can currently run Polly at three different points int the pass manager.
568 /// a) very early, b) after the canonicalizing loop transformations and c) right
569 /// before the vectorizer.
570 ///
571 /// The default is currently a), to register Polly such that it runs as early as
572 /// possible. This has several implications:
573 ///
574 ///   1) We need to schedule more canonicalization passes
575 ///
576 ///   As nothing is run before Polly, it is necessary to run a set of preparing
577 ///   transformations before Polly to canonicalize the LLVM-IR and to allow
578 ///   Polly to detect and understand the code.
579 ///
580 ///   2) LICM and LoopIdiom pass have not yet been run
581 ///
582 ///   Loop invariant code motion as well as the loop idiom recognition pass make
583 ///   it more difficult for Polly to transform code. LICM may introduce
584 ///   additional data dependences that are hard to eliminate and the loop idiom
585 ///   recognition pass may introduce calls to memset that we currently do not
586 ///   understand. By running Polly early enough (meaning before these passes) we
587 ///   avoid difficulties that may be introduced by these passes.
588 ///
589 ///   3) We get the full -O3 optimization sequence after Polly
590 ///
591 ///   The LLVM-IR that is generated by Polly has been optimized on a high level,
592 ///   but it may be rather inefficient on the lower/scalar level. By scheduling
593 ///   Polly before all other passes, we have the full sequence of -O3
594 ///   optimizations behind us, such that inefficiencies on the low level can
595 ///   be optimized away.
596 ///
597 /// We are currently evaluating the benefit or running Polly at position b) or
598 /// c). b) is likely too early as it interacts with the inliner. c) is nice
599 /// as everything is fully inlined and canonicalized, but we need to be able
600 /// to handle LICMed code to make it useful.
601 static llvm::RegisterStandardPasses RegisterPollyOptimizerEarly(
602     llvm::PassManagerBuilder::EP_ModuleOptimizerEarly,
603     registerPollyEarlyAsPossiblePasses);
604 
605 static llvm::RegisterStandardPasses
606     RegisterPollyOptimizerLoopEnd(llvm::PassManagerBuilder::EP_LoopOptimizerEnd,
607                                   registerPollyLoopOptimizerEndPasses);
608 
609 static llvm::RegisterStandardPasses RegisterPollyOptimizerScalarLate(
610     llvm::PassManagerBuilder::EP_VectorizerStart,
611     registerPollyScalarOptimizerLatePasses);
612 
613 static OwningScopAnalysisManagerFunctionProxy
614 createScopAnalyses(FunctionAnalysisManager &FAM,
615                    PassInstrumentationCallbacks *PIC) {
616   OwningScopAnalysisManagerFunctionProxy Proxy;
617 #define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
618   Proxy.getManager().registerPass([PIC] { return CREATE_PASS; });
619 #include "PollyPasses.def"
620 
621   Proxy.getManager().registerPass(
622       [&FAM] { return FunctionAnalysisManagerScopProxy(FAM); });
623   return Proxy;
624 }
625 
626 static void registerFunctionAnalyses(FunctionAnalysisManager &FAM,
627                                      PassInstrumentationCallbacks *PIC) {
628 
629 #define FUNCTION_ANALYSIS(NAME, CREATE_PASS)                                   \
630   FAM.registerPass([] { return CREATE_PASS; });
631 
632 #include "PollyPasses.def"
633 
634   FAM.registerPass([&FAM, PIC] { return createScopAnalyses(FAM, PIC); });
635 }
636 
637 static bool
638 parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM,
639                       ArrayRef<PassBuilder::PipelineElement> Pipeline) {
640   if (parseAnalysisUtilityPasses<OwningScopAnalysisManagerFunctionProxy>(
641           "polly-scop-analyses", Name, FPM))
642     return true;
643 
644 #define FUNCTION_ANALYSIS(NAME, CREATE_PASS)                                   \
645   if (parseAnalysisUtilityPasses<                                              \
646           std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name,      \
647                                                               FPM))            \
648     return true;
649 
650 #define FUNCTION_PASS(NAME, CREATE_PASS)                                       \
651   if (Name == NAME) {                                                          \
652     FPM.addPass(CREATE_PASS);                                                  \
653     return true;                                                               \
654   }
655 
656 #include "PollyPasses.def"
657   return false;
658 }
659 
660 static bool parseScopPass(StringRef Name, ScopPassManager &SPM,
661                           PassInstrumentationCallbacks *PIC) {
662 #define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
663   if (parseAnalysisUtilityPasses<                                              \
664           std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name,      \
665                                                               SPM))            \
666     return true;
667 
668 #define SCOP_PASS(NAME, CREATE_PASS)                                           \
669   if (Name == NAME) {                                                          \
670     SPM.addPass(CREATE_PASS);                                                  \
671     return true;                                                               \
672   }
673 
674 #include "PollyPasses.def"
675 
676   return false;
677 }
678 
679 static bool parseScopPipeline(StringRef Name, FunctionPassManager &FPM,
680                               PassInstrumentationCallbacks *PIC,
681                               ArrayRef<PassBuilder::PipelineElement> Pipeline) {
682   if (Name != "scop")
683     return false;
684   if (!Pipeline.empty()) {
685     ScopPassManager SPM;
686     for (const auto &E : Pipeline)
687       if (!parseScopPass(E.Name, SPM, PIC))
688         return false;
689     FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
690   }
691   return true;
692 }
693 
694 static bool isScopPassName(StringRef Name) {
695 #define SCOP_ANALYSIS(NAME, CREATE_PASS)                                       \
696   if (Name == "require<" NAME ">")                                             \
697     return true;                                                               \
698   if (Name == "invalidate<" NAME ">")                                          \
699     return true;
700 
701 #define SCOP_PASS(NAME, CREATE_PASS)                                           \
702   if (Name == NAME)                                                            \
703     return true;
704 
705 #include "PollyPasses.def"
706 
707   return false;
708 }
709 
710 static bool
711 parseTopLevelPipeline(ModulePassManager &MPM, PassInstrumentationCallbacks *PIC,
712                       ArrayRef<PassBuilder::PipelineElement> Pipeline,
713                       bool DebugLogging) {
714   std::vector<PassBuilder::PipelineElement> FullPipeline;
715   StringRef FirstName = Pipeline.front().Name;
716 
717   if (!isScopPassName(FirstName))
718     return false;
719 
720   FunctionPassManager FPM(DebugLogging);
721   ScopPassManager SPM(DebugLogging);
722 
723   for (auto &Element : Pipeline) {
724     auto &Name = Element.Name;
725     auto &InnerPipeline = Element.InnerPipeline;
726     if (!InnerPipeline.empty()) // Scop passes don't have inner pipelines
727       return false;
728     if (!parseScopPass(Name, SPM, PIC))
729       return false;
730   }
731 
732   FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM)));
733   MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
734 
735   return true;
736 }
737 
738 void registerPollyPasses(PassBuilder &PB) {
739   PassInstrumentationCallbacks *PIC = PB.getPassInstrumentationCallbacks();
740   PB.registerAnalysisRegistrationCallback([PIC](FunctionAnalysisManager &FAM) {
741     registerFunctionAnalyses(FAM, PIC);
742   });
743   PB.registerPipelineParsingCallback(parseFunctionPipeline);
744   PB.registerPipelineParsingCallback(
745       [PIC](StringRef Name, FunctionPassManager &FPM,
746             ArrayRef<PassBuilder::PipelineElement> Pipeline) -> bool {
747         return parseScopPipeline(Name, FPM, PIC, Pipeline);
748       });
749   PB.registerParseTopLevelPipelineCallback(
750       [PIC](ModulePassManager &MPM,
751             ArrayRef<PassBuilder::PipelineElement> Pipeline,
752             bool DebugLogging) -> bool {
753         return parseTopLevelPipeline(MPM, PIC, Pipeline, DebugLogging);
754       });
755 
756   if (PassPosition != POSITION_BEFORE_VECTORIZER)
757     report_fatal_error("Option -polly-position not supported with NPM", false);
758   PB.registerVectorizerStartEPCallback(buildDefaultPollyPipeline);
759 }
760 } // namespace polly
761 
762 llvm::PassPluginLibraryInfo getPollyPluginInfo() {
763   return {LLVM_PLUGIN_API_VERSION, "Polly", LLVM_VERSION_STRING,
764           polly::registerPollyPasses};
765 }
766