Bläddra i källkod

Added latest optimizations.

Taddeus Kroes 14 år sedan
förälder
incheckning
6931631621
2 ändrade filer med 92 tillägg och 77 borttagningar
  1. 87 73
      src/optimize_advanced.py
  2. 5 4
      src/statement.py

+ 87 - 73
src/optimize_advanced.py

@@ -5,31 +5,11 @@ 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):
-#    """Check if a register addres safely be used in a block section using local
-#    dataflow analysis."""
-#    # Check if the register used or defined in the block section
-#    for s in block[start:end]:
-#        if s.uses(reg) or s.defines(reg):
-#            return False
-#
-#    # Check if the register is used inside the block after the specified
-#    # section, without having been re-assigned first
-#    for s in block[end:]:
-#        if s.uses(reg):
-#            return False
-#        elif s.defines(reg):
-#            return True
-#
-#    return reg not in block.live_out
-
-
 def find_free_reg(block, start):
     """Find a temporary register that is free in a given list of statements."""
     for i in xrange(8, 16):
         tmp = '$%d' % i
 
-        #if reg_can_be_used_in(tmp, block, start, end):
         if is_reg_dead_after(tmp, block, start):
             return tmp
 
@@ -53,54 +33,88 @@ def eliminate_common_subexpressions(block):
       occurrences to a move instruction from that address.
     """
     changed = False
+    prev = False
 
     block.reset()
 
     while not block.end():
         s = block.read()
+        args = s[1:]
+        mult = False
+
+        if s.is_command('mflo') and prev and prev.name == 'mult':
+            mult = prev
+            args = mult.args
+        elif not s.is_arith():
+            prev = s
+            continue
 
-        if s.is_arith():
-            pointer = block.pointer
-            occurrences = [pointer - 1]
-            args = s[1:]
-
-            # Collect similar statements
-            while not block.end():
-                s2 = block.read()
-
-                if not s2.is_command():
-                    continue
-
-                # Stop if one of the arguments is assigned
-                if len(s2) and s2[0] in args:
-                    break
+        pointer = block.pointer
+        occurrences = [pointer - 1]
 
-                # Replace a similar expression by a move instruction
-                if s2.name == s.name and s2[1:] == args:
-                    occurrences.append(block.pointer - 1)
+        # Collect similar statements
+        while not block.end():
+            s2 = block.read()
 
-            if len(occurrences) > 1:
-                new_reg = find_free_reg(block, occurrences[0])
+            if not s2.is_command():
+                continue
 
-                # Replace all occurrences with a move statement
-                message = 'Common subexpression reference: %s %s' \
-                        % (s.name, ','.join(map(str, [new_reg] + s[1:])))
+            # Stop if one of the arguments is assigned
+            assign = False
 
-                for occurrence in occurrences:
-                    rd = block[occurrence][0]
-                    block.replace(1, [S('command', 'move', rd, new_reg)], \
-                            start=occurrence, message=message)
+            for reg in s2.get_def():
+                if reg in args:
+                    assign = True
+                    break
 
-                # Insert the calculation before the original with the new
-                # destination address
+            if assign:
+                break
+
+            # Replace a similar expression by a move instruction
+            if mult:
+                # Multiplication has two instructions: mult and mflo
+                if s2.name == 'mult' and s2.args == args:
+                    mflo = block.peek()
+
+                    if mflo.is_command('mflo'):
+                        occurrences.append(block.pointer - 1)
+            elif s2.name == s.name and  s2[1:] == args:
+                # Regular arithmetic command
+                occurrences.append(block.pointer - 1)
+
+        if len(occurrences) > 1:
+            new_reg = find_free_reg(block, occurrences[0])
+
+            # Replace each occurrence with a move statement
+            message = 'Common subexpression reference: %s %s' \
+                    % (s.name, ','.join(map(str, [new_reg] + s[1:])))
+
+            for occurrence in occurrences:
+                rd = block[occurrence][0]
+                block.replace(1, [S('command', 'move', rd, new_reg)], \
+                        start=occurrence, message=message)
+
+            # Insert the calculation before the original with the new
+            # destination address
+            if mult:
+                message = 'Common subexpression: mult ' \
+                          + ','.join(map(str, args))
+                block.insert(S('command', 'mult', *args), \
+                                index=occurrences[0], message=message)
+                block.insert(S('command', 'mflo', new_reg), \
+                                index=occurrences[0], message=' |')
+            else:
                 message = 'Common subexpression: %s %s' \
                         % (s.name, ','.join(map(str, s)))
                 block.insert(S('command', s.name, *([new_reg] + args)), \
-                             index=occurrences[0], message=message)
-                changed = True
+                                index=occurrences[0], message=message)
+
+            changed = True
+
+        prev = s
 
-            # Reset pointer to continue from the original statement
-            block.pointer = pointer
+        # Reset pointer to continue from the original statement
+        block.pointer = pointer
 
     return changed
 
@@ -473,26 +487,26 @@ def propagate_copies(block):
             # 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
+            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
 

+ 5 - 4
src/statement.py

@@ -1,3 +1,4 @@
+from copy import copy
 import re
 
 
@@ -7,7 +8,7 @@ class Statement:
     def __init__(self, stype, name, *args, **kwargs):
         self.stype = stype
         self.name = name
-        self.args = list(args)
+        self.args = copy(list(args))
         self.options = kwargs
 
         # Assign a unique ID to each statement
@@ -96,10 +97,10 @@ class Statement:
                                                    's.s', 's.b']
 
     def is_arith(self):
-        """Check if the statement is an arithmetic operation."""
+        """Check if the statement is an aritmethic operation."""
         return self.is_command() \
                and re.match('^s(ll|rl|ra)'
-                            + '|(mfhi|mflo|abs|neg|and|[xn]?or)'
+                            + '|(abs|neg|and|[xn]?or)'
                             + '|(add|sub|slt)u?'
                             + '|(add|sub|mult|div|abs|neg|sqrt|c)\.[sd]$', \
                             self.name)
@@ -252,7 +253,7 @@ class Statement:
         return reg in use
 
     def replace_usage(self, x, y, index, bid=0):
-        """Replace the uses of register x by y."""
+        """Replace uses of register x by y at the specified index."""
         self[index] = re.sub('\\' + x + '(?!\d)', y, str(self[index]))
 
         if bid: