From d20b3c9f9fb9b0811b09ceca911eb671738cf064 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 4 Apr 2019 17:48:29 +0200 Subject: [PATCH 1/5] Function grouper is a requirement for the VarNameCleaner. --- libyul/optimiser/Suite.cpp | 1 + libyul/optimiser/VarNameCleaner.h | 2 +- test/cmdlineTests.sh | 2 +- test/cmdlineTests/object_compiler/output | 16 +- .../standard_yul_optimized/output.json | 2 +- test/cmdlineTests/yul_stack_opt/output | 8 +- .../yulOptimizerTests/fullSuite/abi2.yul | 22 ++- .../fullSuite/abi_example1.yul | 98 ++++----- .../yulOptimizerTests/fullSuite/aztec.yul | 186 +++++++++--------- .../yulOptimizerTests/fullSuite/medium.yul | 14 +- .../reuse_vars_bug_in_simplifier.yul | 4 +- .../fullSuite/ssaReverse.yul | 18 +- .../fullSuite/ssaReverseComplex.yul | 14 +- .../fullSuite/switch_inline.yul | 4 +- .../fullSuite/switch_inline_match_default.yul | 4 +- .../ssaTransform/multi_decl.yul | 20 +- 16 files changed, 220 insertions(+), 195 deletions(-) diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp index 71a7ed70a..855185a65 100644 --- a/libyul/optimiser/Suite.cpp +++ b/libyul/optimiser/Suite.cpp @@ -198,6 +198,7 @@ void OptimiserSuite::run( BlockFlattener{}(ast); DeadCodeEliminator{}(ast); + FunctionGrouper{}(ast); VarNameCleaner{ast, *_dialect, reservedIdentifiers}(ast); yul::AsmAnalyzer::analyzeStrictAssertCorrect(_dialect, ast); diff --git a/libyul/optimiser/VarNameCleaner.h b/libyul/optimiser/VarNameCleaner.h index 250cd8417..7f2e90989 100644 --- a/libyul/optimiser/VarNameCleaner.h +++ b/libyul/optimiser/VarNameCleaner.h @@ -38,7 +38,7 @@ struct Dialect; * renumbered by their base name. * Function names are not modified. * - * Prerequisites: Disambiguator, FunctionHoister + * Prerequisites: Disambiguator, FunctionHoister, FunctionGrouper */ class VarNameCleaner: public ASTModifier { diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 76aa0229e..5e69425ba 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -343,7 +343,7 @@ printTask "Testing assemble, yul, strict-assembly and optimize..." # while it results in empty binary representation with optimizations turned on. test_solc_assembly_output "{ let x:u256 := 0:u256 }" "{ let x:u256 := 0:u256 }" "--yul" test_solc_assembly_output "{ let x := 0 }" "{ let x := 0 }" "--strict-assembly" - test_solc_assembly_output "{ let x := 0 }" "{ }" "--strict-assembly --optimize" + test_solc_assembly_output "{ let x := 0 }" "{ { } }" "--strict-assembly --optimize" ) diff --git a/test/cmdlineTests/object_compiler/output b/test/cmdlineTests/object_compiler/output index 51830a0c0..c8dcc5a82 100644 --- a/test/cmdlineTests/object_compiler/output +++ b/test/cmdlineTests/object_compiler/output @@ -4,15 +4,19 @@ Pretty printed source: object "MyContract" { code { - sstore(0, caller()) - let _1 := datasize("Runtime") - datacopy(0, dataoffset("Runtime"), _1) - return(0, _1) + { + sstore(0, caller()) + let _1 := datasize("Runtime") + datacopy(0, dataoffset("Runtime"), _1) + return(0, _1) + } } object "Runtime" { code { - mstore(0, sload(0)) - return(0, 0x20) + { + mstore(0, sload(0)) + return(0, 0x20) + } } } } diff --git a/test/cmdlineTests/standard_yul_optimized/output.json b/test/cmdlineTests/standard_yul_optimized/output.json index 80b764ece..fe4992a9f 100644 --- a/test/cmdlineTests/standard_yul_optimized/output.json +++ b/test/cmdlineTests/standard_yul_optimized/output.json @@ -1 +1 @@ -{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */\n 0x00\n 0x00\n /* \"A\":11:19 */\n mload\n /* \"A\":20:40 */\n sstore\n","bytecode":{"linkReferences":{},"object":"600060005155","opcodes":"PUSH1 0x0 PUSH1 0x0 MLOAD SSTORE ","sourceMap":""}},"ir":"object \"object\" {\n code {\n let x := mload(0)\n sstore(add(x, 0), 0)\n }\n}\n","irOptimized":"object \"object\" {\n code {\n sstore(mload(0), 0)\n }\n}\n"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} +{"contracts":{"A":{"object":{"evm":{"assembly":" /* \"A\":17:18 */\n 0x00\n 0x00\n /* \"A\":11:19 */\n mload\n /* \"A\":20:40 */\n sstore\n","bytecode":{"linkReferences":{},"object":"600060005155","opcodes":"PUSH1 0x0 PUSH1 0x0 MLOAD SSTORE ","sourceMap":""}},"ir":"object \"object\" {\n code {\n let x := mload(0)\n sstore(add(x, 0), 0)\n }\n}\n","irOptimized":"object \"object\" {\n code {\n {\n sstore(mload(0), 0)\n }\n }\n}\n"}}},"errors":[{"component":"general","formattedMessage":"Yul is still experimental. Please use the output with care.","message":"Yul is still experimental. Please use the output with care.","severity":"warning","type":"Warning"}]} diff --git a/test/cmdlineTests/yul_stack_opt/output b/test/cmdlineTests/yul_stack_opt/output index c8e10fe86..b37cd03d8 100644 --- a/test/cmdlineTests/yul_stack_opt/output +++ b/test/cmdlineTests/yul_stack_opt/output @@ -4,9 +4,11 @@ Pretty printed source: object "object" { code { - let a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1 := fun() - let a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2 := fun() - sstore(a1, a2) + { + let a1, b1, c1, d1, e1, f1, g1, h1, i1, j1, k1, l1, m1, n1, o1, p1 := fun() + let a2, b2, c2, d2, e2, f2, g2, h2, i2, j2, k2, l2, m2, n2, o2, p2 := fun() + sstore(a1, a2) + } function fun() -> a3, b3, c3, d3, e3, f3, g3, h3, i3, j3, k3, l3, m3, n3, o3, p3 { let a := 1 diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul index 6cffd0765..1983f2ebe 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi2.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi2.yul @@ -1073,18 +1073,20 @@ // step: fullSuite // ---- // { -// let _1 := mload(1) -// let _2 := mload(0) -// if slt(sub(_1, _2), 64) // { -// revert(0, 0) +// let _1 := mload(1) +// let _2 := mload(0) +// if slt(sub(_1, _2), 64) +// { +// revert(0, 0) +// } +// sstore(0, and(calldataload(_2), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) +// let x0, x1, x2, x3, x4 := abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(mload(7), mload(8)) +// sstore(x1, x0) +// sstore(x3, x2) +// sstore(1, x4) +// pop(abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(mload(30), mload(31), mload(32), mload(33), mload(34), mload(35), mload(36), mload(37), mload(38), mload(39), mload(40), mload(41))) // } -// sstore(0, and(calldataload(_2), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) -// let x0, x1, x2, x3, x4 := abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(mload(7), mload(8)) -// sstore(x1, x0) -// sstore(x3, x2) -// sstore(1, x4) -// pop(abi_encode_tuple_t_bytes32_t_address_t_uint256_t_bytes32_t_enum$_Operation_$1949_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256__to_t_bytes32_t_address_t_uint256_t_bytes32_t_uint8_t_uint256_t_uint256_t_uint256_t_address_t_address_t_uint256_(mload(30), mload(31), mload(32), mload(33), mload(34), mload(35), mload(36), mload(37), mload(38), mload(39), mload(40), mload(41))) // function abi_decode_tuple_t_addresst_uint256t_bytes_calldata_ptrt_enum$_Operation_$1949(headStart, dataEnd) -> value0, value1, value2, value3, value4 // { // if slt(sub(dataEnd, headStart), 128) diff --git a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul index 7dbd04fea..4c1991e39 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul @@ -459,62 +459,64 @@ // step: fullSuite // ---- // { -// let _1 := 0x20 -// let _2 := 0 -// let _3 := mload(_2) -// let pos := _1 -// let length := mload(_3) -// mstore(_1, length) -// pos := 64 -// let srcPtr := add(_3, _1) -// let i := _2 -// for { -// } -// lt(i, length) // { -// i := add(i, 1) -// } -// { -// let _4 := mload(srcPtr) -// let pos_1 := pos -// let srcPtr_1 := _4 -// let i_1 := _2 +// let _1 := 0x20 +// let _2 := 0 +// let _3 := mload(_2) +// let pos := _1 +// let length := mload(_3) +// mstore(_1, length) +// pos := 64 +// let srcPtr := add(_3, _1) +// let i := _2 // for { // } -// lt(i_1, 0x3) +// lt(i, length) // { -// i_1 := add(i_1, 1) +// i := add(i, 1) // } // { -// mstore(pos_1, and(mload(srcPtr_1), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) -// srcPtr_1 := add(srcPtr_1, _1) -// pos_1 := add(pos_1, _1) +// let _4 := mload(srcPtr) +// let pos_1 := pos +// let srcPtr_1 := _4 +// let i_1 := _2 +// for { +// } +// lt(i_1, 0x3) +// { +// i_1 := add(i_1, 1) +// } +// { +// mstore(pos_1, and(mload(srcPtr_1), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) +// srcPtr_1 := add(srcPtr_1, _1) +// pos_1 := add(pos_1, _1) +// } +// srcPtr := add(srcPtr, _1) +// pos := add(pos, 0x60) // } -// srcPtr := add(srcPtr, _1) -// pos := add(pos, 0x60) +// let _5 := mload(64) +// let _6 := mload(_1) +// if slt(sub(_5, _6), 128) +// { +// revert(_2, _2) +// } +// let offset := calldataload(add(_6, 64)) +// let _7 := 0xffffffffffffffff +// if gt(offset, _7) +// { +// revert(_2, _2) +// } +// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_6, offset), _5) +// let offset_1 := calldataload(add(_6, 96)) +// if gt(offset_1, _7) +// { +// revert(_2, _2) +// } +// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_6, offset_1), _5) +// sstore(calldataload(_6), calldataload(add(_6, _1))) +// sstore(value2, value3) +// sstore(_2, pos) // } -// let _5 := mload(64) -// let _6 := mload(_1) -// if slt(sub(_5, _6), 128) -// { -// revert(_2, _2) -// } -// let offset := calldataload(add(_6, 64)) -// let _7 := 0xffffffffffffffff -// if gt(offset, _7) -// { -// revert(_2, _2) -// } -// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_6, offset), _5) -// let offset_1 := calldataload(add(_6, 96)) -// if gt(offset_1, _7) -// { -// revert(_2, _2) -// } -// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_6, offset_1), _5) -// sstore(calldataload(_6), calldataload(add(_6, _1))) -// sstore(value2, value3) -// sstore(_2, pos) // function abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(offset, end) -> array // { // if iszero(slt(add(offset, 0x1f), end)) diff --git a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul index 09b40984f..bfe9ea27d 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/aztec.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/aztec.yul @@ -232,107 +232,109 @@ // step: fullSuite // ---- // { -// mstore(0x80, 7673901602397024137095011250362199966051872585513276903826533215767972925880) -// mstore(0xa0, 8489654445897228341090914135473290831551238522473825886865492707826370766375) -// let notes := add(0x04, calldataload(0x04)) -// let m := calldataload(0x24) -// let n := calldataload(notes) -// let gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 -// let challenge := mod(calldataload(0x44), gen_order) -// if gt(m, n) // { -// mstore(0x00, 404) -// revert(0x00, 0x20) -// } -// let kn := calldataload(add(calldatasize(), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40)) -// mstore(0x2a0, caller()) -// mstore(0x2c0, kn) -// mstore(0x2e0, m) -// kn := mulmod(sub(gen_order, kn), challenge, gen_order) -// hashCommitments(notes, n) -// let b := add(0x300, mul(n, 0x80)) -// let i := 0 -// let i_1 := i -// for { -// } -// lt(i, n) -// { -// i := add(i, 0x01) -// } -// { -// let _1 := add(calldataload(0x04), mul(i, 0xc0)) -// let noteIndex := add(_1, 0x24) -// let k := i_1 -// let a := calldataload(add(_1, 0x44)) -// let c := challenge -// let _2 := add(i, 0x01) -// switch eq(_2, n) -// case 1 { -// k := kn -// if eq(m, n) -// { -// k := sub(gen_order, kn) +// mstore(0x80, 7673901602397024137095011250362199966051872585513276903826533215767972925880) +// mstore(0xa0, 8489654445897228341090914135473290831551238522473825886865492707826370766375) +// let notes := add(0x04, calldataload(0x04)) +// let m := calldataload(0x24) +// let n := calldataload(notes) +// let gen_order := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// let challenge := mod(calldataload(0x44), gen_order) +// if gt(m, n) +// { +// mstore(0x00, 404) +// revert(0x00, 0x20) +// } +// let kn := calldataload(add(calldatasize(), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff40)) +// mstore(0x2a0, caller()) +// mstore(0x2c0, kn) +// mstore(0x2e0, m) +// kn := mulmod(sub(gen_order, kn), challenge, gen_order) +// hashCommitments(notes, n) +// let b := add(0x300, mul(n, 0x80)) +// let i := 0 +// let i_1 := i +// for { +// } +// lt(i, n) +// { +// i := add(i, 0x01) +// } +// { +// let _1 := add(calldataload(0x04), mul(i, 0xc0)) +// let noteIndex := add(_1, 0x24) +// let k := i_1 +// let a := calldataload(add(_1, 0x44)) +// let c := challenge +// let _2 := add(i, 0x01) +// switch eq(_2, n) +// case 1 { +// k := kn +// if eq(m, n) +// { +// k := sub(gen_order, kn) +// } // } +// case 0 { +// k := calldataload(noteIndex) +// } +// validateCommitment(noteIndex, k, a) +// switch gt(_2, m) +// case 1 { +// kn := addmod(kn, sub(gen_order, k), gen_order) +// let x := mod(mload(i_1), gen_order) +// k := mulmod(k, x, gen_order) +// a := mulmod(a, x, gen_order) +// c := mulmod(challenge, x, gen_order) +// mstore(i_1, keccak256(i_1, 0x20)) +// } +// case 0 { +// kn := addmod(kn, k, gen_order) +// } +// let _3 := 0x40 +// calldatacopy(0xe0, add(_1, 164), _3) +// calldatacopy(0x20, add(_1, 100), _3) +// mstore(0x120, sub(gen_order, c)) +// mstore(0x60, k) +// mstore(0xc0, a) +// let result := call(gas(), 7, i_1, 0xe0, 0x60, 0x1a0, _3) +// let result_1 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x120, _3)) +// let result_2 := and(result_1, call(gas(), 7, i_1, 0x80, 0x60, 0x160, _3)) +// let result_3 := and(result_2, call(gas(), 6, i_1, 0x120, 0x80, 0x160, _3)) +// result := and(result_3, call(gas(), 6, i_1, 0x160, 0x80, b, _3)) +// if eq(i, m) +// { +// mstore(0x260, mload(0x20)) +// mstore(0x280, mload(_3)) +// mstore(0x1e0, mload(0xe0)) +// mstore(0x200, sub(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47, mload(0x100))) +// } +// if gt(i, m) +// { +// mstore(0x60, c) +// let result_4 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x220, _3)) +// let result_5 := and(result_4, call(gas(), 6, i_1, 0x220, 0x80, 0x260, _3)) +// result := and(result_5, call(gas(), 6, i_1, 0x1a0, 0x80, 0x1e0, _3)) +// } +// if iszero(result) +// { +// mstore(i_1, 400) +// revert(i_1, 0x20) +// } +// b := add(b, _3) // } -// case 0 { -// k := calldataload(noteIndex) -// } -// validateCommitment(noteIndex, k, a) -// switch gt(_2, m) -// case 1 { -// kn := addmod(kn, sub(gen_order, k), gen_order) -// let x := mod(mload(i_1), gen_order) -// k := mulmod(k, x, gen_order) -// a := mulmod(a, x, gen_order) -// c := mulmod(challenge, x, gen_order) -// mstore(i_1, keccak256(i_1, 0x20)) -// } -// case 0 { -// kn := addmod(kn, k, gen_order) -// } -// let _3 := 0x40 -// calldatacopy(0xe0, add(_1, 164), _3) -// calldatacopy(0x20, add(_1, 100), _3) -// mstore(0x120, sub(gen_order, c)) -// mstore(0x60, k) -// mstore(0xc0, a) -// let result := call(gas(), 7, i_1, 0xe0, 0x60, 0x1a0, _3) -// let result_1 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x120, _3)) -// let result_2 := and(result_1, call(gas(), 7, i_1, 0x80, 0x60, 0x160, _3)) -// let result_3 := and(result_2, call(gas(), 6, i_1, 0x120, 0x80, 0x160, _3)) -// result := and(result_3, call(gas(), 6, i_1, 0x160, 0x80, b, _3)) -// if eq(i, m) +// if lt(m, n) // { -// mstore(0x260, mload(0x20)) -// mstore(0x280, mload(_3)) -// mstore(0x1e0, mload(0xe0)) -// mstore(0x200, sub(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47, mload(0x100))) +// validatePairing(0x64) // } -// if gt(i, m) +// if iszero(eq(mod(keccak256(0x2a0, add(b, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60)), gen_order), challenge)) // { -// mstore(0x60, c) -// let result_4 := and(result, call(gas(), 7, i_1, 0x20, 0x60, 0x220, _3)) -// let result_5 := and(result_4, call(gas(), 6, i_1, 0x220, 0x80, 0x260, _3)) -// result := and(result_5, call(gas(), 6, i_1, 0x1a0, 0x80, 0x1e0, _3)) -// } -// if iszero(result) -// { -// mstore(i_1, 400) +// mstore(i_1, 404) // revert(i_1, 0x20) // } -// b := add(b, _3) +// mstore(i_1, 0x01) +// return(i_1, 0x20) // } -// if lt(m, n) -// { -// validatePairing(0x64) -// } -// if iszero(eq(mod(keccak256(0x2a0, add(b, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd60)), gen_order), challenge)) -// { -// mstore(i_1, 404) -// revert(i_1, 0x20) -// } -// mstore(i_1, 0x01) -// return(i_1, 0x20) // function validatePairing(t2) // { // let t2_x := calldataload(t2) diff --git a/test/libyul/yulOptimizerTests/fullSuite/medium.yul b/test/libyul/yulOptimizerTests/fullSuite/medium.yul index aeeebafc8..bebb8c418 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/medium.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/medium.yul @@ -20,10 +20,12 @@ // step: fullSuite // ---- // { -// let _1 := 0x40 -// mstore(_1, add(mload(_1), 0x20)) -// let p := mload(_1) -// mstore(_1, add(p, _1)) -// mstore(add(p, 96), 2) -// mstore(_1, 0x20) +// { +// let _1 := 0x40 +// mstore(_1, add(mload(_1), 0x20)) +// let p := mload(_1) +// mstore(_1, add(p, _1)) +// mstore(add(p, 96), 2) +// mstore(_1, 0x20) +// } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul index a50e515f2..ba797fa7b 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/reuse_vars_bug_in_simplifier.yul @@ -13,5 +13,7 @@ // step: fullSuite // ---- // { -// mstore(1, 1) +// { +// mstore(1, 1) +// } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul index 3e79e4aa1..e9af2c227 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverse.yul @@ -35,14 +35,16 @@ // step: fullSuite // ---- // { -// let a, b := abi_decode_t_bytes_calldata_ptr(mload(0), mload(1)) -// let a_1, b_1 := abi_decode_t_bytes_calldata_ptr(a, b) -// let a_2, b_2 := abi_decode_t_bytes_calldata_ptr(a_1, b_1) -// let a_3, b_3 := abi_decode_t_bytes_calldata_ptr(a_2, b_2) -// let a_4, b_4 := abi_decode_t_bytes_calldata_ptr(a_3, b_3) -// let a_5, b_5 := abi_decode_t_bytes_calldata_ptr(a_4, b_4) -// let a_6, b_6 := abi_decode_t_bytes_calldata_ptr(a_5, b_5) -// mstore(a_6, b_6) +// { +// let a, b := abi_decode_t_bytes_calldata_ptr(mload(0), mload(1)) +// let a_1, b_1 := abi_decode_t_bytes_calldata_ptr(a, b) +// let a_2, b_2 := abi_decode_t_bytes_calldata_ptr(a_1, b_1) +// let a_3, b_3 := abi_decode_t_bytes_calldata_ptr(a_2, b_2) +// let a_4, b_4 := abi_decode_t_bytes_calldata_ptr(a_3, b_3) +// let a_5, b_5 := abi_decode_t_bytes_calldata_ptr(a_4, b_4) +// let a_6, b_6 := abi_decode_t_bytes_calldata_ptr(a_5, b_5) +// mstore(a_6, b_6) +// } // function abi_decode_t_bytes_calldata_ptr(offset, end) -> arrayPos, length // { // if iszero(slt(add(offset, 0x1f), end)) diff --git a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul index c4be165e8..564ed9664 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/ssaReverseComplex.yul @@ -13,12 +13,14 @@ // step: fullSuite // ---- // { -// let a := mload(0) -// let b := mload(1) -// if mload(2) // { -// a := mload(mload(mload(b))) -// b := mload(a) +// let a := mload(0) +// let b := mload(1) +// if mload(2) +// { +// a := mload(mload(mload(b))) +// b := mload(a) +// } +// mstore(a, b) // } -// mstore(a, b) // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul index 2f7be6ae5..9a463e320 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline.yul @@ -10,5 +10,7 @@ // step: fullSuite // ---- // { -// mstore(9, 0) +// { +// mstore(9, 0) +// } // } diff --git a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul index de18975c4..ad1d92c83 100644 --- a/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul +++ b/test/libyul/yulOptimizerTests/fullSuite/switch_inline_match_default.yul @@ -11,5 +11,7 @@ // step: fullSuite // ---- // { -// mstore(10, 0) +// { +// mstore(10, 0) +// } // } diff --git a/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul b/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul index fea7403f6..4f5949c8e 100644 --- a/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul +++ b/test/libyul/yulOptimizerTests/ssaTransform/multi_decl.yul @@ -4,22 +4,22 @@ y := mload(x) let a, b := f(x, y) sstore(a, b) - function f(t, v) -> x, y {} + function f(t, v) -> w, z {} } // ==== // step: ssaTransform // ---- // { -// let x_2, y_3 := f(1, 2) -// let x := x_2 -// let y := y_3 -// let x_4 := mload(y_3) -// x := x_4 -// let y_5 := mload(x_4) -// y := y_5 -// let a, b := f(x_4, y_5) +// let x_1, y_2 := f(1, 2) +// let x := x_1 +// let y := y_2 +// let x_3 := mload(y_2) +// x := x_3 +// let y_4 := mload(x_3) +// y := y_4 +// let a, b := f(x_3, y_4) // sstore(a, b) -// function f(t, v) -> x_1, y_2 +// function f(t, v) -> w, z // { // } // } From 054c16aa05ab99a077e8219373422927017a36e0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 2 Apr 2019 23:19:23 +0200 Subject: [PATCH 2/5] [Yul] Fix registration of functions in scopes. --- libyul/AsmScopeFiller.cpp | 46 +++++++++++++++++++++------------------ libyul/AsmScopeFiller.h | 1 + 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/libyul/AsmScopeFiller.cpp b/libyul/AsmScopeFiller.cpp index 547796d3c..9156e7e02 100644 --- a/libyul/AsmScopeFiller.cpp +++ b/libyul/AsmScopeFiller.cpp @@ -74,28 +74,13 @@ bool ScopeFiller::operator()(VariableDeclaration const& _varDecl) bool ScopeFiller::operator()(FunctionDefinition const& _funDef) { - bool success = true; - vector arguments; - for (auto const& _argument: _funDef.parameters) - arguments.emplace_back(_argument.type.str()); - vector returns; - for (auto const& _return: _funDef.returnVariables) - returns.emplace_back(_return.type.str()); - if (!m_currentScope->registerFunction(_funDef.name, arguments, returns)) - { - //@TODO secondary location - m_errorReporter.declarationError( - _funDef.location, - "Function name " + _funDef.name.str() + " already taken in this scope." - ); - success = false; - } - auto virtualBlock = m_info.virtualBlocks[&_funDef] = make_shared(); Scope& varScope = scope(virtualBlock.get()); varScope.superScope = m_currentScope; m_currentScope = &varScope; varScope.functionScope = true; + + bool success = true; for (auto const& var: _funDef.parameters + _funDef.returnVariables) if (!registerVariable(var, _funDef.location, varScope)) success = false; @@ -153,12 +138,11 @@ bool ScopeFiller::operator()(Block const& _block) // an entry in the scope according to their visibility. for (auto const& s: _block.statements) if (s.type() == typeid(FunctionDefinition)) - if (!boost::apply_visitor(*this, s)) + if (!registerFunction(boost::get(s))) success = false; for (auto const& s: _block.statements) - if (s.type() != typeid(FunctionDefinition)) - if (!boost::apply_visitor(*this, s)) - success = false; + if (!boost::apply_visitor(*this, s)) + success = false; m_currentScope = m_currentScope->superScope; return success; @@ -178,6 +162,26 @@ bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& return true; } +bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef) +{ + vector arguments; + for (auto const& _argument: _funDef.parameters) + arguments.emplace_back(_argument.type.str()); + vector returns; + for (auto const& _return: _funDef.returnVariables) + returns.emplace_back(_return.type.str()); + if (!m_currentScope->registerFunction(_funDef.name, arguments, returns)) + { + //@TODO secondary location + m_errorReporter.declarationError( + _funDef.location, + "Function name " + _funDef.name.str() + " already taken in this scope." + ); + return false; + } + return true; +} + Scope& ScopeFiller::scope(Block const* _block) { auto& scope = m_info.scopes[_block]; diff --git a/libyul/AsmScopeFiller.h b/libyul/AsmScopeFiller.h index 7c8834637..220538bb2 100644 --- a/libyul/AsmScopeFiller.h +++ b/libyul/AsmScopeFiller.h @@ -73,6 +73,7 @@ private: langutil::SourceLocation const& _location, Scope& _scope ); + bool registerFunction(FunctionDefinition const& _funDef); Scope& scope(Block const* _block); From 0d2ae84081500168fb1596c2bc6198b3a67b86d6 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 4 Apr 2019 17:48:02 +0200 Subject: [PATCH 3/5] Use move semantics. --- libyul/AsmScope.cpp | 4 ++-- libyul/AsmScope.h | 4 ++-- libyul/AsmScopeFiller.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libyul/AsmScope.cpp b/libyul/AsmScope.cpp index b71f2367e..252361d27 100644 --- a/libyul/AsmScope.cpp +++ b/libyul/AsmScope.cpp @@ -42,11 +42,11 @@ bool Scope::registerVariable(YulString _name, YulType const& _type) return true; } -bool Scope::registerFunction(YulString _name, std::vector const& _arguments, std::vector const& _returns) +bool Scope::registerFunction(YulString _name, std::vector _arguments, std::vector _returns) { if (exists(_name)) return false; - identifiers[_name] = Function{_arguments, _returns}; + identifiers[_name] = Function{std::move(_arguments), std::move(_returns)}; return true; } diff --git a/libyul/AsmScope.h b/libyul/AsmScope.h index 2a8ef49e8..f6c7fe59a 100644 --- a/libyul/AsmScope.h +++ b/libyul/AsmScope.h @@ -56,8 +56,8 @@ struct Scope bool registerLabel(YulString _name); bool registerFunction( YulString _name, - std::vector const& _arguments, - std::vector const& _returns + std::vector _arguments, + std::vector _returns ); /// Looks up the identifier in this or super scopes and returns a valid pointer if found diff --git a/libyul/AsmScopeFiller.cpp b/libyul/AsmScopeFiller.cpp index 9156e7e02..1706b147d 100644 --- a/libyul/AsmScopeFiller.cpp +++ b/libyul/AsmScopeFiller.cpp @@ -170,7 +170,7 @@ bool ScopeFiller::registerFunction(FunctionDefinition const& _funDef) vector returns; for (auto const& _return: _funDef.returnVariables) returns.emplace_back(_return.type.str()); - if (!m_currentScope->registerFunction(_funDef.name, arguments, returns)) + if (!m_currentScope->registerFunction(_funDef.name, std::move(arguments), std::move(returns))) { //@TODO secondary location m_errorReporter.declarationError( From 1be3882ade5e8dd71a3adaa48e84f2f2b60b013d Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 4 Apr 2019 17:48:41 +0200 Subject: [PATCH 4/5] Test shadowing between variables inside and outside of functions. --- test/libyul/Parser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 8dc4bac36..da07544b9 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -390,6 +390,12 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case_different_literal) BOOST_CHECK(successParse("{ switch 1:u256 case \"1\":u256 {} case \"2\":u256 {} }")); } +BOOST_AUTO_TEST_CASE(function_shadowing_outside_vars) +{ + CHECK_ERROR("{ let x:u256 function f() -> x:u256 {} }", DeclarationError, "already taken in this scope"); + BOOST_CHECK(successParse("{ { let x:u256 } function f() -> x:u256 {} }")); +} + BOOST_AUTO_TEST_CASE(builtins_parser) { struct SimpleDialect: public Dialect From 804c1553bfa227932bace2a29713f05802dcee18 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 4 Apr 2019 17:50:04 +0200 Subject: [PATCH 5/5] Changelog entry. --- Changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.md b/Changelog.md index 65b115f84..829ea903d 100644 --- a/Changelog.md +++ b/Changelog.md @@ -22,6 +22,7 @@ Compiler Features: Bugfixes: * SMTChecker: Implement Boolean short-circuiting. * SMTChecker: SSA control-flow did not take into account state variables that were modified inside inlined functions that were called inside branches. + * Yul: Properly register functions and disallow shadowing between function variables and variables in the outside scope.