Ejemplo n.º 1
0
 def assign_if_null(self, target: AssignmentTargetRegister,
                    get_val: Callable[[], Value], line: int) -> None:
     """Generate blocks for registers that NULL values."""
     error_block, body_block = BasicBlock(), BasicBlock()
     self.add(
         Branch(target.register, error_block, body_block, Branch.IS_ERROR))
     self.activate_block(error_block)
     self.add(
         Assign(target.register,
                self.coerce(get_val(), target.register.type, line)))
     self.goto(body_block)
     self.activate_block(body_block)
Ejemplo n.º 2
0
 def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value:
     """Compare two tagged integers using given op"""
     # generate fast binary logic ops on short ints
     if is_short_int_rprimitive(lhs.type) and is_short_int_rprimitive(rhs.type):
         return self.binary_int_op(bool_rprimitive, lhs, rhs,
                                   int_logical_op_mapping[op][0], line)
     op_type, c_func_desc, negate_result, swap_op = int_logical_op_mapping[op]
     result = self.alloc_temp(bool_rprimitive)
     short_int_block, int_block, out = BasicBlock(), BasicBlock(), BasicBlock()
     check_lhs = self.check_tagged_short_int(lhs, line)
     if op in ("==", "!="):
         check = check_lhs
     else:
         # for non-equal logical ops(less than, greater than, etc.), need to check both side
         check_rhs = self.check_tagged_short_int(rhs, line)
         check = self.binary_int_op(bool_rprimitive, check_lhs,
                                    check_rhs, BinaryIntOp.AND, line)
     branch = Branch(check, short_int_block, int_block, Branch.BOOL_EXPR)
     branch.negated = False
     self.add(branch)
     self.activate_block(short_int_block)
     eq = self.binary_int_op(bool_rprimitive, lhs, rhs, op_type, line)
     self.add(Assign(result, eq, line))
     self.goto(out)
     self.activate_block(int_block)
     if swap_op:
         args = [rhs, lhs]
     else:
         args = [lhs, rhs]
     call = self.call_c(c_func_desc, args, line)
     if negate_result:
         # TODO: introduce UnaryIntOp?
         call_result = self.unary_op(call, "not", line)
     else:
         call_result = call
     self.add(Assign(result, call_result, line))
     self.goto_and_activate(out)
     return result
Ejemplo n.º 3
0
def transform_conditional_expr(builder: IRBuilder, expr: ConditionalExpr) -> Value:
    if_body, else_body, next_block = BasicBlock(), BasicBlock(), BasicBlock()

    builder.process_conditional(expr.cond, if_body, else_body)
    expr_type = builder.node_type(expr)
    # Having actual Phi nodes would be really nice here!
    target = Register(expr_type)

    builder.activate_block(if_body)
    true_value = builder.accept(expr.if_expr)
    true_value = builder.coerce(true_value, expr_type, expr.line)
    builder.add(Assign(target, true_value))
    builder.goto(next_block)

    builder.activate_block(else_body)
    false_value = builder.accept(expr.else_expr)
    false_value = builder.coerce(false_value, expr_type, expr.line)
    builder.add(Assign(target, false_value))
    builder.goto(next_block)

    builder.activate_block(next_block)

    return target
Ejemplo n.º 4
0
def try_finally_entry_blocks(builder: IRBuilder,
                             err_handler: BasicBlock,
                             return_entry: BasicBlock,
                             main_entry: BasicBlock,
                             finally_block: BasicBlock,
                             ret_reg: Optional[Register]) -> Value:
    old_exc = Register(exc_rtuple)

    # Entry block for non-exceptional flow
    builder.activate_block(main_entry)
    if ret_reg:
        builder.add(
            Assign(
                ret_reg,
                builder.add(LoadErrorValue(builder.ret_types[-1]))
            )
        )
    builder.goto(return_entry)

    builder.activate_block(return_entry)
    builder.add(Assign(old_exc, builder.add(LoadErrorValue(exc_rtuple))))
    builder.goto(finally_block)

    # Entry block for errors
    builder.activate_block(err_handler)
    if ret_reg:
        builder.add(
            Assign(
                ret_reg,
                builder.add(LoadErrorValue(builder.ret_types[-1]))
            )
        )
    builder.add(Assign(old_exc, builder.call_c(error_catch_op, [], -1)))
    builder.goto(finally_block)

    return old_exc
Ejemplo n.º 5
0
 def test_invalid_assign(self) -> None:
     arg_reg = Register(type=int64_rprimitive, name="r1")
     assign = Assign(dest=arg_reg,
                     src=Integer(value=5, rtype=int32_rprimitive))
     ret = Return(value=NONE_VALUE)
     fn = FuncIR(
         decl=self.func_decl(name="func_1"),
         arg_regs=[arg_reg],
         blocks=[self.basic_block([assign, ret])],
     )
     assert_has_error(
         fn,
         FnError(source=assign,
                 desc="Cannot coerce source type int32 to dest type int64"),
     )
Ejemplo n.º 6
0
def transform_del_item(builder: IRBuilder, target: AssignmentTarget,
                       line: int) -> None:
    if isinstance(target, AssignmentTargetIndex):
        builder.gen_method_call(target.base,
                                '__delitem__', [target.index],
                                result_type=None,
                                line=line)
    elif isinstance(target, AssignmentTargetAttr):
        key = builder.load_static_unicode(target.attr)
        builder.call_c(py_delattr_op, [target.obj, key], line)
    elif isinstance(target, AssignmentTargetRegister):
        # Delete a local by assigning an error value to it, which will
        # prompt the insertion of uninit checks.
        builder.add(
            Assign(target.register,
                   builder.add(LoadErrorValue(target.type, undefines=True))))
    elif isinstance(target, AssignmentTargetTuple):
        for subtarget in target.items:
            transform_del_item(builder, subtarget, line)
Ejemplo n.º 7
0
 def test_register(self) -> None:
     reg = Register(int_rprimitive)
     op = Assign(reg, Integer(5))
     self.block.ops.append(op)
     fn = FuncIR(
         FuncDecl('myfunc', None, 'mod',
                  FuncSignature([self.arg], list_rprimitive)), [self.reg],
         [self.block])
     value_names = generate_names_for_ir(fn.arg_regs, fn.blocks)
     emitter = Emitter(EmitterContext(NameGenerator([['mod']])),
                       value_names)
     generate_native_function(fn, emitter, 'prog.py', 'prog')
     result = emitter.fragments
     assert_string_arrays_equal([
         'PyObject *CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
         '    CPyTagged cpy_r_r0;\n',
         'CPyL0: ;\n',
         '    cpy_r_r0 = 10;\n',
         '}\n',
     ],
                                result,
                                msg='Generated code invalid')
Ejemplo n.º 8
0
 def visit_assign(self, op: Assign) -> GenAndKill:
     return set(op.sources()), {op.dest}
Ejemplo n.º 9
0
 def test_assign_int(self) -> None:
     self.assert_emit(Assign(self.m, self.n), "cpy_r_m = cpy_r_n;")
Ejemplo n.º 10
0
 def test_integer(self) -> None:
     self.assert_emit(Assign(self.n, Integer(5)), "cpy_r_n = 10;")
     self.assert_emit(Assign(self.i32, Integer(5, c_int_rprimitive)),
                      "cpy_r_i32 = 5;")
Ejemplo n.º 11
0
 def test_long_signed(self) -> None:
     a = Register(int64_rprimitive, 'a')
     self.assert_emit(Assign(a, Integer(-(1 << 31) + 1, int64_rprimitive)),
                      """cpy_r_a = -2147483647;""")
     self.assert_emit(Assign(a, Integer(-(1 << 31), int64_rprimitive)),
                      """cpy_r_a = -2147483648LL;""")
Ejemplo n.º 12
0
 def test_long_unsigned(self) -> None:
     a = Register(int64_rprimitive, 'a')
     self.assert_emit(Assign(a, Integer(1 << 31, int64_rprimitive)),
                      """cpy_r_a = 2147483648U;""")
     self.assert_emit(Assign(a, Integer((1 << 31) - 1, int64_rprimitive)),
                      """cpy_r_a = 2147483647;""")
Ejemplo n.º 13
0
    def gen_return(self, builder: 'IRBuilder', value: Value, line: int) -> None:
        if self.ret_reg is None:
            self.ret_reg = Register(builder.ret_types[-1])

        builder.add(Assign(self.ret_reg, value))
        builder.add(Goto(self.target))
Ejemplo n.º 14
0
def split_blocks_at_uninits(
        blocks: List[BasicBlock],
        pre_must_defined: 'AnalysisDict[Value]') -> List[BasicBlock]:
    new_blocks = []  # type: List[BasicBlock]

    init_registers = []
    init_registers_set = set()

    # First split blocks on ops that may raise.
    for block in blocks:
        ops = block.ops
        block.ops = []
        cur_block = block
        new_blocks.append(cur_block)

        for i, op in enumerate(ops):
            defined = pre_must_defined[block, i]
            for src in op.unique_sources():
                # If a register operand is not guaranteed to be
                # initialized is an operand to something other than a
                # check that it is defined, insert a check.

                # Note that for register operand in a LoadAddress op,
                # we should be able to use it without initialization
                # as we may need to use its address to update itself
                if (isinstance(src, Register) and src not in defined
                        and not (isinstance(op, Branch)
                                 and op.op == Branch.IS_ERROR)
                        and not isinstance(op, LoadAddress)):
                    new_block, error_block = BasicBlock(), BasicBlock()
                    new_block.error_handler = error_block.error_handler = cur_block.error_handler
                    new_blocks += [error_block, new_block]

                    if src not in init_registers_set:
                        init_registers.append(src)
                        init_registers_set.add(src)

                    cur_block.ops.append(
                        Branch(src,
                               true_label=error_block,
                               false_label=new_block,
                               op=Branch.IS_ERROR,
                               line=op.line))
                    raise_std = RaiseStandardError(
                        RaiseStandardError.UNBOUND_LOCAL_ERROR,
                        'local variable "{}" referenced before assignment'.
                        format(src.name), op.line)
                    error_block.ops.append(raise_std)
                    error_block.ops.append(Unreachable())
                    cur_block = new_block
            cur_block.ops.append(op)

    if init_registers:
        new_ops = []  # type: List[Op]
        for reg in init_registers:
            err = LoadErrorValue(reg.type, undefines=True)
            new_ops.append(err)
            new_ops.append(Assign(reg, err))
        new_blocks[0].ops[0:0] = new_ops

    return new_blocks