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