mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7833 from ethereum/combineValueAndLoopDepth
Combine value and loop depth
This commit is contained in:
commit
17158995b5
@ -79,10 +79,10 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
|
|||||||
YulString name = identifier.name;
|
YulString name = identifier.name;
|
||||||
if (m_value.count(name))
|
if (m_value.count(name))
|
||||||
{
|
{
|
||||||
assertThrow(m_value.at(name), OptimizerException, "");
|
assertThrow(m_value.at(name).value, OptimizerException, "");
|
||||||
if (holds_alternative<Identifier>(*m_value.at(name)))
|
if (holds_alternative<Identifier>(*m_value.at(name).value))
|
||||||
{
|
{
|
||||||
YulString value = std::get<Identifier>(*m_value.at(name)).name;
|
YulString value = std::get<Identifier>(*m_value.at(name).value).name;
|
||||||
assertThrow(inScope(value), OptimizerException, "");
|
assertThrow(inScope(value), OptimizerException, "");
|
||||||
_e = Identifier{locationOf(_e), value};
|
_e = Identifier{locationOf(_e), value};
|
||||||
}
|
}
|
||||||
@ -91,13 +91,13 @@ void CommonSubexpressionEliminator::visit(Expression& _e)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO this search is rather inefficient.
|
// TODO this search is rather inefficient.
|
||||||
for (auto const& var: m_value)
|
for (auto const& [variable, value]: m_value)
|
||||||
{
|
{
|
||||||
assertThrow(var.second, OptimizerException, "");
|
assertThrow(value.value, OptimizerException, "");
|
||||||
assertThrow(inScope(var.first), OptimizerException, "");
|
assertThrow(inScope(variable), OptimizerException, "");
|
||||||
if (SyntacticallyEqual{}(_e, *var.second))
|
if (SyntacticallyEqual{}(_e, *value.value))
|
||||||
{
|
{
|
||||||
_e = Identifier{locationOf(_e), var.first};
|
_e = Identifier{locationOf(_e), variable};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,14 +144,12 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun)
|
|||||||
{
|
{
|
||||||
// Save all information. We might rather reinstantiate this class,
|
// Save all information. We might rather reinstantiate this class,
|
||||||
// but this could be difficult if it is subclassed.
|
// but this could be difficult if it is subclassed.
|
||||||
map<YulString, Expression const*> value;
|
map<YulString, AssignedValue> value;
|
||||||
map<YulString, size_t> variableLoopDepth;
|
|
||||||
size_t loopDepth{0};
|
size_t loopDepth{0};
|
||||||
InvertibleRelation<YulString> references;
|
InvertibleRelation<YulString> references;
|
||||||
InvertibleMap<YulString, YulString> storage;
|
InvertibleMap<YulString, YulString> storage;
|
||||||
InvertibleMap<YulString, YulString> memory;
|
InvertibleMap<YulString, YulString> memory;
|
||||||
swap(m_value, value);
|
swap(m_value, value);
|
||||||
swap(m_variableLoopDepth, variableLoopDepth);
|
|
||||||
swap(m_loopDepth, loopDepth);
|
swap(m_loopDepth, loopDepth);
|
||||||
swap(m_references, references);
|
swap(m_references, references);
|
||||||
swap(m_storage, storage);
|
swap(m_storage, storage);
|
||||||
@ -173,7 +171,6 @@ void DataFlowAnalyzer::operator()(FunctionDefinition& _fun)
|
|||||||
|
|
||||||
popScope();
|
popScope();
|
||||||
swap(m_value, value);
|
swap(m_value, value);
|
||||||
swap(m_variableLoopDepth, variableLoopDepth);
|
|
||||||
swap(m_loopDepth, loopDepth);
|
swap(m_loopDepth, loopDepth);
|
||||||
swap(m_references, references);
|
swap(m_references, references);
|
||||||
swap(m_storage, storage);
|
swap(m_storage, storage);
|
||||||
@ -306,18 +303,14 @@ void DataFlowAnalyzer::clearValues(set<YulString> _variables)
|
|||||||
|
|
||||||
// Clear the value and update the reference relation.
|
// Clear the value and update the reference relation.
|
||||||
for (auto const& name: _variables)
|
for (auto const& name: _variables)
|
||||||
{
|
|
||||||
m_value.erase(name);
|
m_value.erase(name);
|
||||||
m_variableLoopDepth.erase(name);
|
|
||||||
}
|
|
||||||
for (auto const& name: _variables)
|
for (auto const& name: _variables)
|
||||||
m_references.eraseKey(name);
|
m_references.eraseKey(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataFlowAnalyzer::assignValue(YulString _variable, Expression const* _value)
|
void DataFlowAnalyzer::assignValue(YulString _variable, Expression const* _value)
|
||||||
{
|
{
|
||||||
m_value[_variable] = _value;
|
m_value[_variable] = {_value, m_loopDepth};
|
||||||
m_variableLoopDepth[_variable] = m_loopDepth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
|
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
|
||||||
|
@ -41,6 +41,14 @@ namespace solidity::yul
|
|||||||
struct Dialect;
|
struct Dialect;
|
||||||
struct SideEffects;
|
struct SideEffects;
|
||||||
|
|
||||||
|
/// Value assigned to a variable.
|
||||||
|
struct AssignedValue
|
||||||
|
{
|
||||||
|
Expression const* value{nullptr};
|
||||||
|
/// Loop nesting depth of the definition of the variable.
|
||||||
|
size_t loopDepth{0};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class to perform data flow analysis during AST walks.
|
* Base class to perform data flow analysis during AST walks.
|
||||||
* Tracks assignments and is used as base class for both Rematerialiser and
|
* Tracks assignments and is used as base class for both Rematerialiser and
|
||||||
@ -145,9 +153,7 @@ protected:
|
|||||||
std::map<YulString, SideEffects> m_functionSideEffects;
|
std::map<YulString, SideEffects> m_functionSideEffects;
|
||||||
|
|
||||||
/// Current values of variables, always movable.
|
/// Current values of variables, always movable.
|
||||||
std::map<YulString, Expression const*> m_value;
|
std::map<YulString, AssignedValue> m_value;
|
||||||
/// The loop nesting depth of the definition of variables (those used in m_value).
|
|
||||||
std::map<YulString, size_t> m_variableLoopDepth;
|
|
||||||
/// m_references.forward[a].contains(b) <=> the current expression assigned to a references b
|
/// m_references.forward[a].contains(b) <=> the current expression assigned to a references b
|
||||||
/// m_references.backward[b].contains(a) <=> the current expression assigned to a references b
|
/// m_references.backward[b].contains(a) <=> the current expression assigned to a references b
|
||||||
InvertibleRelation<YulString> m_references;
|
InvertibleRelation<YulString> m_references;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libyul/Utilities.h>
|
#include <libyul/Utilities.h>
|
||||||
#include <libyul/optimiser/SimplificationRules.h>
|
#include <libyul/optimiser/SimplificationRules.h>
|
||||||
|
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
|
|
||||||
#include <libsolutil/CommonData.h>
|
#include <libsolutil/CommonData.h>
|
||||||
|
@ -28,6 +28,7 @@ namespace solidity::yul
|
|||||||
{
|
{
|
||||||
|
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct AssignedValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that can answer questions about values of variables and their relations.
|
* Class that can answer questions about values of variables and their relations.
|
||||||
@ -37,7 +38,7 @@ struct Dialect;
|
|||||||
class KnowledgeBase
|
class KnowledgeBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KnowledgeBase(Dialect const& _dialect, std::map<YulString, Expression const*> const& _variableValues):
|
KnowledgeBase(Dialect const& _dialect, std::map<YulString, AssignedValue> const& _variableValues):
|
||||||
m_dialect(_dialect),
|
m_dialect(_dialect),
|
||||||
m_variableValues(_variableValues)
|
m_variableValues(_variableValues)
|
||||||
{}
|
{}
|
||||||
@ -50,7 +51,7 @@ private:
|
|||||||
Expression simplify(Expression _expression);
|
Expression simplify(Expression _expression);
|
||||||
|
|
||||||
Dialect const& m_dialect;
|
Dialect const& m_dialect;
|
||||||
std::map<YulString, Expression const*> const& m_variableValues;
|
std::map<YulString, AssignedValue> const& m_variableValues;
|
||||||
size_t m_recursionCounter = 0;
|
size_t m_recursionCounter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,12 +74,12 @@ void Rematerialiser::visit(Expression& _e)
|
|||||||
YulString name = identifier.name;
|
YulString name = identifier.name;
|
||||||
if (m_value.count(name))
|
if (m_value.count(name))
|
||||||
{
|
{
|
||||||
assertThrow(m_value.at(name), OptimizerException, "");
|
assertThrow(m_value.at(name).value, OptimizerException, "");
|
||||||
auto const& value = *m_value.at(name);
|
AssignedValue const& value = m_value.at(name);
|
||||||
size_t refs = m_referenceCounts[name];
|
size_t refs = m_referenceCounts[name];
|
||||||
size_t cost = CodeCost::codeCost(m_dialect, value);
|
size_t cost = CodeCost::codeCost(m_dialect, *value.value);
|
||||||
if (
|
if (
|
||||||
(refs <= 1 && m_variableLoopDepth.at(name) == m_loopDepth) ||
|
(refs <= 1 && value.loopDepth == m_loopDepth) ||
|
||||||
cost == 0 ||
|
cost == 0 ||
|
||||||
(refs <= 5 && cost <= 1 && m_loopDepth == 0) ||
|
(refs <= 5 && cost <= 1 && m_loopDepth == 0) ||
|
||||||
m_varsToAlwaysRematerialize.count(name)
|
m_varsToAlwaysRematerialize.count(name)
|
||||||
@ -90,9 +90,9 @@ void Rematerialiser::visit(Expression& _e)
|
|||||||
assertThrow(inScope(ref), OptimizerException, "");
|
assertThrow(inScope(ref), OptimizerException, "");
|
||||||
// update reference counts
|
// update reference counts
|
||||||
m_referenceCounts[name]--;
|
m_referenceCounts[name]--;
|
||||||
for (auto const& ref: ReferencesCounter::countReferences(value))
|
for (auto const& ref: ReferencesCounter::countReferences(*value.value))
|
||||||
m_referenceCounts[ref.first] += ref.second;
|
m_referenceCounts[ref.first] += ref.second;
|
||||||
_e = (ASTCopier{}).translate(value);
|
_e = (ASTCopier{}).translate(*value.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ void LiteralRematerialiser::visit(Expression& _e)
|
|||||||
YulString name = identifier.name;
|
YulString name = identifier.name;
|
||||||
if (m_value.count(name))
|
if (m_value.count(name))
|
||||||
{
|
{
|
||||||
Expression const* value = m_value.at(name);
|
Expression const* value = m_value.at(name).value;
|
||||||
assertThrow(value, OptimizerException, "");
|
assertThrow(value, OptimizerException, "");
|
||||||
if (holds_alternative<Literal>(*value))
|
if (holds_alternative<Literal>(*value))
|
||||||
_e = *value;
|
_e = *value;
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <libyul/optimiser/ASTCopier.h>
|
#include <libyul/optimiser/ASTCopier.h>
|
||||||
#include <libyul/optimiser/Semantics.h>
|
#include <libyul/optimiser/Semantics.h>
|
||||||
#include <libyul/optimiser/SyntacticalEquality.h>
|
#include <libyul/optimiser/SyntacticalEquality.h>
|
||||||
|
#include <libyul/optimiser/DataFlowAnalyzer.h>
|
||||||
#include <libyul/backends/evm/EVMDialect.h>
|
#include <libyul/backends/evm/EVMDialect.h>
|
||||||
#include <libyul/AsmData.h>
|
#include <libyul/AsmData.h>
|
||||||
#include <libyul/Utilities.h>
|
#include <libyul/Utilities.h>
|
||||||
@ -38,7 +39,7 @@ using namespace solidity::yul;
|
|||||||
SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
|
SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
|
||||||
Expression const& _expr,
|
Expression const& _expr,
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
map<YulString, Expression const*> const& _ssaValues
|
map<YulString, AssignedValue> const& _ssaValues
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
auto instruction = instructionAndArguments(_dialect, _expr);
|
auto instruction = instructionAndArguments(_dialect, _expr);
|
||||||
@ -126,7 +127,7 @@ void Pattern::setMatchGroup(unsigned _group, map<unsigned, Expression const*>& _
|
|||||||
bool Pattern::matches(
|
bool Pattern::matches(
|
||||||
Expression const& _expr,
|
Expression const& _expr,
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
map<YulString, Expression const*> const& _ssaValues
|
map<YulString, AssignedValue> const& _ssaValues
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
Expression const* expr = &_expr;
|
Expression const* expr = &_expr;
|
||||||
@ -137,7 +138,7 @@ bool Pattern::matches(
|
|||||||
{
|
{
|
||||||
YulString varName = std::get<Identifier>(_expr).name;
|
YulString varName = std::get<Identifier>(_expr).name;
|
||||||
if (_ssaValues.count(varName))
|
if (_ssaValues.count(varName))
|
||||||
if (Expression const* new_expr = _ssaValues.at(varName))
|
if (Expression const* new_expr = _ssaValues.at(varName).value)
|
||||||
expr = new_expr;
|
expr = new_expr;
|
||||||
}
|
}
|
||||||
assertThrow(expr, OptimizerException, "");
|
assertThrow(expr, OptimizerException, "");
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
namespace solidity::yul
|
namespace solidity::yul
|
||||||
{
|
{
|
||||||
struct Dialect;
|
struct Dialect;
|
||||||
|
struct AssignedValue;
|
||||||
class Pattern;
|
class Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,7 +53,7 @@ public:
|
|||||||
static evmasm::SimplificationRule<Pattern> const* findFirstMatch(
|
static evmasm::SimplificationRule<Pattern> const* findFirstMatch(
|
||||||
Expression const& _expr,
|
Expression const& _expr,
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
std::map<YulString, Expression const*> const& _ssaValues
|
std::map<YulString, AssignedValue> const& _ssaValues
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Checks whether the rulelist is non-empty. This is usually enforced
|
/// Checks whether the rulelist is non-empty. This is usually enforced
|
||||||
@ -109,7 +110,7 @@ public:
|
|||||||
bool matches(
|
bool matches(
|
||||||
Expression const& _expr,
|
Expression const& _expr,
|
||||||
Dialect const& _dialect,
|
Dialect const& _dialect,
|
||||||
std::map<YulString, Expression const*> const& _ssaValues
|
std::map<YulString, AssignedValue> const& _ssaValues
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
std::vector<Pattern> arguments() const { return m_arguments; }
|
std::vector<Pattern> arguments() const { return m_arguments; }
|
||||||
|
@ -70,7 +70,7 @@ public:
|
|||||||
{
|
{
|
||||||
YulString varName = _varDecl.variables.front().name;
|
YulString varName = _varDecl.variables.front().name;
|
||||||
if (m_value.count(varName))
|
if (m_value.count(varName))
|
||||||
m_expressionCodeCost[varName] = CodeCost::codeCost(m_dialect, *m_value[varName]);
|
m_expressionCodeCost[varName] = CodeCost::codeCost(m_dialect, *m_value[varName].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user