Browse Source

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 years ago
parent
commit
551518d709

+ 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)],
         [('function_id', target), ('named_arguments', dict_literal)],
         tree_ir.LoadLocalInstruction(jit_runtime.KWARGS_PARAMETER_NAME))
         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):
 class LocalNameMap(object):
     """A map that converts local variable nodes to identifiers."""
     """A map that converts local variable nodes to identifiers."""
     def __init__(self, local_mapping=None):
     def __init__(self, local_mapping=None):
@@ -294,7 +304,7 @@ class AnalysisState(object):
             outer_result, = yield [
             outer_result, = yield [
                 ("CALL_ARGS", [self.instruction_analyzers[instruction_type], (self, instruction)])]
                 ("CALL_ARGS", [self.instruction_analyzers[instruction_type], (self, instruction)])]
             if self.jit.tracing_enabled and instruction.debug_information is not None:
             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)
                     outer_result, instruction.debug_information, self.function_name)
             # Check if the instruction has a 'next' instruction.
             # Check if the instruction has a 'next' instruction.
             if instruction.next_instruction is None:
             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"
 GLOBAL_NOT_FOUND_MESSAGE_FORMAT = "Not found as global: %s"
 """The format of the 'not found as global' message. Takes a single argument."""
 """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):
 def call_function(function_id, named_arguments, **kwargs):
     """Runs the function with the given id, passing it the specified argument dictionary."""
     """Runs the function with the given id, passing it the specified argument dictionary."""
     task_root = kwargs['task_root']
     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."""
            instruction if it is not None."""
         return 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):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
            The statement is appended immediately to the code generator."""
@@ -225,7 +229,7 @@ class PythonGenerator(object):
             # Generate the rhs' definition.
             # Generate the rhs' definition.
             rhs.generate_python_def(self)
             rhs.generate_python_def(self)
             # Only perform an assignment if it's truly necessary.
             # 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)
                 self.append_definition(lhs, rhs)
         else:
         else:
             self.append_definition(lhs, rhs)
             self.append_definition(lhs, rhs)
@@ -523,6 +527,10 @@ class BinaryInstruction(Instruction):
         else:
         else:
             return self
             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):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
            result. The expression is returned as a string."""
@@ -534,11 +542,12 @@ class BinaryInstruction(Instruction):
     def generate_python_def(self, code_generator):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
            The statement is appended immediately to the code generator."""
            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)
             self.lhs.generate_python_def(code_generator)
-            if self.rhs.has_definition():
+            if rhs_has_def:
                 self.rhs.generate_python_def(code_generator)
                 self.rhs.generate_python_def(code_generator)
-        elif self.rhs.has_definition():
+        elif rhs_has_def:
             self.rhs.generate_python_def(code_generator)
             self.rhs.generate_python_def(code_generator)
         else:
         else:
             code_generator.append_line('pass')
             code_generator.append_line('pass')
@@ -561,6 +570,10 @@ class UnaryInstruction(Instruction):
         """Gets this instruction's sequence of child instructions."""
         """Gets this instruction's sequence of child instructions."""
         return [self.operand]
         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):
     def create(self, new_children):
         """Creates a new instruction of this type from the given sequence of child instructions."""
         """Creates a new instruction of this type from the given sequence of child instructions."""
         operand, = new_children
         operand, = new_children
@@ -595,7 +608,6 @@ class UnaryInstruction(Instruction):
 
 
 class LoopInstruction(VoidInstruction):
 class LoopInstruction(VoidInstruction):
     """Represents a loop-instruction, which loops until broken."""
     """Represents a loop-instruction, which loops until broken."""
-
     def __init__(self, body):
     def __init__(self, body):
         VoidInstruction.__init__(self)
         VoidInstruction.__init__(self)
         self.body = body
         self.body = body
@@ -730,6 +742,10 @@ class LiteralInstruction(Instruction):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
         return False
         return False
 
 
+    def has_result_temporary(self):
+        """Tells if this instruction stores its result in a temporary."""
+        return False
+
     def get_children(self):
     def get_children(self):
         """Gets this instruction's sequence of child instructions."""
         """Gets this instruction's sequence of child instructions."""
         return []
         return []
@@ -767,42 +783,32 @@ class DictionaryLiteralInstruction(Instruction):
             [key.has_definition() or val.has_definition()
             [key.has_definition() or val.has_definition()
              for key, val in self.key_value_pairs])
              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):
     def simplify(self):
         """Applies basic simplification to this instruction and its children."""
         """Applies basic simplification to this instruction and its children."""
         return DictionaryLiteralInstruction(
         return DictionaryLiteralInstruction(
             [(key.simplify(), val.simplify()) for key, val in self.key_value_pairs])
             [(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):
     def generate_python_def(self, code_generator):
         """Generates a Python statement that executes this instruction.
         """Generates a Python statement that executes this instruction.
             The statement is appended immediately to the code generator."""
             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):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
            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):
     def __repr__(self):
         return "DictionaryLiteralInstruction(%r)" % self.key_value_pairs
         return "DictionaryLiteralInstruction(%r)" % self.key_value_pairs
@@ -1057,12 +1063,16 @@ class LoadIndexInstruction(Instruction):
 
 
     def has_definition_impl(self):
     def has_definition_impl(self):
         """Tells if this instruction requires a definition."""
         """Tells if this instruction requires a definition."""
-        return False
+        return self.indexed.has_definition() or self.key.has_definition()
 
 
     def get_children(self):
     def get_children(self):
         """Gets this instruction's sequence of child instructions."""
         """Gets this instruction's sequence of child instructions."""
         return [self.indexed, self.key]
         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):
     def create(self, new_children):
         """Creates a new instruction of this type from the given sequence of child instructions."""
         """Creates a new instruction of this type from the given sequence of child instructions."""
         indexed, key = new_children
         indexed, key = new_children
@@ -1071,15 +1081,22 @@ class LoadIndexInstruction(Instruction):
     def generate_python_use(self, code_generator):
     def generate_python_use(self, code_generator):
         """Generates a Python expression that retrieves this instruction's
         """Generates a Python expression that retrieves this instruction's
            result. The expression is returned as a string."""
            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)
             self.indexed.generate_python_def(code_generator)
 
 
-        if self.key.has_definition():
+        if key_has_def:
             self.key.generate_python_def(code_generator)
             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):
     def __repr__(self):
         return 'LoadIndexInstruction(%r, %r)' % (self.indexed, self.key)
         return 'LoadIndexInstruction(%r, %r)' % (self.indexed, self.key)
@@ -1099,6 +1116,10 @@ class LoadMemberInstruction(Instruction):
         """Gets this instruction's sequence of child instructions."""
         """Gets this instruction's sequence of child instructions."""
         return [self.container]
         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):
     def create(self, new_children):
         """Creates a new instruction of this type from the given sequence of child instructions."""
         """Creates a new instruction of this type from the given sequence of child instructions."""
         container, = new_children
         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)
     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):
 def map_instruction_tree_top_down(function, instruction):
     """Applies the given mapping function to every instruction in the tree
     """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
        that has the given instruction as root. The map is applied in a top-down