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

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

Refactor IDISA, re, pablo toolchain components

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