Fix load resolver and properly take side-effects of user-defined

functions into account.
This commit is contained in:
chriseth 2019-09-02 14:22:53 +02:00
parent edbec012ae
commit a8e8eaebcd
5 changed files with 70 additions and 29 deletions

View File

@ -297,7 +297,7 @@ void DataFlowAnalyzer::clearValues(set<YulString> _variables)
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block) void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
{ {
SideEffectsCollector sideEffects(m_dialect, _block); SideEffectsCollector sideEffects(m_dialect, _block, &m_functionSideEffects);
if (sideEffects.invalidatesStorage()) if (sideEffects.invalidatesStorage())
m_storage.clear(); m_storage.clear();
if (sideEffects.invalidatesMemory()) if (sideEffects.invalidatesMemory())
@ -306,7 +306,7 @@ void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr) void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr)
{ {
SideEffectsCollector sideEffects(m_dialect, _expr); SideEffectsCollector sideEffects(m_dialect, _expr, &m_functionSideEffects);
if (sideEffects.invalidatesStorage()) if (sideEffects.invalidatesStorage())
m_storage.clear(); m_storage.clear();
if (sideEffects.invalidatesMemory()) if (sideEffects.invalidatesMemory())

View File

@ -23,6 +23,8 @@
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
#include <libyul/optimiser/Semantics.h> #include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/SideEffects.h>
#include <libyul/AsmData.h> #include <libyul/AsmData.h>
using namespace std; using namespace std;
@ -32,35 +34,53 @@ using namespace yul;
void LoadResolver::run(Dialect const& _dialect, Block& _ast) void LoadResolver::run(Dialect const& _dialect, Block& _ast)
{ {
bool containsMSize = MSizeFinder::containsMSize(_dialect, _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) void LoadResolver::visit(Expression& _e)
{ {
DataFlowAnalyzer::visit(_e);
if (!dynamic_cast<EVMDialect const*>(&m_dialect))
return;
if (_e.type() == typeid(FunctionCall)) if (_e.type() == typeid(FunctionCall))
{ {
FunctionCall const& funCall = boost::get<FunctionCall>(_e); FunctionCall const& funCall = boost::get<FunctionCall>(_e);
if (auto const* builtin = dynamic_cast<EVMDialect const&>(m_dialect).builtin(funCall.functionName.name)) if (auto const* builtin = dynamic_cast<EVMDialect const&>(m_dialect).builtin(funCall.functionName.name))
if (!builtin->parameters.empty() && funCall.arguments.at(0).type() == typeid(Identifier)) if (builtin->instruction)
{ tryResolve(_e, *builtin->instruction, funCall.arguments);
YulString key = boost::get<Identifier>(funCall.arguments.at(0)).name; }
if ( else if (_e.type() == typeid(FunctionalInstruction))
builtin->instruction == dev::eth::Instruction::SLOAD && {
m_storage.values.count(key) FunctionalInstruction const& instruction = boost::get<FunctionalInstruction>(_e);
) tryResolve(_e, instruction.instruction, instruction.arguments);
{
_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;
}
}
} }
} }
void LoadResolver::tryResolve(
Expression& _e,
dev::eth::Instruction _instruction,
vector<Expression> const& _arguments
)
{
if (_arguments.empty() || _arguments.at(0).type() != typeid(Identifier))
return;
YulString key = boost::get<Identifier>(_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]};
}

View File

@ -22,11 +22,13 @@
#pragma once #pragma once
#include <libyul/optimiser/DataFlowAnalyzer.h> #include <libyul/optimiser/DataFlowAnalyzer.h>
#include <libevmasm/Instruction.h>
namespace yul namespace yul
{ {
struct EVMDialect; struct EVMDialect;
struct BuiltinFunctionForEVM;
/** /**
* Optimisation stage that replaces expressions of type ``sload(x)`` and ``mload(x)`` by the value * 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 class LoadResolver: public DataFlowAnalyzer
{ {
public: public:
/// Run the load resolver on the given complete AST.
static void run(Dialect const& _dialect, Block& _ast); static void run(Dialect const& _dialect, Block& _ast);
private: private:
LoadResolver(Dialect const& _dialect, bool _optimizeMLoad): LoadResolver(
DataFlowAnalyzer(_dialect), Dialect const& _dialect,
std::map<YulString, SideEffects> _functionSideEffects,
bool _optimizeMLoad
):
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)),
m_optimizeMLoad(_optimizeMLoad) m_optimizeMLoad(_optimizeMLoad)
{} {}
@ -51,6 +58,12 @@ protected:
using ASTModifier::visit; using ASTModifier::visit;
void visit(Expression& _e) override; void visit(Expression& _e) override;
void tryResolve(
Expression& _e,
dev::eth::Instruction _instruction,
std::vector<Expression> const& _arguments
);
bool m_optimizeMLoad = false; bool m_optimizeMLoad = false;
}; };

View File

@ -51,8 +51,12 @@ SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Statement co
visit(_statement); visit(_statement);
} }
SideEffectsCollector::SideEffectsCollector(Dialect const& _dialect, Block const& _ast): SideEffectsCollector::SideEffectsCollector(
SideEffectsCollector(_dialect) Dialect const& _dialect,
Block const& _ast,
map<YulString, SideEffects> const* _functionSideEffects
):
SideEffectsCollector(_dialect, _functionSideEffects)
{ {
operator()(_ast); operator()(_ast);
} }

View File

@ -47,7 +47,11 @@ public:
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
); );
SideEffectsCollector(Dialect const& _dialect, Statement const& _statement); SideEffectsCollector(Dialect const& _dialect, Statement const& _statement);
SideEffectsCollector(Dialect const& _dialect, Block const& _ast); SideEffectsCollector(
Dialect const& _dialect,
Block const& _ast,
std::map<YulString, SideEffects> const* _functionSideEffects = nullptr
);
using ASTWalker::operator(); using ASTWalker::operator();
void operator()(FunctionalInstruction const& _functionalInstruction) override; void operator()(FunctionalInstruction const& _functionalInstruction) override;