Skip to content

Commit cd9ca4f

Browse files
committed
SSACFG: Use variables also for literals that are function arguments
1 parent d6a396e commit cd9ca4f

File tree

15 files changed

+2489
-806
lines changed

15 files changed

+2489
-806
lines changed

libyul/YulStack.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,15 +394,15 @@ Json YulStack::cfgJson() const
394394
yulAssert(m_parserResult->analysisInfo, "");
395395
// FIXME: we should not regenerate the cfg, but for now this is sufficient for testing purposes
396396
auto exportCFGFromObject = [&](Object const& _object) -> Json {
397-
// with this set to `true`, assignments of the type `let x := 42` are preserved and added as assignment
398-
// operations to the control flow graphs
399-
bool constexpr keepLiteralAssignments = true;
397+
// with this set to `false`, all literals get their own variable assignments (except for immediate literal
398+
// arguments of builtins)
399+
bool constexpr treatLiteralsAsPushConstants = false;
400400
// NOTE: The block Ids are reset for each object
401401
std::unique_ptr<ControlFlow> controlFlow = SSAControlFlowGraphBuilder::build(
402402
*_object.analysisInfo,
403403
languageToDialect(m_language, m_evmVersion, m_eofVersion),
404404
_object.code()->root(),
405-
keepLiteralAssignments
405+
treatLiteralsAsPushConstants
406406
);
407407
std::unique_ptr<ControlFlowLiveness> liveness = std::make_unique<ControlFlowLiveness>(*controlFlow);
408408
YulControlFlowGraphExporter exporter(*controlFlow, liveness.get());

libyul/backends/evm/SSAControlFlowGraphBuilder.cpp

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <libsolutil/StringUtils.h>
3232
#include <libsolutil/Visitor.h>
3333

34+
#include <range/v3/algorithm/find_if.hpp>
3435
#include <range/v3/algorithm/replace.hpp>
3536
#include <range/v3/range/conversion.hpp>
3637
#include <range/v3/view/drop_last.hpp>
@@ -52,28 +53,28 @@ SSAControlFlowGraphBuilder::SSAControlFlowGraphBuilder(
5253
AsmAnalysisInfo const& _analysisInfo,
5354
ControlFlowSideEffectsCollector const& _sideEffects,
5455
Dialect const& _dialect,
55-
bool _keepLiteralAssignments
56+
bool _literalsAsPushConstants
5657
):
5758
m_controlFlow(_controlFlow),
5859
m_graph(_graph),
5960
m_info(_analysisInfo),
6061
m_sideEffects(_sideEffects),
6162
m_dialect(_dialect),
62-
m_keepLiteralAssignments(_keepLiteralAssignments)
63+
m_literalsAsPushConstants(_literalsAsPushConstants)
6364
{
6465
}
6566

6667
std::unique_ptr<ControlFlow> SSAControlFlowGraphBuilder::build(
6768
AsmAnalysisInfo const& _analysisInfo,
6869
Dialect const& _dialect,
6970
Block const& _block,
70-
bool _keepLiteralAssignments
71+
bool _literalsAsPushConstants
7172
)
7273
{
7374
ControlFlowSideEffectsCollector sideEffects(_dialect, _block);
7475

7576
auto controlFlow = std::make_unique<ControlFlow>();
76-
SSAControlFlowGraphBuilder builder(*controlFlow, *controlFlow->mainGraph, _analysisInfo, sideEffects, _dialect, _keepLiteralAssignments);
77+
SSAControlFlowGraphBuilder builder(*controlFlow, *controlFlow->mainGraph, _analysisInfo, sideEffects, _dialect, _literalsAsPushConstants);
7778
builder.m_currentBlock = controlFlow->mainGraph->makeBlock(debugDataOf(_block));
7879
builder.sealBlock(builder.m_currentBlock);
7980
builder(_block);
@@ -86,7 +87,6 @@ std::unique_ptr<ControlFlow> SSAControlFlowGraphBuilder::build(
8687

8788
SSACFG::ValueId SSAControlFlowGraphBuilder::tryRemoveTrivialPhi(SSACFG::ValueId _phi)
8889
{
89-
// TODO: double-check if this is sane
9090
auto const* phiInfo = std::get_if<SSACFG::PhiValue>(&m_graph.valueInfo(_phi));
9191
yulAssert(phiInfo);
9292
yulAssert(blockInfo(phiInfo->block).sealed);
@@ -190,8 +190,8 @@ void SSAControlFlowGraphBuilder::cleanUnreachable()
190190

191191
std::set<SSACFG::ValueId> maybeTrivialPhi;
192192
for (auto it = block.entries.begin(); it != block.entries.end();)
193-
if (reachabilityCheck.visited.count(*it))
194-
it++;
193+
if (reachabilityCheck.visited.contains(*it))
194+
++it;
195195
else
196196
it = block.entries.erase(it);
197197
for (auto phi: block.phis)
@@ -211,10 +211,7 @@ void SSAControlFlowGraphBuilder::cleanUnreachable()
211211
}
212212
}
213213

214-
void SSAControlFlowGraphBuilder::buildFunctionGraph(
215-
Scope::Function const* _function,
216-
FunctionDefinition const* _functionDefinition
217-
)
214+
void SSAControlFlowGraphBuilder::buildFunctionGraph(Scope::Function const* _function, FunctionDefinition const* _functionDefinition)
218215
{
219216
m_controlFlow.functionGraphs.emplace_back(std::make_unique<SSACFG>());
220217
auto& cfg = *m_controlFlow.functionGraphs.back();
@@ -240,7 +237,7 @@ void SSAControlFlowGraphBuilder::buildFunctionGraph(
240237
cfg.arguments = arguments;
241238
cfg.returns = returns;
242239

243-
SSAControlFlowGraphBuilder builder(m_controlFlow, cfg, m_info, m_sideEffects, m_dialect, m_keepLiteralAssignments);
240+
SSAControlFlowGraphBuilder builder(m_controlFlow, cfg, m_info, m_sideEffects, m_dialect, m_literalsAsPushConstants);
244241
builder.m_currentBlock = cfg.entry;
245242
builder.m_functionDefinitions = m_functionDefinitions;
246243
for (auto&& [var, varId]: cfg.arguments)
@@ -255,6 +252,19 @@ void SSAControlFlowGraphBuilder::buildFunctionGraph(
255252
builder.cleanUnreachable();
256253
}
257254

255+
SSACFG::ValueId SSAControlFlowGraphBuilder::moveLiteralToVariable(SSACFG::ValueId const _value)
256+
{
257+
yulAssert(!m_literalsAsPushConstants);
258+
yulAssert(m_graph.isLiteralValue(_value));
259+
SSACFG::Operation assignment{
260+
.outputs = {m_graph.newVariable(m_currentBlock)},
261+
.kind = SSACFG::LiteralAssignment{},
262+
.inputs = {_value}
263+
};
264+
currentBlock().operations.emplace_back(assignment);
265+
return assignment.outputs.back();
266+
}
267+
258268
void SSAControlFlowGraphBuilder::operator()(ExpressionStatement const& _expressionStatement)
259269
{
260270
auto const* functionCall = std::get_if<FunctionCall>(&_expressionStatement.expression);
@@ -541,16 +551,8 @@ void SSAControlFlowGraphBuilder::assign(std::vector<std::reference_wrapper<Scope
541551

542552
for (auto const& [var, value]: ranges::zip_view(_variables, rhs))
543553
{
544-
if (m_keepLiteralAssignments && m_graph.isLiteralValue(value))
545-
{
546-
SSACFG::Operation assignment{
547-
.outputs = {m_graph.newVariable(m_currentBlock)},
548-
.kind = SSACFG::LiteralAssignment{},
549-
.inputs = {value}
550-
};
551-
currentBlock().operations.emplace_back(assignment);
552-
writeVariable(var, m_currentBlock, assignment.outputs.back());
553-
}
554+
if (!m_literalsAsPushConstants && m_graph.isLiteralValue(value))
555+
writeVariable(var, m_currentBlock, moveLiteralToVariable(value));
554556
else
555557
writeVariable(var, m_currentBlock, value);
556558
}
@@ -567,7 +569,15 @@ std::vector<SSACFG::ValueId> SSAControlFlowGraphBuilder::visitFunctionCall(Funct
567569
SSACFG::Operation result{{}, SSACFG::BuiltinCall{_call.debugData, builtin, _call}, {}};
568570
for (auto&& [idx, arg]: _call.arguments | ranges::views::enumerate | ranges::views::reverse)
569571
if (!builtin.literalArgument(idx).has_value())
570-
result.inputs.emplace_back(std::visit(*this, arg));
572+
{
573+
if (!m_literalsAsPushConstants && std::holds_alternative<Literal>(arg))
574+
{
575+
auto const lit = m_graph.newLiteral(debugDataOf(currentBlock()), std::get<Literal>(arg).value.value());
576+
result.inputs.emplace_back(moveLiteralToVariable(lit));
577+
}
578+
else
579+
result.inputs.emplace_back(std::visit(*this, arg));
580+
}
571581
for (size_t i = 0; i < builtin.numReturns; ++i)
572582
result.outputs.emplace_back(m_graph.newVariable(m_currentBlock));
573583
canContinue = builtin.controlFlowSideEffects.canContinue;
@@ -582,7 +592,15 @@ std::vector<SSACFG::ValueId> SSAControlFlowGraphBuilder::visitFunctionCall(Funct
582592
canContinue = m_sideEffects.functionSideEffects().at(definition).canContinue;
583593
SSACFG::Operation result{{}, SSACFG::Call{debugDataOf(_call), function, _call, canContinue}, {}};
584594
for (auto const& arg: _call.arguments | ranges::views::reverse)
585-
result.inputs.emplace_back(std::visit(*this, arg));
595+
{
596+
if (!m_literalsAsPushConstants && std::holds_alternative<Literal>(arg))
597+
{
598+
auto const lit = m_graph.newLiteral(debugDataOf(currentBlock()), std::get<Literal>(arg).value.value());
599+
result.inputs.emplace_back(moveLiteralToVariable(lit));
600+
}
601+
else
602+
result.inputs.emplace_back(std::visit(*this, arg));
603+
}
586604
for (size_t i = 0; i < function.numReturns; ++i)
587605
result.outputs.emplace_back(m_graph.newVariable(m_currentBlock));
588606
return result;
@@ -747,9 +765,8 @@ void SSAControlFlowGraphBuilder::tableJump(
747765

748766
FunctionDefinition const* SSAControlFlowGraphBuilder::findFunctionDefinition(Scope::Function const* _function) const
749767
{
750-
auto it = std::find_if(
751-
m_functionDefinitions.begin(),
752-
m_functionDefinitions.end(),
768+
auto it = ranges::find_if(
769+
m_functionDefinitions,
753770
[&_function](auto const& _entry) { return std::get<0>(_entry) == _function; }
754771
);
755772
if (it != m_functionDefinitions.end())

libyul/backends/evm/SSAControlFlowGraphBuilder.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class SSAControlFlowGraphBuilder
4545
AsmAnalysisInfo const& _analysisInfo,
4646
ControlFlowSideEffectsCollector const& _sideEffects,
4747
Dialect const& _dialect,
48-
bool _keepLiteralAssignments
48+
bool _literalsAsPushConstants
4949
);
5050
public:
5151
SSAControlFlowGraphBuilder(SSAControlFlowGraphBuilder const&) = delete;
@@ -54,7 +54,7 @@ class SSAControlFlowGraphBuilder
5454
AsmAnalysisInfo const& _analysisInfo,
5555
Dialect const& _dialect,
5656
Block const& _block,
57-
bool _keepLiteralAssignments
57+
bool _literalsAsPushConstants
5858
);
5959

6060
void operator()(ExpressionStatement const& _statement);
@@ -82,6 +82,7 @@ class SSAControlFlowGraphBuilder
8282
std::vector<SSACFG::ValueId> visitFunctionCall(FunctionCall const& _call);
8383
void registerFunctionDefinition(FunctionDefinition const& _functionDefinition);
8484
void buildFunctionGraph(Scope::Function const* _function, FunctionDefinition const* _functionDefinition);
85+
SSACFG::ValueId moveLiteralToVariable(SSACFG::ValueId _value);
8586

8687
SSACFG::ValueId zero();
8788
SSACFG::ValueId readVariable(Scope::Variable const& _variable, SSACFG::BlockId _block);
@@ -94,7 +95,7 @@ class SSAControlFlowGraphBuilder
9495
AsmAnalysisInfo const& m_info;
9596
ControlFlowSideEffectsCollector const& m_sideEffects;
9697
Dialect const& m_dialect;
97-
bool const m_keepLiteralAssignments;
98+
bool const m_literalsAsPushConstants;
9899
std::vector<std::tuple<Scope::Function const*, FunctionDefinition const*>> m_functionDefinitions;
99100
SSACFG::BlockId m_currentBlock;
100101
SSACFG::BasicBlock& currentBlock() { return m_graph.block(m_currentBlock); }

0 commit comments

Comments
 (0)