Skip to content

Commit eab4ca9

Browse files
committed
Refactor data flow analyzer state access.
1 parent e154d43 commit eab4ca9

14 files changed

+81
-48
lines changed

libyul/optimiser/CommonSubexpressionEliminator.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,18 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
9595
if (Identifier const* identifier = get_if<Identifier>(&_e))
9696
{
9797
YulString identifierName = identifier->name;
98-
if (m_value.count(identifierName))
98+
if (AssignedValue const* assignedValue = variableValue(identifierName))
9999
{
100-
assertThrow(m_value.at(identifierName).value, OptimizerException, "");
101-
if (Identifier const* value = get_if<Identifier>(m_value.at(identifierName).value))
100+
assertThrow(assignedValue->value, OptimizerException, "");
101+
if (Identifier const* value = get_if<Identifier>(assignedValue->value))
102102
if (inScope(value->name))
103103
_e = Identifier{debugDataOf(_e), value->name};
104104
}
105105
}
106106
else
107107
{
108108
// TODO this search is rather inefficient.
109-
for (auto const& [variable, value]: m_value)
109+
for (auto const& [variable, value]: allValues())
110110
{
111111
assertThrow(value.value, OptimizerException, "");
112112
// Prevent using the default value of return variables

libyul/optimiser/DataFlowAnalyzer.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <libyul/optimiser/NameCollector.h>
2626
#include <libyul/optimiser/Semantics.h>
27+
#include <libyul/optimiser/KnowledgeBase.h>
2728
#include <libyul/AST.h>
2829
#include <libyul/Dialect.h>
2930
#include <libyul/Exceptions.h>
@@ -47,7 +48,7 @@ DataFlowAnalyzer::DataFlowAnalyzer(
4748
):
4849
m_dialect(_dialect),
4950
m_functionSideEffects(std::move(_functionSideEffects)),
50-
m_knowledgeBase(_dialect, m_value)
51+
m_knowledgeBase(_dialect, [this](YulString _var) { return variableValue(_var); })
5152
{
5253
if (auto const* builtin = _dialect.memoryStoreFunction(YulString{}))
5354
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
@@ -218,6 +219,22 @@ void DataFlowAnalyzer::operator()(Block& _block)
218219
assertThrow(numScopes == m_variableScopes.size(), OptimizerException, "");
219220
}
220221

222+
optional<YulString> DataFlowAnalyzer::storageValue(YulString _key) const
223+
{
224+
if (YulString const* value = util::valueOrNullptr(m_storage, _key))
225+
return *value;
226+
else
227+
return nullopt;
228+
}
229+
230+
optional<YulString> DataFlowAnalyzer::memoryValue(YulString _key) const
231+
{
232+
if (YulString const* value = util::valueOrNullptr(m_memory, _key))
233+
return *value;
234+
else
235+
return nullopt;
236+
}
237+
221238
void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expression* _value, bool _isDeclaration)
222239
{
223240
if (!_isDeclaration)
@@ -386,8 +403,8 @@ bool DataFlowAnalyzer::inScope(YulString _variableName) const
386403

387404
optional<u256> DataFlowAnalyzer::valueOfIdentifier(YulString const& _name)
388405
{
389-
if (m_value.count(_name))
390-
if (Literal const* literal = get_if<Literal>(m_value.at(_name).value))
406+
if (AssignedValue const* value = variableValue(_name))
407+
if (Literal const* literal = get_if<Literal>(value->value))
391408
return valueOfLiteral(*literal);
392409
return nullopt;
393410
}
@@ -416,3 +433,4 @@ std::optional<YulString> DataFlowAnalyzer::isSimpleLoad(
416433
return key->name;
417434
return {};
418435
}
436+

libyul/optimiser/DataFlowAnalyzer.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <libyul/AST.h> // Needed for m_zero below.
3030
#include <libyul/SideEffects.h>
3131

32+
#include <libsolutil/Numeric.h>
3233
#include <libsolutil/Common.h>
3334

3435
#include <map>
@@ -38,6 +39,7 @@ namespace solidity::yul
3839
{
3940
struct Dialect;
4041
struct SideEffects;
42+
class KnowledgeBase;
4143

4244
/// Value assigned to a variable.
4345
struct AssignedValue
@@ -98,6 +100,13 @@ class DataFlowAnalyzer: public ASTModifier
98100
void operator()(ForLoop&) override;
99101
void operator()(Block& _block) override;
100102

103+
/// @returns the current value of the given variable, if known - always movable.
104+
AssignedValue const* variableValue(YulString _variable) const { return util::valueOrNullptr(m_value, _variable); }
105+
std::set<YulString> const* references(YulString _variable) const { return util::valueOrNullptr(m_references, _variable); }
106+
std::map<YulString, AssignedValue> const& allValues() const { return m_value; }
107+
std::optional<YulString> storageValue(YulString _key) const;
108+
std::optional<YulString> memoryValue(YulString _key) const;
109+
101110
protected:
102111
/// Registers the assignment.
103112
void handleAssignment(std::set<YulString> const& _names, Expression* _value, bool _isDeclaration);

libyul/optimiser/EqualStoreEliminator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ void EqualStoreEliminator::visit(Statement& _statement)
5454
{
5555
if (auto vars = isSimpleStore(StoreLoadLocation::Storage, *expression))
5656
{
57-
if (auto const* currentValue = util::valueOrNullptr(m_storage, vars->first))
57+
if (optional<YulString> currentValue = storageValue(vars->first))
5858
if (*currentValue == vars->second)
5959
m_pendingRemovals.insert(&_statement);
6060
}
6161
else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, *expression))
6262
{
63-
if (auto const* currentValue = util::valueOrNullptr(m_memory, vars->first))
63+
if (optional<YulString> currentValue = memoryValue(vars->first))
6464
if (*currentValue == vars->second)
6565
m_pendingRemovals.insert(&_statement);
6666
}

libyul/optimiser/ExpressionSimplifier.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ void ExpressionSimplifier::visit(Expression& _expression)
3838
{
3939
ASTModifier::visit(_expression);
4040

41-
while (auto const* match = SimplificationRules::findFirstMatch(_expression, m_dialect, m_value))
41+
while (auto const* match = SimplificationRules::findFirstMatch(
42+
_expression,
43+
m_dialect,
44+
[this](YulString _var) { return variableValue(_var); }
45+
))
4246
_expression = match->action().toExpression(debugDataOf(_expression));
4347
}

libyul/optimiser/KnowledgeBase.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ bool KnowledgeBase::knownToBeZero(YulString _a)
8080

8181
optional<u256> KnowledgeBase::valueIfKnownConstant(YulString _a)
8282
{
83-
if (m_variableValues.count(_a))
84-
if (Literal const* literal = get_if<Literal>(m_variableValues.at(_a).value))
83+
if (AssignedValue const* value = m_variableValues(_a))
84+
if (Literal const* literal = get_if<Literal>(value->value))
8585
return valueOfLiteral(*literal);
8686
return {};
8787
}

libyul/optimiser/KnowledgeBase.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <libsolutil/Numeric.h>
2929

3030
#include <map>
31+
#include <functional>
3132

3233
namespace solidity::yul
3334
{
@@ -37,15 +38,16 @@ struct AssignedValue;
3738

3839
/**
3940
* Class that can answer questions about values of variables and their relations.
40-
*
41-
* The reference to the map of values provided at construction is assumed to be updating.
4241
*/
4342
class KnowledgeBase
4443
{
4544
public:
46-
KnowledgeBase(Dialect const& _dialect, std::map<YulString, AssignedValue> const& _variableValues):
45+
KnowledgeBase(
46+
Dialect const& _dialect,
47+
std::function<AssignedValue const*(YulString)> _variableValues
48+
):
4749
m_dialect(_dialect),
48-
m_variableValues(_variableValues)
50+
m_variableValues(std::move(_variableValues))
4951
{}
5052

5153
bool knownToBeDifferent(YulString _a, YulString _b);
@@ -60,7 +62,7 @@ class KnowledgeBase
6062
Expression simplifyRecursively(Expression _expression);
6163

6264
Dialect const& m_dialect;
63-
std::map<YulString, AssignedValue> const& m_variableValues;
65+
std::function<AssignedValue const*(YulString)> m_variableValues;
6466
size_t m_counter = 0;
6567
};
6668

libyul/optimiser/LoadResolver.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,12 @@ void LoadResolver::tryResolve(
8282
YulString key = std::get<Identifier>(_arguments.at(0)).name;
8383
if (_location == StoreLoadLocation::Storage)
8484
{
85-
if (auto value = util::valueOrNullptr(m_storage, key))
85+
if (auto value = storageValue(key))
8686
if (inScope(*value))
8787
_e = Identifier{debugDataOf(_e), *value};
8888
}
8989
else if (!m_containsMSize && _location == StoreLoadLocation::Memory)
90-
if (auto value = util::valueOrNullptr(m_memory, key))
90+
if (auto value = memoryValue(key))
9191
if (inScope(*value))
9292
_e = Identifier{debugDataOf(_e), *value};
9393
}
@@ -129,10 +129,10 @@ void LoadResolver::tryEvaluateKeccak(
129129
if (costOfLiteral > costOfKeccak)
130130
return;
131131

132-
auto memoryValue = util::valueOrNullptr(m_memory, memoryKey->name);
133-
if (memoryValue && inScope(*memoryValue))
132+
optional<YulString> value = memoryValue(memoryKey->name);
133+
if (value && inScope(*value))
134134
{
135-
optional<u256> memoryContent = valueOfIdentifier(*memoryValue);
135+
optional<u256> memoryContent = valueOfIdentifier(*value);
136136
optional<u256> byteLength = valueOfIdentifier(length->name);
137137
if (memoryContent && byteLength && *byteLength <= 32)
138138
{

libyul/optimiser/Rematerialiser.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,30 +79,30 @@ void Rematerialiser::visit(Expression& _e)
7979
{
8080
Identifier& identifier = std::get<Identifier>(_e);
8181
YulString name = identifier.name;
82-
if (m_value.count(name))
82+
if (AssignedValue const* value = variableValue(name))
8383
{
84-
assertThrow(m_value.at(name).value, OptimizerException, "");
85-
AssignedValue const& value = m_value.at(name);
84+
assertThrow(value->value, OptimizerException, "");
8685
size_t refs = m_referenceCounts[name];
87-
size_t cost = CodeCost::codeCost(m_dialect, *value.value);
86+
size_t cost = CodeCost::codeCost(m_dialect, *value->value);
8887
if (
8988
(
9089
!m_onlySelectedVariables && (
91-
(refs <= 1 && value.loopDepth == m_loopDepth) ||
90+
(refs <= 1 && value->loopDepth == m_loopDepth) ||
9291
cost == 0 ||
9392
(refs <= 5 && cost <= 1 && m_loopDepth == 0)
9493
)
9594
) || m_varsToAlwaysRematerialize.count(name)
9695
)
9796
{
9897
assertThrow(m_referenceCounts[name] > 0, OptimizerException, "");
99-
if (ranges::all_of(m_references[name], [&](auto const& ref) { return inScope(ref); }))
98+
auto variableReferences = references(name);
99+
if (!variableReferences || ranges::all_of(*variableReferences, [&](auto const& ref) { return inScope(ref); }))
100100
{
101101
// update reference counts
102102
m_referenceCounts[name]--;
103-
for (auto const& ref: ReferencesCounter::countReferences(*value.value))
103+
for (auto const& ref: ReferencesCounter::countReferences(*value->value))
104104
m_referenceCounts[ref.first] += ref.second;
105-
_e = (ASTCopier{}).translate(*value.value);
105+
_e = (ASTCopier{}).translate(*value->value);
106106
}
107107
}
108108
}
@@ -116,12 +116,11 @@ void LiteralRematerialiser::visit(Expression& _e)
116116
{
117117
Identifier& identifier = std::get<Identifier>(_e);
118118
YulString name = identifier.name;
119-
if (m_value.count(name))
119+
if (AssignedValue const* value = variableValue(name))
120120
{
121-
Expression const* value = m_value.at(name).value;
122-
assertThrow(value, OptimizerException, "");
123-
if (holds_alternative<Literal>(*value))
124-
_e = *value;
121+
assertThrow(value->value, OptimizerException, "");
122+
if (holds_alternative<Literal>(*value->value))
123+
_e = *value->value;
125124
}
126125
}
127126
DataFlowAnalyzer::visit(_e);

libyul/optimiser/SimplificationRules.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ using namespace solidity::yul;
4141
SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
4242
Expression const& _expr,
4343
Dialect const& _dialect,
44-
map<YulString, AssignedValue> const& _ssaValues
44+
function<AssignedValue const*(YulString)> const& _ssaValues
4545
)
4646
{
4747
auto instruction = instructionAndArguments(_dialect, _expr);
@@ -138,7 +138,7 @@ void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _
138138
bool Pattern::matches(
139139
Expression const& _expr,
140140
Dialect const& _dialect,
141-
map<YulString, AssignedValue> const& _ssaValues
141+
function<AssignedValue const*(YulString)> const& _ssaValues
142142
) const
143143
{
144144
Expression const* expr = &_expr;
@@ -148,8 +148,8 @@ bool Pattern::matches(
148148
if (m_kind != PatternKind::Any && holds_alternative<Identifier>(_expr))
149149
{
150150
YulString varName = std::get<Identifier>(_expr).name;
151-
if (_ssaValues.count(varName))
152-
if (Expression const* new_expr = _ssaValues.at(varName).value)
151+
if (AssignedValue const* value = _ssaValues(varName))
152+
if (Expression const* new_expr = value->value)
153153
expr = new_expr;
154154
}
155155
assertThrow(expr, OptimizerException, "");

0 commit comments

Comments
 (0)