The only difference between uint256[] calldata
and uint8[] calldata
is that the latter costs more due to having to clear the unused bytes
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // optimize 200
/**
* @title ExtArgMemVsCallBasic
* @author IllIllI
*/
contract ExtArgMemVsCallBasic {
function test(uint256[] calldata x) pure public returns (uint256) {
uint256 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // optimize 200
/**
* @title ExtArgMemVsCallBasic
* @author IllIllI
*/
contract ExtArgMemVsCallBasic {
function test(uint8[] calldata x) pure public returns (uint8) {
uint8 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
}
diff --git a/ExtArgMemVsCallBasic_256.sol b/ExtArgMemVsCallBasic_8.sol
index 6beeb27..9382636 100644
--- a/ExtArgMemVsCallBasic_256.sol
+++ b/ExtArgMemVsCallBasic_8.sol
@@ -6,8 +6,8 @@ pragma solidity ^0.8.0; // optimize 200
* @author IllIllI
*/
contract ExtArgMemVsCallBasic {
- function test(uint256[] calldata x) pure public returns (uint256) {
- uint256 total;
+ function test(uint8[] calldata x) pure public returns (uint8) {
+ uint8 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
$ solc ExtArgMemVsCallBasic_256.sol --bin --optimize --optimize-runs 200 | egrep "^60[0-9]+"
608060405234801561001057600080fd5b506101ac806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063ca16068414610030575b600080fd5b61004361003e3660046100b5565b610059565b6040516100509190610124565b60405180910390f35b60008082815b818110156100ab5785858281811061008757634e487b7160e01b600052603260045260246000fd5b9050602002013583610099919061012d565b92506100a481610145565b905061005f565b5090949350505050565b600080602083850312156100c7578182fd5b823567ffffffffffffffff808211156100de578384fd5b818501915085601f8301126100f1578384fd5b8135818111156100ff578485fd5b8660208083028501011115610112578485fd5b60209290920196919550909350505050565b90815260200190565b6000821982111561014057610140610160565b500190565b600060001982141561015957610159610160565b5060010190565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220dfc3df939370be6b43dae1ec511e98296e3eccc0becc68dfc9e34e4739370f1e64736f6c63430008000033
$ solc ExtArgMemVsCallBasic_8.sol --bin --optimize --optimize-runs 200 | egrep "^60[0-9]+"
608060405234801561001057600080fd5b506101f3806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80630c07479214610030575b600080fd5b61004361003e3660046100c2565b610059565b6040516100509190610159565b60405180910390f35b60008082815b818110156100b85785858281811061008757634e487b7160e01b600052603260045260246000fd5b905060200201602081019061009c9190610131565b6100a69084610167565b92506100b18161018c565b905061005f565b5090949350505050565b600080602083850312156100d4578182fd5b823567ffffffffffffffff808211156100eb578384fd5b818501915085601f8301126100fe578384fd5b81358181111561010c578485fd5b866020808302850101111561011f578485fd5b60209290920196919550909350505050565b600060208284031215610142578081fd5b813560ff81168114610152578182fd5b9392505050565b60ff91909116815260200190565b600060ff821660ff84168060ff03821115610184576101846101a7565b019392505050565b60006000198214156101a0576101a06101a7565b5060010190565b634e487b7160e01b600052601160045260246000fdfea2646970667358221220e1344142ded6a150fcba3805ed7d927986ae6b1cfeb59887a011ebd8da49e03e64736f6c63430008000033
diff --git a/a b/b
index 3fca2e6..3cd224a 100644
--- a/a
+++ b/b
@@ -32,14 +32,14 @@ object "ExtArgMemVsCallBasic_40" {
let selector := shift_right_224_unsigned(calldataload(0))
switch selector
- case 0xca160684
+ case 0x0c074792
{
- // test(uint256[])
+ // test(uint8[])
if callvalue() { revert(0, 0) }
- let param_0, param_1 := abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr(4, calldatasize())
+ let param_0, param_1 := abi_decode_tuple_t_array$_t_uint8_$dyn_calldata_ptr(4, calldatasize())
let ret_0 := fun_test_39(param_0, param_1)
let memPos := allocateMemory(0)
- let memEnd := abi_encode_tuple_t_uint256__to_t_uint256__fromStack(memPos , ret_0)
+ let memEnd := abi_encode_tuple_t_uint8__to_t_uint8__fromStack(memPos , ret_0)
return(memPos, sub(memEnd, memPos))
}
@@ -48,8 +48,8 @@ object "ExtArgMemVsCallBasic_40" {
if iszero(calldatasize()) { }
revert(0, 0)
- // uint256[]
- function abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(offset, end) -> arrayPos, length {
+ // uint8[]
+ function abi_decode_t_array$_t_uint8_$dyn_calldata_ptr(offset, end) -> arrayPos, length {
if iszero(slt(add(offset, 0x1f), end)) { revert(0, 0) }
length := calldataload(offset)
if gt(length, 0xffffffffffffffff) { revert(0, 0) }
@@ -57,7 +57,7 @@ object "ExtArgMemVsCallBasic_40" {
if gt(add(arrayPos, mul(length, 0x20)), end) { revert(0, 0) }
}
- function abi_decode_tuple_t_array$_t_uint256_$dyn_calldata_ptr(headStart, dataEnd) -> value0, value1 {
+ function abi_decode_tuple_t_array$_t_uint8_$dyn_calldata_ptr(headStart, dataEnd) -> value0, value1 {
if slt(sub(dataEnd, headStart), 32) { revert(0, 0) }
{
@@ -65,19 +65,19 @@ object "ExtArgMemVsCallBasic_40" {
let offset := calldataload(add(headStart, 0))
if gt(offset, 0xffffffffffffffff) { revert(0, 0) }
- value0, value1 := abi_decode_t_array$_t_uint256_$dyn_calldata_ptr(add(headStart, offset), dataEnd)
+ value0, value1 := abi_decode_t_array$_t_uint8_$dyn_calldata_ptr(add(headStart, offset), dataEnd)
}
}
- function abi_encode_t_uint256_to_t_uint256_fromStack(value, pos) {
- mstore(pos, cleanup_t_uint256(value))
+ function abi_encode_t_uint8_to_t_uint8_fromStack(value, pos) {
+ mstore(pos, cleanup_t_uint8(value))
}
- function abi_encode_tuple_t_uint256__to_t_uint256__fromStack(headStart , value0) -> tail {
+ function abi_encode_tuple_t_uint8__to_t_uint8__fromStack(headStart , value0) -> tail {
tail := add(headStart, 32)
- abi_encode_t_uint256_to_t_uint256_fromStack(value0, add(headStart, 0))
+ abi_encode_t_uint8_to_t_uint8_fromStack(value0, add(headStart, 0))
}
@@ -89,24 +89,24 @@ object "ExtArgMemVsCallBasic_40" {
mstore(64, newFreePtr)
}
- function array_length_t_array$_t_uint256_$dyn_calldata_ptr(value, len) -> length {
+ function array_length_t_array$_t_uint8_$dyn_calldata_ptr(value, len) -> length {
length := len
}
- function calldata_array_index_access_t_array$_t_uint256_$dyn_calldata_ptr(base_ref, length, index) -> addr {
+ function calldata_array_index_access_t_array$_t_uint8_$dyn_calldata_ptr(base_ref, length, index) -> addr {
if iszero(lt(index, length)) { panic_error_0x32() }
addr := add(base_ref, mul(index, 32))
}
- function checked_add_t_uint256(x, y) -> sum {
- x := cleanup_t_uint256(x)
- y := cleanup_t_uint256(y)
+ function checked_add_t_uint8(x, y) -> sum {
+ x := cleanup_t_uint8(x)
+ y := cleanup_t_uint8(y)
// overflow, if x > (maxValue - y)
- if gt(x, sub(0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, y)) { panic_error_0x11() }
+ if gt(x, sub(0xff, y)) { panic_error_0x11() }
sum := add(x, y)
}
@@ -115,22 +115,26 @@ object "ExtArgMemVsCallBasic_40" {
cleaned := value
}
+ function cleanup_t_uint8(value) -> cleaned {
+ cleaned := and(value, 0xff)
+ }
+
function convert_t_rational_0_by_1_to_t_uint256(value) -> converted {
converted := cleanup_t_uint256(value)
}
function fun_test_39(vloc_x_5_offset, vloc_x_5_length) -> vloc__8 {
- let zero_value_for_type_t_uint256_1 := zero_value_for_split_t_uint256()
- vloc__8 := zero_value_for_type_t_uint256_1
+ let zero_value_for_type_t_uint8_1 := zero_value_for_split_t_uint8()
+ vloc__8 := zero_value_for_type_t_uint8_1
let vloc_total_11
- let zero_value_for_type_t_uint256_2 := zero_value_for_split_t_uint256()
- vloc_total_11 := zero_value_for_type_t_uint256_2
+ let zero_value_for_type_t_uint8_2 := zero_value_for_split_t_uint8()
+ vloc_total_11 := zero_value_for_type_t_uint8_2
let _3_offset := vloc_x_5_offset
let _3_length := vloc_x_5_length
let expr_15_offset := _3_offset
let expr_15_length := _3_length
- let expr_16 := array_length_t_array$_t_uint256_$dyn_calldata_ptr(expr_15_offset, expr_15_length)
+ let expr_16 := array_length_t_array$_t_uint8_$dyn_calldata_ptr(expr_15_offset, expr_15_length)
let vloc_len_14 := expr_16
for {
let expr_20 := 0x00
@@ -154,9 +158,9 @@ object "ExtArgMemVsCallBasic_40" {
let expr_29_length := _8_length
let _9 := vloc_i_19
let expr_30 := _9
- let expr_31 := read_from_calldatat_uint256(calldata_array_index_access_t_array$_t_uint256_$dyn_calldata_ptr(expr_29_offset, expr_29_length, expr_30))
+ let expr_31 := read_from_calldatat_uint8(calldata_array_index_access_t_array$_t_uint8_$dyn_calldata_ptr(expr_29_offset, expr_29_length, expr_30))
let _10 := vloc_total_11
- expr_31 := checked_add_t_uint256(_10, expr_31)
+ expr_31 := checked_add_t_uint8(_10, expr_31)
vloc_total_11 := expr_31
let expr_32 := expr_31
}
@@ -191,10 +195,10 @@ object "ExtArgMemVsCallBasic_40" {
revert(0, 0x24)
}
- function read_from_calldatat_uint256(ptr) -> returnValue {
+ function read_from_calldatat_uint8(ptr) -> returnValue {
let value := calldataload(ptr)
- validator_revert_t_uint256(value)
+ validator_revert_t_uint8(value)
returnValue :=
@@ -209,11 +213,11 @@ object "ExtArgMemVsCallBasic_40" {
}
- function validator_revert_t_uint256(value) {
- if iszero(eq(value, cleanup_t_uint256(value))) { revert(0, 0) }
+ function validator_revert_t_uint8(value) {
+ if iszero(eq(value, cleanup_t_uint8(value))) { revert(0, 0) }
}
- function zero_value_for_split_t_uint256() -> ret {
+ function zero_value_for_split_t_uint8() -> ret {
ret := 0
}
PC.Uint256 | Operation.Uint256 | Gas.Uint256 | PC.Uint8 | Operation.Uint8 | Gas.Uint8 |
---|---|---|---|---|---|
172(0xac) | MUL(0x2) | 5 | 172(0xac) | MUL(0x2) | 5 |
173(0xad) | ADD(0x1) | 3 | 173(0xad) | ADD(0x1) | 3 |
174(0xae) | PUSH1(0x60) ["0x20"] | 3 | |||
176(0xb0) | DUP2(0x81) | 3 | |||
177(0xb1) | ADD(0x1) | 3 | |||
178(0xb2) | SWAP1(0x90) | 3 | |||
174(0xae) | CALLDATALOAD(0x35) | 3 | |||
175(0xaf) | DUP4(0x83) | 3 | |||
176(0xb0) | PUSH2(0x61) ["0x00","0x99"] | 3 | 179(0xb3) | PUSH2(0x61) ["0x00","0x9c"] | 3 |
179(0xb3) | SWAP2(0x91) | 3 | 182(0xb6) | SWAP2(0x91) | 3 |
180(0xb4) | SWAP1(0x90) | 3 | 183(0xb7) | SWAP1(0x90) | 3 |
181(0xb5) | PUSH2(0x61) ["0x01","0x2d"] | 3 | 184(0xb8) | PUSH2(0x61) ["0x01","0x31"] | 3 |
184(0xb8) | JUMP(0x56) | 8 | 187(0xbb) | JUMP(0x56) | 8 |
185(0xb9) | JUMPDEST(0x5b)@0xb9 | 1 | 188(0xbc) | JUMPDEST(0x5b)@0xbc | 1 |
189(0xbd) | PUSH2(0x61) ["0x00","0xa6"] | 3 | |||
192(0xc0) | SWAP1(0x90) | 3 | |||
193(0xc1) | DUP5(0x84) | 3 | |||
194(0xc2) | PUSH2(0x61) ["0x01","0x67"] | 3 | |||
197(0xc5) | JUMP(0x56) | 8 | |||
198(0xc6) | JUMPDEST(0x5b)@0xc6 | 1 | |||
186(0xba) | SWAP3(0x92) | 3 | 199(0xc7) | SWAP3(0x92) | 3 |
187(0xbb) | POP(0x50) | 2 | 200(0xc8) | POP(0x50) | 2 |
188(0xbc) | PUSH2(0x61) ["0x00","0xa4"] | 3 | 201(0xc9) | PUSH2(0x61) ["0x00","0xb1"] | 3 |
191(0xbf) | DUP2(0x81) | 3 | 204(0xcc) | DUP2(0x81) | 3 |
192(0xc0) | PUSH2(0x61) ["0x01","0x45"] | 3 | 205(0xcd) | PUSH2(0x61) ["0x01","0x8c"] | 3 |
195(0xc3) | JUMP(0x56) | 8 | 208(0xd0) | JUMP(0x56) | 8 |
196(0xc4) | JUMPDEST(0x5b)@0xc4 | 1 | 209(0xd1) | JUMPDEST(0x5b)@0xd1 | 1 |
197(0xc5) | SWAP1(0x90) | 3 | 210(0xd2) | SWAP1(0x90) | 3 |
198(0xc6) | POP(0x50) | 2 | 211(0xd3) | POP(0x50) | 2 |
199(0xc7) | PUSH2(0x61) ["0x00","0x5f"] | 3 | 212(0xd4) | PUSH2(0x61) ["0x00","0x5f"] | 3 |
202(0xca) | JUMP(0x56) | 8 | 215(0xd7) | JUMP(0x56) | 8 |
203(0xcb) | JUMPDEST(0x5b)@0xcb | 1 | 216(0xd8) | JUMPDEST(0x5b)@0xd8 | 1 |
204(0xcc) | POP(0x50) | 2 | 217(0xd9) | POP(0x50) | 2 |
205(0xcd) | SWAP1(0x90) | 3 | 218(0xda) | SWAP1(0x90) | 3 |
206(0xce) | SWAP5(0x94) | 3 | 219(0xdb) | SWAP5(0x94) | 3 |
207(0xcf) | SWAP4(0x93) | 3 | 220(0xdc) | SWAP4(0x93) | 3 |
208(0xd0) | POP(0x50) | 2 | 221(0xdd) | POP(0x50) | 2 |
209(0xd1) | POP(0x50) | 2 | 222(0xde) | POP(0x50) | 2 |
210(0xd2) | POP(0x50) | 2 | 223(0xdf) | POP(0x50) | 2 |
211(0xd3) | POP(0x50) | 2 | 224(0xe0) | POP(0x50) | 2 |
212(0xd4) | JUMP(0x56) | 8 | 225(0xe1) | JUMP(0x56) | 8 |
213(0xd5) | JUMPDEST(0x5b)@0xd5 | 1 | 226(0xe2) | JUMPDEST(0x5b)@0xe2 | 1 |
214(0xd6) | PUSH1(0x60) ["0x00"] | 3 | 227(0xe3) | PUSH1(0x60) ["0x00"] | 3 |
216(0xd8) | DUP1(0x80) | 3 | 229(0xe5) | DUP1(0x80) | 3 |
217(0xd9) | PUSH1(0x60) ["0x20"] | 3 | 230(0xe6) | PUSH1(0x60) ["0x20"] | 3 |
219(0xdb) | DUP4(0x83) | 3 | 232(0xe8) | DUP4(0x83) | 3 |
220(0xdc) | DUP6(0x85) | 3 | 233(0xe9) | DUP6(0x85) | 3 |
221(0xdd) | SUB(0x3) | 3 | 234(0xea) | SUB(0x3) | 3 |
222(0xde) | SLT(0x12) | 3 | 235(0xeb) | SLT(0x12) | 3 |
223(0xdf) | ISZERO(0x15) | 3 | 236(0xec) | ISZERO(0x15) | 3 |
224(0xe0) | PUSH2(0x61) ["0x00","0xc7"] | 3 | 237(0xed) | PUSH2(0x61) ["0x00","0xd4"] | 3 |
227(0xe3) | JUMPI(0x57) | 10 | 240(0xf0) | JUMPI(0x57) | 10 |
228(0xe4) | DUP2(0x81) | 3 | 241(0xf1) | DUP2(0x81) | 3 |
229(0xe5) | DUP3(0x82) | 3 | 242(0xf2) | DUP3(0x82) | 3 |
230(0xe6) | REVERT(0xfd) | 0 | 243(0xf3) | REVERT(0xfd) | 0 |
231(0xe7) | JUMPDEST(0x5b)@0xe7 | 1 | 244(0xf4) | JUMPDEST(0x5b)@0xf4 | 1 |
232(0xe8) | DUP3(0x82) | 3 | 245(0xf5) | DUP3(0x82) | 3 |
233(0xe9) | CALLDATALOAD(0x35) | 3 | 246(0xf6) | CALLDATALOAD(0x35) | 3 |
234(0xea) | PUSH8(0x67) ["0xff","0xff",... | 3 | 247(0xf7) | PUSH8(0x67) ["0xff","0xff",... | 3 |
243(0xf3) | DUP1(0x80) | 3 | 256(0x0100) | DUP1(0x80) | 3 |
244(0xf4) | DUP3(0x82) | 3 | 257(0x0101) | DUP3(0x82) | 3 |
245(0xf5) | GT(0x11) | 3 | 258(0x0102) | GT(0x11) | 3 |
246(0xf6) | ISZERO(0x15) | 3 | 259(0x0103) | ISZERO(0x15) | 3 |
247(0xf7) | PUSH2(0x61) ["0x00","0xde"] | 3 | 260(0x0104) | PUSH2(0x61) ["0x00","0xeb"] | 3 |
250(0xfa) | JUMPI(0x57) | 10 | 263(0x0107) | JUMPI(0x57) | 10 |
251(0xfb) | DUP4(0x83) | 3 | 264(0x0108) | DUP4(0x83) | 3 |
252(0xfc) | DUP5(0x84) | 3 | 265(0x0109) | DUP5(0x84) | 3 |
253(0xfd) | REVERT(0xfd) | 0 | 266(0x010a) | REVERT(0xfd) | 0 |
254(0xfe) | JUMPDEST(0x5b)@0xfe | 1 | 267(0x010b) | JUMPDEST(0x5b)@0x010b | 1 |
255(0xff) | DUP2(0x81) | 3 | 268(0x010c) | DUP2(0x81) | 3 |
256(0x0100) | DUP6(0x85) | 3 | 269(0x010d) | DUP6(0x85) | 3 |
257(0x0101) | ADD(0x1) | 3 | 270(0x010e) | ADD(0x1) | 3 |
258(0x0102) | SWAP2(0x91) | 3 | 271(0x010f) | SWAP2(0x91) | 3 |
259(0x0103) | POP(0x50) | 2 | 272(0x0110) | POP(0x50) | 2 |
260(0x0104) | DUP6(0x85) | 3 | 273(0x0111) | DUP6(0x85) | 3 |
261(0x0105) | PUSH1(0x60) ["0x1f"] | 3 | 274(0x0112) | PUSH1(0x60) ["0x1f"] | 3 |
263(0x0107) | DUP4(0x83) | 3 | 276(0x0114) | DUP4(0x83) | 3 |
264(0x0108) | ADD(0x1) | 3 | 277(0x0115) | ADD(0x1) | 3 |
265(0x0109) | SLT(0x12) | 3 | 278(0x0116) | SLT(0x12) | 3 |
266(0x010a) | PUSH2(0x61) ["0x00","0xf1"] | 3 | 279(0x0117) | PUSH2(0x61) ["0x00","0xfe"] | 3 |
269(0x010d) | JUMPI(0x57) | 10 | 282(0x011a) | JUMPI(0x57) | 10 |
270(0x010e) | DUP4(0x83) | 3 | 283(0x011b) | DUP4(0x83) | 3 |
271(0x010f) | DUP5(0x84) | 3 | 284(0x011c) | DUP5(0x84) | 3 |
272(0x0110) | REVERT(0xfd) | 0 | 285(0x011d) | REVERT(0xfd) | 0 |
273(0x0111) | JUMPDEST(0x5b)@0x0111 | 1 | 286(0x011e) | JUMPDEST(0x5b)@0x011e | 1 |
274(0x0112) | DUP2(0x81) | 3 | 287(0x011f) | DUP2(0x81) | 3 |
275(0x0113) | CALLDATALOAD(0x35) | 3 | 288(0x0120) | CALLDATALOAD(0x35) | 3 |
276(0x0114) | DUP2(0x81) | 3 | 289(0x0121) | DUP2(0x81) | 3 |
277(0x0115) | DUP2(0x81) | 3 | 290(0x0122) | DUP2(0x81) | 3 |
278(0x0116) | GT(0x11) | 3 | 291(0x0123) | GT(0x11) | 3 |
279(0x0117) | ISZERO(0x15) | 3 | 292(0x0124) | ISZERO(0x15) | 3 |
280(0x0118) | PUSH2(0x61) ["0x00","0xff"] | 3 | 293(0x0125) | PUSH2(0x61) ["0x01","0x0c"] | 3 |
283(0x011b) | JUMPI(0x57) | 10 | 296(0x0128) | JUMPI(0x57) | 10 |
284(0x011c) | DUP5(0x84) | 3 | 297(0x0129) | DUP5(0x84) | 3 |
285(0x011d) | DUP6(0x85) | 3 | 298(0x012a) | DUP6(0x85) | 3 |
286(0x011e) | REVERT(0xfd) | 0 | 299(0x012b) | REVERT(0xfd) | 0 |
287(0x011f) | JUMPDEST(0x5b)@0x011f | 1 | 300(0x012c) | JUMPDEST(0x5b)@0x012c | 1 |
288(0x0120) | DUP7(0x86) | 3 | 301(0x012d) | DUP7(0x86) | 3 |
289(0x0121) | PUSH1(0x60) ["0x20"] | 3 | 302(0x012e) | PUSH1(0x60) ["0x20"] | 3 |
291(0x0123) | DUP1(0x80) | 3 | 304(0x0130) | DUP1(0x80) | 3 |
292(0x0124) | DUP4(0x83) | 3 | 305(0x0131) | DUP4(0x83) | 3 |
293(0x0125) | MUL(0x2) | 5 | 306(0x0132) | MUL(0x2) | 5 |
294(0x0126) | DUP6(0x85) | 3 | 307(0x0133) | DUP6(0x85) | 3 |
295(0x0127) | ADD(0x1) | 3 | 308(0x0134) | ADD(0x1) | 3 |
296(0x0128) | ADD(0x1) | 3 | 309(0x0135) | ADD(0x1) | 3 |
297(0x0129) | GT(0x11) | 3 | 310(0x0136) | GT(0x11) | 3 |
298(0x012a) | ISZERO(0x15) | 3 | 311(0x0137) | ISZERO(0x15) | 3 |
299(0x012b) | PUSH2(0x61) ["0x01","0x12"] | 3 | 312(0x0138) | PUSH2(0x61) ["0x01","0x1f"] | 3 |
302(0x012e) | JUMPI(0x57) | 10 | 315(0x013b) | JUMPI(0x57) | 10 |
303(0x012f) | DUP5(0x84) | 3 | 316(0x013c) | DUP5(0x84) | 3 |
304(0x0130) | DUP6(0x85) | 3 | 317(0x013d) | DUP6(0x85) | 3 |
305(0x0131) | REVERT(0xfd) | 0 | 318(0x013e) | REVERT(0xfd) | 0 |
306(0x0132) | JUMPDEST(0x5b)@0x0132 | 1 | 319(0x013f) | JUMPDEST(0x5b)@0x013f | 1 |
307(0x0133) | PUSH1(0x60) ["0x20"] | 3 | 320(0x0140) | PUSH1(0x60) ["0x20"] | 3 |
309(0x0135) | SWAP3(0x92) | 3 | 322(0x0142) | SWAP3(0x92) | 3 |
310(0x0136) | SWAP1(0x90) | 3 | 323(0x0143) | SWAP1(0x90) | 3 |
311(0x0137) | SWAP3(0x92) | 3 | 324(0x0144) | SWAP3(0x92) | 3 |
312(0x0138) | ADD(0x1) | 3 | 325(0x0145) | ADD(0x1) | 3 |
313(0x0139) | SWAP7(0x96) | 3 | 326(0x0146) | SWAP7(0x96) | 3 |
314(0x013a) | SWAP2(0x91) | 3 | 327(0x0147) | SWAP2(0x91) | 3 |
315(0x013b) | SWAP6(0x95) | 3 | 328(0x0148) | SWAP6(0x95) | 3 |
316(0x013c) | POP(0x50) | 2 | 329(0x0149) | POP(0x50) | 2 |
317(0x013d) | SWAP1(0x90) | 3 | 330(0x014a) | SWAP1(0x90) | 3 |
318(0x013e) | SWAP4(0x93) | 3 | 331(0x014b) | SWAP4(0x93) | 3 |
319(0x013f) | POP(0x50) | 2 | 332(0x014c) | POP(0x50) | 2 |
320(0x0140) | POP(0x50) | 2 | 333(0x014d) | POP(0x50) | 2 |
321(0x0141) | POP(0x50) | 2 | 334(0x014e) | POP(0x50) | 2 |
322(0x0142) | POP(0x50) | 2 | 335(0x014f) | POP(0x50) | 2 |
323(0x0143) | JUMP(0x56) | 8 | 336(0x0150) | JUMP(0x56) | 8 |
324(0x0144) | JUMPDEST(0x5b)@0x0144 | 1 | 337(0x0151) | JUMPDEST(0x5b)@0x0151 | 1 |
338(0x0152) | PUSH1(0x60) ["0x00"] | 3 | |||
340(0x0154) | PUSH1(0x60) ["0x20"] | 3 | |||
342(0x0156) | DUP3(0x82) | 3 | |||
343(0x0157) | DUP5(0x84) | 3 | |||
344(0x0158) | SUB(0x3) | 3 | |||
345(0x0159) | SLT(0x12) | 3 | |||
346(0x015a) | ISZERO(0x15) | 3 | |||
347(0x015b) | PUSH2(0x61) ["0x01","0x42"] | 3 | |||
350(0x015e) | JUMPI(0x57) | 10 | |||
351(0x015f) | DUP1(0x80) | 3 | |||
352(0x0160) | DUP2(0x81) | 3 | |||
353(0x0161) | REVERT(0xfd) | 0 | |||
354(0x0162) | JUMPDEST(0x5b)@0x0162 | 1 | |||
355(0x0163) | DUP2(0x81) | 3 | |||
356(0x0164) | CALLDATALOAD(0x35) | 3 | |||
357(0x0165) | PUSH1(0x60) ["0xff"] | 3 | |||
359(0x0167) | DUP2(0x81) | 3 | |||
360(0x0168) | AND(0x16) | 3 | |||
361(0x0169) | DUP2(0x81) | 3 | |||
362(0x016a) | EQ(0x14) | 3 | |||
363(0x016b) | PUSH2(0x61) ["0x01","0x52"] | 3 | |||
366(0x016e) | JUMPI(0x57) | 10 | |||
367(0x016f) | DUP2(0x81) | 3 | |||
368(0x0170) | DUP3(0x82) | 3 | |||
369(0x0171) | REVERT(0xfd) | 0 | |||
370(0x0172) | JUMPDEST(0x5b)@0x0172 | 1 | |||
371(0x0173) | SWAP4(0x93) | 3 | |||
372(0x0174) | SWAP3(0x92) | 3 | |||
373(0x0175) | POP(0x50) | 2 | |||
374(0x0176) | POP(0x50) | 2 | |||
375(0x0177) | POP(0x50) | 2 | |||
376(0x0178) | JUMP(0x56) | 8 | |||
377(0x0179) | JUMPDEST(0x5b)@0x0179 | 1 | |||
378(0x017a) | PUSH1(0x60) ["0xff"] | 3 | |||
380(0x017c) | SWAP2(0x91) | 3 | |||
325(0x0145) | SWAP1(0x90) | 3 | 381(0x017d) | SWAP1(0x90) | 3 |
382(0x017e) | SWAP2(0x91) | 3 | |||
383(0x017f) | AND(0x16) | 3 | |||
326(0x0146) | DUP2(0x81) | 3 | 384(0x0180) | DUP2(0x81) | 3 |
327(0x0147) | MSTORE(0x52) | 3 | 385(0x0181) | MSTORE(0x52) | 3 |
328(0x0148) | PUSH1(0x60) ["0x20"] | 3 | 386(0x0182) | PUSH1(0x60) ["0x20"] | 3 |
330(0x014a) | ADD(0x1) | 3 | 388(0x0184) | ADD(0x1) | 3 |
331(0x014b) | SWAP1(0x90) | 3 | 389(0x0185) | SWAP1(0x90) | 3 |
332(0x014c) | JUMP(0x56) | 8 | 390(0x0186) | JUMP(0x56) | 8 |
333(0x014d) | JUMPDEST(0x5b)@0x014d | 1 | 391(0x0187) | JUMPDEST(0x5b)@0x0187 | 1 |
334(0x014e) | PUSH1(0x60) ["0x00"] | 3 | 392(0x0188) | PUSH1(0x60) ["0x00"] | 3 |
394(0x018a) | PUSH1(0x60) ["0xff"] | 3 | |||
336(0x0150) | DUP3(0x82) | 3 | 396(0x018c) | DUP3(0x82) | 3 |
397(0x018d) | AND(0x16) | 3 | |||
398(0x018e) | PUSH1(0x60) ["0xff"] | 3 | |||
400(0x0190) | DUP5(0x84) | 3 | |||
401(0x0191) | AND(0x16) | 3 | |||
402(0x0192) | DUP1(0x80) | 3 | |||
403(0x0193) | PUSH1(0x60) ["0xff"] | 3 | |||
405(0x0195) | SUB(0x3) | 3 | |||
337(0x0151) | NOT(0x19) | 3 | |||
338(0x0152) | DUP3(0x82) | 3 | 406(0x0196) | DUP3(0x82) | 3 |
339(0x0153) | GT(0x11) | 3 | 407(0x0197) | GT(0x11) | 3 |
340(0x0154) | ISZERO(0x15) | 3 | 408(0x0198) | ISZERO(0x15) | 3 |
341(0x0155) | PUSH2(0x61) ["0x01","0x40"] | 3 | 409(0x0199) | PUSH2(0x61) ["0x01","0x84"] | 3 |
344(0x0158) | JUMPI(0x57) | 10 | 412(0x019c) | JUMPI(0x57) | 10 |
345(0x0159) | PUSH2(0x61) ["0x01","0x40"] | 3 | 413(0x019d) | PUSH2(0x61) ["0x01","0x84"] | 3 |
348(0x015c) | PUSH2(0x61) ["0x01","0x60"] | 3 | 416(0x01a0) | PUSH2(0x61) ["0x01","0xa7"] | 3 |
351(0x015f) | JUMP(0x56) | 8 | 419(0x01a3) | JUMP(0x56) | 8 |
352(0x0160) | JUMPDEST(0x5b)@0x0160 | 1 | 420(0x01a4) | JUMPDEST(0x5b)@0x01a4 | 1 |
421(0x01a5) | ADD(0x1) | 3 | |||
422(0x01a6) | SWAP4(0x93) | 3 | |||
423(0x01a7) | SWAP3(0x92) | 3 | |||
353(0x0161) | POP(0x50) | 2 | 424(0x01a8) | POP(0x50) | 2 |
425(0x01a9) | POP(0x50) | 2 | |||
426(0x01aa) | POP(0x50) | 2 | |||
354(0x0162) | ADD(0x1) | 3 | |||
355(0x0163) | SWAP1(0x90) | 3 | |||
356(0x0164) | JUMP(0x56) | 8 | 427(0x01ab) | JUMP(0x56) | 8 |
Total.Uint256: | 465 | Total.Uint8: | 635 |
The change costs 170 more gas
It's cheaper to use calldata
as long as the array isn't an array of basic types whose sizes are each less than 256 bits
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // optimize 200
struct S {
uint256 word;
uint128 hword1;
uint128 hword2;
}
struct SA {
address addr;
}
/**
* @title ExtArgMemVsCall_c
* @author IllIllI
*/
contract ExtArgMemVsCall_c {
function basicAddr(address[] calldata x) pure public returns (uint256) {
uint256 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += uint256(uint160(x[i]));
}
return total;
}
function basicUint8(uint8[] calldata x) pure public returns (uint8) {
uint8 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
function basicUint248(uint248[] calldata x) pure public returns (uint248) {
uint248 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
function basicUint256(uint256[] calldata x) pure public returns (uint256) {
uint256 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
function structFull(S[] calldata x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i].word;
total2 += x[i].hword1;
total3 += x[i].hword2;
}
return total + total2 + total3;
}
function structPart(S[] calldata x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i].word;
}
return total + total2 + total3;
}
function structFullPointer(S[] calldata x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
S calldata xi = x[i];
total += xi.word;
total2 += xi.hword1;
total3 += xi.hword2;
}
return total + total2 + total3;
}
function structFullPointerMem(S[] calldata x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
S memory xi = x[i];
total += xi.word;
total2 += xi.hword1;
total3 += xi.hword2;
}
return total + total2 + total3;
}
function structAddr(SA[] calldata x) pure public returns (uint256) {
uint256 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += uint256(uint160(x[i].addr));
}
return total;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // optimize 200
struct S {
uint256 word;
uint128 hword1;
uint128 hword2;
}
struct SA {
address addr;
}
/**
* @title ExtArgMemVsCall_m
* @author IllIllI
*/
contract ExtArgMemVsCall_m {
function basicAddr(address[] memory x) pure public returns (uint256) {
uint256 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += uint256(uint160(x[i]));
}
return total;
}
function basicUint8(uint8[] memory x) pure public returns (uint8) {
uint8 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
function basicUint248(uint248[] memory x) pure public returns (uint248) {
uint248 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
function basicUint256(uint256[] memory x) pure public returns (uint256) {
uint256 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i];
}
return total;
}
function structFull(S[] memory x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i].word;
total2 += x[i].hword1;
total3 += x[i].hword2;
}
return total + total2 + total3;
}
function structPart(S[] memory x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += x[i].word;
}
return total + total2 + total3;
}
function structFullPointer(S[] memory x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
S memory xi = x[i];
total += xi.word;
total2 += xi.hword1;
total3 += xi.hword2;
}
return total + total2 + total3;
}
function structFullPointerMem(S[] memory x) pure public returns (uint256) {
uint256 total;
uint128 total2;
uint128 total3;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
S memory xi = x[i];
total += xi.word;
total2 += xi.hword1;
total3 += xi.hword2;
}
return total + total2 + total3;
}
function structAddr(SA[] memory x) pure public returns (uint256) {
uint256 total;
uint256 len = x.length;
for (uint256 i = 0; i < len; ++i) {
total += uint256(uint160(x[i].addr));
}
return total;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ExtArgMemVsCall_c, S, SA} from "../src/ExtArgMemVsCall_c.sol";
contract Tst {
uint256 constant ITERATIONS_S = 2;
uint256 constant ITERATIONS_M = 128;
uint256 constant ITERATIONS_L = 256;
function testBasicAddr() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.basicAddr(new address[](ITERATIONS_S));
c.basicAddr(new address[](ITERATIONS_M));
c.basicAddr(new address[](ITERATIONS_L));
}
function testBasicUint8() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.basicUint8(new uint8[](ITERATIONS_S));
c.basicUint8(new uint8[](ITERATIONS_M));
c.basicUint8(new uint8[](ITERATIONS_L));
}
function testBasicUint248() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.basicUint248(new uint248[](ITERATIONS_S));
c.basicUint248(new uint248[](ITERATIONS_M));
c.basicUint248(new uint248[](ITERATIONS_L));
}
function testBasicUint256() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.basicUint256(new uint256[](ITERATIONS_S));
c.basicUint256(new uint256[](ITERATIONS_M));
c.basicUint256(new uint256[](ITERATIONS_L));
}
function testStructFull() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.structFull(new S[](ITERATIONS_S));
c.structFull(new S[](ITERATIONS_M));
c.structFull(new S[](ITERATIONS_L));
}
function testStructPart() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.structPart(new S[](ITERATIONS_S));
c.structPart(new S[](ITERATIONS_M));
c.structPart(new S[](ITERATIONS_L));
}
function testStructFullPointer() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.structFullPointer(new S[](ITERATIONS_S));
c.structFullPointer(new S[](ITERATIONS_M));
c.structFullPointer(new S[](ITERATIONS_L));
}
function testStructFullPointerMem() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.structFullPointerMem(new S[](ITERATIONS_S));
c.structFullPointerMem(new S[](ITERATIONS_M));
c.structFullPointerMem(new S[](ITERATIONS_L));
}
function testStructAddr() external {
ExtArgMemVsCall_c c = new ExtArgMemVsCall_c();
c.structAddr(new SA[](ITERATIONS_S));
c.structAddr(new SA[](ITERATIONS_M));
c.structAddr(new SA[](ITERATIONS_L));
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {ExtArgMemVsCall_m, S, SA} from "../src/ExtArgMemVsCall_m.sol";
contract Tst {
uint256 constant ITERATIONS_S = 2;
uint256 constant ITERATIONS_M = 128;
uint256 constant ITERATIONS_L = 256;
function testBasicAddr() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.basicAddr(new address[](ITERATIONS_S));
c.basicAddr(new address[](ITERATIONS_M));
c.basicAddr(new address[](ITERATIONS_L));
}
function testBasicUint8() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.basicUint8(new uint8[](ITERATIONS_S));
c.basicUint8(new uint8[](ITERATIONS_M));
c.basicUint8(new uint8[](ITERATIONS_L));
}
function testBasicUint248() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.basicUint248(new uint248[](ITERATIONS_S));
c.basicUint248(new uint248[](ITERATIONS_M));
c.basicUint248(new uint248[](ITERATIONS_L));
}
function testBasicUint256() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.basicUint256(new uint256[](ITERATIONS_S));
c.basicUint256(new uint256[](ITERATIONS_M));
c.basicUint256(new uint256[](ITERATIONS_L));
}
function testStructFull() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.structFull(new S[](ITERATIONS_S));
c.structFull(new S[](ITERATIONS_M));
c.structFull(new S[](ITERATIONS_L));
}
function testStructPart() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.structPart(new S[](ITERATIONS_S));
c.structPart(new S[](ITERATIONS_M));
c.structPart(new S[](ITERATIONS_L));
}
function testStructFullPointer() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.structFullPointer(new S[](ITERATIONS_S));
c.structFullPointer(new S[](ITERATIONS_M));
c.structFullPointer(new S[](ITERATIONS_L));
}
function testStructFullPointerMem() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.structFullPointerMem(new S[](ITERATIONS_S));
c.structFullPointerMem(new S[](ITERATIONS_M));
c.structFullPointerMem(new S[](ITERATIONS_L));
}
function testStructAddr() external {
ExtArgMemVsCall_m c = new ExtArgMemVsCall_m();
c.structAddr(new SA[](ITERATIONS_S));
c.structAddr(new SA[](ITERATIONS_M));
c.structAddr(new SA[](ITERATIONS_L));
}
}
Compiling 4 files with 0.8.20
Solc 0.8.20 finished in 966.83ms
Compiler run �[32msuccessful!�[0m
Running 9 tests for test/Memory.sol:Tst
�[32m[PASS]�[0m testBasicAddr() (gas: 792070)
�[32m[PASS]�[0m testBasicUint248() (gas: 784135)
�[32m[PASS]�[0m testBasicUint256() (gas: 748596)
�[32m[PASS]�[0m testBasicUint8() (gas: 768084)
�[32m[PASS]�[0m testStructAddr() (gas: 878300)
�[32m[PASS]�[0m testStructFull() (gas: 1105563)
�[32m[PASS]�[0m testStructFullPointer() (gas: 1074107)
�[32m[PASS]�[0m testStructFullPointerMem() (gas: 1074165)
�[32m[PASS]�[0m testStructPart() (gas: 969799)
Test result: �[32mok�[0m. 9 passed; 0 failed; finished in 31.26ms
Running 9 tests for test/Calldata.sol:Tst
�[32m[PASS]�[0m testBasicAddr() (gas: 659952)
�[32m[PASS]�[0m testBasicUint248() (gas: 665527)
�[32m[PASS]�[0m testBasicUint256() (gas: 595634)
�[32m[PASS]�[0m testBasicUint8() (gas: 649476)
�[32m[PASS]�[0m testStructAddr() (gas: 693197)
�[32m[PASS]�[0m testStructFull() (gas: 942337)
�[32m[PASS]�[0m testStructFullPointer() (gas: 906635)
�[32m[PASS]�[0m testStructFullPointerMem() (gas: 931315)
�[32m[PASS]�[0m testStructPart() (gas: 682281)
Test result: �[32mok�[0m. 9 passed; 0 failed; finished in 31.44ms
| src/ExtArgMemVsCall_c.sol:ExtArgMemVsCall_c contract | | | | | |
|------------------------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 432668 | 2193 | | | | |
| Function Name | min | avg | median | max | # calls |
| basicAddr | 1412 | 50558 | 50300 | 99964 | 3 |
| basicUint248 | 1429 | 52349 | 52081 | 103537 | 3 |
| basicUint256 | 1028 | 31428 | 31268 | 61988 | 3 |
| basicUint8 | 1337 | 48583 | 48335 | 96079 | 3 |
| structAddr | 1390 | 50536 | 50278 | 99942 | 3 |
| structFull | 2554 | 118707 | 118096 | 235472 | 3 |
| structFullPointer | 2411 | 106784 | 106235 | 211707 | 3 |
| structFullPointerMem | 2554 | 115014 | 114233 | 228257 | 3 |
| structPart | 1227 | 32007 | 31845 | 62949 | 3 |
| src/ExtArgMemVsCall_m.sol:ExtArgMemVsCall_m contract | | | | | |
|------------------------------------------------------|-----------------|--------|--------|--------|---------|
| Deployment Cost | Deployment Size | | | | |
| 555187 | 2805 | | | | |
| Function Name | min | avg | median | max | # calls |
| basicAddr | 1623 | 53739 | 53444 | 106151 | 3 |
| basicUint248 | 1570 | 51026 | 50745 | 100764 | 3 |
| basicUint256 | 1347 | 41556 | 41324 | 81999 | 3 |
| basicUint8 | 1478 | 47261 | 46999 | 93306 | 3 |
| structAddr | 1873 | 71379 | 70929 | 141335 | 3 |
| structFull | 2952 | 132257 | 131240 | 262580 | 3 |
| structFullPointer | 2831 | 121749 | 120787 | 241631 | 3 |
| structFullPointerMem | 2854 | 121772 | 120810 | 241654 | 3 |
| structPart | 2269 | 86987 | 86205 | 172489 | 3 |