Merge pull request #8958 from ethereum/evm-version-dependent-rules

[yul] Add support for EVM version-dependent rules.
This commit is contained in:
chriseth 2020-05-27 12:52:51 +02:00 committed by GitHub
commit a06ac0f39f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 88 additions and 11 deletions

View File

@ -29,6 +29,10 @@
#include <boost/multiprecision/detail/min_max.hpp> #include <boost/multiprecision/detail/min_max.hpp>
#include <libyul/Dialect.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <liblangutil/EVMVersion.h>
#include <vector> #include <vector>
#include <functional> #include <functional>
@ -657,12 +661,37 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart9(
return rules; return rules;
} }
template<class Pattern>
std::vector<SimplificationRule<Pattern>> evmRuleList(
langutil::EVMVersion _evmVersion,
Pattern,
Pattern,
Pattern,
Pattern,
Pattern,
Pattern,
Pattern
)
{
using Builtins = typename Pattern::Builtins;
std::vector<SimplificationRule<Pattern>> rules;
if (_evmVersion.hasSelfBalance())
rules.push_back({
Builtins::BALANCE(Instruction::ADDRESS),
[]() -> Pattern { return Instruction::SELFBALANCE; }, false
});
return rules;
}
/// @returns a list of simplification rules given certain match placeholders. /// @returns a list of simplification rules given certain match placeholders.
/// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions. /// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions.
/// The simplifications should never change the order of evaluation of /// The simplifications should never change the order of evaluation of
/// arbitrary operations. /// arbitrary operations.
template <class Pattern> template <class Pattern>
std::vector<SimplificationRule<Pattern>> simplificationRuleList( std::vector<SimplificationRule<Pattern>> simplificationRuleList(
std::optional<langutil::EVMVersion> _evmVersion,
Pattern A, Pattern A,
Pattern B, Pattern B,
Pattern C, Pattern C,
@ -691,6 +720,10 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
rules += simplificationRuleListPart7(A, B, C, W, X); rules += simplificationRuleListPart7(A, B, C, W, X);
rules += simplificationRuleListPart8(A, B, C, W, X); rules += simplificationRuleListPart8(A, B, C, W, X);
rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z); rules += simplificationRuleListPart9(A, B, C, W, X, Y, Z);
if (_evmVersion.has_value())
rules += evmRuleList(*_evmVersion, A, B, C, W, X, Y, Z);
return rules; return rules;
} }

View File

@ -92,7 +92,7 @@ Rules::Rules()
Y.setMatchGroup(6, m_matchGroups); Y.setMatchGroup(6, m_matchGroups);
Z.setMatchGroup(7, m_matchGroups); Z.setMatchGroup(7, m_matchGroups);
addRules(simplificationRuleList(A, B, C, W, X, Y, Z)); addRules(simplificationRuleList(nullopt, A, B, C, W, X, Y, Z));
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
} }

View File

@ -36,7 +36,7 @@ using namespace solidity::evmasm;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::yul; using namespace solidity::yul;
SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch( SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
Expression const& _expr, Expression const& _expr,
Dialect const& _dialect, Dialect const& _dialect,
map<YulString, AssignedValue> const& _ssaValues map<YulString, AssignedValue> const& _ssaValues
@ -46,7 +46,16 @@ SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
if (!instruction) if (!instruction)
return nullptr; return nullptr;
static SimplificationRules rules; static std::map<std::optional<EVMVersion>, std::unique_ptr<SimplificationRules>> evmRules;
std::optional<EVMVersion> version;
if (yul::EVMDialect const* evmDialect = dynamic_cast<yul::EVMDialect const*>(&_dialect))
version = evmDialect->evmVersion();
if (!evmRules[version])
evmRules[version] = std::make_unique<SimplificationRules>(version);
SimplificationRules& rules = *evmRules[version];
assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized."); assertThrow(rules.isInitialized(), OptimizerException, "Rule list not properly initialized.");
for (auto const& rule: rules.m_rules[uint8_t(instruction->first)]) for (auto const& rule: rules.m_rules[uint8_t(instruction->first)])
@ -76,18 +85,18 @@ std::optional<std::pair<evmasm::Instruction, vector<Expression> const*>>
return {}; return {};
} }
void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules) void SimplificationRules::addRules(std::vector<Rule> const& _rules)
{ {
for (auto const& r: _rules) for (auto const& r: _rules)
addRule(r); addRule(r);
} }
void SimplificationRules::addRule(SimplificationRule<Pattern> const& _rule) void SimplificationRules::addRule(Rule const& _rule)
{ {
m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule); m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule);
} }
SimplificationRules::SimplificationRules() SimplificationRules::SimplificationRules(std::optional<langutil::EVMVersion> _evmVersion)
{ {
// Multiple occurrences of one of these inside one rule must match the same equivalence class. // Multiple occurrences of one of these inside one rule must match the same equivalence class.
// Constants. // Constants.
@ -107,7 +116,7 @@ SimplificationRules::SimplificationRules()
Y.setMatchGroup(6, m_matchGroups); Y.setMatchGroup(6, m_matchGroups);
Z.setMatchGroup(7, m_matchGroups); Z.setMatchGroup(7, m_matchGroups);
addRules(simplificationRuleList(A, B, C, W, X, Y, Z)); addRules(simplificationRuleList(_evmVersion, A, B, C, W, X, Y, Z));
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
} }

View File

@ -27,6 +27,8 @@
#include <libsolutil/CommonData.h> #include <libsolutil/CommonData.h>
#include <liblangutil/EVMVersion.h>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <functional> #include <functional>
@ -45,12 +47,14 @@ class Pattern;
class SimplificationRules: public boost::noncopyable class SimplificationRules: public boost::noncopyable
{ {
public: public:
SimplificationRules(); using Rule = evmasm::SimplificationRule<Pattern>;
explicit SimplificationRules(std::optional<langutil::EVMVersion> _evmVersion = std::nullopt);
/// @returns a pointer to the first matching pattern and sets the match /// @returns a pointer to the first matching pattern and sets the match
/// groups accordingly. /// groups accordingly.
/// @param _ssaValues values of variables that are assigned exactly once. /// @param _ssaValues values of variables that are assigned exactly once.
static evmasm::SimplificationRule<Pattern> const* findFirstMatch( static Rule const* findFirstMatch(
Expression const& _expr, Expression const& _expr,
Dialect const& _dialect, Dialect const& _dialect,
std::map<YulString, AssignedValue> const& _ssaValues std::map<YulString, AssignedValue> const& _ssaValues
@ -64,8 +68,8 @@ public:
instructionAndArguments(Dialect const& _dialect, Expression const& _expr); instructionAndArguments(Dialect const& _dialect, Expression const& _expr);
private: private:
void addRules(std::vector<evmasm::SimplificationRule<Pattern>> const& _rules); void addRules(std::vector<Rule> const& _rules);
void addRule(evmasm::SimplificationRule<Pattern> const& _rule); void addRule(Rule const& _rule);
void resetMatchGroups() { m_matchGroups.clear(); } void resetMatchGroups() { m_matchGroups.clear(); }

View File

@ -0,0 +1,9 @@
{
let ret := balance(address())
}
// ====
// EVMVersion: <istanbul
// ----
// step: expressionSimplifier
//
// { let ret := balance(address()) }

View File

@ -0,0 +1,13 @@
{
let a := address()
let ret := balance(a)
}
// ====
// EVMVersion: >=istanbul
// ----
// step: expressionSimplifier
//
// {
// let a := address()
// let ret := selfbalance()
// }

View File

@ -0,0 +1,9 @@
{
let ret := balance(address())
}
// ====
// EVMVersion: >=istanbul
// ----
// step: expressionSimplifier
//
// { let ret := selfbalance() }