Example #1
0
 def setUp(self) -> None:
     self.env = Environment()
     self.n = self.env.add_local(Var('n'), IntRType())
     self.m = self.env.add_local(Var('m'), IntRType())
     self.k = self.env.add_local(Var('k'), IntRType())
     self.l = self.env.add_local(Var('l'), ListRType())
     self.ll = self.env.add_local(Var('ll'), ListRType())
     self.o = self.env.add_local(Var('o'), ObjectRType())
     self.o2 = self.env.add_local(Var('o2'), ObjectRType())
     self.d = self.env.add_local(Var('d'), DictRType())
     self.b = self.env.add_local(Var('b'), BoolRType())
     self.context = EmitterContext()
     self.emitter = Emitter(self.context, self.env)
     self.declarations = Emitter(self.context, self.env)
     self.visitor = FunctionEmitterVisitor(self.emitter, self.declarations)
Example #2
0
 def binary_op(self,
               ltype: RType,
               lreg: Register,
               rtype: RType,
               rreg: Register,
               expr_op: str,
               target: Optional[Register] = None) -> Register:
     if ltype.name == 'int' and rtype.name == 'int':
         # Primitive int operation
         if target is None:
             target = self.alloc_target(IntRType())
         op = self.int_binary_ops[expr_op]
     elif (ltype.name == 'list' or rtype.name == 'list') and expr_op == '*':
         if rtype.name == 'list':
             ltype, rtype = rtype, ltype
             lreg, rreg = rreg, lreg
         if rtype.name != 'int':
             assert False, 'Unsupported binary operation'  # TODO: Operator overloading
         if target is None:
             target = self.alloc_target(ListRType())
         op = PrimitiveOp.LIST_REPEAT
     elif isinstance(rtype, DictRType):
         if expr_op == 'in':
             if target is None:
                 target = self.alloc_target(BoolRType())
             lreg = self.box(lreg, ltype)
             op = PrimitiveOp.DICT_CONTAINS
         else:
             assert False, 'Unsupported binary operation'
     else:
         assert False, 'Unsupported binary operation'
     self.add(PrimitiveOp(target, op, lreg, rreg))
     return target
Example #3
0
 def type_to_rtype(self, typ: Type) -> RType:
     if isinstance(typ, Instance):
         if typ.type.fullname() == 'builtins.int':
             return IntRType()
         elif typ.type.fullname() == 'builtins.bool':
             return BoolRType()
         elif typ.type.fullname() == 'builtins.list':
             return ListRType()
         elif typ.type.fullname() == 'builtins.dict':
             return DictRType()
         elif typ.type.fullname() == 'builtins.tuple':
             return SequenceTupleRType()
         elif typ.type in self.type_to_ir:
             return UserRType(self.type_to_ir[typ.type])
     elif isinstance(typ, TupleType):
         return TupleRType([self.type_to_rtype(t) for t in typ.items])
     elif isinstance(typ, CallableType):
         return ObjectRType()
     elif isinstance(typ, NoneTyp):
         return NoneRType()
     elif isinstance(typ, UnionType):
         assert len(typ.items) == 2 and any(
             isinstance(it, NoneTyp) for it in typ.items)
         if isinstance(typ.items[0], NoneTyp):
             value_type = typ.items[1]
         else:
             value_type = typ.items[0]
         return OptionalRType(self.type_to_rtype(value_type))
     assert False, '%s unsupported' % type(typ)
Example #4
0
 def test_unbox(self) -> None:
     self.assert_emit(
         Unbox(self.n, self.m, IntRType()), """if (PyLong_Check(cpy_r_m))
                             cpy_r_n = CPyTagged_FromObject(cpy_r_m);
                         else
                             abort();
                      """)
Example #5
0
    def visit_unary_expr(self, expr: UnaryExpr) -> Register:
        if expr.op != '-':
            assert False, 'Unsupported unary operation'

        etype = self.node_type(expr.expr)
        reg = self.accept(expr.expr)
        if etype.name != 'int':
            assert False, 'Unsupported unary operation'

        target = self.alloc_target(IntRType())
        zero = self.accept(IntExpr(0))
        self.add(PrimitiveOp(target, PrimitiveOp.INT_SUB, zero, reg))

        return target
Example #6
0
 def test_simple(self) -> None:
     self.block.ops.append(Return(self.reg))
     fn = FuncIR('myfunc', [self.arg], IntRType(), [self.block], self.env)
     emitter = Emitter(EmitterContext())
     generate_native_function(fn, emitter)
     result = emitter.fragments
     assert_string_arrays_equal([
         'static CPyTagged CPyDef_myfunc(CPyTagged cpy_r_arg) {\n',
         'CPyL0: ;\n',
         '    return cpy_r_arg;\n',
         '}\n',
     ],
                                result,
                                msg='Generated code invalid')
Example #7
0
    def visit_call_expr(self, expr: CallExpr) -> Register:
        if isinstance(expr.callee, MemberExpr):
            is_module_call = self.is_module_member_expr(expr.callee)
            if expr.callee.expr in self.types and not is_module_call:
                target = self.translate_special_method_call(expr.callee, expr)
                if target:
                    return target

            # Either its a module call or translating to a special method call failed, so we have
            # to fallback to a PyCall
            function = self.accept(expr.callee)
            return self.py_call(function, expr.args, self.node_type(expr))

        assert isinstance(expr.callee, NameExpr)
        fn = expr.callee.name  # TODO: fullname
        if fn == 'len' and len(expr.args) == 1 and expr.arg_kinds == [ARG_POS]:
            target = self.alloc_target(IntRType())
            arg = self.accept(expr.args[0])

            expr_rtype = self.node_type(expr.args[0])
            if expr_rtype.name == 'list':
                self.add(PrimitiveOp(target, PrimitiveOp.LIST_LEN, arg))
            elif expr_rtype.name == 'sequence_tuple':
                self.add(
                    PrimitiveOp(target, PrimitiveOp.HOMOGENOUS_TUPLE_LEN, arg))
            elif isinstance(expr_rtype, TupleRType):
                self.add(LoadInt(target, len(expr_rtype.types)))
            else:
                assert False, "unsupported use of len"

        # Handle conversion to sequence tuple
        elif fn == 'tuple' and len(
                expr.args) == 1 and expr.arg_kinds == [ARG_POS]:
            target = self.alloc_target(SequenceTupleRType())
            arg = self.accept(expr.args[0])

            self.add(
                PrimitiveOp(target, PrimitiveOp.LIST_TO_HOMOGENOUS_TUPLE, arg))
        else:
            target_type = self.node_type(expr)
            if not (self.is_native_name_expr(expr.callee)):
                function = self.accept(expr.callee)
                return self.py_call(function, expr.args, target_type)

            target = self.alloc_target(target_type)
            args = [self.accept(arg) for arg in expr.args]
            self.add(Call(target, fn, args))
        return target
Example #8
0
 def test_register(self) -> None:
     self.temp = self.env.add_temp(IntRType())
     self.block.ops.append(LoadInt(self.temp, 5))
     fn = FuncIR('myfunc', [self.arg], ListRType(), [self.block], self.env)
     emitter = Emitter(EmitterContext())
     generate_native_function(fn, emitter)
     result = emitter.fragments
     assert_string_arrays_equal([
         'static 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')
Example #9
0
 def visit_int_expr(self, expr: IntExpr) -> Register:
     reg = self.alloc_target(IntRType())
     self.add(LoadInt(reg, expr.value))
     return reg
Example #10
0
    def visit_for_stmt(self, s: ForStmt) -> Register:
        if (isinstance(s.expr, CallExpr)
                and isinstance(s.expr.callee, RefExpr)
                and s.expr.callee.fullname == 'builtins.range'):
            self.push_loop_stack()

            # Special case for x in range(...)
            # TODO: Check argument counts and kinds; check the lvalue
            end = s.expr.args[0]
            end_reg = self.accept(end)

            # Initialize loop index to 0.
            index_reg = self.assign(s.index,
                                    IntExpr(0),
                                    IntRType(),
                                    IntRType(),
                                    declare_new=True)
            goto = Goto(INVALID_LABEL)
            self.add(goto)

            # Add loop condition check.
            top = self.new_block()
            goto.label = top.label
            branch = Branch(index_reg, end_reg, INVALID_LABEL, INVALID_LABEL,
                            Branch.INT_LT)
            self.add(branch)
            branches = [branch]

            body = self.new_block()
            self.set_branches(branches, True, body)
            s.body.accept(self)

            end_goto = Goto(INVALID_LABEL)
            self.add(end_goto)
            end_block = self.new_block()
            end_goto.label = end_block.label

            # Increment index register.
            one_reg = self.alloc_temp(IntRType())
            self.add(LoadInt(one_reg, 1))
            self.add(
                PrimitiveOp(index_reg, PrimitiveOp.INT_ADD, index_reg,
                            one_reg))

            # Go back to loop condition check.
            self.add(Goto(top.label))
            next = self.new_block()
            self.set_branches(branches, False, next)

            self.pop_loop_stack(end_block, next)
            return INVALID_REGISTER

        if self.node_type(s.expr).name == 'list':
            self.push_loop_stack()

            expr_reg = self.accept(s.expr)

            index_reg = self.alloc_temp(IntRType())
            self.add(LoadInt(index_reg, 0))

            one_reg = self.alloc_temp(IntRType())
            self.add(LoadInt(one_reg, 1))

            assert isinstance(s.index, NameExpr)
            assert isinstance(s.index.node, Var)
            lvalue_reg = self.environment.add_local(s.index.node,
                                                    self.node_type(s.index))

            condition_block = self.goto_new_block()

            # For compatibility with python semantics we recalculate the length
            # at every iteration.
            len_reg = self.alloc_temp(IntRType())
            self.add(PrimitiveOp(len_reg, PrimitiveOp.LIST_LEN, expr_reg))

            branch = Branch(index_reg, len_reg, INVALID_LABEL, INVALID_LABEL,
                            Branch.INT_LT)
            self.add(branch)
            branches = [branch]

            body_block = self.new_block()
            self.set_branches(branches, True, body_block)

            target_list_type = self.types[s.expr]
            assert isinstance(target_list_type, Instance)
            target_type = self.type_to_rtype(target_list_type.args[0])
            value_box = self.alloc_temp(ObjectRType())
            self.add(
                PrimitiveOp(value_box, PrimitiveOp.LIST_GET, expr_reg,
                            index_reg))

            self.unbox_or_cast(value_box, target_type, target=lvalue_reg)

            s.body.accept(self)

            end_block = self.goto_new_block()
            self.add(
                PrimitiveOp(index_reg, PrimitiveOp.INT_ADD, index_reg,
                            one_reg))
            self.add(Goto(condition_block.label))

            next_block = self.new_block()
            self.set_branches(branches, False, next_block)

            self.pop_loop_stack(end_block, next_block)

            return INVALID_REGISTER

        assert False, 'for not supported'
Example #11
0
 def test_dec_ref(self) -> None:
     self.assert_emit(DecRef(self.m, IntRType()),
                      "CPyTagged_DecRef(cpy_r_m);")
Example #12
0
 def setUp(self) -> None:
     self.var = Var('arg')
     self.arg = RuntimeArg('arg', IntRType())
     self.env = Environment()
     self.reg = self.env.add_local(self.var, IntRType())
     self.block = BasicBlock(Label(0))
Example #13
0
 def test_set_attr(self) -> None:
     ir = ClassIR('A', [('x', BoolRType()), ('y', IntRType())])
     rtype = UserRType(ir)
     self.assert_emit(
         SetAttr(self.n, 'y', self.m, rtype),
         """CPY_SET_ATTR(cpy_r_n, 3, cpy_r_m, AObject, CPyTagged);""")
Example #14
0
 def test_get_attr(self) -> None:
     ir = ClassIR('A', [('x', BoolRType()), ('y', IntRType())])
     rtype = UserRType(ir)
     self.assert_emit(
         GetAttr(self.n, self.m, 'y', rtype),
         """cpy_r_n = CPY_GET_ATTR(cpy_r_m, 2, AObject, CPyTagged);""")
Example #15
0
 def test_box(self) -> None:
     self.assert_emit(Box(self.o, self.n, IntRType()),
                      """cpy_r_o = CPyTagged_StealAsObject(cpy_r_n);""")
Example #16
0
 def test_dec_ref_tuple_nested(self) -> None:
     tuple_type = TupleRType(
         [TupleRType([IntRType(), BoolRType()]),
          BoolRType()])
     self.assert_emit(DecRef(self.m, tuple_type),
                      'CPyTagged_DecRef(cpy_r_m.f0.f0);')
Example #17
0
 def setUp(self) -> None:
     self.env = Environment()
     self.n = self.env.add_local(Var('n'), IntRType())
     self.context = EmitterContext()
     self.emitter = Emitter(self.context, self.env)
Example #18
0
 def test_inc_ref(self) -> None:
     self.assert_emit(IncRef(self.m, IntRType()),
                      "CPyTagged_IncRef(cpy_r_m);")