Skip to content

Commit 9794963

Browse files
tlivelyradekdoulik
authored andcommitted
[analysis] Make it easier to implement a transfer function (WebAssembly#6077)
Combine the `transfer` and `getDependents` methods of a transfer function so that a transfer function only has to implement `transfer`, which now returns a range of basic blocks that may need to be re-analyzed. To make it easier to implement the returned basic block range, change the requirement so that it provides iterators to `const BasicBlock*` rather than `BasicBlock`. This allows us to entirely remove cfg-impl.h.
1 parent 70b4152 commit 9794963

File tree

6 files changed

+28
-190
lines changed

6 files changed

+28
-190
lines changed

src/analysis/cfg-impl.h

Lines changed: 0 additions & 149 deletions
This file was deleted.

src/analysis/cfg.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,19 @@ void CFG::print(std::ostream& os, Module* wasm) const {
8080

8181
void BasicBlock::print(std::ostream& os, Module* wasm, size_t start) const {
8282
os << ";; preds: [";
83-
for (auto& pred : preds()) {
84-
if (&pred != &*preds().begin()) {
83+
for (const auto* pred : preds()) {
84+
if (pred != *preds().begin()) {
8585
os << ", ";
8686
}
87-
os << pred.index;
87+
os << pred->index;
8888
}
8989
os << "], succs: [";
9090

91-
for (auto& succ : succs()) {
92-
if (&succ != &*succs().begin()) {
91+
for (const auto* succ : succs()) {
92+
if (succ != *succs().begin()) {
9393
os << ", ";
9494
}
95-
os << succ.index;
95+
os << succ->index;
9696
}
9797
os << "]\n";
9898

src/analysis/cfg.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,8 @@ struct BasicBlock {
4444
reverse_iterator rbegin() const { return insts.rbegin(); }
4545
reverse_iterator rend() const { return insts.rend(); }
4646

47-
// Iterables for predecessor and successor blocks.
48-
struct BasicBlockIterable;
49-
BasicBlockIterable preds() const;
50-
BasicBlockIterable succs() const;
47+
const std::vector<const BasicBlock*>& preds() const { return predecessors; }
48+
const std::vector<const BasicBlock*>& succs() const { return successors; }
5149

5250
void print(std::ostream& os, Module* wasm = nullptr, size_t start = 0) const;
5351

@@ -56,8 +54,8 @@ struct BasicBlock {
5654
private:
5755
Index index;
5856
std::vector<Expression*> insts;
59-
std::vector<BasicBlock*> predecessors;
60-
std::vector<BasicBlock*> successors;
57+
std::vector<const BasicBlock*> predecessors;
58+
std::vector<const BasicBlock*> successors;
6159

6260
friend CFG;
6361
};
@@ -109,6 +107,4 @@ struct CFGBlockIndexes {
109107

110108
} // namespace wasm::analysis
111109

112-
#include "cfg-impl.h"
113-
114110
#endif // wasm_analysis_cfg_h

src/analysis/monotone-analyzer-impl.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,13 @@ inline void MonotoneCFGAnalyzer<L, TxFn>::evaluate() {
3737
Index i = worklist.pop();
3838

3939
// Apply the transfer function to the input state to compute the output
40-
// state for the block.
40+
// state, then propagate the output state to the dependent blocks.
4141
auto state = states[i];
42-
txfn.transfer(cfg[i], state);
43-
44-
// Propagate state to the dependent blocks.
45-
for (auto& dep : txfn.getDependents(cfg[i])) {
42+
for (const auto* dep : txfn.transfer(cfg[i], state)) {
4643
// If the input state for the dependent block changes, we need to
4744
// re-analyze it.
48-
if (lattice.join(states[dep.getIndex()], state)) {
49-
worklist.push(dep.getIndex());
45+
if (lattice.join(states[dep->getIndex()], state)) {
46+
worklist.push(dep->getIndex());
5047
}
5148
}
5249
}
@@ -73,11 +70,11 @@ inline void MonotoneCFGAnalyzer<L, TxFn>::print(std::ostream& os) {
7370
os << "Input State: ";
7471
states[i].print(os);
7572
for (auto& pred : cfg[i].preds()) {
76-
os << " " << pred.getIndex();
73+
os << " " << pred->getIndex();
7774
}
7875
os << std::endl << "Successors:";
7976
for (auto& succ : cfg[i].succs()) {
80-
os << " " << succ.getIndex();
77+
os << " " << succ->getIndex();
8178
}
8279
os << "\n";
8380
txfn.print(os, cfg[i], states[i]);

src/analysis/transfer-function.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,15 @@ namespace wasm::analysis {
3232
template<typename T>
3333
concept BasicBlockInputRange =
3434
std::ranges::input_range<T> &&
35-
std::is_same<std::ranges::range_value_t<T>, BasicBlock>::value;
35+
std::is_same<std::ranges::range_value_t<T>, const BasicBlock*>::value;
3636

3737
template<typename TxFn, typename L>
3838
concept TransferFunctionImpl = requires(
3939
TxFn& txfn, const CFG& cfg, const BasicBlock& bb, typename L::Element& elem) {
4040
// Apply the transfer function to update a lattice element with information
41-
// from a basic block.
42-
{ txfn.transfer(bb, elem) } noexcept -> std::same_as<void>;
43-
// Get a range over the basic blocks that depend on the given block.
44-
{ txfn.getDependents(bb) } noexcept -> BasicBlockInputRange;
41+
// from a basic block. Return an object that can be iterated over to get the
42+
// basic blocks that may need to be re-analyzed.
43+
{ txfn.transfer(bb, elem) } noexcept -> BasicBlockInputRange;
4544
};
4645

4746
#define TransferFunction TransferFunctionImpl<L>

src/analysis/visitor-transfer-function.h

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,11 @@ struct VisitorTransferFunc : public Visitor<SubType> {
3434
bool collectingResults = false;
3535

3636
public:
37-
// Returns an iterable to all the BasicBlocks which depend on currBlock for
38-
// information.
39-
BasicBlock::BasicBlockIterable
40-
getDependents(const BasicBlock& currBlock) noexcept {
41-
if constexpr (Direction == AnalysisDirection::Backward) {
42-
return currBlock.preds();
43-
} else {
44-
return currBlock.succs();
45-
}
46-
}
47-
4837
// Executes the transfer function on all the expressions of the corresponding
4938
// CFG node, starting with the node's input state, and changes the input state
5039
// to the final output state of the node in place.
51-
void transfer(const BasicBlock& bb,
52-
typename L::Element& inputState) noexcept {
40+
const std::vector<const BasicBlock*>&
41+
transfer(const BasicBlock& bb, typename L::Element& inputState) noexcept {
5342
// If the block is empty, we propagate the state by inputState =
5443
// outputState.
5544

@@ -64,6 +53,12 @@ struct VisitorTransferFunc : public Visitor<SubType> {
6453
}
6554
}
6655
currState = nullptr;
56+
57+
if constexpr (Direction == AnalysisDirection::Backward) {
58+
return bb.preds();
59+
} else {
60+
return bb.succs();
61+
}
6762
}
6863

6964
// This is for collecting results after solving an analysis. Implemented in

0 commit comments

Comments
 (0)