Skip to content

Commit 3328b6e

Browse files
authored
Merge pull request #12240 from ethereum/forEachForYulNodes
Introduce forEach for yul ast nodes.
2 parents 386a5a5 + dd8f127 commit 3328b6e

11 files changed

+79
-140
lines changed

libyul/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,6 @@ add_library(yul
140140
optimiser/FullInliner.h
141141
optimiser/FunctionCallFinder.cpp
142142
optimiser/FunctionCallFinder.h
143-
optimiser/FunctionDefinitionCollector.cpp
144-
optimiser/FunctionDefinitionCollector.h
145143
optimiser/FunctionGrouper.cpp
146144
optimiser/FunctionGrouper.h
147145
optimiser/FunctionHoister.cpp

libyul/ControlFlowSideEffectsCollector.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919
#include <libyul/ControlFlowSideEffectsCollector.h>
2020

21-
#include <libyul/optimiser/FunctionDefinitionCollector.h>
22-
2321
#include <libyul/AST.h>
2422
#include <libyul/Dialect.h>
2523

libyul/optimiser/ASTWalker.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,35 @@ class ASTModifier
102102
}
103103
};
104104

105+
namespace detail
106+
{
107+
template <
108+
typename Node,
109+
typename Visitor,
110+
typename Base = std::conditional_t<std::is_const_v<Node>, ASTWalker, ASTModifier>
111+
>
112+
struct ForEach: Base
113+
{
114+
template<typename Callable>
115+
ForEach(Callable&& _visitor): visitor(std::forward<Callable>(_visitor)) {}
116+
117+
using Base::operator();
118+
void operator()(Node& _node) override
119+
{
120+
visitor(_node);
121+
Base::operator()(_node);
122+
}
123+
124+
Visitor visitor;
125+
};
126+
}
127+
128+
/// Helper function that traverses the AST and calls the visitor for each
129+
/// node of a specific type.
130+
template<typename Node, typename Entry, typename Visitor>
131+
void forEach(Entry&& _entry, Visitor&& _visitor)
132+
{
133+
detail::ForEach<Node, std::decay_t<Visitor>>{std::forward<Visitor>(_visitor)}(std::forward<Entry>(_entry));
134+
}
135+
105136
}

libyul/optimiser/DataFlowAnalyzer.cpp

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ DataFlowAnalyzer::DataFlowAnalyzer(
4545
Dialect const& _dialect,
4646
map<YulString, SideEffects> _functionSideEffects
4747
):
48-
m_dialect(_dialect),
49-
m_functionSideEffects(std::move(_functionSideEffects)),
50-
m_knowledgeBase(_dialect, m_value)
48+
m_dialect(_dialect),
49+
m_functionSideEffects(std::move(_functionSideEffects)),
50+
m_knowledgeBase(_dialect, m_value)
5151
{
5252
if (auto const* builtin = _dialect.memoryStoreFunction(YulString{}))
5353
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
@@ -123,9 +123,7 @@ void DataFlowAnalyzer::operator()(If& _if)
123123

124124
joinKnowledge(storage, memory);
125125

126-
Assignments assignments;
127-
assignments(_if.body);
128-
clearValues(assignments.names());
126+
clearValues(assignedVariableNames(_if.body));
129127
}
130128

131129
void DataFlowAnalyzer::operator()(Switch& _switch)
@@ -140,11 +138,10 @@ void DataFlowAnalyzer::operator()(Switch& _switch)
140138
(*this)(_case.body);
141139
joinKnowledge(storage, memory);
142140

143-
Assignments assignments;
144-
assignments(_case.body);
145-
assignedVariables += assignments.names();
141+
set<YulString> variables = assignedVariableNames(_case.body);
142+
assignedVariables += variables;
146143
// This is a little too destructive, we could retain the old values.
147-
clearValues(assignments.names());
144+
clearValues(variables);
148145
clearKnowledgeIfInvalidated(_case.body);
149146
}
150147
for (auto& _case: _switch.cases)
@@ -190,10 +187,9 @@ void DataFlowAnalyzer::operator()(ForLoop& _for)
190187
AssignmentsSinceContinue assignmentsSinceCont;
191188
assignmentsSinceCont(_for.body);
192189

193-
Assignments assignments;
194-
assignments(_for.body);
195-
assignments(_for.post);
196-
clearValues(assignments.names());
190+
set<YulString> assignedVariables =
191+
assignedVariableNames(_for.body) + assignedVariableNames(_for.post);
192+
clearValues(assignedVariables);
197193

198194
// break/continue are tricky for storage and thus we almost always clear here.
199195
clearKnowledgeIfInvalidated(*_for.condition);
@@ -205,7 +201,7 @@ void DataFlowAnalyzer::operator()(ForLoop& _for)
205201
clearValues(assignmentsSinceCont.names());
206202
clearKnowledgeIfInvalidated(_for.body);
207203
(*this)(_for.post);
208-
clearValues(assignments.names());
204+
clearValues(assignedVariables);
209205
clearKnowledgeIfInvalidated(*_for.condition);
210206
clearKnowledgeIfInvalidated(_for.post);
211207
clearKnowledgeIfInvalidated(_for.body);

libyul/optimiser/FunctionDefinitionCollector.cpp

Lines changed: 0 additions & 36 deletions
This file was deleted.

libyul/optimiser/FunctionDefinitionCollector.h

Lines changed: 0 additions & 44 deletions
This file was deleted.

libyul/optimiser/NameCollector.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,6 @@ map<YulString, size_t> ReferencesCounter::countReferences(Expression const& _exp
7878
return counter.references();
7979
}
8080

81-
void Assignments::operator()(Assignment const& _assignment)
82-
{
83-
for (auto const& var: _assignment.variableNames)
84-
m_names.emplace(var.name);
85-
}
86-
87-
8881
void AssignmentsSinceContinue::operator()(ForLoop const& _forLoop)
8982
{
9083
m_forLoopDepth++;
@@ -109,3 +102,22 @@ void AssignmentsSinceContinue::operator()(FunctionDefinition const&)
109102
{
110103
yulAssert(false, "");
111104
}
105+
106+
std::set<YulString> solidity::yul::assignedVariableNames(Block const& _code)
107+
{
108+
std::set<YulString> names;
109+
forEach<Assignment const>(_code, [&](Assignment const& _assignment) {
110+
for (auto const& var: _assignment.variableNames)
111+
names.emplace(var.name);
112+
});
113+
return names;
114+
}
115+
116+
map<YulString, FunctionDefinition const*> solidity::yul::allFunctionDefinitions(Block const& _block)
117+
{
118+
std::map<YulString, FunctionDefinition const*> result;
119+
forEach<FunctionDefinition const>(_block, [&](FunctionDefinition const& _function) {
120+
result[_function.name] = &_function;
121+
});
122+
return result;
123+
}

libyul/optimiser/NameCollector.h

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,6 @@ class ReferencesCounter: public ASTWalker
9191
std::map<YulString, size_t> m_references;
9292
};
9393

94-
/**
95-
* Specific AST walker that finds all variables that are assigned to.
96-
*/
97-
class Assignments: public ASTWalker
98-
{
99-
public:
100-
using ASTWalker::operator ();
101-
void operator()(Assignment const& _assignment) override;
102-
103-
std::set<YulString> const& names() const { return m_names; }
104-
private:
105-
std::set<YulString> m_names;
106-
};
107-
10894
/**
10995
* Collects all names from a given continue statement on onwards.
11096
*
@@ -130,4 +116,12 @@ class AssignmentsSinceContinue: public ASTWalker
130116
std::set<YulString> m_names;
131117
};
132118

119+
/// @returns the names of all variables that are assigned to inside @a _code.
120+
/// (ignores variable declarations)
121+
std::set<YulString> assignedVariableNames(Block const& _code);
122+
123+
/// @returns all function definitions anywhere in the AST.
124+
/// Requires disambiguated source.
125+
std::map<YulString, FunctionDefinition const*> allFunctionDefinitions(Block const& _block);
126+
133127
}

libyul/optimiser/SSATransform.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,7 @@ void IntroduceControlFlowSSA::operator()(ForLoop& _for)
196196
{
197197
yulAssert(_for.pre.statements.empty(), "For loop init rewriter not run.");
198198

199-
Assignments assignments;
200-
assignments(_for.body);
201-
assignments(_for.post);
202-
203-
204-
for (auto const& var: assignments.names())
199+
for (auto const& var: assignedVariableNames(_for.body) + assignedVariableNames(_for.post))
205200
if (m_variablesInScope.count(var))
206201
m_variablesToReassign.insert(var);
207202

@@ -359,11 +354,7 @@ void PropagateValues::operator()(ForLoop& _for)
359354
{
360355
yulAssert(_for.pre.statements.empty(), "For loop init rewriter not run.");
361356

362-
Assignments assignments;
363-
assignments(_for.body);
364-
assignments(_for.post);
365-
366-
for (auto const& var: assignments.names())
357+
for (auto const& var: assignedVariableNames(_for.body) + assignedVariableNames(_for.post))
367358
m_currentVariableValues.erase(var);
368359

369360
visit(*_for.condition);
@@ -389,11 +380,10 @@ void PropagateValues::operator()(Block& _block)
389380
void SSATransform::run(OptimiserStepContext& _context, Block& _ast)
390381
{
391382
TypeInfo typeInfo(_context.dialect, _ast);
392-
Assignments assignments;
393-
assignments(_ast);
394-
IntroduceSSA{_context.dispenser, assignments.names(), typeInfo}(_ast);
395-
IntroduceControlFlowSSA{_context.dispenser, assignments.names(), typeInfo}(_ast);
396-
PropagateValues{assignments.names()}(_ast);
383+
set<YulString> assignedVariables = assignedVariableNames(_ast);
384+
IntroduceSSA{_context.dispenser, assignedVariables, typeInfo}(_ast);
385+
IntroduceControlFlowSSA{_context.dispenser, assignedVariables, typeInfo}(_ast);
386+
PropagateValues{assignedVariables}(_ast);
397387
}
398388

399389

libyul/optimiser/StackLimitEvader.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
#include <libyul/optimiser/StackLimitEvader.h>
1919
#include <libyul/optimiser/CallGraphGenerator.h>
2020
#include <libyul/optimiser/FunctionCallFinder.h>
21-
#include <libyul/optimiser/FunctionDefinitionCollector.h>
2221
#include <libyul/optimiser/NameDispenser.h>
22+
#include <libyul/optimiser/NameCollector.h>
2323
#include <libyul/optimiser/StackToMemoryMover.h>
2424
#include <libyul/backends/evm/ControlFlowGraphBuilder.h>
2525
#include <libyul/backends/evm/EVMDialect.h>
@@ -193,7 +193,7 @@ void StackLimitEvader::run(
193193
if (_unreachableVariables.count(function))
194194
return;
195195

196-
map<YulString, FunctionDefinition const*> functionDefinitions = FunctionDefinitionCollector::run(*_object.code);
196+
map<YulString, FunctionDefinition const*> functionDefinitions = allFunctionDefinitions(*_object.code);
197197

198198
MemoryOffsetAllocator memoryOffsetAllocator{_unreachableVariables, callGraph.functionCalls, functionDefinitions};
199199
uint64_t requiredSlots = memoryOffsetAllocator.run();

0 commit comments

Comments
 (0)