#ifndef wasm_analysis_monotone_analyzer_h #define wasm_analysis_monotone_analyzer_h #include #include #include #include "cfg.h" #include "lattice.h" namespace wasm::analysis { // A node which contains all the lattice states for a given CFG node. template struct BlockState { static_assert(is_lattice); // CFG node corresponding to this state block. const BasicBlock* cfgBlock; // State at which the analysis flow starts for a CFG. For instance, the ending // state for backward analysis, or the beginning state for forward analysis. typename Lattice::Element inputState; // All states are set to the bottom lattice element in this constructor. BlockState(const BasicBlock* underlyingBlock, Lattice& lattice); // Prints out BlockState information, but not any intermediate states. void print(std::ostream& os); }; // A transfer function using a lattice is required to have the // following methods: // Lattice::Element transfer(const BasicBlock* cfgBlock, Lattice::Element& // inputState); // This function takes in a pointer to a CFG BasicBlock and the input state // associated with it and modifies the input state in-place into the ouptut // state for the basic block by applying the analysis transfer function to each // expression in the CFG BasicBlock. Starting with the input state, the transfer // function is used to change the state to new intermediate states based on each // expression until we reach the output state. The outuput state will be // propagated to dependents of the CFG BasicBlock by the worklist algorithm in // MonotoneCFGAnalyzer. template constexpr bool has_transfer = std::is_invocable_r::value; // void enqueueWorklist(CFG&, std::queue& value); // Loads CFG BasicBlocks in some order into the worklist. Custom specifying the // order for each analysis brings performance savings. For example, when doing a // backward analysis, loading the BasicBlocks in reverse order will lead to less // state propagations, and therefore better performance. The opposite is true // for a forward analysis. template constexpr bool has_enqueueWorklist = std::is_invocable_r&>::value; // BasicBlock::BasicBlockIterable getDependents(const BasicBlock* currBlock); // Returns an iterable to the CFG BasicBlocks which depend on currBlock for // information (e.g. predecessors in a backward analysis). Used to select which // blocks to propagate to after applying the transfer function to a block. template constexpr bool has_getDependents = std::is_invocable_r::value; // Combined TransferFunction assertions. template constexpr bool is_TransferFunction = has_transfer&& has_enqueueWorklist&& has_getDependents; template class MonotoneCFGAnalyzer { static_assert(is_lattice); static_assert(is_TransferFunction); Lattice& lattice; TransferFunction& transferFunction; CFG& cfg; std::vector> stateBlocks; public: // Will constuct BlockState objects corresponding to BasicBlocks from the // given CFG. MonotoneCFGAnalyzer(Lattice& lattice, TransferFunction& transferFunction, CFG& cfg); // Runs the worklist algorithm to compute the states for the BlockState graph. void evaluate(); // This modifies the state of the CFG's entry block, with function // information. This cannot be done otherwise in a forward analysis, as the // entry block depends on no other blocks, and hence cannot be changed by // them. void evaluateFunctionEntry(Function* func); // Iterates over all of the BlockStates after evaluate() is completed for the // transfer function to collect the finalized intermediate states from each // block. For instance, the reaching definitions analysis transfer functions // will take the final states and use it to populate a map of local.get's to // sets of local.set's which affect it. void collectResults(); // The analyzer is run in two distinct phases. First evaluate() runs the // worklist algorithm to obtain a solution. Then collectResults() iterates // over the vector of BlockState's, allowing the transfer function to access // the final states to and turn them into some result. void evaluateAndCollectResults() { evaluate(); collectResults(); } // Prints out all BlockStates in this analyzer. void print(std::ostream& os); }; } // namespace wasm::analysis #include "monotone-analyzer-impl.h" #endif // wasm_analysis_monotone_analyzer_h