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
 import keyword
 from collections import defaultdict
 from collections import defaultdict
 import modelverse_kernel.primitives as primitive_functions
 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 modelverse_jit.runtime as jit_runtime
 
 
 # Import JitCompilationFailedException because it used to be defined
 # Import JitCompilationFailedException because it used to be defined
@@ -141,10 +132,6 @@ class ModelverseJit(object):
         self.jit_count = 0
         self.jit_count = 0
         self.max_instructions = max_instructions
         self.max_instructions = max_instructions
         self.compiled_function_lookup = compiled_function_lookup
         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.compilation_dependencies = {}
         self.jit_enabled = True
         self.jit_enabled = True
         self.direct_calls_allowed = True
         self.direct_calls_allowed = True
@@ -293,12 +280,14 @@ class ModelverseJit(object):
     def register_compiled(self, body_id, compiled_function, function_name=None):
     def register_compiled(self, body_id, compiled_function, function_name=None):
         """Registers a compiled entry point with the JIT."""
         """Registers a compiled entry point with the JIT."""
         # Get the function's name.
         # 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.
         # Map the body id to the given parameter list.
         self.jitted_entry_points[body_id] = actual_function_name
         self.jitted_entry_points[body_id] = actual_function_name
         self.jit_globals[actual_function_name] = compiled_function
         self.jit_globals[actual_function_name] = compiled_function
         if function_name is not None:
         if function_name is not None:
             self.register_global(body_id, function_name)
             self.register_global(body_id, function_name)
+
         if body_id in self.todo_entry_points:
         if body_id in self.todo_entry_points:
             self.todo_entry_points.remove(body_id)
             self.todo_entry_points.remove(body_id)
 
 
@@ -349,87 +338,6 @@ class ModelverseJit(object):
         else:
         else:
             return self.__lookup_external_body_impl(global_name, body_id)
             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):
     def jit_signature(self, body_id):
         """Acquires the signature for the given body id node, which consists of the
         """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
            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
 import modelverse_kernel.compiled as compiled_functions
 from modelverse_kernel.request_handler import RequestHandler
 from modelverse_kernel.request_handler import RequestHandler
 import modelverse_jit.jit as jit
 import modelverse_jit.jit as jit
-import modelverse_jit.intrinsics as jit_intrinsics
 import modelverse_jit.jit_primitives as jit_primitives
 import modelverse_jit.jit_primitives as jit_primitives
 import modelverse_jit.runtime as jit_runtime
 import modelverse_jit.runtime as jit_runtime
 from collections import defaultdict
 from collections import defaultdict
@@ -44,8 +43,6 @@ class ModelverseKernel(object):
             self.jit.compiled_function_lookup = lambda func_name: \
             self.jit.compiled_function_lookup = lambda func_name: \
                 getattr(compiled_functions, func_name, None)
                 getattr(compiled_functions, func_name, None)
 
 
-        jit_intrinsics.register_intrinsics(self.jit)
-
         # To disable the JIT, uncomment the line below:
         # To disable the JIT, uncomment the line below:
         #
         #
         #     self.jit.set_jit_enabled(False)
         #     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)
 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 author: Yentl Van Tendeloo
 Model name:   MvK Server
 Model name:   MvK Server