diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp index d25beb6bd..d1d482877 100644 --- a/libyul/optimiser/CommonSubexpressionEliminator.cpp +++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp @@ -48,7 +48,7 @@ CommonSubexpressionEliminator::CommonSubexpressionEliminator( Dialect const& _dialect, map _functionSideEffects ): - DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)) + DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore, std::move(_functionSideEffects)) { } diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 65cdf31c3..7e98fe517 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -44,47 +44,54 @@ using namespace solidity::yul; DataFlowAnalyzer::DataFlowAnalyzer( Dialect const& _dialect, + MemoryAndStorage _analyzeStores, map _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(StoreLoadLocation::Memory)] = builtin->name; - if (auto const* builtin = _dialect.memoryLoadFunction(YulString{})) - m_loadFunctionName[static_cast(StoreLoadLocation::Memory)] = builtin->name; - if (auto const* builtin = _dialect.storageStoreFunction(YulString{})) - m_storeFunctionName[static_cast(StoreLoadLocation::Storage)] = builtin->name; - if (auto const* builtin = _dialect.storageLoadFunction(YulString{})) - m_loadFunctionName[static_cast(StoreLoadLocation::Storage)] = builtin->name; + if (m_analyzeStores) + { + if (auto const* builtin = _dialect.memoryStoreFunction(YulString{})) + m_storeFunctionName[static_cast(StoreLoadLocation::Memory)] = builtin->name; + if (auto const* builtin = _dialect.memoryLoadFunction(YulString{})) + m_loadFunctionName[static_cast(StoreLoadLocation::Memory)] = builtin->name; + if (auto const* builtin = _dialect.storageStoreFunction(YulString{})) + m_storeFunctionName[static_cast(StoreLoadLocation::Storage)] = builtin->name; + if (auto const* builtin = _dialect.storageLoadFunction(YulString{})) + m_loadFunctionName[static_cast(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 const& _olderMemory ) { + if (!m_analyzeStores) + return; joinKnowledgeHelper(m_state.storage, _olderStorage); joinKnowledgeHelper(m_state.memory, _olderMemory); } diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h index a8463360b..4a8cc7445 100644 --- a/libyul/optimiser/DataFlowAnalyzer.h +++ b/libyul/optimiser/DataFlowAnalyzer.h @@ -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 _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(StoreLoadLocation::Last) + 1]; YulString m_loadFunctionName[static_cast(StoreLoadLocation::Last) + 1]; diff --git a/libyul/optimiser/EqualStoreEliminator.h b/libyul/optimiser/EqualStoreEliminator.h index 796fcc538..b8572f466 100644 --- a/libyul/optimiser/EqualStoreEliminator.h +++ b/libyul/optimiser/EqualStoreEliminator.h @@ -47,7 +47,7 @@ private: Dialect const& _dialect, std::map _functionSideEffects ): - DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)) + DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects)) {} protected: diff --git a/libyul/optimiser/ExpressionSimplifier.h b/libyul/optimiser/ExpressionSimplifier.h index f9d4e8da5..324ff419a 100644 --- a/libyul/optimiser/ExpressionSimplifier.h +++ b/libyul/optimiser/ExpressionSimplifier.h @@ -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) + {} }; } diff --git a/libyul/optimiser/LoadResolver.h b/libyul/optimiser/LoadResolver.h index 93d37d779..e56bc6c4a 100644 --- a/libyul/optimiser/LoadResolver.h +++ b/libyul/optimiser/LoadResolver.h @@ -53,7 +53,7 @@ private: bool _containsMSize, std::optional _expectedExecutionsPerDeployment ): - DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)), + DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects)), m_containsMSize(_containsMSize), m_expectedExecutionsPerDeployment(std::move(_expectedExecutionsPerDeployment)) {} diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp index 7dff1df80..fb42e6593 100644 --- a/libyul/optimiser/Rematerialiser.cpp +++ b/libyul/optimiser/Rematerialiser.cpp @@ -43,7 +43,7 @@ Rematerialiser::Rematerialiser( set _varsToAlwaysRematerialize, bool _onlySelectedVariables ): - DataFlowAnalyzer(_dialect), + DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore), m_referenceCounts(ReferencesCounter::countReferences(_ast)), m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)), m_onlySelectedVariables(_onlySelectedVariables) diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h index 592f79d1b..9ee5209fd 100644 --- a/libyul/optimiser/Rematerialiser.h +++ b/libyul/optimiser/Rematerialiser.h @@ -95,7 +95,7 @@ public: private: LiteralRematerialiser(Dialect const& _dialect): - DataFlowAnalyzer(_dialect) + DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore) {} }; diff --git a/libyul/optimiser/StackCompressor.cpp b/libyul/optimiser/StackCompressor.cpp index b3402e4d7..6e33078a0 100644 --- a/libyul/optimiser/StackCompressor.cpp +++ b/libyul/optimiser/StackCompressor.cpp @@ -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.