24
24
25
25
#include < libyul/optimiser/NameCollector.h>
26
26
#include < libyul/optimiser/Semantics.h>
27
+ #include < libyul/optimiser/KnowledgeBase.h>
27
28
#include < libyul/AST.h>
28
29
#include < libyul/Dialect.h>
29
30
#include < libyul/Exceptions.h>
@@ -47,7 +48,7 @@ DataFlowAnalyzer::DataFlowAnalyzer(
47
48
):
48
49
m_dialect(_dialect),
49
50
m_functionSideEffects(std::move(_functionSideEffects)),
50
- m_knowledgeBase(_dialect, m_value )
51
+ m_knowledgeBase(_dialect, [ this ](YulString _var) { return variableValue (_var); } )
51
52
{
52
53
if (auto const * builtin = _dialect.memoryStoreFunction (YulString{}))
53
54
m_storeFunctionName[static_cast <unsigned >(StoreLoadLocation::Memory)] = builtin->name ;
@@ -64,20 +65,20 @@ void DataFlowAnalyzer::operator()(ExpressionStatement& _statement)
64
65
if (auto vars = isSimpleStore (StoreLoadLocation::Storage, _statement))
65
66
{
66
67
ASTModifier::operator ()(_statement);
67
- cxx20::erase_if (m_storage , mapTuple ([&](auto && key, auto && value) {
68
+ cxx20::erase_if (m_state. storage , mapTuple ([&](auto && key, auto && value) {
68
69
return
69
70
!m_knowledgeBase.knownToBeDifferent (vars->first , key) &&
70
71
!m_knowledgeBase.knownToBeEqual (vars->second , value);
71
72
}));
72
- m_storage [vars->first ] = vars->second ;
73
+ m_state. storage [vars->first ] = vars->second ;
73
74
}
74
75
else if (auto vars = isSimpleStore (StoreLoadLocation::Memory, _statement))
75
76
{
76
77
ASTModifier::operator ()(_statement);
77
- cxx20::erase_if (m_memory , mapTuple ([&](auto && key, auto && /* value */ ) {
78
+ cxx20::erase_if (m_state. memory , mapTuple ([&](auto && key, auto && /* value */ ) {
78
79
return !m_knowledgeBase.knownToBeDifferentByAtLeast32 (vars->first , key);
79
80
}));
80
- m_memory [vars->first ] = vars->second ;
81
+ m_state. memory [vars->first ] = vars->second ;
81
82
}
82
83
else
83
84
{
@@ -116,8 +117,8 @@ void DataFlowAnalyzer::operator()(VariableDeclaration& _varDecl)
116
117
void DataFlowAnalyzer::operator ()(If& _if)
117
118
{
118
119
clearKnowledgeIfInvalidated (*_if.condition );
119
- unordered_map<YulString, YulString> storage = m_storage ;
120
- unordered_map<YulString, YulString> memory = m_memory ;
120
+ unordered_map<YulString, YulString> storage = m_state. storage ;
121
+ unordered_map<YulString, YulString> memory = m_state. memory ;
121
122
122
123
ASTModifier::operator ()(_if);
123
124
@@ -133,8 +134,8 @@ void DataFlowAnalyzer::operator()(Switch& _switch)
133
134
set<YulString> assignedVariables;
134
135
for (auto & _case: _switch.cases )
135
136
{
136
- unordered_map<YulString, YulString> storage = m_storage ;
137
- unordered_map<YulString, YulString> memory = m_memory ;
137
+ unordered_map<YulString, YulString> storage = m_state. storage ;
138
+ unordered_map<YulString, YulString> memory = m_state. memory ;
138
139
(*this )(_case.body );
139
140
joinKnowledge (storage, memory);
140
141
@@ -153,11 +154,8 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun)
153
154
{
154
155
// Save all information. We might rather reinstantiate this class,
155
156
// but this could be difficult if it is subclassed.
156
- ScopedSaveAndRestore valueResetter (m_value , {});
157
+ ScopedSaveAndRestore stateResetter (m_state , {});
157
158
ScopedSaveAndRestore loopDepthResetter (m_loopDepth, 0u );
158
- ScopedSaveAndRestore referencesResetter (m_references, {});
159
- ScopedSaveAndRestore storageResetter (m_storage, {});
160
- ScopedSaveAndRestore memoryResetter (m_memory, {});
161
159
pushScope (true );
162
160
163
161
for (auto const & parameter: _fun.parameters )
@@ -218,6 +216,22 @@ void DataFlowAnalyzer::operator()(Block& _block)
218
216
assertThrow (numScopes == m_variableScopes.size (), OptimizerException, " " );
219
217
}
220
218
219
+ optional<YulString> DataFlowAnalyzer::storageValue (YulString _key) const
220
+ {
221
+ if (YulString const * value = util::valueOrNullptr (m_state.storage , _key))
222
+ return *value;
223
+ else
224
+ return nullopt;
225
+ }
226
+
227
+ optional<YulString> DataFlowAnalyzer::memoryValue (YulString _key) const
228
+ {
229
+ if (YulString const * value = util::valueOrNullptr (m_state.memory , _key))
230
+ return *value;
231
+ else
232
+ return nullopt;
233
+ }
234
+
221
235
void DataFlowAnalyzer::handleAssignment (set<YulString> const & _variables, Expression* _value, bool _isDeclaration)
222
236
{
223
237
if (!_isDeclaration)
@@ -242,17 +256,17 @@ void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expres
242
256
auto const & referencedVariables = movableChecker.referencedVariables ();
243
257
for (auto const & name: _variables)
244
258
{
245
- m_references [name] = referencedVariables;
259
+ m_state. references [name] = referencedVariables;
246
260
if (!_isDeclaration)
247
261
{
248
262
// assignment to slot denoted by "name"
249
- m_storage .erase (name);
263
+ m_state. storage .erase (name);
250
264
// assignment to slot contents denoted by "name"
251
- cxx20::erase_if (m_storage , mapTuple ([&name](auto && /* key */ , auto && value) { return value == name; }));
265
+ cxx20::erase_if (m_state. storage , mapTuple ([&name](auto && /* key */ , auto && value) { return value == name; }));
252
266
// assignment to slot denoted by "name"
253
- m_memory .erase (name);
267
+ m_state. memory .erase (name);
254
268
// assignment to slot contents denoted by "name"
255
- cxx20::erase_if (m_memory , mapTuple ([&name](auto && /* key */ , auto && value) { return value == name; }));
269
+ cxx20::erase_if (m_state. memory , mapTuple ([&name](auto && /* key */ , auto && value) { return value == name; }));
256
270
}
257
271
}
258
272
@@ -265,9 +279,9 @@ void DataFlowAnalyzer::handleAssignment(set<YulString> const& _variables, Expres
265
279
// On the other hand, if we knew the value in the slot
266
280
// already, then the sload() / mload() would have been replaced by a variable anyway.
267
281
if (auto key = isSimpleLoad (StoreLoadLocation::Memory, *_value))
268
- m_memory [*key] = variable;
282
+ m_state. memory [*key] = variable;
269
283
else if (auto key = isSimpleLoad (StoreLoadLocation::Storage, *_value))
270
- m_storage [*key] = variable;
284
+ m_state. storage [*key] = variable;
271
285
}
272
286
}
273
287
}
@@ -281,8 +295,8 @@ void DataFlowAnalyzer::popScope()
281
295
{
282
296
for (auto const & name: m_variableScopes.back ().variables )
283
297
{
284
- m_value .erase (name);
285
- m_references .erase (name);
298
+ m_state. value .erase (name);
299
+ m_state. references .erase (name);
286
300
}
287
301
m_variableScopes.pop_back ();
288
302
}
@@ -308,53 +322,53 @@ void DataFlowAnalyzer::clearValues(set<YulString> _variables)
308
322
auto eraseCondition = mapTuple ([&_variables](auto && key, auto && value) {
309
323
return _variables.count (key) || _variables.count (value);
310
324
});
311
- cxx20::erase_if (m_storage , eraseCondition);
312
- cxx20::erase_if (m_memory , eraseCondition);
325
+ cxx20::erase_if (m_state. storage , eraseCondition);
326
+ cxx20::erase_if (m_state. memory , eraseCondition);
313
327
314
328
// Also clear variables that reference variables to be cleared.
315
329
for (auto const & variableToClear: _variables)
316
- for (auto const & [ref, names]: m_references )
330
+ for (auto const & [ref, names]: m_state. references )
317
331
if (names.count (variableToClear))
318
332
_variables.emplace (ref);
319
333
320
334
// Clear the value and update the reference relation.
321
335
for (auto const & name: _variables)
322
336
{
323
- m_value .erase (name);
324
- m_references .erase (name);
337
+ m_state. value .erase (name);
338
+ m_state. references .erase (name);
325
339
}
326
340
}
327
341
328
342
void DataFlowAnalyzer::assignValue (YulString _variable, Expression const * _value)
329
343
{
330
- m_value [_variable] = {_value, m_loopDepth};
344
+ m_state. value [_variable] = {_value, m_loopDepth};
331
345
}
332
346
333
347
void DataFlowAnalyzer::clearKnowledgeIfInvalidated (Block const & _block)
334
348
{
335
349
SideEffectsCollector sideEffects (m_dialect, _block, &m_functionSideEffects);
336
350
if (sideEffects.invalidatesStorage ())
337
- m_storage .clear ();
351
+ m_state. storage .clear ();
338
352
if (sideEffects.invalidatesMemory ())
339
- m_memory .clear ();
353
+ m_state. memory .clear ();
340
354
}
341
355
342
356
void DataFlowAnalyzer::clearKnowledgeIfInvalidated (Expression const & _expr)
343
357
{
344
358
SideEffectsCollector sideEffects (m_dialect, _expr, &m_functionSideEffects);
345
359
if (sideEffects.invalidatesStorage ())
346
- m_storage .clear ();
360
+ m_state. storage .clear ();
347
361
if (sideEffects.invalidatesMemory ())
348
- m_memory .clear ();
362
+ m_state. memory .clear ();
349
363
}
350
364
351
365
void DataFlowAnalyzer::joinKnowledge (
352
366
unordered_map<YulString, YulString> const & _olderStorage,
353
367
unordered_map<YulString, YulString> const & _olderMemory
354
368
)
355
369
{
356
- joinKnowledgeHelper (m_storage , _olderStorage);
357
- joinKnowledgeHelper (m_memory , _olderMemory);
370
+ joinKnowledgeHelper (m_state. storage , _olderStorage);
371
+ joinKnowledgeHelper (m_state. memory , _olderMemory);
358
372
}
359
373
360
374
void DataFlowAnalyzer::joinKnowledgeHelper (
@@ -364,8 +378,8 @@ void DataFlowAnalyzer::joinKnowledgeHelper(
364
378
{
365
379
// We clear if the key does not exist in the older map or if the value is different.
366
380
// This also works for memory because _older is an "older version"
367
- // of m_memory and thus any overlapping write would have cleared the keys
368
- // that are not known to be different inside m_memory already.
381
+ // of m_state.memory and thus any overlapping write would have cleared the keys
382
+ // that are not known to be different inside m_state.memory already.
369
383
cxx20::erase_if (_this, mapTuple ([&_older](auto && key, auto && currentValue){
370
384
YulString const * oldValue = util::valueOrNullptr (_older, key);
371
385
return !oldValue || *oldValue != currentValue;
@@ -386,8 +400,8 @@ bool DataFlowAnalyzer::inScope(YulString _variableName) const
386
400
387
401
optional<u256> DataFlowAnalyzer::valueOfIdentifier (YulString const & _name)
388
402
{
389
- if (m_value. count (_name))
390
- if (Literal const * literal = get_if<Literal>(m_value. at (_name). value ))
403
+ if (AssignedValue const * value = variableValue (_name))
404
+ if (Literal const * literal = get_if<Literal>(value-> value ))
391
405
return valueOfLiteral (*literal);
392
406
return nullopt;
393
407
}
0 commit comments