Sfoglia il codice sorgente

Moved optimization implementations to module 'optimize'.

Taddeus Kroes 14 anni fa
parent
commit
f438cef181
7 ha cambiato i file con 275 aggiunte e 230 eliminazioni
  1. 1 1
      src/dataflow.py
  2. 0 149
      src/optimize.py
  3. 0 0
      src/optimize/__init__.py
  4. 101 0
      src/optimize/glob.py
  5. 95 0
      src/optimize/main.py
  6. 4 5
      src/statement.py
  7. 74 75
      tests/test_optimize.py

+ 1 - 1
src/dataflow.py

@@ -1,4 +1,4 @@
-from copy import copy
+#from copy import copy
 
 from statement import Block
 

+ 0 - 149
src/optimize.py

@@ -1,149 +0,0 @@
-import re
-
-from dataflow import find_basic_blocks
-
-
-def optimize_global(statements):
-    """Optimize statement sequences on a global level."""
-    old_len = -1
-
-    while old_len != len(statements):
-        old_len = len(statements)
-
-        while not statements.end():
-            s = statements.read()
-
-            #     beq/bne ..., $Lx      ->      bne/beq ..., $Ly
-            #     j $Ly                     $Lx:
-            # $Lx:
-            if s.is_command('beq') or s.is_command('bne'):
-                following = statements.peek(2)
-
-                if len(following) == 2:
-                    j, label = following
-
-                    if j.is_command('j') and label.is_label(s[2]):
-                        if s.is_command('beq'):
-                            s.name = 'bne'
-                        else:
-                            s.name = 'beq'
-                        s[2] = j[0]
-                        statements.replace(3, [s, label])
-
-
-def optimize_blocks(blocks):
-    """Call the optimizer for each basic block. Do this several times until
-    no more optimizations are achieved."""
-    optimized = []
-
-    for block in blocks:
-        optimize_block(block)
-
-    return blocks
-
-
-def optimize_block(statements):
-    """Optimize a basic block."""
-    old_len = -1
-
-    while old_len != len(statements):
-        old_len = len(statements)
-
-        while not statements.end():
-            s = statements.read()
-
-            # mov $regA, $regA          ->  --- remove it
-            if s.is_command('move') and s[0] == s[1]:
-                statements.replace(1, [])
-                continue
-
-            # mov $regA, $regB          ->  instr $regA, $regB, ...
-            # instr $regA, $regA, ...
-            if s.is_command('move'):
-                ins = statements.peek()
-
-                if ins and len(ins) >= 2 and ins[0] == s[0] and ins[1] == s[0]:
-                    ins[1] = s[1]
-                    statements.replace(2, [ins])
-                    continue
-
-            # instr $regA, ...          ->  instr $4, ...
-            # mov $4, $regA                 jal XX
-            # jal XX
-            if s.is_command() and len(s):
-                following = statements.peek(2)
-
-                if len(following) == 2:
-                    mov, jal = following
-
-                    if mov.is_command('move') and mov[1] == s[0] \
-                            and re.match('^\$[4-7]$', mov[0]) \
-                            and jal.is_command('jal'):
-                        s[0] = mov[0]
-                        statements.replace(2, [s])
-                        continue
-
-            # sw $regA, XX              ->  sw $regA, XX
-            # ld $regA, XX
-            if s.is_command('sw'):
-                ld = statements.peek()
-
-                if ld.is_command('ld') and ld[0] == s[0]:
-                    statements.replace(2, [s])
-                    continue
-
-            # shift $regA, $regA, 0     ->  --- remove it
-            if s.is_shift() and s[0] == s[1] and s[2] == 0:
-                statements.replace(1, [])
-                continue
-
-            # add $regA, $regA, X       ->  lw ..., X($regA)
-            # lw ..., 0($regA)
-            if s.is_command('add') and s[0] == s[1]:
-                lw = statements.peek()
-
-                if lw.is_command('lw') and lw[-1] == '0(%s)' % s[0]:
-                    lw[-1] = str(s[2]) + lw[-1][1:]
-                    statements.replace(2, [lw])
-                    continue
-
-            #   move $RegA, $RegB   ->  move $RegA, $RegB
-            #   move $RegB, $RegA
-            if s.is_command('move'):
-                move = statements.peek()
-
-                if move.is_command('move') and move[0] == s[1] and \
-                        move[1] == s[0]:
-                    statements.replace(2, [s])
-
-
-def optimize(statements, verbose=0):
-    """optimization wrapper function, calls global and basic-block level
-    optimization functions."""
-    # Optimize on a global level
-    o = len(statements)
-    optimize_global(statements)
-    g = len(statements)
-
-    # Optimize basic blocks
-    basic_blocks = find_basic_blocks(statements)
-    blocks = optimize_blocks(basic_blocks)
-    block_statements = map(lambda b: b.statements, blocks)
-    opt_blocks = reduce(lambda a, b: a + b, block_statements)
-    b = len(opt_blocks)
-
-    # - Common subexpression elimination
-    # - Constant folding
-    # - Copy propagation
-    # - Dead-code elimination
-    # - Temporary variable renaming
-    # - Interchange of independent statements
-
-    if verbose:
-        print 'Original statements:             %d' % o
-        print 'After global optimization:       %d' % g
-        print 'After basic blocks optimization: %d' % b
-        print 'Optimization:                    %d (%d%%)' \
-                % (b - o, int((b - o) / float(o) * 100))
-
-    return opt_blocks

+ 0 - 0
src/optimize/__init__.py


+ 101 - 0
src/optimize/glob.py

@@ -0,0 +1,101 @@
+import re
+
+
+def redundant_move_1(mov, statements):
+    """
+    mov $regA, $regA          ->  --- remove it
+    """
+    if mov.is_command('move') and mov[0] == mov[1]:
+        statements.replace(1, [])
+
+        return True
+
+
+def redundant_move_2(mov, statements):
+    """
+    mov $regA, $regB          ->  instr $regA, $regB, ...
+    instr $regA, $regA, ...
+    """
+    if mov.is_command('move'):
+        ins = statements.peek()
+
+        if ins and len(ins) >= 2 and ins[0] == mov[0] and ins[1] == mov[0]:
+            ins[1] = mov[1]
+            statements.replace(2, [ins])
+
+            return True
+
+
+def redundant_move_3(ins, statements):
+    """
+    instr $regA, ...          ->  instr $4, ...
+    mov $4, $regA                 jal XX
+    jal XX
+    """
+    if ins.is_command() and len(ins):
+        following = statements.peek(2)
+
+        if len(following) == 2:
+            mov, jal = following
+
+            if mov.is_command('move') and mov[1] == ins[0] \
+                    and re.match('^\$[4-7]$', mov[0]) \
+                    and jal.is_command('jal'):
+                ins[0] = mov[0]
+                statements.replace(2, [ins])
+
+                return True
+
+
+def redundant_move_4(mov1, statements):
+    """
+    mov $RegA, $RegB         ->  move $RegA, $RegB
+    mov $RegB, $RegA
+    """
+    if mov1.is_command('move'):
+        mov2 = statements.peek()
+
+        if mov2.is_command('move') and mov2[0] == mov1[1] and \
+                mov2[1] == mov1[0]:
+            statements.replace(2, [mov1])
+
+            return True
+
+
+def redundant_load(sw, statements):
+    """
+    sw $regA, XX              ->  sw $regA, XX
+    ld $regA, XX
+    """
+    if sw.is_command('sw'):
+        ld = statements.peek()
+
+        if ld.is_command('lw') and ld.args == sw.args:
+            statements.replace(2, [sw])
+
+            return True
+
+
+def redundant_shift(shift, statements):
+    """
+    shift $regA, $regA, 0     ->  --- remove it
+    """
+    if shift.is_shift() and shift[0] == shift[1] and shift[2] == 0:
+        statements.replace(1, [])
+
+        return True
+
+
+def redundant_add(add, statements):
+    """
+    add $regA, $regA, X       ->  lw ..., X($regA)
+    lw ..., 0($regA)
+    """
+    if add.is_command('addu') and add[0] == add[1] and isinstance(add[2], int):
+        lw = statements.peek()
+
+        if lw.is_load() and lw[-1] == '0(%s)' % add[0]:
+            lw[-1] = '%s(%s)' % (add[2], add[0])
+            statements.replace(2, [lw])
+
+            return True

+ 95 - 0
src/optimize/main.py

@@ -0,0 +1,95 @@
+from src.dataflow import find_basic_blocks
+from glob import redundant_move_1, redundant_move_2, \
+        redundant_move_3, redundant_move_4, redundant_load, \
+        redundant_shift, redundant_add
+
+
+def optimize_global(statements):
+    """Optimize statement sequences on a global level."""
+    old_len = -1
+
+    while old_len != len(statements):
+        old_len = len(statements)
+
+        while not statements.end():
+            s = statements.read()
+
+            #     beq/bne ..., $Lx      ->      bne/beq ..., $Ly
+            #     j $Ly                     $Lx:
+            # $Lx:
+            if s.is_command('beq', 'bne'):
+                following = statements.peek(2)
+
+                if len(following) == 2:
+                    j, label = following
+
+                    if j.is_command('j') and label.is_label(s[2]):
+                        s.name = 'bne' if s.is_command('beq') else 'beq'
+                        s[2] = j[0]
+                        statements.replace(3, [s, label])
+
+
+#def optimize_blocks(blocks):
+#    """Call the optimizer for each basic block. Do this several times until
+#    no more optimizations are achieved."""
+#    for block in blocks:
+#        optimize_block(block)
+#
+#    return blocks
+
+
+def optimize_block(statements):
+    """Optimize a basic block."""
+    glob = [redundant_move_1, redundant_move_2, redundant_move_3, \
+            redundant_move_4, redundant_load, redundant_shift, redundant_add]
+    old_len = -1
+
+    while old_len != len(statements):
+        old_len = len(statements)
+
+        while not statements.end():
+            s = statements.read()
+
+            cont = False
+
+            for callback in glob:
+                if callback(s, statements):
+                    cont = True
+                    break
+
+            if cont:
+                continue
+
+            # Other optimizations...
+
+
+def optimize(statements, verbose=0):
+    """optimization wrapper function, calls global and basic-block level
+    optimization functions."""
+    # Optimize on a global level
+    o = len(statements)
+    optimize_global(statements)
+    g = len(statements)
+
+    # Optimize basic blocks
+    blocks = find_basic_blocks(statements)
+    map(optimize_block, blocks)
+    block_statements = map(lambda b: b.statements, blocks)
+    opt_blocks = reduce(lambda a, b: a + b, block_statements)
+    b = len(opt_blocks)
+
+    # - Common subexpression elimination
+    # - Constant folding
+    # - Copy propagation
+    # - Dead-code elimination
+    # - Temporary variable renaming
+    # - Interchange of independent statements
+
+    if verbose:
+        print 'Original statements:             %d' % o
+        print 'After global optimization:       %d' % g
+        print 'After basic blocks optimization: %d' % b
+        print 'Optimization:                    %d (%d%%)' \
+                % (b - o, int((b - o) / float(o) * 100))
+
+    return opt_blocks

+ 4 - 5
src/statement.py

@@ -45,9 +45,8 @@ class Statement:
         return self.stype == 'label' if name == None \
                else self.stype == 'label' and self.name == name
 
-    def is_command(self, name=None):
-        return self.stype == 'command' if name == None \
-               else self.stype == 'command' and self.name == name
+    def is_command(self, *args):
+        return self.stype == 'command' and (not len(args) or self.name in args)
 
     def is_jump(self):
         """Check if the statement is a jump."""
@@ -118,10 +117,10 @@ class Block:
 
     def peek(self, count=1):
         """Read the statements until an offset from the current pointer
-        position."""      
+        position."""
         if self.end():
             return Statement('empty', '') if count == 1 else []
-              
+
         return self.statements[self.pointer] if count == 1 \
                else self.statements[self.pointer:self.pointer + count]
 

+ 74 - 75
tests/test_optimize.py

@@ -1,6 +1,6 @@
 import unittest
 
-from src.optimize import optimize_global, optimize_block, optimize_blocks
+from src.optimize.main import optimize_global, optimize_block#, optimize_blocks
 from src.statement import Statement as S, Block as B
 
 
@@ -17,7 +17,7 @@ class TestOptimize(unittest.TestCase):
                    bar])
         optimize_block(block)
         self.assertEquals(block.statements, [foo, bar])
-        
+
     def test_optimize_block_movab(self):
         foo = S('command', 'foo')
         move = S('command', 'move', '$regA', '$regB')
@@ -27,20 +27,20 @@ class TestOptimize(unittest.TestCase):
                    bar])
         optimize_block(block)
         self.assertEquals(block.statements, [foo, move, bar])
-        
+
     def test_optimize_block_movinst_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
                    S('command', 'move', '$regA', '$regB'),
                    S('command', 'addu', '$regA', '$regA', 2),
                    bar])
         optimize_block(block)
-        self.assertEquals(block.statements, [foo,                     
-                   S('command', 'addu', '$regA', '$regB', 2),      
+        self.assertEquals(block.statements, [foo,
+                   S('command', 'addu', '$regA', '$regB', 2),
                    bar])
-                   
+
     def test_optimize_block_movinst_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
@@ -48,31 +48,31 @@ class TestOptimize(unittest.TestCase):
                       S('command', 'move', '$regA', '$regB'), \
                       S('command', 'addu', '$regA', '$regC', 2), \
                       bar]
-        
+
         block = B(statements)
         optimize_block(block)
         self.assertEquals(block.statements, statements)
-                
+
     def test_optimize_block_instr_mov_jal_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
                    S('command', 'addu', '$regA', '$regC', 2),
                    S('command', 'move', '$4', '$regA'),
                    S('command', 'jal', 'L1'),
                    bar])
         optimize_block(block)
-        
-        self.assertEquals(block.statements, [foo,                     
+
+        self.assertEquals(block.statements, [foo,
                    S('command', 'addu', '$4', '$regC', 2),
-                   S('command', 'jal', 'L1'),      
+                   S('command', 'jal', 'L1'),
                    bar])
-        
+
     def test_optimize_block_instr_mov_jal_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         arguments = [foo, \
                       S('command', 'addu', '$regA', '$regC', 2), \
                       S('command', 'move', '$3', '$regA'), \
@@ -80,130 +80,129 @@ class TestOptimize(unittest.TestCase):
                       bar]
         block = B(arguments)
         optimize_block(block)
-        
+
         self.assertEquals(block.statements, arguments)
-        
+
     def test_optimize_block_sw_ld_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
                    S('command', 'sw', '$regA', '$regB'),
-                   S('command', 'ld', '$regA', '$regC'),
+                   S('command', 'lw', '$regA', '$regB'),
                    bar])
         optimize_block(block)
-        
+
         self.assertEquals(block.statements, [foo,
                    S('command', 'sw', '$regA', '$regB'),
                    bar])
-                   
+
     def test_optimize_block_sw_ld_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         arguments = [foo, \
                      S('command', 'sw', '$regA', '$regB'), \
-                     S('command', 'ld', '$regD', '$regC'), \
+                     S('command', 'lw', '$regD', '$regC'), \
                      bar]
         block = B(arguments)
         optimize_block(block)
-        
+
         self.assertEquals(block.statements, arguments)
 
     def test_optimize_block_shift_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
                    S('command', 'sll', '$regA', '$regA', 0),
                    bar])
         optimize_block(block)
-        
-        self.assertEquals(block.statements, [foo,
-                   bar])
-                   
+
+        self.assertEquals(block.statements, [foo, bar])
+
     def test_optimize_block_shift_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         arguments = [foo, \
                      S('command', 'sll', '$regA', '$regB', 0), \
                      bar]
         block = B(arguments)
         optimize_block(block)
-        
+
         self.assertEquals(block.statements, arguments)
-        
+
         arguments2 = [foo, \
                      S('command', 'sll', '$regA', '$regA', 1), \
                      bar]
         block2 = B(arguments2)
         optimize_block(block2)
-        
+
         self.assertEquals(block2.statements, arguments2)
-    
+
     def test_optimize_block_add_lw_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
-                   S('command', 'add', '$regA', '$regA', 10),
+                   S('command', 'addu', '$regA', '$regA', 10),
                    S('command', 'lw', '$regB', '0($regA)'),
                    bar])
         optimize_block(block)
-        
+
         self.assertEquals(block.statements, [foo,
                    S('command', 'lw', '$regB', '10($regA)'),
                    bar])
-                   
+
     def test_optimize_block_add_lw_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         arguments = [foo, \
-                     S('command', 'add', '$regA', '$regA', 10), \
+                     S('command', 'addu', '$regA', '$regA', 10), \
                      S('command', 'lw', '$regB', '0($regC)'), \
                      bar]
         block = B(arguments)
         optimize_block(block)
-        
+
         arguments2 = [foo, \
-                     S('command', 'add', '$regA', '$regB', 10), \
+                     S('command', 'addu', '$regA', '$regB', 10), \
                      S('command', 'lw', '$regB', '0($regA)'), \
                      bar]
         block2 = B(arguments2)
-        
+
         arguments3 = [foo, \
-                     S('command', 'add', '$regA', '$regA', 10), \
+                     S('command', 'addu', '$regA', '$regA', 10), \
                      S('command', 'lw', '$regB', '1($regA)'), \
                      bar]
         block3 = B(arguments3)
         optimize_block(block3)
-        
+
         self.assertEquals(block.statements, arguments)
         self.assertEquals(block2.statements, arguments2)
         self.assertEquals(block3.statements, arguments3)
-        
+
     def test_optimize_global_beq_j_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
                    S('command', 'beq', '$regA', '$regB', '$Lx'),
                    S('command', 'j', '$Ly'),
                    S('label', '$Lx'),
                    bar])
         optimize_global(block)
-        
+
         self.assertEquals(block.statements, [foo,
                    S('command', 'bne', '$regA', '$regB', '$Ly'),
                    S('label', '$Lx'),
                    bar])
-                   
+
     def test_optimize_global_beq_j_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         arguments = [foo, \
                      S('command', 'beq', '$regA', '$regB', '$Lz'), \
                      S('command', 'j', '$Ly'), \
@@ -211,29 +210,29 @@ class TestOptimize(unittest.TestCase):
                      bar]
         block = B(arguments)
         optimize_global(block)
-        
+
         self.assertEquals(block.statements, arguments)
-        
+
     def test_optimize_global_bne_j_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
                    S('command', 'bne', '$regA', '$regB', '$Lx'),
                    S('command', 'j', '$Ly'),
                    S('label', '$Lx'),
                    bar])
         optimize_global(block)
-        
+
         self.assertEquals(block.statements, [foo,
                    S('command', 'beq', '$regA', '$regB', '$Ly'),
                    S('label', '$Lx'),
                    bar])
-                   
+
     def test_optimize_global_bne_j_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         arguments = [foo, \
                      S('command', 'bne', '$regA', '$regB', '$Lz'), \
                      S('command', 'j', '$Ly'), \
@@ -241,44 +240,44 @@ class TestOptimize(unittest.TestCase):
                      bar]
         block = B(arguments)
         optimize_global(block)
-        
+
         self.assertEquals(block.statements, arguments)
-        
+
     def test_optimize_block_move_move_true(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         block = B([foo,
                    S('command', 'move', '$regA', '$regB'),
                    S('command', 'move', '$regB', '$regA'),
                    bar])
         optimize_block(block)
-        
+
         self.assertEquals(block.statements, [foo,
                    S('command', 'move', '$regA', '$regB'),
                    bar])
-                   
+
     def test_optimize_block_mov_mov_false(self):
         foo = S('command', 'foo')
         bar = S('command', 'bar')
-        
+
         arguments = [foo, \
                      S('command', 'move', '$regA', '$regB'), \
                      S('command', 'move', '$regB', '$regC'), \
                      bar]
         block = B(arguments)
         optimize_block(block)
-        
+
         self.assertEquals(block.statements, arguments)
-        
-    def test_optimize_blocks(self):
-        foo = S('command', 'foo')
-        bar = S('command', 'bar')
-        
-        block1 = B([foo, bar])
-        block2 = B([bar, foo])
-        blocks_in = [block1, block2];
-        
-        blocks_out = optimize_blocks(blocks_in)
-        
-        self.assertEquals(blocks_in, blocks_out)
+
+    #def test_optimize_blocks(self):
+    #    foo = S('command', 'foo')
+    #    bar = S('command', 'bar')
+
+    #    block1 = B([foo, bar])
+    #    block2 = B([bar, foo])
+    #    blocks_in = [block1, block2];
+
+    #    blocks_out = optimize_blocks(blocks_in)
+
+    #    self.assertEquals(blocks_in, blocks_out)