diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp index 3f3b31f2a..c2042a19c 100644 --- a/libyul/optimiser/DataFlowAnalyzer.cpp +++ b/libyul/optimiser/DataFlowAnalyzer.cpp @@ -297,7 +297,7 @@ void DataFlowAnalyzer::clearValues(set _variables) void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block) { - SideEffectsCollector sideEffects(m_dialect, _block); + SideEffectsCollector sideEffects(m_dialect, _block, &m_functionSideEffects); if (sideEffects.invalidatesStorage()) m_storage.clear(); if (sideEffects.invalidatesMemory()) @@ -306,7 +306,7 @@ void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block) void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr) { - SideEffectsCollector sideEffects(m_dialect, _expr); + SideEffectsCollector sideEffects(m_dialect, _expr, &m_functionSideEffects); if (sideEffects.invalidatesStorage()) m_storage.clear(); if (sideEffects.invalidatesMemory()) diff --git a/libyul/optimiser/LoadResolver.cpp b/libyul/optimiser/LoadResolver.cpp index 2a68149fe..3ff064fd7 100644 --- a/libyul/optimiser/LoadResolver.cpp +++ b/libyul/optimiser/LoadResolver.cpp @@ -23,6 +23,8 @@ #include #include +#include +#include #include using namespace std; @@ -32,35 +34,53 @@ using namespace yul; void LoadResolver::run(Dialect const& _dialect, Block& _ast) { bool containsMSize = MSizeFinder::containsMSize(_dialect, _ast); - LoadResolver{_dialect, !containsMSize}(_ast); + LoadResolver{ + _dialect, + SideEffectsPropagator::sideEffects(_dialect, CallGraphGenerator::callGraph(_ast)), + !containsMSize + }(_ast); } void LoadResolver::visit(Expression& _e) { + DataFlowAnalyzer::visit(_e); + + if (!dynamic_cast(&m_dialect)) + return; + if (_e.type() == typeid(FunctionCall)) { FunctionCall const& funCall = boost::get(_e); if (auto const* builtin = dynamic_cast(m_dialect).builtin(funCall.functionName.name)) - if (!builtin->parameters.empty() && funCall.arguments.at(0).type() == typeid(Identifier)) - { - YulString key = boost::get(funCall.arguments.at(0)).name; - if ( - builtin->instruction == dev::eth::Instruction::SLOAD && - m_storage.values.count(key) - ) - { - _e = Identifier{locationOf(_e), m_storage.values[key]}; - return; - } - else if ( - m_optimizeMLoad && - builtin->instruction == dev::eth::Instruction::MLOAD && - m_memory.values.count(key) - ) - { - _e = Identifier{locationOf(_e), m_memory.values[key]}; - return; - } - } + if (builtin->instruction) + tryResolve(_e, *builtin->instruction, funCall.arguments); + } + else if (_e.type() == typeid(FunctionalInstruction)) + { + FunctionalInstruction const& instruction = boost::get(_e); + tryResolve(_e, instruction.instruction, instruction.arguments); } } + +void LoadResolver::tryResolve( + Expression& _e, + dev::eth::Instruction _instruction, + vector const& _arguments +) +{ + if (_arguments.empty() || _arguments.at(0).type() != typeid(Identifier)) + return; + + YulString key = boost::get(_arguments.at(0)).name; + if ( + _instruction == dev::eth::Instruction::SLOAD && + m_storage.values.count(key) + ) + _e = Identifier{locationOf(_e), m_storage.values[key]}; + else if ( + m_optimizeMLoad && + _instruction == dev::eth::Instruction::MLOAD && + m_memory.values.count(key) + ) + _e = Identifier{locationOf(_e), m_memory.values[key]}; +} diff --git a/libyul/optimiser/LoadResolver.h b/libyul/optimiser/LoadResolver.h index 3db124594..37afc6b6e 100644 --- a/libyul/optimiser/LoadResolver.h +++ b/libyul/optimiser/LoadResolver.h @@ -22,11 +22,13 @@ #pragma once #include +#include namespace yul { struct EVMDialect; +struct BuiltinFunctionForEVM; /** * Optimisation stage that replaces expressions of type ``sload(x)`` and ``mload(x)`` by the value @@ -39,11 +41,16 @@ struct EVMDialect; class LoadResolver: public DataFlowAnalyzer { public: + /// Run the load resolver on the given complete AST. static void run(Dialect const& _dialect, Block& _ast); private: - LoadResolver(Dialect const& _dialect, bool _optimizeMLoad): - DataFlowAnalyzer(_dialect), + LoadResolver( + Dialect const& _dialect, + std::map _functionSideEffects, + bool _optimizeMLoad + ): + DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)), m_optimizeMLoad(_optimizeMLoad) {} @@ -51,6 +58,12 @@ protected: using ASTModifier::visit; void visit(Expression& _e) override; + void tryResolve( + Expression& _e, + dev::eth::Instruction _instruction, + std::vector const& _arguments + ); + bool m_optimizeMLoad = false; }; diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp index a4784af66..001193533 100644 --- a/libyul/optimiser/Semantics.cpp +++ b/libyul/optimiser/Semantics.cpp @@ -51,8 +51,12 @@ SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Statement co visit(_statement); } -SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Block const& _ast): - SideEffectsCollector(_dialect) +SideEffectsCollector::SideEffectsCollector( + Dialect const& _dialect, + Block const& _ast, + map const* _functionSideEffects +): + SideEffectsCollector(_dialect, _functionSideEffects) { operator()(_ast); } diff --git a/libyul/optimiser/Semantics.h b/libyul/optimiser/Semantics.h index 1135b7070..8953ab321 100644 --- a/libyul/optimiser/Semantics.h +++ b/libyul/optimiser/Semantics.h @@ -47,7 +47,11 @@ public: std::map const* _functionSideEffects = nullptr ); SideEffectsCollector(Dialect const& _dialect, Statement const& _statement); - SideEffectsCollector(Dialect const& _dialect, Block const& _ast); + SideEffectsCollector( + Dialect const& _dialect, + Block const& _ast, + std::map const* _functionSideEffects = nullptr + ); using ASTWalker::operator(); void operator()(FunctionalInstruction const& _functionalInstruction) override;