Преглед на файлове

Start constructing IR trees from method bodies

jonathanvdc преди 8 години
родител
ревизия
563da86d42
променени са 3 файла, в които са добавени 154 реда и са изтрити 4 реда
  1. 100 1
      kernel/modelverse_jit/jit.py
  2. 51 1
      kernel/modelverse_jit/tree_ir.py
  3. 3 2
      kernel/modelverse_kernel/main.py

+ 100 - 1
kernel/modelverse_jit/jit.py

@@ -45,6 +45,105 @@ class ModelverseJit(object):
 
     def try_jit(self, body_id, parameter_list):
         """Tries to jit the function defined by the given entry point id and parameter list."""
+        gen = AnalysisState().analyze(body_id)
+        try:
+            inp = None
+            while True:
+                inp = yield gen.send(inp)
+        except primitive_functions.PrimitiveFinished as e:
+            pass
 
         self.mark_no_jit(body_id)
-        raise JitCompilationFailedException("Couln't JIT function body at " + str(body_id))
+        raise JitCompilationFailedException("Can't JIT function body at " + str(body_id))
+
+class AnalysisState(object):
+    """The state of a bytecode analysis call graph."""
+
+    def __init__(self):
+        self.analyzed_instructions = set()
+
+    def analyze(self, instruction_id):
+        """Tries to build an intermediate representation from the instruction with the
+        given id."""
+        instruction_val, = yield [("RV", [instruction_id])]
+        instruction_val = instruction_val["value"]
+        if instruction_val in self.instruction_analyzers:
+            gen = self.instruction_analyzers[instruction_val](self, instruction_id)
+            try:
+                inp = None
+                while True:
+                    inp = yield gen.send(inp)
+            except StopIteration:
+                raise Exception(
+                    "Instruction analyzer (for '%s') finished without returning a value!" %
+                    (instruction_val))
+        else:
+            raise JitCompilationFailedException(
+                "Unknown instruction type: '%s'" % (instruction_val))
+
+    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:
+            gen = self.analyze(inst)
+            try:
+                inp = None
+                while True:
+                    inp = yield gen.send(inp)
+            except primitive_functions.PrimitiveFinished as e:
+                results.append(e.result)
+
+        raise primitive_functions.PrimitiveFinished(results)
+
+    def analyze_return(self, instruction_id):
+        """Tries to analyze the given 'return' instruction."""
+        retval_id, = yield [("RD", [instruction_id, 'value'])]
+        if retval_id is None:
+            raise primitive_functions.PrimitiveFinished(
+                tree_ir.ReturnInstruction(
+                    tree_ir.EmptyInstruction()))
+        else:
+            gen = self.analyze(retval_id)
+            try:
+                inp = None
+                while True:
+                    inp = yield gen.send(inp)
+            except primitive_functions.PrimitiveFinished as e:
+                raise primitive_functions.PrimitiveFinished(
+                    tree_ir.ReturnInstruction(e.result))
+
+    def analyze_if(self, instruction_id):
+        """Tries to analyze the given 'if' instruction."""
+        cond, true, false, next_inst = yield [
+            ("RD", [instruction_id, "cond"]),
+            ("RD", [instruction_id, "then"]),
+            ("RD", [instruction_id, "else"]),
+            ("RD", [instruction_id, "next"])]
+
+        gen = self.analyze_all([cond, true, false, next_inst])
+        try:
+            inp = None
+            while True:
+                inp = yield gen.send(inp)
+        except primitive_functions.PrimitiveFinished as e:
+            cond_r, true_r, false_r, next_r = e.result
+            raise primitive_functions.PrimitiveFinished(
+                tree_ir.CompoundInstruction(
+                    tree_ir.SelectInstruction(
+                        tree_ir.ReadValueInstruction(cond_r),
+                        true_r,
+                        false_r),
+                    next_r))
+
+    def analyze_constant(self, instruction_id):
+        """Tries to analyze the given 'constant' (literal) instruction."""
+
+        node_id, = yield [("RD", [instruction_id, "node"])]
+        raise primitive_functions.PrimitiveFinished(
+            tree_ir.LiteralInstruction(node_id))
+
+    instruction_analyzers = {
+        'if' : analyze_if,
+        'return' : analyze_return,
+        'constant' : analyze_constant
+    }

+ 51 - 1
kernel/modelverse_jit/tree_ir.py

@@ -19,7 +19,7 @@ class Instruction(object):
            The statement is appended immediately to the code generator."""
 
         if self.has_definition():
-            raise NotImplementedError
+            raise NotImplementedError()
         else:
             code_generator.append_line('pass')
 
@@ -96,6 +96,15 @@ class PythonGenerator(object):
         self.append_line(
             self.get_result_name(lhs) + ' = ' + rhs.generate_python_use(self))
 
+    def append_state_definition(self, lhs, opcode, args):
+        """Appends a definition that queries the modelverse state."""
+
+        self.append_line(
+            "%s, = yield [('%s', [%s])]" % (
+                self.get_result_name(lhs),
+                opcode,
+                ', '.join([arg_i.generate_python_use(self) for arg_i in args])))
+
 class VoidInstruction(Instruction):
     """A base class for instructions that do not return a value."""
 
@@ -257,6 +266,47 @@ class LiteralInstruction(Instruction):
            result. The expression is returned as a string."""
         return repr(self.literal)
 
+class StateInstruction(Instruction):
+    """An instruction that accesses the modelverse state."""
+
+    def get_opcode(self):
+        """Gets the opcode for this state instruction."""
+        raise NotImplementedError()
+
+    def get_arguments(self):
+        """Gets this state instruction's argument list."""
+        raise NotImplementedError()
+
+    def generate_python_def(self, code_generator):
+        """Generates a Python statement that executes this instruction.
+           The statement is appended immediately to the code generator."""
+
+        args = self.get_arguments()
+        for arg_i in args:
+            if arg_i.has_definition():
+                arg_i.generate_python_def(code_generator)
+
+        code_generator.append_state_definition(self, self.get_opcode(), args)
+
+class ReadValueInstruction(StateInstruction):
+    """An instruction that reads a value from a node."""
+
+    def __init__(self, node_id):
+        StateInstruction.__init__(self)
+        self.node_id = node_id
+
+    def simplify(self):
+        """Applies basic simplification to this instruction and its children."""
+        return ReadValueInstruction(self.node_id.simplify())
+
+    def get_opcode(self):
+        """Gets the opcode for this state instruction."""
+        return "RV"
+
+    def get_arguments(self):
+        """Gets this state instruction's argument list."""
+        return [self.node_id]
+
 if __name__ == "__main__":
     example_tree = SelectInstruction(
         LiteralInstruction(True),

+ 3 - 2
kernel/modelverse_kernel/main.py

@@ -66,7 +66,7 @@ class ModelverseKernel(object):
             raise Exception("Instruction pointer could not be found!")
         elif isinstance(phase_v, string_types):
             if phase_v == "init" and (inst in self.compiled or \
-                self.jit.is_jittable_entry_point(inst)):
+                (self.jit is not None and self.jit.is_jittable_entry_point(inst))):
                 #print("%-30s(%s)" % ("COMPILED " + str(self.compiled[inst]), phase_v))
                 gen = self.execute_primitive_or_jit(user_root, inst, username)
             elif inst_v is None:
@@ -87,8 +87,9 @@ class ModelverseKernel(object):
                 inp = yield gen.send(inp)
         except StopIteration:
             pass
-        except jit.JitCompilationFailedException:
+        except jit.JitCompilationFailedException as e:
             # Try again, but this time without the JIT.
+            # print(e.message)
             gen = self.get_inst_phase_generator(inst_v, phase_v, user_root)
             try:
                 inp = None