source: icGREP/icgrep-devel/icgrep/pablo/analysis/pabloverifier.cpp @ 4775

Last change on this file since 4775 was 4775, checked in by nmedfort, 4 years ago

Work towards testing reassociation + multiplexing.

File size: 3.5 KB
Line 
1#include "pabloverifier.hpp"
2#include <pablo/function.h>
3#include <pablo/codegenstate.h>
4#include <pablo/printer_pablos.h>
5#include <iostream>
6#include <boost/container/flat_set.hpp>
7
8namespace pablo {
9
10struct OrderingVerifier {
11    OrderingVerifier() : mParent(nullptr) {}
12    OrderingVerifier(const OrderingVerifier & parent) : mParent(&parent) {}
13    bool count(const PabloAST * expr) const {
14        if (mSet.count(expr)) {
15            return true;
16        } else if (mParent) {
17            return mParent->count(expr);
18        }
19        return false;
20    }
21    void insert(const PabloAST * expr) {
22        mSet.insert(expr);
23    }
24private:
25    const OrderingVerifier * const mParent;
26    boost::container::flat_set<const PabloAST *> mSet;
27};
28
29void isTopologicallyOrdered(const PabloBlock & block, const OrderingVerifier & parent, const bool ignoreUnusedStatements) {
30    OrderingVerifier ov(parent);
31    const Statement * previousStatement = nullptr;
32    for (const Statement * stmt : block) {
33        if (stmt->getPrevNode() != previousStatement) {
34            // TODO: make this actually test whether the operand is ever defined,
35            // or if it was defined in a scope that cannot be reached?
36            std::string tmp;
37            raw_string_ostream str(tmp);
38            PabloPrinter::print(stmt, "PabloVerifier: ", str);
39            str << " is not preceeded by the expected statement!";
40            throw std::runtime_error(str.str());
41        }
42        previousStatement = stmt;
43        if (stmt->getNumUses() == 0 && ignoreUnusedStatements) {
44            continue;
45        }
46        if (LLVM_UNLIKELY(isa<While>(stmt))) {
47            isTopologicallyOrdered(cast<While>(stmt)->getBody(), ov, ignoreUnusedStatements);
48            for (const Next * var : cast<While>(stmt)->getVariants()) {
49                ov.insert(var);
50            }
51        }
52        for (unsigned i = 0; i != stmt->getNumOperands(); ++i) {
53            const PabloAST * op = stmt->getOperand(i);
54            if ((isa<Statement>(op) || isa<Var>(op)) && ov.count(op) == false) {
55                // TODO: make this actually test whether the operand is ever defined,
56                // or if it was defined in a scope that cannot be reached?
57                std::string tmp;
58                raw_string_ostream str(tmp);
59                str << "PabloVerifier: function is not topologically ordered! ";
60                PabloPrinter::print(stmt->getOperand(i), str);
61                PabloPrinter::print(stmt, " was used before definition by ", str);
62                throw std::runtime_error(str.str());
63            }
64        }
65        ov.insert(stmt);
66        if (LLVM_UNLIKELY(isa<If>(stmt))) {
67            isTopologicallyOrdered(cast<If>(stmt)->getBody(), ov, ignoreUnusedStatements);
68            for (const Assign * def : cast<If>(stmt)->getDefined()) {
69                ov.insert(def);
70            }
71        }
72    }
73}
74
75void isTopologicallyOrdered(const PabloFunction & function, const bool ignoreUnusedStatements) {
76    OrderingVerifier ov;
77    for (unsigned i = 0; i != function.getNumOfParameters(); ++i) {
78        ov.insert(function.getParameter(i));
79    }
80    isTopologicallyOrdered(function.getEntryBlock(), ov, ignoreUnusedStatements);
81}
82
83void PabloVerifier::verify(const PabloFunction & function, const bool ignoreUnusedStatements) {
84    try {
85        isTopologicallyOrdered(function, ignoreUnusedStatements);
86    } catch(std::runtime_error err) {
87        raw_os_ostream out(std::cerr);
88        PabloPrinter::print(function.getEntryBlock().statements(), out);
89        out.flush();
90        throw err;
91    }
92}
93
94}
Note: See TracBrowser for help on using the repository browser.