From a7b89065ca16daa4558890c79b8cb5c959587803 Mon Sep 17 00:00:00 2001 From: Alexander Arlt Date: Fri, 15 May 2020 18:59:57 -0500 Subject: [PATCH] [yul] Add support for EVM version-dependent rules. --- libevmasm/RuleList.h | 33 +++++++++++++++++++ libevmasm/SimplificationRules.cpp | 2 +- libyul/optimiser/SimplificationRules.cpp | 21 ++++++++---- libyul/optimiser/SimplificationRules.h | 12 ++++--- .../selfbalance_not_supported.yul | 9 +++++ .../selfbalance_split.yul | 13 ++++++++ .../selfbalance_supported.yul | 9 +++++ 7 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul create mode 100644 test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_split.yul create mode 100644 test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul diff --git a/libevmasm/RuleList.h b/libevmasm/RuleList.h index cd6eda81d..e29141b49 100644 --- a/libevmasm/RuleList.h +++ b/libevmasm/RuleList.h @@ -29,6 +29,10 @@ #include +#include +#include +#include + #include #include @@ -657,12 +661,37 @@ std::vector> simplificationRuleListPart9( return rules; } +template +std::vector> evmRuleList( + langutil::EVMVersion _evmVersion, + Pattern, + Pattern, + Pattern, + Pattern, + Pattern, + Pattern, + Pattern +) +{ + using Builtins = typename Pattern::Builtins; + std::vector> 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 std::vector> simplificationRuleList( + std::optional _evmVersion, Pattern A, Pattern B, Pattern C, @@ -691,6 +720,10 @@ std::vector> 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; } diff --git a/libevmasm/SimplificationRules.cpp b/libevmasm/SimplificationRules.cpp index 8fb65d1d3..c4cc59863 100644 --- a/libevmasm/SimplificationRules.cpp +++ b/libevmasm/SimplificationRules.cpp @@ -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."); } diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp index 0d70fbf38..7a9b6576a 100644 --- a/libyul/optimiser/SimplificationRules.cpp +++ b/libyul/optimiser/SimplificationRules.cpp @@ -36,7 +36,7 @@ using namespace solidity::evmasm; using namespace solidity::langutil; using namespace solidity::yul; -SimplificationRule const* SimplificationRules::findFirstMatch( +SimplificationRules::Rule const* SimplificationRules::findFirstMatch( Expression const& _expr, Dialect const& _dialect, map const& _ssaValues @@ -46,7 +46,16 @@ SimplificationRule const* SimplificationRules::findFirstMatch( if (!instruction) return nullptr; - static SimplificationRules rules; + static std::map, std::unique_ptr> evmRules; + + std::optional version; + if (yul::EVMDialect const* evmDialect = dynamic_cast(&_dialect)) + version = evmDialect->evmVersion(); + + if (!evmRules[version]) + evmRules[version] = std::make_unique(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 const*>> return {}; } -void SimplificationRules::addRules(vector> const& _rules) +void SimplificationRules::addRules(std::vector const& _rules) { for (auto const& r: _rules) addRule(r); } -void SimplificationRules::addRule(SimplificationRule const& _rule) +void SimplificationRules::addRule(Rule const& _rule) { m_rules[uint8_t(_rule.pattern.instruction())].push_back(_rule); } -SimplificationRules::SimplificationRules() +SimplificationRules::SimplificationRules(std::optional _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."); } diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h index 1a438ce36..b897ed492 100644 --- a/libyul/optimiser/SimplificationRules.h +++ b/libyul/optimiser/SimplificationRules.h @@ -27,6 +27,8 @@ #include +#include + #include #include @@ -45,12 +47,14 @@ class Pattern; class SimplificationRules: public boost::noncopyable { public: - SimplificationRules(); + using Rule = evmasm::SimplificationRule; + + explicit SimplificationRules(std::optional _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 const* findFirstMatch( + static Rule const* findFirstMatch( Expression const& _expr, Dialect const& _dialect, std::map const& _ssaValues @@ -64,8 +68,8 @@ public: instructionAndArguments(Dialect const& _dialect, Expression const& _expr); private: - void addRules(std::vector> const& _rules); - void addRule(evmasm::SimplificationRule const& _rule); + void addRules(std::vector const& _rules); + void addRule(Rule const& _rule); void resetMatchGroups() { m_matchGroups.clear(); } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul new file mode 100644 index 000000000..693c05c42 --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_not_supported.yul @@ -0,0 +1,9 @@ +{ + let ret := balance(address()) +} +// ==== +// EVMVersion: =istanbul +// ---- +// step: expressionSimplifier +// +// { +// let a := address() +// let ret := selfbalance() +// } diff --git a/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul new file mode 100644 index 000000000..7b0a7524e --- /dev/null +++ b/test/libyul/yulOptimizerTests/expressionSimplifier/selfbalance_supported.yul @@ -0,0 +1,9 @@ +{ + let ret := balance(address()) +} +// ==== +// EVMVersion: >=istanbul +// ---- +// step: expressionSimplifier +// +// { let ret := selfbalance() }