[yul] Add support for EVM version-dependent rules.

This commit is contained in:
Alexander Arlt 2020-05-15 18:59:57 -05:00 committed by chriseth
parent 1bf706085d
commit a7b89065ca
7 changed files with 88 additions and 11 deletions

View File

@ -29,6 +29,10 @@
#include <boost/multiprecision/detail/min_max.hpp>
#include <libyul/Dialect.h>
#include <libyul/backends/evm/EVMDialect.h>
#include <liblangutil/EVMVersion.h>
#include <vector>
#include <functional>
@ -657,12 +661,37 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart9(
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.
/// A, B and C should represent constants, W, X, Y, and Z arbitrary expressions.
/// The simplifications should never change the order of evaluation of
/// arbitrary operations.
template <class Pattern>
std::vector<SimplificationRule<Pattern>> simplificationRuleList(
std::optional<langutil::EVMVersion> _evmVersion,
Pattern A,
Pattern B,
Pattern C,
@ -691,6 +720,10 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleList(
rules += simplificationRuleListPart7(A, B, C, W, X);
rules += simplificationRuleListPart8(A, B, C, W, X);
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;
}

View File

@ -92,7 +92,7 @@ Rules::Rules()
Y.setMatchGroup(6, 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.");
}

View File

@ -36,7 +36,7 @@ using namespace solidity::evmasm;
using namespace solidity::langutil;
using namespace solidity::yul;
SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
SimplificationRules::Rule const* SimplificationRules::findFirstMatch(
Expression const& _expr,
Dialect const& _dialect,
map<YulString, AssignedValue> const& _ssaValues
@ -46,7 +46,16 @@ SimplificationRule<yul::Pattern> const* SimplificationRules::findFirstMatch(
if (!instruction)
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.");
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 {};
}
void SimplificationRules::addRules(vector<SimplificationRule<Pattern>> const& _rules)
void SimplificationRules::addRules(std::vector<Rule> const& _rules)
{
for (auto const& r: _rules)
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);
}
SimplificationRules::SimplificationRules()
SimplificationRules::SimplificationRules(std::optional<langutil::EVMVersion> _evmVersion)
{
// Multiple occurrences of one of these inside one rule must match the same equivalence class.
// Constants.
@ -107,7 +116,7 @@ SimplificationRules::SimplificationRules()
Y.setMatchGroup(6, 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.");
}

View File

@ -27,6 +27,8 @@
#include <libsolutil/CommonData.h>
#include <liblangutil/EVMVersion.h>
#include <boost/noncopyable.hpp>
#include <functional>
@ -45,12 +47,14 @@ class Pattern;
class SimplificationRules: public boost::noncopyable
{
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
/// groups accordingly.
/// @param _ssaValues values of variables that are assigned exactly once.
static evmasm::SimplificationRule<Pattern> const* findFirstMatch(
static Rule const* findFirstMatch(
Expression const& _expr,
Dialect const& _dialect,
std::map<YulString, AssignedValue> const& _ssaValues
@ -64,8 +68,8 @@ public:
instructionAndArguments(Dialect const& _dialect, Expression const& _expr);
private:
void addRules(std::vector<evmasm::SimplificationRule<Pattern>> const& _rules);
void addRule(evmasm::SimplificationRule<Pattern> const& _rule);
void addRules(std::vector<Rule> const& _rules);
void addRule(Rule const& _rule);
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() }