Skip to content
Snippets Groups Projects
Commit 8d6930d4 authored by Taddeus Kroes's avatar Taddeus Kroes
Browse files

Improved local copy propagation.

parent f58d2e0b
No related branches found
No related tags found
No related merge requests found
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:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment