Only analyze memory in DataFlowAnalyzer if it is needed in the optimizer step.

This commit is contained in:
chriseth 2022-07-11 15:51:25 +02:00
parent e7c5f04464
commit c12d151834
9 changed files with 56 additions and 37 deletions

View File

@ -48,7 +48,7 @@ CommonSubexpressionEliminator::CommonSubexpressionEliminator(
Dialect const& _dialect,
map<YulString, SideEffects> _functionSideEffects
):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore, std::move(_functionSideEffects))
{
}

View File

@ -44,47 +44,54 @@ using namespace solidity::yul;
DataFlowAnalyzer::DataFlowAnalyzer(
Dialect const& _dialect,
MemoryAndStorage _analyzeStores,
map<YulString, SideEffects> _functionSideEffects
):
m_dialect(_dialect),
m_functionSideEffects(std::move(_functionSideEffects)),
m_knowledgeBase(_dialect, [this](YulString _var) { return variableValue(_var); })
m_knowledgeBase(_dialect, [this](YulString _var) { return variableValue(_var); }),
m_analyzeStores(_analyzeStores == MemoryAndStorage::Analyze)
{
if (auto const* builtin = _dialect.memoryStoreFunction(YulString{}))
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
if (auto const* builtin = _dialect.memoryLoadFunction(YulString{}))
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
if (auto const* builtin = _dialect.storageStoreFunction(YulString{}))
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
if (auto const* builtin = _dialect.storageLoadFunction(YulString{}))
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
if (m_analyzeStores)
{
if (auto const* builtin = _dialect.memoryStoreFunction(YulString{}))
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
if (auto const* builtin = _dialect.memoryLoadFunction(YulString{}))
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
if (auto const* builtin = _dialect.storageStoreFunction(YulString{}))
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
if (auto const* builtin = _dialect.storageLoadFunction(YulString{}))
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
}
}
void DataFlowAnalyzer::operator()(ExpressionStatement& _statement)
{
if (auto vars = isSimpleStore(StoreLoadLocation::Storage, _statement))
if (m_analyzeStores)
{
ASTModifier::operator()(_statement);
cxx20::erase_if(m_state.storage, mapTuple([&](auto&& key, auto&& value) {
return
!m_knowledgeBase.knownToBeDifferent(vars->first, key) &&
!m_knowledgeBase.knownToBeEqual(vars->second, value);
}));
m_state.storage[vars->first] = vars->second;
}
else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, _statement))
{
ASTModifier::operator()(_statement);
cxx20::erase_if(m_state.memory, mapTuple([&](auto&& key, auto&& /* value */) {
return !m_knowledgeBase.knownToBeDifferentByAtLeast32(vars->first, key);
}));
m_state.memory[vars->first] = vars->second;
}
else
{
clearKnowledgeIfInvalidated(_statement.expression);
ASTModifier::operator()(_statement);
if (auto vars = isSimpleStore(StoreLoadLocation::Storage, _statement))
{
ASTModifier::operator()(_statement);
cxx20::erase_if(m_state.storage, mapTuple([&](auto&& key, auto&& value) {
return
!m_knowledgeBase.knownToBeDifferent(vars->first, key) &&
!m_knowledgeBase.knownToBeEqual(vars->second, value);
}));
m_state.storage[vars->first] = vars->second;
return;
}
else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, _statement))
{
ASTModifier::operator()(_statement);
cxx20::erase_if(m_state.memory, mapTuple([&](auto&& key, auto&& /* value */) {
return !m_knowledgeBase.knownToBeDifferentByAtLeast32(vars->first, key);
}));
m_state.memory[vars->first] = vars->second;
return;
}
}
clearKnowledgeIfInvalidated(_statement.expression);
ASTModifier::operator()(_statement);
}
void DataFlowAnalyzer::operator()(Assignment& _assignment)
@ -346,6 +353,8 @@ void DataFlowAnalyzer::assignValue(YulString _variable, Expression const* _value
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
{
if (!m_analyzeStores)
return;
SideEffectsCollector sideEffects(m_dialect, _block, &m_functionSideEffects);
if (sideEffects.invalidatesStorage())
m_state.storage.clear();
@ -355,6 +364,8 @@ void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr)
{
if (!m_analyzeStores)
return;
SideEffectsCollector sideEffects(m_dialect, _expr, &m_functionSideEffects);
if (sideEffects.invalidatesStorage())
m_state.storage.clear();
@ -367,6 +378,8 @@ void DataFlowAnalyzer::joinKnowledge(
unordered_map<YulString, YulString> const& _olderMemory
)
{
if (!m_analyzeStores)
return;
joinKnowledgeHelper(m_state.storage, _olderStorage);
joinKnowledgeHelper(m_state.memory, _olderMemory);
}

View File

@ -81,12 +81,14 @@ struct AssignedValue
class DataFlowAnalyzer: public ASTModifier
{
public:
enum class MemoryAndStorage { Analyze, Ignore };
/// @param _functionSideEffects
/// Side-effects of user-defined functions. Worst-case side-effects are assumed
/// if this is not provided or the function is not found.
/// The parameter is mostly used to determine movability of expressions.
explicit DataFlowAnalyzer(
Dialect const& _dialect,
MemoryAndStorage _analyzeStores,
std::map<YulString, SideEffects> _functionSideEffects = {}
);
@ -189,6 +191,8 @@ private:
protected:
KnowledgeBase m_knowledgeBase;
/// If true, analyzes memory and storage content via mload/mstore and sload/sstore.
bool m_analyzeStores = true;
YulString m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Last) + 1];
YulString m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Last) + 1];

View File

@ -47,7 +47,7 @@ private:
Dialect const& _dialect,
std::map<YulString, SideEffects> _functionSideEffects
):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects))
{}
protected:

View File

@ -51,7 +51,9 @@ public:
void visit(Expression& _expression) override;
private:
explicit ExpressionSimplifier(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
explicit ExpressionSimplifier(Dialect const& _dialect):
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore)
{}
};
}

View File

@ -53,7 +53,7 @@ private:
bool _containsMSize,
std::optional<size_t> _expectedExecutionsPerDeployment
):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)),
DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects)),
m_containsMSize(_containsMSize),
m_expectedExecutionsPerDeployment(std::move(_expectedExecutionsPerDeployment))
{}

View File

@ -43,7 +43,7 @@ Rematerialiser::Rematerialiser(
set<YulString> _varsToAlwaysRematerialize,
bool _onlySelectedVariables
):
DataFlowAnalyzer(_dialect),
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore),
m_referenceCounts(ReferencesCounter::countReferences(_ast)),
m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)),
m_onlySelectedVariables(_onlySelectedVariables)

View File

@ -95,7 +95,7 @@ public:
private:
LiteralRematerialiser(Dialect const& _dialect):
DataFlowAnalyzer(_dialect)
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore)
{}
};

View File

@ -56,7 +56,7 @@ namespace
class RematCandidateSelector: public DataFlowAnalyzer
{
public:
explicit RematCandidateSelector(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
explicit RematCandidateSelector(Dialect const& _dialect): DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore) {}
/// @returns a map from function name to rematerialisation costs to a vector of variables to rematerialise
/// and variables that occur in their expression.