예제 #1
0
def make_branch_func_object() -> Tuple[Function, Tuple[BasicBlock, ...]]:
    bb0 = BasicBlock("bb0")
    bb1 = BasicBlock("bb1")
    bb2 = BasicBlock("bb2")
    bb3 = BasicBlock("bb3")
    bb0.add_inst(bytecode.CopyInst(Var('v0'), NumLit(SNum(42))))
    bb0.add_inst(bytecode.BrInst(Var('x'), bb1))
    bb0.add_inst(bytecode.JmpInst(bb2))
    bb1.add_inst(
        bytecode.BinopInst(Var('v0'), Binop.ADD, Var('v0'), NumLit(SNum(27))))
    bb1.add_inst(bytecode.JmpInst(bb3))
    bb2.add_inst(bytecode.CopyInst(Var('v0'), SymLit(SSym('hi'))))
    bb2.add_inst(bytecode.JmpInst(bb3))
    bb3.add_inst(bytecode.ReturnInst(Var('v0')))
    return Function([Var('x')], bb0), (bb0, bb1, bb2, bb3)
예제 #2
0
def make_func() -> Function:
    bb0 = BasicBlock("bb0")
    bb1 = BasicBlock("bb1")
    bb0.add_inst(bytecode.CopyInst(Var('v0'), NumLit(SNum(42))))
    bb0.add_inst(
        bytecode.BinopInst(Var('v1'), Binop.ADD, Var('v0'), NumLit(SNum(69))))
    bb0.add_inst(bytecode.JmpInst(bb1))
    bb1.add_inst(bytecode.ReturnInst(Var('v1')))
    return Function([], bb0)
예제 #3
0
    def visit_SCall(self, call: sexp.SCall) -> None:
        assert not self.quoted, 'Non-primitives in quoted list unsupported'

        if self._is_true_assertion(call):
            self.result = bytecode.NumLit(sexp.SNum(0))
            return

        tail_call_data = self._get_tail_call_data(call)
        is_known_function = self._is_known_function(call)
        arity_known_correct = self._arity_known_correct(
            call, is_known_function, tail_call_data)
        tail_call_args_compatible = self._tail_call_args_compatible(
            call, tail_call_data)

        func_to_call = self._get_func_to_call(
            call, is_known_function,
            arity_known_correct, tail_call_data, tail_call_args_compatible)

        args = self._emit_args(call)

        if tail_call_data is not None and func_to_call is None:
            for arg, param in zip(args, tail_call_data.func_params):
                local_var = self.local_env[param]
                if arg != local_var:
                    self.end_block.add_inst(bytecode.CopyInst(local_var, arg))

            assert self._function_entrypoint is not None
            self.end_block.add_inst(
                bytecode.JmpInst(self._function_entrypoint))

            # We need a placeholder result since we're jumping back
            # to the beginning of the function
            self.result = bytecode.NumLit(sexp.SNum(0))
        else:
            assert func_to_call is not None
            call_result_var = bytecode.Var(next(self.var_names))
            call_instr = bytecode.CallInst(
                call_result_var, func_to_call, args,
                specialization=self._get_arg_types(call))

            self.end_block.add_inst(call_instr)
            self.result = call_result_var
예제 #4
0
    def test_example_tail_call(self) -> None:
        """
        function list? (v0) entry=bb0
        bb0:
            v1 = lookup 'nil?
            v2 = call v1 (v0)
            br v2 bb1
            v3 = lookup 'pair?
            v4 = call v3 (v0)
            brn v4 bb2
            v5 = lookup 'cdr
            v0 = call v5 (v0)
            jmp bb0

        bb1:
            return 'true

        bb2:
            return 'false
        """
        bb0 = bytecode.BasicBlock("bb0")
        bb1 = bytecode.BasicBlock("bb1")
        bb2 = bytecode.BasicBlock("bb2")
        is_list = bytecode.Function([Var("v0")], bb0)

        bb0.add_inst(bytecode.LookupInst(Var("v1"), SymLit(SSym("nil?"))))
        bb0.add_inst(bytecode.CallInst(Var("v2"), Var("v1"), [Var("v0")]))
        bb0.add_inst(bytecode.BrInst(Var("v2"), bb1))
        bb0.add_inst(bytecode.LookupInst(Var("v3"), SymLit(SSym("pair?"))))
        bb0.add_inst(bytecode.CallInst(Var("v4"), Var("v3"), [Var("v0")]))
        bb0.add_inst(bytecode.BrnInst(Var("v4"), bb2))
        bb0.add_inst(bytecode.LookupInst(Var("v5"), SymLit(SSym("global"))))
        bb0.add_inst(bytecode.CallInst(Var("v0"), Var("v5"), [Var("v0")]))
        bb0.add_inst(bytecode.JmpInst(bb0))

        bb1.add_inst(bytecode.ReturnInst(SymLit(SSym("true"))))

        bb2.add_inst(bytecode.ReturnInst(SymLit(SSym("false"))))

        assert is_list
예제 #5
0
    def visit_SConditional(self, conditional: sexp.SConditional) -> None:
        assert not self.quoted, 'Non-primitives in quoted list unsupported'

        if (self._expr_types is not None
                and self._expr_types.expr_value_known(conditional.test)):
            test_val = self._expr_types.get_expr_value(conditional.test)
            assert isinstance(test_val, sexp.SBool)
            branch_to_emit = (conditional.then_expr if test_val.value
                              else conditional.else_expr)

            emitter = ExpressionEmitter(
                self.parent_block, self.bb_names, self.var_names,
                self.local_env, self.global_env,
                function_entrypoint=self._function_entrypoint,
                tail_calls=self._tail_calls,
                expr_types=self._expr_types)
            emitter.visit(branch_to_emit)

            self.result = emitter.result
            self.end_block = emitter.end_block
            return

        test_emitter = ExpressionEmitter(
            self.parent_block, self.bb_names, self.var_names,
            self.local_env, self.global_env,
            function_entrypoint=self._function_entrypoint,
            tail_calls=self._tail_calls,
            expr_types=self._expr_types)
        test_emitter.visit(conditional.test)

        then_block = bytecode.BasicBlock(next(self.bb_names))
        else_block = bytecode.BasicBlock(next(self.bb_names))

        result_var = bytecode.Var(next(self.var_names))

        then_br_instr = bytecode.BrInst(test_emitter.result, then_block)
        else_br_instr = bytecode.JmpInst(else_block)

        test_emitter.end_block.add_inst(then_br_instr)
        test_emitter.end_block.add_inst(else_br_instr)

        then_emitter = ExpressionEmitter(
            then_block, self.bb_names, self.var_names,
            self.local_env, self.global_env,
            function_entrypoint=self._function_entrypoint,
            tail_calls=self._tail_calls,
            expr_types=self._expr_types)
        then_emitter.visit(conditional.then_expr)

        then_result_instr = bytecode.CopyInst(result_var, then_emitter.result)
        then_emitter.end_block.add_inst(then_result_instr)

        else_emitter = ExpressionEmitter(
            else_block, self.bb_names, self.var_names,
            self.local_env, self.global_env,
            function_entrypoint=self._function_entrypoint,
            tail_calls=self._tail_calls,
            expr_types=self._expr_types)
        else_emitter.visit(conditional.else_expr)

        else_result_instr = bytecode.CopyInst(result_var, else_emitter.result)
        else_emitter.end_block.add_inst(else_result_instr)

        new_end_block = bytecode.BasicBlock(next(self.bb_names))
        then_emitter.end_block.add_inst(bytecode.JmpInst(new_end_block))
        else_emitter.end_block.add_inst(bytecode.JmpInst(new_end_block))
        self.end_block = new_end_block

        self.result = result_var
예제 #6
0
    def test_example_inlined(self) -> None:
        """
        function list? (v0) entry=bb0
        bb0:
            v1 = typeof v0
            v2 = sym_eq v1 'vector
            brn v2 false
            v3 = length v0
            v4 = num_eq v3 0
            br v4 true
            v5 = num_eq v3 2
            brn v5 false
            v0 = load v0 [1]
            jmp bb0

        true:
            return 'true

        false:
            return 'false
        """
        bb0 = bytecode.BasicBlock("bb0")
        true = bytecode.BasicBlock("true")
        false = bytecode.BasicBlock("false")
        is_list = bytecode.Function([Var("v0")], bb0)

        # These tests are just to test the API
        bb0.add_inst(bytecode.TypeofInst(Var("v1"), Var("v0")))
        bb0.add_inst(
            bytecode.BinopInst(Var("v2"), Binop.SYM_EQ, Var("v1"),
                               SymLit(SSym("vector"))))
        bb0.add_inst(bytecode.BrnInst(Var("v2"), false))
        bb0.add_inst(bytecode.LengthInst(Var("v3"), Var("v0")))
        bb0.add_inst(
            bytecode.BinopInst(Var("v4"), Binop.NUM_EQ, Var("v3"),
                               NumLit(SNum(0))))
        bb0.add_inst(bytecode.BrInst(Var("v4"), true))

        bb0.add_inst(
            bytecode.BinopInst(Var("v5"), Binop.NUM_EQ, Var("v3"),
                               NumLit(SNum(2))))
        bb0.add_inst(bytecode.BrnInst(Var("v5"), false))
        bb0.add_inst(bytecode.LoadInst(Var("v0"), Var("v0"), NumLit(SNum(1))))
        bb0.add_inst(bytecode.JmpInst(bb0))

        true.add_inst(bytecode.ReturnInst(BoolLit(SBool(True))))

        false.add_inst(bytecode.ReturnInst(BoolLit(SBool(False))))

        env = bytecode.EvalEnv(local_env={Var("v0"): SNum(42)})
        gen = bytecode.ResultGenerator(is_list.run(env))
        gen.run()
        self.assertEqual(gen.value, SBool(False))

        env = bytecode.EvalEnv(local_env={
            Var("v0"):
            SVect([SNum(42), SVect([SNum(69), SVect([])])])
        })
        gen = bytecode.ResultGenerator(is_list.run(env))
        gen.run()
        self.assertEqual(gen.value, SBool(True))