Skip to content

Commit

Permalink
feat: optimize int256 bounds checks
Browse files Browse the repository at this point in the history
  • Loading branch information
iamdefinitelyahuman committed Apr 14, 2021
1 parent 94dbf89 commit 2ff7329
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 8 deletions.
8 changes: 6 additions & 2 deletions vyper/functions/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from vyper import ast as vy_ast
from vyper.exceptions import InvalidLiteral, StructureException, TypeMismatch
from vyper.functions.signatures import signature
from vyper.opcodes import version_check
from vyper.parser.arg_clamps import address_clamp, int128_clamp
from vyper.parser.parser_utils import LLLnode, byte_array_to_num, getpos
from vyper.types import BaseType, ByteArrayType, StringType, get_type
Expand Down Expand Up @@ -190,9 +191,12 @@ def to_int256(expr, args, kwargs, context):
return LLLnode.from_list(in_arg, typ=BaseType("int256"), pos=getpos(expr))

elif isinstance(in_arg, LLLnode) and input_type == "uint256":
# TODO bitshift to save gas on the bounds check
if version_check(begin="constantinople"):
upper_bound = ["shl", 255, 1]
else:
upper_bound = -(2 ** 255)
return LLLnode.from_list(
["uclample", in_arg, SizeLimits.MAX_INT256], typ=BaseType("int256"), pos=getpos(expr)
["uclamplt", in_arg, upper_bound], typ=BaseType("int256"), pos=getpos(expr)
)

elif isinstance(in_arg, LLLnode) and input_type == "decimal":
Expand Down
26 changes: 20 additions & 6 deletions vyper/parser/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -559,12 +559,19 @@ def parse_BinOp(self):
]

elif ltyp == "int256":
if version_check(begin="constantinople"):
upper_bound = ["shl", 255, 1]
else:
upper_bound = -(2 ** 255)
if not left.typ.is_literal and not right.typ.is_literal:
bounds_check = ["assert", ["or", ["ne", "l", -1], ["ne", "r", -(2 ** 255)]]]
bounds_check = [
"assert",
["or", ["ne", "l", ["not", 0]], ["ne", "r", upper_bound]],
]
elif left.typ.is_literal and left.value == -1:
bounds_check = ["assert", ["ne", "r", -(2 ** 255)]]
bounds_check = ["assert", ["ne", "r", upper_bound]]
elif right.typ.is_literal and right.value == -(2 ** 255):
bounds_check = ["assert", ["ne", "l", -1]]
bounds_check = ["assert", ["ne", "l", ["not", 0]]]
else:
bounds_check = "pass"
arith = [
Expand Down Expand Up @@ -610,12 +617,19 @@ def parse_BinOp(self):
arith = ["div", "l", divisor]

elif ltyp == "int256":
if version_check(begin="constantinople"):
upper_bound = ["shl", 255, 1]
else:
upper_bound = -(2 ** 255)
if not left.typ.is_literal and not right.typ.is_literal:
bounds_check = ["assert", ["or", ["ne", "r", -1], ["ne", "l", -(2 ** 255)]]]
bounds_check = [
"assert",
["or", ["ne", "r", ["not", 0]], ["ne", "l", upper_bound]],
]
elif left.typ.is_literal and left.value == -(2 ** 255):
bounds_check = ["assert", ["ne", "r", -1]]
bounds_check = ["assert", ["ne", "r", ["not", 0]]]
elif right.typ.is_literal and right.value == -1:
bounds_check = ["assert", ["ne", "l", -(2 ** 255)]]
bounds_check = ["assert", ["ne", "l", upper_bound]]
else:
bounds_check = "pass"
arith = ["seq", bounds_check, ["sdiv", "l", divisor]]
Expand Down

0 comments on commit 2ff7329

Please sign in to comment.