mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Optimizer rules that combine shifts and masks.
This commit is contained in:
parent
66cea5abb6
commit
f6437a2016
@ -5,6 +5,7 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Optimizer: Add rule to simplify SHL/SHR combinations.
|
||||
* SMTChecker: Support inherited state variables.
|
||||
* SMTChecker: Support tuples and function calls with multiple return values.
|
||||
* SMTChecker: Support ``delete``.
|
||||
|
@ -188,12 +188,6 @@ inline bytes toCompactBigEndian(uint8_t _val, unsigned _min = 0)
|
||||
return (_min || _val) ? bytes{ _val } : bytes{};
|
||||
}
|
||||
|
||||
/// Workarounds shift left bug in boost <1.65.1.
|
||||
template <class S> S bigintShiftLeftWorkaround(S const& _a, unsigned _b)
|
||||
{
|
||||
return (S)(bigint(_a) << _b);
|
||||
}
|
||||
|
||||
/// Convenience function for conversion of a u256 to hex
|
||||
inline std::string toHex(u256 val, HexPrefix prefix = HexPrefix::DontAdd)
|
||||
{
|
||||
|
@ -47,6 +47,13 @@ template <class S> S modWorkaround(S const& _a, S const& _b)
|
||||
return (S)(bigint(_a) % bigint(_b));
|
||||
}
|
||||
|
||||
// This works around a bug fixed with Boost 1.64.
|
||||
// https://www.boost.org/doc/libs/1_68_0/libs/multiprecision/doc/html/boost_multiprecision/map/hist.html#boost_multiprecision.map.hist.multiprecision_2_3_1_boost_1_64
|
||||
inline u256 shlWorkaround(u256 const& _x, unsigned _amount)
|
||||
{
|
||||
return u256((bigint(_x) << _amount) & u256(-1));
|
||||
}
|
||||
|
||||
// simplificationRuleList below was split up into parts to prevent
|
||||
// stack overflows in the JavaScript optimizer for emscripten builds
|
||||
// that affected certain browser versions.
|
||||
@ -93,7 +100,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart1(
|
||||
{{Instruction::SHL, {A, B}}, [=]{
|
||||
if (A.d() > 255)
|
||||
return u256(0);
|
||||
return bigintShiftLeftWorkaround(B.d(), unsigned(A.d()));
|
||||
return shlWorkaround(B.d(), unsigned(A.d()));
|
||||
}, false},
|
||||
{{Instruction::SHR, {A, B}}, [=]{
|
||||
if (A.d() > 255)
|
||||
@ -365,6 +372,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
||||
}
|
||||
}
|
||||
|
||||
// Combine two SHL by constant
|
||||
rules.push_back({
|
||||
// SHL(B, SHL(A, X)) -> SHL(min(A+B, 256), X)
|
||||
{Instruction::SHL, {{B}, {Instruction::SHL, {{A}, {X}}}}},
|
||||
@ -378,6 +386,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
||||
false
|
||||
});
|
||||
|
||||
// Combine two SHR by constant
|
||||
rules.push_back({
|
||||
// SHR(B, SHR(A, X)) -> SHR(min(A+B, 256), X)
|
||||
{Instruction::SHR, {{B}, {Instruction::SHR, {{A}, {X}}}}},
|
||||
@ -391,6 +400,68 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
|
||||
false
|
||||
});
|
||||
|
||||
// Combine SHL-SHR by constant
|
||||
rules.push_back({
|
||||
// SHR(B, SHL(A, X)) -> AND(SH[L/R]([B - A / A - B], X), Mask)
|
||||
{Instruction::SHR, {{B}, {Instruction::SHL, {{A}, {X}}}}},
|
||||
[=]() -> Pattern {
|
||||
u256 mask = shlWorkaround(u256(-1), unsigned(A.d())) >> unsigned(B.d());
|
||||
|
||||
if (A.d() > B.d())
|
||||
return {Instruction::AND, {{Instruction::SHL, {A.d() - B.d(), X}}, mask}};
|
||||
else if (B.d() > A.d())
|
||||
return {Instruction::AND, {{Instruction::SHR, {B.d() - A.d(), X}}, mask}};
|
||||
else
|
||||
return {Instruction::AND, {X, mask}};
|
||||
},
|
||||
false,
|
||||
[=] { return A.d() < 256 && B.d() < 256; }
|
||||
});
|
||||
|
||||
// Combine SHR-SHL by constant
|
||||
rules.push_back({
|
||||
// SHL(B, SHR(A, X)) -> AND(SH[L/R]([B - A / A - B], X), Mask)
|
||||
{Instruction::SHL, {{B}, {Instruction::SHR, {{A}, {X}}}}},
|
||||
[=]() -> Pattern {
|
||||
u256 mask = shlWorkaround(u256(-1) >> unsigned(A.d()), unsigned(B.d()));
|
||||
|
||||
if (A.d() > B.d())
|
||||
return {Instruction::AND, {{Instruction::SHR, {A.d() - B.d(), X}}, mask}};
|
||||
else if (B.d() > A.d())
|
||||
return {Instruction::AND, {{Instruction::SHL, {B.d() - A.d(), X}}, mask}};
|
||||
else
|
||||
return {Instruction::AND, {X, mask}};
|
||||
},
|
||||
false,
|
||||
[=] { return A.d() < 256 && B.d() < 256; }
|
||||
});
|
||||
|
||||
// Move AND with constant across SHL and SHR by constant
|
||||
for (auto shiftOp: {Instruction::SHL, Instruction::SHR})
|
||||
{
|
||||
auto replacement = [=]() -> Pattern {
|
||||
u256 mask =
|
||||
shiftOp == Instruction::SHL ?
|
||||
shlWorkaround(A.d(), unsigned(B.d())) :
|
||||
A.d() >> unsigned(B.d());
|
||||
return {Instruction::AND, {{shiftOp, {B.d(), X}}, std::move(mask)}};
|
||||
};
|
||||
rules.push_back({
|
||||
// SH[L/R](B, AND(X, A)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
|
||||
{shiftOp, {{B}, {Instruction::AND, {{X}, {A}}}}},
|
||||
replacement,
|
||||
false,
|
||||
[=] { return B.d() < 256; }
|
||||
});
|
||||
rules.push_back({
|
||||
// SH[L/R](B, AND(A, X)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
|
||||
{shiftOp, {{B}, {Instruction::AND, {{A}, {X}}}}},
|
||||
replacement,
|
||||
false,
|
||||
[=] { return B.d() < 256; }
|
||||
});
|
||||
}
|
||||
|
||||
rules.push_back({
|
||||
// MUL(X, SHL(Y, 1)) -> SHL(Y, X)
|
||||
{Instruction::MUL, {X, {Instruction::SHL, {Y, u256(1)}}}},
|
||||
|
@ -27,29 +27,29 @@ contract Large {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 261800
|
||||
// codeDepositCost: 260400
|
||||
// executionCost: 300
|
||||
// totalCost: 262100
|
||||
// totalCost: 260700
|
||||
// external:
|
||||
// a(): 398
|
||||
// b(uint256): 1105
|
||||
// f0(uint256): 334
|
||||
// f1(uint256): 40886
|
||||
// f2(uint256): 20952
|
||||
// f3(uint256): 21040
|
||||
// f4(uint256): 21018
|
||||
// f5(uint256): 20996
|
||||
// f6(uint256): 20908
|
||||
// f7(uint256): 20688
|
||||
// f8(uint256): 20820
|
||||
// f9(uint256): 20842
|
||||
// f1(uint256): 40874
|
||||
// f2(uint256): 20940
|
||||
// f3(uint256): 21028
|
||||
// f4(uint256): 21006
|
||||
// f5(uint256): 20984
|
||||
// f6(uint256): 20896
|
||||
// f7(uint256): 20676
|
||||
// f8(uint256): 20808
|
||||
// f9(uint256): 20830
|
||||
// g0(uint256): 574
|
||||
// g1(uint256): 40598
|
||||
// g2(uint256): 20686
|
||||
// g3(uint256): 20774
|
||||
// g4(uint256): 20752
|
||||
// g5(uint256): 20840
|
||||
// g6(uint256): 20620
|
||||
// g7(uint256): 20730
|
||||
// g8(uint256): 20708
|
||||
// g9(uint256): 20554
|
||||
// g1(uint256): 40586
|
||||
// g2(uint256): 20674
|
||||
// g3(uint256): 20762
|
||||
// g4(uint256): 20740
|
||||
// g5(uint256): 20828
|
||||
// g6(uint256): 20608
|
||||
// g7(uint256): 20718
|
||||
// g8(uint256): 20696
|
||||
// g9(uint256): 20542
|
||||
|
@ -14,16 +14,16 @@ contract Medium {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 142200
|
||||
// executionCost: 190
|
||||
// totalCost: 142390
|
||||
// codeDepositCost: 140800
|
||||
// executionCost: 183
|
||||
// totalCost: 140983
|
||||
// external:
|
||||
// a(): 398
|
||||
// b(uint256): 863
|
||||
// f1(uint256): 40666
|
||||
// f2(uint256): 20710
|
||||
// f3(uint256): 20754
|
||||
// f1(uint256): 40654
|
||||
// f2(uint256): 20698
|
||||
// f3(uint256): 20742
|
||||
// g0(uint256): 332
|
||||
// g7(uint256): 20620
|
||||
// g8(uint256): 20598
|
||||
// g9(uint256): 20554
|
||||
// g7(uint256): 20608
|
||||
// g8(uint256): 20586
|
||||
// g9(uint256): 20542
|
||||
|
@ -9,11 +9,11 @@ contract Small {
|
||||
// optimize-runs: 2
|
||||
// ----
|
||||
// creation:
|
||||
// codeDepositCost: 65400
|
||||
// executionCost: 117
|
||||
// totalCost: 65517
|
||||
// codeDepositCost: 60400
|
||||
// executionCost: 111
|
||||
// totalCost: 60511
|
||||
// external:
|
||||
// fallback: 118
|
||||
// a(): 376
|
||||
// b(uint256): 753
|
||||
// f1(uint256): 40600
|
||||
// f1(uint256): 40588
|
||||
|
@ -188,6 +188,8 @@ TestCase::TestResult YulOptimizerTest::run(ostream& _stream, string const& _line
|
||||
{
|
||||
disambiguate();
|
||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
||||
ExpressionSimplifier::run(*m_dialect, *m_ast);
|
||||
}
|
||||
else if (m_optimizerStep == "fullSimplify")
|
||||
{
|
||||
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
let x := calldataload(0)
|
||||
let a := and(0xff, shr(248, shl(248, shr(248, x))))
|
||||
let b := shr(12, shl(8, and(x, 0xf0f0)))
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >byzantium
|
||||
// step: expressionSimplifier
|
||||
// ----
|
||||
// {
|
||||
// let x := calldataload(0)
|
||||
// let a := shr(248, x)
|
||||
// let b := and(shr(4, x), 3855)
|
||||
// }
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
let x := calldataload(0)
|
||||
let a := and(0xff, shr(248, shl(248, shr(248, and(x, 0xf)))))
|
||||
let b := shl(12, shr(4, and(x, 0xf0f0)))
|
||||
let c := shl(12, shr(4, and(0xf0f0, x)))
|
||||
let d := shl(12, shr(255, and(0xf0f0, x)))
|
||||
let e := shl(255, shr(4, and(0xf0f0, x)))
|
||||
let f := shl(12, shr(256, and(0xf0f0, x)))
|
||||
let g := shl(256, shr(4, and(0xf0f0, x)))
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >byzantium
|
||||
// step: expressionSimplifier
|
||||
// ----
|
||||
// {
|
||||
// let x := calldataload(0)
|
||||
// let a := 0
|
||||
// let b := and(shl(8, x), 15790080)
|
||||
// let c := and(shl(8, x), 15790080)
|
||||
// let d := 0
|
||||
// let e := and(shl(251, x), 0x8000000000000000000000000000000000000000000000000000000000000000)
|
||||
// let f := 0
|
||||
// let g := 0
|
||||
// }
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
let x := calldataload(0)
|
||||
let a := shl(12, shr(4, x))
|
||||
let b := shl(4, shr(12, x))
|
||||
let c := shr(12, shl(4, x))
|
||||
let d := shr(4, shl(12, x))
|
||||
let e := shl(150, shr(2, shl(150, x)))
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >byzantium
|
||||
// step: expressionSimplifier
|
||||
// ----
|
||||
// {
|
||||
// let x := calldataload(0)
|
||||
// let a := and(shl(8, x), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000)
|
||||
// let b := and(shr(8, x), 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0)
|
||||
// let c := and(shr(8, x), 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
|
||||
// let d := and(shl(8, x), 0x0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00)
|
||||
// let e := 0
|
||||
// }
|
Loading…
Reference in New Issue
Block a user