|
20 | 20 |
|
21 | 21 | #include <libyul/backends/evm/ssa/SSACFG.h> |
22 | 22 |
|
| 23 | +#include <libsolutil/Visitor.h> |
| 24 | + |
| 25 | +#include <cstdint> |
23 | 26 | #include <deque> |
24 | 27 | #include <vector> |
25 | 28 |
|
@@ -47,12 +50,53 @@ void transform::cleanUnreachableBlocks(SSACFG& _cfg) |
47 | 50 | }); |
48 | 51 | } |
49 | 52 |
|
| 53 | + auto& store = _cfg.instructionStore(); |
50 | 54 | for (SSACFG::BlockId blockId{0}; blockId.value < _cfg.numBlocks(); ++blockId.value) |
51 | 55 | { |
52 | 56 | auto& block = _cfg.block(blockId); |
53 | 57 | if (reachable[blockId.value]) |
54 | 58 | std::erase_if(block.entries, [&](auto const& entry) { return !reachable[entry.value]; }); |
55 | 59 | else |
| 60 | + { |
| 61 | + for (InstId const id: block.instructions) |
| 62 | + store.tombstone(id); |
56 | 63 | block = {}; |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + // Post-condition: every reference reachable from a live block resolves to a |
| 68 | + // non-Tombstoned slot. Catches CFG-construction bugs and any future pass that |
| 69 | + // fails to drop a stale cross-block reference. |
| 70 | + for (SSACFG::BlockId blockId{0}; blockId.value < _cfg.numBlocks(); ++blockId.value) |
| 71 | + { |
| 72 | + if (!reachable[blockId.value]) |
| 73 | + continue; |
| 74 | + auto const& block = _cfg.block(blockId); |
| 75 | + auto const checkRef = [&](InstId const _ref) { |
| 76 | + yulAssert(_ref.hasValue()); |
| 77 | + yulAssert( |
| 78 | + store.kindOf(_ref) != InstOpcode::Tombstone, |
| 79 | + "reachable IR references a tombstoned Inst" |
| 80 | + ); |
| 81 | + }; |
| 82 | + for (InstId const id: block.instructions) |
| 83 | + { |
| 84 | + auto const& inst = store.inst(id); |
| 85 | + yulAssert(inst.opcode != InstOpcode::Tombstone); |
| 86 | + for (InstId const input: inst.inputs) |
| 87 | + checkRef(input); |
| 88 | + if (inst.isUpsilon()) |
| 89 | + checkRef(_cfg.upsilonPhi(id)); |
| 90 | + } |
| 91 | + std::visit(solidity::util::GenericVisitor{ |
| 92 | + [&](SSACFG::BasicBlock::ConditionalJump const& _c) { checkRef(_c.condition); }, |
| 93 | + [&](SSACFG::BasicBlock::FunctionReturn const& _r) { |
| 94 | + for (InstId const v: _r.returnValues) |
| 95 | + checkRef(v); |
| 96 | + }, |
| 97 | + [](SSACFG::BasicBlock::Jump const&) {}, |
| 98 | + [](SSACFG::BasicBlock::MainExit const&) {}, |
| 99 | + [](SSACFG::BasicBlock::Terminated const&) {} |
| 100 | + }, block.exit); |
57 | 101 | } |
58 | 102 | } |
0 commit comments