forked from tkoptimizer/Assembly-code-optimizer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
copyPropagation.py
150 lines (110 loc) · 5.07 KB
/
copyPropagation.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""
File: copyPropagation.py
Authors: Tim van Deurzen, Koos van Strien
Date: 26-02-2010
"""
import re
from basicblock import *
from operations_new import *
from optimizationClass import *
class copyPropagation(optimizationClass):
"""
Optimizes assembly by trying to remove unnecessary 'move' operations.
"""
def __init__(self, blocks):
"""
Initializes all the necessary variables.
"""
self.name = "Copy propagation"
self.optimizedBlocks = blocks
self.moves = []
self.output = [" ==== Copy propagation optimizer ==== "]
def analyseBasicBlock(self, block):
self.output.append("\n>>>> Starting analysis of new block. <<<<\n")
updated_ops = []
dead_moves = []
for i, op in enumerate(block.operations):
# For each move operation check all next operations.
if not op.isMove():
continue
if op.included == False:
self.output.append("\t{{ operation previously excluded: " +
op.code + " }}")
continue
self.output.append("\t--> Analysing operation: " + str(op) +
" on line " + str(op.lineNumber))
dest = op.getMoveDestination()
source = op.getMoveSource()
pattern = "\$(s|f)[0-9p]+"
# We don't mess with frame pointers and such.
if re.match(pattern, dest):
continue
next_ops = block.operations[i + 1:]
for n_op in next_ops:
n_target = None
n_source = None
n_offset = None
if n_op.type not in (operation.CONTROL, operation.SYSTEM):
n_target = n_op.getTarget()
if n_op.type in (operation.LOAD, operation.STORE):
n_source = n_op.getAddress()
if n_op.usesOffset():
n_offset = n_op.getOffsetRegister()
if n_op.type is operation.STORE:
if n_target == dest:
# Storing the dest. register of a move, try to store
# source register.
updated_ops.append(n_op)
dead_moves.append(op)
n_op.setSource(source)
self.output.append("\n\t!!--> Updated " +
"STORE operation\n");
elif n_op.isMove():
n_dest = n_op.getMoveDestination()
n_source = n_op.getMoveSource()
if n_dest == dest and n_source == source or \
n_dest == source or n_source == dest:
try:
dead_moves.remove(op)
except:
" Move wasn't dead yet, skip step "
break
if n_dest == dest and n_source != source:
try:
dead_moves.remove(op)
except:
" Move wasn't dead yet, skip step "
break
elif n_op.type is operation.LOAD:
if n_target == dest or n_target == source:
break
elif n_op.type in (operation.INT_ARITHMETIC,
operation.FLOAT_ARITHMETIC,
operation.CONTROL):
args = n_op.getArguments()
if n_op.operation in ("jal", "jalr"):
self.output.append("\n\t!!--> Breaking at function call" +
" (jal / jalr).")
break
if dest in args:
if n_target == dest and dest not in args[1:]:
self.output.append("\n\t!!--> Arithmetic operation" +
" only writes register, breaking: " +
n_op.code)
break
if n_op.type == operation.CONTROL:
start = 0
else:
start = 1
for i in range(start, len(args)):
if args[i] == dest:
args[i] = source
n_op.setArguments(args)
self.output.append("\n\t!!--> Updating arithmetic or" +
" control operation (" + n_op.code + ")")
updated_ops.append(n_op)
dead_moves.append(op)
# Exclude all the dead moves from the output.
for move in dead_moves:
self.output.append("Excluding move (" + move.code + ") from output.")
move.exclude()