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)
{
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())

View File

@ -23,6 +23,8 @@
#include <libyul/backends/evm/EVMDialect.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/CallGraphGenerator.h>
#include <libyul/SideEffects.h>
#include <libyul/AsmData.h>
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<EVMDialect const*>(&m_dialect))
return;
if (_e.type() == typeid(FunctionCall))
{
FunctionCall const& funCall = boost::get<FunctionCall>(_e);
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))
{
YulString key = boost::get<Identifier>(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<FunctionalInstruction>(_e);
tryResolve(_e, instruction.instruction, instruction.arguments);
}
}
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
#include <libyul/optimiser/DataFlowAnalyzer.h>
#include <libevmasm/Instruction.h>
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<YulString, SideEffects> _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<Expression> const& _arguments
);
bool m_optimizeMLoad = false;
};

View File

@ -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<YulString, SideEffects> const* _functionSideEffects
):
SideEffectsCollector(_dialect, _functionSideEffects)
{
operator()(_ast);
}

View File

@ -47,7 +47,11 @@ public:
std::map<YulString, SideEffects> 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<YulString, SideEffects> const* _functionSideEffects = nullptr
);
using ASTWalker::operator();
void operator()(FunctionalInstruction const& _functionalInstruction) override;