source: icGREP/icgrep-devel/icgrep/pablo/pablo_toolchain.cpp @ 5350

Last change on this file since 5350 was 5295, checked in by cameron, 3 years ago

Debug Options: SerializeThreads?; unify ShowIR, ShowPablo?, ShowREs, ShowASM

File size: 12.6 KB
Line 
1/*
2 *  Copyright (c) 2015 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include "pablo_toolchain.h"
8#include <pablo/pablo_kernel.h>
9#include <pablo/optimizers/pablo_simplifier.hpp>
10#include <pablo/optimizers/codemotionpass.h>
11#include <pablo/passes/flattenassociativedfg.h>
12#include <pablo/passes/flattenif.hpp>
13#include <pablo/passes/factorizedfg.h>
14#ifdef ENABLE_MULTIPLEXING
15#include <pablo/optimizers/pablo_automultiplexing.hpp>
16#include <pablo/optimizers/pablo_bddminimization.h>
17#include <pablo/optimizers/booleanreassociationpass.h>
18#include <pablo/optimizers/distributivepass.h>
19#include <pablo/optimizers/schedulingprepass.h>
20#endif
21#include <pablo/analysis/pabloverifier.hpp>
22#include <pablo/printer_pablos.h>
23#include <llvm/Support/CommandLine.h>
24#include <llvm/Support/FileSystem.h>
25#include <llvm/Support/raw_ostream.h>
26#ifdef PRINT_TIMING_INFORMATION
27#include <hrtime.h>
28#endif
29
30
31using namespace llvm;
32
33namespace pablo {
34
35static cl::OptionCategory PabloOptions("Pablo Options", "These options control printing, generation and instrumentation of Pablo intermediate code.");
36
37const cl::OptionCategory * pablo_toolchain_flags() {
38    return &PabloOptions;
39}
40   
41   
42static cl::bits<PabloDebugFlags> 
43DebugOptions(cl::values(clEnumVal(ShowPablo, "Print generated Pablo code"),
44                        clEnumVal(ShowOptimizedPablo, "Print optimizeed Pablo code"),
45                        clEnumVal(ShowUnloweredPablo, "Print Pablo code prior to lowering."),
46                        clEnumVal(DumpTrace, "Generate dynamic traces of executed Pablo assignments."),
47                        clEnumValEnd), cl::cat(PabloOptions));
48   
49static cl::opt<std::string> PabloOutputFilename("print-pablo-output", cl::init(""), cl::desc("output Pablo filename"), cl::cat(PabloOptions));
50static cl::opt<bool> Flatten("flatten-if", cl::init(false), cl::desc("Flatten all the Ifs in the Pablo AST"), cl::cat(PabloOptions));
51
52static cl::bits<PabloCompilationFlags> 
53    PabloOptimizationsOptions(cl::values(clEnumVal(DisableSimplification, "Disable Pablo Simplification pass (not recommended)"),
54                                         clEnumVal(EnableCodeMotion, "Moves statements into the innermost legal If-scope and moves invariants out of While-loops."),
55#ifdef ENABLE_MULTIPLEXING
56                                         clEnumVal(EnableMultiplexing, "combine Advances whose inputs are mutual exclusive into the fewest number of advances possible (expensive)."),
57                                         clEnumVal(EnableLowering, "coalesce associative functions prior to optimization passes."),
58                                         clEnumVal(EnablePreDistribution, "apply distribution law optimization prior to multiplexing."),
59                                         clEnumVal(EnablePostDistribution, "apply distribution law optimization after multiplexing."),
60                                         clEnumVal(EnablePrePassScheduling, "apply pre-pass scheduling prior to LLVM IR generation."),
61#endif                                         
62                            clEnumValEnd), cl::cat(PabloOptions));
63
64bool DebugOptionIsSet(PabloDebugFlags flag) {return DebugOptions.isSet(flag);}
65   
66   
67   
68#ifdef PRINT_TIMING_INFORMATION
69#define READ_CYCLE_COUNTER(name) name = read_cycle_counter();
70#else
71#define READ_CYCLE_COUNTER(name)
72#endif
73
74#ifdef PRINT_TIMING_INFORMATION
75unsigned COUNT_STATEMENTS(const PabloKernel * const entry) {
76    std::stack<const Statement *> scope;
77    unsigned statements = 0;
78    // Scan through and collect all the advances, scanthrus and matchstars ...
79    for (const Statement * stmt = entry->getEntryBlock()->front(); ; ) {
80        while ( stmt ) {
81            ++statements;
82            if (LLVM_UNLIKELY(isa<If>(stmt) || isa<While>(stmt))) {
83                // Set the next statement to be the first statement of the inner scope and push the
84                // next statement of the current statement into the scope stack.
85                const PabloBlock * const nested = isa<If>(stmt) ? cast<If>(stmt)->getBody() : cast<While>(stmt)->getBody();
86                scope.push(stmt->getNextNode());
87                stmt = nested->front();
88                assert (stmt);
89                continue;
90            }
91            stmt = stmt->getNextNode();
92        }
93        if (scope.empty()) {
94            break;
95        }
96        stmt = scope.top();
97        scope.pop();
98    }
99    return statements;
100}
101
102unsigned COUNT_ADVANCES(const PabloKernel * const entry) {
103
104    std::stack<const Statement *> scope;
105    unsigned advances = 0;
106
107    // Scan through and collect all the advances, scanthrus and matchstars ...
108    for (const Statement * stmt = entry->getEntryBlock()->front(); ; ) {
109        while ( stmt ) {
110            if (isa<Advance>(stmt)) {
111                ++advances;
112            }
113            else if (LLVM_UNLIKELY(isa<If>(stmt) || isa<While>(stmt))) {
114                // Set the next statement to be the first statement of the inner scope and push the
115                // next statement of the current statement into the scope stack.
116                const PabloBlock * const nested = isa<If>(stmt) ? cast<If>(stmt)->getBody() : cast<While>(stmt)->getBody();
117                scope.push(stmt->getNextNode());
118                stmt = nested->front();
119                assert (stmt);
120                continue;
121            }
122            stmt = stmt->getNextNode();
123        }
124        if (scope.empty()) {
125            break;
126        }
127        stmt = scope.top();
128        scope.pop();
129    }
130    return advances;
131}
132
133using DistributionMap = boost::container::flat_map<unsigned, unsigned>;
134
135DistributionMap SUMMARIZE_VARIADIC_DISTRIBUTION(const PabloKernel * const entry) {
136    std::stack<const Statement *> scope;
137    DistributionMap distribution;
138    // Scan through and collect all the advances, scanthrus and matchstars ...
139    for (const Statement * stmt = entry->getEntryBlock()->front(); ; ) {
140        while ( stmt ) {
141            if (isa<Variadic>(stmt)) {
142                auto f = distribution.find(stmt->getNumOperands());
143                if (f == distribution.end()) {
144                    distribution.emplace(stmt->getNumOperands(), 1);
145                } else {
146                    f->second += 1;
147                }
148            }
149            else if (LLVM_UNLIKELY(isa<If>(stmt) || isa<While>(stmt))) {
150                // Set the next statement to be the first statement of the inner scope and push the
151                // next statement of the current statement into the scope stack.
152                const PabloBlock * const nested = isa<If>(stmt) ? cast<If>(stmt)->getBody() : cast<While>(stmt)->getBody();
153                scope.push(stmt->getNextNode());
154                stmt = nested->front();
155                assert (stmt);
156                continue;
157            }
158            stmt = stmt->getNextNode();
159        }
160        if (scope.empty()) {
161            break;
162        }
163        stmt = scope.top();
164        scope.pop();
165    }
166    return distribution;
167}
168#endif
169
170void pablo_function_passes(PabloKernel * kernel) {
171   
172    if (DebugOptions.isSet(ShowPablo)) {
173        //Print to the terminal the AST that was generated by the pararallel bit-stream compiler.
174        errs() << "Initial Pablo AST:\n";
175        PabloPrinter::print(kernel, errs());
176    }
177   
178    #ifndef NDEBUG
179    PabloVerifier::verify(kernel, "creation");
180    #endif
181
182    // Scan through the pablo code and perform DCE and CSE
183
184#ifdef PRINT_TIMING_INFORMATION
185    timestamp_t simplification_start = 0, simplification_end = 0;
186    timestamp_t flattenif_start = 0, flattenif_end = 0;
187    timestamp_t coalescing_start = 0, coalescing_end = 0;
188    timestamp_t sinking_start = 0, sinking_end = 0;
189    timestamp_t pre_distribution_start = 0, pre_distribution_end = 0;
190    timestamp_t multiplexing_start = 0, multiplexing_end = 0;
191    timestamp_t post_distribution_start = 0, post_distribution_end = 0;
192    timestamp_t lowering_start = 0, lowering_end = 0;
193    timestamp_t scheduling_start = 0, scheduling_end = 0;
194    DistributionMap distribution;
195    const timestamp_t optimization_start = read_cycle_counter();
196#endif
197    if (!PabloOptimizationsOptions.isSet(DisableSimplification)) {
198        READ_CYCLE_COUNTER(simplification_start);
199        Simplifier::optimize(kernel);
200        READ_CYCLE_COUNTER(simplification_end);
201    }
202    if (Flatten){
203        READ_CYCLE_COUNTER(flattenif_start);
204        FlattenIf::transform(kernel);
205        READ_CYCLE_COUNTER(flattenif_end);
206    }
207#ifdef ENABLE_MULTIPLEXING
208//    if (PabloOptimizationsOptions.isSet(EnableLowering) || PabloOptimizationsOptions.isSet(EnablePreDistribution) || PabloOptimizationsOptions.isSet(EnablePostDistribution)) {
209//        READ_CYCLE_COUNTER(coalescing_start);
210//        CanonicalizeDFG::transform(kernel);
211//        READ_CYCLE_COUNTER(coalescing_end);
212//    }
213    if (PabloOptimizationsOptions.isSet(EnablePreDistribution)) {
214        READ_CYCLE_COUNTER(pre_distribution_start);
215        BooleanReassociationPass::optimize(kernel);
216        READ_CYCLE_COUNTER(pre_distribution_end);
217    }
218    if (PabloOptimizationsOptions.isSet(EnableMultiplexing)) {
219        READ_CYCLE_COUNTER(multiplexing_start);
220        MultiplexingPass::optimize(kernel);
221        READ_CYCLE_COUNTER(multiplexing_end);
222//        if (PabloOptimizationsOptions.isSet(EnableLowering) || PabloOptimizationsOptions.isSet(EnablePreDistribution) || PabloOptimizationsOptions.isSet(EnablePostDistribution)) {
223//            CanonicalizeDFG::transform(kernel);
224//        }
225    }
226    if (PabloOptimizationsOptions.isSet(EnablePostDistribution)) {
227        READ_CYCLE_COUNTER(post_distribution_start);
228        BooleanReassociationPass::optimize(kernel);
229        READ_CYCLE_COUNTER(post_distribution_end);
230    }
231#endif
232    if (PabloOptimizationsOptions.isSet(EnableCodeMotion)) {
233        READ_CYCLE_COUNTER(sinking_start);
234        CodeMotionPass::optimize(kernel);
235        READ_CYCLE_COUNTER(sinking_end);
236    }
237#ifdef ENABLE_MULTIPLEXING
238    if (DebugOptions.isSet(ShowUnloweredPablo)) {
239        //Print to the terminal the AST that was generated by the pararallel bit-stream compiler.
240        errs() << "Unlowered Pablo AST:\n";
241        PabloPrinter::print(kernel, errs());
242    }
243    #ifdef PRINT_TIMING_INFORMATION
244    distribution = SUMMARIZE_VARIADIC_DISTRIBUTION(function);
245    #endif
246//    if (PabloOptimizationsOptions.isSet(EnableLowering) || PabloOptimizationsOptions.isSet(EnablePreDistribution) || PabloOptimizationsOptions.isSet(EnablePostDistribution)) {
247//        READ_CYCLE_COUNTER(lowering_start);
248//        FactorizeDFG::transform(kernel);
249//        READ_CYCLE_COUNTER(lowering_end);
250//    }
251//    if (PabloOptimizationsOptions.isSet(EnablePrePassScheduling)) {
252//        READ_CYCLE_COUNTER(scheduling_start);
253//        SchedulingPrePass::optimize(kernel);
254//        READ_CYCLE_COUNTER(scheduling_end);
255//    }
256#endif
257#ifdef PRINT_TIMING_INFORMATION
258    const timestamp_t optimization_end = read_cycle_counter();
259#endif
260    if (DebugOptions.isSet(ShowOptimizedPablo)) {
261        if (PabloOutputFilename.empty()) {
262            //Print to the terminal the AST that was generated by the pararallel bit-stream compiler.
263            errs() << "Final Pablo AST:\n";
264            PabloPrinter::print(kernel, errs());
265        } else {
266            std::error_code error;
267            llvm::raw_fd_ostream out(PabloOutputFilename, error, sys::fs::OpenFlags::F_None);
268            PabloPrinter::print(kernel, out);
269        }
270    }
271#ifdef PRINT_TIMING_INFORMATION
272    errs() << "PABLO OPTIMIZATION TIME: " << (optimization_end - optimization_start) << "\n";
273    errs() << "  SIMPLIFICATION TIME: " << (simplification_end - simplification_start) << "\n";
274    errs() << "  COALESCING TIME: " << (coalescing_end - coalescing_start) << "\n";
275    errs() << "  SINKING TIME: " << (sinking_end - sinking_start) << "\n";
276    errs() << "  PRE-DISTRIBUTION TIME: " << (pre_distribution_end - pre_distribution_start) << "\n";
277    errs() << "  MULTIPLEXING TIME: " << (multiplexing_end - multiplexing_start) << "\n";
278    errs() << "  LOWERING TIME: " << (lowering_end - lowering_start) << "\n";
279    errs() << "  FLATTENIF TIME: " << (flattenif_end - flattenif_start) << "\n";
280    errs() << "  POST-DISTRIBUTION TIME: " << (post_distribution_end - post_distribution_start) << "\n";
281    errs() << "  SCHEDULING TIME: " << (scheduling_end - scheduling_start) << "\n";
282    errs() << "PABLO STATEMENTS: " << COUNT_STATEMENTS(function) << "\n";
283    errs() << "PABLO ADVANCES: " << COUNT_ADVANCES(function) << "\n";
284    errs() << "PRE-LOWERING VARIADIC DISTRIBUTION: ";
285    bool join = false;
286    for (auto dist : distribution) {
287        if (join) {
288            errs() << ';';
289        }
290        errs() << dist.first << '|' << dist.second;
291        join = true;
292    }
293    errs() << "\n";
294#endif
295}
296
297}
Note: See TracBrowser for help on using the repository browser.