mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Use builtin iszero for for loop condition rewriting.
This commit is contained in:
parent
324cc71b13
commit
4f80117eef
@ -61,6 +61,7 @@ struct Dialect: boost::noncopyable
|
||||
|
||||
virtual BuiltinFunction const* discardFunction() const { return nullptr; }
|
||||
virtual BuiltinFunction const* equalityFunction() const { return nullptr; }
|
||||
virtual BuiltinFunction const* booleanNegationFunction() const { return nullptr; }
|
||||
|
||||
virtual std::set<YulString> fixedFunctionNames() const { return {}; }
|
||||
|
||||
|
@ -70,6 +70,7 @@ struct EVMDialect: public Dialect
|
||||
|
||||
BuiltinFunctionForEVM const* discardFunction() const override { return builtin("pop"_yulstring); }
|
||||
BuiltinFunctionForEVM const* equalityFunction() const override { return builtin("eq"_yulstring); }
|
||||
BuiltinFunctionForEVM const* booleanNegationFunction() const override { return builtin("iszero"_yulstring); }
|
||||
|
||||
static EVMDialect const& looseAssemblyForEVM(langutil::EVMVersion _version);
|
||||
static EVMDialect const& strictAssemblyForEVM(langutil::EVMVersion _version);
|
||||
|
@ -47,6 +47,7 @@ struct WasmDialect: public Dialect
|
||||
BuiltinFunction const* builtin(YulString _name) const override;
|
||||
BuiltinFunction const* discardFunction() const override { return builtin("drop"_yulstring); }
|
||||
BuiltinFunction const* equalityFunction() const override { return builtin("i64.eq"_yulstring); }
|
||||
BuiltinFunction const* booleanNegationFunction() const override { return builtin("i64.eqz"_yulstring); }
|
||||
|
||||
std::set<YulString> fixedFunctionNames() const override { return {"main"_yulstring}; }
|
||||
|
||||
|
@ -25,7 +25,7 @@ using namespace yul;
|
||||
|
||||
void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
|
||||
{
|
||||
if (_forLoop.condition->type() != typeid(Literal))
|
||||
if (m_dialect.booleanNegationFunction() && _forLoop.condition->type() != typeid(Literal))
|
||||
{
|
||||
langutil::SourceLocation loc = locationOf(*_forLoop.condition);
|
||||
_forLoop.body.statements.insert(
|
||||
@ -33,9 +33,9 @@ void ForLoopConditionIntoBody::operator()(ForLoop& _forLoop)
|
||||
If {
|
||||
loc,
|
||||
make_unique<Expression>(
|
||||
FunctionalInstruction {
|
||||
FunctionCall {
|
||||
loc,
|
||||
eth::Instruction::ISZERO,
|
||||
{loc, m_dialect.booleanNegationFunction()->name},
|
||||
make_vector<Expression>(std::move(*_forLoop.condition))
|
||||
}
|
||||
),
|
||||
|
@ -17,6 +17,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <libyul/optimiser/ASTWalker.h>
|
||||
#include <libyul/Dialect.h>
|
||||
|
||||
namespace yul
|
||||
{
|
||||
@ -29,17 +30,22 @@ namespace yul
|
||||
* By moving the iteration check part into the ForLoop body, we can apply expression splitter
|
||||
* to the condition expression.
|
||||
*
|
||||
* This rewritter will skip loops that already have literal constant as iteration condition.
|
||||
* This rewriter will skip loops that already have literal constant as iteration condition.
|
||||
*
|
||||
* Requirements:
|
||||
* - The Disambiguator must be run upfront.
|
||||
* - To avoid unnecessary rewrite, it is recommended to run this rewriter after StructuralSimplifier.
|
||||
* - Only works for dialects with a builtin boolean negation function.
|
||||
*/
|
||||
class ForLoopConditionIntoBody: public ASTModifier
|
||||
{
|
||||
public:
|
||||
ForLoopConditionIntoBody(Dialect const& _dialect): m_dialect(_dialect) {}
|
||||
using ASTModifier::operator();
|
||||
void operator()(ForLoop& _forLoop) override;
|
||||
|
||||
private:
|
||||
Dialect const& m_dialect;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <libyul/optimiser/ExpressionJoiner.h>
|
||||
#include <libyul/optimiser/ExpressionInliner.h>
|
||||
#include <libyul/optimiser/FullInliner.h>
|
||||
#include <libyul/optimiser/ForLoopConditionIntoBody.h>
|
||||
#include <libyul/optimiser/ForLoopInitRewriter.h>
|
||||
#include <libyul/optimiser/Rematerialiser.h>
|
||||
#include <libyul/optimiser/UnusedPruner.h>
|
||||
@ -94,6 +95,7 @@ void OptimiserSuite::run(
|
||||
LiteralRematerialiser{_dialect}(ast);
|
||||
StructuralSimplifier{}(ast);
|
||||
ControlFlowSimplifier{_dialect}(ast);
|
||||
ForLoopConditionIntoBody{_dialect}(ast);
|
||||
BlockFlattener{}(ast);
|
||||
|
||||
// None of the above can make stack problems worse.
|
||||
|
@ -17,9 +17,9 @@ contract C {
|
||||
// optimize-yul: true
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 610600
|
||||
// executionCost: 645
|
||||
// totalCost: 611245
|
||||
// codeDepositCost: 624200
|
||||
// executionCost: 657
|
||||
// totalCost: 624857
|
||||
// external:
|
||||
// a(): 429
|
||||
// b(uint256): 884
|
||||
|
@ -141,7 +141,7 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
else if (m_optimizerStep == "forLoopConditionIntoBody")
|
||||
{
|
||||
disambiguate();
|
||||
ForLoopConditionIntoBody{}(*m_ast);
|
||||
ForLoopConditionIntoBody{*m_dialect}(*m_ast);
|
||||
}
|
||||
else if (m_optimizerStep == "forLoopInitRewriter")
|
||||
{
|
||||
|
@ -0,0 +1,77 @@
|
||||
{
|
||||
let _1 := 0
|
||||
let _33 := calldataload(_1)
|
||||
let sum_50_141 := _1
|
||||
let sum_50_146 := _1
|
||||
let sum_50 := _1
|
||||
let length_51 := calldataload(_33)
|
||||
let i_53_142 := _1
|
||||
let i_53_147 := _1
|
||||
let i_53 := _1
|
||||
for { }
|
||||
1
|
||||
{
|
||||
let _108 := 1
|
||||
let i_53_121 := add(i_53, _108)
|
||||
let i_53_144 := i_53_121
|
||||
let i_53_149 := i_53_121
|
||||
i_53 := i_53_121
|
||||
}
|
||||
{
|
||||
let _109 := lt(i_53, length_51)
|
||||
let _110 := iszero(_109)
|
||||
if _110 { break }
|
||||
let _114_128 := iszero(_109)
|
||||
if _114_128 { revert(_1, _1) }
|
||||
let _13_129 := 0x20
|
||||
let _115_130 := mul(i_53, _13_129)
|
||||
let _116_131 := add(_33, _115_130)
|
||||
let _117_132 := add(_116_131, _13_129)
|
||||
let v_122_133 := calldataload(_117_132)
|
||||
let sum_50_120 := add(sum_50, v_122_133)
|
||||
let sum_50_143 := sum_50_120
|
||||
let sum_50_148 := sum_50_120
|
||||
sum_50 := sum_50_120
|
||||
}
|
||||
sstore(_1, sum_50)
|
||||
}
|
||||
// ====
|
||||
// step: commonSubexpressionEliminator
|
||||
// ----
|
||||
// {
|
||||
// let _1 := 0
|
||||
// let _33 := calldataload(_1)
|
||||
// let sum_50_141 := _1
|
||||
// let sum_50_146 := _1
|
||||
// let sum_50 := _1
|
||||
// let length_51 := calldataload(_33)
|
||||
// let i_53_142 := _1
|
||||
// let i_53_147 := _1
|
||||
// let i_53 := _1
|
||||
// for { }
|
||||
// 1
|
||||
// {
|
||||
// let _108 := 1
|
||||
// let i_53_121 := add(i_53, _108)
|
||||
// let i_53_144 := i_53_121
|
||||
// let i_53_149 := i_53_121
|
||||
// i_53 := i_53_121
|
||||
// }
|
||||
// {
|
||||
// let _109 := lt(i_53, length_51)
|
||||
// let _110 := iszero(_109)
|
||||
// if _110 { break }
|
||||
// let _114_128 := _110
|
||||
// if _110 { revert(_1, _1) }
|
||||
// let _13_129 := 0x20
|
||||
// let _115_130 := mul(i_53, _13_129)
|
||||
// let _116_131 := add(_33, _115_130)
|
||||
// let _117_132 := add(_116_131, _13_129)
|
||||
// let v_122_133 := calldataload(_117_132)
|
||||
// let sum_50_120 := add(sum_50, v_122_133)
|
||||
// let sum_50_143 := sum_50_120
|
||||
// let sum_50_148 := sum_50_120
|
||||
// sum_50 := sum_50_120
|
||||
// }
|
||||
// sstore(_1, sum_50)
|
||||
// }
|
@ -471,8 +471,9 @@
|
||||
// pos := 64
|
||||
// let srcPtr := add(_2, pos_1)
|
||||
// let i := _1
|
||||
// for { } lt(i, length) { i := add(i, 1) }
|
||||
// for { } 1 { i := add(i, 1) }
|
||||
// {
|
||||
// if iszero(lt(i, length)) { break }
|
||||
// abi_encode_t_array$_t_contract$_C_$55_$3_memory_to_t_array$_t_address_$3_memory_ptr(mload(srcPtr), pos)
|
||||
// srcPtr := add(srcPtr, pos_1)
|
||||
// pos := add(pos, 0x60)
|
||||
@ -503,8 +504,9 @@
|
||||
// let src := add(offset, _1)
|
||||
// if gt(add(add(offset, mul(length, 0x40)), _1), end) { revert(0, 0) }
|
||||
// let i := 0
|
||||
// for { } lt(i, length) { i := add(i, 1) }
|
||||
// for { } 1 { i := add(i, 1) }
|
||||
// {
|
||||
// if iszero(lt(i, length)) { break }
|
||||
// if iszero(slt(add(src, 0x1f), end)) { revert(0, 0) }
|
||||
// let dst_1 := allocateMemory(array_allocation_size_t_array$_t_uint256_$2_memory(0x2))
|
||||
// let dst_2 := dst_1
|
||||
@ -512,8 +514,9 @@
|
||||
// let _2 := add(src, 0x40)
|
||||
// if gt(_2, end) { revert(0, 0) }
|
||||
// let i_1 := 0
|
||||
// for { } lt(i_1, 0x2) { i_1 := add(i_1, 1) }
|
||||
// for { } 1 { i_1 := add(i_1, 1) }
|
||||
// {
|
||||
// if iszero(lt(i_1, 0x2)) { break }
|
||||
// mstore(dst_1, calldataload(src_1))
|
||||
// dst_1 := add(dst_1, _1)
|
||||
// src_1 := add(src_1, _1)
|
||||
@ -535,8 +538,9 @@
|
||||
// let src := add(offset, _1)
|
||||
// if gt(add(add(offset, mul(length, _1)), _1), end) { revert(0, 0) }
|
||||
// let i := 0
|
||||
// for { } lt(i, length) { i := add(i, 1) }
|
||||
// for { } 1 { i := add(i, 1) }
|
||||
// {
|
||||
// if iszero(lt(i, length)) { break }
|
||||
// mstore(dst, calldataload(src))
|
||||
// dst := add(dst, _1)
|
||||
// src := add(src, _1)
|
||||
@ -546,8 +550,9 @@
|
||||
// {
|
||||
// let srcPtr := value
|
||||
// let i := 0
|
||||
// for { } lt(i, 0x3) { i := add(i, 1) }
|
||||
// for { } 1 { i := add(i, 1) }
|
||||
// {
|
||||
// if iszero(lt(i, 0x3)) { break }
|
||||
// mstore(pos, and(mload(srcPtr), sub(shl(160, 1), 1)))
|
||||
// srcPtr := add(srcPtr, 0x20)
|
||||
// pos := add(pos, 0x20)
|
||||
|
@ -254,8 +254,9 @@
|
||||
// let b := add(0x300, mul(n, 0x80))
|
||||
// let i := 0
|
||||
// let i_1 := i
|
||||
// for { } lt(i, n) { i := add(i, 0x01) }
|
||||
// for { } 1 { i := add(i, 0x01) }
|
||||
// {
|
||||
// if iszero(lt(i, n)) { break }
|
||||
// let _2 := add(calldataload(0x04), mul(i, 0xc0))
|
||||
// let noteIndex := add(_2, 0x24)
|
||||
// let k := i_1
|
||||
@ -373,8 +374,9 @@
|
||||
// function hashCommitments(notes, n)
|
||||
// {
|
||||
// let i := 0
|
||||
// for { } lt(i, n) { i := add(i, 0x01) }
|
||||
// for { } 1 { i := add(i, 0x01) }
|
||||
// {
|
||||
// if iszero(lt(i, n)) { break }
|
||||
// calldatacopy(add(0x300, mul(i, 0x80)), add(add(notes, mul(i, 0xc0)), 0x60), 0x80)
|
||||
// }
|
||||
// mstore(0, keccak256(0x300, mul(n, 0x80)))
|
||||
|
@ -151,7 +151,7 @@ public:
|
||||
ForLoopInitRewriter{}(*m_ast);
|
||||
break;
|
||||
case 'O':
|
||||
ForLoopConditionIntoBody{}(*m_ast);
|
||||
ForLoopConditionIntoBody{m_dialect}(*m_ast);
|
||||
break;
|
||||
case 'c':
|
||||
CommonSubexpressionEliminator::run(m_dialect, *m_ast);
|
||||
|
Loading…
Reference in New Issue
Block a user