Skip to content

Commit c6ed825

Browse files
authored
Merge pull request #15702 from ethereum/liveness_fixes
Small fixes for liveness
2 parents c91c204 + f0010d5 commit c6ed825

File tree

7 files changed

+75
-37
lines changed

7 files changed

+75
-37
lines changed

libyul/backends/evm/ControlFlow.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,8 @@ ControlFlowLiveness::ControlFlowLiveness(ControlFlow const& _controlFlow):
2626
mainLiveness(std::make_unique<SSACFGLiveness>(*_controlFlow.mainGraph)),
2727
functionLiveness(_controlFlow.functionGraphs | ranges::views::transform([](auto const& _cfg) { return std::make_unique<SSACFGLiveness>(*_cfg); }) | ranges::to<std::vector>)
2828
{ }
29+
30+
std::string ControlFlowLiveness::toDot() const
31+
{
32+
return controlFlow.get().toDot(this);
33+
}

libyul/backends/evm/ControlFlow.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ struct ControlFlowLiveness{
3434
std::reference_wrapper<ControlFlow const> controlFlow;
3535
std::unique_ptr<SSACFGLiveness> mainLiveness;
3636
std::vector<std::unique_ptr<SSACFGLiveness>> functionLiveness;
37+
38+
std::string toDot() const;
3739
};
3840

3941
struct ControlFlow

libyul/backends/evm/SSACFGLiveness.cpp

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,29 @@ constexpr auto literalsFilter(SSACFG const& _cfg)
3737
}
3838
}
3939

40+
std::set<SSACFG::ValueId> SSACFGLiveness::blockExitValues(SSACFG::BlockId const& _blockId) const
41+
{
42+
std::set<SSACFG::ValueId> result;
43+
util::GenericVisitor exitVisitor {
44+
[](SSACFG::BasicBlock::MainExit const&) {},
45+
[&](SSACFG::BasicBlock::FunctionReturn const& _functionReturn) {
46+
result += _functionReturn.returnValues | ranges::views::filter(literalsFilter(m_cfg));
47+
},
48+
[&](SSACFG::BasicBlock::JumpTable const& _jt) {
49+
if (literalsFilter(m_cfg)(_jt.value))
50+
result.emplace(_jt.value);
51+
},
52+
[](SSACFG::BasicBlock::Jump const&) {},
53+
[&](SSACFG::BasicBlock::ConditionalJump const& _conditionalJump) {
54+
if (literalsFilter(m_cfg)(_conditionalJump.condition))
55+
result.emplace(_conditionalJump.condition);
56+
},
57+
[](SSACFG::BasicBlock::Terminated const&) {}
58+
};
59+
std::visit(exitVisitor, m_cfg.block(_blockId).exit);
60+
return result;
61+
}
62+
4063
SSACFGLiveness::SSACFGLiveness(SSACFG const& _cfg):
4164
m_cfg(_cfg),
4265
m_topologicalSort(_cfg),
@@ -70,12 +93,7 @@ void SSACFGLiveness::runDagDfs()
7093
{
7194
auto const& info = m_cfg.valueInfo(phi);
7295
yulAssert(std::holds_alternative<SSACFG::PhiValue>(info), "value info of phi wasn't PhiValue");
73-
auto const& entries = m_cfg.block(std::get<SSACFG::PhiValue>(info).block).entries;
74-
// this is getting the argument index of the phi function corresponding to the path going
75-
// through "blockId", ie, the currently handled block
76-
auto const it = entries.find(blockId);
77-
yulAssert(it != entries.end());
78-
auto const argIndex = static_cast<size_t>(std::distance(entries.begin(), it));
96+
auto const argIndex = m_cfg.phiArgumentIndex(blockId, _successor);
7997
yulAssert(argIndex < std::get<SSACFG::PhiValue>(info).arguments.size());
8098
auto const arg = std::get<SSACFG::PhiValue>(info).arguments.at(argIndex);
8199
if (!std::holds_alternative<SSACFG::LiteralValue>(m_cfg.valueInfo(arg)))
@@ -103,23 +121,7 @@ void SSACFGLiveness::runDagDfs()
103121
// for each program point p in B, backwards, do:
104122
{
105123
// add value ids to the live set that are used in exit blocks
106-
util::GenericVisitor exitVisitor {
107-
[](SSACFG::BasicBlock::MainExit const&) {},
108-
[&](SSACFG::BasicBlock::FunctionReturn const& _functionReturn) {
109-
live += _functionReturn.returnValues | ranges::views::filter(literalsFilter(m_cfg));
110-
},
111-
[&](SSACFG::BasicBlock::JumpTable const& _jt) {
112-
if (literalsFilter(m_cfg)(_jt.value))
113-
live.emplace(_jt.value);
114-
},
115-
[](SSACFG::BasicBlock::Jump const&) {},
116-
[&](SSACFG::BasicBlock::ConditionalJump const& _conditionalJump) {
117-
if (literalsFilter(m_cfg)(_conditionalJump.condition))
118-
live.emplace(_conditionalJump.condition);
119-
},
120-
[](SSACFG::BasicBlock::Terminated const&) {}
121-
};
122-
std::visit(exitVisitor, block.exit);
124+
live += blockExitValues(blockId);
123125

124126
for (auto const& op: block.operations | ranges::views::reverse)
125127
{
@@ -163,12 +165,13 @@ void SSACFGLiveness::fillOperationsLiveOut()
163165
{
164166
for (size_t blockIdValue = 0; blockIdValue < m_cfg.numBlocks(); ++blockIdValue)
165167
{
166-
auto const& operations = m_cfg.block(SSACFG::BlockId{blockIdValue}).operations;
168+
SSACFG::BlockId const blockId{blockIdValue};
169+
auto const& operations = m_cfg.block(blockId).operations;
167170
auto& liveOuts = m_operationLiveOuts[blockIdValue];
168171
liveOuts.resize(operations.size());
169172
if (!operations.empty())
170173
{
171-
auto live = m_liveOuts[blockIdValue];
174+
auto live = m_liveOuts[blockIdValue] + blockExitValues(blockId);
172175
auto rit = liveOuts.rbegin();
173176
for (auto const& op: operations | ranges::views::reverse)
174177
{

libyul/backends/evm/SSACFGLiveness.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class SSACFGLiveness
4747
void runDagDfs();
4848
void runLoopTreeDfs(size_t _loopHeader);
4949
void fillOperationsLiveOut();
50+
std::set<SSACFG::ValueId> blockExitValues(SSACFG::BlockId const& _blockId) const;
5051

5152
SSACFG const& m_cfg;
5253
ForwardSSACFGTopologicalSort m_topologicalSort;

libyul/backends/evm/SSACFGTopologicalSort.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ ForwardSSACFGTopologicalSort::ForwardSSACFGTopologicalSort(SSACFG const& _cfg):
2828
yulAssert(m_cfg.entry.value == 0);
2929
m_preOrder.reserve(m_cfg.numBlocks());
3030
m_postOrder.reserve(m_cfg.numBlocks());
31-
for (size_t id = 0; id < m_cfg.numBlocks(); ++id)
32-
{
33-
if (!m_explored[id])
34-
dfs(id);
35-
}
31+
dfs(0);
3632

3733
for (auto const& [v1, v2]: m_potentialBackEdges)
3834
if (ancestor(v2, v1))

libyul/backends/evm/SSAControlFlowGraph.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,25 @@ class SSACFGPrinter
7777
);
7878
}
7979

80+
static std::string escape(std::string_view const str)
81+
{
82+
using namespace std::literals;
83+
static constexpr auto replacements = std::array{std::make_tuple('$', "_d_")};
84+
std::stringstream ss;
85+
for (auto const c: str)
86+
{
87+
auto const it = std::find_if(replacements.begin(), replacements.end(), [c](auto const& replacement)
88+
{
89+
return std::get<0>(replacement) == c;
90+
});
91+
if (it != replacements.end())
92+
ss << std::get<1>(*it);
93+
else
94+
ss << c;
95+
}
96+
return ss.str();
97+
}
98+
8099
std::string formatBlockHandle(SSACFG::BlockId const& _id) const
81100
{
82101
return fmt::format("Block{}_{}", m_functionIndex, _id.value);
@@ -157,7 +176,7 @@ class SSACFGPrinter
157176
);
158177
m_result << fmt::format(
159178
"{}({})\\l\\\n",
160-
label,
179+
escape(label),
161180
fmt::join(operation.inputs | ranges::views::transform(valueToString), ", ")
162181
);
163182
}
@@ -247,15 +266,15 @@ class SSACFGPrinter
247266

248267
void printFunction(Scope::Function const& _fun)
249268
{
250-
static auto constexpr returnsTransform = [](auto const& functionReturnValue) { return functionReturnValue.get().name.str(); };
269+
static auto constexpr returnsTransform = [](auto const& functionReturnValue) { return escape(functionReturnValue.get().name.str()); };
251270
static auto constexpr argsTransform = [](auto const& arg) { return fmt::format("v{}", std::get<1>(arg).value); };
252-
m_result << "FunctionEntry_" << _fun.name.str() << "_" << m_cfg.entry.value << " [label=\"";
271+
m_result << "FunctionEntry_" << escape(_fun.name.str()) << "_" << m_cfg.entry.value << " [label=\"";
253272
if (!m_cfg.returns.empty())
254-
m_result << fmt::format("function {0}:\n {1} := {0}({2})", _fun.name.str(), fmt::join(m_cfg.returns | ranges::views::transform(returnsTransform), ", "), fmt::join(m_cfg.arguments | ranges::views::transform(argsTransform), ", "));
273+
m_result << fmt::format("function {0}:\n {1} := {0}({2})", escape(_fun.name.str()), fmt::join(m_cfg.returns | ranges::views::transform(returnsTransform), ", "), fmt::join(m_cfg.arguments | ranges::views::transform(argsTransform), ", "));
255274
else
256-
m_result << fmt::format("function {0}:\n {0}({1})", _fun.name.str(), fmt::join(m_cfg.arguments | ranges::views::transform(argsTransform), ", "));
275+
m_result << fmt::format("function {0}:\n {0}({1})", escape(_fun.name.str()), fmt::join(m_cfg.arguments | ranges::views::transform(argsTransform), ", "));
257276
m_result << "\"];\n";
258-
m_result << "FunctionEntry_" << _fun.name.str() << "_" << m_cfg.entry.value << " -> Block" << m_functionIndex << "_" << m_cfg.entry.value << ";\n";
277+
m_result << "FunctionEntry_" << escape(_fun.name.str()) << "_" << m_cfg.entry.value << " -> Block" << m_functionIndex << "_" << m_cfg.entry.value << ";\n";
259278
printBlock(m_cfg.entry);
260279
}
261280

libyul/backends/evm/SSAControlFlowGraph.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class SSACFG
7676
langutil::DebugData::ConstPtr debugData;
7777
std::reference_wrapper<Scope::Function const> function;
7878
std::reference_wrapper<FunctionCall const> call;
79-
bool const canContinue = true;
79+
bool canContinue;
8080
};
8181

8282
struct Operation {
@@ -162,6 +162,10 @@ class SSACFG
162162
};
163163
struct UnreachableValue {};
164164
using ValueInfo = std::variant<UnreachableValue, VariableValue, LiteralValue, PhiValue>;
165+
bool isLiteralValue(ValueId const _var) const
166+
{
167+
return std::holds_alternative<LiteralValue>(valueInfo(_var));
168+
}
165169
ValueInfo& valueInfo(ValueId const _var)
166170
{
167171
return m_valueInfos.at(_var.value);
@@ -208,6 +212,14 @@ class SSACFG
208212
return it->second;
209213
}
210214

215+
size_t phiArgumentIndex(BlockId const _source, BlockId const _target) const
216+
{
217+
auto const& targetBlock = block(_target);
218+
auto idx = util::findOffset(targetBlock.entries, _source);
219+
yulAssert(idx, fmt::format("Target block {} not found as entry in one of the exits of the current block {}.", _target.value, _source.value));
220+
return *idx;
221+
}
222+
211223
std::string toDot(
212224
bool _includeDiGraphDefinition=true,
213225
std::optional<size_t> _functionIndex=std::nullopt,

0 commit comments

Comments
 (0)