Browse Source

Removed a lot of old JIT code that is now deprecated

Yentl Van Tendeloo 7 years ago
parent
commit
63ac447911

+ 0 - 319
kernel/modelverse_jit/bytecode_interpreter.py

@@ -1,319 +0,0 @@
-"""Interprets parsed bytecode graphs."""
-
-import modelverse_jit.bytecode_ir as bytecode_ir
-import modelverse_jit.runtime as jit_runtime
-import modelverse_kernel.primitives as primitive_functions
-
-class BreakException(Exception):
-    """A type of exception that is used to interpret 'break' instructions:
-       the 'break' instructions throw a BreakException, which is then handled
-       by the appropriate 'while' instruction."""
-    def __init__(self, loop):
-        Exception.__init__(self)
-        self.loop = loop
-
-class ContinueException(Exception):
-    """A type of exception that is used to interpret 'continue' instructions:
-       the 'continue' instructions throw a ContinueException, which is then handled
-       by the appropriate 'while' instruction."""
-    def __init__(self, loop):
-        Exception.__init__(self)
-        self.loop = loop
-
-class InterpreterState(object):
-    """The state of the bytecode interpreter."""
-    def __init__(self, gc_root_node, keyword_arg_dict, nop_period=20):
-        self.gc_root_node = gc_root_node
-        self.nop_period = nop_period
-        self.keyword_arg_dict = keyword_arg_dict
-        self.current_result = None
-        self.nop_phase = 0
-        self.local_vars = {}
-
-    def import_local(self, node_id, value):
-        """Imports the given value as a local in this interpreter state."""
-        local_node, = yield [("CN", [])]
-        yield [
-            ("CE", [self.gc_root_node, local_node]),
-            ("CD", [local_node, "value", value])]
-        self.local_vars[node_id] = local_node
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def schedule_nop(self):
-        """Increments the nop-phase. If a nop should be performed, then True is returned.
-           Otherwise, False."""
-        self.nop_phase += 1
-        if self.nop_phase == self.nop_period:
-            self.nop_phase = 0
-            return True
-        else:
-            return False
-
-    def update_result(self, new_result):
-        """Sets the current result to the given value, if it is not None."""
-        if new_result is not None:
-            self.current_result = new_result
-
-    def get_task_root(self):
-        """Gets the task root node id."""
-        return self.keyword_arg_dict['task_root']
-
-    def get_kernel(self):
-        """Gets the Modelverse kernel instance."""
-        return self.keyword_arg_dict['mvk']
-
-    def interpret(self, instruction):
-        """Interprets the given instruction and returns the current result."""
-        instruction_type = type(instruction)
-        if instruction_type in InterpreterState.INTERPRETERS:
-            # Interpret the instruction.
-            yield [("CALL_ARGS",
-                    [InterpreterState.INTERPRETERS[instruction_type], (self, instruction)])]
-
-            # Maybe perform a nop.
-            if self.schedule_nop():
-                yield None
-
-            # Interpret the next instruction.
-            next_instruction = instruction.next_instruction
-            if next_instruction is not None:
-                yield [("TAIL_CALL_ARGS", [self.interpret, (next_instruction,)])]
-            else:
-                raise primitive_functions.PrimitiveFinished(self.current_result)
-        else:
-            raise jit_runtime.JitCompilationFailedException(
-                'Unknown bytecode instruction: %r' % instruction)
-
-    def interpret_select(self, instruction):
-        """Interprets the given 'select' instruction."""
-        cond_node, = yield [("CALL_ARGS", [self.interpret, (instruction.condition,)])]
-        cond_val, = yield [("RV", [cond_node])]
-        if cond_val:
-            yield [("TAIL_CALL_ARGS", [self.interpret, (instruction.if_clause,)])]
-        elif instruction.else_clause is not None:
-            yield [("TAIL_CALL_ARGS", [self.interpret, (instruction.else_clause,)])]
-        else:
-            raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_while(self, instruction):
-        """Interprets the given 'while' instruction."""
-        def __handle_break(exception):
-            if exception.loop == instruction:
-                # End the loop.
-                raise primitive_functions.PrimitiveFinished(None)
-            else:
-                # Propagate the exception to the next 'while' loop.
-                raise exception
-
-        def __handle_continue(exception):
-            if exception.loop == instruction:
-                # Restart the loop.
-                yield [("TAIL_CALL_ARGS", [self.interpret, (instruction,)])]
-            else:
-                # Propagate the exception to the next 'while' loop.
-                raise exception
-
-        yield [("TRY", [])]
-        yield [("CATCH", [BreakException, __handle_break])]
-        yield [("CATCH", [ContinueException, __handle_continue])]
-        while 1:
-            cond_node, = yield [("CALL_ARGS", [self.interpret, (instruction.condition,)])]
-            cond_val, = yield [("RV", [cond_node])]
-            if cond_val:
-                yield [("CALL_ARGS", [self.interpret, (instruction.body,)])]
-            else:
-                break
-        yield [("END_TRY", [])]
-
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_break(self, instruction):
-        """Interprets the given 'break' instruction."""
-        raise BreakException(instruction.loop)
-
-    def interpret_continue(self, instruction):
-        """Interprets the given 'continue' instruction."""
-        raise ContinueException(instruction.loop)
-
-    def interpret_return(self, instruction):
-        """Interprets the given 'return' instruction."""
-        if instruction.value is None:
-            raise primitive_functions.InterpretedFunctionFinished(None)
-        else:
-            return_node, = yield [("CALL_ARGS", [self.interpret, (instruction.value,)])]
-            raise primitive_functions.InterpretedFunctionFinished(return_node)
-
-    def interpret_call(self, instruction):
-        """Interprets the given 'call' instruction."""
-        target, = yield [("CALL_ARGS", [self.interpret, (instruction.target,)])]
-        named_args = {}
-        for name, arg_instruction in instruction.argument_list:
-            arg, = yield [("CALL_ARGS", [self.interpret, (arg_instruction,)])]
-            named_args[name] = arg
-
-        kwargs = {'function_id': target, 'named_arguments': named_args}
-        kwargs.update(self.keyword_arg_dict)
-        result, = yield [("CALL_KWARGS", [jit_runtime.call_function, kwargs])]
-        if result is not None:
-            yield [("CE", [self.gc_root_node, result])]
-            self.update_result(result)
-
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_constant(self, instruction):
-        """Interprets the given 'constant' instruction."""
-        self.update_result(instruction.constant_id)
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_input(self, instruction):
-        """Interprets the given 'input' instruction."""
-        result, = yield [("CALL_KWARGS", [jit_runtime.get_input, self.keyword_arg_dict])]
-        self.update_result(result)
-        yield [("CE", [self.gc_root_node, result])]
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_output(self, instruction):
-        """Interprets the given 'output' instruction."""
-        output_value, = yield [("CALL_ARGS", [self.interpret, (instruction.value,)])]
-        task_root = self.get_task_root()
-        last_output, last_output_link, new_last_output = yield [
-            ("RD", [task_root, "last_output"]),
-            ("RDE", [task_root, "last_output"]),
-            ("CN", [])
-        ]
-        yield [
-            ("CD", [last_output, "value", output_value]),
-            ("CD", [last_output, "next", new_last_output]),
-            ("CD", [task_root, "last_output", new_last_output]),
-            ("DE", [last_output_link])
-        ]
-        yield None
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_declare(self, instruction):
-        """Interprets a 'declare' (local) instruction."""
-        node_id = instruction.variable.node_id
-        if node_id in self.local_vars:
-            self.update_result(self.local_vars[node_id])
-            raise primitive_functions.PrimitiveFinished(None)
-        else:
-            local_node, = yield [("CN", [])]
-            yield [("CE", [self.gc_root_node, local_node])]
-            self.update_result(local_node)
-            self.local_vars[node_id] = local_node
-            raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_global(self, instruction):
-        """Interprets a (declare) 'global' instruction."""
-        var_name = instruction.variable.name
-        task_root = self.get_task_root()
-        _globals, = yield [("RD", [task_root, "globals"])]
-        global_var, = yield [("RDE", [_globals, var_name])]
-
-        if global_var is not None:
-            yield [("DE", [global_var])]
-
-        global_var, = yield [("CN", [])]
-        yield [("CD", [_globals, var_name, global_var])]
-
-        self.update_result(global_var)
-        yield [("CE", [self.gc_root_node, global_var])]
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_resolve(self, instruction):
-        """Interprets a 'resolve' instruction."""
-        node_id = instruction.variable.node_id
-        if node_id in self.local_vars:
-            self.update_result(self.local_vars[node_id])
-            raise primitive_functions.PrimitiveFinished(None)
-        else:
-            task_root = self.get_task_root()
-            var_name = instruction.variable.name
-            _globals, = yield [("RD", [task_root, "globals"])]
-            global_var, = yield [("RD", [_globals, var_name])]
-
-            if global_var is None:
-                raise Exception(jit_runtime.GLOBAL_NOT_FOUND_MESSAGE_FORMAT % var_name)
-
-            mvk = self.get_kernel()
-            if mvk.suggest_function_names and mvk.jit.get_global_body_id(var_name) is None:
-                global_val, = yield [("RD", [global_var, "value"])]
-                if global_val is not None:
-                    func_body, = yield [("RD", [global_val, "body"])]
-                    if func_body is not None:
-                        mvk.jit.register_global(func_body, var_name)
-
-            self.update_result(global_var)
-            yield [("CE", [self.gc_root_node, global_var])]
-            raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_access(self, instruction):
-        """Interprets an 'access' instruction."""
-        pointer_node, = yield [("CALL_ARGS", [self.interpret, (instruction.pointer,)])]
-        value_node, = yield [("RD", [pointer_node, "value"])]
-        self.update_result(value_node)
-        yield [("CE", [self.gc_root_node, value_node])]
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def interpret_assign(self, instruction):
-        """Interprets an 'assign' instruction."""
-        pointer_node, = yield [("CALL_ARGS", [self.interpret, (instruction.pointer,)])]
-        value_node, = yield [("CALL_ARGS", [self.interpret, (instruction.value,)])]
-        value_link, = yield [("RDE", [pointer_node, "value"])]
-        yield [
-            ("CD", [pointer_node, "value", value_node]),
-            ("DE", [value_link])]
-        raise primitive_functions.PrimitiveFinished(None)
-
-    INTERPRETERS = {
-        bytecode_ir.SelectInstruction: interpret_select,
-        bytecode_ir.WhileInstruction: interpret_while,
-        bytecode_ir.BreakInstruction: interpret_break,
-        bytecode_ir.ContinueInstruction: interpret_continue,
-        bytecode_ir.ReturnInstruction: interpret_return,
-        bytecode_ir.CallInstruction: interpret_call,
-        bytecode_ir.ConstantInstruction: interpret_constant,
-        bytecode_ir.InputInstruction: interpret_input,
-        bytecode_ir.OutputInstruction: interpret_output,
-        bytecode_ir.DeclareInstruction: interpret_declare,
-        bytecode_ir.GlobalInstruction: interpret_global,
-        bytecode_ir.ResolveInstruction: interpret_resolve,
-        bytecode_ir.AccessInstruction: interpret_access,
-        bytecode_ir.AssignInstruction: interpret_assign
-    }
-
-def interpret_bytecode_function(function_name, body_bytecode, local_arguments, keyword_arguments):
-    """Interprets the bytecode function with the given name, body, named arguments and
-       keyword arguments."""
-    yield [("DEBUG_INFO", [function_name, None, jit_runtime.BYTECODE_INTERPRETER_ORIGIN_NAME])]
-    task_root = keyword_arguments['task_root']
-    gc_root_node, = yield [("CN", [])]
-    gc_root_edge, = yield [("CE", [task_root, gc_root_node])]
-    interpreter = InterpreterState(gc_root_node, keyword_arguments)
-    for param_id, arg_node in list(local_arguments.items()):
-        yield [("CALL_ARGS", [interpreter.import_local, (param_id, arg_node)])]
-
-    def __handle_return(exception):
-        yield [("DE", [gc_root_edge])]
-        raise primitive_functions.PrimitiveFinished(exception.result)
-
-    def __handle_break(_):
-        raise jit_runtime.UnreachableCodeException(
-            "Function '%s' tries to break out of a loop that is not currently executing." %
-            function_name)
-
-    def __handle_continue(_):
-        raise jit_runtime.UnreachableCodeException(
-            "Function '%s' tries to continue a loop that is not currently executing." %
-            function_name)
-
-    # Perform a nop before interpreting the function.
-    yield None
-
-    yield [("TRY", [])]
-    yield [("CATCH", [primitive_functions.InterpretedFunctionFinished, __handle_return])]
-    yield [("CATCH", [BreakException, __handle_break])]
-    yield [("CATCH", [ContinueException, __handle_continue])]
-    yield [("CALL_ARGS", [interpreter.interpret, (body_bytecode,)])]
-    yield [("END_TRY", [])]
-    raise jit_runtime.UnreachableCodeException("Function '%s' failed to return." % function_name)

+ 0 - 312
kernel/modelverse_jit/bytecode_ir.py

@@ -1,312 +0,0 @@
-"""Provides data structures that represent parsed Modelverse bytecode graphs."""
-
-class Instruction(object):
-    """Represents a Modelverse bytecode instruction."""
-    def __init__(self):
-        self.next_instruction = None
-        self.debug_information = None
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction, excluding the
-           next instruction."""
-        raise NotImplementedError()
-
-    def get_reachable(self, filter_children=lambda _: True):
-        """Gets the set of all instructions that are reachable from the given instruction, including
-           this instruction. A function can be used to filter out certain instructions' children."""
-        results = set()
-        stack = [self]
-        while len(stack) > 0:
-            instr = stack.pop()
-            results.add(instr)
-            next_instr = instr.next_instruction
-            if next_instr is not None and next_instr not in results:
-                stack.append(next_instr)
-
-            if filter_children(instr):
-                for other in instr.get_directly_reachable():
-                    if other not in results:
-                        assert other is not None
-                        stack.append(other)
-
-        return results
-
-class VariableNode(object):
-    """Represents a variable node, which has an identifier and an optional name."""
-    def __init__(self, node_id, name):
-        self.node_id = node_id
-        if node_id is None:
-            print(locals())
-            raise Exception("NONE")
-        self.name = name
-
-    def __str__(self):
-        return 'var(%d, %s)' % (self.node_id, self.name)
-
-    def __repr__(self):
-        return 'VariableNode(%r, %r)' % (self.node_id, self.name)
-
-class SelectInstruction(Instruction):
-    """Represents an 'if/else' instruction."""
-    def __init__(self, condition, if_clause, else_clause):
-        Instruction.__init__(self)
-        self.condition = condition
-        self.if_clause = if_clause
-        self.else_clause = else_clause
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        if self.else_clause is None:
-            return (self.condition, self.if_clause)
-        else:
-            return (self.condition, self.if_clause, self.else_clause)
-
-    constructor_parameters = (
-        ('cond', Instruction),
-        ('then', Instruction),
-        ('else', Instruction))
-
-    def __repr__(self):
-        return '@%r: SelectInstruction(@%r, @%r, @%r)' % (
-            id(self), id(self.condition), id(self.if_clause), id(self.else_clause))
-
-class WhileInstruction(Instruction):
-    """Represents a 'while' instruction."""
-    def __init__(self, condition, body):
-        Instruction.__init__(self)
-        self.condition = condition
-        self.body = body
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return (self.condition, self.body)
-
-    constructor_parameters = (
-        ('cond', Instruction),
-        ('body', Instruction))
-
-    def __repr__(self):
-        return '@%r: WhileInstruction(@%r, @%r)' % (
-            id(self), id(self.condition), id(self.body))
-
-class BreakInstruction(Instruction):
-    """Represents a 'break' instruction."""
-    def __init__(self, loop):
-        Instruction.__init__(self)
-        self.loop = loop
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return (self.loop,)
-
-    constructor_parameters = (('while', WhileInstruction),)
-
-    def __repr__(self):
-        return '@%r: BreakInstruction(@%r)' % (
-            id(self), id(self.loop))
-
-class ContinueInstruction(Instruction):
-    """Represents a 'continue' instruction."""
-    def __init__(self, loop):
-        Instruction.__init__(self)
-        self.loop = loop
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return (self.loop,)
-
-    constructor_parameters = (('while', WhileInstruction),)
-
-    def __repr__(self):
-        return '@%r: ContinueInstruction(@%r)' % (
-            id(self), id(self.loop))
-
-class ReturnInstruction(Instruction):
-    """Represents a 'return' instruction, which terminates the current function
-       and optionally returns a value."""
-    def __init__(self, value):
-        Instruction.__init__(self)
-        self.value = value
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        if self.value is None:
-            return ()
-        else:
-            return (self.value,)
-
-    constructor_parameters = (('value', Instruction),)
-
-    def __repr__(self):
-        return '@%r: ReturnInstruction(@%r)' % (
-            id(self), id(self.value))
-
-class CallInstruction(Instruction):
-    """Represents a 'call' instruction, which calls a function with an argument
-       list, encoded as a list of name-instruction tuples."""
-    def __init__(self, target, argument_list):
-        Instruction.__init__(self)
-        self.target = target
-        self.argument_list = argument_list
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return (self.target,) + tuple((value for _, value in self.argument_list))
-
-    def __repr__(self):
-        return '@%r: CallInstruction(@%r, [%s])' % (
-            id(self), id(self.target),
-            ', '.join(['%s=@%r' % (name, id(value)) for name, value in self.argument_list]))
-
-class ConstantInstruction(Instruction):
-    """Represents a 'constant' instruction, which produces a reference
-       to a constant node."""
-    def __init__(self, constant_id):
-        Instruction.__init__(self)
-        self.constant_id = constant_id
-        assert self.constant_id is not None
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return ()
-
-    constructor_parameters = (('node', int),)
-
-    def __repr__(self):
-        return '@%r: ConstantInstruction(%r)' % (id(self), self.constant_id)
-
-class InputInstruction(Instruction):
-    """Represents an 'input' instruction, which pops a node from the input
-       queue."""
-    def __init__(self):
-        Instruction.__init__(self)
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return ()
-
-    constructor_parameters = ()
-
-    def __repr__(self):
-        return '@%r: InputInstruction()' % id(self)
-
-class OutputInstruction(Instruction):
-    """Represents an 'output' instruction, which pushes a node onto the output
-       queue."""
-    def __init__(self, value):
-        Instruction.__init__(self)
-        self.value = value
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return (self.value,)
-
-    constructor_parameters = (('value', Instruction),)
-
-    def __repr__(self):
-        return '@%r: OutputInstruction(@%r)' % (
-            id(self), id(self.value))
-
-class DeclareInstruction(Instruction):
-    """Represents a 'declare' instruction, which declares a local variable."""
-    def __init__(self, variable):
-        Instruction.__init__(self)
-        self.variable = variable
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return ()
-
-    constructor_parameters = (('var', VariableNode),)
-
-    def __repr__(self):
-        return '@%r: DeclareInstruction(%r)' % (
-            id(self), self.variable)
-
-class GlobalInstruction(Instruction):
-    """Represents a 'global' instruction, which declares a global variable."""
-    def __init__(self, variable):
-        Instruction.__init__(self)
-        self.variable = variable
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return ()
-
-    constructor_parameters = (('var', VariableNode),)
-
-    def __repr__(self):
-        return '@%r: GlobalInstruction(%r)' % (
-            id(self), self.variable)
-
-class ResolveInstruction(Instruction):
-    """Represents a 'resolve' instruction, which resolves a variable node/name as
-       either a local or global variable."""
-    def __init__(self, variable):
-        Instruction.__init__(self)
-        self.variable = variable
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return ()
-
-    constructor_parameters = (('var', VariableNode),)
-
-    def __repr__(self):
-        return '@%r: ResolveInstruction(%r)' % (
-            id(self), self.variable)
-
-class AccessInstruction(Instruction):
-    """Represents an 'access' instruction, which loads the node pointed to by a
-       pointer node."""
-    def __init__(self, pointer):
-        Instruction.__init__(self)
-        self.pointer = pointer
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return (self.pointer,)
-
-    constructor_parameters = (('var', Instruction),)
-
-    def __repr__(self):
-        return '@%r: AccessInstruction(@%r)' % (
-            id(self), id(self.pointer))
-
-class AssignInstruction(Instruction):
-    """Represents an 'assign' instruction, which sets the node pointed to by a
-       pointer node to the given node."""
-    def __init__(self, pointer, value):
-        Instruction.__init__(self)
-        self.pointer = pointer
-        self.value = value
-
-    def get_directly_reachable(self):
-        """Gets all instructions that are directly reachable from this instruction."""
-        return (self.pointer, self.value)
-
-    constructor_parameters = (
-        ('var', Instruction),
-        ('value', Instruction))
-
-    def __repr__(self):
-        return '@%r: AssignInstruction(@%r, @%r)' % (
-            id(self), id(self.pointer), id(self.value))
-
-INSTRUCTION_TYPE_MAPPING = {
-    'if' : SelectInstruction,
-    'while' : WhileInstruction,
-    'return' : ReturnInstruction,
-    'constant' : ConstantInstruction,
-    'resolve' : ResolveInstruction,
-    'declare' : DeclareInstruction,
-    'global' : GlobalInstruction,
-    'assign' : AssignInstruction,
-    'access' : AccessInstruction,
-    'output' : OutputInstruction,
-    'input' : InputInstruction,
-    'call' : CallInstruction,
-    'break' : BreakInstruction,
-    'continue' : ContinueInstruction
-}
-"""Maps instruction names to types."""

+ 0 - 117
kernel/modelverse_jit/bytecode_parser.py

@@ -1,117 +0,0 @@
-"""Parses Modelverse bytecode graphs into bytecode ir."""
-
-import modelverse_jit.bytecode_ir as bytecode_ir
-import modelverse_jit.runtime as jit_runtime
-import modelverse_kernel.primitives as primitive_functions
-
-class BytecodeParser(object):
-    """Parses bytecode graphs."""
-    def __init__(self):
-        self.parsed_nodes = {}
-
-    def parse_instruction(self, node_id):
-        """Parses the instruction node with the given identifier."""
-        if node_id is None:
-            raise primitive_functions.PrimitiveFinished(None)
-        elif node_id in self.parsed_nodes:
-            # We've already parsed this node, so return it right away.
-            raise primitive_functions.PrimitiveFinished(self.parsed_nodes[node_id])
-
-        instruction_val, = yield [("RV", [node_id])]
-        instruction_type = instruction_val["value"]
-        # Create an instruction and store it in the instruction dictionary.
-        instruction = self.create_instruction(instruction_type)
-        self.parsed_nodes[node_id] = instruction
-        # Initialize the instruction from the node's data.
-        yield [("CALL_ARGS", [self.initialize_instruction, (instruction, node_id)])]
-        # Retrieve the debug information.
-        debug_info, = yield [("RD", [node_id, "__debug"])]
-        if debug_info is not None:
-            debug_info, = yield [("RV", [debug_info])]
-            instruction.debug_information = debug_info
-
-        # Check if the instruction has a 'next' instruction.
-        next_instr_id, = yield [("RD", [node_id, "next"])]
-        if next_instr_id is not None:
-            instruction.next_instruction, = yield [
-                ("CALL_ARGS", [self.parse_instruction, (next_instr_id,)])]
-
-        raise primitive_functions.PrimitiveFinished(instruction)
-
-    def parse_variable(self, node_id):
-        """Parses the given variable node."""
-        var_name, = yield [("RV", [node_id])]
-        raise primitive_functions.PrimitiveFinished(
-            bytecode_ir.VariableNode(node_id, var_name))
-
-    def __parse_node_unchecked(self, node_id, result_type):
-        """Parses the given node as the specified type of object, without
-           checking that the result actually conforms to said type."""
-        if result_type is bytecode_ir.VariableNode:
-            yield [("TAIL_CALL_ARGS", [self.parse_variable, (node_id,)])]
-        elif result_type is int:
-            raise primitive_functions.PrimitiveFinished(node_id)
-        else:
-            yield [("TAIL_CALL_ARGS", [self.parse_instruction, (node_id,)])]
-
-    def parse_node(self, node_id, result_type):
-        """Parses the given node as the specified type of object."""
-        result, = yield [("CALL_ARGS", [self.__parse_node_unchecked, (node_id, result_type)])]
-        if result is not None and not isinstance(result, result_type):
-            raise jit_runtime.JitCompilationFailedException(
-                "Parsed a node as an instance of '%s', expected an instance of '%s'." % (
-                    type(result).__name__, result_type.__name__))
-
-        raise primitive_functions.PrimitiveFinished(result)
-
-    def parse_arguments(self, first_argument_id):
-        """Parses the parameter-to-argument mapping started by the specified first argument
-           node."""
-        next_param = first_argument_id
-        named_args = []
-        while next_param is not None:
-            param_name_id, = yield [("RD", [next_param, "name"])]
-            param_name, = yield [("RV", [param_name_id])]
-            param_val_id, = yield [("RD", [next_param, "value"])]
-            param_val, = yield [("CALL_ARGS", [self.parse_instruction, (param_val_id,)])]
-            named_args.append((param_name, param_val))
-
-            next_param, = yield [("RD", [next_param, "next_param"])]
-
-        raise primitive_functions.PrimitiveFinished(named_args)
-
-    def create_instruction(self, instruction_type):
-        """Creates an instruction of the given type."""
-        if instruction_type in bytecode_ir.INSTRUCTION_TYPE_MAPPING:
-            return object.__new__(bytecode_ir.INSTRUCTION_TYPE_MAPPING[instruction_type])
-        else:
-            raise jit_runtime.JitCompilationFailedException(
-                "Unknown instruction type: '%s'" % instruction_type)
-
-    def initialize_call(self, call_instruction, node_id):
-        """Initializes the given call instruction."""
-        func_id, first_arg_id, = yield [
-            ("RD", [node_id, "func"]),
-            ("RD", [node_id, "params"])]
-        func_val, = yield [("CALL_ARGS", [self.parse_instruction, (func_id,)])]
-        named_args, = yield [("CALL_ARGS", [self.parse_arguments, (first_arg_id,)])]
-        call_instruction.__init__(func_val, named_args)
-        raise primitive_functions.PrimitiveFinished(None)
-
-    def initialize_instruction(self, instruction, node_id):
-        """Initializes the given instruction with data from the given node."""
-        instr_type = type(instruction)
-        # print("Initializing '%s' node" % instr_type)
-        if instr_type is bytecode_ir.CallInstruction:
-            # Call instructions are complicated, so they get special treatment.
-            yield [("TAIL_CALL_ARGS", [self.initialize_call, (instruction, node_id)])]
-        else:
-            # Construct an argument list based on the `constructor_parameters` attribute
-            # of the instruction type.
-            arg_list = []
-            for dict_key, ctor_param_ty in instr_type.constructor_parameters:
-                arg_id, = yield [("RD", [node_id, dict_key])]
-                arg, = yield [("CALL_ARGS", [self.parse_node, (arg_id, ctor_param_ty)])]
-                arg_list.append(arg)
-            instruction.__init__(*arg_list)
-            raise primitive_functions.PrimitiveFinished(None)

+ 0 - 374
kernel/modelverse_jit/bytecode_to_cfg.py

@@ -1,374 +0,0 @@
-"""Converts bytecode IR to CFG IR."""
-
-import modelverse_jit.bytecode_ir as bytecode_ir
-import modelverse_jit.cfg_ir as cfg_ir
-import modelverse_jit.runtime as jit_runtime
-
-def emit_debug_info_trace(block, debug_info, function_name):
-    """Appends a tracing instruction to the given block that prints
-       the given debug information and function name."""
-    if debug_info is not None or function_name is not None:
-        block.append_definition(
-            cfg_ir.create_print(
-                block.append_definition(
-                    cfg_ir.Literal(jit_runtime.format_trace_message(
-                        debug_info, function_name, jit_runtime.FAST_JIT_ORIGIN_NAME)))))
-
-class AnalysisState(object):
-    """State that is common to the bytecode->CFG transformation of a function."""
-    def __init__(self, jit, function_name, param_dict):
-        self.jit = jit
-        self.function_name = function_name
-        self.counter = cfg_ir.SharedCounter()
-        self.analyzed_instructions = set()
-        self.loop_instructions = {}
-        self.entry_point = cfg_ir.BasicBlock(self.counter)
-        self.current_block = self.entry_point
-        self.root_node = None
-        self.__write_prolog(param_dict)
-
-    def __write_prolog(self, param_dict):
-        # Write a prolog in CFG IR.
-        # We want to create the following definition:
-        #
-        #     !entry_point():
-        #         static if self.jit.source_maps_enabled:
-        #             $function_name = literal <function map>
-        #             $source_map_name = literal <source map name>
-        #             $origin_name = literal jit_runtime.FAST_JIT_ORIGIN_NAME
-        #             $_ = direct-call ('macro-positional', void) register_debug_info(
-        #                 function_name=$functionsource_map=$source_map_name)
-        #
-        #         $jit_locals = alloc-root-node
-        #         $_ = declare-local var(...)
-        #         $param_1 = resolve-local var(...)
-        #         $arg_1 = function-parameter ...
-        #         $_ = store $param_1, $arg_1
-        #         ...
-        #
-        #         static if self.jit.nop_insertion_enabled:
-        #             $_ = direct-call ('macro-io', void) nop()
-        #
-        # We also want to store '$jit_locals' in an attribute, so we can
-        # use it to shield locals from the GC.
-        if self.jit.source_maps_enabled:
-            function_name = self.current_block.append_definition(
-                cfg_ir.Literal(self.function_name))
-            source_map_name = self.current_block.append_definition(
-                cfg_ir.Literal(self.jit.get_source_map_name(self.function_name)))
-            origin_name = self.current_block.append_definition(
-                cfg_ir.Literal(jit_runtime.FAST_JIT_ORIGIN_NAME))
-            self.current_block.append_definition(
-                cfg_ir.DirectFunctionCall(
-                    cfg_ir.REGISTER_DEBUG_INFO_MACRO_NAME,
-                    [('function_name', function_name),
-                     ('source_map', source_map_name),
-                     ('origin_name', origin_name)],
-                    calling_convention=cfg_ir.MACRO_POSITIONAL_CALLING_CONVENTION,
-                    has_value=False))
-
-        self.root_node = self.current_block.append_definition(cfg_ir.AllocateRootNode())
-        for node_id, name in list(param_dict.items()):
-            variable = bytecode_ir.VariableNode(node_id, name)
-            self.current_block.append_definition(cfg_ir.DeclareLocal(variable, self.root_node))
-            param_i = self.current_block.append_definition(cfg_ir.ResolveLocal(variable))
-            arg_i = self.current_block.append_definition(cfg_ir.FunctionParameter(name))
-            self.current_block.append_definition(cfg_ir.StoreAtPointer(param_i, arg_i))
-
-        if self.jit.nop_insertion_enabled:
-            self.current_block.append_definition(cfg_ir.create_nop())
-
-    def analyze(self, instruction):
-        """Analyzes the given instruction as a basic block."""
-        if instruction in self.analyzed_instructions:
-            raise jit_runtime.JitCompilationFailedException(
-                'Cannot jit non-tree instruction graph.')
-
-        self.analyzed_instructions.add(instruction)
-
-        # Find an analyzer.
-        instruction_type = type(instruction)
-        if instruction_type in self.instruction_analyzers:
-            if self.jit.tracing_enabled:
-                emit_debug_info_trace(
-                    self.current_block, instruction.debug_information, self.function_name)
-
-            # Analyze the instruction.
-            result = self.instruction_analyzers[instruction_type](self, instruction)
-
-            if self.jit.source_maps_enabled:
-                result.debug_information = instruction.debug_information
-
-            # Check if the instruction has a 'next' instruction. If so, analyze it!
-            if instruction.next_instruction is not None:
-                next_result = self.analyze(instruction.next_instruction)
-                if next_result.value.has_value() or (not result.value.has_value()):
-                    result = next_result
-
-            return result
-        else:
-            raise jit_runtime.JitCompilationFailedException(
-                "Unknown instruction type: '%s'" % type(instruction))
-
-    def emit_select(self, create_condition, create_if_body, create_else_body):
-        """Emits a 'select' instruction."""
-        # Create blocks that look like this:
-        #
-        # !current_block(...):
-        #     ...
-        #     $cond = <condition>
-        #     select $cond, !if_block(), !else_block()
-        #
-        # !if_block():
-        #     $if_result = <if-body>
-        #     jump !phi_block($if_result)
-        #
-        # !else_block():
-        #     $else_result = <else-body>
-        #     jump !phi_block($else_result)
-        #
-        # !phi_block($result = block-parameter):
-        #     ...
-        #
-        if_block = cfg_ir.BasicBlock(self.counter)
-        else_block = cfg_ir.BasicBlock(self.counter)
-        phi_block = cfg_ir.BasicBlock(self.counter)
-        param_def = phi_block.append_parameter(cfg_ir.BlockParameter())
-
-        condition = create_condition()
-        self.current_block.flow = cfg_ir.SelectFlow(
-            condition, cfg_ir.Branch(if_block), cfg_ir.Branch(else_block))
-
-        self.current_block = if_block
-        if_result = create_if_body()
-        self.current_block.flow = cfg_ir.create_jump(phi_block, [if_result])
-
-        self.current_block = else_block
-        else_result = create_else_body()
-        self.current_block.flow = cfg_ir.create_jump(phi_block, [else_result])
-
-        self.current_block = phi_block
-        return param_def
-
-    def analyze_if(self, instruction):
-        """Analyzes an 'if' instruction."""
-        def __analyze_condition():
-            condition_node = self.analyze(instruction.condition)
-            return self.current_block.append_definition(cfg_ir.Read(condition_node))
-        return self.emit_select(
-            __analyze_condition,
-            lambda: self.analyze(instruction.if_clause),
-            lambda:
-            self.current_block.append_definition(cfg_ir.Literal(None))
-            if instruction.else_clause is None
-            else self.analyze(instruction.else_clause))
-
-    def analyze_while(self, instruction):
-        """Analyzes a 'while' instruction."""
-        # Create blocks that look like this:
-        #
-        # !current_block(...):
-        #     ...
-        #     jump !loop_condition()
-        #
-        # !loop_condition():
-        #     $condition_node = <condition>
-        #     $condition = read condition_node
-        #     select $condition, !loop_body(), !loop_exit()
-        #
-        # !loop_body():
-        #     $result = <body>
-        #     static if jit.nop_insertion_enabled:
-        #         $_ = direct-call ('macro-io', void) nop()
-        #     jump !loop_condition()
-        #
-        # !loop_exit():
-        #     $nothing = literal None
-        #     ...
-        loop_condition_block = cfg_ir.BasicBlock(self.counter)
-        loop_body_block = cfg_ir.BasicBlock(self.counter)
-        loop_exit_block = cfg_ir.BasicBlock(self.counter)
-        self.loop_instructions[instruction] = (loop_condition_block, loop_exit_block)
-
-        self.current_block.flow = cfg_ir.create_jump(loop_condition_block)
-
-        self.current_block = loop_condition_block
-        condition_node = self.analyze(instruction.condition)
-        condition = self.current_block.append_definition(cfg_ir.Read(condition_node))
-        self.current_block.flow = cfg_ir.SelectFlow(
-            condition, cfg_ir.Branch(loop_body_block), cfg_ir.Branch(loop_exit_block))
-
-        self.current_block = loop_body_block
-        self.analyze(instruction.body)
-        if self.jit.nop_insertion_enabled:
-            self.current_block.append_definition(cfg_ir.create_nop())
-        self.current_block.flow = cfg_ir.create_jump(loop_condition_block)
-
-        self.current_block = loop_exit_block
-        return loop_exit_block.append_definition(cfg_ir.Literal(None))
-
-    def analyze_return(self, instruction):
-        """Analyzes a 'return' instruction."""
-        if instruction.value is None:
-            return_value = self.current_block.append_definition(cfg_ir.Literal(None))
-        else:
-            return_value = self.analyze(instruction.value)
-        # Don't forget to deallocate the root node.
-        self.current_block.append_definition(cfg_ir.DeallocateRootNode(self.root_node))
-        self.current_block.flow = cfg_ir.ReturnFlow(return_value)
-        self.current_block = cfg_ir.BasicBlock(self.counter)
-        return self.current_block.append_definition(cfg_ir.Literal(None))
-
-    def analyze_constant(self, instruction):
-        """Analyzes a 'constant' instruction."""
-        return self.current_block.append_definition(cfg_ir.Literal(instruction.constant_id))
-
-    def analyze_resolve(self, instruction):
-        """Analyzes a 'resolve' instruction."""
-        def __resolve_global_carefully():
-            # We might be resolving a global that does not exist. In that case, we
-            # need to throw. We want to create the following blocks:
-            #
-            # !current_block(...):
-            #     ...
-            #     $resolved_global = resolve-global global
-            #     $nothing = literal None
-            #     $condition = binary $resolved_global, 'is', $nothing
-            #     select $condition, !no_global_block(), !global_exists_block()
-            #
-            # !no_global_block():
-            #     $message = literal <GLOBAL_NOT_FOUND_MESSAGE_FORMAT % instruction.variable.name>
-            #     $exception = direct-call "simple-positional" Exception(message=$message)
-            #     throw $exception
-            #
-            # !global_exists_block():
-            #     ...
-            #
-            no_global_block = cfg_ir.BasicBlock(self.counter)
-            global_exists_block = cfg_ir.BasicBlock(self.counter)
-
-            resolved_global = self.current_block.append_definition(
-                cfg_ir.ResolveGlobal(instruction.variable))
-            nothing = self.current_block.append_definition(cfg_ir.Literal(None))
-            condition = self.current_block.append_definition(
-                cfg_ir.Binary(resolved_global, 'is', nothing))
-            self.current_block.flow = cfg_ir.SelectFlow(
-                condition, cfg_ir.Branch(no_global_block), cfg_ir.Branch(global_exists_block))
-
-            message = no_global_block.append_definition(
-                cfg_ir.Literal(
-                    jit_runtime.GLOBAL_NOT_FOUND_MESSAGE_FORMAT % instruction.variable.name))
-            exception = no_global_block.append_definition(
-                cfg_ir.DirectFunctionCall(
-                    'Exception',
-                    [('message', message)],
-                    cfg_ir.SIMPLE_POSITIONAL_CALLING_CONVENTION))
-            no_global_block.flow = cfg_ir.ThrowFlow(exception)
-
-            self.current_block = global_exists_block
-            return resolved_global
-        return self.emit_select(
-            lambda:
-            self.current_block.append_definition(
-                cfg_ir.CheckLocalExists(instruction.variable)),
-            lambda:
-            self.current_block.append_definition(
-                cfg_ir.ResolveLocal(instruction.variable)),
-            __resolve_global_carefully)
-
-    def analyze_declare(self, instruction):
-        """Analyzes a 'declare' instruction."""
-        return self.current_block.append_definition(
-            cfg_ir.DeclareLocal(instruction.variable, self.root_node))
-
-    def analyze_global(self, instruction):
-        """Analyzes a 'global' instruction."""
-
-        return self.current_block.append_definition(
-            cfg_ir.DeclareGlobal(instruction.variable))
-
-        """
-        resolved_global = self.current_block.append_definition(
-            cfg_ir.ResolveGlobal(instruction.variable))
-        nothing = self.current_block.append_definition(cfg_ir.Literal(None))
-        return self.emit_select(
-            lambda:
-            self.current_block.append_definition(
-                cfg_ir.Binary(resolved_global, 'is', nothing)),
-            lambda:
-            self.current_block.append_definition(
-                cfg_ir.DeclareGlobal(instruction.variable)),
-            lambda: resolved_global)
-        """
-
-    def analyze_assign(self, instruction):
-        """Analyzes an 'assign' instruction."""
-        pointer_result = self.analyze(instruction.pointer)
-        value_result = self.analyze(instruction.value)
-        return self.current_block.append_definition(
-            cfg_ir.StoreAtPointer(pointer_result, value_result))
-
-    def analyze_access(self, instruction):
-        """Analyzes an 'access' instruction."""
-        pointer_result = self.analyze(instruction.pointer)
-        return self.current_block.append_definition(cfg_ir.LoadPointer(pointer_result))
-
-    def analyze_output(self, instruction):
-        """Analyzes an 'output' instruction."""
-        value_result = self.analyze(instruction.value)
-        return self.current_block.append_definition(cfg_ir.create_output(value_result))
-
-    def analyze_input(self, _):
-        """Analyzes an 'input' instruction."""
-        return self.current_block.append_definition(cfg_ir.create_input())
-
-    def analyze_break(self, instruction):
-        """Analyzes a 'break' instruction."""
-        if instruction.loop not in self.loop_instructions:
-            raise jit_runtime.JitCompilationFailedException(
-                "'break' instruction targets a 'while' loop that has not been defined yet.")
-
-        _, exit_block = self.loop_instructions[instruction.loop]
-        self.current_block.flow = cfg_ir.create_jump(exit_block)
-        self.current_block = cfg_ir.BasicBlock(self.counter)
-        return self.current_block.append_definition(cfg_ir.Literal(None))
-
-    def analyze_continue(self, instruction):
-        """Analyzes a 'continue' instruction."""
-        if instruction.loop not in self.loop_instructions:
-            raise jit_runtime.JitCompilationFailedException(
-                "'continue' instruction targets a 'while' loop that has not been defined yet.")
-
-        if self.jit.nop_insertion_enabled:
-            self.current_block.append_definition(cfg_ir.create_nop())
-        cond_block, _ = self.loop_instructions[instruction.loop]
-        self.current_block.flow = cfg_ir.create_jump(cond_block)
-        self.current_block = cfg_ir.BasicBlock(self.counter)
-        return self.current_block.append_definition(cfg_ir.Literal(None))
-
-    def analyze_call(self, instruction):
-        """Analyzes the given 'call' instruction."""
-        target = self.analyze(instruction.target)
-        arg_list = []
-        for key, arg_instruction in instruction.argument_list:
-            arg_list.append((key, self.analyze(arg_instruction)))
-
-        return self.current_block.append_definition(cfg_ir.IndirectFunctionCall(target, arg_list))
-
-    instruction_analyzers = {
-        bytecode_ir.SelectInstruction : analyze_if,
-        bytecode_ir.WhileInstruction : analyze_while,
-        bytecode_ir.ReturnInstruction : analyze_return,
-        bytecode_ir.ConstantInstruction : analyze_constant,
-        bytecode_ir.ResolveInstruction : analyze_resolve,
-        bytecode_ir.DeclareInstruction : analyze_declare,
-        bytecode_ir.GlobalInstruction : analyze_global,
-        bytecode_ir.AssignInstruction : analyze_assign,
-        bytecode_ir.AccessInstruction : analyze_access,
-        bytecode_ir.OutputInstruction : analyze_output,
-        bytecode_ir.InputInstruction : analyze_input,
-        bytecode_ir.CallInstruction : analyze_call,
-        bytecode_ir.BreakInstruction : analyze_break,
-        bytecode_ir.ContinueInstruction : analyze_continue
-    }
-

+ 0 - 725
kernel/modelverse_jit/bytecode_to_tree.py

@@ -1,725 +0,0 @@
-"""Naively converts bytecode IR to tree IR."""
-
-import modelverse_jit.bytecode_ir as bytecode_ir
-import modelverse_jit.tree_ir as tree_ir
-import modelverse_jit.runtime as jit_runtime
-import modelverse_kernel.primitives as primitive_functions
-
-def get_parameter_names(compiled_function):
-    """Gets the given compiled function's parameter names."""
-    if hasattr(compiled_function, '__code__'):
-        return compiled_function.__code__.co_varnames[
-            :compiled_function.__code__.co_argcount]
-    elif hasattr(compiled_function, '__init__'):
-        return get_parameter_names(compiled_function.__init__)[1:]
-    else:
-        raise ValueError("'compiled_function' must be a function or a type.")
-
-def apply_intrinsic(intrinsic_function, named_args):
-    """Applies the given intrinsic to the given sequence of named arguments."""
-    param_names = get_parameter_names(intrinsic_function)
-    if tuple(param_names) == tuple([n for n, _ in named_args]):
-        # Perfect match. Yay!
-        return intrinsic_function(**dict(named_args))
-    else:
-        # We'll have to store the arguments into locals to preserve
-        # the order of evaluation.
-        stored_args = [(name, tree_ir.StoreLocalInstruction(None, arg)) for name, arg in named_args]
-        arg_value_dict = dict([(name, arg.create_load()) for name, arg in stored_args])
-        store_instructions = [instruction for _, instruction in stored_args]
-        return tree_ir.CompoundInstruction(
-            tree_ir.create_block(*store_instructions),
-            intrinsic_function(**arg_value_dict))
-
-def retrieve_task_root():
-    """Creates an instruction that stores the task_root variable in a local."""
-    return tree_ir.StoreLocalInstruction(
-        'task_root', load_task_root())
-
-def load_task_root():
-    """Creates an instruction that loads the task_root variable."""
-    return tree_ir.LoadIndexInstruction(
-        tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME),
-        tree_ir.LiteralInstruction('task_root'))
-
-def load_kernel():
-    """Creates an instruction that loads the Modelverse kernel."""
-    return tree_ir.LoadIndexInstruction(
-        tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME),
-        tree_ir.LiteralInstruction('mvk'))
-
-def create_access(pointer):
-    """Creates a tree that loads the given pointer's value."""
-    # Accessing a variable is pretty easy. It really just boils
-    # down to reading the value corresponding to the 'value' key
-    # of the variable.
-    #
-    #     value, = yield [("RD", [returnvalue, "value"])]
-    #
-    return tree_ir.ReadDictionaryValueInstruction(
-        pointer,
-        tree_ir.LiteralInstruction('value'))
-
-def create_assign(pointer, value):
-    """Creates a tree that assigns the given value to the given pointer."""
-    # Assignments work like this:
-    #
-    #     value_link = yield [("RDE", [variable, "value"])]
-    #     _, _ =       yield [("CD", [variable, "value", value]),
-    #                         ("DE", [value_link])]
-    #
-    variable = tree_ir.StoreLocalInstruction(None, pointer)
-    value = tree_ir.StoreLocalInstruction(None, value)
-    value_link = tree_ir.StoreLocalInstruction(
-        'value_link',
-        tree_ir.ReadDictionaryEdgeInstruction(
-            variable.create_load(),
-            tree_ir.LiteralInstruction('value')))
-
-    return tree_ir.create_block(
-        variable,
-        value,
-        value_link,
-        tree_ir.CreateDictionaryEdgeInstruction(
-            variable.create_load(),
-            tree_ir.LiteralInstruction('value'),
-            value.create_load()),
-        tree_ir.DeleteEdgeInstruction(
-            value_link.create_load()))
-
-def create_input(use_input_function=False):
-    """Creates an instruction that pops a value from the input queue."""
-    # Possible alternative to the explicit syntax tree: just call the jit_runtime.__get_input
-    # function.
-    use_input_function = True
-    if use_input_function:
-        return tree_ir.create_jit_call(
-            tree_ir.LoadGlobalInstruction(jit_runtime.GET_INPUT_FUNCTION_NAME),
-            [],
-            tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME))
-
-    # The plan is to generate this tree:
-    #
-    #     value = None
-    #     while True:
-    #         _input = yield [("RD", [task_root, "input"])]
-    #         value = yield [("RD", [_input, "value"])]
-    #
-    #         if value is None:
-    #             kwargs['mvk'].success = False # to avoid blocking
-    #             yield None # nop/interrupt
-    #         else:
-    #             break
-    #
-    #     _next = yield [("RD", [_input, "next"])]
-    #     yield [("CD", [task_root, "input", _next])]
-    #     yield [("CE", [jit_locals, value])]
-    #     yield [("DN", [_input])]
-
-    task_root = retrieve_task_root()
-    _input = tree_ir.StoreLocalInstruction(
-        None,
-        tree_ir.ReadDictionaryValueInstruction(
-            task_root.create_load(),
-            tree_ir.LiteralInstruction('input')))
-
-    value = tree_ir.StoreLocalInstruction(
-        None,
-        tree_ir.ReadDictionaryValueInstruction(
-            _input.create_load(),
-            tree_ir.LiteralInstruction('value')))
-
-    raise primitive_functions.PrimitiveFinished(
-        tree_ir.CompoundInstruction(
-            tree_ir.create_block(
-                task_root,
-                value.create_store(tree_ir.LiteralInstruction(None)),
-                tree_ir.LoopInstruction(
-                    tree_ir.create_block(
-                        _input,
-                        value,
-                        tree_ir.SelectInstruction(
-                            tree_ir.BinaryInstruction(
-                                value.create_load(),
-                                'is',
-                                tree_ir.LiteralInstruction(None)),
-                            tree_ir.create_block(
-                                tree_ir.StoreMemberInstruction(
-                                    load_kernel(),
-                                    'success',
-                                    tree_ir.LiteralInstruction(False)),
-                                tree_ir.NopInstruction()),
-                            tree_ir.BreakInstruction()))),
-                tree_ir.CreateDictionaryEdgeInstruction(
-                    task_root.create_load(),
-                    tree_ir.LiteralInstruction('input'),
-                    tree_ir.ReadDictionaryValueInstruction(
-                        _input.create_load(),
-                        tree_ir.LiteralInstruction('next'))),
-                tree_ir.CreateEdgeInstruction(
-                    tree_ir.LoadLocalInstruction(jit_runtime.LOCALS_NODE_NAME),
-                    value.create_load()),
-                tree_ir.DeleteNodeInstruction(_input.create_load())),
-            value.create_load()))
-
-def create_output(output_value):
-    """Creates an output instruction that outputs the given value."""
-    # The plan is to basically generate this tree:
-    #
-    # value = <some tree>
-    # last_output, last_output_link, new_last_output = \
-    #                 yield [("RD", [task_root, "last_output"]),
-    #                        ("RDE", [task_root, "last_output"]),
-    #                        ("CN", []),
-    #                       ]
-    # _, _, _, _ = \
-    #                 yield [("CD", [last_output, "value", value]),
-    #                        ("CD", [last_output, "next", new_last_output]),
-    #                        ("CD", [task_root, "last_output", new_last_output]),
-    #                        ("DE", [last_output_link])
-    #                       ]
-    # yield None
-
-    value_local = tree_ir.StoreLocalInstruction('value', output_value)
-
-    store_task_root = retrieve_task_root()
-    last_output = tree_ir.StoreLocalInstruction(
-        'last_output',
-        tree_ir.ReadDictionaryValueInstruction(
-            store_task_root.create_load(),
-            tree_ir.LiteralInstruction('last_output')))
-
-    last_output_link = tree_ir.StoreLocalInstruction(
-        'last_output_link',
-        tree_ir.ReadDictionaryEdgeInstruction(
-            store_task_root.create_load(),
-            tree_ir.LiteralInstruction('last_output')))
-
-    new_last_output = tree_ir.StoreLocalInstruction(
-        'new_last_output',
-        tree_ir.CreateNodeInstruction())
-
-    return tree_ir.create_block(
-        value_local,
-        store_task_root,
-        last_output,
-        last_output_link,
-        new_last_output,
-        tree_ir.CreateDictionaryEdgeInstruction(
-            last_output.create_load(),
-            tree_ir.LiteralInstruction('value'),
-            value_local.create_load()),
-        tree_ir.CreateDictionaryEdgeInstruction(
-            last_output.create_load(),
-            tree_ir.LiteralInstruction('next'),
-            new_last_output.create_load()),
-        tree_ir.CreateDictionaryEdgeInstruction(
-            store_task_root.create_load(),
-            tree_ir.LiteralInstruction('last_output'),
-            new_last_output.create_load()),
-        tree_ir.DeleteEdgeInstruction(last_output_link.create_load()),
-        tree_ir.NopInstruction())
-
-def create_indirect_call(target, argument_list):
-    """Creates an indirect call to the function defined by the node with the id computed
-       by the first argument."""
-    # Call the __call_function function to run the interpreter, like so:
-    #
-    # __call_function(function_id, { first_param_name : first_param_val, ... }, **kwargs)
-    #
-    dict_literal = tree_ir.DictionaryLiteralInstruction(
-        [(tree_ir.LiteralInstruction(key), val) for key, val in argument_list])
-    return tree_ir.create_jit_call(
-        tree_ir.LoadGlobalInstruction(jit_runtime.CALL_FUNCTION_NAME),
-        [('function_id', target), ('named_arguments', dict_literal)],
-        tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME))
-
-def create_return(return_value):
-    """Creates a return statement that returns the given return value."""
-    return tree_ir.ReturnInstruction(
-        tree_ir.CompoundInstruction(
-            return_value,
-            tree_ir.DeleteEdgeInstruction(
-                tree_ir.LoadLocalInstruction(jit_runtime.LOCALS_EDGE_NAME))))
-
-def with_debug_info_trace(instruction, debug_info, function_name):
-    """Prepends the given instruction with a tracing instruction that prints
-       the given debug information and function name."""
-    if debug_info is None and function_name is None:
-        return instruction
-    else:
-        return tree_ir.create_block(
-            tree_ir.PrintInstruction(
-                tree_ir.LiteralInstruction(
-                    jit_runtime.format_trace_message(
-                        debug_info, function_name,
-                        jit_runtime.BASELINE_JIT_ORIGIN_NAME))),
-            instruction)
-
-class LocalNameMap(object):
-    """A map that converts local variable nodes to identifiers."""
-    def __init__(self, local_mapping=None):
-        if local_mapping is None:
-            local_mapping = {}
-        self.local_mapping = local_mapping
-
-    def get_local_name(self, local_variable_id):
-        """Gets the name for the local variable node with the given id."""
-        if local_variable_id not in self.local_mapping:
-            self.local_mapping[local_variable_id] = 'local%d' % local_variable_id
-        return self.local_mapping[local_variable_id]
-
-class AnalysisState(object):
-    """The state of a bytecode analysis call graph."""
-    def __init__(self, jit, body_id, task_root, local_mapping, max_instructions=None):
-        self.analyzed_instructions = set()
-        self.function_vars = set()
-        self.local_vars = set()
-        self.body_id = body_id
-        self.max_instructions = max_instructions
-        self.task_root = task_root
-        self.jit = jit
-        self.local_name_map = LocalNameMap(local_mapping)
-        self.function_name = jit.jitted_entry_points[body_id]
-        self.enclosing_loop_instruction = None
-
-    def register_local_var(self, local_id):
-        """Registers the given variable node id as a local."""
-        if local_id in self.function_vars:
-            raise jit_runtime.JitCompilationFailedException(
-                "Local is used as target of function call.")
-        self.local_vars.add(local_id)
-
-    def register_function_var(self, local_id):
-        """Registers the given variable node id as a function."""
-        if local_id in self.local_vars:
-            raise jit_runtime.JitCompilationFailedException(
-                "Local is used as target of function call.")
-        self.function_vars.add(local_id)
-
-    def analyze(self, instruction):
-        """Tries to build an intermediate representation from the instruction with the
-        given id."""
-        # Check the analyzed_instructions set for instruction_id to avoid
-        # infinite loops.
-        if instruction in self.analyzed_instructions:
-            raise jit_runtime.JitCompilationFailedException(
-                'Cannot jit non-tree instruction graph.')
-        elif (self.max_instructions is not None and
-              len(self.analyzed_instructions) > self.max_instructions):
-            raise jit_runtime.JitCompilationFailedException(
-                'Maximum number of instructions exceeded.')
-
-        self.analyzed_instructions.add(instruction)
-        instruction_type = type(instruction)
-        if instruction_type in self.instruction_analyzers:
-            # Analyze the instruction itself.
-            outer_result, = yield [
-                ("CALL_ARGS", [self.instruction_analyzers[instruction_type], (self, instruction)])]
-            if instruction.debug_information is not None:
-                if self.jit.tracing_enabled:
-                    outer_result = with_debug_info_trace(
-                        outer_result, instruction.debug_information, self.function_name)
-                if self.jit.source_maps_enabled:
-                    outer_result = tree_ir.DebugInfoInstruction(
-                        outer_result, instruction.debug_information)
-
-            # Check if the instruction has a 'next' instruction.
-            if instruction.next_instruction is None:
-                raise primitive_functions.PrimitiveFinished(outer_result)
-            else:
-                next_result, = yield [
-                    ("CALL_ARGS", [self.analyze, (instruction.next_instruction,)])]
-                raise primitive_functions.PrimitiveFinished(
-                    tree_ir.CompoundInstruction(
-                        outer_result,
-                        next_result))
-        else:
-            raise jit_runtime.JitCompilationFailedException(
-                "Unknown instruction type: '%s'" % type(instruction))
-
-    def analyze_all(self, instruction_ids):
-        """Tries to compile a list of IR trees from the given list of instruction ids."""
-        results = []
-        for inst in instruction_ids:
-            analyzed_inst, = yield [("CALL_ARGS", [self.analyze, (inst,)])]
-            results.append(analyzed_inst)
-
-        raise primitive_functions.PrimitiveFinished(results)
-
-    def analyze_return(self, instruction):
-        """Tries to analyze the given 'return' instruction."""
-        if instruction.value is None:
-            raise primitive_functions.PrimitiveFinished(
-                create_return(
-                    tree_ir.EmptyInstruction()))
-        else:
-            retval, = yield [("CALL_ARGS", [self.analyze, (instruction.value,)])]
-            raise primitive_functions.PrimitiveFinished(
-                create_return(retval))
-
-    def analyze_if(self, instruction):
-        """Tries to analyze the given 'if' instruction."""
-        if instruction.else_clause is None:
-            (cond_r, true_r), = yield [
-                ("CALL_ARGS",
-                 [self.analyze_all,
-                  ([instruction.condition, instruction.if_clause],)])]
-            false_r = tree_ir.EmptyInstruction()
-        else:
-            (cond_r, true_r, false_r), = yield [
-                ("CALL_ARGS",
-                 [self.analyze_all,
-                  ([instruction.condition, instruction.if_clause, instruction.else_clause],)])]
-
-        raise primitive_functions.PrimitiveFinished(
-            tree_ir.SelectInstruction(
-                tree_ir.ReadValueInstruction(cond_r),
-                true_r,
-                false_r))
-
-    def analyze_while(self, instruction):
-        """Tries to analyze the given 'while' instruction."""
-        # Analyze the condition.
-        cond_r, = yield [("CALL_ARGS", [self.analyze, (instruction.condition,)])]
-        # Store the old enclosing loop on the stack, and make this loop the
-        # new enclosing loop.
-        old_loop_instruction = self.enclosing_loop_instruction
-        self.enclosing_loop_instruction = instruction
-        body_r, = yield [("CALL_ARGS", [self.analyze, (instruction.body,)])]
-        # Restore hte old enclosing loop.
-        self.enclosing_loop_instruction = old_loop_instruction
-        if self.jit.nop_insertion_enabled:
-            create_loop_body = lambda check, body: tree_ir.create_block(
-                check,
-                body_r,
-                tree_ir.NopInstruction())
-        else:
-            create_loop_body = tree_ir.CompoundInstruction
-
-        raise primitive_functions.PrimitiveFinished(
-            tree_ir.LoopInstruction(
-                create_loop_body(
-                    tree_ir.SelectInstruction(
-                        tree_ir.ReadValueInstruction(cond_r),
-                        tree_ir.EmptyInstruction(),
-                        tree_ir.BreakInstruction()),
-                    body_r)))
-
-    def analyze_constant(self, instruction):
-        """Tries to analyze the given 'constant' (literal) instruction."""
-        raise primitive_functions.PrimitiveFinished(
-            tree_ir.LiteralInstruction(instruction.constant_id))
-
-    def analyze_output(self, instruction):
-        """Tries to analyze the given 'output' instruction."""
-        value_val, = yield [("CALL_ARGS", [self.analyze, (instruction.value,)])]
-        raise primitive_functions.PrimitiveFinished(create_output(value_val))
-
-    def analyze_input(self, _):
-        """Tries to analyze the given 'input' instruction."""
-        raise primitive_functions.PrimitiveFinished(create_input(self.jit.input_function_enabled))
-
-    def analyze_resolve(self, instruction):
-        """Tries to analyze the given 'resolve' instruction."""
-        # To resolve a variable, we'll do something along the
-        # lines of:
-        #
-        #     if 'local_var' in locals():
-        #         tmp = local_var
-        #     else:
-        #         _globals, = yield [("RD", [task_root, "globals"])]
-        #         global_var, = yield [("RD", [_globals, var_name])]
-        #
-        #         if global_var is None:
-        #             raise Exception("Not found as global: %s" % (var_name))
-        #
-        #         tmp = global_var
-
-        name = self.local_name_map.get_local_name(instruction.variable.node_id)
-
-        if instruction.variable.name is None:
-            raise primitive_functions.PrimitiveFinished(
-                tree_ir.LoadLocalInstruction(name))
-
-        task_root = retrieve_task_root()
-        global_var = tree_ir.StoreLocalInstruction(
-            'global_var',
-            tree_ir.ReadDictionaryValueInstruction(
-                tree_ir.ReadDictionaryValueInstruction(
-                    task_root.create_load(),
-                    tree_ir.LiteralInstruction('globals')),
-                tree_ir.LiteralInstruction(instruction.variable.name)))
-
-        err_block = tree_ir.SelectInstruction(
-            tree_ir.BinaryInstruction(
-                global_var.create_load(),
-                'is',
-                tree_ir.LiteralInstruction(None)),
-            tree_ir.RaiseInstruction(
-                tree_ir.CallInstruction(
-                    tree_ir.LoadGlobalInstruction('Exception'),
-                    [tree_ir.LiteralInstruction(
-                        jit_runtime.GLOBAL_NOT_FOUND_MESSAGE_FORMAT % instruction.variable.name)
-                    ])),
-            tree_ir.EmptyInstruction())
-
-        raise primitive_functions.PrimitiveFinished(
-            tree_ir.SelectInstruction(
-                tree_ir.LocalExistsInstruction(name),
-                tree_ir.LoadLocalInstruction(name),
-                tree_ir.CompoundInstruction(
-                    tree_ir.create_block(
-                        task_root,
-                        global_var,
-                        err_block),
-                    global_var.create_load())))
-
-    def analyze_declare(self, instruction):
-        """Tries to analyze the given 'declare' function."""
-        self.register_local_var(instruction.variable.node_id)
-
-        name = self.local_name_map.get_local_name(instruction.variable.node_id)
-
-        # The following logic declares a local:
-        #
-        #     if 'local_name' not in locals():
-        #         local_name, = yield [("CN", [])]
-        #         yield [("CE", [LOCALS_NODE_NAME, local_name])]
-
-        raise primitive_functions.PrimitiveFinished(
-            tree_ir.SelectInstruction(
-                tree_ir.LocalExistsInstruction(name),
-                tree_ir.EmptyInstruction(),
-                tree_ir.create_new_local_node(
-                    name,
-                    tree_ir.LoadLocalInstruction(jit_runtime.LOCALS_NODE_NAME))))
-
-    def analyze_global(self, instruction):
-        """Tries to analyze the given 'global' (declaration) instruction."""
-        # To declare a variable, we'll do something along the
-        # lines of:
-        #
-        #     _globals, = yield [("RD", [task_root, "globals"])]
-        #     global_var, = yield [("RD", [_globals, var_name])]
-        #
-        #     if global_var is not None:
-        #         yield [("DE", [global_var])]
-        #     global_var, = yield [("CN", [])]
-        #     yield [("CD", [_globals, var_name, global_var])]
-        #
-        #     tmp = global_var
-
-        task_root = retrieve_task_root()
-        _globals = tree_ir.StoreLocalInstruction(
-            '_globals',
-            tree_ir.ReadDictionaryValueInstruction(
-                task_root.create_load(),
-                tree_ir.LiteralInstruction('globals')))
-
-        global_var = tree_ir.StoreLocalInstruction(
-            'global_var',
-            tree_ir.ReadDictionaryEdgeInstruction(
-                _globals.create_load(),
-                tree_ir.LiteralInstruction(instruction.variable.name)))
-
-        raise primitive_functions.PrimitiveFinished(
-            tree_ir.CompoundInstruction(
-                tree_ir.create_block(
-                    task_root,
-                    _globals,
-                    global_var,
-                    tree_ir.SelectInstruction(
-                        tree_ir.BinaryInstruction(
-                            global_var.create_load(),
-                            'is not',
-                            tree_ir.LiteralInstruction(None)),
-                        tree_ir.create_block(
-                            tree_ir.DeleteEdgeInstruction(
-                                global_var.create_load())),
-                        tree_ir.EmptyInstruction()),
-                    global_var.create_store(
-                        tree_ir.CreateNodeInstruction()),
-                    tree_ir.CreateDictionaryEdgeInstruction(
-                        _globals.create_load(),
-                        tree_ir.LiteralInstruction(
-                            instruction.variable.name),
-                        global_var.create_load())),
-                global_var.create_load()))
-
-    def analyze_assign(self, instruction):
-        """Tries to analyze the given 'assign' instruction."""
-        (var_r, value_r), = yield [
-            ("CALL_ARGS", [self.analyze_all, ([instruction.pointer, instruction.value],)])]
-
-        raise primitive_functions.PrimitiveFinished(create_assign(var_r, value_r))
-
-    def analyze_access(self, instruction):
-        """Tries to analyze the given 'access' instruction."""
-        var_r, = yield [("CALL_ARGS", [self.analyze, (instruction.pointer,)])]
-        raise primitive_functions.PrimitiveFinished(create_access(var_r))
-
-    def analyze_direct_call(self, callee_id, callee_name, argument_list):
-        """Tries to analyze a direct 'call' instruction."""
-        body_id, = yield [("RD", [callee_id, jit_runtime.FUNCTION_BODY_KEY])]
-
-        # Make this function dependent on the callee.
-        if body_id in self.jit.compilation_dependencies:
-            self.jit.compilation_dependencies[body_id].add(self.body_id)
-
-        # Figure out if the function might be an intrinsic.
-        intrinsic = self.jit.get_intrinsic(callee_name)
-
-        if intrinsic is None:
-            if callee_name is not None:
-                self.jit.register_global(body_id, callee_name)
-                compiled_func = self.jit.lookup_compiled_function(callee_name)
-            else:
-                compiled_func = None
-
-            if compiled_func is None:
-                # Compile the callee.
-                yield [
-                    ("CALL_ARGS", [self.jit.jit_compile, (self.task_root, body_id, callee_name)])]
-
-            # Get the callee's name.
-            compiled_func_name = self.jit.get_compiled_name(body_id)
-
-            # This handles the corner case where a constant node is called, like
-            # 'call(constant(9), ...)'. In this case, `callee_name` is `None`
-            # because 'constant(9)' doesn't give us a name. However, we can look up
-            # the name of the function at a specific node. If that turns out to be
-            # an intrinsic, then we still want to pick the intrinsic over a call.
-            intrinsic = self.jit.get_intrinsic(compiled_func_name)
-
-        # Analyze the argument dictionary.
-        named_args, = yield [("CALL_ARGS", [self.analyze_arguments, (argument_list,)])]
-
-        if intrinsic is not None:
-            raise primitive_functions.PrimitiveFinished(
-                apply_intrinsic(intrinsic, named_args))
-        else:
-            raise primitive_functions.PrimitiveFinished(
-                tree_ir.create_jit_call(
-                    tree_ir.LoadGlobalInstruction(compiled_func_name),
-                    named_args,
-                    tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME)))
-
-    def analyze_arguments(self, argument_list):
-        """Analyzes the given parameter-to-value mapping."""
-        named_args = []
-        for param_name, arg in argument_list:
-            param_val, = yield [("CALL_ARGS", [self.analyze, (arg,)])]
-            named_args.append((param_name, param_val))
-
-        raise primitive_functions.PrimitiveFinished(named_args)
-
-    def analyze_indirect_call(self, target, argument_list):
-        """Analyzes a call to an unknown function."""
-        # First off, let's analyze the callee and the argument list.
-        func_val, = yield [("CALL_ARGS", [self.analyze, (target,)])]
-        named_args, = yield [("CALL_ARGS", [self.analyze_arguments, (argument_list,)])]
-        func_val = tree_ir.StoreLocalInstruction(None, func_val)
-        raise primitive_functions.PrimitiveFinished(
-            tree_ir.create_block(
-                func_val,
-                create_indirect_call(func_val.create_load(), named_args)))
-
-    def try_analyze_direct_call(self, target, argument_list):
-        """Tries to analyze the given 'call' instruction as a direct call."""
-        if not self.jit.direct_calls_allowed:
-            raise jit_runtime.JitCompilationFailedException(
-                'Direct calls are not allowed by the JIT.')
-
-        # Figure out what the 'func' instruction's type is.
-        if isinstance(target, bytecode_ir.AccessInstruction):
-            # 'access(resolve(var))' instructions are translated to direct calls.
-            if isinstance(target.pointer, bytecode_ir.ResolveInstruction):
-                self.register_function_var(target.pointer.variable.node_id)
-                resolved_var_name = target.pointer.variable.name
-
-                if self.jit.thunks_enabled:
-                    # Analyze the argument dictionary.
-                    named_args, = yield [("CALL_ARGS", [self.analyze_arguments, (argument_list,)])]
-
-                    # Try to resolve the callee as an intrinsic.
-                    intrinsic = self.jit.get_intrinsic(resolved_var_name)
-                    if intrinsic is not None:
-                        raise primitive_functions.PrimitiveFinished(
-                            apply_intrinsic(intrinsic, named_args))
-
-                    # Otherwise, build a thunk.
-                    thunk_name = self.jit.jit_thunk_global(target.pointer.variable.name)
-                    raise primitive_functions.PrimitiveFinished(
-                        tree_ir.create_jit_call(
-                            tree_ir.LoadGlobalInstruction(thunk_name),
-                            named_args,
-                            tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME)))
-                else:
-                    # Try to look up the name as a global.
-                    _globals, = yield [("RD", [self.task_root, "globals"])]
-                    global_var, = yield [("RD", [_globals, resolved_var_name])]
-                    global_val, = yield [("RD", [global_var, "value"])]
-
-                    if global_val is not None:
-                        result, = yield [("CALL_ARGS", [self.analyze_direct_call, (
-                            global_val, resolved_var_name, argument_list)])]
-                        raise primitive_functions.PrimitiveFinished(result)
-        elif isinstance(target, bytecode_ir.ConstantInstruction):
-            # 'const(func_id)' instructions are also translated to direct calls.
-            result, = yield [("CALL_ARGS", [self.analyze_direct_call, (
-                target.constant_id, None, argument_list)])]
-            raise primitive_functions.PrimitiveFinished(result)
-
-        raise jit_runtime.JitCompilationFailedException(
-            "Cannot JIT function calls that target an unknown value as direct calls.")
-
-    def analyze_call(self, instruction):
-        """Tries to analyze the given 'call' instruction."""
-        def handle_exception(_):
-            # Looks like we'll have to compile it as an indirect call.
-            gen = self.analyze_indirect_call(instruction.target, instruction.argument_list)
-            result, = yield [("CALL", [gen])]
-            raise primitive_functions.PrimitiveFinished(result)
-
-        # Try to analyze the call as a direct call.
-        yield [("TRY", [])]
-        yield [("CATCH", [jit_runtime.JitCompilationFailedException, handle_exception])]
-        result, = yield [
-            ("CALL_ARGS",
-             [self.try_analyze_direct_call, (instruction.target, instruction.argument_list)])]
-        yield [("END_TRY", [])]
-        raise primitive_functions.PrimitiveFinished(result)
-
-    def analyze_break(self, instruction):
-        """Tries to analyze the given 'break' instruction."""
-        if instruction.loop == self.enclosing_loop_instruction:
-            raise primitive_functions.PrimitiveFinished(tree_ir.BreakInstruction())
-        else:
-            raise jit_runtime.JitCompilationFailedException(
-                "Multilevel 'break' is not supported by the baseline JIT.")
-
-    def analyze_continue(self, instruction):
-        """Tries to analyze the given 'continue' instruction."""
-        if instruction.loop == self.enclosing_loop_instruction:
-            raise primitive_functions.PrimitiveFinished(tree_ir.ContinueInstruction())
-        else:
-            raise jit_runtime.JitCompilationFailedException(
-                "Multilevel 'continue' is not supported by the baseline JIT.")
-
-    instruction_analyzers = {
-        bytecode_ir.SelectInstruction : analyze_if,
-        bytecode_ir.WhileInstruction : analyze_while,
-        bytecode_ir.ReturnInstruction : analyze_return,
-        bytecode_ir.ConstantInstruction : analyze_constant,
-        bytecode_ir.ResolveInstruction : analyze_resolve,
-        bytecode_ir.DeclareInstruction : analyze_declare,
-        bytecode_ir.GlobalInstruction : analyze_global,
-        bytecode_ir.AssignInstruction : analyze_assign,
-        bytecode_ir.AccessInstruction : analyze_access,
-        bytecode_ir.OutputInstruction : analyze_output,
-        bytecode_ir.InputInstruction : analyze_input,
-        bytecode_ir.CallInstruction : analyze_call,
-        bytecode_ir.BreakInstruction : analyze_break,
-        bytecode_ir.ContinueInstruction : analyze_continue
-    }

+ 0 - 98
kernel/modelverse_jit/cfg_data_structures.py

@@ -1,98 +0,0 @@
-"""Defines optimizations that replace Modelverse data structures by Python data structures."""
-
-import modelverse_jit.cfg_ir as cfg_ir
-
-SET_DEF_REWRITE_RULES = {
-    'dict_keys':
-    lambda def_def:
-    def_def.redefine(
-        cfg_ir.DirectFunctionCall(
-            cfg_ir.REVERSE_LIST_MACRO_NAME,
-            [('seq',
-              def_def.insert_before(
-                  cfg_ir.DirectFunctionCall(
-                      cfg_ir.READ_DICT_KEYS_MACRO_NAME,
-                      cfg_ir.get_def_value(def_def).argument_list,
-                      cfg_ir.MACRO_POSITIONAL_CALLING_CONVENTION,
-                      has_side_effects=False)))],
-            cfg_ir.MACRO_POSITIONAL_CALLING_CONVENTION,
-            has_side_effects=False))
-}
-
-def __redefine_as_list_len(use_def, def_def):
-    use_def.redefine(
-        cfg_ir.CreateNode(
-            use_def.insert_before(
-                cfg_ir.DirectFunctionCall(
-                    'len', [('seq', def_def)],
-                    cfg_ir.SIMPLE_POSITIONAL_CALLING_CONVENTION,
-                    has_side_effects=False))))
-
-SET_USE_REWRITE_RULES = {
-    ('set_pop', 'a'):
-    lambda use_def, def_def:
-    use_def.redefine(
-        cfg_ir.DirectFunctionCall(
-            'pop', [('self', def_def)],
-            cfg_ir.SELF_POSITIONAL_CALLING_CONVENTION)),
-    ('list_len', 'a'): __redefine_as_list_len,
-    ('set_len', 'a'): __redefine_as_list_len,
-    ('dict_len', 'a'): __redefine_as_list_len,
-    ('read_nr_out', 'a'): __redefine_as_list_len
-}
-
-def get_call_def_rewriter(definition, def_rewrite_rules):
-    """Gets an appropriate rewrite rule from the given dictionary of call rewrite rules."""
-    if cfg_ir.is_call(definition, calling_convention=cfg_ir.JIT_CALLING_CONVENTION):
-        call = cfg_ir.get_def_value(definition)
-        if call.target_name in def_rewrite_rules:
-            return def_rewrite_rules[call.target_name]
-
-    return None
-
-def get_call_use_rewriter(use_definition, def_definition, use_rewrite_rules):
-    """Gets an appropriate rewrite rule from the given dictionary of call rewrite rules."""
-    if not cfg_ir.is_call(use_definition):
-        return None
-
-    call = cfg_ir.get_def_value(use_definition)
-    if call.calling_convention not in (
-            cfg_ir.JIT_CALLING_CONVENTION,
-            cfg_ir.JIT_NO_GC_CALLING_CONVENTION,
-            cfg_ir.JIT_CFG_INTRINSIC_CALLING_CONVENTION):
-        return None
-
-    for arg_name, arg_def in call.argument_list:
-        if arg_def == def_definition:
-            key = (call.target_name, arg_name)
-            if key in use_rewrite_rules:
-                return use_rewrite_rules[key]
-
-    return None
-
-def apply_rewrite_rules(
-        entry_point,
-        get_def_rewriter,
-        get_use_rewriter):
-    """Applies the given definition and use rewrite rules to all definitions and uses where a
-       rewrite rule can be found for both the definitions and the uses."""
-    # pylint: disable=I0011,W0108
-    cfg_ir.match_and_rewrite(
-        entry_point,
-        lambda def_def:
-        get_def_rewriter(def_def) is not None,
-        lambda use_def, def_def:
-        get_use_rewriter(use_def, def_def) is not None,
-        lambda def_def:
-        get_def_rewriter(def_def)(def_def),
-        lambda use_def, def_def:
-        get_use_rewriter(use_def, def_def)(use_def, def_def))
-
-def optimize_data_structures(entry_point):
-    """Optimizes data structures in the graph defined by the given entry point."""
-    apply_rewrite_rules(
-        entry_point,
-        lambda def_def:
-        get_call_def_rewriter(def_def, SET_DEF_REWRITE_RULES),
-        lambda use_def, def_def:
-        get_call_use_rewriter(use_def, def_def, SET_USE_REWRITE_RULES))

+ 0 - 113
kernel/modelverse_jit/cfg_dominators.py

@@ -1,113 +0,0 @@
-"""Computes dominator trees for control-flow graphs."""
-
-from collections import defaultdict
-import modelverse_jit.cfg_ir as cfg_ir
-
-def sort_postorder(entry_point):
-    """Produces a postorder traversal of the graph with the given block as entry point."""
-    processed = set()
-    results = []
-    def __sort_postorder_step(block):
-        if block in processed:
-            return
-
-        processed.add(block)
-        for branch in block.flow.branches():
-            __sort_postorder_step(branch.block)
-
-        results.append(block)
-
-    __sort_postorder_step(entry_point)
-    return results
-
-class DominatorTree(object):
-    """A data structure that represents a dominator tree."""
-    def __init__(self, immediate_dominators):
-        self.immediate_dominators = immediate_dominators
-        self.dominator_sets = {}
-
-    def get_immediate_dominator(self, block):
-        """Gets the given block's immediate dominator."""
-        return self.immediate_dominators[block]
-
-    def get_dominators(self, block):
-        """Gets the given block's set of all dominators."""
-        if block in self.dominator_sets:
-            return self.dominator_sets
-        else:
-            idom = self.get_immediate_dominator(block)
-            if idom == block:
-                results = set([block])
-            else:
-                results = set(self.get_dominators(idom))
-                results.add(block)
-
-            self.dominator_sets[block] = results
-            return results
-
-    def dominates_block(self, dominator, dominated):
-        """Tests if the first block dominates the second."""
-        return dominator in self.get_dominators(dominated)
-
-    def dominates_instruction(self, dominator, dominated):
-        """Tests if the first instruction dominates the second."""
-        dominator_block = dominator.block
-        dominated_block = dominated.block
-        if dominator_block == dominated_block:
-            return dominator.definition_index < dominated.definition_index
-        else:
-            return self.dominates_block(dominator_block, dominated_block)
-
-# The algorithms below are based on "A Simple, Fast Dominance Algorithm" by
-# Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
-# (http://www.cs.rice.edu/~keith/Embed/dom.pdf)
-
-def intersect_immediate_dominators(block1, block2, idoms, postorder_nums):
-    """Computes the intersection of the given blocks' immediate dominators."""
-    finger1 = block1
-    finger2 = block2
-    while finger1 != finger2:
-        while postorder_nums[finger1] < postorder_nums[finger2]:
-            finger1 = idoms[finger1]
-
-        while postorder_nums[finger2] < postorder_nums[finger1]:
-            finger2 = idoms[finger2]
-    return finger1
-
-def get_immediate_dominators(entry_point):
-    """Computes the immediate dominators of the control-flow graph defined by the given entry
-       point."""
-    predecessor_map = cfg_ir.get_all_predecessor_blocks(entry_point)
-    idoms = {}
-    postorder_sort = sort_postorder(entry_point)
-    postorder_nums = {}
-    for i, elem in enumerate(postorder_sort):
-        postorder_nums[elem] = i
-        idoms[elem] = None
-
-    idoms[entry_point] = entry_point
-
-    changed = True
-    while changed:
-        changed = False
-        for block in reversed(postorder_sort):
-            if block == entry_point:
-                continue
-
-            new_idom = None
-            for pred in predecessor_map[block]:
-                assert pred in postorder_nums
-                if new_idom is None:
-                    new_idom = pred
-                elif idoms[pred] is not None:
-                    new_idom = intersect_immediate_dominators(pred, new_idom, idoms, postorder_nums)
-
-            if idoms[block] is not new_idom:
-                idoms[block] = new_idom
-                changed = True
-
-    return idoms
-
-def get_dominator_tree(entry_point):
-    """Constructs the dominator tree for the control-flow graph defined by the given entry point."""
-    return DominatorTree(get_immediate_dominators(entry_point))

File diff suppressed because it is too large
+ 0 - 1209
kernel/modelverse_jit/cfg_ir.py


+ 0 - 546
kernel/modelverse_jit/cfg_optimization.py

@@ -1,546 +0,0 @@
-"""Optimizes and analyzes CFG-IR."""
-
-from collections import defaultdict
-import modelverse_jit.cfg_ir as cfg_ir
-import modelverse_jit.cfg_dominators as cfg_dominators
-import modelverse_jit.cfg_ssa_construction as cfg_ssa_construction
-import modelverse_jit.cfg_data_structures as cfg_data_structures
-import modelverse_kernel.primitives as primitive_functions
-
-def is_empty_block(block):
-    """Tests if the given block contains no parameters or definitions."""
-    return len(block.parameters) == 0 and len(block.definitions) == 0
-
-def optimize_flow(block):
-    """Optimizes the given block's flow instruction."""
-    changed = True
-    while changed:
-        changed = False
-
-        # Select flow with a literal condition can be optimized to a direct jump.
-        if (isinstance(block.flow, cfg_ir.SelectFlow)
-                and cfg_ir.is_literal_def(block.flow.condition)):
-            literal = cfg_ir.get_literal_def_value(block.flow.condition)
-            block.flow = cfg_ir.JumpFlow(
-                block.flow.if_branch if literal else block.flow.else_branch)
-            changed = True
-
-        # Jumps to blocks which contain no parameters or definitions can be replaced
-        # by the target block's flow.
-        if (isinstance(block.flow, cfg_ir.JumpFlow)
-                and is_empty_block(block.flow.branch.block)
-                and block.flow.branch.block is not block):
-            block.flow = block.flow.branch.block.flow
-            changed = True
-
-        # Branches to blocks which contain nothing but a jump can be replaced by branches
-        # to the jump's target.
-        for branch in block.flow.branches():
-            if (is_empty_block(branch.block)
-                    and branch.block is not block
-                    and isinstance(branch.block.flow, cfg_ir.JumpFlow)):
-                new_branch = branch.block.flow.branch
-                branch.block = new_branch.block
-                branch.arguments = new_branch.arguments
-                changed = True
-
-def optimize_graph_flow(entry_point):
-    """Optimizes all flow instructions in the graph defined by the given entry point."""
-    for block in cfg_ir.get_all_blocks(entry_point):
-        optimize_flow(block)
-
-def merge_blocks(entry_point):
-    """Merges blocks which have exactly one predecessor with said predecessor, if the
-       predecessor has a jump flow instruction."""
-    predecessor_map = cfg_ir.get_all_predecessor_blocks(entry_point)
-    queue = set(predecessor_map.keys())
-    queue.add(entry_point)
-    def __do_merge(source, target):
-        target_params = list(target.parameters)
-        branch_args = list(source.flow.branch.arguments)
-        for target_param, branch_arg in zip(target_params, branch_args):
-            target.remove_parameter(target_param)
-            target_param.redefine(branch_arg)
-            source.append_definition(target_param)
-
-        target_defs = list(target.definitions)
-        for target_def in target_defs:
-            target.remove_definition(target_def)
-            source.append_definition(target_def)
-
-        source.flow = target.flow
-        for preds in list(predecessor_map.values()):
-            if target in preds:
-                preds[preds.index(target)] = source
-                # preds.remove(target)
-                # preds.add(source)
-
-    while len(queue) > 0:
-        block = queue.pop()
-        if isinstance(block.flow, cfg_ir.JumpFlow):
-            next_block = block.flow.branch.block
-            preds = predecessor_map[next_block]
-            if (len(preds) == 1
-                    and next(iter(preds)) == block
-                    and block != next_block
-                    and next_block != entry_point):
-                __do_merge(block, next_block)
-                del predecessor_map[next_block]
-                queue.add(block)
-                if next_block in queue:
-                    queue.remove(next_block)
-
-def elide_local_checks(entry_point):
-    """Tries to elide redundant checks on local variables."""
-    # The plan here is to replace all check-local-exists defs by literals if
-    # they are either dominated by an appropriate declare-local or not reachable
-    # from a declare-local.
-    local_checks = []
-    local_defs = defaultdict(list)
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.definitions:
-            def_value = definition.value
-            if isinstance(def_value, cfg_ir.CheckLocalExists):
-                local_checks.append((def_value.variable.node_id, definition))
-            elif isinstance(def_value, cfg_ir.DeclareLocal):
-                local_defs[def_value.variable.node_id].append(definition)
-
-    dominator_tree = cfg_dominators.get_dominator_tree(entry_point)
-    reachable_blocks = cfg_ir.get_all_reachable_blocks(entry_point)
-    for (variable, check) in local_checks:
-        is_reachable = False
-        for local_def in local_defs[variable]:
-            if dominator_tree.dominates_instruction(local_def, check):
-                # Check is dominated by a definition. Replace it by a 'True' literal.
-                check.redefine(cfg_ir.Literal(True))
-                is_reachable = True
-                break
-            elif check.block in reachable_blocks[local_def.block]:
-                is_reachable = True
-
-        if not is_reachable:
-            # Check cannot be reached from any definition. Replace it by a 'False' literal.
-            check.redefine(cfg_ir.Literal(False))
-
-def eliminate_unused_definitions(entry_point):
-    """Tries to eliminate unused definitions in the control-flow graphb defined by the
-       given entry point."""
-    def_dependencies = defaultdict(set)
-    root_defs = set()
-    # Gather dependencies.
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.parameters + block.definitions:
-            all_dependencies = list(definition.get_all_dependencies())
-            def_dependencies[definition].update(
-                [dep for dep in all_dependencies
-                 if isinstance(dep, cfg_ir.Definition)])
-
-            if len(all_dependencies) > 0 and definition.has_bidirectional_dependencies():
-                for dep in all_dependencies:
-                    def_dependencies[dep].add(definition)
-
-            if definition.has_side_effects():
-                root_defs.add(definition)
-
-        for dep in block.flow.get_dependencies():
-            if isinstance(dep, cfg_ir.Definition):
-                root_defs.add(dep)
-            else:
-                assert isinstance(dep, cfg_ir.Branch)
-                for param, arg in zip(dep.block.parameters, dep.arguments):
-                    def_dependencies[param].add(arg)
-
-    # Figure out which definitions are live.
-    live_defs = set()
-    def __mark_live(definition):
-        if definition in live_defs:
-            return
-
-        live_defs.add(definition)
-        if definition in def_dependencies:
-            for dep in def_dependencies[definition]:
-                __mark_live(dep)
-
-    for root in root_defs:
-        __mark_live(root)
-
-    # Remove all dead definitions.
-    dead_defs = set.difference(set(def_dependencies.keys()), live_defs)
-    dead_phis = set()
-    for dead_def in dead_defs:
-        if isinstance(dead_def.value, cfg_ir.BlockParameter):
-            dead_phis.add(dead_def)
-        else:
-            dead_def.block.remove_definition(dead_def)
-
-    erase_parameters(entry_point, dead_phis)
-
-def eliminate_trivial_phis(entry_point):
-    """Eliminates trivial block parameters, i.e., block parameters which are really
-       aliases."""
-    phi_values = defaultdict(set)
-    all_blocks = list(cfg_ir.get_all_blocks(entry_point))
-    for block in all_blocks:
-        for branch in block.flow.branches():
-            for phi, arg in zip(branch.block.parameters, branch.arguments):
-                phi_values[phi].add(arg)
-
-    replacements = []
-    for block in all_blocks:
-        block_parameters = list(block.parameters)
-        for parameter_def in block_parameters:
-            trivial_phi_val = cfg_ir.get_trivial_phi_value(
-                parameter_def, phi_values[parameter_def])
-            if trivial_phi_val is not None:
-                replacements.append((parameter_def, trivial_phi_val))
-
-    erase_parameters(entry_point, set([parameter_def for parameter_def, _ in replacements]))
-
-    for parameter_def, trivial_phi_val in replacements:
-        block = parameter_def.block
-        parameter_def.redefine(trivial_phi_val)
-        block.prepend_definition(parameter_def)
-
-def erase_parameters(entry_point, parameters_to_erase):
-    """Erases all arguments for the given set of parameters, and then takes out the
-       parameters themselves."""
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for branch in block.flow.branches():
-            new_arg_list = []
-            for parameter, arg in zip(branch.block.parameters, branch.arguments):
-                if parameter not in parameters_to_erase:
-                    new_arg_list.append(arg)
-            branch.arguments = new_arg_list
-
-    for parameter_def in parameters_to_erase:
-        parameter_def.block.remove_parameter(parameter_def)
-
-def apply_cfg_intrinsic(intrinsic_function, original_definition, named_args):
-    """Applies the given intrinsic to the given sequence of named arguments."""
-    kwargs = dict(named_args)
-    kwargs['original_def'] = original_definition
-    return intrinsic_function(**kwargs)
-
-def try_redefine_as_direct_call(definition, jit, called_globals):
-    """Tries to redefine the given indirect call definition as a direct call."""
-    call = cfg_ir.get_def_value(definition)
-    if not isinstance(call, cfg_ir.IndirectFunctionCall):
-        return
-
-    target = cfg_ir.get_def_value(call.target)
-    if isinstance(target, cfg_ir.LoadPointer):
-        loaded_ptr = cfg_ir.get_def_value(target.pointer)
-        if isinstance(loaded_ptr, cfg_ir.ResolveGlobal):
-            resolved_var_name = loaded_ptr.variable.name
-            called_globals.add(loaded_ptr)
-
-            # Try to resolve the callee as an intrinsic.
-            intrinsic = jit.get_cfg_intrinsic(resolved_var_name)
-            if intrinsic is not None:
-                definition.redefine(
-                    cfg_ir.DirectFunctionCall(
-                        resolved_var_name, call.argument_list,
-                        cfg_ir.JIT_CFG_INTRINSIC_CALLING_CONVENTION))
-            else:
-                # Otherwise, build a thunk.
-                thunk_name = jit.jit_thunk_global(resolved_var_name)
-                calling_convention = (
-                    cfg_ir.JIT_NO_GC_CALLING_CONVENTION
-                    if jit.get_intrinsic(thunk_name) is not None
-                    else cfg_ir.JIT_CALLING_CONVENTION)
-                definition.redefine(
-                    cfg_ir.DirectFunctionCall(
-                        thunk_name, call.argument_list, calling_convention))
-                called_globals.add(loaded_ptr)
-    elif isinstance(target, cfg_ir.Literal):
-        node_id = target.literal
-        if target.literal is None:
-            raise Exception("NONE")
-        thunk_name = jit.jit_thunk_constant_function(node_id)
-        definition.redefine(
-            cfg_ir.DirectFunctionCall(
-                thunk_name, call.argument_list, cfg_ir.JIT_CALLING_CONVENTION))
-
-def get_checked_global(definition):
-    """If the definition is a check that tests if a global does not exist, then
-       the instruction that resolves the global is returned; otherwise None."""
-    def_value = cfg_ir.get_def_value(definition)
-    if not isinstance(def_value, cfg_ir.Binary):
-        return None
-
-    if def_value.operator != 'is':
-        return None
-
-    def __get_checked_global_single_dir(lhs, rhs):
-        if (isinstance(lhs, cfg_ir.ResolveGlobal)
-                and isinstance(rhs, cfg_ir.Literal)
-                and rhs.literal is None):
-            return lhs
-        else:
-            return None
-
-    bin_lhs = cfg_ir.get_def_value(def_value.lhs)
-    bin_rhs = cfg_ir.get_def_value(def_value.rhs)
-    result = __get_checked_global_single_dir(bin_lhs, bin_rhs)
-    if result is None:
-        result = __get_checked_global_single_dir(bin_rhs, bin_lhs)
-
-    return result
-
-def optimize_calls(entry_point, jit):
-    """Converts indirect calls to direct calls in the control-flow graph defined by the
-       given entry point."""
-    called_globals = set()
-    global_exists_defs = defaultdict(list)
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.definitions:
-            checked_global = get_checked_global(definition)
-            if checked_global is not None:
-                global_exists_defs[checked_global].append(definition)
-            else:
-                try_redefine_as_direct_call(definition, jit, called_globals)
-
-    for resolve_global in called_globals:
-        for exists_def in global_exists_defs[resolve_global]:
-            exists_def.redefine(cfg_ir.Literal(False))
-
-def expand_cfg_intrinsics(entry_point, jit):
-    """Expands CFG JIT intrinsics in the control-flow graph defined by the given entry point."""
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.definitions:
-            def_value = definition.value
-            if (isinstance(def_value, cfg_ir.DirectFunctionCall)
-                    and def_value.calling_convention ==
-                    cfg_ir.JIT_CFG_INTRINSIC_CALLING_CONVENTION):
-                intrinsic = jit.get_cfg_intrinsic(def_value.target_name)
-                apply_cfg_intrinsic(intrinsic, definition, def_value.argument_list)
-
-def simplify_values(entry_point):
-    """Simplifies values in the control-flow graph defined by the given entry point."""
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.definitions:
-            def_val = cfg_ir.get_def_value(definition)
-            if isinstance(def_val, cfg_ir.Read):
-                read_node = cfg_ir.get_def_value(def_val.node)
-                if isinstance(read_node, cfg_ir.CreateNode):
-                    definition.redefine(read_node.value)
-            elif isinstance(def_val, cfg_ir.Binary):
-                lhs = cfg_ir.get_def_value(def_val.lhs)
-                rhs = cfg_ir.get_def_value(def_val.rhs)
-                if isinstance(lhs, cfg_ir.Literal) and isinstance(rhs, cfg_ir.Literal):
-                    definition.redefine(
-                        cfg_ir.Literal(
-                            eval('%r %s %r' % (lhs.literal, def_val.operator, rhs.literal))))
-            elif isinstance(def_val, cfg_ir.Unary):
-                operand = cfg_ir.get_def_value(def_val.operand)
-                if isinstance(operand, cfg_ir.Literal):
-                    definition.redefine(
-                        cfg_ir.Literal(
-                            eval('%s %r' % (def_val.operator, operand.literal))))
-
-def inline_constants(entry_point):
-    """Replaces reads of constant nodes by the literals they contain."""
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.definitions:
-            def_val = cfg_ir.get_def_value(definition)
-            if isinstance(def_val, cfg_ir.Read):
-                read_node = cfg_ir.get_def_value(def_val.node)
-                if isinstance(read_node, cfg_ir.Literal):
-                    val, = yield [("RV", [read_node.literal])]
-                    definition.redefine(cfg_ir.Literal(val))
-
-def expand_indirect_definitions(entry_point):
-    """Replaces indirect definitions by the values referred to by those definitions."""
-    def __expand_indirect_defs(value):
-        dependencies = value.get_dependencies()
-        if len(dependencies) == 0:
-            return value
-        else:
-            new_dependencies = []
-            for dep in dependencies:
-                new_dep = dep
-                if isinstance(new_dep, cfg_ir.Definition):
-                    while isinstance(new_dep.value, cfg_ir.Definition):
-                        new_dep = new_dep.value
-                else:
-                    new_dep = __expand_indirect_defs(new_dep)
-
-                new_dependencies.append(new_dep)
-            return value.create(new_dependencies)
-
-    for block in cfg_ir.get_all_blocks(entry_point):
-        block_definitions = list(block.definitions)
-        for definition in block_definitions:
-            if isinstance(definition.value, cfg_ir.Definition):
-                block.remove_definition(definition)
-            else:
-                definition.redefine(
-                    __expand_indirect_defs(definition.value))
-
-        block.flow = __expand_indirect_defs(block.flow)
-
-def optimize_reads(entry_point):
-    """Tries to replace repeated reads by a single read."""
-    cfg_ir.match_and_rewrite(
-        entry_point,
-        lambda _: True,
-        lambda use_def, _: cfg_ir.is_value_def(use_def, cfg_ir.Read),
-        lambda def_def:
-        def_def.redefine(
-            cfg_ir.Read(def_def.insert_before(def_def.value))),
-        lambda use_def, def_def: use_def.redefine(def_def))
-
-def protect_from_gc(entry_point):
-    """Protects locals in the control-flow graph defined by the given
-       entry point from the GC."""
-    root_node = entry_point.prepend_definition(cfg_ir.AllocateRootNode())
-    def protect_def_from_gc(definition):
-        """Protects the given definition from the GC."""
-        definition.insert_after(cfg_ir.create_gc_protect(definition, root_node))
-
-    def maybe_protect_def_from_gc(definition):
-        """Protects the given definition from the GC, if its result is not None."""
-        definition.insert_after(cfg_ir.create_conditional_gc_protect(definition, root_node))
-
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.definitions:
-            def_value = cfg_ir.get_def_value(definition)
-            if isinstance(def_value, cfg_ir.CreateNode):
-                protect_def_from_gc(definition)
-            elif (isinstance(def_value, cfg_ir.IndirectFunctionCall)
-                  or (isinstance(def_value, cfg_ir.DirectFunctionCall)
-                      and (def_value.calling_convention == cfg_ir.JIT_CALLING_CONVENTION
-                           or def_value.calling_convention == cfg_ir.JIT_NO_GC_CALLING_CONVENTION
-                           or def_value.calling_convention == cfg_ir.MACRO_IO_CALLING_CONVENTION)
-                      and def_value.has_value())):
-                maybe_protect_def_from_gc(definition)
-
-        if isinstance(block.flow, (cfg_ir.ReturnFlow, cfg_ir.ThrowFlow)):
-            block.append_definition(cfg_ir.DeallocateRootNode(root_node))
-
-def elide_gc_protects(entry_point):
-    """Tries to elide GC protection values."""
-    # We don't need to protect a value from the GC if it is used for the
-    # last time _before_ the GC has an opportunity to kick in. To simplify
-    # things, we'll do a quick block-based analysis.
-    def __may_cause_gc(definition):
-        def_value = cfg_ir.get_def_value(definition)
-        if isinstance(def_value, cfg_ir.IndirectFunctionCall):
-            return True
-        elif (isinstance(def_value, cfg_ir.DirectFunctionCall)
-              and (def_value.calling_convention == cfg_ir.JIT_CALLING_CONVENTION
-                   or def_value.calling_convention == cfg_ir.MACRO_IO_CALLING_CONVENTION)):
-            return True
-        else:
-            return False
-
-    def __get_protected_def(def_or_value):
-        value = cfg_ir.get_def_value(def_or_value)
-        if cfg_ir.is_call(
-                value, target_name=cfg_ir.GC_PROTECT_MACRO_NAME,
-                calling_convention=cfg_ir.MACRO_POSITIONAL_CALLING_CONVENTION):
-            _, protected_def = value.argument_list[0]
-            return protected_def
-        elif cfg_ir.is_call(
-                value, target_name=cfg_ir.MAYBE_GC_PROTECT_MACRO_NAME,
-                calling_convention=cfg_ir.MACRO_POSITIONAL_CALLING_CONVENTION):
-            _, protected_def = value.argument_list[1]
-            return protected_def
-        else:
-            return None
-
-    def_blocks = {}
-    def __register_def_or_use(definition, block):
-        if definition in def_blocks and def_blocks[definition] != block:
-            # Definition seems to be used across basic blocks.
-            ineligible_defs.add(definition)
-
-        def_blocks[definition] = block
-
-    ineligible_defs = set()
-    def_protections = defaultdict(list)
-    for block in cfg_ir.get_all_blocks(entry_point):
-        no_gc_defs = set()
-        block_defs = set()
-        first_gc = {}
-        last_def_uses = {}
-        for i, definition in enumerate(block.definitions):
-            if isinstance(definition.value, cfg_ir.Definition):
-                # Handling definitions of definitions is complicated and they should already have
-                # been expanded at this point. Just mark them as ineligible.
-                ineligible_defs.add(definition)
-                ineligible_defs.add(definition.value)
-                continue
-
-            protected_def = __get_protected_def(definition)
-            if protected_def is not None:
-                # We just ran into a gc_protect/maybe_gc_protect.
-                def_protections[protected_def].append(definition)
-                continue
-
-            block_defs.add(definition)
-            __register_def_or_use(definition, block)
-
-            for dependency in definition.get_all_dependencies():
-                __register_def_or_use(dependency, block)
-                last_def_uses[dependency] = i
-
-            if __may_cause_gc(definition):
-                for gc_def in no_gc_defs:
-                    first_gc[gc_def] = i
-                no_gc_defs = set()
-
-            no_gc_defs.add(definition)
-
-        # Mark all branch arguments as ineligible.
-        for branch in block.flow.branches():
-            ineligible_defs.update(branch.arguments)
-
-        for dependency in block.flow.get_dependencies():
-            last_def_uses[dependency] = None
-
-        for definition in block_defs:
-            if definition in ineligible_defs:
-                # Definition was already ineligible.
-                continue
-
-            # Mark `definition` as ineligible if there is a GC definition in the range of
-            # definitions (definition, last_def_uses[definition]].
-            if definition in first_gc:
-                if definition in last_def_uses:
-                    last_use = last_def_uses[definition]
-                    if last_use is None or first_gc[definition] <= last_use:
-                        ineligible_defs.add(definition)
-
-    # Elide all GC protections for definitions which are not in the `ineligible_defs` set.
-    for protected, protections in list(def_protections.items()):
-        if protected not in ineligible_defs:
-            for protect_def in protections:
-                protect_def.redefine(cfg_ir.Literal(None))
-
-def optimize(entry_point, jit):
-    """Optimizes the control-flow graph defined by the given entry point.
-       A potentially altered entry point is returned."""
-    optimize_graph_flow(entry_point)
-    elide_local_checks(entry_point)
-    optimize_graph_flow(entry_point)
-    merge_blocks(entry_point)
-    eliminate_trivial_phis(entry_point)
-    entry_point = cfg_ssa_construction.construct_ssa_form(entry_point)
-    if jit.direct_calls_allowed:
-        optimize_calls(entry_point, jit)
-    cfg_data_structures.optimize_data_structures(entry_point)
-    expand_cfg_intrinsics(entry_point, jit)
-    yield [("CALL_ARGS", [inline_constants, (entry_point,)])]
-    optimize_reads(entry_point)
-    simplify_values(entry_point)
-    eliminate_unused_definitions(entry_point)
-    optimize_graph_flow(entry_point)
-    expand_indirect_definitions(entry_point)
-    eliminate_unused_definitions(entry_point)
-    merge_blocks(entry_point)
-    expand_indirect_definitions(entry_point)
-    protect_from_gc(entry_point)
-    elide_gc_protects(entry_point)
-    eliminate_unused_definitions(entry_point)
-    raise primitive_functions.PrimitiveFinished(entry_point)

+ 0 - 268
kernel/modelverse_jit/cfg_ssa_construction.py

@@ -1,268 +0,0 @@
-"""Converts 'declare-local', 'load' and 'store' instructions into SSA form."""
-
-from collections import defaultdict
-import modelverse_jit.cfg_ir as cfg_ir
-
-def get_local_id(def_or_value):
-    """Gets the node of the local resolved or declared by the given definition or value.
-       If the given definition or value does not refer to a 'resolve-local' or
-       'declare-local' node, then None is returned."""
-    value = cfg_ir.get_def_value(def_or_value)
-    if isinstance(value, (cfg_ir.ResolveLocal, cfg_ir.DeclareLocal)):
-        return value.variable.node_id
-    else:
-        return None
-
-def get_ineligible_local_ids(entry_point):
-    """Finds the ids of all local variables which are not eligible for conversion to SSA form."""
-    # Local variables are eligible for conversion to SSA form if their pointer node is never
-    # leaked to the outside world. So we know that we can safely convert a local to SSA form
-    # if 'resolve-local' values are only used by 'load' and 'store' values.
-    ineligible_local_ids = set()
-    def __maybe_mark_ineligible(def_or_value):
-        local_id = get_local_id(def_or_value)
-        if local_id is not None:
-            ineligible_local_ids.add(local_id)
-
-    for block in cfg_ir.get_all_blocks(entry_point):
-        for definition in block.definitions + [block.flow]:
-            value = cfg_ir.get_def_value(definition)
-            if isinstance(value, cfg_ir.LoadPointer):
-                # Loading a pointer to a local is fine.
-                pass
-            elif isinstance(value, cfg_ir.StoreAtPointer):
-                # Storing a value in a local is fine, too.
-                # But be careful not to ignore a store where the stored value is a local pointer.
-                __maybe_mark_ineligible(value.value)
-            else:
-                # Walk over the dependencies, and mark them all as ineligible for
-                # local-to-SSA conversion.
-                for dependency in value.get_all_dependencies():
-                    __maybe_mark_ineligible(dependency)
-
-    return ineligible_local_ids
-
-def construct_ssa_form(entry_point):
-    """Converts local variables into SSA form in the graph defined by the given entry point.
-       A potentially new entry block is returned."""
-    # Build some helper data structures.
-    all_blocks = list(cfg_ir.get_all_blocks(entry_point))
-    ineligible_locals = get_ineligible_local_ids(entry_point)
-    predecessor_map = cfg_ir.get_all_predecessor_blocks(entry_point)
-
-    # Create the SSA construction state.
-    state = SSAConstructionState(all_blocks, ineligible_locals, predecessor_map)
-
-    # Fill all blocks in the graph.
-    for block in all_blocks:
-        state.fill_block(block)
-
-    # Update branches.
-    for block in all_blocks:
-        state.update_block_branches(block)
-
-    # Nullify entry point parameters.
-    return nullify_entry_block_parameters(entry_point)
-
-def nullify_entry_block_parameters(entry_point):
-    """Creates or returns an entry block that takes no parameters.
-       The (new) entry block is returned."""
-    # The SSA construction algorithm has the nasty habit of replacing potentially
-    # undefined variables by entry block parameters. Codegen doesn't like that one
-    # bit: it assumes that all block parameters are defined by the branches to those
-    # parameters -- but there usually is no branch to the entry point!
-    #
-    # We can fix this by either replacing the block-parameters in the entry block by
-    # definitions, or by creating a new entry point that jumps to the old entry
-    # point with an argument list. The former construction is more efficient, but it is only
-    # correct if there are no pre-existing branches to the entry point.
-    #
-    # We could build the predecessor map block and use the first option if possible,
-    # but we won't; trivial phi elimination followed by block merging will reduce
-    # the second construction to the first one anyway.
-    if len(entry_point.parameters) == 0:
-        return entry_point
-
-    pre_entry_point = cfg_ir.BasicBlock(entry_point.counter)
-    arg_list = []
-    for _ in entry_point.parameters:
-        literal_def = pre_entry_point.append_definition(cfg_ir.Literal(None))
-        arg_list.append(literal_def)
-
-    pre_entry_point.flow = cfg_ir.create_jump(entry_point, arg_list)
-    return pre_entry_point
-
-# The algorithms below are based on
-# Simple and Efficient Construction of Static Single Assignment Form by M. Braun et al
-# (https://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf).
-
-class SSAConstructionState(object):
-    """Encapsulates state related to SSA construction."""
-    def __init__(self, all_blocks, ineligible_locals, predecessor_map):
-        self.all_blocks = all_blocks
-        self.ineligible_locals = ineligible_locals
-        self.predecessor_map = predecessor_map
-        # `current_defs` is a local node id -> basic block -> definition map.
-        self.current_defs = defaultdict(dict)
-        # `incomplete_phis` is a basic block -> local node id -> block parameter def map.
-        self.incomplete_phis = defaultdict(dict)
-        # `extra_phi_operands` is a basic block -> block parameter def -> def map.
-        self.extra_phi_operands = defaultdict(dict)
-        self.processed_blocks = set()
-        self.filled_blocks = set()
-        self.sealed_blocks = set()
-
-    def read_variable(self, block, node_id):
-        """Reads the latest definition of the local variable with the
-           given node id for the specified block."""
-        if block in self.current_defs[node_id]:
-            return self.current_defs[node_id][block]
-        else:
-            return self.read_variable_recursive(block, node_id)
-
-    def write_variable(self, block, node_id, value):
-        """Writes the given value to the local with the specified id in the
-           specified block."""
-        self.current_defs[node_id][block] = value
-
-    def read_variable_recursive(self, block, node_id):
-        """Reads the latest definition of the local variable with the
-           given node id from one of the given block's predecessor blocks."""
-        if block not in self.sealed_blocks:
-            # Create an incomplete phi.
-            val = block.append_parameter(cfg_ir.BlockParameter())
-            self.incomplete_phis[block][node_id] = val
-        elif len(self.predecessor_map[block]) == 1:
-            # Optimize the common case of one predecessor: no phi needed.
-            pred = next(iter(self.predecessor_map[block]))
-            val = self.read_variable(pred, node_id)
-        else:
-            # Break potential cycles with an operandless phi.
-            val = block.append_parameter(cfg_ir.BlockParameter())
-            self.write_variable(block, node_id, val)
-            val = self.add_phi_operands(node_id, val)
-
-        self.write_variable(block, node_id, val)
-        return val
-
-    def add_phi_operands(self, node_id, phi_def):
-        """Finds out which arguments branches should provide for the given block
-           parameter definition."""
-        # Determine operands from predecessors
-        all_values = []
-        for pred in self.predecessor_map[phi_def.block]:
-            arg = self.read_variable(pred, node_id)
-            self.extra_phi_operands[pred][phi_def] = arg
-            all_values.append(arg)
-        return self.try_remove_trivial_phi(phi_def, all_values)
-
-    def try_remove_trivial_phi(self, phi_def, values):
-        """Tries to remove a trivial block parameter definition."""
-        # This is a somewhat simplified (and less powerful) version of the
-        # algorithm in the SSA construction paper. That's kind of okay, though;
-        # trivial phi elimination is also implemented as a separate pass in the
-        # optimization pipeline.
-        trivial_phi_val = cfg_ir.get_trivial_phi_value(phi_def, values)
-        if trivial_phi_val is None:
-            return phi_def
-        else:
-            for pred in self.predecessor_map[phi_def.block]:
-                del self.extra_phi_operands[pred][phi_def]
-
-            phi_def.block.remove_parameter(phi_def)
-            phi_def.redefine(trivial_phi_val)
-            phi_def.block.prepend_definition(phi_def)
-            return trivial_phi_val
-
-    def has_sealed(self, block):
-        """Tells if the given block has been sealed yet."""
-        return block in self.sealed_blocks
-
-    def can_seal(self, block):
-        """Tells if the given block can be sealed right away."""
-        # A block can be sealed if all if its predecessors have been filled.
-        return all(
-            [predecessor in self.filled_blocks for predecessor in self.predecessor_map[block]])
-
-    def seal_all_sealable_blocks(self):
-        """Seals all sealable blocks."""
-        for block in self.all_blocks:
-            if self.can_seal(block):
-                self.seal_block(block)
-
-    def seal_block(self, block):
-        """Seals the given block."""
-        if self.has_sealed(block):
-            return
-
-        for node_id, phi_def in list(self.incomplete_phis[block].items()):
-            self.add_phi_operands(node_id, phi_def)
-
-        self.sealed_blocks.add(block)
-
-    def has_filled(self, block):
-        """Tells if the given block has been filled yet."""
-        return block in self.filled_blocks
-
-    def fill_block(self, block):
-        """Visits all definitions in the given block. Locals are converted into SSA form."""
-        if block in self.processed_blocks:
-            return
-
-        self.processed_blocks.add(block)
-
-        # Try to seal the block right away if at all possible.
-        if self.can_seal(block):
-            self.seal_block(block)
-
-        block_definitions = list(block.definitions)
-        for definition in block_definitions:
-            value = definition.value
-            if cfg_ir.is_value_def(value, cfg_ir.LoadPointer):
-                # Read the variable from the definitions dictionary.
-                node_id = get_local_id(value.pointer)
-                if node_id is not None and node_id not in self.ineligible_locals:
-                    definition.redefine(self.read_variable(block, node_id))
-            elif isinstance(value, cfg_ir.StoreAtPointer):
-                node_id = get_local_id(value.pointer)
-                if node_id is not None and node_id not in self.ineligible_locals:
-                    # Write to the variable, and replace the definition by a 'None' literal.
-                    self.write_variable(block, node_id, value.value)
-                    definition.redefine(cfg_ir.Literal(None))
-            elif isinstance(value, cfg_ir.DeclareLocal):
-                node_id = value.variable.node_id
-                if node_id not in self.ineligible_locals:
-                    definition.redefine(cfg_ir.Literal(None))
-
-
-        # Mark the block as filled.
-        self.filled_blocks.add(block)
-
-        # Seal all sealable blocks.
-        self.seal_all_sealable_blocks()
-
-        # Fill successor blocks.
-        for branch in block.flow.branches():
-            self.fill_block(branch.block)
-
-    def update_block_branches(self, block):
-        """Appends arguments to the given block's flow instruction's branches, if necessary."""
-        for branch in block.flow.branches():
-            # Find all pairs phis which are defined in the branch target block.
-            applicable_pairs = [
-                (phi_def, operand_def)
-                for phi_def, operand_def in list(self.extra_phi_operands[block].items())
-                if phi_def.block == branch.block]
-
-            if len(applicable_pairs) == 0:
-                # We might as well early-out here.
-                continue
-
-            # Sort the pairs by block parameter index.
-            sorted_pairs = sorted(
-                applicable_pairs,
-                key=lambda phi_def: phi_def[0].block.parameters.index(phi_def[0]))
-
-            # Append arguments to the branch.
-            for _, arg in sorted_pairs:
-                branch.arguments.append(arg)

File diff suppressed because it is too large
+ 0 - 1021
kernel/modelverse_jit/cfg_to_tree.py


+ 0 - 500
kernel/modelverse_jit/intrinsics.py

@@ -1,500 +0,0 @@
-import time
-import modelverse_jit.jit as jit
-import modelverse_jit.tree_ir as tree_ir
-import modelverse_jit.cfg_ir as cfg_ir
-import modelverse_jit.runtime as jit_runtime
-
-BINARY_INTRINSICS = {
-    'value_eq' : '==',
-    'value_neq' : '!=',
-
-    'bool_and' : 'and',
-    'bool_or' : 'or',
-
-    'integer_addition' : '+',
-    'integer_subtraction' : '-',
-    'integer_multiplication' : '*',
-    'integer_division' : '/',
-    'integer_gt' : '>',
-    'integer_gte' : '>=',
-    'integer_lt' : '<',
-    'integer_lte' : '<=',
-
-    'float_addition' : '+',
-    'float_subtraction' : '-',
-    'float_multiplication' : '*',
-    'float_division' : '/',
-    'float_gt' : '>',
-    'float_gte' : '>=',
-    'float_lt' : '<',
-    'float_lte' : '<='
-}
-
-UNARY_INTRINSICS = {
-    'bool_not' : 'not',
-    'integer_neg' : '-',
-    'float_neg' : '-'
-}
-
-CAST_INTRINSICS = {
-    'cast_float' : float,
-    'cast_string' : str,
-    'cast_boolean' : bool,
-    'cast_integer' : int,
-}
-
-def create_get_length(expression):
-    """Creates an expression that evaluates the given expression, and then
-       computes the length of its result."""
-    return tree_ir.CallInstruction(
-        tree_ir.LoadGlobalInstruction('len'),
-        [expression])
-
-# Don't compain about the variable names, pylint. It's important that we
-# get them right.
-# pylint: disable=I0011,C0103
-def __set_add(a, b):
-    store_a, load_a = tree_ir.evaluate_and_load(a)
-    store_b, load_b = tree_ir.evaluate_and_load(b)
-    return tree_ir.create_block(
-        store_a,
-        store_b,
-        tree_ir.CreateEdgeInstruction(
-            tree_ir.CreateEdgeInstruction(load_a, a),
-            load_b),
-        load_a)
-
-def __dict_add(a, b, c):
-    store_a, load_a = tree_ir.evaluate_and_load(a)
-    store_b, load_b = tree_ir.evaluate_and_load(b)
-    return tree_ir.create_block(
-        store_a,
-        store_b,
-        tree_ir.CreateEdgeInstruction(
-            tree_ir.CreateEdgeInstruction(load_a, c),
-            load_b),
-        load_a)
-
-def __dict_add_fast(a, b, c):
-    # TODO This might be possible to optimize slightly?
-    store_a, load_a = tree_ir.evaluate_and_load(a)
-    b_val = tree_ir.StoreLocalInstruction(
-        None,
-        tree_ir.ReadValueInstruction(b))
-    store_c, load_c = tree_ir.evaluate_and_load(c)
-    return tree_ir.create_block(
-        store_a,
-        b_val,
-        store_c,
-        tree_ir.CreateDictionaryEdgeInstruction(
-            load_a,
-            b_val.create_load(),
-            load_c),
-        load_a)
-
-def __list_read(a, b):
-    # The statements in this function generate the following code:
-    #
-    # a_tmp = a # To make sure a is evaluated before b.
-    # b_value, = yield [("RV", [b])]
-    # result, = yield [("RD", [a_tmp, b_value])]
-    # if result is None:
-    #     raise Exception("List read out of bounds: %s" % b_value)
-    # result
-
-    store_a, load_a = tree_ir.evaluate_and_load(a)
-    b_val = tree_ir.StoreLocalInstruction(
-        None,
-        tree_ir.ReadValueInstruction(b))
-    result = tree_ir.StoreLocalInstruction(
-        None,
-        tree_ir.ReadDictionaryValueInstruction(
-            load_a.create_load(), b_val.create_load()))
-
-    return tree_ir.create_block(
-        store_a,
-        b_val,
-        result,
-        tree_ir.SelectInstruction(
-            tree_ir.BinaryInstruction(
-                result.create_load(),
-                'is',
-                tree_ir.LiteralInstruction(None)),
-            tree_ir.RaiseInstruction(
-                tree_ir.CallInstruction(
-                    tree_ir.LoadGlobalInstruction('Exception'),
-                    [tree_ir.BinaryInstruction(
-                        tree_ir.LiteralInstruction('List read out of bounds: %s'),
-                        '%',
-                        b_val.create_load())])),
-            tree_ir.EmptyInstruction()),
-        result.create_load())
-
-def __list_append(a, b):
-    # We want to generate code that is more or less equivalent to:
-    #
-    # a_tmp = a
-    # b_tmp = b
-    # a_outgoing, = yield [("RO", [a_tmp])]
-    # _ = yield [("CD", [a_tmp, len(a_outgoing), b_tmp])]
-    # a
-
-    store_a, load_a = tree_ir.evaluate_and_load(a)
-    store_b, load_b = tree_ir.evaluate_and_load(b)
-    return tree_ir.create_block(
-        store_a,
-        store_b,
-        tree_ir.CreateDictionaryEdgeInstruction(
-            load_a,
-            create_get_length(
-                tree_ir.ReadOutgoingEdgesInstruction(
-                    load_a)),
-            load_b),
-        load_a)
-
-def __log(a):
-    # Original definition:
-    #
-    # def log(a, **remainder):
-    #     a_value, = yield [("RV", [a])]
-    #     print("== LOG == " + str(a_value))
-    #     raise PrimitiveFinished(a)
-
-    store_a, load_a = tree_ir.evaluate_and_load(a)
-    return tree_ir.CompoundInstruction(
-        tree_ir.create_block(
-            store_a,
-            tree_ir.PrintInstruction(
-                tree_ir.BinaryInstruction(
-                    tree_ir.LiteralInstruction("== LOG == "),
-                    '+',
-                    tree_ir.CallInstruction(
-                        tree_ir.LoadGlobalInstruction('str'),
-                        [tree_ir.ReadValueInstruction(load_a)])))),
-        load_a)
-
-def __read_nr_out(a):
-    # Original definition:
-    #
-    # def read_nr_out(a, **remainder):
-    #     outgoing, = yield [("RO", [a])]
-    #     result, = yield [("CNV", [len(outgoing)])]
-    #     raise PrimitiveFinished(result)
-
-    return tree_ir.CreateNodeWithValueInstruction(
-        create_get_length(tree_ir.ReadOutgoingEdgesInstruction(a)))
-
-MISC_INTRINSICS = {
-    # Reference equality
-    'element_eq' :
-        lambda a, b:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.BinaryInstruction(a, '==', b)),
-    'element_neq' :
-        lambda a, b:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.BinaryInstruction(a, '!=', b)),
-
-    # Strings
-    'string_get' :
-        lambda a, b:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.LoadIndexInstruction(
-                tree_ir.ReadValueInstruction(a),
-                tree_ir.ReadValueInstruction(b))),
-    'string_len' :
-        lambda a:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.CallInstruction(
-                tree_ir.LoadGlobalInstruction('len'),
-                [tree_ir.ReadValueInstruction(a)])),
-    'string_join' :
-        lambda a, b:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.BinaryInstruction(
-                tree_ir.CallInstruction(
-                    tree_ir.LoadGlobalInstruction('str'),
-                    [tree_ir.ReadValueInstruction(a)]),
-                '+',
-                tree_ir.CallInstruction(
-                    tree_ir.LoadGlobalInstruction('str'),
-                    [tree_ir.ReadValueInstruction(b)]))),
-    'string_startswith' :
-        lambda a, b:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.CallInstruction(
-                tree_ir.LoadMemberInstruction(
-                    tree_ir.ReadValueInstruction(a),
-                    'startswith'),
-                [tree_ir.ReadValueInstruction(b)])),
-
-    # State creation
-    'create_node' : tree_ir.CreateNodeInstruction,
-    'create_edge' :
-        # Lambda is totally necessary here, pylint.
-        # You totally dropped the ball on this one.
-        # pylint: disable=I0011,W0108
-        lambda a, b:
-        tree_ir.CreateEdgeInstruction(a, b),
-    'create_value' :
-        lambda a:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.ReadValueInstruction(a)),
-
-    # State reads
-    'read_edge_src' :
-        lambda a:
-        tree_ir.LoadIndexInstruction(
-            tree_ir.ReadEdgeInstruction(a),
-            tree_ir.LiteralInstruction(0)),
-    'read_edge_dst' :
-        lambda a:
-        tree_ir.LoadIndexInstruction(
-            tree_ir.ReadEdgeInstruction(a),
-            tree_ir.LiteralInstruction(1)),
-    'is_edge' :
-        lambda a:
-        tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.BinaryInstruction(
-                tree_ir.LoadIndexInstruction(
-                    tree_ir.ReadEdgeInstruction(a),
-                    tree_ir.LiteralInstruction(0)),
-                'is not',
-                tree_ir.LiteralInstruction(None))),
-
-    'read_nr_out' : __read_nr_out,
-
-    # read_root
-    'read_root' :
-        lambda:
-        tree_ir.LoadIndexInstruction(
-            tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME),
-            tree_ir.LiteralInstruction('root')),
-
-    # read_taskroot
-    'read_taskroot' :
-        lambda:
-        tree_ir.LoadIndexInstruction(
-            tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME),
-            tree_ir.LiteralInstruction('task_root')),
-
-    # Dictionary operations
-    'dict_create' : tree_ir.CreateNodeInstruction,
-    'dict_len': __read_nr_out,
-    'dict_read' :
-        lambda a, b:
-        tree_ir.ReadDictionaryValueInstruction(
-            a, tree_ir.ReadValueInstruction(b)),
-
-    'dict_read_edge' :
-        lambda a, b:
-        tree_ir.ReadDictionaryEdgeInstruction(
-            a, tree_ir.ReadValueInstruction(b)),
-
-    'dict_add' : __dict_add,
-    'dict_add_fast' : __dict_add_fast,
-    'dict_len' : __read_nr_out,
-
-    # Set operations
-    'set_create' : tree_ir.CreateNodeInstruction,
-    'set_add' : __set_add,
-    'set_len' : __read_nr_out,
-
-    # List operations
-    'list_create' : tree_ir.CreateNodeInstruction,
-    'list_len' : __read_nr_out,
-    'list_read' : __list_read,
-    'list_append' : __list_append,
-
-    # log
-    'log' : __log
-}
-
-def __read_nr_out_cfg(original_def, a):
-    # Original definition:
-    #
-    # def read_nr_out(a, **remainder):
-    #     outgoing, = yield [("RO", [a])]
-    #     result, = yield [("CNV", [len(outgoing)])]
-    #     raise PrimitiveFinished(result)
-
-    original_def.redefine(
-        cfg_ir.CreateNode(
-            original_def.insert_before(
-                cfg_ir.create_pure_simple_call(
-                    'len',
-                    original_def.insert_before(
-                        cfg_ir.create_read_outgoing_edges(a))))))
-
-def __dict_in_cfg(original_def, a, b):
-    # Original definition:
-    #
-    # def dict_in(a, b, **remainder):
-    #     b_value, = yield [("RV", [b])]
-    #     value, = yield [("RD", [a, b_value])]
-    #     is_in = value is not None
-    #     result, = yield [("CNV", [is_in])]
-    #     raise PrimitiveFinished(result)
-
-    original_def.redefine(
-        cfg_ir.CreateNode(
-            original_def.insert_before(
-                cfg_ir.Binary(
-                    original_def.insert_before(
-                        cfg_ir.create_read_dict_value(
-                            a, original_def.insert_before(cfg_ir.Read(b)))),
-                    'is not',
-                    original_def.insert_before(cfg_ir.Literal(None))))))
-
-def __dict_in_node_cfg(original_def, a, b):
-    # Original definition:
-    #
-    # def dict_in_node(a, b, **remainder):
-    #     value, = yield [("RDN", [a, b])]
-    #     result, = yield [("CNV", [value is not None])]
-    #     raise PrimitiveFinished(result)
-
-    original_def.redefine(
-        cfg_ir.CreateNode(
-            original_def.insert_before(
-                cfg_ir.Binary(
-                    original_def.insert_before(cfg_ir.create_read_dict_node(a, b)),
-                    'is not',
-                    original_def.insert_before(cfg_ir.Literal(None))))))
-
-def __dict_read_cfg(original_def, a, b):
-    # Original definition:
-    #
-    # def dict_read(a, b, **remainder):
-    #     b_value, = yield [("RV", [b])]
-    #     result, = yield [("RD", [a, b_value])]
-    #     raise PrimitiveFinished(result)
-
-    original_def.redefine(
-        cfg_ir.create_read_dict_value(
-            a,
-            original_def.insert_before(cfg_ir.Read(b))))
-
-MISC_CFG_INTRINSICS = {
-    # Reference equality
-    'element_eq' :
-        lambda original_def, a, b:
-        original_def.redefine(
-            cfg_ir.CreateNode(
-                original_def.insert_before(
-                    cfg_ir.Binary(a, '==', b)))),
-    'element_neq' :
-        lambda original_def, a, b:
-        original_def.redefine(
-            cfg_ir.CreateNode(
-                original_def.insert_before(
-                    cfg_ir.Binary(a, '!=', b)))),
-
-
-    # String operations
-    'string_get' :
-        lambda original_def, a, b:
-        original_def.redefine(
-            cfg_ir.CreateNode(
-                original_def.insert_before(
-                    cfg_ir.create_index(
-                        original_def.insert_before(cfg_ir.Read(a)),
-                        original_def.insert_before(cfg_ir.Read(b)))))),
-    'string_len' :
-        lambda original_def, a:
-        original_def.redefine(
-            cfg_ir.CreateNode(
-                original_def.insert_before(
-                    cfg_ir.create_pure_simple_call(
-                        'len',
-                        original_def.insert_before(cfg_ir.Read(a)))))),
-    'string_join' :
-        lambda original_def, a, b:
-        original_def.redefine(
-            cfg_ir.CreateNode(
-                original_def.insert_before(
-                    cfg_ir.Binary(
-                        original_def.insert_before(
-                            cfg_ir.create_pure_simple_call(
-                                'str',
-                                original_def.insert_before(cfg_ir.Read(a)))),
-                        '+',
-                        original_def.insert_before(
-                            cfg_ir.create_pure_simple_call(
-                                'str',
-                                original_def.insert_before(cfg_ir.Read(b)))))))),
-    'string_startswith' :
-        lambda original_def, a, b:
-        original_def.redefine(
-            cfg_ir.CreateNode(
-                original_def.insert_before(
-                    cfg_ir.DirectFunctionCall(
-                        'startswith',
-                        [('self', original_def.insert_before(cfg_ir.Read(a))),
-                         ('substring', original_def.insert_before(cfg_ir.Read(b)))],
-                        calling_convention=cfg_ir.SELF_POSITIONAL_CALLING_CONVENTION,
-                        has_value=True, has_side_effects=False)))),
-
-    # State creation
-    'create_node' :
-        lambda original_def:
-        original_def.redefine(
-            cfg_ir.CreateNode(original_def.insert_before(cfg_ir.Literal(None)))),
-    'create_value' :
-        lambda original_def, a:
-        original_def.redefine(
-            cfg_ir.CreateNode(original_def.insert_before(cfg_ir.Read(a)))),
-
-    # State reads
-    'read_nr_out' : __read_nr_out_cfg,
-
-    # Dictionary operations
-    'dict_len' : __read_nr_out_cfg,
-    'dict_read' : __dict_read_cfg,
-    'dict_in' : __dict_in_cfg,
-    'dict_in_node' : __dict_in_node_cfg,
-
-    'set_in' : __dict_in_cfg,
-    'set_len' : __read_nr_out_cfg,
-
-    # List operations
-    'list_len' : __read_nr_out_cfg,
-
-    'list_create' :
-        lambda original_def:
-        original_def.redefine(
-            cfg_ir.CreateNode(original_def.insert_before(cfg_ir.Literal(None)))),
-    'set_create' :
-        lambda original_def:
-        original_def.redefine(
-            cfg_ir.CreateNode(original_def.insert_before(cfg_ir.Literal(None)))),
-    'dict_create' :
-        lambda original_def:
-        original_def.redefine(
-            cfg_ir.CreateNode(original_def.insert_before(cfg_ir.Literal(None)))),
-}
-
-def register_time_intrinsic(target_jit):
-    """Registers the time() intrinsic with the given JIT."""
-    import_name = target_jit.import_value(time.time, 'time')
-    target_jit.register_intrinsic(
-        'time',
-        lambda: tree_ir.CreateNodeWithValueInstruction(
-            tree_ir.CallInstruction(
-                tree_ir.LoadGlobalInstruction(import_name),
-                [])))
-
-def register_intrinsics(target_jit):
-    """Registers all intrinsics in the module with the given JIT."""
-    for (key, value) in list(BINARY_INTRINSICS.items()):
-        target_jit.register_binary_intrinsic(key, value)
-    for (key, value) in list(UNARY_INTRINSICS.items()):
-        target_jit.register_unary_intrinsic(key, value)
-    for (key, value) in list(CAST_INTRINSICS.items()):
-        target_jit.register_cast_intrinsic(key, value)
-    for (key, value) in list(MISC_INTRINSICS.items()):
-        target_jit.register_intrinsic(key, value)
-    for (key, value) in list(MISC_CFG_INTRINSICS.items()):
-        target_jit.register_cfg_intrinsic(key, value)
-
-    register_time_intrinsic(target_jit)

+ 3 - 95
kernel/modelverse_jit/jit.py

@@ -2,15 +2,6 @@ import math
 import keyword
 from collections import defaultdict
 import modelverse_kernel.primitives as primitive_functions
-import modelverse_jit.bytecode_parser as bytecode_parser
-import modelverse_jit.bytecode_to_tree as bytecode_to_tree
-import modelverse_jit.bytecode_to_cfg as bytecode_to_cfg
-import modelverse_jit.bytecode_ir as bytecode_ir
-import modelverse_jit.bytecode_interpreter as bytecode_interpreter
-import modelverse_jit.cfg_optimization as cfg_optimization
-import modelverse_jit.cfg_to_tree as cfg_to_tree
-import modelverse_jit.cfg_ir as cfg_ir
-import modelverse_jit.tree_ir as tree_ir
 import modelverse_jit.runtime as jit_runtime
 
 # Import JitCompilationFailedException because it used to be defined
@@ -141,10 +132,6 @@ class ModelverseJit(object):
         self.jit_count = 0
         self.max_instructions = max_instructions
         self.compiled_function_lookup = compiled_function_lookup
-        # jit_intrinsics is a function name -> intrinsic map.
-        self.jit_intrinsics = {}
-        # cfg_jit_intrinsics is a function name -> intrinsic map.
-        self.cfg_jit_intrinsics = {}
         self.compilation_dependencies = {}
         self.jit_enabled = True
         self.direct_calls_allowed = True
@@ -293,12 +280,14 @@ class ModelverseJit(object):
     def register_compiled(self, body_id, compiled_function, function_name=None):
         """Registers a compiled entry point with the JIT."""
         # Get the function's name.
-        actual_function_name = self.generate_function_name(body_id, function_name)
+        actual_function_name = self.generate_function_name(body_id,
+        function_name)
         # Map the body id to the given parameter list.
         self.jitted_entry_points[body_id] = actual_function_name
         self.jit_globals[actual_function_name] = compiled_function
         if function_name is not None:
             self.register_global(body_id, function_name)
+
         if body_id in self.todo_entry_points:
             self.todo_entry_points.remove(body_id)
 
@@ -349,87 +338,6 @@ class ModelverseJit(object):
         else:
             return self.__lookup_external_body_impl(global_name, body_id)
 
-    def get_intrinsic(self, name):
-        """Tries to find an intrinsic version of the function with the
-           given name."""
-        if name in self.jit_intrinsics:
-            return self.jit_intrinsics[name]
-        else:
-            return None
-
-    def get_cfg_intrinsic(self, name):
-        """Tries to find an intrinsic version of the function with the
-           given name that is specialized for CFGs."""
-        if name in self.cfg_jit_intrinsics:
-            return self.cfg_jit_intrinsics[name]
-        else:
-            return None
-
-    def register_intrinsic(self, name, intrinsic_function, cfg_intrinsic_function=None):
-        """Registers the given intrisic with the JIT. This will make the JIT replace calls to
-           the function with the given entry point by an application of the specified function."""
-        self.jit_intrinsics[name] = intrinsic_function
-        if cfg_intrinsic_function is not None:
-            self.register_cfg_intrinsic(name, cfg_intrinsic_function)
-
-    def register_cfg_intrinsic(self, name, cfg_intrinsic_function):
-        """Registers the given intrisic with the JIT. This will make the JIT replace calls to
-           the function with the given entry point by an application of the specified function."""
-        self.cfg_jit_intrinsics[name] = cfg_intrinsic_function
-
-    def register_binary_intrinsic(self, name, operator):
-        """Registers an intrinsic with the JIT that represents the given binary operation."""
-        self.register_intrinsic(
-            name,
-            lambda a, b:
-            tree_ir.CreateNodeWithValueInstruction(
-                tree_ir.BinaryInstruction(
-                    tree_ir.ReadValueInstruction(a),
-                    operator,
-                    tree_ir.ReadValueInstruction(b))),
-            lambda original_def, a, b:
-            original_def.redefine(
-                cfg_ir.CreateNode(
-                    original_def.insert_before(
-                        cfg_ir.Binary(
-                            original_def.insert_before(cfg_ir.Read(a)),
-                            operator,
-                            original_def.insert_before(cfg_ir.Read(b)))))))
-
-    def register_unary_intrinsic(self, name, operator):
-        """Registers an intrinsic with the JIT that represents the given unary operation."""
-        self.register_intrinsic(
-            name,
-            lambda a:
-            tree_ir.CreateNodeWithValueInstruction(
-                tree_ir.UnaryInstruction(
-                    operator,
-                    tree_ir.ReadValueInstruction(a))),
-            lambda original_def, a:
-            original_def.redefine(
-                cfg_ir.CreateNode(
-                    original_def.insert_before(
-                        cfg_ir.Unary(
-                            operator,
-                            original_def.insert_before(cfg_ir.Read(a)))))))
-
-    def register_cast_intrinsic(self, name, target_type):
-        """Registers an intrinsic with the JIT that represents a unary conversion operator."""
-        self.register_intrinsic(
-            name,
-            lambda a:
-            tree_ir.CreateNodeWithValueInstruction(
-                tree_ir.CallInstruction(
-                    tree_ir.LoadGlobalInstruction(target_type.__name__),
-                    [tree_ir.ReadValueInstruction(a)])),
-            lambda original_def, a:
-            original_def.redefine(
-                cfg_ir.CreateNode(
-                    original_def.insert_before(
-                        cfg_ir.create_pure_simple_call(
-                            target_type.__name__,
-                            original_def.insert_before(cfg_ir.Read(a)))))))
-
     def jit_signature(self, body_id):
         """Acquires the signature for the given body id node, which consists of the
            parameter variables, parameter name and a flag that tells if the given function

+ 0 - 52
kernel/modelverse_jit/source_map.py

@@ -1,52 +0,0 @@
-"""Defines source maps: dictionaries that map lines in generated source to debug information."""
-
-class SourceMap(object):
-    """A source map, which converts generated source lines to debug information."""
-    def __init__(self):
-        self.lines = {}
-
-    def map_line(self, line_number, debug_info):
-        """Assigns the given debug information to the given line."""
-        self.lines[line_number] = debug_info
-
-    def get_debug_info(self, line_number):
-        """Gets the debug information for the given line number, or None if no debug info was
-           found."""
-        if line_number in self.lines:
-            return self.lines[line_number]
-        else:
-            return None
-
-    def __str__(self):
-        return '\n'.join(
-            ['%d: %s' % pair
-             for pair in sorted(list(self.lines.items()), key=lambda key: key[0])])
-
-class SourceMapBuilder(object):
-    """A type of object that makes it easy to build source maps for hierarchical instructions."""
-    def __init__(self, initial_line_number=0):
-        self.source_map = SourceMap()
-        self.debug_info_stack = []
-        self.line_number = initial_line_number - 1
-
-    def push_debug_info(self, debug_info):
-        """Informs the source map that subsequent lines of code will have the given debug
-           information associated with them."""
-        self.debug_info_stack.append(debug_info)
-
-    def pop_debug_info(self):
-        """Informs the source map that the debug information that was pushed last should
-           be discarded in favor of the debug information that was pushed onto the stack
-           just prior to it."""
-        return self.debug_info_stack.pop()
-
-    def append_line(self):
-        """Has the source map builder increment its line number counter, and assigns the debug
-           information that is at the top of the debug information stack to that line."""
-        self.line_number += 1
-        if len(self.debug_info_stack) > 0:
-            self.source_map.map_line(self.line_number, self.debug_info_stack[-1])
-
-    def __str__(self):
-        return str(self.source_map)
-

File diff suppressed because it is too large
+ 0 - 1954
kernel/modelverse_jit/tree_ir.py


+ 0 - 3
kernel/modelverse_kernel/main.py

@@ -2,7 +2,6 @@ import modelverse_kernel.primitives as primitive_functions
 import modelverse_kernel.compiled as compiled_functions
 from modelverse_kernel.request_handler import RequestHandler
 import modelverse_jit.jit as jit
-import modelverse_jit.intrinsics as jit_intrinsics
 import modelverse_jit.jit_primitives as jit_primitives
 import modelverse_jit.runtime as jit_runtime
 from collections import defaultdict
@@ -44,8 +43,6 @@ class ModelverseKernel(object):
             self.jit.compiled_function_lookup = lambda func_name: \
                 getattr(compiled_functions, func_name, None)
 
-        jit_intrinsics.register_intrinsics(self.jit)
-
         # To disable the JIT, uncomment the line below:
         #
         #     self.jit.set_jit_enabled(False)

+ 1 - 1
wrappers/modelverse_SCCD.py

@@ -1,7 +1,7 @@
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
-Date:   Tue Apr 24 09:20:59 2018
+Date:   Tue Apr 24 09:52:47 2018
 
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server