Compilerbau: Sprung- und Peephole-Optimierung |
|
1begin
2 var i,j : int := 1,2
3 ;
4 if i = 1 or j = 2
5 then
6 while i /= 0 do
7 i := i-1
8 endwhile
9 endif
10 ;
11 while i > 1 do
12 while j > i do
13 j := j - 1
14 endwhile
15 ;
16 i := i - 1
17 endwhile
18 ;
19 if 1 /= 0
20 then
21 i := i + 1
22 endif
23 ;
24 if 1 = 0
25 then
26 i := i - 1
27 endif
28end
|
1.text
2 loadi 1
3 loadi 2
4 store m[1]
5 store m[0]
6 load m[0]
7 loadi 1
8 eqi
9 brtrue l2
10 load m[1]
11 loadi 2
12 eqi
13 brfalse l0
14l2:
15 jmp l3
16l4:
17 load m[0]
18 loadi 1
19 subi
20 store m[0]
21l3:
22 load m[0]
23 loadi 0
24 eqi
25 brfalse l4
26l0:
27 jmp l5
28l6:
29 jmp l7
30l8:
31 load m[1]
32 loadi 1
33 subi
34 store m[1]
35l7:
36 load m[1]
37 load m[0]
38 gti
39 brtrue l8
40 load m[0]
41 loadi 1
42 subi
43 store m[0]
44l5:
45 load m[0]
46 loadi 1
47 gti
48 brtrue l6
49 loadi 1
50 loadi 0
51 eqi
52 brtrue l9
53 load m[0]
54 loadi 1
55 addi
56 store m[0]
57l9:
58 loadi 1
59 loadi 0
60 eqi
61 brfalse l11
62 load m[0]
63 loadi 1
64 subi
65 store m[0]
66l11:
67 undef
68 store m[0]
69 undef
70 store m[1]
71 terminate
72
73.data 2
|
1.text
2 loadi 1
3 loadi 2
4 store m[1]
5 dup
6 store m[0]
7 loadi 1
8 eqi
9 brtrue l3
10 load m[1]
11 loadi 2
12 eqi
13 brfalse l5
14 jmp l3
15l4:
16 load m[0]
17 decri
18 store m[0]
19l3:
20 load m[0]
21 loadi 0
22 eqi
23 brfalse l4
24 jmp l5
25l8:
26 load m[1]
27 decri
28 store m[1]
29l7:
30 load m[1]
31 load m[0]
32 gti
33 brtrue l8
34 load m[0]
35 decri
36 store m[0]
37l5:
38 load m[0]
39 loadi 1
40 gti
41 brtrue l7
42 loadi 1
43 loadi 0
44 eqi
45 brtrue l9
46 load m[0]
47 incri
48 store m[0]
49l9:
50 loadi 1
51 loadi 0
52 eqi
53 brfalse l11
54 load m[0]
55 decri
56 store m[0]
57l11:
58 undef
59 store m[0]
60 undef
61 store m[1]
62 terminate
63
64.data 2
|
1.text .text
2 loadi 1 loadi 1
3 loadi 2 loadi 2
4 store m[1] store m[1]
5 > dup
6 store m[0] store m[0]
7 load m[0] <
8 loadi 1 loadi 1
9 eqi eqi
10 brtrue l2 | brtrue l3
11 load m[1] load m[1]
12 loadi 2 loadi 2
13 eqi eqi
14 brfalse l0 | brfalse l5
15l2: <
16 jmp l3 jmp l3
17l4: l4:
18 load m[0] load m[0]
19 loadi 1 | decri
20 subi <
21 store m[0] store m[0]
22l3: l3:
23 load m[0] load m[0]
24 loadi 0 loadi 0
25 eqi eqi
26 brfalse l4 brfalse l4
27l0: <
28 jmp l5 jmp l5
29l6: <
30 jmp l7 <
31l8: l8:
32 load m[1] load m[1]
33 loadi 1 | decri
34 subi <
35 store m[1] store m[1]
36l7: l7:
37 load m[1] load m[1]
38 load m[0] load m[0]
39 gti gti
40 brtrue l8 brtrue l8
41 load m[0] load m[0]
42 loadi 1 | decri
43 subi <
44 store m[0] store m[0]
45l5: l5:
46 load m[0] load m[0]
47 loadi 1 loadi 1
48 gti gti
49 brtrue l6 | brtrue l7
50 loadi 1 loadi 1
51 loadi 0 loadi 0
52 eqi eqi
53 brtrue l9 brtrue l9
54 load m[0] load m[0]
55 loadi 1 | incri
56 addi <
57 store m[0] store m[0]
58l9: l9:
59 loadi 1 loadi 1
60 loadi 0 loadi 0
61 eqi eqi
62 brfalse l11 brfalse l11
63 load m[0] load m[0]
64 loadi 1 | decri
65 subi <
66 store m[0] store m[0]
67l11: l11:
68 undef undef
69 store m[0] store m[0]
70 undef undef
71 store m[1] store m[1]
72 terminate terminate
73
74.data 2 .data 2
|
1module PPL.OptimizeInstr
2 ( optimizeInstr
3 )
4where
5
6import PPL.Instructions
7
8import Data.Maybe
9
10type LabSubst = [(Label, Label)]
11
12optimizeInstr :: Executable -> Executable
13optimizeInstr (is, ds)
14 = ((peephole . removeUnusedLabels . jumpChaining . optimizeTailRecursion) is, ds)
15
16jumpChaining :: Code -> Code
17jumpChaining is
18 = let
19 labTab = buildLabSubst [] is
20 is' = renameLabels labTab is
21 in
22 is'
23
24buildLabSubst :: LabSubst -> Code -> LabSubst
25
26-- real jump chaining
27buildLabSubst lt ( (Label l1)
28 : (Jump (Symb l2))
29 : is2)
30 = buildLabSubst lt1 is2
31 where
32 lt1 = insLabSubst l1 l2 lt
33
34-- labels with equal values are collapsed
35buildLabSubst lt ( (Label l1)
36 : is1@((Label l2)
37 : _))
38 = buildLabSubst lt1 is1
39 where
40 lt1 = insLabSubst l1 l2 lt
41
42-- default rules
43buildLabSubst lt (_:is1)
44 = buildLabSubst lt is1
45
46buildLabSubst lt []
47 = lt
48
49
50-- --------------------
51
52insLabSubst :: Label -> Label -> LabSubst -> LabSubst
53insLabSubst l1 l2 lt
54 = if (l2,l1) `elem` lt || l1 == l2
55 then lt
56 else (l1, l2) : lt'
57 where
58 lt' = map renameWith lt
59 renameWith (l1',l2')
60 | l2' == l1
61 = (l1', l2)
62 renameWith p
63 = p
64
65newLabName :: LabSubst -> Label -> Label
66newLabName lt l
67 = case lookup l lt of
68 Just l1 -> l1
69 Nothing -> l
70
71renameLabels :: LabSubst -> Code -> Code
72
73-- remove alias labels
74
75renameLabels lt ((Label l1) : is1)
76 | isJust (lookup l1 lt)
77 = renameLabels lt is1
78
79-- default
80renameLabels lt (i1:is)
81 = renameLab lt i1 : renameLabels lt is
82
83renameLabels _ []
84 = []
85
86renameLab :: LabSubst -> Instr -> Instr
87
88renameLab lt (Branch cond (Symb l1))
89 = Branch cond (Symb (newLabName lt l1))
90
91renameLab lt (Jump (Symb l1))
92 = Jump (Symb (newLabName lt l1))
93
94renameLab _lt i
95 = i
96
97-- --------------------
98
99usedLabels :: Code -> [Label]
100usedLabels
101 = concat . map lab
102 where
103 lab (Branch _ (Symb l)) = [l]
104 lab (Jump (Symb l)) = [l]
105 lab _ = []
106
107removeUnusedLabels :: Code -> Code
108removeUnusedLabels cs
109 = filter usedLabel cs
110 where
111 used = usedLabels cs
112
113 usedLabel (Label l@(c:_))
114 = c == '_' -- global label
115 ||
116 l `elem` used -- label is referenced in jump or branch
117 usedLabel _
118 = True
119
120-- --------------------
121
122-- peephole optimizations
123-- local instruction optimization
124
125peephole :: Code -> Code
126
127-- remove instructions following unconditional jumps
128
129peephole (i1@(Jump _l1)
130 : i2
131 : is
132 )
133 | noLabel i2
134 = peephole (i1:is)
135
136-- remove jump to following instruction
137
138peephole (Jump (Symb l1)
139 : is2@(Label l2
140 : _
141 )
142 )
143 | l1 == l2
144 = peephole is2
145
146-- remove conditional branch to following instruction
147
148peephole (Branch _ (Symb l1)
149 : is2@(Label l2
150 : _
151 )
152 )
153 | l1 == l2
154 = Pop
155 : peephole is2
156
157-- conditional branches with constants
158
159peephole (LoadI val
160 : Branch cond lab
161 : is
162 )
163 | (val /= 0) == cond
164 = peephole (Jump lab : is)
165 | otherwise
166 = peephole is
167
168-- optimize store load sequences
169
170peephole (Store a1
171 : Load a2
172 : is
173 )
174 | a1 == a2
175 = Dup
176 : peephole (Store a1 : is)
177
178-- optimize increment and decrement
179
180peephole (LoadI 1
181 : Compute OPaddi
182 : is
183 )
184 = Compute OPincri
185 : peephole is
186
187peephole (LoadI 1
188 : Compute OPsubi
189 : is
190 )
191 = Compute OPdecri
192 : peephole is
193
194peephole (Pop
195 : LoadU
196 : is
197 )
198 = peephole is
199
200-- next step
201
202peephole (i1:is1)
203 = i1 : peephole is1
204
205peephole []
206 = []
207
208-- --------------------
209
210noLabel :: Instr -> Bool
211
212noLabel (Label _) = False
213noLabel _ = True
214
215-- --------------------
216
217optimizeCalls :: LabSubst -> Code -> Code
218optimizeCalls lt cs@( Label sl
219 : Entry _
220 : Store _
221 : Label sl1
222 : cs4
223 )
224 = take 4 cs
225 ++
226 optimize1Fct cs4
227 where
228 el1 = 'e' : sl
229 el = newLabName lt el1
230
231 optimize1Fct cs'@( Exit -- function exit detected
232 : PopJ -- optimize rest
233 : rest'
234 )
235 = take 2 cs'
236 ++
237 optimizeCalls lt rest'
238
239 optimize1Fct ( PushJ fct@(Symb target)
240 : Jump (Symb l1)
241 : rest
242 )
243 -- pure tail recursion detected
244 -- subroutine call substituted
245 -- by a jump to routine start
246 | target == sl && newLabName lt l1 == el
247 = Jump (Symb sl1)
248 : optimize1Fct rest
249 -- tail recursion to another function
250 -- load return address
251 -- remove stack frame
252 -- and jump
253 | newLabName lt l1 == el
254 = Load (LocA 0)
255 : Exit
256 : Jump fct
257 : optimize1Fct rest
258
259 -- same as above for calls
260 -- directly in front of exit code
261 optimize1Fct ( PushJ fct@(Symb target)
262 : cs1@( Label l1
263 : _rest
264 )
265 )
266 | target == sl && newLabName lt l1 == el
267 = Jump (Symb sl1)
268 : optimize1Fct cs1
269
270 | newLabName lt l1 == el
271 = Load (LocA 0)
272 : Exit
273 : Jump fct
274 : optimize1Fct cs1
275
276 -- continue search for calls
277 optimize1Fct (c : cs1)
278 = c : optimize1Fct cs1
279
280 optimize1Fct []
281 = []
282
283optimizeCalls lt (c1 : cs1)
284 = c1 : optimizeCalls lt cs1
285
286optimizeCalls _ []
287 = []
288
289-- optimize tail recursion
290-- 1. step: collect all function entry end exit points
291-- 2. step: look for function calls
292
293optimizeTailRecursion :: Code -> Code
294optimizeTailRecursion cs
295 = optimizeCalls labTab cs
296 where
297 labTab = buildLabSubst [] cs
298
299-- --------------------
|
Letzte Änderung: 14.02.2012 | © Prof. Dr. Uwe Schmidt |