]>
Commit | Line | Data |
---|---|---|
1 | (* L3 Compiler | |
2 | * Turns pseudoasm into liveness-annotated pseudoasm | |
3 | * Author: Chris Lu <czl@andrew.cmu.edu> | |
4 | * Author: Joshua Wise <jwise@andrew.cmu.edu> | |
5 | *) | |
6 | ||
7 | signature LIVENESS = | |
8 | sig | |
9 | structure OperSet : ORD_SET | |
10 | where type Key.ord_key = x86.oper; | |
11 | structure LiveMap : ORD_MAP | |
12 | where type Key.ord_key = int; | |
13 | ||
14 | type live = int * OperSet.set | |
15 | type pseudoasm = x86.insn list | |
16 | type livenesses = OperSet.set LiveMap.map | |
17 | ||
18 | type ident = int | |
19 | datatype pred = DEF of x86.oper | USE of x86.oper | SUCC of ident | ISMOVE | |
20 | ||
21 | type predicates = pred list LiveMap.map | |
22 | ||
23 | val uses : pred list -> x86.oper list | |
24 | val succs : pred list -> ident list | |
25 | val defs : pred list -> x86.oper list | |
26 | val ismove : pred list -> bool | |
27 | ||
28 | val liveness : pseudoasm -> predicates * livenesses | |
29 | val listify : livenesses -> OperSet.set list | |
30 | val prettyprint : OperSet.set -> string | |
31 | end | |
32 | ||
33 | structure Liveness :> LIVENESS = | |
34 | struct | |
35 | structure T = Temp | |
36 | structure X = x86 | |
37 | ||
38 | structure OperSet = x86.OperSet | |
39 | structure LiveMap = x86.LiveMap | |
40 | ||
41 | type live = int * OperSet.set | |
42 | type pseudoasm = X.insn list | |
43 | type numasm = X.insn LiveMap.map | |
44 | type livenesses = OperSet.set LiveMap.map | |
45 | ||
46 | type ident = int | |
47 | datatype pred = DEF of X.oper | USE of X.oper | SUCC of ident | ISMOVE | |
48 | ||
49 | type predicates = pred list LiveMap.map | |
50 | ||
51 | (* val number : pseudoasm -> numasm | |
52 | * numbers the instructions! | |
53 | *) | |
54 | ||
55 | fun number instrs = | |
56 | let | |
57 | val nums = List.tabulate (List.length instrs, (fn i => i)) | |
58 | in | |
59 | foldr | |
60 | LiveMap.insert' | |
61 | LiveMap.empty | |
62 | (ListPair.zip (nums,instrs)) | |
63 | end | |
64 | ||
65 | (* val defusesucc : numasm -> (ident * pred list) list | |
66 | * generates def/use/succ predicates according to rules | |
67 | *) | |
68 | ||
69 | fun defusesucc l = | |
70 | let | |
71 | fun findlabel (lb) = | |
72 | Option.valOf | |
73 | (LiveMap.foldri (fn (n, X.LABEL lb', NONE) => if (Label.compare (lb, lb') = EQUAL) then SOME n else NONE | |
74 | | (_, _, old) => old) NONE l) | |
75 | ||
76 | (* val defhit/usehit : X.oper -> pred list | |
77 | * helper functions to discard constant operands *) | |
78 | fun defhit (X.REG a) = [DEF(X.REG a)] | |
79 | | defhit (X.TEMP a) = [DEF(X.TEMP a)] | |
80 | | defhit (_) = nil | |
81 | ||
82 | fun usehit (X.REG a) = [USE(X.REG a)] | |
83 | | usehit (X.TEMP a) = [USE(X.TEMP a)] | |
84 | | usehit (_) = nil | |
85 | ||
86 | fun callhit 0 = nil | |
87 | | callhit 1 = USE(X.REG(X.EDI))::(callhit 0) | |
88 | | callhit 2 = USE(X.REG(X.ESI))::(callhit 1) | |
89 | | callhit 3 = USE(X.REG(X.EDX))::(callhit 2) | |
90 | | callhit 4 = USE(X.REG(X.ECX))::(callhit 3) | |
91 | | callhit 5 = USE(X.REG(X.R8D))::(callhit 4) | |
92 | | callhit 6 = USE(X.REG(X.R9D))::(callhit 5) | |
93 | | callhit _ = callhit 6 | |
94 | ||
95 | (* val gendef : ident * X.insn -> ident * pred list | |
96 | * generates the def/use/succ predicates for a single insn | |
97 | *) | |
98 | fun gendef (n, X.DIRECTIVE(_)) = (nil) | |
99 | | gendef (n, X.COMMENT(_)) = (nil) | |
100 | | gendef (n, X.LIVEIGN (_)) = ([SUCC (n+1)]) | |
101 | | gendef (n, X.SIZE(_, i)) = gendef (n,i) | |
102 | | gendef (n, X.MOV(dest, src)) = (defhit dest @ usehit src @ [SUCC(n+1), ISMOVE]) | |
103 | | gendef (n, X.SUB(dest, src)) = (defhit dest @ usehit dest @ usehit src @ [SUCC(n+1)]) | |
104 | | gendef (n, X.IMUL(dest, src)) = (defhit dest @ usehit dest @ usehit src @ [SUCC(n+1)]) | |
105 | | gendef (n, X.IMUL3(dest, src, _)) = (defhit dest @ usehit src @ [SUCC(n+1)]) | |
106 | | gendef (n, X.ADD(dest, src)) = (defhit dest @ usehit dest @ usehit src @ [SUCC(n+1)]) | |
107 | | gendef (n, X.IDIV(src)) = (usehit src @ [DEF(X.REG(X.EAX)), DEF(X.REG(X.EDX)), | |
108 | USE(X.REG(X.EAX)), USE(X.REG(X.EDX)), | |
109 | SUCC(n+1)]) | |
110 | | gendef (n, X.CLTD) = ([USE(X.REG(X.EAX)), DEF(X.REG(X.EDX)), SUCC(n+1)]) | |
111 | | gendef (n, X.SAL(dest, shft)) = (defhit dest @ usehit shft @ usehit dest @ [SUCC(n+1)]) | |
112 | | gendef (n, X.SAR(dest, shft)) = (defhit dest @ usehit shft @ usehit dest @ [SUCC(n+1)]) | |
113 | | gendef (n, X.NEG(src)) = (defhit src @ usehit src @ [SUCC(n+1)]) | |
114 | | gendef (n, X.NOT(src)) = (defhit src @ usehit src @ [SUCC(n+1)]) | |
115 | | gendef (n, X.AND(dest, src)) = (defhit dest @ usehit dest @ usehit src @ [SUCC(n+1)]) | |
116 | | gendef (n, X.OR(dest, src)) = (defhit dest @ usehit dest @ usehit src @ [SUCC(n+1)]) | |
117 | | gendef (n, X.XOR(dest, src)) = (defhit dest @ usehit dest @ usehit src @ [SUCC(n+1)]) | |
118 | | gendef (n, X.CMP(dest, src)) = (usehit dest @ usehit src @ [SUCC(n+1)]) | |
119 | | gendef (n, X.TEST(dest, src)) = (usehit dest @ usehit src @ [SUCC(n+1)]) | |
120 | | gendef (n, X.SETcc(_,dest)) = (defhit dest @ [SUCC(n+1)]) | |
121 | | gendef (n, X.CALL(_, a)) = (callhit a @ [DEF(X.REG(X.EAX)), DEF(X.REG(X.ECX)), DEF(X.REG(X.EDX)), | |
122 | DEF(X.REG(X.EDI)), DEF(X.REG(X.ESI)), DEF(X.REG(X.R8D)), | |
123 | DEF(X.REG(X.R9D)), DEF(X.REG(X.R10D)), DEF(X.REG(X.R11D)), SUCC(n+1)]) | |
124 | | gendef (n, X.MOVZB(dest, src)) = (defhit dest @ usehit src @ [SUCC(n+1)]) | |
125 | | gendef (n, X.RET) = ([USE (X.REG X.EAX)]) | |
126 | | gendef (n, X.LABEL l) = ([SUCC (n+1)]) | |
127 | | gendef (n, X.JMP l) = ([SUCC (findlabel l)]) | |
128 | | gendef (n, X.Jcc (_,l)) = ([SUCC (n+1), SUCC (findlabel l)]) | |
129 | in | |
130 | LiveMap.mapi gendef l | |
131 | end | |
132 | ||
133 | (* val uselive : (int * pred list) list -> OperSet.set LiveMap.map | |
134 | * generates liveness for 'use' rules to get the iterative analyzer started | |
135 | *) | |
136 | fun uselive preds = | |
137 | LiveMap.mapi | |
138 | (fn (n, pl) => | |
139 | foldr | |
140 | (fn (USE (l), set) => OperSet.add (set, l) | |
141 | | (_, set) => set) | |
142 | OperSet.empty | |
143 | pl | |
144 | ) | |
145 | preds | |
146 | ||
147 | (* val subsetlive : OperSet.set LiveMap.map * OperSet.set LiveMap.map -> bool | |
148 | * true if first is subset of second | |
149 | *) | |
150 | ||
151 | fun subsetlive (l1,l2) = | |
152 | LiveMap.foldri | |
153 | (fn (_, _, false) => false | |
154 | | (n, set1, _) => case LiveMap.find (l2, n) | |
155 | of NONE => false | |
156 | | SOME set2 => OperSet.isSubset (set1, set2)) | |
157 | true | |
158 | l1 | |
159 | ||
160 | (* val succs : pred list -> int list | |
161 | * generates a list of lines that succeed a line given the predicates | |
162 | * for that line | |
163 | *) | |
164 | fun succs (SUCC(a)::l') = a::(succs l') | |
165 | | succs (_::l') = succs l' | |
166 | | succs nil = nil | |
167 | ||
168 | fun defs (DEF(a)::l) = a::(defs l) | |
169 | | defs (_::l) = defs l | |
170 | | defs nil = nil | |
171 | ||
172 | fun uses (USE(a)::l) = a::(defs l) | |
173 | | uses (_::l) = defs l | |
174 | | uses nil = nil | |
175 | ||
176 | fun ismove l = List.exists (fn ISMOVE => true | _ => false) l | |
177 | ||
178 | (* val liveiter : OperSet.set LiveMap.map -> (int * pred list) list -> OperSet.set LiveMap.map | |
179 | * iteratively generates livenesses from def/use/succ rules | |
180 | * it must be fed a liveness list generated from the use rule as it only | |
181 | * processes the second rule : | |
182 | * | |
183 | * use(l',x) | |
184 | * !def(l,x) | |
185 | * succ(l,l') | |
186 | * -------------- | |
187 | * live(l,x) | |
188 | *) | |
189 | ||
190 | fun liveiter livemap preds = | |
191 | let | |
192 | ||
193 | ||
194 | ||
195 | (* val lives : int list -> OperSet.set LiveMap.map -> OperSet.set | |
196 | * scans l for live variables in succeeding lines *) | |
197 | fun lives l' idents = | |
198 | let | |
199 | val lines = List.mapPartial (fn a => LiveMap.find (l', a)) idents | |
200 | in | |
201 | foldr | |
202 | (fn (set', set) => OperSet.union (set', set)) | |
203 | OperSet.empty | |
204 | lines | |
205 | end | |
206 | ||
207 | (* val isndef : X.oper -> pred list -> bool | |
208 | * checks to see if x is defined in a predicate list *) | |
209 | fun isndef (X.STACKARG(_)) _ = false | |
210 | | isndef x (DEF(y)::l') = not (X.opereq (x,y)) andalso isndef x l' | |
211 | | isndef x (a::l') = isndef x l' | |
212 | | isndef x nil = true | |
213 | ||
214 | (* val liveadd : live -> OperSet.set LiveMap.map -> OperSet.set LiveMap.map *) | |
215 | fun liveadd (n,oper) map = case LiveMap.find (map, n) | |
216 | of SOME(x) => LiveMap.insert (map, n, OperSet.add (x, oper)) | |
217 | | NONE => LiveMap.insert (map, n, OperSet.singleton oper) | |
218 | ||
219 | (* this does the dirty work! | |
220 | * for each line, checks if the live variables in succeeding lines are | |
221 | * not defined here; if so, it accumulates them onto the inital list | |
222 | * | |
223 | * changing the first foldr to a foldl slows down liveness by a factor | |
224 | * of at least 100 on cedar-anastulate.l2 | |
225 | *) | |
226 | val newl = LiveMap.foldri | |
227 | (fn (n, a, b) => OperSet.foldr | |
228 | (fn (a',b') => if (isndef a' a) then liveadd (n, a') b' else b') | |
229 | b | |
230 | (lives b (succs a)) | |
231 | ) | |
232 | livemap | |
233 | preds | |
234 | in | |
235 | if subsetlive (newl, livemap) | |
236 | then livemap | |
237 | else liveiter newl preds | |
238 | end | |
239 | ||
240 | fun dustostring (DEF(a)) = "DEF(" ^ X.prettyprint_oper X.Long a ^ ")" | |
241 | | dustostring (USE(a)) = "USE(" ^ X.prettyprint_oper X.Long a ^ ")" | |
242 | | dustostring (SUCC(a)) = "SUCC(" ^ Int.toString a ^ ")" | |
243 | | dustostring ISMOVE = "ISMOVE" | |
244 | ||
245 | (* val liveness : pseudoasm -> livenesses | |
246 | * analyzes liveness of variables in the given pseudo-asm | |
247 | *) | |
248 | ||
249 | fun liveness instrs = | |
250 | let | |
251 | val preds = defusesucc (number instrs) | |
252 | (* val (_,l) = ListPair.unzip preds | |
253 | val () = print ( | |
254 | String.concatWith "\n" ( | |
255 | List.map | |
256 | (fn a => String.concatWith ", " (List.map dustostring a)) | |
257 | l | |
258 | ) | |
259 | )*) | |
260 | val init = uselive preds | |
261 | val initmap = LiveMap.foldri (fn (n,a,b) => LiveMap.insert (b, n, a)) LiveMap.empty init | |
262 | in | |
263 | (preds, liveiter initmap preds) | |
264 | end | |
265 | ||
266 | fun prettyprint (set) = | |
267 | OperSet.foldr | |
268 | (fn (oper, s) => (X.prettyprint_oper X.Long oper) ^ ", " ^ s) | |
269 | "-\n" | |
270 | set | |
271 | ||
272 | fun listify map = | |
273 | let | |
274 | val maxln = LiveMap.foldri (fn (a, _, b) => Int.max (a, b)) 0 map | |
275 | val nums = List.tabulate (maxln+1, fn x => x) | |
276 | in | |
277 | List.map (fn num => valOf (LiveMap.find (map, num)) handle Option => OperSet.empty) nums | |
278 | end | |
279 | end |