diff --git a/Changelog.md b/Changelog.md index 18066a775..d91eccb31 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Language Features: Compiler Features: + * Code Generator: More efficient overflow checks for multiplication. Bugfixes: diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index b24cf4f90..b66189f05 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -684,28 +684,46 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type) function (x, y) -> product { x := (x) y := (y) + let product_raw := mul(x, y) + product := (product_raw) - // overflow, if x > 0, y > 0 and x > (maxValue / y) - if and(and(sgt(x, 0), sgt(y, 0)), gt(x, div(, y))) { () } - // underflow, if x > 0, y < 0 and y < (minValue / x) - if and(and(sgt(x, 0), slt(y, 0)), slt(y, sdiv(, x))) { () } - // underflow, if x < 0, y > 0 and x < (minValue / y) - if and(and(slt(x, 0), sgt(y, 0)), slt(x, sdiv(, y))) { () } - // overflow, if x < 0, y < 0 and x < (maxValue / y) - if and(and(slt(x, 0), slt(y, 0)), slt(x, sdiv(, y))) { () } + + + // special case + if and(slt(x, 0), eq(y, )) { () } + + // overflow, if x != 0 and y != product/x + if iszero( + or( + iszero(x), + eq(y, sdiv(product, x)) + ) + ) { () } + + if iszero(eq(product, product_raw)) { () } + - // overflow, if x != 0 and y > (maxValue / x) - if and(iszero(iszero(x)), gt(y, div(, x))) { () } + + // overflow, if x != 0 and y != product/x + if iszero( + or( + iszero(x), + eq(y, div(product, x)) + ) + ) { () } + + if iszero(eq(product, product_raw)) { () } + - product := mul(x, y) } )") ("functionName", functionName) ("signed", _type.isSigned()) - ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) - ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("cleanupFunction", cleanupFunction(_type)) ("panic", panicFunction(PanicCode::UnderOverflow)) + ("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) + ("256bit", _type.numBits() == 256) + ("gt128bit", _type.numBits() > 128) .render(); }); } diff --git a/test/formal/checked_int_mul_12.py b/test/formal/checked_int_mul_12.py new file mode 100644 index 000000000..ea13f0194 --- /dev/null +++ b/test/formal/checked_int_mul_12.py @@ -0,0 +1,46 @@ +from opcodes import AND, SDIV, MUL, EQ, ISZERO, OR, SLT +from rule import Rule +from util import BVSignedUpCast, BVSignedMin, BVSignedCleanupFunction +from z3 import BVMulNoOverflow, BVMulNoUnderflow, BitVec, Not, Or + +""" +Overflow checked signed integer multiplication. +""" + +# Approximation with 16-bit base types. +n_bits = 12 + +for type_bits in [4, 6, 8, 12]: + + rule = Rule() + + # Input vars + X_short = BitVec('X', type_bits) + Y_short = BitVec('Y', type_bits) + + # Z3's overflow and underflow conditions + actual_overflow = Not(BVMulNoOverflow(X_short, Y_short, True)) + actual_underflow = Not(BVMulNoUnderflow(X_short, Y_short)) + + # cast to full n_bits values + X = BVSignedUpCast(X_short, n_bits) + Y = BVSignedUpCast(Y_short, n_bits) + product_raw = MUL(X, Y) + #remove any overflown bits + product = BVSignedCleanupFunction(product_raw, type_bits) + + # Constants + min_value = BVSignedMin(type_bits, n_bits) + + # Overflow and underflow checks in YulUtilFunction::overflowCheckedIntMulFunction + if type_bits > n_bits / 2: + sol_overflow_check_1 = ISZERO(OR(ISZERO(X), EQ(Y, SDIV(product, X)))) + if type_bits == n_bits: + sol_overflow_check_2 = AND(SLT(X, 0), EQ(Y, min_value)) + sol_overflow_check = Or(sol_overflow_check_1 != 0, sol_overflow_check_2 != 0) + else: + sol_overflow_check = (sol_overflow_check_1 != 0) + else: + sol_overflow_check = (ISZERO(EQ(product, product_raw)) != 0) + + rule.check(Or(actual_overflow, actual_underflow), sol_overflow_check) diff --git a/test/formal/checked_int_mul_16.py b/test/formal/checked_int_mul_16.py deleted file mode 100644 index b2f9eb852..000000000 --- a/test/formal/checked_int_mul_16.py +++ /dev/null @@ -1,43 +0,0 @@ -from opcodes import AND, DIV, GT, SDIV, SGT, SLT -from rule import Rule -from util import BVSignedMax, BVSignedMin, BVSignedUpCast -from z3 import BVMulNoOverflow, BVMulNoUnderflow, BitVec, Not, Or - -""" -Overflow checked signed integer multiplication. -""" - -# Approximation with 16-bit base types. -n_bits = 16 -type_bits = 8 - -while type_bits <= n_bits: - - rule = Rule() - - # Input vars - X_short = BitVec('X', type_bits) - Y_short = BitVec('Y', type_bits) - - # Z3's overflow and underflow conditions - actual_overflow = Not(BVMulNoOverflow(X_short, Y_short, True)) - actual_underflow = Not(BVMulNoUnderflow(X_short, Y_short)) - - # cast to full n_bits values - X = BVSignedUpCast(X_short, n_bits) - Y = BVSignedUpCast(Y_short, n_bits) - - # Constants - maxValue = BVSignedMax(type_bits, n_bits) - minValue = BVSignedMin(type_bits, n_bits) - - # Overflow and underflow checks in YulUtilFunction::overflowCheckedIntMulFunction - overflow_check_1 = AND(AND(SGT(X, 0), SGT(Y, 0)), GT(X, DIV(maxValue, Y))) - underflow_check_1 = AND(AND(SGT(X, 0), SLT(Y, 0)), SLT(Y, SDIV(minValue, X))) - underflow_check_2 = AND(AND(SLT(X, 0), SGT(Y, 0)), SLT(X, SDIV(minValue, Y))) - overflow_check_2 = AND(AND(SLT(X, 0), SLT(Y, 0)), SLT(X, SDIV(maxValue, Y))) - - rule.check(actual_overflow, Or(overflow_check_1 != 0, overflow_check_2 != 0)) - rule.check(actual_underflow, Or(underflow_check_1 != 0, underflow_check_2 != 0)) - - type_bits *= 2 diff --git a/test/formal/checked_uint_mul_16.py b/test/formal/checked_uint_mul_12.py similarity index 58% rename from test/formal/checked_uint_mul_16.py rename to test/formal/checked_uint_mul_12.py index 1c60de47b..a386fcfa4 100644 --- a/test/formal/checked_uint_mul_16.py +++ b/test/formal/checked_uint_mul_12.py @@ -1,6 +1,6 @@ -from opcodes import AND, ISZERO, GT, DIV +from opcodes import ISZERO, DIV, MUL, EQ, OR from rule import Rule -from util import BVUnsignedUpCast, BVUnsignedMax +from util import BVUnsignedUpCast, BVUnsignedCleanupFunction from z3 import BitVec, Not, BVMulNoOverflow """ @@ -8,10 +8,9 @@ Overflow checked unsigned integer multiplication. """ # Approximation with 16-bit base types. -n_bits = 16 -type_bits = 8 +n_bits = 12 -while type_bits <= n_bits: +for type_bits in [4, 6, 8, 12]: rule = Rule() @@ -25,13 +24,14 @@ while type_bits <= n_bits: # cast to full n_bits values X = BVUnsignedUpCast(X_short, n_bits) Y = BVUnsignedUpCast(Y_short, n_bits) + product_raw = MUL(X, Y) + #remove any overflown bits + product = BVUnsignedCleanupFunction(product_raw, type_bits) - # Constants - maxValue = BVUnsignedMax(type_bits, n_bits) - - # Overflow check in YulUtilFunction::overflowCheckedIntMulFunction - overflow_check = AND(ISZERO(ISZERO(X)), GT(Y, DIV(maxValue, X))) + # Overflow check in YulUtilFunction::overflowCheckedIntMulFunctions + if type_bits > n_bits / 2: + overflow_check = ISZERO(OR(ISZERO(X), EQ(Y, DIV(product, X)))) + else: + overflow_check = ISZERO(EQ(product, product_raw)) rule.check(overflow_check != 0, actual_overflow) - - type_bits *= 2 diff --git a/test/formal/signed_integer_cleanup_function.py b/test/formal/signed_integer_cleanup_function.py new file mode 100644 index 000000000..2b7b0e440 --- /dev/null +++ b/test/formal/signed_integer_cleanup_function.py @@ -0,0 +1,41 @@ +from opcodes import SIGNEXTEND +from rule import Rule +from util import BVSignedCleanupFunction, BVSignedUpCast +from z3 import BitVec, BitVecVal, Concat + +""" +Overflow checked signed integer multiplication. +""" + +n_bits = 256 + +# Check that YulUtilFunction::cleanupFunction cleanup matches BVSignedCleanupFunction +for type_bits in range(8,256,8): + + rule = Rule() + + # Input vars + X = BitVec('X', n_bits) + arg = BitVecVal(type_bits / 8 - 1, n_bits) + + cleaned_reference = BVSignedCleanupFunction(X, type_bits) + cleaned = SIGNEXTEND(arg, X) + + rule.check(cleaned, cleaned_reference) + + +# Check that BVSignedCleanupFunction properly cleans up values. +for type_bits in range(8,256,8): + + rule = Rule() + + # Input vars + X_short = BitVec('X', type_bits) + dirt = BitVec('dirt', n_bits - type_bits) + + X = BVSignedUpCast(X_short, n_bits) + X_dirty = Concat(dirt, X_short) + X_cleaned = BVSignedCleanupFunction(X_dirty, type_bits) + + + rule.check(X, X_cleaned) diff --git a/test/formal/unsigned_integer_cleanup_function.py b/test/formal/unsigned_integer_cleanup_function.py new file mode 100644 index 000000000..42296f89b --- /dev/null +++ b/test/formal/unsigned_integer_cleanup_function.py @@ -0,0 +1,40 @@ +from opcodes import AND +from rule import Rule +from util import BVUnsignedCleanupFunction, BVUnsignedUpCast +from z3 import BitVec, BitVecVal, Concat + +""" +Overflow checked unsigned integer multiplication. +""" + +n_bits = 256 + +# Check that YulUtilFunction::cleanupFunction cleanup matches BVUnsignedCleanupFunction +for type_bits in range(8,256,8): + + rule = Rule() + + # Input vars + X = BitVec('X', n_bits) + mask = BitVecVal((1 << type_bits) - 1, n_bits) + + cleaned_reference = BVUnsignedCleanupFunction(X, type_bits) + cleaned = AND(X, mask) + + rule.check(cleaned, cleaned_reference) + +# Check that BVUnsignedCleanupFunction properly cleans up values. +for type_bits in range(8,256,8): + + rule = Rule() + + # Input vars + X_short = BitVec('X', type_bits) + dirt = BitVec('dirt', n_bits - type_bits) + + X = BVUnsignedUpCast(X_short, n_bits) + X_dirty = Concat(dirt, X_short) + X_cleaned = BVUnsignedCleanupFunction(X_dirty, type_bits) + + + rule.check(X, X_cleaned) diff --git a/test/formal/util.py b/test/formal/util.py index 8d0debbef..8fc261fdc 100644 --- a/test/formal/util.py +++ b/test/formal/util.py @@ -25,3 +25,18 @@ def BVSignedMax(type_bits, n_bits): def BVSignedMin(type_bits, n_bits): assert type_bits <= n_bits return BitVecVal(-(1 << (type_bits - 1)), n_bits) + +def BVSignedCleanupFunction(x, type_bits): + assert x.size() >= type_bits + sign_mask = BitVecVal(1, x.size()) << (type_bits - 1) + bit_mask = (BitVecVal(1, x.size()) << type_bits) - 1 + return If( + x & sign_mask == 0, + x & bit_mask, + x | ~bit_mask + ) + +def BVUnsignedCleanupFunction(x, type_bits): + assert x.size() >= type_bits + bit_mask = (BitVecVal(1, x.size()) << type_bits) - 1 + return x & bit_mask diff --git a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol index 5f71fc7e2..16f365bd4 100644 --- a/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol +++ b/test/libsolidity/semanticTests/abiEncoderV2/storage_array_encoding.sol @@ -18,10 +18,10 @@ contract C { // EVMVersion: >homestead // ---- // h(uint256[2][]): 0x20, 3, 123, 124, 223, 224, 323, 324 -> 32, 256, 0x20, 3, 123, 124, 223, 224, 323, 324 -// gas irOptimized: 180726 +// gas irOptimized: 180829 // gas legacy: 184921 // gas legacyOptimized: 181506 // i(uint256[2][2]): 123, 124, 223, 224 -> 32, 128, 123, 124, 223, 224 -// gas irOptimized: 112453 +// gas irOptimized: 112464 // gas legacy: 115460 // gas legacyOptimized: 112990 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol b/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol index b98ddec9d..c3958abac 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_including_array.sol @@ -35,12 +35,12 @@ contract c { } // ---- // test() -> 0x02000202 -// gas irOptimized: 4649903 -// gas legacy: 4578320 -// gas legacyOptimized: 4548312 +// gas irOptimized: 4649835 +// gas legacy: 4578446 +// gas legacyOptimized: 4548309 // storageEmpty -> 1 // clear() -> 0, 0 -// gas irOptimized: 4477229 +// gas irOptimized: 4477223 // gas legacy: 4410748 // gas legacyOptimized: 4382489 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol b/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol index d8907cf03..a85765cd9 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_nested_array.sol @@ -13,6 +13,6 @@ contract c { // ---- // test(uint256[2][]): 32, 3, 7, 8, 9, 10, 11, 12 -> 10 -// gas irOptimized: 689768 +// gas irOptimized: 689759 // gas legacy: 686268 // gas legacyOptimized: 685688 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol index 0225f421c..3fc10b7a2 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_storage_storage_struct.sol @@ -17,7 +17,7 @@ contract c { } // ---- // test() -> 4, 5 -// gas irOptimized: 238692 +// gas irOptimized: 238623 // gas legacy: 238736 // gas legacyOptimized: 237159 // storageEmpty -> 1 diff --git a/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol b/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol index 6c07ceec7..f2d02ee57 100644 --- a/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol +++ b/test/libsolidity/semanticTests/array/copying/array_copy_target_leftover.sol @@ -19,6 +19,6 @@ contract c { // compileToEwasm: also // ---- // test() -> 0xffffffff, 0x0000000000000000000000000a00090008000700060005000400030002000100, 0x0000000000000000000000000000000000000000000000000000000000000000 -// gas irOptimized: 124817 -// gas legacy: 186028 -// gas legacyOptimized: 165692 +// gas irOptimized: 124910 +// gas legacy: 187414 +// gas legacyOptimized: 165659 diff --git a/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol index c737a5b04..02872f8dd 100644 --- a/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_nested_calldata_to_storage.sol @@ -42,6 +42,6 @@ contract c { // test2(uint256[][2]): 0x20, 0x40, 0x40, 2, 23, 42 -> 2, 65 // gas irOptimized: 157567 // test3(uint256[2][]): 0x20, 2, 23, 42, 23, 42 -> 2, 65 -// gas irOptimized: 134633 +// gas irOptimized: 134644 // test4(uint256[2][2]): 23, 42, 23, 42 -> 65 // gas irOptimized: 111271 diff --git a/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol b/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol index a8bacdda6..a7487a64f 100644 --- a/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol +++ b/test/libsolidity/semanticTests/array/copying/array_of_struct_calldata_to_storage.sol @@ -17,4 +17,4 @@ contract C { // compileViaYul: true // ---- // f((uint128,uint64,uint128)[]): 0x20, 3, 0, 0, 12, 0, 11, 0, 10, 0, 0 -> 10, 11, 12 -// gas irOptimized: 119740 +// gas irOptimized: 119737 diff --git a/test/libsolidity/semanticTests/externalContracts/base64.sol b/test/libsolidity/semanticTests/externalContracts/base64.sol index 84ece36be..de5def995 100644 --- a/test/libsolidity/semanticTests/externalContracts/base64.sol +++ b/test/libsolidity/semanticTests/externalContracts/base64.sol @@ -33,9 +33,9 @@ contract test { // EVMVersion: >=constantinople // ---- // constructor() -// gas irOptimized: 441142 -// gas legacy: 755907 -// gas legacyOptimized: 538354 +// gas irOptimized: 438352 +// gas legacy: 750723 +// gas legacyOptimized: 536620 // encode_inline_asm(bytes): 0x20, 0 -> 0x20, 0 // encode_inline_asm(bytes): 0x20, 1, "f" -> 0x20, 4, "Zg==" // encode_inline_asm(bytes): 0x20, 2, "fo" -> 0x20, 4, "Zm8=" @@ -51,10 +51,10 @@ contract test { // encode_no_asm(bytes): 0x20, 5, "fooba" -> 0x20, 8, "Zm9vYmE=" // encode_no_asm(bytes): 0x20, 6, "foobar" -> 0x20, 8, "Zm9vYmFy" // encode_inline_asm_large() -// gas irOptimized: 1382042 -// gas legacy: 1646033 -// gas legacyOptimized: 1206033 +// gas irOptimized: 1387042 +// gas legacy: 1688033 +// gas legacyOptimized: 1205033 // encode_no_asm_large() -// gas irOptimized: 3311099 -// gas legacy: 4723077 -// gas legacyOptimized: 2909077 +// gas irOptimized: 3316099 +// gas legacy: 4765077 +// gas legacyOptimized: 2908077 diff --git a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol index bf62bb81a..b4b7054a4 100644 --- a/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol +++ b/test/libsolidity/semanticTests/externalContracts/ramanujan_pi.sol @@ -33,10 +33,10 @@ contract test { } // ---- // constructor() -// gas irOptimized: 422763 -// gas legacy: 654526 -// gas legacyOptimized: 474842 +// gas irOptimized: 430305 +// gas legacy: 649335 +// gas legacyOptimized: 473132 // prb_pi() -> 3141592656369545286 // gas irOptimized: 57478 -// gas legacy: 98903 +// gas legacy: 103112 // gas legacyOptimized: 75735 diff --git a/test/libsolidity/semanticTests/externalContracts/snark.sol b/test/libsolidity/semanticTests/externalContracts/snark.sol index 10c16c4b7..7d04b5af6 100644 --- a/test/libsolidity/semanticTests/externalContracts/snark.sol +++ b/test/libsolidity/semanticTests/externalContracts/snark.sol @@ -297,5 +297,5 @@ contract Test { // verifyTx() -> true // ~ emit Verified(string): 0x20, 0x16, "Successfully verified." // gas irOptimized: 95261 -// gas legacy: 113239 +// gas legacy: 116473 // gas legacyOptimized: 83670 diff --git a/test/libsolidity/semanticTests/externalContracts/strings.sol b/test/libsolidity/semanticTests/externalContracts/strings.sol index edbf82a29..654562ef0 100644 --- a/test/libsolidity/semanticTests/externalContracts/strings.sol +++ b/test/libsolidity/semanticTests/externalContracts/strings.sol @@ -49,9 +49,9 @@ contract test { } // ---- // constructor() -// gas irOptimized: 675980 -// gas legacy: 1101298 -// gas legacyOptimized: 743666 +// gas irOptimized: 670586 +// gas legacy: 1096108 +// gas legacyOptimized: 741962 // toSlice(string): 0x20, 11, "hello world" -> 11, 0xa0 // gas irOptimized: 22660 // gas legacy: 23190 @@ -69,6 +69,6 @@ contract test { // gas legacy: 31621 // gas legacyOptimized: 27914 // benchmark(string,bytes32): 0x40, 0x0842021, 8, "solidity" -> 0x2020 -// gas irOptimized: 2017767 -// gas legacy: 4294510 -// gas legacyOptimized: 2327982 +// gas irOptimized: 2017770 +// gas legacy: 4294552 +// gas legacyOptimized: 2327981 diff --git a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol index 8bd823e39..d51b99b59 100644 --- a/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol +++ b/test/libsolidity/semanticTests/salted_create/salted_create_with_value.sol @@ -21,6 +21,6 @@ contract A { // EVMVersion: >=constantinople // ---- // f(), 10 ether -> 3007, 3008, 3009 -// gas irOptimized: 268645 -// gas legacy: 402016 -// gas legacyOptimized: 288087 +// gas irOptimized: 255997 +// gas legacy: 387712 +// gas legacyOptimized: 283266 diff --git a/test/libsolidity/semanticTests/viaYul/detect_mul_overflow_signed.sol b/test/libsolidity/semanticTests/viaYul/detect_mul_overflow_signed.sol index dd1953d00..a9581c49f 100644 --- a/test/libsolidity/semanticTests/viaYul/detect_mul_overflow_signed.sol +++ b/test/libsolidity/semanticTests/viaYul/detect_mul_overflow_signed.sol @@ -5,6 +5,9 @@ contract C { function g(int8 a, int8 b) public pure returns (int8 x) { x = a * b; } + function h(int160 a, int160 b) public pure returns (int160 x) { + x = a * b; + } } // ==== // compileToEwasm: also @@ -15,6 +18,9 @@ contract C { // f(int256,int256): 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, 2 -> 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE // f(int256,int256): 0x4000000000000000000000000000000000000000000000000000000000000000, 2 -> FAILURE, hex"4e487b71", 0x11 // f(int256,int256): 2, 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +// f(int256,int256): 2, 0x4000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"4e487b71", 0x11 +// f(int256,int256): -1, 0x8000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"4e487b71", 0x11 +// f(int256,int256): 0x8000000000000000000000000000000000000000000000000000000000000000, -1 -> FAILURE, hex"4e487b71", 0x11 // f(int256,int256): 2, 0x4000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"4e487b71", 0x11 # positive, negative # // f(int256,int256): 2, 0x4000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"4e487b71", 0x11 # positive, negative # // f(int256,int256): 2, 0x4000000000000000000000000000000000000000000000000000000000000000 -> FAILURE, hex"4e487b71", 0x11 # positive, negative # @@ -61,3 +67,18 @@ contract C { // g(int8,int8): -64, -2 -> FAILURE, hex"4e487b71", 0x11 // g(int8,int8): -2, -63 -> 126 // g(int8,int8): -2, -64 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): -1, 1 -> -1 +// h(int160,int160): 1, -1 -> -1 +// h(int160,int160): -1, 2 -> -2 +// h(int160,int160): 2, -1 -> -2 +// h(int160,int160): -1, 0xFFFFFFFFFFFFFFFFFFFFFFFF8000000000000000000000000000000000000000 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): -1, 0xFFFFFFFFFFFFFFFFFFFFFFFF8000000000000000000000000000000000000000 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): 0xFFFFFFFFFFFFFFFFFFFFFFFF8000000000000000000000000000000000000000, -1 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): 0x0000000000000000000000004000000000000000000000000000000000000000, -2 -> 0xFFFFFFFFFFFFFFFFFFFFFFFF8000000000000000000000000000000000000000 +// h(int160,int160): -2, 0x0000000000000000000000004000000000000000000000000000000000000000 -> 0xFFFFFFFFFFFFFFFFFFFFFFFF8000000000000000000000000000000000000000 +// h(int160,int160): -2, 0x0000000000000000000000004000000000000000000000000000000000000001 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): 0x0000000000000000000000004000000000000000000000000000000000000001, -2 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): 0x0000000000000000000000004000000000000000000000000000000000000001, 2 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): 2, 0x0000000000000000000000004000000000000000000000000000000000000001 -> FAILURE, hex"4e487b71", 0x11 +// h(int160,int160): 0x0000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, 2 -> 0x0000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +// h(int160,int160): 2, 0x0000000000000000000000004000000000000000000000000000000000000001 -> FAILURE, hex"4e487b71", 0x11