source: icGREP/icgrep-devel/icgrep/pablo/optimizers/pablo_simplifier.cpp @ 5821

Last change on this file since 5821 was 5821, checked in by nmedfort, 16 months ago

Bug fixes

File size: 24.6 KB
Line 
1#include <pablo/optimizers/pablo_simplifier.hpp>
2#include <pablo/pablo_kernel.h>
3#include <pablo/codegenstate.h>
4#include <pablo/expression_map.hpp>
5#include <pablo/boolean.h>
6#include <pablo/pe_zeroes.h>
7#include <pablo/pe_ones.h>
8#include <pablo/arithmetic.h>
9#include <pablo/branch.h>
10#include <pablo/ps_assign.h>
11#include <pablo/pe_advance.h>
12#include <pablo/pe_lookahead.h>
13#include <pablo/pe_scanthru.h>
14#include <pablo/pe_matchstar.h>
15#include <pablo/pe_var.h>
16#ifndef NDEBUG
17#include <pablo/analysis/pabloverifier.hpp>
18#endif
19#include <boost/container/flat_set.hpp>
20#include <llvm/IR/Type.h>
21
22using namespace boost;
23using namespace boost::container;
24using namespace llvm;
25
26namespace pablo {
27
28using TypeId = PabloAST::ClassTypeId;
29
30using ScopeMap = flat_map<PabloBlock *, unsigned>;
31
32/** ------------------------------------------------------------------------------------------------------------- *
33 * @brief VariableTable
34 ** ------------------------------------------------------------------------------------------------------------- */
35struct VariableTable {
36
37    VariableTable(VariableTable * predecessor = nullptr)
38    : mPredecessor(predecessor) {
39
40    }
41
42    PabloAST * get(PabloAST * const var) const {
43        const auto f = mMap.find(var);
44        if (f == mMap.end()) {
45            return (mPredecessor) ? mPredecessor->get(var) : nullptr;
46        }
47        return f->second;
48    }
49
50    void put(PabloAST * const var, PabloAST * value) {
51        const auto f = mMap.find(var);
52        if (LLVM_LIKELY(f == mMap.end())) {
53            mMap.emplace(var, value);
54        } else {
55            f->second = value;
56        }
57        assert (get(var) == value);
58    }
59
60private:
61    VariableTable * const mPredecessor;
62    flat_map<PabloAST *, PabloAST *> mMap;
63};
64
65struct PassContainer {
66
67/** ------------------------------------------------------------------------------------------------------------- *
68 * @brief run
69 ** ------------------------------------------------------------------------------------------------------------- */
70void run(PabloKernel * const kernel) {
71    redundancyElimination(kernel->getEntryBlock(), nullptr, nullptr);
72    strengthReduction(kernel->getEntryBlock());
73    deadCodeElimination(kernel->getEntryBlock());
74}
75
76protected:
77
78/** ------------------------------------------------------------------------------------------------------------- *
79 * @brief redundancyElimination
80 *
81 * Note: Do not recursively delete statements in this function. The ExpressionTable could use deleted statements
82 * as replacements. Let the DCE remove the unnecessary statements with the finalized Def-Use information.
83 ** ------------------------------------------------------------------------------------------------------------- */
84void redundancyElimination(PabloBlock * const block, ExpressionTable * const et, VariableTable * const vt) {
85    ExpressionTable expressions(et);
86    VariableTable variables(vt);
87
88    if (Branch * br = block->getBranch()) {
89        assert ("block has a branch but the expression and variable tables were not supplied" && et && vt);
90        for (Var * var : br->getEscaped()) {
91            variables.put(var, var);
92        }
93    }
94
95    mInScope.push_back(block);
96
97    const auto baseNonZeroEntries = mNonZero.size();
98    Statement * stmt = block->front();
99    while (stmt) {
100
101        if (LLVM_UNLIKELY(isa<Assign>(stmt))) {
102            Assign * const assign = cast<Assign>(stmt);
103            PabloAST * const var = assign->getVariable();
104            PabloAST * value = assign->getValue();
105            if (LLVM_UNLIKELY(var == value)) {
106                stmt = stmt->eraseFromParent();
107                continue;
108            }
109            while (LLVM_UNLIKELY(isa<Var>(value))) {
110                PabloAST * next = variables.get(cast<Var>(value));
111                if (LLVM_LIKELY(next == nullptr || next == value)) {
112                    break;
113                }
114                value = next;
115                assign->setValue(value);
116            }
117            if (LLVM_UNLIKELY(variables.get(var) == value)) {
118                stmt = stmt->eraseFromParent();
119                continue;
120            }
121            variables.put(var, value);
122
123        } else if (LLVM_UNLIKELY(isa<Branch>(stmt))) {
124
125            Branch * const br = cast<Branch>(stmt);
126            PabloAST * cond = br->getCondition();
127            if (isa<Var>(cond)) {
128                PabloAST * const value = variables.get(cast<Var>(cond));
129                if (value) {
130                    cond = value;
131                    if (isa<If>(br)) {
132                        br->setCondition(cond);
133                    }
134                }
135            }
136
137            // Test whether we can ever take this branch
138            if (LLVM_UNLIKELY(isa<Zeroes>(cond))) {
139                stmt = stmt->eraseFromParent();
140                continue;
141            }
142
143            // If we're guaranteed to take this branch, flatten it.
144            if (LLVM_LIKELY(isa<If>(br)) && LLVM_UNLIKELY(isNonZero(cond))) {
145                stmt = flatten(br);
146                continue;
147            }
148
149            // Mark the cond as non-zero prior to processing the inner scope.
150            mNonZero.push_back(cond);
151            // Process the Branch body
152            redundancyElimination(br->getBody(), &expressions, &variables);
153            assert (mNonZero.back() == cond);
154            mNonZero.pop_back();
155
156            if (LLVM_LIKELY(isa<If>(br))) {
157                // Check whether the cost of testing the condition and taking the branch with
158                // 100% correct prediction rate exceeds the cost of the body itself
159                if (LLVM_UNLIKELY(isTrivial(br->getBody()))) {
160                    stmt = flatten(br);
161                    continue;
162                }
163            }
164
165        } else {
166
167            // demote any uses of any Var whose value is in scope
168            for (unsigned i = 0; i < stmt->getNumOperands(); ++i) {
169                PabloAST * op = stmt->getOperand(i);
170                if (LLVM_UNLIKELY(isa<Var>(op))) {
171                    PabloAST * const value = variables.get(cast<Var>(op));
172                    if (value && value != op) {
173                        stmt->setOperand(i, value);
174                    }
175                }
176            }
177
178            PabloAST * const folded = triviallyFold(stmt, block);
179            if (folded) {
180                Statement * const prior = stmt->getPrevNode();
181                stmt->replaceWith(folded);
182                stmt = prior ? prior->getNextNode() : block->front();
183                continue;
184            }
185
186            // By recording which statements have already been seen, we can detect the redundant statements
187            // as any having the same type and operands. If so, we can replace its users with the prior statement.
188            // and erase this statement from the AST
189            const auto f = expressions.findOrAdd(stmt);
190            if (!f.second) {
191                stmt = stmt->replaceWith(f.first);
192                continue;
193            }
194
195            // Attempt to extend our set of trivially non-zero statements.
196            if (isa<Or>(stmt)) {
197                for (unsigned i = 0; i < stmt->getNumOperands(); ++i) {
198                    if (LLVM_UNLIKELY(isNonZero(stmt->getOperand(i)))) {
199                        mNonZero.push_back(stmt);
200                        break;
201                    }
202                }
203            } else if (isa<Advance>(stmt)) {
204                const Advance * const adv = cast<Advance>(stmt);
205                if (LLVM_LIKELY(adv->getAmount() < (adv->getType()->getPrimitiveSizeInBits() / 2))) {
206                    if (LLVM_UNLIKELY(isNonZero(adv->getExpression()))) {
207                        mNonZero.push_back(adv);
208                    }
209                }
210            }
211        }
212
213        stmt = stmt->getNextNode();
214    }
215
216    // Erase any local non-zero entries that were discovered while processing this scope
217    mNonZero.erase(mNonZero.begin() + baseNonZeroEntries, mNonZero.end());
218
219    assert (mInScope.back() == block);
220    mInScope.pop_back();
221
222    // If this block has a branch statement leading into it, we can verify whether an escaped value
223    // was updated within this block and update the preceeding block's variable state appropriately.
224
225    Branch * const br = block->getBranch();
226    if (LLVM_LIKELY(br != nullptr)) {
227
228        // When removing identical escaped values, we have to consider that the identical Vars could
229        // be assigned new differing values later in the outer body. Thus instead of replacing them
230        // directly, we map future uses of the duplicate Var to the initial one. The DCE pass will
231        // later mark any Assign statement as dead if the Var is never read.
232
233        const auto escaped = br->getEscaped();
234        const auto n = escaped.size();
235        PabloAST * variable[n];
236        PabloAST * incoming[n];
237        PabloAST * outgoing[n];
238        for (unsigned i = 0; i < n; ++i) {
239            variable[i] = escaped[i];
240            incoming[i] = vt->get(variable[i]);
241            outgoing[i] = variables.get(variable[i]);
242            if (LLVM_UNLIKELY(incoming[i] == outgoing[i])) {
243                variable[i] = incoming[i];
244            } else {
245                for (unsigned j = 0; j < i; ++j) {
246                    if (LLVM_UNLIKELY((outgoing[j] == outgoing[i]) && (incoming[j] == incoming[i]))) {
247                        variable[i] = variable[j];
248                        break;
249                    }
250                }
251            }
252            vt->put(escaped[i], variable[i]);
253        }
254
255    }
256
257}
258
259
260/** ------------------------------------------------------------------------------------------------------------- *
261 * @brief fold
262 ** ------------------------------------------------------------------------------------------------------------- */
263static PabloAST * triviallyFold(Statement * stmt, PabloBlock * const block) {
264    if (isa<Not>(stmt)) {
265        PabloAST * value = stmt->getOperand(0);
266        if (LLVM_UNLIKELY(isa<Not>(value))) {
267            return cast<Not>(value)->getOperand(0); // ¬¬A ⇔ A
268        } else if (LLVM_UNLIKELY(isa<Zeroes>(value))) {
269            return block->createOnes(stmt->getType()); // ¬0 ⇔ 1
270        }  else if (LLVM_UNLIKELY(isa<Ones>(value))) {
271            return block->createZeroes(stmt->getType()); // ¬1 ⇔ 0
272        }
273    } else if (isa<Variadic>(stmt)) {
274        std::sort(cast<Variadic>(stmt)->begin(), cast<Variadic>(stmt)->end());
275        for (unsigned i = 1; i < stmt->getNumOperands(); ) {
276            if (LLVM_UNLIKELY(stmt->getOperand(i - 1) == stmt->getOperand(i))) {
277                if (LLVM_UNLIKELY(isa<Xor>(stmt))) {
278                    if (LLVM_LIKELY(stmt->getNumOperands() == 2)) {
279                        return block->createZeroes(stmt->getType());
280                    } else {
281                        cast<Variadic>(stmt)->removeOperand(i);
282                        cast<Variadic>(stmt)->removeOperand(i - 1);
283                        continue;
284                    }
285                } else {
286                    if (LLVM_LIKELY(stmt->getNumOperands() == 2)) {
287                        return stmt->getOperand(1 - i);
288                    } else {
289                        cast<Variadic>(stmt)->removeOperand(i);
290                        continue;
291                    }
292                }
293            }
294            ++i;
295        }
296        if (LLVM_UNLIKELY(stmt->getNumOperands() < 2)) {
297            if (LLVM_LIKELY(stmt->getNumOperands() == 1)) {
298                return stmt->getOperand(0);
299            } else {
300                return block->createZeroes(stmt->getType());
301            }
302        }
303        if (LLVM_UNLIKELY(isa<Xor>(stmt))) {
304            bool negated = false;
305            PabloAST * expr = nullptr;
306            for (unsigned i = 0; i < stmt->getNumOperands(); ) {
307                const PabloAST * const op = stmt->getOperand(i);
308                if (isa<Not>(op)) {
309                    negated ^= true;
310                    stmt->setOperand(i, cast<Not>(op)->getExpr());
311                } else if (LLVM_UNLIKELY(isa<Zeroes>(op) || isa<Ones>(op))) {
312                    negated ^= isa<Ones>(op);
313                    if (LLVM_LIKELY(stmt->getNumOperands() == 2)) {
314                        expr = stmt->getOperand(1 - i);
315                        break;
316                    } else {
317                        cast<Variadic>(stmt)->removeOperand(i);
318                        continue;
319                    }
320                }
321                ++i;
322            }
323            if (LLVM_UNLIKELY(negated)) {
324                block->setInsertPoint(stmt);
325                expr = triviallyFold(block->createNot(expr ? expr : stmt), block);
326            }
327            return expr;
328        } else { // if (isa<And>(stmt) || isa<Or>(stmt))
329            for (unsigned i = 0; i < stmt->getNumOperands(); ++i) {
330                const PabloAST * const op = stmt->getOperand(i);
331                if (LLVM_UNLIKELY(isa<Zeroes>(op) || isa<Ones>(op))) {
332                    if (isa<And>(stmt) ^ isa<Zeroes>(op)) {
333                        if (LLVM_LIKELY(stmt->getNumOperands() == 2)) {
334                            return stmt->getOperand(1 - i);
335                        } else {
336                            cast<Variadic>(stmt)->removeOperand(i);
337                            continue;
338                        }
339                    } else {
340                        return stmt->getOperand(i);
341                    }
342                }
343                ++i;
344            }
345        }
346    } else if (isa<Advance>(stmt)) {
347        Advance * const adv = cast<Advance>(stmt);
348        if (LLVM_UNLIKELY(isa<Zeroes>(adv->getExpression()) || adv->getAmount() == 0)) {
349            return adv->getExpression();
350        }
351    } else if (isa<ScanThru>(stmt)) {
352        ScanThru * const st = cast<ScanThru>(stmt);
353        if (LLVM_UNLIKELY(isa<Zeroes>(st->getScanFrom()) || isa<Zeroes>(st->getScanThru()))) {
354            return st->getScanFrom();
355        } else if (LLVM_UNLIKELY(isa<Ones>(st->getScanThru()))) {
356            block->setInsertPoint(stmt->getPrevNode());
357            return block->createZeroes(stmt->getType());
358        } else if (LLVM_UNLIKELY(isa<ScanThru>(st->getScanFrom()))) {
359            ScanThru * const nested = cast<ScanThru>(st->getScanFrom());
360            if (LLVM_UNLIKELY(st->getScanThru() == nested->getScanThru())) {
361                return nested;
362            }
363        }
364    } else if (isa<MatchStar>(stmt)) {
365        MatchStar * const mstar = cast<MatchStar>(stmt);
366        if (LLVM_UNLIKELY(isa<Zeroes>(mstar->getMarker()) || isa<Zeroes>(mstar->getCharClass()))) {
367            return mstar->getMarker();
368        } else if (LLVM_UNLIKELY(isa<Ones>(mstar->getMarker()))) {
369            block->setInsertPoint(stmt->getPrevNode());
370            return block->createOnes(stmt->getType());
371        }
372    } else if (isa<Lookahead>(stmt)) {
373        Lookahead * const la = cast<Lookahead>(stmt);
374        if (LLVM_UNLIKELY(isa<Zeroes>(la->getExpression()) || la->getAmount() == 0)) {
375            return la->getExpression();
376        }
377    } else if (LLVM_UNLIKELY(isa<Sel>(stmt))) {
378        Sel * const sel = cast<Sel>(stmt);
379        if (LLVM_UNLIKELY(isa<Zeroes>(sel->getCondition()))) {
380            return sel->getFalseExpr();
381        }
382        if (LLVM_UNLIKELY(isa<Ones>(sel->getCondition()))) {
383            return sel->getTrueExpr();
384        }
385        if (LLVM_UNLIKELY(isa<Zeroes>(sel->getTrueExpr()))) {
386            block->setInsertPoint(stmt->getPrevNode());
387            PabloAST * const negCond = triviallyFold(block->createNot(sel->getCondition()), block);
388            return triviallyFold(block->createAnd(sel->getFalseExpr(), negCond), block);
389        }
390        if (LLVM_UNLIKELY(isa<Ones>(sel->getTrueExpr()))) {
391            block->setInsertPoint(stmt->getPrevNode());
392            return triviallyFold(block->createOr(sel->getCondition(), sel->getFalseExpr()), block);
393        }
394        if (LLVM_UNLIKELY(isa<Zeroes>(sel->getFalseExpr()))) {
395            block->setInsertPoint(stmt->getPrevNode());
396            return triviallyFold(block->createAnd(sel->getCondition(), sel->getTrueExpr()), block);
397        }
398        if (LLVM_UNLIKELY(isa<Ones>(sel->getFalseExpr()))) {
399            block->setInsertPoint(stmt->getPrevNode());
400            PabloAST * const negCond = triviallyFold(block->createNot(sel->getCondition()), block);
401            return triviallyFold(block->createOr(sel->getTrueExpr(), negCond), block);
402        }
403    } else if (LLVM_UNLIKELY(isa<Add>(stmt) || isa<Subtract>(stmt))) {
404       if (LLVM_UNLIKELY(isa<Integer>(stmt->getOperand(0)) && isa<Integer>(stmt->getOperand(1)))) {
405           const Integer * const int0 = cast<Integer>(stmt->getOperand(0));
406           const Integer * const int1 = cast<Integer>(stmt->getOperand(1));
407           Integer::IntTy result = 0;
408           if (isa<Add>(stmt)) {
409               result = int0->value() + int1->value();
410           } else {
411               result = int0->value() - int1->value();
412           }
413           return block->getInteger(result);
414       }
415    }
416    return nullptr;
417}
418
419/** ------------------------------------------------------------------------------------------------------------- *
420 * @brief isTrivial
421 *
422 * If this inner block is composed of only Boolean logic and Assign statements and there are fewer than 3
423 * statements, just add the statements in the inner block to the current block
424 ** ------------------------------------------------------------------------------------------------------------- */
425static bool isTrivial(const PabloBlock * const block) {
426    unsigned computations = 0;
427    for (const Statement * stmt : *block) {
428        switch (stmt->getClassTypeId()) {
429            case TypeId::And:
430            case TypeId::Or:
431            case TypeId::Xor:
432                if (++computations > 3) {
433                    return false;
434                }
435            case TypeId::Not:
436            case TypeId::Assign:
437                break;
438            default:
439                return false;
440        }
441    }
442    return true;
443}
444
445/** ------------------------------------------------------------------------------------------------------------- *
446 * @brief flatten
447 ** ------------------------------------------------------------------------------------------------------------- */
448static Statement * flatten(Branch * const br) {
449    Statement * stmt = br;
450    Statement * nested = br->getBody()->front();
451    while (nested) {
452        Statement * next = nested->removeFromParent();
453        nested->insertAfter(stmt);
454        stmt = nested;
455        nested = next;
456    }
457    return br->eraseFromParent();
458}
459
460/** ------------------------------------------------------------------------------------------------------------- *
461 * @brief isNonZero
462 ** ------------------------------------------------------------------------------------------------------------- */
463bool isNonZero(const PabloAST * const expr) const {
464    return isa<Ones>(expr) || std::find(mNonZero.begin(), mNonZero.end(), expr) != mNonZero.end();
465}
466
467/** ------------------------------------------------------------------------------------------------------------- *
468 * @brief strengthReduction
469 *
470 * Find and replace any Pablo operations with a less expensive equivalent operation whenever possible.
471 ** ------------------------------------------------------------------------------------------------------------- */
472void strengthReduction(PabloBlock * const block) {
473
474    Statement * stmt = block->front();
475    while (stmt) {
476        if (isa<Branch>(stmt)) {
477            strengthReduction(cast<Branch>(stmt)->getBody());
478        } else if (isa<Advance>(stmt)) {
479            Advance * adv = cast<Advance>(stmt);
480            if (LLVM_UNLIKELY(isa<Advance>(adv->getOperand(0)))) {
481                // Replace an Advance(Advance(x, n), m) with an Advance(x,n + m)
482                // Test whether this will generate a long advance and abort?
483                Advance * op = cast<Advance>(stmt->getOperand(0));
484                if (LLVM_UNLIKELY(op->getNumUses() == 1)) {
485                    adv->setOperand(0, op->getOperand(0));
486                    adv->setOperand(1, block->getInteger(adv->getAmount() + op->getAmount()));
487                    op->eraseFromParent(false);
488                }
489            }
490        } else if (LLVM_UNLIKELY(isa<ScanThru>(stmt))) {           
491            ScanThru * const outer = cast<ScanThru>(stmt);
492            if (LLVM_UNLIKELY(isa<Advance>(outer->getScanFrom()))) {
493                // Replace ScanThru(Advance(x,n),y) with ScanThru(Advance(x, n - 1), Advance(x, n - 1) | y), where Advance(x, 0) = x               
494                Advance * const inner = cast<Advance>(outer->getScanFrom());
495                if (LLVM_UNLIKELY(inner->getNumUses() == 1)) {
496                    PabloAST * stream = inner->getExpression();
497                    block->setInsertPoint(stmt);
498                    if (LLVM_UNLIKELY(inner->getAmount() != 1)) {
499                        stream = block->createAdvance(stream, block->getInteger(inner->getAmount() - 1));
500                    }
501                    stmt = outer->replaceWith(block->createAdvanceThenScanThru(stream, outer->getScanThru()));
502                    inner->eraseFromParent(false);
503                    continue;
504                }
505//            } else if (LLVM_UNLIKELY(isa<ScanThru>(outer->getScanFrom()))) {
506//                // Replace ScanThru(ScanThru(x, y), z) with ScanThru(x, y | z)
507//                // TODO: this transformation is valid if and only if there can be no instance of ...yzy... in the (y | z) stream
508//                // but that degree of reasoning is too complex to perform linearly here
509//                ScanThru * const inner = cast<ScanThru>(outer->getScanFrom());
510//                block->setInsertPoint(stmt);
511//                ScanThru * const scanThru = block->createScanThru(inner->getScanFrom(), block->createOr(inner->getScanThru(), outer->getScanThru()));
512//                stmt->replaceWith(scanThru);
513//                stmt = scanThru;
514//                continue;
515            } else if (LLVM_UNLIKELY(isa<And>(outer->getScanFrom()))) {
516                // Suppose B is an arbitrary bitstream and A = Advance(B, 1). ScanThru(B ∧ ¬A, B) will leave a marker on the position
517                // following the end of any run of 1-bits in B. But this is equivalent to computing A ∧ ¬B since A will have exactly
518                // one 1-bit past the end of any run of 1-bits in B.
519
520
521
522
523
524            }
525        } else if (LLVM_UNLIKELY(isa<ScanTo>(stmt))) {
526            ScanTo * scanTo = cast<ScanTo>(stmt);
527            if (LLVM_UNLIKELY(isa<Advance>(scanTo->getScanFrom()))) {
528                // Replace a ScanTo(Advance(x,n),y) with an ScanTo(Advance(x, n - 1), Advance(x, n - 1) | y), where Advance(x, 0) = x
529                Advance * adv = cast<Advance>(scanTo->getScanFrom());
530                if (LLVM_UNLIKELY(adv->getNumUses() == 1)) {
531                    PabloAST * stream = adv->getExpression();
532                    block->setInsertPoint(stmt);
533                    if (LLVM_UNLIKELY(adv->getAmount() != 1)) {
534                        stream = block->createAdvance(stream, block->getInteger(adv->getAmount() - 1));
535                    }
536                    stmt = scanTo->replaceWith(block->createAdvanceThenScanTo(stream, scanTo->getScanTo()));
537                    adv->eraseFromParent(false);
538                    continue;
539                }
540            }
541        }
542        stmt = stmt->getNextNode();
543    }
544}
545
546/** ------------------------------------------------------------------------------------------------------------- *
547 * @brief deadCodeElimination
548 ** ------------------------------------------------------------------------------------------------------------- */
549void deadCodeElimination(PabloBlock * const block) {
550
551    flat_set<PabloAST *> written;
552
553    for (Statement * stmt = block->back(), * prior; stmt; stmt = prior) {
554        prior = stmt->getPrevNode();
555        if (LLVM_UNLIKELY(stmt->getNumUses() == 0)) {
556            if (LLVM_UNLIKELY(isa<Branch>(stmt))) {
557                written.clear();
558                deadCodeElimination(cast<Branch>(stmt)->getBody());
559            } else if (LLVM_UNLIKELY(isa<Assign>(stmt))) {
560                // An Assign statement is locally dead whenever its variable is not read
561                // before being reassigned a value.
562                PabloAST * var = cast<Assign>(stmt)->getVariable();
563                if (LLVM_UNLIKELY(!written.insert(var).second)) {
564                    stmt->eraseFromParent();
565                }
566            } else {
567                stmt->eraseFromParent();
568            }
569        }
570    }
571}
572
573std::vector<const PabloAST *>       mNonZero;
574std::vector<const PabloBlock *>     mInScope;
575
576};
577
578/** ------------------------------------------------------------------------------------------------------------- *
579 * @brief optimize
580 ** ------------------------------------------------------------------------------------------------------------- */
581bool Simplifier::optimize(PabloKernel * kernel) {
582    PassContainer pc;
583    pc.run(kernel);
584    #ifndef NDEBUG
585    PabloVerifier::verify(kernel, "post-simplification");
586    #endif
587    return true;
588}
589
590}
Note: See TracBrowser for help on using the repository browser.