Skip to content

Commit 6cf2f82

Browse files
committed
SSA CFG: free up insts in unreachable blocks
1 parent 2bcd3b4 commit 6cf2f82

2 files changed

Lines changed: 44 additions & 1 deletion

File tree

libyul/backends/evm/ssa/transform/UnreachableBlockCleaner.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
#include <libyul/backends/evm/ssa/SSACFG.h>
2222

23+
#include <libsolutil/Visitor.h>
24+
25+
#include <cstdint>
2326
#include <deque>
2427
#include <vector>
2528

@@ -47,12 +50,53 @@ void transform::cleanUnreachableBlocks(SSACFG& _cfg)
4750
});
4851
}
4952

53+
auto& store = _cfg.instructionStore();
5054
for (SSACFG::BlockId blockId{0}; blockId.value < _cfg.numBlocks(); ++blockId.value)
5155
{
5256
auto& block = _cfg.block(blockId);
5357
if (reachable[blockId.value])
5458
std::erase_if(block.entries, [&](auto const& entry) { return !reachable[entry.value]; });
5559
else
60+
{
61+
for (InstId const id: block.instructions)
62+
store.tombstone(id);
5663
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);
57101
}
58102
}

libyul/backends/evm/ssa/transform/UnreachableBlockCleaner.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
// SPDX-License-Identifier: GPL-3.0
1818
/**
1919
* Removes unreachable blocks from an SSA CFG and cleans up entry lists referencing them.
20-
* Note that this invalidates ValueIds and InstIds pointing into the (unreachable) blocks.
2120
*/
2221
#pragma once
2322

0 commit comments

Comments
 (0)