Merge pull request #5959 from ethereum/optimiser2

Introduce global optimiser settings.
This commit is contained in:
chriseth
2019-03-04 12:54:59 +01:00
committed by GitHub
37 changed files with 905 additions and 219 deletions
+1
View File
@@ -0,0 +1 @@
--gas
+3
View File
@@ -0,0 +1,3 @@
gas_test_abiv2/input.sol:2:1: Warning: Experimental features are turned on. Do not use experimental features on live deployments.
pragma experimental ABIEncoderV2;
^-------------------------------^
@@ -0,0 +1,15 @@
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract C {
uint public a;
uint[] public b;
function f1(uint) public pure returns (uint) { }
function f2(uint[] memory, string[] memory, uint16, address) public returns (uint[] memory, uint16[] memory) {}
function f3(uint16[] memory, string[] memory, uint16, address) public returns (uint[] memory, uint16[] memory) {}
function f4(uint32[] memory, string[12] memory, bytes[2][] memory, address) public returns (uint[] memory, uint16[] memory) {}
function f5(address[] memory, string[] memory, bytes memory, address) public returns (uint[] memory, uint16[] memory) {}
function f6(uint[30] memory, string[] memory, uint16, address) public returns (uint16[200] memory, uint16[] memory) {}
function f7(uint[31] memory, string[20] memory, C, address) public returns (bytes[] memory, uint16[] memory) {}
function f8(uint[32] memory, string[] memory, uint32, address) public returns (uint[] memory, uint16[] memory) {}
}
+16
View File
@@ -0,0 +1,16 @@
======= gas_test_abiv2/input.sol:C =======
Gas estimation:
construction:
1154 + 1109000 = 1110154
external:
a(): 535
b(uint256): 1129
f1(uint256): 591
f2(uint256[],string[],uint16,address): infinite
f3(uint16[],string[],uint16,address): infinite
f4(uint32[],string[12],bytes[2][],address): infinite
f5(address[],string[],bytes,address): infinite
f6(uint256[30],string[],uint16,address): infinite
f7(uint256[31],string[20],address,address): infinite
f8(uint256[32],string[],uint32,address): infinite
@@ -0,0 +1 @@
--gas --optimize --optimize-yul
@@ -0,0 +1,3 @@
gas_test_abiv2_optimize_yul/input.sol:2:1: Warning: Experimental features are turned on. Do not use experimental features on live deployments.
pragma experimental ABIEncoderV2;
^-------------------------------^
@@ -0,0 +1,15 @@
pragma solidity >=0.0;
pragma experimental ABIEncoderV2;
contract C {
uint public a;
uint[] public b;
function f1(uint) public pure returns (uint) { }
function f2(uint[] memory, string[] memory, uint16, address) public returns (uint[] memory, uint16[] memory) {}
function f3(uint16[] memory, string[] memory, uint16, address) public returns (uint[] memory, uint16[] memory) {}
function f4(uint32[] memory, string[12] memory, bytes[2][] memory, address) public returns (uint[] memory, uint16[] memory) {}
function f5(address[] memory, string[] memory, bytes memory, address) public returns (uint[] memory, uint16[] memory) {}
function f6(uint[30] memory, string[] memory, uint16, address) public returns (uint16[200] memory, uint16[] memory) {}
function f7(uint[31] memory, string[20] memory, C, address) public returns (bytes[] memory, uint16[] memory) {}
function f8(uint[32] memory, string[] memory, uint32, address) public returns (uint[] memory, uint16[] memory) {}
}
@@ -0,0 +1,16 @@
======= gas_test_abiv2_optimize_yul/input.sol:C =======
Gas estimation:
construction:
676 + 641600 = 642276
external:
a(): 434
b(uint256): 892
f1(uint256): 356
f2(uint256[],string[],uint16,address): infinite
f3(uint16[],string[],uint16,address): infinite
f4(uint32[],string[12],bytes[2][],address): infinite
f5(address[],string[],bytes,address): infinite
f6(uint256[30],string[],uint16,address): infinite
f7(uint256[31],string[20],address,address): infinite
f8(uint256[32],string[],uint32,address): infinite
@@ -0,0 +1,16 @@
{
"language": "Solidity",
"sources":
{
"A":
{
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
}
},
"settings":
{
"optimizer": {
"details": { "peephole": 7 }
}
}
}
@@ -0,0 +1 @@
{"errors":[{"component":"general","formattedMessage":"\"settings.optimizer.details.peephole\" must be Boolean","message":"\"settings.optimizer.details.peephole\" must be Boolean","severity":"error","type":"JSONError"}]}
@@ -0,0 +1,16 @@
{
"language": "Solidity",
"sources":
{
"A":
{
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
}
},
"settings":
{
"optimizer": {
"details": { "notThere": true }
}
}
}
@@ -0,0 +1 @@
{"errors":[{"component":"general","formattedMessage":"Unknown key \"notThere\"","message":"Unknown key \"notThere\"","severity":"error","type":"JSONError"}]}
@@ -0,0 +1,16 @@
{
"language": "Solidity",
"sources":
{
"A":
{
"content": "pragma solidity >=0.0; contract C { function f() public pure {} }"
}
},
"settings":
{
"optimizer": {
"details": { "yulDetails": 7 }
}
}
}
@@ -0,0 +1 @@
{"errors":[{"component":"general","formattedMessage":"The \"yulDetails\" optimizer setting has to be a JSON object.","message":"The \"yulDetails\" optimizer setting has to be a JSON object.","severity":"error","type":"JSONError"}]}
+1 -1
View File
@@ -1053,7 +1053,7 @@ BOOST_AUTO_TEST_CASE(jumpdest_removal_subassemblies)
main.append(t1.toSubAssemblyTag(subId));
main.append(u256(8));
main.optimise(true, dev::test::Options::get().evmVersion());
main.optimise(true, dev::test::Options::get().evmVersion(), false, 200);
AssemblyItems expectationMain{
AssemblyItem(PushSubSize, 0),
+33 -15
View File
@@ -84,7 +84,10 @@ eth::AssemblyItems compileContract(std::shared_ptr<CharStream> _sourceCode)
for (ASTPointer<ASTNode> const& node: sourceUnit->nodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
Compiler compiler(dev::test::Options::get().evmVersion());
Compiler compiler(
dev::test::Options::get().evmVersion(),
dev::test::Options::get().optimize ? OptimiserSettings::enabled() : OptimiserSettings::minimal()
);
compiler.compileContract(*contract, map<ContractDefinition const*, shared_ptr<Compiler const>>{}, bytes());
return compiler.runtimeAssemblyItems();
@@ -165,20 +168,35 @@ BOOST_AUTO_TEST_CASE(location_test)
auto codegenCharStream = make_shared<CharStream>("", "--CODEGEN--");
vector<SourceLocation> locations =
vector<SourceLocation>(4, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{8, 17, codegenCharStream}) +
vector<SourceLocation>(3, SourceLocation{5, 7, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{30, 31, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{27, 28, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{20, 32, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{5, 7, codegenCharStream}) +
vector<SourceLocation>(hasShifts ? 19 : 20, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(24, SourceLocation{20, 79, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{49, 58, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{72, 74, sourceCode}) +
vector<SourceLocation>(2, SourceLocation{65, 74, sourceCode}) +
vector<SourceLocation>(2, SourceLocation{20, 79, sourceCode});
vector<SourceLocation> locations;
if (dev::test::Options::get().optimize)
locations =
vector<SourceLocation>(4, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{8, 17, codegenCharStream}) +
vector<SourceLocation>(3, SourceLocation{5, 7, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{30, 31, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{27, 28, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{20, 32, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{5, 7, codegenCharStream}) +
vector<SourceLocation>(19, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(21, SourceLocation{20, 79, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{72, 74, sourceCode}) +
vector<SourceLocation>(2, SourceLocation{20, 79, sourceCode});
else
locations =
vector<SourceLocation>(4, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{8, 17, codegenCharStream}) +
vector<SourceLocation>(3, SourceLocation{5, 7, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{30, 31, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{27, 28, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{20, 32, codegenCharStream}) +
vector<SourceLocation>(1, SourceLocation{5, 7, codegenCharStream}) +
vector<SourceLocation>(hasShifts ? 19 : 20, SourceLocation{2, 82, sourceCode}) +
vector<SourceLocation>(24, SourceLocation{20, 79, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{49, 58, sourceCode}) +
vector<SourceLocation>(1, SourceLocation{72, 74, sourceCode}) +
vector<SourceLocation>(2, SourceLocation{65, 74, sourceCode}) +
vector<SourceLocation>(2, SourceLocation{20, 79, sourceCode});
checkAssemblyLocations(items, locations);
}
+200 -114
View File
@@ -153,7 +153,7 @@ bytes compileFirstExpression(
parametersSize--
);
ExpressionCompiler(context).compile(*extractor.expression());
ExpressionCompiler(context, dev::test::Options::get().optimize).compile(*extractor.expression());
for (vector<string> const& function: _functions)
context << context.functionEntryLabel(dynamic_cast<FunctionDefinition const&>(
@@ -282,12 +282,26 @@ BOOST_AUTO_TEST_CASE(comparison)
)";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH2), 0x11, 0xaa,
uint8_t(Instruction::PUSH2), 0x10, 0xaa,
uint8_t(Instruction::LT), uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)});
bytes expectation;
if (dev::test::Options::get().optimize)
expectation = {
uint8_t(Instruction::PUSH2), 0x11, 0xaa,
uint8_t(Instruction::PUSH2), 0x10, 0xaa,
uint8_t(Instruction::LT), uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)
};
else
expectation = {
uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH2), 0x11, 0xaa,
uint8_t(Instruction::PUSH2), 0x10, 0xaa,
uint8_t(Instruction::LT), uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)
};
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -300,23 +314,25 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
)";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({uint8_t(Instruction::PUSH1), 0x12, // 8 + 10
uint8_t(Instruction::PUSH1), 0x4,
uint8_t(Instruction::GT),
uint8_t(Instruction::ISZERO), // after this we have 4 <= 8 + 10
uint8_t(Instruction::DUP1),
uint8_t(Instruction::PUSH1), 0x11,
uint8_t(Instruction::JUMPI), // short-circuit if it is true
uint8_t(Instruction::POP),
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::PUSH1), 0x9,
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO), // after this we have 9 != 2
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)});
bytes expectation{
uint8_t(Instruction::PUSH1), 0x12, // 8 + 10
uint8_t(Instruction::PUSH1), 0x4,
uint8_t(Instruction::GT),
uint8_t(Instruction::ISZERO), // after this we have 4 <= 8 + 10
uint8_t(Instruction::DUP1),
uint8_t(Instruction::PUSH1), 0x11,
uint8_t(Instruction::JUMPI), // short-circuit if it is true
uint8_t(Instruction::POP),
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::PUSH1), 0x9,
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO), // after this we have 9 != 2
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)
};
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -328,37 +344,76 @@ BOOST_AUTO_TEST_CASE(arithmetic)
}
)";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
bytes expectation({uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::PUSH1), 0x3,
uint8_t(Instruction::PUSH1), 0x4,
uint8_t(Instruction::PUSH1), 0x5,
uint8_t(Instruction::PUSH1), 0x6,
uint8_t(Instruction::PUSH1), 0x7,
uint8_t(Instruction::PUSH1), 0x8,
uint8_t(Instruction::DUP9),
uint8_t(Instruction::XOR),
uint8_t(Instruction::AND),
uint8_t(Instruction::OR),
uint8_t(Instruction::SUB),
uint8_t(Instruction::ADD),
uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1d,
uint8_t(Instruction::JUMPI),
uint8_t(Instruction::INVALID),
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::MOD),
uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x26,
uint8_t(Instruction::JUMPI),
uint8_t(Instruction::INVALID),
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::DIV),
uint8_t(Instruction::MUL)});
bytes expectation;
if (dev::test::Options::get().optimize)
expectation = {
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::PUSH1), 0x3,
uint8_t(Instruction::PUSH1), 0x5,
uint8_t(Instruction::DUP4),
uint8_t(Instruction::PUSH1), 0x8,
uint8_t(Instruction::XOR),
uint8_t(Instruction::PUSH1), 0x7,
uint8_t(Instruction::AND),
uint8_t(Instruction::PUSH1), 0x6,
uint8_t(Instruction::OR),
uint8_t(Instruction::SUB),
uint8_t(Instruction::PUSH1), 0x4,
uint8_t(Instruction::ADD),
uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1b,
uint8_t(Instruction::JUMPI),
uint8_t(Instruction::INVALID),
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::MOD),
uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x24,
uint8_t(Instruction::JUMPI),
uint8_t(Instruction::INVALID),
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::DIV),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::MUL)
};
else
expectation = {
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::PUSH1), 0x3,
uint8_t(Instruction::PUSH1), 0x4,
uint8_t(Instruction::PUSH1), 0x5,
uint8_t(Instruction::PUSH1), 0x6,
uint8_t(Instruction::PUSH1), 0x7,
uint8_t(Instruction::PUSH1), 0x8,
uint8_t(Instruction::DUP9),
uint8_t(Instruction::XOR),
uint8_t(Instruction::AND),
uint8_t(Instruction::OR),
uint8_t(Instruction::SUB),
uint8_t(Instruction::ADD),
uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1d,
uint8_t(Instruction::JUMPI),
uint8_t(Instruction::INVALID),
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::MOD),
uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x26,
uint8_t(Instruction::JUMPI),
uint8_t(Instruction::INVALID),
uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::DIV),
uint8_t(Instruction::MUL)
};
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -371,13 +426,27 @@ BOOST_AUTO_TEST_CASE(unary_operators)
)";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
bytes expectation({uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::DUP2),
uint8_t(Instruction::PUSH1), 0x0,
uint8_t(Instruction::SUB),
uint8_t(Instruction::NOT),
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)});
bytes expectation;
if (dev::test::Options::get().optimize)
expectation = {
uint8_t(Instruction::DUP1),
uint8_t(Instruction::PUSH1), 0x0,
uint8_t(Instruction::SUB),
uint8_t(Instruction::NOT),
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)
};
else
expectation = {
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::DUP2),
uint8_t(Instruction::PUSH1), 0x0,
uint8_t(Instruction::SUB),
uint8_t(Instruction::NOT),
uint8_t(Instruction::EQ),
uint8_t(Instruction::ISZERO)
};
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -391,48 +460,50 @@ BOOST_AUTO_TEST_CASE(unary_inc_dec)
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "x"}});
// Stack: a, x
bytes expectation({uint8_t(Instruction::DUP2),
uint8_t(Instruction::DUP1),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::ADD),
// Stack here: a x a (a+1)
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP), // first ++
// Stack here: (a+1) x a
uint8_t(Instruction::DUP3),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::ADD),
// Stack here: (a+1) x a (a+2)
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP),
// Stack here: (a+2) x a
uint8_t(Instruction::DUP3), // second ++
uint8_t(Instruction::XOR),
// Stack here: (a+2) x a^(a+2)
uint8_t(Instruction::DUP3),
uint8_t(Instruction::DUP1),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::SWAP1),
uint8_t(Instruction::SUB),
// Stack here: (a+2) x a^(a+2) (a+2) (a+1)
uint8_t(Instruction::SWAP4),
uint8_t(Instruction::POP), // first --
uint8_t(Instruction::XOR),
// Stack here: (a+1) x a^(a+2)^(a+2)
uint8_t(Instruction::DUP3),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::SWAP1),
uint8_t(Instruction::SUB),
// Stack here: (a+1) x a^(a+2)^(a+2) a
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP), // second ++
// Stack here: a x a^(a+2)^(a+2)
uint8_t(Instruction::DUP3), // will change
uint8_t(Instruction::XOR),
uint8_t(Instruction::SWAP1),
uint8_t(Instruction::POP),
uint8_t(Instruction::DUP1)});
// Stack here: a x a^(a+2)^(a+2)^a
bytes expectation{
uint8_t(Instruction::DUP2),
uint8_t(Instruction::DUP1),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::ADD),
// Stack here: a x a (a+1)
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP), // first ++
// Stack here: (a+1) x a
uint8_t(Instruction::DUP3),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::ADD),
// Stack here: (a+1) x a (a+2)
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP),
// Stack here: (a+2) x a
uint8_t(Instruction::DUP3), // second ++
uint8_t(Instruction::XOR),
// Stack here: (a+2) x a^(a+2)
uint8_t(Instruction::DUP3),
uint8_t(Instruction::DUP1),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::SWAP1),
uint8_t(Instruction::SUB),
// Stack here: (a+2) x a^(a+2) (a+2) (a+1)
uint8_t(Instruction::SWAP4),
uint8_t(Instruction::POP), // first --
uint8_t(Instruction::XOR),
// Stack here: (a+1) x a^(a+2)^(a+2)
uint8_t(Instruction::DUP3),
uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::SWAP1),
uint8_t(Instruction::SUB),
// Stack here: (a+1) x a^(a+2)^(a+2) a
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP), // second ++
// Stack here: a x a^(a+2)^(a+2)
uint8_t(Instruction::DUP3), // will change
uint8_t(Instruction::XOR),
uint8_t(Instruction::SWAP1),
uint8_t(Instruction::POP),
uint8_t(Instruction::DUP1)
};
// Stack here: a x a^(a+2)^(a+2)^a
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@@ -446,16 +517,31 @@ BOOST_AUTO_TEST_CASE(assignment)
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b
bytes expectation({uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::DUP2),
uint8_t(Instruction::DUP4),
uint8_t(Instruction::ADD),
// Stack here: a b 2 a+b
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP),
uint8_t(Instruction::DUP3),
// Stack here: a+b b 2 a+b
uint8_t(Instruction::MUL)});
bytes expectation;
if (dev::test::Options::get().optimize)
expectation = {
uint8_t(Instruction::DUP1),
uint8_t(Instruction::DUP3),
uint8_t(Instruction::ADD),
uint8_t(Instruction::SWAP2),
uint8_t(Instruction::POP),
uint8_t(Instruction::DUP2),
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::MUL)
};
else
expectation = {
uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::DUP2),
uint8_t(Instruction::DUP4),
uint8_t(Instruction::ADD),
// Stack here: a b 2 a+b
uint8_t(Instruction::SWAP3),
uint8_t(Instruction::POP),
uint8_t(Instruction::DUP3),
// Stack here: a+b b 2 a+b
uint8_t(Instruction::MUL)
};
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
+154 -1
View File
@@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(optimizer_enabled_not_boolean)
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsError(result, "JSONError", "The \"enabled\" setting must be a boolean."));
BOOST_CHECK(containsError(result, "JSONError", "The \"enabled\" setting must be a Boolean."));
}
BOOST_AUTO_TEST_CASE(optimizer_runs_not_a_number)
@@ -859,6 +859,159 @@ BOOST_AUTO_TEST_CASE(evm_version)
BOOST_CHECK(result["errors"][0]["message"].asString() == "Invalid EVM version requested.");
}
BOOST_AUTO_TEST_CASE(optimizer_settings_default_disabled)
{
char const* input = R"(
{
"language": "Solidity",
"settings": {
"outputSelection": {
"fileA": { "A": [ "metadata" ] }
}
},
"sources": {
"fileA": {
"content": "contract A { }"
}
}
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsAtMostWarnings(result));
Json::Value contract = getContractResult(result, "fileA", "A");
BOOST_CHECK(contract.isObject());
BOOST_CHECK(contract["metadata"].isString());
Json::Value metadata;
BOOST_CHECK(jsonParseStrict(contract["metadata"].asString(), metadata));
Json::Value const& optimizer = metadata["settings"]["optimizer"];
BOOST_CHECK(optimizer.isMember("enabled"));
BOOST_CHECK(optimizer["enabled"].asBool() == false);
BOOST_CHECK(!optimizer.isMember("details"));
BOOST_CHECK(optimizer["runs"].asUInt() == 200);
}
BOOST_AUTO_TEST_CASE(optimizer_settings_default_enabled)
{
char const* input = R"(
{
"language": "Solidity",
"settings": {
"outputSelection": {
"fileA": { "A": [ "metadata" ] }
},
"optimizer": { "enabled": true }
},
"sources": {
"fileA": {
"content": "contract A { }"
}
}
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsAtMostWarnings(result));
Json::Value contract = getContractResult(result, "fileA", "A");
BOOST_CHECK(contract.isObject());
BOOST_CHECK(contract["metadata"].isString());
Json::Value metadata;
BOOST_CHECK(jsonParseStrict(contract["metadata"].asString(), metadata));
Json::Value const& optimizer = metadata["settings"]["optimizer"];
BOOST_CHECK(optimizer.isMember("enabled"));
BOOST_CHECK(optimizer["enabled"].asBool() == true);
BOOST_CHECK(!optimizer.isMember("details"));
BOOST_CHECK(optimizer["runs"].asUInt() == 200);
}
BOOST_AUTO_TEST_CASE(optimizer_settings_details_exactly_as_default_disabled)
{
char const* input = R"(
{
"language": "Solidity",
"settings": {
"outputSelection": {
"fileA": { "A": [ "metadata" ] }
},
"optimizer": { "details": {
"constantOptimizer" : false,
"cse" : false,
"deduplicate" : false,
"jumpdestRemover" : true,
"orderLiterals" : false,
"peephole" : true
} }
},
"sources": {
"fileA": {
"content": "contract A { }"
}
}
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsAtMostWarnings(result));
Json::Value contract = getContractResult(result, "fileA", "A");
BOOST_CHECK(contract.isObject());
BOOST_CHECK(contract["metadata"].isString());
Json::Value metadata;
BOOST_CHECK(jsonParseStrict(contract["metadata"].asString(), metadata));
Json::Value const& optimizer = metadata["settings"]["optimizer"];
BOOST_CHECK(optimizer.isMember("enabled"));
// enabled is switched to false instead!
BOOST_CHECK(optimizer["enabled"].asBool() == false);
BOOST_CHECK(!optimizer.isMember("details"));
BOOST_CHECK(optimizer["runs"].asUInt() == 200);
}
BOOST_AUTO_TEST_CASE(optimizer_settings_details_different)
{
char const* input = R"(
{
"language": "Solidity",
"settings": {
"outputSelection": {
"fileA": { "A": [ "metadata" ] }
},
"optimizer": { "runs": 600, "details": {
"constantOptimizer" : true,
"cse" : false,
"deduplicate" : true,
"jumpdestRemover" : true,
"orderLiterals" : false,
"peephole" : true,
"yul": true
} }
},
"sources": {
"fileA": {
"content": "contract A { }"
}
}
}
)";
Json::Value result = compile(input);
BOOST_CHECK(containsAtMostWarnings(result));
Json::Value contract = getContractResult(result, "fileA", "A");
BOOST_CHECK(contract.isObject());
BOOST_CHECK(contract["metadata"].isString());
Json::Value metadata;
BOOST_CHECK(jsonParseStrict(contract["metadata"].asString(), metadata));
Json::Value const& optimizer = metadata["settings"]["optimizer"];
BOOST_CHECK(!optimizer.isMember("enabled"));
BOOST_CHECK(optimizer.isMember("details"));
BOOST_CHECK(optimizer["details"]["constantOptimizer"].asBool() == true);
BOOST_CHECK(optimizer["details"]["cse"].asBool() == false);
BOOST_CHECK(optimizer["details"]["deduplicate"].asBool() == true);
BOOST_CHECK(optimizer["details"]["jumpdestRemover"].asBool() == true);
BOOST_CHECK(optimizer["details"]["orderLiterals"].asBool() == false);
BOOST_CHECK(optimizer["details"]["peephole"].asBool() == true);
BOOST_CHECK(optimizer["details"]["yulDetails"].isObject());
BOOST_CHECK_EQUAL(optimizer["details"].getMemberNames().size(), 8);
BOOST_CHECK(optimizer["runs"].asUInt() == 600);
}
BOOST_AUTO_TEST_SUITE_END()