comparison python/transform.py @ 253:74c6a20302d5

Added better logging
author Windel Bouwman
date Wed, 31 Jul 2013 17:57:03 +0200
parents c4370696ccc7
children 7416c923a02a
comparison
equal deleted inserted replaced
252:c4370696ccc7 253:74c6a20302d5
1 """ 1 """
2 Transformation to optimize IR-code 2 Transformation to optimize IR-code
3 """ 3 """
4 4
5 import logging
5 from ir import * 6 from ir import *
6 # Standard passes: 7 # Standard passes:
7 8
8 class FunctionPass: 9 class FunctionPass:
9 def run(self, ir): 10 def run(self, ir):
10 """ Main entry point for the pass """ 11 """ Main entry point for the pass """
11 self.prepare() 12 logging.info('Running pass {}'.format(type(self)))
12 for f in ir.Functions: 13 self.prepare()
13 self.onFunction(f) 14 for f in ir.Functions:
14 def onFunction(self, f): 15 self.onFunction(f)
15 """ Override this virtual method """ 16
16 raise NotImplementedError() 17 def onFunction(self, f):
17 def prepare(self): 18 """ Override this virtual method """
18 pass 19 raise NotImplementedError()
20
21 def prepare(self):
22 pass
19 23
20 24
21 class BasicBlockPass(FunctionPass): 25 class BasicBlockPass(FunctionPass):
22 def onFunction(self, f): 26 def onFunction(self, f):
23 for bb in f.BasicBlocks: 27 for bb in f.BasicBlocks:
62 vr = None 66 vr = None
63 return 67 return
64 self.constMap[i.result] = vr 68 self.constMap[i.result] = vr
65 i.removeDef(i.result) 69 i.removeDef(i.result)
66 i2 = ImmLoad(i.result, vr) 70 i2 = ImmLoad(i.result, vr)
67 print('Replacing', i) 71 logging.debug('Replacing {}'.format(i))
68 i.Parent.replaceInstruction(i, i2) 72 i.Parent.replaceInstruction(i, i2)
69 73
70 74
71 class DeadCodeDeleter(BasicBlockPass): 75 class DeadCodeDeleter(BasicBlockPass):
72 def onBasicBlock(self, bb): 76 def onBasicBlock(self, bb):
73 def instructionUsed(ins): 77 def instructionUsed(ins):
78 if not type(ins) in [ImmLoad, BinaryOperator]:
79 return True
74 if len(ins.defs) == 0: 80 if len(ins.defs) == 0:
75 # In case this instruction does not define any 81 # In case this instruction does not define any
76 # variables, assume it is usefull. 82 # variables, assume it is usefull.
77 return True 83 return True
78 return any(d.Used for d in ins.defs) 84 return any(d.Used for d in ins.defs)
94 for i in bb.Instructions: 100 for i in bb.Instructions:
95 if isinstance(i, ImmLoad): 101 if isinstance(i, ImmLoad):
96 if i.value in constMap: 102 if i.value in constMap:
97 t_new = constMap[i.value] 103 t_new = constMap[i.value]
98 t_old = i.target 104 t_old = i.target
105 logging.debug('Replacing {} with {}'.format(t_old, t_new))
99 for ui in t_old.used_by: 106 for ui in t_old.used_by:
100 ui.replaceValue(t_old, t_new) 107 ui.replaceValue(t_old, t_new)
101 to_remove.append(i) 108 to_remove.append(i)
102 else: 109 else:
103 constMap[i.value] = i.target 110 constMap[i.value] = i.target
104 elif isinstance(i, BinaryOperator): 111 elif isinstance(i, BinaryOperator):
105 k = (i.value1, i.operation, i.value2) 112 k = (i.value1, i.operation, i.value2)
106 if k in constMap: 113 if k in constMap:
107 print('Duplicate binop!', i)
108 t_old = i.result 114 t_old = i.result
109 t_new = constMap[k] 115 t_new = constMap[k]
116 logging.debug('Replacing {} with {}'.format(t_old, t_new))
110 for ui in t_old.used_by: 117 for ui in t_old.used_by:
111 ui.replaceValue(t_old, t_new) 118 ui.replaceValue(t_old, t_new)
112 to_remove.append(i) 119 to_remove.append(i)
113 else: 120 else:
114 constMap[k] = i.result 121 constMap[k] = i.result
115 for i in to_remove: 122 for i in to_remove:
116 print('removing ', i) 123 logging.debug('removing {}'.format(i))
117 bb.removeInstruction(i) 124 bb.removeInstruction(i)
118
119
120 125
121 126
122 class CleanPass(FunctionPass): 127 class CleanPass(FunctionPass):
123 def onFunction(self, f): 128 def onFunction(self, f):
124 bbs = list(f.BasicBlocks) 129 bbs = list(f.BasicBlocks)
125 for bb in bbs: 130 for bb in bbs:
126 # TODO: determine check for 'empty' 131 # If a block only contains a branch, it can be removed:
127 132 if len(bb.Instructions) == 1 and type(bb.LastInstruction) is Branch:
128 # If a block only contains a branch, it can be removed: 133 # This block is empty.
129 if len(bb.Instructions) == 1 and type(bb.LastInstruction) is Branch: 134 # find predecessors of this block and replace this block reference with the jumped reference.
130 # This block is empty. 135 ins = bb.LastInstruction
131 # find predecessors of this block and replace this block reference with the jumped reference. 136 preds = bb.Predecessors
132 ins = bb.LastInstruction 137 if bb in preds:
133 preds = bb.Predecessors
134 if bb in preds:
135 # Do not remove if preceeded by itself 138 # Do not remove if preceeded by itself
136 pass 139 pass
137 else: 140 else:
138 for pred in bb.Predecessors: 141 for pred in bb.Predecessors:
139 pred.LastInstruction.changeTarget(bb, ins.target) 142 pred.LastInstruction.changeTarget(bb, ins.target)
140 f.removeBasicBlock(bb) 143 f.removeBasicBlock(bb)
141 144
142 145
143 def isAllocPromotable(allocinst):
144 # Check if alloc value is only used by load and store operations.
145 assert type(allocinst) is Alloc
146 for use in allocinst.value.used_by:
147 if not type(use) in [Load, Store]:
148 # TODO: check volatile
149 return False
150 otherUse = True
151 return True
152 146
153 147
154 class Mem2RegPromotor(FunctionPass):
155 def promoteSingleBlock(self, ai):
156 print('Single block:', ai)
157 v = ai.value
158 bb = ai.Block
159
160 # Replace all loads with the value:
161 loads = [i for i in v.used_by if isinstance(i, Load)]
162 stores = [i for i in v.used_by if isinstance(i, Store)]
163 stores.sort(key=lambda s: s.Position)
164 stores.reverse()
165 print(stores)
166
167 for load in loads:
168 idx = load.Position
169 # Search upwards:
170 for store in stores:
171 if store.Position < load.Position:
172 break
173 #print('replace {} with {}'.format(load, store.value))
174 for use_ins in load.value.used_by:
175 use_ins.replaceValue(load.value, store.value)
176 assert not load.value.Used
177 print('removing {}'.format(load))
178 bb.removeInstruction(load)
179
180 # Remove store instructions:
181 for store in stores:
182 sv = store.value
183 print('removing {}'.format(store))
184 bb.removeInstruction(store)
185 #assert sv.Used
186
187 # Remove alloca instruction:
188 assert not ai.value.Used, ai.value.used_by
189 bb.removeInstruction(ai)
190
191
192
193 def promote(self, ai):
194 # Find load operations and replace them with assignments
195 v = ai.value
196 if len(ai.value.UsedInBlocks) == 1:
197 self.promoteSingleBlock(ai)
198 return
199
200 loads = [i for i in v.used_by if isinstance(i, Load)]
201 stores = [i for i in v.used_by if isinstance(i, Store)]
202
203 # Each store instruction can be removed (later).
204 # Instead of storing the value, we use it
205 # where the load would have been!
206 replMap = {}
207 for store in stores:
208 replMap[store] = store.value
209
210 # for each load, track back what the defining store
211 # was.
212 for load in loads:
213 print(load)
214
215 def onFunction(self, f):
216 # TODO
217 for bb in f.BasicBlocks:
218 allocs = [i for i in bb.Instructions if isinstance(i, Alloc)]
219 for i in allocs:
220 print(i, isAllocPromotable(i))
221 if isAllocPromotable(i):
222 self.promote(i)
223
224 def optimize(ir):
225 cf = ConstantFolder()
226 dcd = DeadCodeDeleter()
227 m2r = Mem2RegPromotor()
228 clr = CleanPass()
229 cse = CommonSubexpressionElimination()
230 ir.check()
231 cf.run(ir)
232 dcd.run(ir)
233 ir.check()
234 clr.run(ir)
235 ir.check()
236 m2r.run(ir)
237 ir.check()
238 cse.run(ir)
239 ir.check()
240