20
20
*/
21
21
22
22
#include < libyul/backends/evm/SSAControlFlowGraphBuilder.h>
23
- #include < libyul/AST.h>
24
- #include < libyul/Exceptions.h>
23
+
25
24
#include < libyul/backends/evm/ControlFlow.h>
25
+ #include < libyul/AST.h>
26
26
#include < libyul/ControlFlowSideEffectsCollector.h>
27
+ #include < libyul/Exceptions.h>
27
28
#include < libyul/Utilities.h>
28
29
29
30
#include < libsolutil/Algorithms.h>
30
31
#include < libsolutil/StringUtils.h>
31
32
#include < libsolutil/Visitor.h>
32
33
34
+ #include < range/v3/algorithm/replace.hpp>
33
35
#include < range/v3/range/conversion.hpp>
34
36
#include < range/v3/view/drop_last.hpp>
35
37
#include < range/v3/view/enumerate.hpp>
@@ -49,26 +51,29 @@ SSAControlFlowGraphBuilder::SSAControlFlowGraphBuilder(
49
51
SSACFG& _graph,
50
52
AsmAnalysisInfo const & _analysisInfo,
51
53
ControlFlowSideEffectsCollector const & _sideEffects,
52
- Dialect const & _dialect
54
+ Dialect const & _dialect,
55
+ bool _keepLiteralAssignments
53
56
):
54
57
m_controlFlow (_controlFlow),
55
58
m_graph (_graph),
56
59
m_info (_analysisInfo),
57
60
m_sideEffects (_sideEffects),
58
- m_dialect (_dialect)
61
+ m_dialect (_dialect),
62
+ m_keepLiteralAssignments (_keepLiteralAssignments)
59
63
{
60
64
}
61
65
62
66
std::unique_ptr<ControlFlow> SSAControlFlowGraphBuilder::build (
63
67
AsmAnalysisInfo const & _analysisInfo,
64
68
Dialect const & _dialect,
65
- Block const & _block
69
+ Block const & _block,
70
+ bool _keepLiteralAssignments
66
71
)
67
72
{
68
73
ControlFlowSideEffectsCollector sideEffects (_dialect, _block);
69
74
70
75
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 );
72
77
builder.m_currentBlock = controlFlow->mainGraph ->makeBlock (debugDataOf (_block));
73
78
builder.sealBlock (builder.m_currentBlock );
74
79
builder (_block);
@@ -147,8 +152,8 @@ SSACFG::ValueId SSAControlFlowGraphBuilder::tryRemoveTrivialPhi(SSACFG::ValueId
147
152
[](SSACFG::BasicBlock::Terminated&) {}
148
153
}, block.exit );
149
154
}
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);
152
157
153
158
for (auto phiUse: phiUses)
154
159
tryRemoveTrivialPhi (phiUse);
@@ -178,11 +183,6 @@ void SSAControlFlowGraphBuilder::cleanUnreachable()
178
183
}, block.exit );
179
184
});
180
185
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
-
186
186
// Remove all entries from unreachable nodes from the graph.
187
187
for (SSACFG::BlockId blockId: reachabilityCheck.visited )
188
188
{
@@ -197,7 +197,7 @@ void SSAControlFlowGraphBuilder::cleanUnreachable()
197
197
for (auto phi: block.phis )
198
198
if (auto * phiInfo = std::get_if<SSACFG::PhiValue>(&m_graph.valueInfo (phi)))
199
199
std::erase_if (phiInfo->arguments , [&](SSACFG::ValueId _arg) {
200
- if (isUnreachableValue ( _arg))
200
+ if (std::holds_alternative<SSACFG::UnreachableValue>(m_graph. valueInfo ( _arg) ))
201
201
{
202
202
maybeTrivialPhi.insert (phi);
203
203
return true ;
@@ -240,7 +240,7 @@ void SSAControlFlowGraphBuilder::buildFunctionGraph(
240
240
cfg.arguments = arguments;
241
241
cfg.returns = returns;
242
242
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 );
244
244
builder.m_currentBlock = cfg.entry ;
245
245
builder.m_functionDefinitions = m_functionDefinitions;
246
246
for (auto && [var, varId]: cfg.arguments )
@@ -273,6 +273,11 @@ void SSAControlFlowGraphBuilder::operator()(Assignment const& _assignment)
273
273
274
274
void SSAControlFlowGraphBuilder::operator ()(VariableDeclaration const & _variableDeclaration)
275
275
{
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
+
276
281
assign (
277
282
_variableDeclaration.variables | ranges::views::transform ([&](auto & _var) { return std::ref (lookupVariable (_var.name )); }) | ranges::to<std::vector>,
278
283
_variableDeclaration.value .get ()
@@ -533,15 +538,27 @@ void SSAControlFlowGraphBuilder::assign(std::vector<std::reference_wrapper<Scope
533
538
auto rhs = [&]() -> std::vector<SSACFG::ValueId> {
534
539
if (auto const * functionCall = std::get_if<FunctionCall>(_expression))
535
540
return visitFunctionCall (*functionCall);
536
- else if (_expression)
541
+ if (_expression)
537
542
return {std::visit (*this , *_expression)};
538
- else
539
- return {_variables.size (), zero ()};
543
+ return {_variables.size (), zero ()};
540
544
}();
541
545
yulAssert (rhs.size () == _variables.size ());
542
546
543
547
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
+ }
545
562
546
563
}
547
564
@@ -610,7 +627,7 @@ SSACFG::ValueId SSAControlFlowGraphBuilder::readVariableRecursive(Scope::Variabl
610
627
// incomplete block
611
628
val = m_graph.newPhi (_block);
612
629
block.phis .insert (val);
613
- info.incompletePhis .emplace_back (val, std::ref ( _variable) );
630
+ info.incompletePhis .emplace_back (val, _variable);
614
631
}
615
632
else if (block.entries .size () == 1 )
616
633
// one predecessor: no phi needed
@@ -633,7 +650,7 @@ SSACFG::ValueId SSAControlFlowGraphBuilder::addPhiOperands(Scope::Variable const
633
650
{
634
651
yulAssert (std::holds_alternative<SSACFG::PhiValue>(m_graph.valueInfo (_phi)));
635
652
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 )
637
654
phi.arguments .emplace_back (readVariable (_variable, pred));
638
655
// we call tryRemoveTrivialPhi explicitly to avoid removing trivial phis in unsealed blocks
639
656
return _phi;
@@ -660,14 +677,14 @@ Scope::Variable const& SSAControlFlowGraphBuilder::lookupVariable(YulName _name)
660
677
yulAssert (m_scope, " " );
661
678
Scope::Variable const * var = nullptr ;
662
679
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 &)
665
682
{
666
683
yulAssert (false , " Function not removed during desugaring." );
667
684
}
668
685
}))
669
686
{
670
- yulAssert (var, " " );
687
+ yulAssert (var);
671
688
return *var;
672
689
};
673
690
yulAssert (false , " External identifier access unimplemented." );
0 commit comments