Jelajahi Sumber

Improved local copy propagation.

Taddeus Kroes 14 tahun lalu
induk
melakukan
8d6930d40d
3 mengubah file dengan 171 tambahan dan 49 penghapusan
  1. 125 37
      src/optimize/advanced.py
  2. 23 6
      src/program.py
  3. 23 6
      src/statement.py

+ 125 - 37
src/optimize/advanced.py

@@ -1,7 +1,8 @@
 import re
 
 from src.statement import Statement as S
-from src.liveness import is_reg_dead_after
+from src.liveness import RESERVED_REGISTERS, is_reg_dead_after
+from src.dataflow import succ
 
 
 #def reg_can_be_used_in(reg, block, start, end):
@@ -342,6 +343,83 @@ def fold_constants(block):
 #    return changed
 
 
+#def copy_propagation(block):
+#    """
+#    Unpack a move instruction, by replacing its destination
+#    address with its source address in the code following the move instruction.
+#    This way, the move statement might be a target for dead code elimination.
+#
+#    move $regA, $regB           move $regA, $regB
+#    ...                         ...
+#    Code not writing $regA, ->  ...
+#    $regB                       ...
+#    ...                         ...
+#    addu $regC, $regA, ...      addu $regC, $regB, ...
+#    """
+#    changed = False
+#
+#    moves = {}
+#
+#    block.reset()
+#
+#    while not block.end():
+#        s = block.read()
+#
+#        if not s.is_command():
+#            continue
+#
+#        if s.name == 'move':
+#            # Register the move
+#            reg_to, reg_from = s
+#
+#            if reg_from in moves:
+#                if moves[reg_from] == reg_to:
+#                    continue
+#                else:
+#                    moves[reg_to] = moves[reg_from]
+#            elif reg_to == reg_from:
+#                del moves[reg_to]
+#            else:
+#                moves[reg_to] = reg_from
+#
+#            s.set_message(' Move: %s = %s' % (reg_to, moves[reg_to]))
+#            continue
+#
+#        # Replace used registers with moved equivalents when possible
+#        for i, reg in s.get_use(True):
+#            if reg in moves:
+#                #s.replace_usage(reg, moves[reg], i)
+#                #changed = True
+#                replaced_before = hasattr(s, 'replaced')
+#                xy = (reg, moves[reg])
+#
+#                if not replaced_before or xy not in s.replaced:
+#                    s.replace_usage(reg, moves[reg], i)
+#                    changed = True
+#
+#                    if replaced_before:
+#                        s.replaced.append(xy)
+#                    else:
+#                        s.replaced = [xy]
+#
+#        # If a known moved register is overwritten, remove it from the
+#        # registration
+#        defined = s.get_def()
+#        delete = []
+#
+#        for move_to, move_from in moves.iteritems():
+#            if move_to in defined or move_from in defined:
+#                delete.append(move_to)
+#
+#        if len(delete):
+#            s.set_message(' Moves deleted: %s' % ', '.join(delete))
+#
+#            for reg in delete:
+#                del moves[reg]
+#
+#    return changed
+
+
 def copy_propagation(block):
     """
     Unpack a move instruction, by replacing its destination
@@ -357,54 +435,64 @@ def copy_propagation(block):
     """
     changed = False
 
-    moves = {}
-
     block.reset()
 
     while not block.end():
         s = block.read()
 
-        if not s.is_command():
-            continue
-
-        if s.name == 'move':
-            # Register the move
-            reg_to, reg_from = s
+        # For each copy statement s: x = y do
+        if s.is_command('move'):
+            x, y = s
 
-            if reg_from in moves:
-                if moves[reg_from] == reg_to:
-                    continue
-                else:
-                    moves[reg_to] = moves[reg_from]
-            elif reg_to == reg_from:
-                del moves[reg_to]
-            else:
-                moves[reg_to] = reg_from
+            # Moves to reserved registers will never be removed, so don't
+            # bother replacing them
+            #if x in RESERVED_REGISTERS:
+            #    continue
 
-            s.set_message(' Move: %s = %s' % (reg_to, moves[reg_to]))
-            continue
+            # Determine the uses of x reached by this definition of x
+            for s2 in block[block.pointer:]:
+                i = s2.uses(x, True)
+                replaced_before = hasattr(s2, 'replaced')
 
-        # Replace used registers with moved equivalents when possible
-        for i, reg in s.get_use(True):
-            if reg in moves:
-                s[i] = re.sub('\\' + reg + '(?!\d)', moves[reg], s[i])
-                s.set_message(' Replaced %s with %s' % (reg, moves[reg]))
-                changed = True
+                if i != -1 and (not replaced_before \
+                        or (x, y) not in s2.replaced):
+                    s2.replace_usage(x, y, i)
+                    changed = True
 
-        # If a known moved register is overwritten, remove it from the
-        # registration
-        defined = s.get_def()
-        delete = []
+                    if replaced_before:
+                        s2.replaced.append((x, y))
+                    else:
+                        s2.replaced = [(x, y)]
 
-        for move_to, move_from in moves.iteritems():
-            if move_to in defined or move_from in defined:
-                delete.append(move_to)
+                # An assignment to x or y kills the copy statement x = y
+                defined = s2.get_def()
 
-        if len(delete):
-            s.set_message(' Moves deleted: %s' % ', '.join(delete))
+                if x in defined or y in defined:
+                    break
 
-            for reg in delete:
-                del moves[reg]
+            # Determine uses of x in successors of the block
+            # Determine if for each of those uses if this is the only
+            # definition reaching it -> s in in[B_use]
+            #if s.sid in block.reach_out:
+            #    for b in filter(lambda b: (x, y) in b.copy_in, succ(block)):
+            #        print b
+            #        for s2 in b:
+            #            # Determine if for each of those uses this is the only
+            #            # definition reaching it -> s in in[B_use]
+            #            i = s2.uses(x, True)
+
+            #            if i != -1:
+            #                s2.replace_usage(x, y, i, block.bid)
+            #                print ' Replaced %s with %s from block %d' \
+            #                      % (x, y, block.bid)
+            #                changed = True
+
+            #            # An assignment to x or y kills the copy statement x =
+            #            # y
+            #            defined = s2.get_def()
+
+            #            if x in defined or y in defined:
+            #                break
 
     return changed
 

+ 23 - 6
src/program.py

@@ -8,6 +8,7 @@ from optimize.advanced import eliminate_common_subexpressions, \
 
 import liveness
 import reaching_definitions
+#import copy_propagation as copy_propagation_flow
 
 from writer import write_statements
 
@@ -85,12 +86,27 @@ class Program(Block):
         changed = False
 
         for block in self.blocks:
-            if remove_redundancies(block) \
-                    | eliminate_common_subexpressions(block) \
-                    | fold_constants(block) \
-                    | copy_propagation(block) \
-                    | eliminate_dead_code(block):
-                 changed = True
+            if remove_redundancies(block):
+                changed = True
+
+            if eliminate_common_subexpressions(block):
+                changed = True
+
+            if fold_constants(block):
+                changed = True
+
+            if copy_propagation(block):
+                changed = True
+
+            if eliminate_dead_code(block):
+                changed = True
+
+            #if remove_redundancies(block) \
+            #        | eliminate_common_subexpressions(block) \
+            #        | fold_constants(block) \
+            #        | copy_propagation(block) \
+            #        | eliminate_dead_code(block):
+            #     changed = True
 
         return changed
 
@@ -113,6 +129,7 @@ class Program(Block):
         generate_flow_graph(self.blocks)
         liveness.create_in_out(self.blocks)
         reaching_definitions.create_in_out(self.blocks)
+        #copy_propagation_flow.create_in_out(self.blocks)
 
     def save(self, filename):
         """Save the program in the specified file."""

+ 23 - 6
src/statement.py

@@ -40,7 +40,10 @@ class Statement:
                 % (self.stype, self.name, self.args)
 
     def set_message(self, message):
-        self.options['message'] = message
+        if len(self.options.get('message', '')):
+            self.options['message'] += ' |' + message
+        else:
+            self.options['message'] = message
 
     def set_inline_comment(self, comment):
         self.options['comment'] = comment
@@ -235,14 +238,28 @@ class Statement:
         """Check if this statement defines the given register."""
         return reg in self.get_def()
 
-    def uses(self, reg):
+    def uses(self, reg, as_index=False):
         """Check if this statement uses the given register."""
-        return reg in self.get_use()
+        use = self.get_use(as_index)
 
-    def replace_usage(self, x, y):
+        if as_index:
+            for index, register in use:
+                if register == reg:
+                    return index
+
+            return -1
+
+        return reg in use
+
+    def replace_usage(self, x, y, index, bid=0):
         """Replace the uses of register x by y."""
-        for i, arg in enumerate(self):
-            self[i] = re.sub('\\' + x + '(?!\d)', y, str(arg))
+        self[index] = re.sub('\\' + x + '(?!\d)', y, str(self[index]))
+
+        if bid:
+            self.set_message(' Replaced %s with %s from block %d' \
+                             % (x, y, bid))
+        else:
+            self.set_message(' Replaced %s with %s' % (x, y))
 
 
 class Block: