Esempio n. 1
0
def to_address(expr, arg, out_typ):
    # question: should this be allowed?
    if is_integer_type(arg.typ):
        if arg.typ._int_info.is_signed:
            _FAIL(arg.typ, out_typ, expr)

    # TODO once we introduce uint160, we can just check that arg
    # is unsigned, and then call to_int(expr, arg, uint160) because
    # the logic is equivalent.

    # disallow casting from Bytes[N>20]
    _check_bytes(expr, arg, out_typ, 32)

    if isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=False)
        # clamp after shift
        if arg_typ.maxlen > 20:
            arg = int_clamp(arg, 160, signed=False)

    if is_bytes_m_type(arg.typ):
        info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=False)

        # clamp after shift
        if info.m > 20:
            arg = int_clamp(arg, 160, signed=False)

    elif is_integer_type(arg.typ):
        arg_info = arg.typ._int_info
        if arg_info.bits > 160 or arg_info.is_signed:
            arg = int_clamp(arg, 160, signed=False)

    return IRnode.from_list(arg, typ=out_typ)
Esempio n. 2
0
def clamp_basetype(ir_node):
    t = ir_node.typ
    if not isinstance(t, BaseType):
        raise CompilerPanic(f"{t} passed to clamp_basetype")  # pragma: notest

    # copy of the input
    ir_node = unwrap_location(ir_node)

    if isinstance(t, EnumType):
        bits = len(t.members)
        # assert x >> bits == 0
        ret = int_clamp(ir_node, bits, signed=False)

    elif is_integer_type(t) or is_decimal_type(t):
        if t._num_info.bits == 256:
            ret = ir_node
        else:
            ret = int_clamp(ir_node,
                            t._num_info.bits,
                            signed=t._num_info.is_signed)

    elif is_bytes_m_type(t):
        if t._bytes_info.m == 32:
            ret = ir_node  # special case, no clamp.
        else:
            ret = bytes_clamp(ir_node, t._bytes_info.m)

    elif t.typ in ("address", ):
        ret = int_clamp(ir_node, 160)
    elif t.typ in ("bool", ):
        ret = int_clamp(ir_node, 1)
    else:  # pragma: nocover
        raise CompilerPanic(f"{t} passed to clamp_basetype")

    return IRnode.from_list(ret, typ=ir_node.typ)
Esempio n. 3
0
def safe_pow(x, y):
    num_info = x.typ._num_info
    if not is_integer_type(x.typ):
        # type checker should have caught this
        raise TypeCheckFailure("non-integer pow")

    if x.is_literal:
        # cannot pass 1 or 0 to `calculate_largest_power`
        if x.value == 1:
            return IRnode.from_list([1])
        if x.value == 0:
            return IRnode.from_list(["iszero", y])

        upper_bound = calculate_largest_power(x.value, num_info.bits,
                                              num_info.is_signed) + 1
        # for signed integers, this also prevents negative values
        ok = ["lt", y, upper_bound]

    elif y.is_literal:
        upper_bound = calculate_largest_base(y.value, num_info.bits,
                                             num_info.is_signed) + 1
        if num_info.is_signed:
            ok = ["and", ["slt", x, upper_bound], ["sgt", x, -upper_bound]]
        else:
            ok = ["lt", x, upper_bound]
    else:
        # `a ** b` where neither `a` or `b` are known
        # TODO this is currently unreachable, once we implement a way to do it safely
        # remove the check in `vyper/context/types/value/numeric.py`
        return

    return IRnode.from_list(["seq", ["assert", ok], ["exp", x, y]])
Esempio n. 4
0
def to_address(expr, arg, out_typ):
    # question: should this be allowed?
    if is_integer_type(arg.typ):
        if arg.typ._int_info.is_signed:
            _FAIL(arg.typ, out_typ, expr)

    return to_int(expr, arg, out_typ)
Esempio n. 5
0
def convert(expr, context):
    if len(expr.args) != 2:
        raise StructureException(
            "The convert function expects two parameters.", expr)

    arg_ast = expr.args[0]
    arg = Expr(arg_ast, context).ir_node
    out_typ = context.parse_type(expr.args[1])

    if isinstance(arg.typ, BaseType):
        arg = unwrap_location(arg)
    with arg.cache_when_complex("arg") as (b, arg):
        if is_base_type(out_typ, "bool"):
            ret = to_bool(arg_ast, arg, out_typ)
        elif is_base_type(out_typ, "address"):
            ret = to_address(arg_ast, arg, out_typ)
        elif is_integer_type(out_typ):
            ret = to_int(arg_ast, arg, out_typ)
        elif is_bytes_m_type(out_typ):
            ret = to_bytes_m(arg_ast, arg, out_typ)
        elif is_decimal_type(out_typ):
            ret = to_decimal(arg_ast, arg, out_typ)
        elif isinstance(out_typ, ByteArrayType):
            ret = to_bytes(arg_ast, arg, out_typ)
        elif isinstance(out_typ, StringType):
            ret = to_string(arg_ast, arg, out_typ)
        else:
            raise StructureException(f"Conversion to {out_typ} is invalid.",
                                     arg_ast)

        ret = b.resolve(ret)

    return IRnode.from_list(ret)
Esempio n. 6
0
def to_int(expr, arg, out_typ):
    int_info = out_typ._int_info

    assert int_info.bits % 8 == 0
    _check_bytes(expr, arg, out_typ, 32)

    if isinstance(expr, vy_ast.Constant):
        return _literal_int(expr, arg.typ, out_typ)

    elif isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=int_info.is_signed)
        if arg_typ.maxlen * 8 > int_info.bits:
            arg = int_clamp(arg, int_info.bits, signed=int_info.is_signed)

    elif is_bytes_m_type(arg.typ):
        arg_info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=int_info.is_signed)
        if arg_info.m_bits > int_info.bits:
            arg = int_clamp(arg, int_info.bits, signed=int_info.is_signed)

    elif is_decimal_type(arg.typ):
        arg = _fixed_to_int(arg, out_typ)

    elif is_integer_type(arg.typ):
        arg = _int_to_int(arg, out_typ)

    elif is_base_type(arg.typ, "address"):
        if int_info.is_signed:
            # TODO if possible, refactor to move this validation close to the entry of the function
            _FAIL(arg.typ, out_typ, expr)
        if int_info.bits < 160:
            arg = int_clamp(arg, int_info.bits, signed=False)

    return IRnode.from_list(arg, typ=out_typ)
Esempio n. 7
0
def clamp_basetype(ir_node):
    t = ir_node.typ
    if not isinstance(t, BaseType):
        raise CompilerPanic(f"{t} passed to clamp_basetype")  # pragma: notest

    # copy of the input
    ir_node = unwrap_location(ir_node)

    if is_integer_type(t) or is_decimal_type(t):
        if t._num_info.bits == 256:
            return ir_node
        else:
            return int_clamp(ir_node,
                             t._num_info.bits,
                             signed=t._num_info.is_signed)

    if is_bytes_m_type(t):
        if t._bytes_info.m == 32:
            return ir_node  # special case, no clamp.
        else:
            return bytes_clamp(ir_node, t._bytes_info.m)

    if t.typ in ("address", ):
        return int_clamp(ir_node, 160)
    if t.typ in ("bool", ):
        return int_clamp(ir_node, 1)

    raise CompilerPanic(f"{t} passed to clamp_basetype")  # pragma: notest
Esempio n. 8
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]))
Esempio n. 9
0
def _type_class_of(typ):
    if is_integer_type(typ):
        return "int"
    if is_bytes_m_type(typ):
        return "bytes_m"
    if is_decimal_type(typ):
        return "decimal"
    if isinstance(typ, BaseType):
        return typ.typ  # e.g., "bool"
    if isinstance(typ, ByteArrayType):
        return "bytes"
    if isinstance(typ, StringType):
        return "string"
Esempio n. 10
0
def to_decimal(expr, arg, out_typ):
    # question: is converting from Bytes to decimal allowed?
    _check_bytes(expr, arg, out_typ, max_bytes_allowed=16)

    if isinstance(expr, vy_ast.Constant):
        return _literal_decimal(expr, out_typ)

    if isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=True)
        # TODO revisit this condition once we have more decimal types
        # and decimal bounds expand
        # will be something like: if info.m_bits > 168
        if arg_typ.maxlen * 8 > 128:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_bytes_m_type(arg.typ):
        info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=True)
        # TODO revisit this condition once we have more decimal types
        # and decimal bounds expand
        # will be something like: if info.m_bits > 168
        if info.m_bits > 128:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_integer_type(arg.typ):
        int_info = arg.typ._int_info
        arg = _int_to_fixed(arg, out_typ)
        out_info = out_typ._decimal_info
        if int_info.bits > out_info.bits:
            # TODO: _num_clamp probably not necessary bc already
            # clamped in _int_to_fixed
            arg = _num_clamp(arg, out_info, int_info)
        return IRnode.from_list(arg, typ=out_typ)

    elif is_base_type(arg.typ, "bool"):
        arg = _int_to_fixed(arg, out_typ)
        return IRnode.from_list(arg, typ=out_typ)
    else:
        raise CompilerPanic("unreachable")  # pragma: notest
Esempio n. 11
0
def to_bytes_m(expr, arg, out_typ):
    out_info = out_typ._bytes_info

    _check_bytes(expr, arg, out_typ, max_bytes_allowed=out_info.m)

    if isinstance(arg.typ, ByteArrayType):
        bytes_val = LOAD(bytes_data_ptr(arg))

        # zero out any dirty bytes (which can happen in the last
        # word of a bytearray)
        len_ = get_bytearray_length(arg)
        num_zero_bits = IRnode.from_list(["mul", ["sub", 32, len_], 8])
        with num_zero_bits.cache_when_complex("bits") as (b, num_zero_bits):
            arg = shl(num_zero_bits, shr(num_zero_bits, bytes_val))
            arg = b.resolve(arg)

    elif is_bytes_m_type(arg.typ):
        arg_info = arg.typ._bytes_info
        # clamp if it's a downcast
        if arg_info.m > out_info.m:
            arg = bytes_clamp(arg, out_info.m)

    elif is_integer_type(arg.typ) or is_base_type(arg.typ, "address"):
        int_bits = arg.typ._int_info.bits

        if out_info.m_bits < int_bits:
            # question: allow with runtime clamp?
            # arg = int_clamp(m_bits, signed=int_info.signed)
            _FAIL(arg.typ, out_typ, expr)

        # note: neg numbers not OOB. keep sign bit
        arg = shl(256 - out_info.m_bits, arg)

    elif is_decimal_type(arg.typ):
        if out_info.m_bits < arg.typ._decimal_info.bits:
            _FAIL(arg.typ, out_typ, expr)

        # note: neg numbers not OOB. keep sign bit
        arg = shl(256 - out_info.m_bits, arg)

    else:
        # bool
        arg = shl(256 - out_info.m_bits, arg)

    return IRnode.from_list(arg, typ=out_typ)
Esempio n. 12
0
def convert(expr, context):
    if len(expr.args) != 2:
        raise StructureException(
            "The convert function expects two parameters.", expr)

    arg_ast = expr.args[0]
    arg = Expr(arg_ast, context).ir_node
    original_arg = arg
    out_typ = context.parse_type(expr.args[1])

    if isinstance(arg.typ, BaseType):
        arg = unwrap_location(arg)
    with arg.cache_when_complex("arg") as (b, arg):
        if is_base_type(out_typ, "bool"):
            ret = to_bool(arg_ast, arg, out_typ)
        elif is_base_type(out_typ, "address"):
            ret = to_address(arg_ast, arg, out_typ)
        elif isinstance(out_typ, EnumType):
            ret = to_enum(arg_ast, arg, out_typ)
        elif is_integer_type(out_typ):
            ret = to_int(arg_ast, arg, out_typ)
        elif is_bytes_m_type(out_typ):
            ret = to_bytes_m(arg_ast, arg, out_typ)
        elif is_decimal_type(out_typ):
            ret = to_decimal(arg_ast, arg, out_typ)
        elif isinstance(out_typ, ByteArrayType):
            ret = to_bytes(arg_ast, arg, out_typ)
        elif isinstance(out_typ, StringType):
            ret = to_string(arg_ast, arg, out_typ)
        else:
            raise StructureException(f"Conversion to {out_typ} is invalid.",
                                     arg_ast)

        # test if arg actually changed. if not, we do not need to use
        # unwrap_location (this can reduce memory traffic for downstream
        # operations which are in-place, like the returndata routine)
        test_arg = IRnode.from_list(arg, typ=out_typ)
        if test_arg == ret:
            original_arg.typ = out_typ
            return original_arg

        return IRnode.from_list(b.resolve(ret))
Esempio n. 13
0
def to_decimal(expr, arg, out_typ):
    _check_bytes(expr, arg, out_typ, 32)

    out_info = out_typ._decimal_info

    if isinstance(expr, vy_ast.Constant):
        return _literal_decimal(expr, arg.typ, out_typ)

    if isinstance(arg.typ, ByteArrayType):
        arg_typ = arg.typ
        arg = _bytes_to_num(arg, out_typ, signed=True)
        if arg_typ.maxlen * 8 > 168:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_bytes_m_type(arg.typ):
        info = arg.typ._bytes_info
        arg = _bytes_to_num(arg, out_typ, signed=True)
        if info.m_bits > 168:
            arg = IRnode.from_list(arg, typ=out_typ)
            arg = clamp_basetype(arg)

        return IRnode.from_list(arg, typ=out_typ)

    elif is_integer_type(arg.typ):
        arg = _int_to_fixed(arg, out_typ)
        return IRnode.from_list(arg, typ=out_typ)

    elif is_base_type(arg.typ, "bool"):
        # TODO: consider adding _int_info to bool so we can use _int_to_fixed
        arg = ["mul", arg, 10**out_info.decimals]
        return IRnode.from_list(arg, typ=out_typ)
    else:
        raise CompilerPanic("unreachable")  # pragma: notest
Esempio n. 14
0
def _get_element_ptr_array(parent, key, array_bounds_check):

    assert isinstance(parent.typ, ArrayLike)

    if not is_integer_type(key.typ):
        raise TypeCheckFailure(f"{key.typ} used as array index")

    subtype = parent.typ.subtype

    if parent.value == "~empty":
        if array_bounds_check:
            # this case was previously missing a bounds check. codegen
            # is a bit complicated when bounds check is required, so
            # block it. there is no reason to index into a literal empty
            # array anyways!
            raise TypeCheckFailure("indexing into zero array not allowed")
        return IRnode.from_list("~empty", subtype)

    if parent.value == "multi":
        assert isinstance(key.value, int)
        return parent.args[key.value]

    ix = unwrap_location(key)

    if array_bounds_check:
        is_darray = isinstance(parent.typ, DArrayType)
        bound = get_dyn_array_count(parent) if is_darray else parent.typ.count
        # uclamplt works, even for signed ints. since two's-complement
        # is used, if the index is negative, (unsigned) LT will interpret
        # it as a very large number, larger than any practical value for
        # an array index, and the clamp will throw an error.
        # NOTE: there are optimization rules for this when ix or bound is literal
        ix = clamp("lt", ix, bound)

    if parent.encoding == Encoding.ABI:
        if parent.location == STORAGE:
            raise CompilerPanic("storage variables should not be abi encoded"
                                )  # pragma: notest

        member_abi_t = subtype.abi_type

        ofst = _mul(ix, member_abi_t.embedded_static_size())

        return _getelemptr_abi_helper(parent, subtype, ofst)

    if parent.location.word_addressable:
        element_size = subtype.storage_size_in_words
    elif parent.location.byte_addressable:
        element_size = subtype.memory_bytes_required
    else:
        raise CompilerPanic("unreachable")  # pragma: notest

    ofst = _mul(ix, element_size)

    if has_length_word(parent.typ):
        data_ptr = add_ofst(
            parent, parent.location.word_scale * DYNAMIC_ARRAY_OVERHEAD)
    else:
        data_ptr = parent

    return IRnode.from_list(add_ofst(data_ptr, ofst),
                            typ=subtype,
                            location=parent.location)