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

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

Pablo Command Line options restructured

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