| #ifndef wasm_analysis_monotone_analyzer_impl_h | |
| #define wasm_analysis_monotone_analyzer_impl_h | |
| #include <iostream> | |
| #include <unordered_map> | |
| #include "monotone-analyzer.h" | |
| #include "support/unique_deferring_queue.h" | |
| namespace wasm::analysis { | |
| template<Lattice L, TransferFunction TxFn> | |
| inline MonotoneCFGAnalyzer<L, TxFn>::MonotoneCFGAnalyzer(L& lattice, | |
| TxFn& txfn, | |
| CFG& cfg) | |
| : lattice(lattice), txfn(txfn), cfg(cfg), | |
| states(cfg.size(), lattice.getBottom()) {} | |
| template<Lattice L, TransferFunction TxFn> | |
| inline void | |
| MonotoneCFGAnalyzer<L, TxFn>::evaluateFunctionEntry(Function* func) { | |
| txfn.evaluateFunctionEntry(func, states[0]); | |
| } | |
| template<Lattice L, TransferFunction TxFn> | |
| inline void MonotoneCFGAnalyzer<L, TxFn>::evaluateFunctionExit(Function* func) { | |
| for (size_t i = 0; i < cfg.size(); i++) { | |
| if (cfg[i].isExit()) { | |
| txfn.evaluateFunctionExit(func, states[i]); | |
| break; | |
| } | |
| } | |
| } | |
| template<Lattice L, TransferFunction TxFn> | |
| inline void MonotoneCFGAnalyzer<L, TxFn>::evaluate() { | |
| UniqueDeferredQueue<Index> worklist; | |
| // Start with all blocks on the work list. TODO: optimize the iteration order | |
| // using e.g. strongly-connected components. | |
| for (Index i = 0; i < cfg.size(); ++i) { | |
| worklist.push(i); | |
| } | |
| while (!worklist.empty()) { | |
| // The index of the block we will analyze. | |
| Index i = worklist.pop(); | |
| // Apply the transfer function to the input state to compute the output | |
| // state, then propagate the output state to the dependent blocks. | |
| auto state = states[i]; | |
| for (const auto* dep : txfn.transfer(cfg[i], state)) { | |
| // If the input state for the dependent block changes, we need to | |
| // re-analyze it. | |
| if (lattice.join(states[dep->getIndex()], state)) { | |
| worklist.push(dep->getIndex()); | |
| } | |
| } | |
| } | |
| } | |
| template<Lattice L, TransferFunction TxFn> | |
| inline void MonotoneCFGAnalyzer<L, TxFn>::collectResults() { | |
| for (Index i = 0, size = cfg.size(); i < size; ++i) { | |
| // The transfer function generates the final set of states and uses it to | |
| // produce useful information. For example, in reaching definitions | |
| // analysis, these final states are used to populate a mapping of | |
| // local.get's to a set of local.set's that affect its value. | |
| txfn.collectResults(cfg[i], states[i]); | |
| } | |
| } | |
| // Currently prints both the basic information and intermediate states of each | |
| // BlockState. | |
| template<Lattice L, TransferFunction TxFn> | |
| inline void MonotoneCFGAnalyzer<L, TxFn>::print(std::ostream& os) { | |
| os << "CFG Analyzer" << std::endl; | |
| for (Index i = 0, size = cfg.size(); i < size; ++i) { | |
| os << "CFG Block: " << cfg[i].getIndex() << std::endl; | |
| os << "Input State: "; | |
| states[i].print(os); | |
| for (auto& pred : cfg[i].preds()) { | |
| os << " " << pred->getIndex(); | |
| } | |
| os << std::endl << "Successors:"; | |
| for (auto& succ : cfg[i].succs()) { | |
| os << " " << succ->getIndex(); | |
| } | |
| os << "\n"; | |
| txfn.print(os, cfg[i], states[i]); | |
| } | |
| os << "End\n"; | |
| } | |
| } // namespace wasm::analysis | |
| #endif // wasm_analysis_monotone_analyzer_impl_h |