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

View File

@ -81,12 +81,14 @@ struct AssignedValue
class DataFlowAnalyzer: public ASTModifier class DataFlowAnalyzer: public ASTModifier
{ {
public: public:
enum class MemoryAndStorage { Analyze, Ignore };
/// @param _functionSideEffects /// @param _functionSideEffects
/// Side-effects of user-defined functions. Worst-case side-effects are assumed /// Side-effects of user-defined functions. Worst-case side-effects are assumed
/// if this is not provided or the function is not found. /// if this is not provided or the function is not found.
/// The parameter is mostly used to determine movability of expressions. /// The parameter is mostly used to determine movability of expressions.
explicit DataFlowAnalyzer( explicit DataFlowAnalyzer(
Dialect const& _dialect, Dialect const& _dialect,
MemoryAndStorage _analyzeStores,
std::map<YulString, SideEffects> _functionSideEffects = {} std::map<YulString, SideEffects> _functionSideEffects = {}
); );
@ -189,6 +191,8 @@ private:
protected: protected:
KnowledgeBase m_knowledgeBase; 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_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Last) + 1];
YulString m_loadFunctionName[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, Dialect const& _dialect,
std::map<YulString, SideEffects> _functionSideEffects std::map<YulString, SideEffects> _functionSideEffects
): ):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)) DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects))
{} {}
protected: protected:

View File

@ -51,7 +51,9 @@ public:
void visit(Expression& _expression) override; void visit(Expression& _expression) override;
private: 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, bool _containsMSize,
std::optional<size_t> _expectedExecutionsPerDeployment std::optional<size_t> _expectedExecutionsPerDeployment
): ):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)), DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects)),
m_containsMSize(_containsMSize), m_containsMSize(_containsMSize),
m_expectedExecutionsPerDeployment(std::move(_expectedExecutionsPerDeployment)) m_expectedExecutionsPerDeployment(std::move(_expectedExecutionsPerDeployment))
{} {}

View File

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

View File

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

View File

@ -56,7 +56,7 @@ namespace
class RematCandidateSelector: public DataFlowAnalyzer class RematCandidateSelector: public DataFlowAnalyzer
{ {
public: 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 /// @returns a map from function name to rematerialisation costs to a vector of variables to rematerialise
/// and variables that occur in their expression. /// and variables that occur in their expression.