/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/Support/RegisterPasses.cpp
Line | Count | Source (jump to first uncovered line) |
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/DependenceInfo.h" |
28 | | #include "polly/ForwardOpTree.h" |
29 | | #include "polly/JSONExporter.h" |
30 | | #include "polly/LinkAllPasses.h" |
31 | | #include "polly/PolyhedralInfo.h" |
32 | | #include "polly/ScopDetection.h" |
33 | | #include "polly/ScopInfo.h" |
34 | | #include "polly/Simplify.h" |
35 | | #include "polly/Support/DumpModulePass.h" |
36 | | #include "llvm/Analysis/CFGPrinter.h" |
37 | | #include "llvm/IR/LegacyPassManager.h" |
38 | | #include "llvm/IR/Verifier.h" |
39 | | #include "llvm/Passes/PassBuilder.h" |
40 | | #include "llvm/Passes/PassPlugin.h" |
41 | | #include "llvm/Support/TargetSelect.h" |
42 | | #include "llvm/Transforms/IPO.h" |
43 | | #include "llvm/Transforms/IPO/PassManagerBuilder.h" |
44 | | |
45 | | using namespace llvm; |
46 | | using namespace polly; |
47 | | |
48 | | cl::OptionCategory PollyCategory("Polly Options", |
49 | | "Configure the polly loop optimizer"); |
50 | | |
51 | | static cl::opt<bool> |
52 | | PollyEnabled("polly", cl::desc("Enable the polly optimizer (only at -O3)"), |
53 | | cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); |
54 | | |
55 | | static cl::opt<bool> PollyDetectOnly( |
56 | | "polly-only-scop-detection", |
57 | | cl::desc("Only run scop detection, but no other optimizations"), |
58 | | cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); |
59 | | |
60 | | enum PassPositionChoice { |
61 | | POSITION_EARLY, |
62 | | POSITION_AFTER_LOOPOPT, |
63 | | POSITION_BEFORE_VECTORIZER |
64 | | }; |
65 | | |
66 | | enum OptimizerChoice { OPTIMIZER_NONE, OPTIMIZER_ISL }; |
67 | | |
68 | | static cl::opt<PassPositionChoice> PassPosition( |
69 | | "polly-position", cl::desc("Where to run polly in the pass pipeline"), |
70 | | cl::values( |
71 | | clEnumValN(POSITION_EARLY, "early", "Before everything"), |
72 | | clEnumValN(POSITION_AFTER_LOOPOPT, "after-loopopt", |
73 | | "After the loop optimizer (but within the inline cycle)"), |
74 | | clEnumValN(POSITION_BEFORE_VECTORIZER, "before-vectorizer", |
75 | | "Right before the vectorizer")), |
76 | | cl::Hidden, cl::init(POSITION_BEFORE_VECTORIZER), cl::ZeroOrMore, |
77 | | cl::cat(PollyCategory)); |
78 | | |
79 | | static cl::opt<OptimizerChoice> |
80 | | Optimizer("polly-optimizer", cl::desc("Select the scheduling optimizer"), |
81 | | cl::values(clEnumValN(OPTIMIZER_NONE, "none", "No optimizer"), |
82 | | clEnumValN(OPTIMIZER_ISL, "isl", |
83 | | "The isl scheduling optimizer")), |
84 | | cl::Hidden, cl::init(OPTIMIZER_ISL), cl::ZeroOrMore, |
85 | | cl::cat(PollyCategory)); |
86 | | |
87 | | enum CodeGenChoice { CODEGEN_FULL, CODEGEN_AST, CODEGEN_NONE }; |
88 | | static cl::opt<CodeGenChoice> CodeGeneration( |
89 | | "polly-code-generation", cl::desc("How much code-generation to perform"), |
90 | | cl::values(clEnumValN(CODEGEN_FULL, "full", "AST and IR generation"), |
91 | | clEnumValN(CODEGEN_AST, "ast", "Only AST generation"), |
92 | | clEnumValN(CODEGEN_NONE, "none", "No code generation")), |
93 | | cl::Hidden, cl::init(CODEGEN_FULL), cl::ZeroOrMore, cl::cat(PollyCategory)); |
94 | | |
95 | | enum TargetChoice { TARGET_CPU, TARGET_GPU, TARGET_HYBRID }; |
96 | | static cl::opt<TargetChoice> |
97 | | Target("polly-target", cl::desc("The hardware to target"), |
98 | | cl::values(clEnumValN(TARGET_CPU, "cpu", "generate CPU code") |
99 | | #ifdef GPU_CODEGEN |
100 | | , |
101 | | clEnumValN(TARGET_GPU, "gpu", "generate GPU code"), |
102 | | clEnumValN(TARGET_HYBRID, "hybrid", |
103 | | "generate GPU code (preferably) or CPU code") |
104 | | #endif |
105 | | ), |
106 | | cl::init(TARGET_CPU), cl::ZeroOrMore, cl::cat(PollyCategory)); |
107 | | |
108 | | #ifdef GPU_CODEGEN |
109 | | static cl::opt<GPURuntime> GPURuntimeChoice( |
110 | | "polly-gpu-runtime", cl::desc("The GPU Runtime API to target"), |
111 | | cl::values(clEnumValN(GPURuntime::CUDA, "libcudart", |
112 | | "use the CUDA Runtime API"), |
113 | | clEnumValN(GPURuntime::OpenCL, "libopencl", |
114 | | "use the OpenCL Runtime API")), |
115 | | cl::init(GPURuntime::CUDA), cl::ZeroOrMore, cl::cat(PollyCategory)); |
116 | | |
117 | | static cl::opt<GPUArch> |
118 | | GPUArchChoice("polly-gpu-arch", cl::desc("The GPU Architecture to target"), |
119 | | cl::values(clEnumValN(GPUArch::NVPTX64, "nvptx64", |
120 | | "target NVIDIA 64-bit architecture"), |
121 | | clEnumValN(GPUArch::SPIR32, "spir32", |
122 | | "target SPIR 32-bit architecture"), |
123 | | clEnumValN(GPUArch::SPIR64, "spir64", |
124 | | "target SPIR 64-bit architecture")), |
125 | | cl::init(GPUArch::NVPTX64), cl::ZeroOrMore, |
126 | | cl::cat(PollyCategory)); |
127 | | #endif |
128 | | |
129 | | VectorizerChoice polly::PollyVectorizerChoice; |
130 | | static cl::opt<polly::VectorizerChoice, true> Vectorizer( |
131 | | "polly-vectorizer", cl::desc("Select the vectorization strategy"), |
132 | | cl::values( |
133 | | clEnumValN(polly::VECTORIZER_NONE, "none", "No Vectorization"), |
134 | | clEnumValN(polly::VECTORIZER_POLLY, "polly", |
135 | | "Polly internal vectorizer"), |
136 | | clEnumValN( |
137 | | polly::VECTORIZER_STRIPMINE, "stripmine", |
138 | | "Strip-mine outer loops for the loop-vectorizer to trigger")), |
139 | | cl::location(PollyVectorizerChoice), cl::init(polly::VECTORIZER_NONE), |
140 | | cl::ZeroOrMore, cl::cat(PollyCategory)); |
141 | | |
142 | | static cl::opt<bool> ImportJScop( |
143 | | "polly-import", |
144 | | cl::desc("Import the polyhedral description of the detected Scops"), |
145 | | cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); |
146 | | |
147 | | static cl::opt<bool> FullyIndexedStaticExpansion( |
148 | | "polly-enable-mse", |
149 | | cl::desc("Fully expand the memory accesses of the detected Scops"), |
150 | | cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); |
151 | | |
152 | | static cl::opt<bool> ExportJScop( |
153 | | "polly-export", |
154 | | cl::desc("Export the polyhedral description of the detected Scops"), |
155 | | cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); |
156 | | |
157 | | static cl::opt<bool> DeadCodeElim("polly-run-dce", |
158 | | cl::desc("Run the dead code elimination"), |
159 | | cl::Hidden, cl::init(false), cl::ZeroOrMore, |
160 | | cl::cat(PollyCategory)); |
161 | | |
162 | | static cl::opt<bool> PollyViewer( |
163 | | "polly-show", |
164 | | cl::desc("Highlight the code regions that will be optimized in a " |
165 | | "(CFG BBs and LLVM-IR instructions)"), |
166 | | cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); |
167 | | |
168 | | static cl::opt<bool> PollyOnlyViewer( |
169 | | "polly-show-only", |
170 | | cl::desc("Highlight the code regions that will be optimized in " |
171 | | "a (CFG only BBs)"), |
172 | | cl::init(false), cl::cat(PollyCategory)); |
173 | | |
174 | | static cl::opt<bool> |
175 | | PollyPrinter("polly-dot", cl::desc("Enable the Polly DOT printer in -O3"), |
176 | | cl::Hidden, cl::value_desc("Run the Polly DOT printer at -O3"), |
177 | | cl::init(false), cl::cat(PollyCategory)); |
178 | | |
179 | | static cl::opt<bool> PollyOnlyPrinter( |
180 | | "polly-dot-only", |
181 | | cl::desc("Enable the Polly DOT printer in -O3 (no BB content)"), cl::Hidden, |
182 | | cl::value_desc("Run the Polly DOT printer at -O3 (no BB content"), |
183 | | cl::init(false), cl::cat(PollyCategory)); |
184 | | |
185 | | static cl::opt<bool> |
186 | | CFGPrinter("polly-view-cfg", |
187 | | cl::desc("Show the Polly CFG right after code generation"), |
188 | | cl::Hidden, cl::init(false), cl::cat(PollyCategory)); |
189 | | |
190 | | static cl::opt<bool> |
191 | | EnablePolyhedralInfo("polly-enable-polyhedralinfo", |
192 | | cl::desc("Enable polyhedral interface of Polly"), |
193 | | cl::Hidden, cl::init(false), cl::cat(PollyCategory)); |
194 | | |
195 | | static cl::opt<bool> |
196 | | EnableForwardOpTree("polly-enable-optree", |
197 | | cl::desc("Enable operand tree forwarding"), cl::Hidden, |
198 | | cl::init(true), cl::cat(PollyCategory)); |
199 | | |
200 | | static cl::opt<bool> |
201 | | DumpBefore("polly-dump-before", |
202 | | cl::desc("Dump module before Polly transformations into a file " |
203 | | "suffixed with \"-before\""), |
204 | | cl::init(false), cl::cat(PollyCategory)); |
205 | | |
206 | | static cl::list<std::string> DumpBeforeFile( |
207 | | "polly-dump-before-file", |
208 | | cl::desc("Dump module before Polly transformations to the given file"), |
209 | | cl::cat(PollyCategory)); |
210 | | |
211 | | static cl::opt<bool> |
212 | | DumpAfter("polly-dump-after", |
213 | | cl::desc("Dump module after Polly transformations into a file " |
214 | | "suffixed with \"-after\""), |
215 | | cl::init(false), cl::cat(PollyCategory)); |
216 | | |
217 | | static cl::list<std::string> DumpAfterFile( |
218 | | "polly-dump-after-file", |
219 | | cl::desc("Dump module after Polly transformations to the given file"), |
220 | | cl::ZeroOrMore, cl::cat(PollyCategory)); |
221 | | |
222 | | static cl::opt<bool> |
223 | | EnableDeLICM("polly-enable-delicm", |
224 | | cl::desc("Eliminate scalar loop carried dependences"), |
225 | | cl::Hidden, cl::init(true), cl::cat(PollyCategory)); |
226 | | |
227 | | static cl::opt<bool> |
228 | | EnableSimplify("polly-enable-simplify", |
229 | | cl::desc("Simplify SCoP after optimizations"), |
230 | | cl::init(true), cl::cat(PollyCategory)); |
231 | | |
232 | | static cl::opt<bool> EnablePruneUnprofitable( |
233 | | "polly-enable-prune-unprofitable", |
234 | | cl::desc("Bail out on unprofitable SCoPs before rescheduling"), cl::Hidden, |
235 | | cl::init(true), cl::cat(PollyCategory)); |
236 | | |
237 | | namespace polly { |
238 | 48.2k | void initializePollyPasses(PassRegistry &Registry) { |
239 | 48.2k | initializeCodeGenerationPass(Registry); |
240 | 48.2k | |
241 | | #ifdef GPU_CODEGEN |
242 | | initializePPCGCodeGenerationPass(Registry); |
243 | | initializeManagedMemoryRewritePassPass(Registry); |
244 | | LLVMInitializeNVPTXTarget(); |
245 | | LLVMInitializeNVPTXTargetInfo(); |
246 | | LLVMInitializeNVPTXTargetMC(); |
247 | | LLVMInitializeNVPTXAsmPrinter(); |
248 | | #endif |
249 | | initializeCodePreparationPass(Registry); |
250 | 48.2k | initializeDeadCodeElimPass(Registry); |
251 | 48.2k | initializeDependenceInfoPass(Registry); |
252 | 48.2k | initializeDependenceInfoWrapperPassPass(Registry); |
253 | 48.2k | initializeJSONExporterPass(Registry); |
254 | 48.2k | initializeJSONImporterPass(Registry); |
255 | 48.2k | initializeMaximalStaticExpanderPass(Registry); |
256 | 48.2k | initializeIslAstInfoWrapperPassPass(Registry); |
257 | 48.2k | initializeIslScheduleOptimizerPass(Registry); |
258 | 48.2k | initializePollyCanonicalizePass(Registry); |
259 | 48.2k | initializePolyhedralInfoPass(Registry); |
260 | 48.2k | initializeScopDetectionWrapperPassPass(Registry); |
261 | 48.2k | initializeScopInlinerPass(Registry); |
262 | 48.2k | initializeScopInfoRegionPassPass(Registry); |
263 | 48.2k | initializeScopInfoWrapperPassPass(Registry); |
264 | 48.2k | initializeRewriteByrefParamsPass(Registry); |
265 | 48.2k | initializeCodegenCleanupPass(Registry); |
266 | 48.2k | initializeFlattenSchedulePass(Registry); |
267 | 48.2k | initializeForwardOpTreePass(Registry); |
268 | 48.2k | initializeDeLICMPass(Registry); |
269 | 48.2k | initializeSimplifyPass(Registry); |
270 | 48.2k | initializeDumpModulePass(Registry); |
271 | 48.2k | initializePruneUnprofitablePass(Registry); |
272 | 48.2k | } |
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 | 0 | void registerPollyPasses(llvm::legacy::PassManagerBase &PM) { |
301 | 0 | if (DumpBefore) |
302 | 0 | PM.add(polly::createDumpModulePass("-before", true)); |
303 | 0 | for (auto &Filename : DumpBeforeFile) |
304 | 0 | PM.add(polly::createDumpModulePass(Filename, false)); |
305 | 0 |
|
306 | 0 | PM.add(polly::createScopDetectionWrapperPassPass()); |
307 | 0 |
|
308 | 0 | if (PollyDetectOnly) |
309 | 0 | return; |
310 | 0 | |
311 | 0 | if (PollyViewer) |
312 | 0 | PM.add(polly::createDOTViewerPass()); |
313 | 0 | if (PollyOnlyViewer) |
314 | 0 | PM.add(polly::createDOTOnlyViewerPass()); |
315 | 0 | if (PollyPrinter) |
316 | 0 | PM.add(polly::createDOTPrinterPass()); |
317 | 0 | if (PollyOnlyPrinter) |
318 | 0 | PM.add(polly::createDOTOnlyPrinterPass()); |
319 | 0 |
|
320 | 0 | PM.add(polly::createScopInfoRegionPassPass()); |
321 | 0 | if (EnablePolyhedralInfo) |
322 | 0 | PM.add(polly::createPolyhedralInfoPass()); |
323 | 0 |
|
324 | 0 | if (EnableSimplify) |
325 | 0 | PM.add(polly::createSimplifyPass(0)); |
326 | 0 | if (EnableForwardOpTree) |
327 | 0 | PM.add(polly::createForwardOpTreePass()); |
328 | 0 | if (EnableDeLICM) |
329 | 0 | PM.add(polly::createDeLICMPass()); |
330 | 0 | if (EnableSimplify) |
331 | 0 | PM.add(polly::createSimplifyPass(1)); |
332 | 0 |
|
333 | 0 | if (ImportJScop) |
334 | 0 | PM.add(polly::createJSONImporterPass()); |
335 | 0 |
|
336 | 0 | if (DeadCodeElim) |
337 | 0 | PM.add(polly::createDeadCodeElimPass()); |
338 | 0 |
|
339 | 0 | if (FullyIndexedStaticExpansion) |
340 | 0 | PM.add(polly::createMaximalStaticExpansionPass()); |
341 | 0 |
|
342 | 0 | if (EnablePruneUnprofitable) |
343 | 0 | PM.add(polly::createPruneUnprofitablePass()); |
344 | 0 |
|
345 | | #ifdef GPU_CODEGEN |
346 | | if (Target == TARGET_HYBRID) |
347 | | PM.add( |
348 | | polly::createPPCGCodeGenerationPass(GPUArchChoice, GPURuntimeChoice)); |
349 | | #endif |
350 | 0 | if (Target == TARGET_CPU || Target == TARGET_HYBRID) |
351 | 0 | switch (Optimizer) { |
352 | 0 | case OPTIMIZER_NONE: |
353 | 0 | break; /* Do nothing */ |
354 | 0 |
|
355 | 0 | case OPTIMIZER_ISL: |
356 | 0 | PM.add(polly::createIslScheduleOptimizerPass()); |
357 | 0 | break; |
358 | 0 | } |
359 | 0 | |
360 | 0 | if (ExportJScop) |
361 | 0 | PM.add(polly::createJSONExporterPass()); |
362 | 0 |
|
363 | 0 | if (Target == TARGET_CPU || Target == TARGET_HYBRID) |
364 | 0 | switch (CodeGeneration) { |
365 | 0 | case CODEGEN_AST: |
366 | 0 | PM.add(polly::createIslAstInfoWrapperPassPass()); |
367 | 0 | break; |
368 | 0 | case CODEGEN_FULL: |
369 | 0 | PM.add(polly::createCodeGenerationPass()); |
370 | 0 | break; |
371 | 0 | case CODEGEN_NONE: |
372 | 0 | break; |
373 | 0 | } |
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 | 0 | // FIXME: This dummy ModulePass keeps some programs from miscompiling, |
389 | 0 | // probably some not correctly preserved analyses. It acts as a barrier to |
390 | 0 | // force all analysis results to be recomputed. |
391 | 0 | PM.add(createBarrierNoopPass()); |
392 | 0 |
|
393 | 0 | if (DumpAfter) |
394 | 0 | PM.add(polly::createDumpModulePass("-after", true)); |
395 | 0 | for (auto &Filename : DumpAfterFile) |
396 | 0 | PM.add(polly::createDumpModulePass(Filename, false)); |
397 | 0 |
|
398 | 0 | if (CFGPrinter) |
399 | 0 | PM.add(llvm::createCFGPrinterLegacyPassPass()); |
400 | 0 | } |
401 | | |
402 | 37.9k | static bool shouldEnablePolly() { |
403 | 37.9k | if (PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer) |
404 | 0 | PollyTrackFailures = true; |
405 | 37.9k | |
406 | 37.9k | if (PollyOnlyPrinter || PollyPrinter || PollyOnlyViewer || PollyViewer || |
407 | 37.9k | ExportJScop || ImportJScop) |
408 | 0 | PollyEnabled = true; |
409 | 37.9k | |
410 | 37.9k | return PollyEnabled; |
411 | 37.9k | } |
412 | | |
413 | | static void |
414 | | registerPollyEarlyAsPossiblePasses(const llvm::PassManagerBuilder &Builder, |
415 | 12.6k | llvm::legacy::PassManagerBase &PM) { |
416 | 12.6k | if (!polly::shouldEnablePolly()) |
417 | 12.6k | return; |
418 | 0 | |
419 | 0 | if (PassPosition != POSITION_EARLY) |
420 | 0 | return; |
421 | 0 | |
422 | 0 | registerCanonicalicationPasses(PM); |
423 | 0 | polly::registerPollyPasses(PM); |
424 | 0 | } |
425 | | |
426 | | static void |
427 | | registerPollyLoopOptimizerEndPasses(const llvm::PassManagerBuilder &Builder, |
428 | 12.6k | llvm::legacy::PassManagerBase &PM) { |
429 | 12.6k | if (!polly::shouldEnablePolly()) |
430 | 12.6k | return; |
431 | 0 | |
432 | 0 | if (PassPosition != POSITION_AFTER_LOOPOPT) |
433 | 0 | return; |
434 | 0 | |
435 | 0 | PM.add(polly::createCodePreparationPass()); |
436 | 0 | polly::registerPollyPasses(PM); |
437 | 0 | PM.add(createCodegenCleanupPass()); |
438 | 0 | } |
439 | | |
440 | | static void |
441 | | registerPollyScalarOptimizerLatePasses(const llvm::PassManagerBuilder &Builder, |
442 | 12.6k | llvm::legacy::PassManagerBase &PM) { |
443 | 12.6k | if (!polly::shouldEnablePolly()) |
444 | 12.6k | return; |
445 | 0 | |
446 | 0 | if (PassPosition != POSITION_BEFORE_VECTORIZER) |
447 | 0 | return; |
448 | 0 | |
449 | 0 | PM.add(polly::createCodePreparationPass()); |
450 | 0 | polly::registerPollyPasses(PM); |
451 | 0 | PM.add(createCodegenCleanupPass()); |
452 | 0 | } |
453 | | |
454 | | static void buildDefaultPollyPipeline(FunctionPassManager &PM, |
455 | 46 | PassBuilder::OptimizationLevel Level) { |
456 | 46 | if (!polly::shouldEnablePolly()) |
457 | 46 | return; |
458 | 0 | PassBuilder PB; |
459 | 0 | ScopPassManager SPM; |
460 | 0 |
|
461 | 0 | // TODO add utility passes for the various command line options, once they're |
462 | 0 | // ported |
463 | 0 | assert(!DumpBefore && "This option is not implemented"); |
464 | 0 | assert(DumpBeforeFile.empty() && "This option is not implemented"); |
465 | 0 |
|
466 | 0 | if (PollyDetectOnly) |
467 | 0 | return; |
468 | 0 | |
469 | 0 | assert(!PollyViewer && "This option is not implemented"); |
470 | 0 | assert(!PollyOnlyViewer && "This option is not implemented"); |
471 | 0 | assert(!PollyPrinter && "This option is not implemented"); |
472 | 0 | assert(!PollyOnlyPrinter && "This option is not implemented"); |
473 | 0 | assert(!EnablePolyhedralInfo && "This option is not implemented"); |
474 | 0 | assert(!EnableDeLICM && "This option is not implemented"); |
475 | 0 | assert(!EnableSimplify && "This option is not implemented"); |
476 | 0 | if (ImportJScop) |
477 | 0 | SPM.addPass(JSONImportPass()); |
478 | 0 | assert(!DeadCodeElim && "This option is not implemented"); |
479 | 0 | assert(!EnablePruneUnprofitable && "This option is not implemented"); |
480 | 0 | if (Target == TARGET_CPU || Target == TARGET_HYBRID) |
481 | 0 | switch (Optimizer) { |
482 | 0 | case OPTIMIZER_NONE: |
483 | 0 | break; /* Do nothing */ |
484 | 0 | case OPTIMIZER_ISL: |
485 | 0 | llvm_unreachable("ISL optimizer is not implemented"); |
486 | 0 | break; |
487 | 0 | } |
488 | 0 | |
489 | 0 | assert(!ExportJScop && "This option is not implemented"); |
490 | 0 |
|
491 | 0 | if (Target == TARGET_CPU || Target == TARGET_HYBRID) { |
492 | 0 | switch (CodeGeneration) { |
493 | 0 | case CODEGEN_FULL: |
494 | 0 | SPM.addPass(polly::CodeGenerationPass()); |
495 | 0 | break; |
496 | 0 | case CODEGEN_AST: |
497 | 0 | default: // Does it actually make sense to distinguish IslAst codegen? |
498 | 0 | break; |
499 | 0 | } |
500 | 0 | } |
501 | | #ifdef GPU_CODEGEN |
502 | | else |
503 | | llvm_unreachable("Hybrid Target with GPU support is not implemented"); |
504 | | #endif |
505 | | |
506 | 0 | PM.addPass(CodePreparationPass()); |
507 | 0 | PM.addPass(createFunctionToScopPassAdaptor(std::move(SPM))); |
508 | 0 | PM.addPass(PB.buildFunctionSimplificationPipeline( |
509 | 0 | Level, PassBuilder::ThinLTOPhase::None)); // Cleanup |
510 | 0 |
|
511 | 0 | assert(!DumpAfter && "This option is not implemented"); |
512 | 0 | assert(DumpAfterFile.empty() && "This option is not implemented"); |
513 | 0 |
|
514 | 0 | if (CFGPrinter) |
515 | 0 | PM.addPass(llvm::CFGPrinterPass()); |
516 | 0 | } |
517 | | |
518 | | /// Register Polly to be available as an optimizer |
519 | | /// |
520 | | /// |
521 | | /// We can currently run Polly at three different points int the pass manager. |
522 | | /// a) very early, b) after the canonicalizing loop transformations and c) right |
523 | | /// before the vectorizer. |
524 | | /// |
525 | | /// The default is currently a), to register Polly such that it runs as early as |
526 | | /// possible. This has several implications: |
527 | | /// |
528 | | /// 1) We need to schedule more canonicalization passes |
529 | | /// |
530 | | /// As nothing is run before Polly, it is necessary to run a set of preparing |
531 | | /// transformations before Polly to canonicalize the LLVM-IR and to allow |
532 | | /// Polly to detect and understand the code. |
533 | | /// |
534 | | /// 2) LICM and LoopIdiom pass have not yet been run |
535 | | /// |
536 | | /// Loop invariant code motion as well as the loop idiom recognition pass make |
537 | | /// it more difficult for Polly to transform code. LICM may introduce |
538 | | /// additional data dependences that are hard to eliminate and the loop idiom |
539 | | /// recognition pass may introduce calls to memset that we currently do not |
540 | | /// understand. By running Polly early enough (meaning before these passes) we |
541 | | /// avoid difficulties that may be introduced by these passes. |
542 | | /// |
543 | | /// 3) We get the full -O3 optimization sequence after Polly |
544 | | /// |
545 | | /// The LLVM-IR that is generated by Polly has been optimized on a high level, |
546 | | /// but it may be rather inefficient on the lower/scalar level. By scheduling |
547 | | /// Polly before all other passes, we have the full sequence of -O3 |
548 | | /// optimizations behind us, such that inefficiencies on the low level can |
549 | | /// be optimized away. |
550 | | /// |
551 | | /// We are currently evaluating the benefit or running Polly at position b) or |
552 | | /// c). b) is likely too early as it interacts with the inliner. c) is nice |
553 | | /// as everything is fully inlined and canonicalized, but we need to be able |
554 | | /// to handle LICMed code to make it useful. |
555 | | static llvm::RegisterStandardPasses RegisterPollyOptimizerEarly( |
556 | | llvm::PassManagerBuilder::EP_ModuleOptimizerEarly, |
557 | | registerPollyEarlyAsPossiblePasses); |
558 | | |
559 | | static llvm::RegisterStandardPasses |
560 | | RegisterPollyOptimizerLoopEnd(llvm::PassManagerBuilder::EP_LoopOptimizerEnd, |
561 | | registerPollyLoopOptimizerEndPasses); |
562 | | |
563 | | static llvm::RegisterStandardPasses RegisterPollyOptimizerScalarLate( |
564 | | llvm::PassManagerBuilder::EP_VectorizerStart, |
565 | | registerPollyScalarOptimizerLatePasses); |
566 | | |
567 | | static OwningScopAnalysisManagerFunctionProxy |
568 | 1.24k | createScopAnalyses(FunctionAnalysisManager &FAM) { |
569 | 1.24k | OwningScopAnalysisManagerFunctionProxy Proxy; |
570 | 1.24k | #define SCOP_ANALYSIS(NAME, CREATE_PASS) \ |
571 | 2.49k | Proxy.getManager().registerPass([] { return CREATE_PASS; }); RegisterPasses.cpp:polly::createScopAnalyses(llvm::AnalysisManager<llvm::Function>&)::$_0::operator()() const Line | Count | Source | 571 | 1.24k | Proxy.getManager().registerPass([] { return CREATE_PASS; }); |
RegisterPasses.cpp:polly::createScopAnalyses(llvm::AnalysisManager<llvm::Function>&)::$_1::operator()() const Line | Count | Source | 571 | 1.24k | Proxy.getManager().registerPass([] { return CREATE_PASS; }); |
|
572 | 1.24k | |
573 | 1.24k | #include "PollyPasses.def" |
574 | 1.24k | |
575 | 1.24k | Proxy.getManager().registerPass( |
576 | 1.24k | [&FAM] { return FunctionAnalysisManagerScopProxy(FAM); }); |
577 | 1.24k | return Proxy; |
578 | 1.24k | } |
579 | | |
580 | 1.24k | static void registerFunctionAnalyses(FunctionAnalysisManager &FAM) { |
581 | 1.24k | #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ |
582 | 2.49k | FAM.registerPass([] { return CREATE_PASS; }); RegisterPasses.cpp:polly::registerFunctionAnalyses(llvm::AnalysisManager<llvm::Function>&)::$_3::operator()() const Line | Count | Source | 582 | 1.24k | FAM.registerPass([] { return CREATE_PASS; }); |
RegisterPasses.cpp:polly::registerFunctionAnalyses(llvm::AnalysisManager<llvm::Function>&)::$_4::operator()() const Line | Count | Source | 582 | 1.24k | FAM.registerPass([] { return CREATE_PASS; }); |
|
583 | 1.24k | |
584 | 1.24k | #include "PollyPasses.def" |
585 | 1.24k | |
586 | 1.24k | FAM.registerPass([&FAM] { return createScopAnalyses(FAM); }); |
587 | 1.24k | } |
588 | | |
589 | | static bool |
590 | | parseFunctionPipeline(StringRef Name, FunctionPassManager &FPM, |
591 | 30 | ArrayRef<PassBuilder::PipelineElement> Pipeline) { |
592 | 30 | if (parseAnalysisUtilityPasses<OwningScopAnalysisManagerFunctionProxy>( |
593 | 30 | "polly-scop-analyses", Name, FPM)) |
594 | 0 | return true; |
595 | 30 | |
596 | 30 | #define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ |
597 | 90 | if (parseAnalysisUtilityPasses< \ |
598 | 60 | std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name, \ |
599 | 60 | FPM)) \ |
600 | 90 | return true0 ; |
601 | 30 | |
602 | 30 | #define FUNCTION_PASS(NAME, CREATE_PASS) \ |
603 | 86 | if (Name == NAME) { \ |
604 | 2 | FPM.addPass(CREATE_PASS); \ |
605 | 2 | return true; \ |
606 | 2 | } |
607 | 30 | |
608 | 146 | #include "PollyPasses.def"30 |
609 | 146 | return false28 ; |
610 | 146 | } |
611 | | |
612 | 1 | static bool parseScopPass(StringRef Name, ScopPassManager &SPM) { |
613 | 1 | #define SCOP_ANALYSIS(NAME, CREATE_PASS) \ |
614 | 2 | if (parseAnalysisUtilityPasses< \ |
615 | 2 | std::remove_reference<decltype(CREATE_PASS)>::type>(NAME, Name, \ |
616 | 2 | SPM)) \ |
617 | 2 | return true0 ; |
618 | 1 | |
619 | 1 | #define SCOP_PASS(NAME, CREATE_PASS) \ |
620 | 3 | if (Name == NAME) { \ |
621 | 1 | SPM.addPass(CREATE_PASS); \ |
622 | 1 | return true; \ |
623 | 1 | } |
624 | 1 | |
625 | 4 | #include "PollyPasses.def"1 |
626 | 4 | |
627 | 4 | return false0 ; |
628 | 4 | } |
629 | | |
630 | | static bool parseScopPipeline(StringRef Name, FunctionPassManager &FPM, |
631 | 28 | ArrayRef<PassBuilder::PipelineElement> Pipeline) { |
632 | 28 | if (Name != "scop") |
633 | 27 | return false; |
634 | 1 | if (!Pipeline.empty()) { |
635 | 1 | ScopPassManager SPM; |
636 | 1 | for (const auto &E : Pipeline) |
637 | 1 | if (!parseScopPass(E.Name, SPM)) |
638 | 0 | return false; |
639 | 1 | FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM))); |
640 | 1 | } |
641 | 1 | return true; |
642 | 1 | } |
643 | | |
644 | 0 | static bool isScopPassName(StringRef Name) { |
645 | 0 | #define SCOP_ANALYSIS(NAME, CREATE_PASS) \ |
646 | 0 | if (Name == "require<" NAME ">") \ |
647 | 0 | return true; \ |
648 | 0 | if (Name == "invalidate<" NAME ">") \ |
649 | 0 | return true; |
650 | 0 |
|
651 | 0 | #define SCOP_PASS(NAME, CREATE_PASS) \ |
652 | 0 | if (Name == NAME) \ |
653 | 0 | return true; |
654 | 0 |
|
655 | 0 | #include "PollyPasses.def" |
656 | 0 |
|
657 | 0 | return false; |
658 | 0 | } |
659 | | |
660 | | static bool |
661 | | parseTopLevelPipeline(ModulePassManager &MPM, |
662 | | ArrayRef<PassBuilder::PipelineElement> Pipeline, |
663 | 0 | bool VerifyEachPass, bool DebugLogging) { |
664 | 0 | std::vector<PassBuilder::PipelineElement> FullPipeline; |
665 | 0 | StringRef FirstName = Pipeline.front().Name; |
666 | 0 |
|
667 | 0 | if (!isScopPassName(FirstName)) |
668 | 0 | return false; |
669 | 0 | |
670 | 0 | FunctionPassManager FPM(DebugLogging); |
671 | 0 | ScopPassManager SPM(DebugLogging); |
672 | 0 |
|
673 | 0 | for (auto &Element : Pipeline) { |
674 | 0 | auto &Name = Element.Name; |
675 | 0 | auto &InnerPipeline = Element.InnerPipeline; |
676 | 0 | if (!InnerPipeline.empty()) // Scop passes don't have inner pipelines |
677 | 0 | return false; |
678 | 0 | if (!parseScopPass(Name, SPM)) |
679 | 0 | return false; |
680 | 0 | } |
681 | 0 |
|
682 | 0 | FPM.addPass(createFunctionToScopPassAdaptor(std::move(SPM))); |
683 | 0 | if (VerifyEachPass) |
684 | 0 | FPM.addPass(VerifierPass()); |
685 | 0 | MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); |
686 | 0 | if (VerifyEachPass) |
687 | 0 | MPM.addPass(VerifierPass()); |
688 | 0 |
|
689 | 0 | return true; |
690 | 0 | } |
691 | | |
692 | 1.25k | void RegisterPollyPasses(PassBuilder &PB) { |
693 | 1.25k | PB.registerAnalysisRegistrationCallback(registerFunctionAnalyses); |
694 | 1.25k | PB.registerPipelineParsingCallback(parseFunctionPipeline); |
695 | 1.25k | PB.registerPipelineParsingCallback(parseScopPipeline); |
696 | 1.25k | PB.registerParseTopLevelPipelineCallback(parseTopLevelPipeline); |
697 | 1.25k | |
698 | 1.25k | if (PassPosition == POSITION_BEFORE_VECTORIZER) |
699 | 1.25k | PB.registerVectorizerStartEPCallback(buildDefaultPollyPipeline); |
700 | 1.25k | // FIXME else Error? |
701 | 1.25k | } |
702 | | } // namespace polly |
703 | | |
704 | | // Plugin Entrypoint: |
705 | | extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK |
706 | 1 | llvmGetPassPluginInfo() { |
707 | 1 | return {LLVM_PLUGIN_API_VERSION, "Polly", LLVM_VERSION_STRING, |
708 | 1 | polly::RegisterPollyPasses}; |
709 | 1 | } |