Пример #1
0
    def parse_UnaryOp(self):
        operand = Expr.parse_value_expr(self.expr.operand, self.context)
        if isinstance(self.expr.op, vy_ast.Not):
            if isinstance(operand.typ, BaseType) and operand.typ.typ == "bool":
                return IRnode.from_list(["iszero", operand], typ="bool")

        if isinstance(self.expr.op, vy_ast.Invert):
            if isinstance(operand.typ, EnumType):
                n_members = len(operand.typ.members)
                # use (xor 0b11..1 operand) to flip all the bits in
                # `operand`. `mask` could be a very large constant and
                # hurt codesize, but most user enums will likely have few
                # enough members that the mask will not be large.
                mask = (2**n_members) - 1
                return IRnode.from_list(["xor", mask, operand],
                                        typ=operand.typ)

            if is_base_type(operand.typ, "uint256"):
                return IRnode.from_list(["not", operand], typ=operand.typ)

            # block `~` for all other integer types, since reasoning
            # about dirty bits is not entirely trivial. maybe revisit
            # this at a later date.
            raise UnimplementedException(
                f"~ is not supported for {operand.typ}", self.expr)

        if isinstance(self.expr.op, vy_ast.USub) and is_numeric_type(
                operand.typ):
            assert operand.typ._num_info.is_signed
            # Clamp on minimum signed integer value as we cannot negate that
            # value (all other integer values are fine)
            min_int_val, _ = operand.typ._num_info.bounds
            return IRnode.from_list(
                ["sub", 0, clamp("sgt", operand, min_int_val)],
                typ=operand.typ)
Пример #2
0
def _clamp_numeric_convert(arg, arg_bounds, out_bounds, arg_is_signed):
    arg_lo, arg_hi = arg_bounds
    out_lo, out_hi = out_bounds

    if arg_lo < out_lo:
        # if not arg_is_signed, arg_lo is 0, so this branch cannot be hit
        assert arg_is_signed, "bad assumption in numeric convert"
        arg = clamp("sge", arg, out_lo)

    if arg_hi > out_hi:
        # out_hi must be smaller than MAX_UINT256, so clample makes sense.
        # add an assertion, just in case this assumption ever changes.
        assert out_hi < 2**256 - 1, "bad assumption in numeric convert"
        CLAMP_OP = "sle" if arg_is_signed else "le"
        arg = clamp(CLAMP_OP, arg, out_hi)

    return arg
Пример #3
0
def safe_div(x, y):
    num_info = x.typ._num_info
    typ = x.typ

    ok = [1]  # true

    if is_decimal_type(x.typ):
        lo, hi = num_info.bounds
        if max(abs(lo), abs(hi)) * num_info.divisor > 2**256 - 1:
            # stub to prevent us from adding fixed point numbers we don't know
            # how to deal with
            raise UnimplementedException(
                "safe_mul for decimal{num_info.bits}x{num_info.decimals}")
        x = ["mul", x, num_info.divisor]

    DIV = "sdiv" if num_info.is_signed else "div"
    res = IRnode.from_list([DIV, x, clamp("gt", y, 0)], typ=typ)
    with res.cache_when_complex("res") as (b1, res):

        # TODO: refactor this condition / push some things into the optimizer
        if num_info.is_signed and num_info.bits == 256:
            if version_check(begin="constantinople"):
                upper_bound = ["shl", 255, 1]
            else:
                upper_bound = -(2**255)

            if not x.is_literal and not y.typ.is_literal:
                ok = ["or", ["ne", y, ["not", 0]], ["ne", x, upper_bound]]
            # TODO push these rules into the optimizer
            elif x.is_literal and x.value == -(2**255):
                ok = ["ne", y, ["not", 0]]
            elif y.is_literal and y.value == -1:
                ok = ["ne", x, upper_bound]
            else:
                # x or y is a literal, and not an evil value.
                pass

        elif num_info.is_signed and is_integer_type(typ):
            lo, hi = num_info.bounds
            # we need to throw on min_value(typ) / -1,
            # but we can skip if one of the operands is a literal and not
            # the evil value
            can_skip_clamp = (x.is_literal
                              and x.value != lo) or (y.is_literal
                                                     and y.value != -1)
            if not can_skip_clamp:
                # clamp_basetype has fewer ops than the int256 rule.
                res = clamp_basetype(res)

        elif is_decimal_type(typ):
            # always clamp decimals, since decimal division can actually
            # result in something larger than either operand (e.g. 1.0 / 0.1)
            # TODO maybe use safe_mul
            res = clamp_basetype(res)

        check = IRnode.from_list(["assert", ok], error_msg="safemul")
        return IRnode.from_list(b1.resolve(["seq", check, res]))
Пример #4
0
def _int_to_int(arg, out_typ):
    arg_info = arg.typ._int_info
    out_info = out_typ._int_info

    # do the same thing as
    # _clamp_numeric_convert(arg, arg_info.bounds, out_info.bounds, arg_info.is_signed)
    # but with better code size and gas.
    if arg_info.is_signed and not out_info.is_signed:

        # e.g. (clample (clampge arg 0) (2**128 - 1))

        # note that when out_info.bits == 256,
        # (clample arg 2**256 - 1) does not make sense.
        # see similar assertion in _clamp_numeric_convert.

        if out_info.bits < arg_info.bits:

            assert out_info.bits < 256, "unreachable"
            # note: because of the usage of signed=False, and the fact
            # that out_bits < 256 in this branch, below implies
            # not only (clample arg 2**128 - 1) but also (clampge arg 0).
            arg = int_clamp(arg, out_info.bits, signed=False)

        else:
            # note: this also works for out_bits == 256.
            arg = clamp("sge", arg, 0)

    elif not arg_info.is_signed and out_info.is_signed:
        # e.g. (uclample (uclampge arg 0) (2**127 - 1))
        # (note that (uclampge arg 0) always evaluates to true.)
        arg = int_clamp(arg, out_info.bits - 1, signed=False)

    elif out_info.bits < arg_info.bits:
        assert out_info.bits < 256, "unreachable"
        # narrowing conversion, signs are the same.
        # we can just use regular int clampers.
        arg = int_clamp(arg, out_info.bits, out_info.is_signed)

    else:
        # widening conversion, signs are the same.
        # we do not have to do any clamps.
        assert arg_info.is_signed == out_info.is_signed and out_info.bits >= arg_info.bits

    return IRnode.from_list(arg, typ=out_typ)
Пример #5
0
def safe_mod(x, y):
    num_info = x.typ._num_info
    MOD = "smod" if num_info.is_signed else "mod"
    return IRnode.from_list([MOD, x, clamp("gt", y, 0)])