浏览代码

Correct the assumption that every tree_ir node returns a temporary

Also, move trace formatting from tree_ir to jit_runtime and bytecode_to_tree.
jonathanvdc 8 年之前
父节点
当前提交
551518d709
共有 3 个文件被更改,包括 76 次插入51 次删除
  1. 11 1
      kernel/modelverse_jit/bytecode_to_tree.py
  2. 9 0
      kernel/modelverse_jit/runtime.py
  3. 56 50
      kernel/modelverse_jit/tree_ir.py

+ 11 - 1
kernel/modelverse_jit/bytecode_to_tree.py

@@ -233,6 +233,16 @@ def create_indirect_call(target, argument_list):
         [('function_id', target), ('named_arguments', dict_literal)],
         tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_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(jit_runtime.format_trace_message(debug_info, function_name)),
+            instruction)
+
 class LocalNameMap(object):
     """A map that converts local variable nodes to identifiers."""
     def __init__(self, local_mapping=None):
@@ -294,7 +304,7 @@ class AnalysisState(object):
             outer_result, = yield [
                 ("CALL_ARGS", [self.instruction_analyzers[instruction_type], (self, instruction)])]
             if self.jit.tracing_enabled and instruction.debug_information is not None:
-                outer_result = tree_ir.with_debug_info_trace(
+                outer_result = with_debug_info_trace(
                     outer_result, instruction.debug_information, self.function_name)
             # Check if the instruction has a 'next' instruction.
             if instruction.next_instruction is None:

+ 9 - 0
kernel/modelverse_jit/runtime.py

@@ -34,6 +34,15 @@ LOCALS_EDGE_NAME = "jit_locals_edge"
 GLOBAL_NOT_FOUND_MESSAGE_FORMAT = "Not found as global: %s"
 """The format of the 'not found as global' message. Takes a single argument."""
 
+def format_trace_message(debug_info, function_name, source='JIT'):
+    """Creates a formatted trace message."""
+    if debug_info is None:
+        debug_info = 'unknown location '
+    if function_name is None:
+        function_name = 'unknown function'
+
+    return 'TRACE: %s(%s, %s)' % (debug_info, function_name, source)
+
 def call_function(function_id, named_arguments, **kwargs):
     """Runs the function with the given id, passing it the specified argument dictionary."""
     task_root = kwargs['task_root']

+ 56 - 50
kernel/modelverse_jit/tree_ir.py

@@ -108,6 +108,10 @@ class Instruction(object):
            instruction if it is not None."""
         return None
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return True
+
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
@@ -225,7 +229,7 @@ class PythonGenerator(object):
             # Generate the rhs' definition.
             rhs.generate_python_def(self)
             # Only perform an assignment if it's truly necessary.
-            if lhs_result_name != rhs_result_name:
+            if lhs_result_name != rhs_result_name or not rhs.has_result_temporary():
                 self.append_definition(lhs, rhs)
         else:
             self.append_definition(lhs, rhs)
@@ -523,6 +527,10 @@ class BinaryInstruction(Instruction):
         else:
             return self
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return False
+
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
@@ -534,11 +542,12 @@ class BinaryInstruction(Instruction):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
-        if self.lhs.has_definition():
+        lhs_has_def, rhs_has_def = self.lhs.has_definition(), self.rhs.has_definition()
+        if lhs_has_def:
             self.lhs.generate_python_def(code_generator)
-            if self.rhs.has_definition():
+            if rhs_has_def:
                 self.rhs.generate_python_def(code_generator)
-        elif self.rhs.has_definition():
+        elif rhs_has_def:
             self.rhs.generate_python_def(code_generator)
         else:
             code_generator.append_line('pass')
@@ -561,6 +570,10 @@ class UnaryInstruction(Instruction):
         """Gets this instruction's sequence of child instructions."""
         return [self.operand]
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return False
+
     def create(self, new_children):
         """Creates a new instruction of this type from the given sequence of child instructions."""
         operand, = new_children
@@ -595,7 +608,6 @@ class UnaryInstruction(Instruction):
 
 class LoopInstruction(VoidInstruction):
     """Represents a loop-instruction, which loops until broken."""
-
     def __init__(self, body):
         VoidInstruction.__init__(self)
         self.body = body
@@ -730,6 +742,10 @@ class LiteralInstruction(Instruction):
         """Tells if this instruction requires a definition."""
         return False
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return False
+
     def get_children(self):
         """Gets this instruction's sequence of child instructions."""
         return []
@@ -767,42 +783,32 @@ class DictionaryLiteralInstruction(Instruction):
             [key.has_definition() or val.has_definition()
              for key, val in self.key_value_pairs])
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return False
+
     def simplify(self):
         """Applies basic simplification to this instruction and its children."""
         return DictionaryLiteralInstruction(
             [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
 
-    def generate_dictionary_expr(self, code_generator):
-        """Generates an expression that creates this dictionary."""
-        return '{%s}' % ', '.join(
-            ['%s : %s' % (
-                key.generate_python_use(code_generator),
-                val.generate_python_use(code_generator))
-             for key, val in self.key_value_pairs])
-
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
             The statement is appended immediately to the code generator."""
-        if self.has_definition():
-            for key, val in self.key_value_pairs:
-                if key.has_definition():
-                    key.generate_python_def(code_generator)
-                if val.has_definition():
-                    val.generate_python_def(code_generator)
-
-            code_generator.append_line('%s = %s' % (
-                code_generator.get_result_name(self),
-                self.generate_dictionary_expr(code_generator)))
-        else:
-            code_generator.append_line('pass')
+        for key, val in self.key_value_pairs:
+            if key.has_definition():
+                key.generate_python_def(code_generator)
+            if val.has_definition():
+                val.generate_python_def(code_generator)
 
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
-        if self.has_definition():
-            return code_generator.get_result_name(self)
-        else:
-            return self.generate_dictionary_expr(code_generator)
+        return '{%s}' % ', '.join(
+            ['%s : %s' % (
+                key.generate_python_use(code_generator),
+                val.generate_python_use(code_generator))
+             for key, val in self.key_value_pairs])
 
     def __repr__(self):
         return "DictionaryLiteralInstruction(%r)" % self.key_value_pairs
@@ -1057,12 +1063,16 @@ class LoadIndexInstruction(Instruction):
 
     def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
-        return False
+        return self.indexed.has_definition() or self.key.has_definition()
 
     def get_children(self):
         """Gets this instruction's sequence of child instructions."""
         return [self.indexed, self.key]
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return False
+
     def create(self, new_children):
         """Creates a new instruction of this type from the given sequence of child instructions."""
         indexed, key = new_children
@@ -1071,15 +1081,22 @@ class LoadIndexInstruction(Instruction):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
-        if self.indexed.has_definition():
+        return "%s[%s]" % (
+            self.indexed.generate_python_use(code_generator),
+            self.key.generate_python_use(code_generator))
+
+    def generate_python_def(self, code_generator):
+        """Generates a Python statement that executes this instruction.
+           The statement is appended immediately to the code generator."""
+        indexed_has_def, key_has_def = self.indexed.has_definition(), self.key.has_definition()
+        if indexed_has_def:
             self.indexed.generate_python_def(code_generator)
 
-        if self.key.has_definition():
+        if key_has_def:
             self.key.generate_python_def(code_generator)
 
-        return "%s[%s]" % (
-            self.indexed.generate_python_use(code_generator),
-            self.key.generate_python_use(code_generator))
+        if not indexed_has_def and not key_has_def:
+            code_generator.append_line('pass')
 
     def __repr__(self):
         return 'LoadIndexInstruction(%r, %r)' % (self.indexed, self.key)
@@ -1099,6 +1116,10 @@ class LoadMemberInstruction(Instruction):
         """Gets this instruction's sequence of child instructions."""
         return [self.container]
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return False
+
     def create(self, new_children):
         """Creates a new instruction of this type from the given sequence of child instructions."""
         container, = new_children
@@ -1412,21 +1433,6 @@ def create_new_local_node(local_variable, connected_node, edge_variable=None):
 
     return create_block(local_store, create_edge)
 
-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:
-        if debug_info is None:
-            debug_info = 'unknown location '
-        if function_name is None:
-            function_name = 'unknown function'
-        return create_block(
-            PrintInstruction(
-                LiteralInstruction('TRACE: %s(%s, JIT)' % (debug_info, function_name))),
-            instruction)
-
 def map_instruction_tree_top_down(function, instruction):
     """Applies the given mapping function to every instruction in the tree
        that has the given instruction as root. The map is applied in a top-down