Esempio n. 1
0
 def test_lambda(self) -> None:
     prog = '(lambda (spam egg) (+ spam egg)) (lambda () 42)'
     self.assertEqual([
         SFunction(
             SSym('__lambda0'), [SSym('spam'), SSym('egg')],
             sexp.to_slist([SCall(SSym('+'),
                                  [SSym('spam'), SSym('egg')])]),
             is_lambda=True),
         SFunction(SSym('__lambda1'), [],
                   sexp.to_slist([SNum(42)]),
                   is_lambda=True),
     ], sexp.parse(prog))
Esempio n. 2
0
    def _generate_specialization(self, env: EvalEnv, func: sexp.SFunction,
                                 func_code: Function,
                                 type_tuple: TypeTuple) -> None:
        if not (env.jit or env.bytecode_jit):
            return
        if env.print_specializations:
            type_names = ', '.join(str(s) for s in type_tuple)
            print(f"Specializing: {func.name} ({type_names})")

        type_analyzer = None
        if env.jit:
            param_types = dict(zip(func.params, type_tuple))
            type_analyzer = scheme_types.FunctionTypeAnalyzer(
                param_types, env._global_env)
            type_analyzer.visit(func)

        tail_calls = None
        if env.optimize_tail_calls:
            tail_call_finder = find_tail_calls.TailCallFinder()
            tail_call_finder.visit(func)
            tail_calls = tail_call_finder.tail_calls

        from emit_IR import FunctionEmitter
        emitter = FunctionEmitter(env._global_env,
                                  tail_calls=tail_calls,
                                  expr_types=type_analyzer)
        emitter.visit(func)
        emitted_func = emitter.get_emitted_func()
        func.specializations[type_tuple] = emitted_func

        if env.bytecode_jit:
            self._optimize(env, func, type_tuple)
Esempio n. 3
0
 def _optimize(self, env: EvalEnv, func: sexp.SFunction,
               type_tuple: TypeTuple) -> None:
     from optimization import FunctionOptimizer
     if env.print_optimizations:
         type_names = ', '.join(str(s) for s in type_tuple)
         print(f"Optimizing {func.name} ({type_names})")
     opt = FunctionOptimizer(func.get_specialized(type_tuple))
     opt.specialization = type_tuple
     opt.optimize(env)
Esempio n. 4
0
 def test_function_def(self) -> None:
     prog = '(define (funcy spam egg) (+ spam egg)) (funcy 42 43)'
     self.assertEqual([
         SFunction(
             SSym('funcy'), [SSym('spam'), SSym('egg')],
             sexp.to_slist([SCall(SSym('+'),
                                  [SSym('spam'), SSym('egg')])])),
         SCall(SSym('funcy'), [SNum(42), SNum(43)])
     ], sexp.parse(prog))
Esempio n. 5
0
    def should_inline(self, env: EvalEnv, func: SFunction,
                      types: Optional[TypeTuple]) -> bool:
        if func.name in self.banned_from_inline:
            return False
        name = func.name.name
        if name.startswith('inst/'):
            return True

        ALWAYS_INLINE = (
            'trap',
            'trace',
            'breakpoint',
            'assert',
            'typeof',
            'number?',
            'symbol?',
            'vector?',
            'function?',
            'bool?',
        )
        if name in ALWAYS_INLINE:
            return True

        if not types:
            return False

        SHOULD_INLINE = (
            'pair?',
            'nil?',
            'symbol=',
            '+',
            '-',
            '*',
            '/',
            '%',
            'pointer=',
            'number=',
            'number<',
            'vector-length',
            'vector-index',
            'vector-set!',
            '<',
            '!=',
            '>',
            '<=',
            '>=',
            'cons',
            'car',
            'cdr',
        )
        if not any(t == SchemeObject for t in types) and name in SHOULD_INLINE:
            return True

        spec = func.get_specialized(types)
        icount = sum(len(b.instructions) for b in spec.blocks())
        return icount <= env.inline_threshold
Esempio n. 6
0
 def test_lambda_called_inline(self) -> None:
     self.maxDiff = None
     prog = '((lambda (spam egg) (+ spam egg)) 42 43)'
     self.assertEqual([
         SCall(
             SFunction(SSym('__lambda0'),
                       [SSym('spam'), SSym('egg')],
                       sexp.to_slist(
                           [SCall(SSym('+'),
                                  [SSym('spam'), SSym('egg')])]),
                       is_lambda=True), [SNum(42), SNum(43)])
     ], sexp.parse(prog))
Esempio n. 7
0
 def inst_function(
         name: SSym, params: List[Var],
         return_val: Optional[bytecode.Parameter], *insts: Inst,
         ) -> SFunction:
     """Create a function out of the instructions in insts."""
     begin = BasicBlock('bb0')
     for inst in insts:
         begin.add_inst(inst)
     if return_val is not None:
         begin.add_inst(bytecode.ReturnInst(return_val))
     code = Function(params, begin)
     param_syms = [SSym(p.name) for p in params]
     return SFunction(name, param_syms, Nil, code, False)
Esempio n. 8
0
 def test_comments(self) -> None:
     prog = """
     ;;; We want to define a cool function here!
     (define ; hi
       ;; A function name
       (cool-func x y) ; wow
       ;; branches are cheaper than subtraction, right? :P
       (if (= x y)
         0
         (- x y)))
     """
     self.assertEqual([
         SFunction(
             SSym('cool-func'), [SSym('x'), SSym('y')],
             sexp.to_slist([
                 SConditional(
                     SCall(SSym('='), [SSym('x'), SSym('y')]), SNum(0),
                     SCall(SSym('-'), [SSym('x'), SSym('y')]))
             ]))
     ], sexp.parse(prog))
Esempio n. 9
0
    def visit_SFunction(self, func: sexp.SFunction) -> None:
        assert func.is_lambda, 'Nested named functions not supported'
        assert not self.quoted, 'Non-primitives in quoted list unsupported'

        # Don't re-emit lambdas defined in a function we're specializing
        func_emitter = FunctionEmitter(self.global_env)
        func_emitter.visit(func)
        func.code = func_emitter.get_emitted_func()

        if func.name in self.global_env:
            looked_up_func = self.global_env[func.name]
            if isinstance(looked_up_func, sexp.SFunction):
                assert func.code == looked_up_func.code
            else:
                assert False, f"Duplicate function name: {func.name}"
        else:
            self.global_env[func.name] = func

        lambda_var = bytecode.Var(next(self.var_names))
        lookup_lambda_instr = bytecode.LookupInst(
            lambda_var, bytecode.SymLit(func.name))

        self.parent_block.add_inst(lookup_lambda_instr)
        self.result = lambda_var
Esempio n. 10
0
def _add_func_to_env(func: sexp.SFunction, func_emitter: FunctionEmitter,
                     env: EvalEnv) -> None:
    func.code = func_emitter.get_emitted_func()
    assert func.name not in env._global_env, (
        f"Duplicate function name: {func.name}")
    env._global_env[func.name] = func