Commit 8d6930d4 authored by Taddeus Kroes's avatar Taddeus Kroes

Improved local copy propagation.

parent f58d2e0b
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
......
......@@ -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."""
......
......@@ -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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment