Skip to content

Commit d790750

Browse files
committed
Add option to keep literal assignments in SSACFG builder
1 parent 895eb45 commit d790750

File tree

11 files changed

+367
-290
lines changed

11 files changed

+367
-290
lines changed

libyul/YulStack.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +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;
397400
// NOTE: The block Ids are reset for each object
398401
std::unique_ptr<ControlFlow> controlFlow = SSAControlFlowGraphBuilder::build(
399-
*_object.analysisInfo.get(),
402+
*_object.analysisInfo,
400403
languageToDialect(m_language, m_evmVersion, m_eofVersion),
401-
_object.code()->root()
404+
_object.code()->root(),
405+
keepLiteralAssignments
402406
);
403407
std::unique_ptr<ControlFlowLiveness> liveness = std::make_unique<ControlFlowLiveness>(*controlFlow);
404408
YulControlFlowGraphExporter exporter(*controlFlow, liveness.get());

libyul/backends/evm/SSAControlFlowGraphBuilder.cpp

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,18 @@
2020
*/
2121

2222
#include <libyul/backends/evm/SSAControlFlowGraphBuilder.h>
23-
#include <libyul/AST.h>
24-
#include <libyul/Exceptions.h>
23+
2524
#include <libyul/backends/evm/ControlFlow.h>
25+
#include <libyul/AST.h>
2626
#include <libyul/ControlFlowSideEffectsCollector.h>
27+
#include <libyul/Exceptions.h>
2728
#include <libyul/Utilities.h>
2829

2930
#include <libsolutil/Algorithms.h>
3031
#include <libsolutil/StringUtils.h>
3132
#include <libsolutil/Visitor.h>
3233

34+
#include <range/v3/algorithm/replace.hpp>
3335
#include <range/v3/range/conversion.hpp>
3436
#include <range/v3/view/drop_last.hpp>
3537
#include <range/v3/view/enumerate.hpp>
@@ -49,26 +51,29 @@ SSAControlFlowGraphBuilder::SSAControlFlowGraphBuilder(
4951
SSACFG& _graph,
5052
AsmAnalysisInfo const& _analysisInfo,
5153
ControlFlowSideEffectsCollector const& _sideEffects,
52-
Dialect const& _dialect
54+
Dialect const& _dialect,
55+
bool _keepLiteralAssignments
5356
):
5457
m_controlFlow(_controlFlow),
5558
m_graph(_graph),
5659
m_info(_analysisInfo),
5760
m_sideEffects(_sideEffects),
58-
m_dialect(_dialect)
61+
m_dialect(_dialect),
62+
m_keepLiteralAssignments(_keepLiteralAssignments)
5963
{
6064
}
6165

6266
std::unique_ptr<ControlFlow> SSAControlFlowGraphBuilder::build(
6367
AsmAnalysisInfo const& _analysisInfo,
6468
Dialect const& _dialect,
65-
Block const& _block
69+
Block const& _block,
70+
bool _keepLiteralAssignments
6671
)
6772
{
6873
ControlFlowSideEffectsCollector sideEffects(_dialect, _block);
6974

7075
auto controlFlow = std::make_unique<ControlFlow>();
71-
SSAControlFlowGraphBuilder builder(*controlFlow, *controlFlow->mainGraph, _analysisInfo, sideEffects, _dialect);
76+
SSAControlFlowGraphBuilder builder(*controlFlow, *controlFlow->mainGraph, _analysisInfo, sideEffects, _dialect, _keepLiteralAssignments);
7277
builder.m_currentBlock = controlFlow->mainGraph->makeBlock(debugDataOf(_block));
7378
builder.sealBlock(builder.m_currentBlock);
7479
builder(_block);
@@ -147,8 +152,8 @@ SSACFG::ValueId SSAControlFlowGraphBuilder::tryRemoveTrivialPhi(SSACFG::ValueId
147152
[](SSACFG::BasicBlock::Terminated&) {}
148153
}, block.exit);
149154
}
150-
for (auto& [_, currentVariableDefs]: m_currentDef)
151-
std::replace(currentVariableDefs.begin(), currentVariableDefs.end(), _phi, same);
155+
for (auto& currentVariableDefs: m_currentDef | ranges::views::values)
156+
ranges::replace(currentVariableDefs, _phi, same);
152157

153158
for (auto phiUse: phiUses)
154159
tryRemoveTrivialPhi(phiUse);
@@ -178,11 +183,6 @@ void SSAControlFlowGraphBuilder::cleanUnreachable()
178183
}, block.exit);
179184
});
180185

181-
auto isUnreachableValue = [&](SSACFG::ValueId const& _value) -> bool {
182-
auto* valueInfo = std::get_if<SSACFG::UnreachableValue>(&m_graph.valueInfo(_value));
183-
return (valueInfo) ? true : false;
184-
};
185-
186186
// Remove all entries from unreachable nodes from the graph.
187187
for (SSACFG::BlockId blockId: reachabilityCheck.visited)
188188
{
@@ -197,7 +197,7 @@ void SSAControlFlowGraphBuilder::cleanUnreachable()
197197
for (auto phi: block.phis)
198198
if (auto* phiInfo = std::get_if<SSACFG::PhiValue>(&m_graph.valueInfo(phi)))
199199
std::erase_if(phiInfo->arguments, [&](SSACFG::ValueId _arg) {
200-
if (isUnreachableValue(_arg))
200+
if (std::holds_alternative<SSACFG::UnreachableValue>(m_graph.valueInfo(_arg)))
201201
{
202202
maybeTrivialPhi.insert(phi);
203203
return true;
@@ -240,7 +240,7 @@ void SSAControlFlowGraphBuilder::buildFunctionGraph(
240240
cfg.arguments = arguments;
241241
cfg.returns = returns;
242242

243-
SSAControlFlowGraphBuilder builder(m_controlFlow, cfg, m_info, m_sideEffects, m_dialect);
243+
SSAControlFlowGraphBuilder builder(m_controlFlow, cfg, m_info, m_sideEffects, m_dialect, m_keepLiteralAssignments);
244244
builder.m_currentBlock = cfg.entry;
245245
builder.m_functionDefinitions = m_functionDefinitions;
246246
for (auto&& [var, varId]: cfg.arguments)
@@ -273,6 +273,11 @@ void SSAControlFlowGraphBuilder::operator()(Assignment const& _assignment)
273273

274274
void SSAControlFlowGraphBuilder::operator()(VariableDeclaration const& _variableDeclaration)
275275
{
276+
// if we have no value (like in `let a` without right-hand side), we can just skip this. the variable(s) will be
277+
// added when first needed
278+
if (!_variableDeclaration.value)
279+
return;
280+
276281
assign(
277282
_variableDeclaration.variables | ranges::views::transform([&](auto& _var) { return std::ref(lookupVariable(_var.name)); }) | ranges::to<std::vector>,
278283
_variableDeclaration.value.get()
@@ -533,15 +538,27 @@ void SSAControlFlowGraphBuilder::assign(std::vector<std::reference_wrapper<Scope
533538
auto rhs = [&]() -> std::vector<SSACFG::ValueId> {
534539
if (auto const* functionCall = std::get_if<FunctionCall>(_expression))
535540
return visitFunctionCall(*functionCall);
536-
else if (_expression)
541+
if (_expression)
537542
return {std::visit(*this, *_expression)};
538-
else
539-
return {_variables.size(), zero()};
543+
return {_variables.size(), zero()};
540544
}();
541545
yulAssert(rhs.size() == _variables.size());
542546

543547
for (auto const& [var, value]: ranges::zip_view(_variables, rhs))
544-
writeVariable(var, m_currentBlock, value);
548+
{
549+
if (m_keepLiteralAssignments && m_graph.isLiteralValue(value))
550+
{
551+
SSACFG::Operation assignment{
552+
.outputs = {m_graph.newVariable(m_currentBlock)},
553+
.kind = SSACFG::LiteralAssignment{},
554+
.inputs = {value}
555+
};
556+
currentBlock().operations.emplace_back(assignment);
557+
writeVariable(var, m_currentBlock, assignment.outputs.back());
558+
}
559+
else
560+
writeVariable(var, m_currentBlock, value);
561+
}
545562

546563
}
547564

@@ -610,7 +627,7 @@ SSACFG::ValueId SSAControlFlowGraphBuilder::readVariableRecursive(Scope::Variabl
610627
// incomplete block
611628
val = m_graph.newPhi(_block);
612629
block.phis.insert(val);
613-
info.incompletePhis.emplace_back(val, std::ref(_variable));
630+
info.incompletePhis.emplace_back(val, _variable);
614631
}
615632
else if (block.entries.size() == 1)
616633
// one predecessor: no phi needed
@@ -633,7 +650,7 @@ SSACFG::ValueId SSAControlFlowGraphBuilder::addPhiOperands(Scope::Variable const
633650
{
634651
yulAssert(std::holds_alternative<SSACFG::PhiValue>(m_graph.valueInfo(_phi)));
635652
auto& phi = std::get<SSACFG::PhiValue>(m_graph.valueInfo(_phi));
636-
for (auto pred: m_graph.block(phi.block).entries)
653+
for (auto const& pred: m_graph.block(phi.block).entries)
637654
phi.arguments.emplace_back(readVariable(_variable, pred));
638655
// we call tryRemoveTrivialPhi explicitly to avoid removing trivial phis in unsealed blocks
639656
return _phi;
@@ -660,14 +677,14 @@ Scope::Variable const& SSAControlFlowGraphBuilder::lookupVariable(YulName _name)
660677
yulAssert(m_scope, "");
661678
Scope::Variable const* var = nullptr;
662679
if (m_scope->lookup(_name, util::GenericVisitor{
663-
[&](Scope::Variable& _var) { var = &_var; },
664-
[](Scope::Function&)
680+
[&](Scope::Variable const& _var) { var = &_var; },
681+
[](Scope::Function const&)
665682
{
666683
yulAssert(false, "Function not removed during desugaring.");
667684
}
668685
}))
669686
{
670-
yulAssert(var, "");
687+
yulAssert(var);
671688
return *var;
672689
};
673690
yulAssert(false, "External identifier access unimplemented.");

libyul/backends/evm/SSAControlFlowGraphBuilder.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,17 @@ class SSAControlFlowGraphBuilder
4444
SSACFG& _graph,
4545
AsmAnalysisInfo const& _analysisInfo,
4646
ControlFlowSideEffectsCollector const& _sideEffects,
47-
Dialect const& _dialect
47+
Dialect const& _dialect,
48+
bool _keepLiteralAssignments
4849
);
4950
public:
5051
SSAControlFlowGraphBuilder(SSAControlFlowGraphBuilder const&) = delete;
5152
SSAControlFlowGraphBuilder& operator=(SSAControlFlowGraphBuilder const&) = delete;
5253
static std::unique_ptr<ControlFlow> build(
5354
AsmAnalysisInfo const& _analysisInfo,
5455
Dialect const& _dialect,
55-
Block const& _block
56+
Block const& _block,
57+
bool _keepLiteralAssignments
5658
);
5759

5860
void operator()(ExpressionStatement const& _statement);
@@ -92,6 +94,7 @@ class SSAControlFlowGraphBuilder
9294
AsmAnalysisInfo const& m_info;
9395
ControlFlowSideEffectsCollector const& m_sideEffects;
9496
Dialect const& m_dialect;
97+
bool const m_keepLiteralAssignments;
9598
std::vector<std::tuple<Scope::Function const*, FunctionDefinition const*>> m_functionDefinitions;
9699
SSACFG::BlockId m_currentBlock;
97100
SSACFG::BasicBlock& currentBlock() { return m_graph.block(m_currentBlock); }

0 commit comments

Comments
 (0)