Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 2009,2014,2017 Matthew Fluet. |
2 | * Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh | |
3 | * Jagannathan, and Stephen Weeks. | |
4 | * Copyright (C) 1997-2000 NEC Research Institute. | |
5 | * | |
6 | * MLton is released under a BSD-style license. | |
7 | * See the file MLton-LICENSE for details. | |
8 | *) | |
9 | ||
10 | functor SsaTree (S: SSA_TREE_STRUCTS): SSA_TREE = | |
11 | struct | |
12 | ||
13 | open S | |
14 | ||
15 | structure Type = | |
16 | struct | |
17 | datatype t = | |
18 | T of {hash: Word.t, | |
19 | plist: PropertyList.t, | |
20 | tree: tree} | |
21 | and tree = | |
22 | Array of t | |
23 | | CPointer | |
24 | | Datatype of Tycon.t | |
25 | | IntInf | |
26 | | Real of RealSize.t | |
27 | | Ref of t | |
28 | | Thread | |
29 | | Tuple of t vector | |
30 | | Vector of t | |
31 | | Weak of t | |
32 | | Word of WordSize.t | |
33 | ||
34 | local | |
35 | fun make f (T r) = f r | |
36 | in | |
37 | val hash = make #hash | |
38 | val plist = make #plist | |
39 | val tree = make #tree | |
40 | end | |
41 | ||
42 | datatype dest = datatype tree | |
43 | ||
44 | val dest = tree | |
45 | ||
46 | fun equals (t, t') = PropertyList.equals (plist t, plist t') | |
47 | ||
48 | local | |
49 | fun make (sel : dest -> 'a option) = | |
50 | let | |
51 | val deOpt: t -> 'a option = fn t => sel (dest t) | |
52 | val de: t -> 'a = valOf o deOpt | |
53 | val is: t -> bool = isSome o deOpt | |
54 | in | |
55 | (deOpt, de, is) | |
56 | end | |
57 | in | |
58 | val (_,deArray,_) = make (fn Array t => SOME t | _ => NONE) | |
59 | val (_,deDatatype,_) = make (fn Datatype tyc => SOME tyc | _ => NONE) | |
60 | val (_,deRef,_) = make (fn Ref t => SOME t | _ => NONE) | |
61 | val (deTupleOpt,deTuple,isTuple) = make (fn Tuple ts => SOME ts | _ => NONE) | |
62 | val (_,deVector,_) = make (fn Vector t => SOME t | _ => NONE) | |
63 | val (_,deWeak,_) = make (fn Weak t => SOME t | _ => NONE) | |
64 | val (deWordOpt,deWord,_) = make (fn Word ws => SOME ws | _ => NONE) | |
65 | end | |
66 | ||
67 | local | |
68 | val same: tree * tree -> bool = | |
69 | fn (Array t1, Array t2) => equals (t1, t2) | |
70 | | (CPointer, CPointer) => true | |
71 | | (Datatype t1, Datatype t2) => Tycon.equals (t1, t2) | |
72 | | (IntInf, IntInf) => true | |
73 | | (Real s1, Real s2) => RealSize.equals (s1, s2) | |
74 | | (Ref t1, Ref t2) => equals (t1, t2) | |
75 | | (Thread, Thread) => true | |
76 | | (Tuple ts1, Tuple ts2) => Vector.equals (ts1, ts2, equals) | |
77 | | (Vector t1, Vector t2) => equals (t1, t2) | |
78 | | (Weak t1, Weak t2) => equals (t1, t2) | |
79 | | (Word s1, Word s2) => WordSize.equals (s1, s2) | |
80 | | _ => false | |
81 | val table: t HashSet.t = HashSet.new {hash = hash} | |
82 | in | |
83 | fun lookup (hash, tr) = | |
84 | HashSet.lookupOrInsert (table, hash, | |
85 | fn t => same (tr, tree t), | |
86 | fn () => T {hash = hash, | |
87 | plist = PropertyList.new (), | |
88 | tree = tr}) | |
89 | ||
90 | fun stats () = | |
91 | let open Layout | |
92 | in align [seq [str "num types in hash table = ", | |
93 | Int.layout (HashSet.size table)], | |
94 | Control.sizeMessage ("types hash table", lookup)] | |
95 | end | |
96 | end | |
97 | ||
98 | val newHash = Random.word | |
99 | ||
100 | local | |
101 | fun make f : t -> t = | |
102 | let | |
103 | val w = newHash () | |
104 | in | |
105 | fn t => lookup (Word.xorb (w, hash t), f t) | |
106 | end | |
107 | in | |
108 | val array = make Array | |
109 | val reff = make Ref | |
110 | val vector = make Vector | |
111 | val weak = make Weak | |
112 | end | |
113 | ||
114 | val datatypee: Tycon.t -> t = | |
115 | fn t => lookup (Tycon.hash t, Datatype t) | |
116 | ||
117 | val bool = datatypee Tycon.bool | |
118 | ||
119 | local | |
120 | fun make (tycon, tree) = lookup (Tycon.hash tycon, tree) | |
121 | in | |
122 | val cpointer = make (Tycon.cpointer, CPointer) | |
123 | val intInf = make (Tycon.intInf, IntInf) | |
124 | val thread = make (Tycon.thread, Thread) | |
125 | end | |
126 | ||
127 | val real: RealSize.t -> t = | |
128 | fn s => lookup (Tycon.hash (Tycon.real s), Real s) | |
129 | ||
130 | val word: WordSize.t -> t = | |
131 | fn s => lookup (Tycon.hash (Tycon.word s), Word s) | |
132 | ||
133 | ||
134 | local | |
135 | val generator: Word.t = 0wx5555 | |
136 | val w = newHash () | |
137 | in | |
138 | fun tuple ts = | |
139 | if 1 = Vector.length ts | |
140 | then Vector.first ts | |
141 | else lookup (Vector.fold (ts, w, fn (t, w) => | |
142 | Word.xorb (w * generator, hash t)), | |
143 | Tuple ts) | |
144 | end | |
145 | ||
146 | fun ofConst c = | |
147 | let | |
148 | datatype z = datatype Const.t | |
149 | in | |
150 | case c of | |
151 | IntInf _ => intInf | |
152 | | Null => cpointer | |
153 | | Real r => real (RealX.size r) | |
154 | | Word w => word (WordX.size w) | |
155 | | WordVector v => vector (word (WordXVector.elementSize v)) | |
156 | end | |
157 | ||
158 | val unit: t = tuple (Vector.new0 ()) | |
159 | ||
160 | val isUnit: t -> bool = | |
161 | fn t => | |
162 | case deTupleOpt t of | |
163 | SOME ts => Vector.isEmpty ts | |
164 | | _ => false | |
165 | ||
166 | local | |
167 | open Layout | |
168 | in | |
169 | val {get = layout, ...} = | |
170 | Property.get | |
171 | (plist, | |
172 | Property.initRec | |
173 | (fn (t, layout) => | |
174 | case dest t of | |
175 | Array t => seq [layout t, str " array"] | |
176 | | CPointer => str "pointer" | |
177 | | Datatype t => Tycon.layout t | |
178 | | IntInf => str "intInf" | |
179 | | Real s => str (concat ["real", RealSize.toString s]) | |
180 | | Ref t => seq [layout t, str " ref"] | |
181 | | Thread => str "thread" | |
182 | | Tuple ts => | |
183 | if Vector.isEmpty ts | |
184 | then str "unit" | |
185 | else seq [str "(", | |
186 | (mayAlign o separateRight) | |
187 | (Vector.toListMap (ts, layout), " *"), | |
188 | str ")"] | |
189 | | Vector t => seq [layout t, str " vector"] | |
190 | | Weak t => seq [layout t, str " weak"] | |
191 | | Word s => str (concat ["word", WordSize.toString s]))) | |
192 | end | |
193 | ||
194 | fun checkPrimApp {args, prim, result, targs}: bool = | |
195 | let | |
196 | exception BadPrimApp | |
197 | fun default () = | |
198 | Prim.checkApp | |
199 | (prim, | |
200 | {args = args, | |
201 | result = result, | |
202 | targs = targs, | |
203 | typeOps = {array = array, | |
204 | arrow = fn _ => raise BadPrimApp, | |
205 | bool = bool, | |
206 | cpointer = cpointer, | |
207 | equals = equals, | |
208 | exn = unit, | |
209 | intInf = intInf, | |
210 | real = real, | |
211 | reff = reff, | |
212 | thread = thread, | |
213 | unit = unit, | |
214 | vector = vector, | |
215 | weak = weak, | |
216 | word = word}}) | |
217 | val default = fn () => | |
218 | (default ()) handle BadPrimApp => false | |
219 | ||
220 | datatype z = datatype Prim.Name.t | |
221 | in | |
222 | case Prim.name prim of | |
223 | _ => default () | |
224 | end | |
225 | end | |
226 | ||
227 | structure Cases = | |
228 | struct | |
229 | datatype t = | |
230 | Con of (Con.t * Label.t) vector | |
231 | | Word of WordSize.t * (WordX.t * Label.t) vector | |
232 | ||
233 | fun equals (c1: t, c2: t): bool = | |
234 | let | |
235 | fun doit (l1, l2, eq') = | |
236 | Vector.equals | |
237 | (l1, l2, fn ((x1, a1), (x2, a2)) => | |
238 | eq' (x1, x2) andalso Label.equals (a1, a2)) | |
239 | in | |
240 | case (c1, c2) of | |
241 | (Con l1, Con l2) => doit (l1, l2, Con.equals) | |
242 | | (Word (_, l1), Word (_, l2)) => doit (l1, l2, WordX.equals) | |
243 | | _ => false | |
244 | end | |
245 | ||
246 | fun hd (c: t): Label.t = | |
247 | let | |
248 | fun doit v = | |
249 | if Vector.length v >= 1 | |
250 | then let val (_, a) = Vector.first v | |
251 | in a | |
252 | end | |
253 | else Error.bug "SsaTree.Cases.hd" | |
254 | in | |
255 | case c of | |
256 | Con cs => doit cs | |
257 | | Word (_, cs) => doit cs | |
258 | end | |
259 | ||
260 | fun isEmpty (c: t): bool = | |
261 | let | |
262 | fun doit v = Vector.isEmpty v | |
263 | in | |
264 | case c of | |
265 | Con cs => doit cs | |
266 | | Word (_, cs) => doit cs | |
267 | end | |
268 | ||
269 | fun fold (c: t, b, f) = | |
270 | let | |
271 | fun doit l = Vector.fold (l, b, fn ((_, a), b) => f (a, b)) | |
272 | in | |
273 | case c of | |
274 | Con l => doit l | |
275 | | Word (_, l) => doit l | |
276 | end | |
277 | ||
278 | fun map (c: t, f): t = | |
279 | let | |
280 | fun doit l = Vector.map (l, fn (i, x) => (i, f x)) | |
281 | in | |
282 | case c of | |
283 | Con l => Con (doit l) | |
284 | | Word (s, l) => Word (s, doit l) | |
285 | end | |
286 | ||
287 | fun forall (c: t, f: Label.t -> bool): bool = | |
288 | let | |
289 | fun doit l = Vector.forall (l, fn (_, x) => f x) | |
290 | in | |
291 | case c of | |
292 | Con l => doit l | |
293 | | Word (_, l) => doit l | |
294 | end | |
295 | ||
296 | fun length (c: t): int = fold (c, 0, fn (_, i) => i + 1) | |
297 | ||
298 | fun foreach (c, f) = fold (c, (), fn (x, ()) => f x) | |
299 | end | |
300 | ||
301 | structure Size = | |
302 | struct | |
303 | val check: int * int option -> int *bool = | |
304 | fn (size, NONE) => (size,false) | |
305 | | (size, SOME max) => (size,size > max) | |
306 | end | |
307 | ||
308 | structure Exp = | |
309 | struct | |
310 | datatype t = | |
311 | ConApp of {con: Con.t, | |
312 | args: Var.t vector} | |
313 | | Const of Const.t | |
314 | | PrimApp of {prim: Type.t Prim.t, | |
315 | targs: Type.t vector, | |
316 | args: Var.t vector} | |
317 | | Profile of ProfileExp.t | |
318 | | Select of {tuple: Var.t, | |
319 | offset: int} | |
320 | | Tuple of Var.t vector | |
321 | | Var of Var.t | |
322 | ||
323 | val unit = Tuple (Vector.new0 ()) | |
324 | ||
325 | (* Vals to determine the size for inline.fun and loop optimization*) | |
326 | val size : t -> int = | |
327 | fn ConApp {args, ...} => 1 + Vector.length args | |
328 | | Const _ => 0 | |
329 | | PrimApp {args, ...} => 1 + Vector.length args | |
330 | | Profile _ => 0 | |
331 | | Select _ => 1 + 1 | |
332 | | Tuple xs => 1 + Vector.length xs | |
333 | | Var _ => 0 | |
334 | ||
335 | fun foreachVar (e, v) = | |
336 | let | |
337 | fun vs xs = Vector.foreach (xs, v) | |
338 | in | |
339 | case e of | |
340 | ConApp {args, ...} => vs args | |
341 | | Const _ => () | |
342 | | PrimApp {args, ...} => vs args | |
343 | | Profile _ => () | |
344 | | Select {tuple, ...} => v tuple | |
345 | | Tuple xs => vs xs | |
346 | | Var x => v x | |
347 | end | |
348 | ||
349 | fun replaceVar (e, fx) = | |
350 | let | |
351 | fun fxs xs = Vector.map (xs, fx) | |
352 | in | |
353 | case e of | |
354 | ConApp {con, args} => ConApp {con = con, args = fxs args} | |
355 | | Const _ => e | |
356 | | PrimApp {prim, targs, args} => | |
357 | PrimApp {prim = prim, targs = targs, args = fxs args} | |
358 | | Profile _ => e | |
359 | | Select {tuple, offset} => | |
360 | Select {tuple = fx tuple, offset = offset} | |
361 | | Tuple xs => Tuple (fxs xs) | |
362 | | Var x => Var (fx x) | |
363 | end | |
364 | ||
365 | fun layout' (e, layoutVar) = | |
366 | let | |
367 | open Layout | |
368 | fun layoutArgs xs = Vector.layout layoutVar xs | |
369 | in | |
370 | case e of | |
371 | ConApp {con, args} => | |
372 | seq [Con.layout con, | |
373 | if Vector.isEmpty args | |
374 | then empty | |
375 | else seq [str " ", layoutArgs args]] | |
376 | | Const c => Const.layout c | |
377 | | PrimApp {prim, targs, args} => | |
378 | seq [Prim.layout prim, | |
379 | if !Control.showTypes | |
380 | then if Vector.isEmpty targs | |
381 | then empty | |
382 | else Vector.layout Type.layout targs | |
383 | else empty, | |
384 | str " ", | |
385 | layoutArgs args] | |
386 | | Profile p => ProfileExp.layout p | |
387 | | Select {tuple, offset} => | |
388 | seq [str "#", Int.layout offset, str " ", | |
389 | paren (layoutVar tuple)] | |
390 | | Tuple xs => layoutArgs xs | |
391 | | Var x => layoutVar x | |
392 | end | |
393 | fun layout e = layout' (e, Var.layout) | |
394 | ||
395 | fun maySideEffect (e: t): bool = | |
396 | case e of | |
397 | ConApp _ => false | |
398 | | Const _ => false | |
399 | | PrimApp {prim,...} => Prim.maySideEffect prim | |
400 | | Profile _ => false | |
401 | | Select _ => false | |
402 | | Tuple _ => false | |
403 | | Var _ => false | |
404 | ||
405 | fun varsEquals (xs, xs') = Vector.equals (xs, xs', Var.equals) | |
406 | ||
407 | fun equals (e: t, e': t): bool = | |
408 | case (e, e') of | |
409 | (ConApp {con, args}, ConApp {con = con', args = args'}) => | |
410 | Con.equals (con, con') andalso varsEquals (args, args') | |
411 | | (Const c, Const c') => Const.equals (c, c') | |
412 | | (PrimApp {prim, args, ...}, | |
413 | PrimApp {prim = prim', args = args', ...}) => | |
414 | Prim.equals (prim, prim') andalso varsEquals (args, args') | |
415 | | (Profile p, Profile p') => ProfileExp.equals (p, p') | |
416 | | (Select {tuple = t, offset = i}, Select {tuple = t', offset = i'}) => | |
417 | Var.equals (t, t') andalso i = i' | |
418 | | (Tuple xs, Tuple xs') => varsEquals (xs, xs') | |
419 | | (Var x, Var x') => Var.equals (x, x') | |
420 | | _ => false | |
421 | ||
422 | local | |
423 | val newHash = Random.word | |
424 | val primApp = newHash () | |
425 | val profile = newHash () | |
426 | val select = newHash () | |
427 | val tuple = newHash () | |
428 | fun hashVars (xs: Var.t vector, w: Word.t): Word.t = | |
429 | Vector.fold (xs, w, fn (x, w) => Word.xorb (w, Var.hash x)) | |
430 | in | |
431 | val hash: t -> Word.t = | |
432 | fn ConApp {con, args, ...} => hashVars (args, Con.hash con) | |
433 | | Const c => Const.hash c | |
434 | | PrimApp {args, ...} => hashVars (args, primApp) | |
435 | | Profile p => Word.xorb (profile, ProfileExp.hash p) | |
436 | | Select {tuple, offset} => | |
437 | Word.xorb (select, Var.hash tuple + Word.fromInt offset) | |
438 | | Tuple xs => hashVars (xs, tuple) | |
439 | | Var x => Var.hash x | |
440 | end | |
441 | ||
442 | val hash = Trace.trace ("SsaTree.Exp.hash", layout, Word.layout) hash | |
443 | end | |
444 | datatype z = datatype Exp.t | |
445 | ||
446 | structure Statement = | |
447 | struct | |
448 | datatype t = T of {var: Var.t option, | |
449 | ty: Type.t, | |
450 | exp: Exp.t} | |
451 | ||
452 | local | |
453 | fun make f (T r) = f r | |
454 | in | |
455 | val var = make #var | |
456 | val exp = make #exp | |
457 | end | |
458 | ||
459 | fun sizeAux (T {exp, ...}, acc, max, sizeExp) = | |
460 | Size.check (sizeExp exp + acc, max) | |
461 | ||
462 | fun layout' (T {var, ty, exp}, layoutVar) = | |
463 | let | |
464 | open Layout | |
465 | val (sep, ty) = | |
466 | if !Control.showTypes | |
467 | then (str ":", indent (seq [Type.layout ty, str " ="], 2)) | |
468 | else (str " =", empty) | |
469 | in | |
470 | mayAlign [mayAlign [seq [case var of | |
471 | NONE => str "_" | |
472 | | SOME var => Var.layout var, | |
473 | sep], | |
474 | ty], | |
475 | indent (Exp.layout' (exp, layoutVar), 2)] | |
476 | end | |
477 | fun layout e = layout' (e, Var.layout) | |
478 | ||
479 | local | |
480 | fun make f x = | |
481 | T {var = NONE, | |
482 | ty = Type.unit, | |
483 | exp = f x} | |
484 | in | |
485 | val profile = make Exp.Profile | |
486 | end | |
487 | ||
488 | fun clear s = Option.app (var s, Var.clear) | |
489 | ||
490 | fun prettifyGlobals (v: t vector): Var.t -> Layout.t = | |
491 | let | |
492 | val {get = global: Var.t -> Layout.t, set = setGlobal, ...} = | |
493 | Property.getSet (Var.plist, Property.initFun Var.layout) | |
494 | val _ = | |
495 | Vector.foreach | |
496 | (v, fn T {var, exp, ...} => | |
497 | Option.app | |
498 | (var, fn var => | |
499 | let | |
500 | fun set () = | |
501 | let | |
502 | val s = Layout.toString (Exp.layout' (exp, global)) | |
503 | val maxSize = 20 | |
504 | val dots = " ... " | |
505 | val dotsSize = String.size dots | |
506 | val frontSize = 2 * (maxSize - dotsSize) div 3 | |
507 | val backSize = maxSize - dotsSize - frontSize | |
508 | val s = | |
509 | if String.size s > maxSize | |
510 | then concat [String.prefix (s, frontSize), | |
511 | dots, | |
512 | String.suffix (s, backSize)] | |
513 | else s | |
514 | in | |
515 | setGlobal (var, Layout.seq [Var.layout var, | |
516 | Layout.str (" (*" ^ s ^ "*)")]) | |
517 | end | |
518 | in | |
519 | case exp of | |
520 | Const _ => set () | |
521 | | ConApp _ => set () | |
522 | | Tuple xs => if Vector.isEmpty xs then set () else () | |
523 | | _ => () | |
524 | end)) | |
525 | in | |
526 | global | |
527 | end | |
528 | end | |
529 | ||
530 | structure Handler = | |
531 | struct | |
532 | structure Label = Label | |
533 | ||
534 | datatype t = | |
535 | Caller | |
536 | | Dead | |
537 | | Handle of Label.t | |
538 | ||
539 | fun layout (h: t): Layout.t = | |
540 | let | |
541 | open Layout | |
542 | in | |
543 | case h of | |
544 | Caller => str "Caller" | |
545 | | Dead => str "Dead" | |
546 | | Handle l => seq [str "Handle ", Label.layout l] | |
547 | end | |
548 | ||
549 | val equals = | |
550 | fn (Caller, Caller) => true | |
551 | | (Dead, Dead) => true | |
552 | | (Handle l, Handle l') => Label.equals (l, l') | |
553 | | _ => false | |
554 | ||
555 | fun foldLabel (h: t, a: 'a, f: Label.t * 'a -> 'a): 'a = | |
556 | case h of | |
557 | Caller => a | |
558 | | Dead => a | |
559 | | Handle l => f (l, a) | |
560 | ||
561 | fun foreachLabel (h, f) = foldLabel (h, (), f o #1) | |
562 | ||
563 | fun map (h, f) = | |
564 | case h of | |
565 | Caller => Caller | |
566 | | Dead => Dead | |
567 | | Handle l => Handle (f l) | |
568 | ||
569 | local | |
570 | val newHash = Random.word | |
571 | val caller = newHash () | |
572 | val dead = newHash () | |
573 | val handlee = newHash () | |
574 | in | |
575 | fun hash (h: t): word = | |
576 | case h of | |
577 | Caller => caller | |
578 | | Dead => dead | |
579 | | Handle l => Word.xorb (handlee, Label.hash l) | |
580 | end | |
581 | end | |
582 | ||
583 | structure Return = | |
584 | struct | |
585 | structure Label = Label | |
586 | structure Handler = Handler | |
587 | ||
588 | datatype t = | |
589 | Dead | |
590 | | NonTail of {cont: Label.t, | |
591 | handler: Handler.t} | |
592 | | Tail | |
593 | ||
594 | fun layout r = | |
595 | let | |
596 | open Layout | |
597 | in | |
598 | case r of | |
599 | Dead => str "Dead" | |
600 | | NonTail {cont, handler} => | |
601 | seq [str "NonTail ", | |
602 | Layout.record | |
603 | [("cont", Label.layout cont), | |
604 | ("handler", Handler.layout handler)]] | |
605 | | Tail => str "Tail" | |
606 | end | |
607 | ||
608 | fun equals (r, r'): bool = | |
609 | case (r, r') of | |
610 | (Dead, Dead) => true | |
611 | | (NonTail {cont = c, handler = h}, | |
612 | NonTail {cont = c', handler = h'}) => | |
613 | Label.equals (c, c') andalso Handler.equals (h, h') | |
614 | | (Tail, Tail) => true | |
615 | | _ => false | |
616 | ||
617 | fun foldLabel (r: t, a, f) = | |
618 | case r of | |
619 | Dead => a | |
620 | | NonTail {cont, handler} => | |
621 | Handler.foldLabel (handler, f (cont, a), f) | |
622 | | Tail => a | |
623 | ||
624 | fun foreachLabel (r, f) = foldLabel (r, (), f o #1) | |
625 | ||
626 | fun foreachHandler (r, f) = | |
627 | case r of | |
628 | Dead => () | |
629 | | NonTail {handler, ...} => Handler.foreachLabel (handler, f) | |
630 | | Tail => () | |
631 | ||
632 | fun map (r, f) = | |
633 | case r of | |
634 | Dead => Dead | |
635 | | NonTail {cont, handler} => | |
636 | NonTail {cont = f cont, | |
637 | handler = Handler.map (handler, f)} | |
638 | | Tail => Tail | |
639 | ||
640 | fun compose (r, r') = | |
641 | case r' of | |
642 | Dead => Dead | |
643 | | NonTail {cont, handler} => | |
644 | NonTail | |
645 | {cont = cont, | |
646 | handler = (case handler of | |
647 | Handler.Caller => | |
648 | (case r of | |
649 | Dead => Handler.Caller | |
650 | | NonTail {handler, ...} => handler | |
651 | | Tail => Handler.Caller) | |
652 | | Handler.Dead => handler | |
653 | | Handler.Handle _ => handler)} | |
654 | | Tail => r | |
655 | ||
656 | local | |
657 | val newHash = Random.word | |
658 | val dead = newHash () | |
659 | val nonTail = newHash () | |
660 | val tail = newHash () | |
661 | in | |
662 | fun hash r = | |
663 | case r of | |
664 | Dead => dead | |
665 | | NonTail {cont, handler} => | |
666 | Word.xorb (Word.xorb (nonTail, Label.hash cont), | |
667 | Handler.hash handler) | |
668 | | Tail => tail | |
669 | end | |
670 | end | |
671 | ||
672 | structure Transfer = | |
673 | struct | |
674 | datatype t = | |
675 | Arith of {prim: Type.t Prim.t, | |
676 | args: Var.t vector, | |
677 | overflow: Label.t, (* Must be nullary. *) | |
678 | success: Label.t, (* Must be unary. *) | |
679 | ty: Type.t} | |
680 | | Bug (* MLton thought control couldn't reach here. *) | |
681 | | Call of {args: Var.t vector, | |
682 | func: Func.t, | |
683 | return: Return.t} | |
684 | | Case of {test: Var.t, | |
685 | cases: Cases.t, | |
686 | default: Label.t option} (* Must be nullary. *) | |
687 | | Goto of {dst: Label.t, | |
688 | args: Var.t vector} | |
689 | | Raise of Var.t vector | |
690 | | Return of Var.t vector | |
691 | | Runtime of {prim: Type.t Prim.t, | |
692 | args: Var.t vector, | |
693 | return: Label.t} (* Must be nullary. *) | |
694 | ||
695 | (* Vals to determine the size for inline.fun and loop optimization*) | |
696 | val size = | |
697 | fn Arith {args, ...} => 1 + Vector.length args | |
698 | | Bug => 1 | |
699 | | Call {args, ...} => 1 + Vector.length args | |
700 | | Case {cases, ...} => 1 + Cases.length cases | |
701 | | Goto {args, ...} => 1 + Vector.length args | |
702 | | Raise xs => 1 + Vector.length xs | |
703 | | Return xs => 1 + Vector.length xs | |
704 | | Runtime {args, ...} => 1 + Vector.length args | |
705 | ||
706 | fun foreachFuncLabelVar (t, func: Func.t -> unit, label: Label.t -> unit, var) = | |
707 | let | |
708 | fun vars xs = Vector.foreach (xs, var) | |
709 | in | |
710 | case t of | |
711 | Arith {args, overflow, success, ...} => | |
712 | (vars args | |
713 | ; label overflow | |
714 | ; label success) | |
715 | | Bug => () | |
716 | | Call {func = f, args, return, ...} => | |
717 | (func f | |
718 | ; Return.foreachLabel (return, label) | |
719 | ; vars args) | |
720 | | Case {test, cases, default, ...} => | |
721 | (var test | |
722 | ; Cases.foreach (cases, label) | |
723 | ; Option.app (default, label)) | |
724 | | Goto {dst, args, ...} => (vars args; label dst) | |
725 | | Raise xs => vars xs | |
726 | | Return xs => vars xs | |
727 | | Runtime {args, return, ...} => | |
728 | (vars args | |
729 | ; label return) | |
730 | end | |
731 | ||
732 | fun foreachFunc (t, func) = | |
733 | foreachFuncLabelVar (t, func, fn _ => (), fn _ => ()) | |
734 | ||
735 | fun foreachLabelVar (t, label, var) = | |
736 | foreachFuncLabelVar (t, fn _ => (), label, var) | |
737 | ||
738 | fun foreachLabel (t, j) = foreachLabelVar (t, j, fn _ => ()) | |
739 | fun foreachVar (t, v) = foreachLabelVar (t, fn _ => (), v) | |
740 | ||
741 | fun replaceLabelVar (t, fl, fx) = | |
742 | let | |
743 | fun fxs xs = Vector.map (xs, fx) | |
744 | in | |
745 | case t of | |
746 | Arith {prim, args, overflow, success, ty} => | |
747 | Arith {prim = prim, | |
748 | args = fxs args, | |
749 | overflow = fl overflow, | |
750 | success = fl success, | |
751 | ty = ty} | |
752 | | Bug => Bug | |
753 | | Call {func, args, return} => | |
754 | Call {func = func, | |
755 | args = fxs args, | |
756 | return = Return.map (return, fl)} | |
757 | | Case {test, cases, default} => | |
758 | Case {test = fx test, | |
759 | cases = Cases.map(cases, fl), | |
760 | default = Option.map(default, fl)} | |
761 | | Goto {dst, args} => | |
762 | Goto {dst = fl dst, | |
763 | args = fxs args} | |
764 | | Raise xs => Raise (fxs xs) | |
765 | | Return xs => Return (fxs xs) | |
766 | | Runtime {prim, args, return} => | |
767 | Runtime {prim = prim, | |
768 | args = fxs args, | |
769 | return = fl return} | |
770 | end | |
771 | ||
772 | fun replaceLabel (t, f) = replaceLabelVar (t, f, fn x => x) | |
773 | fun replaceVar (t, f) = replaceLabelVar (t, fn l => l, f) | |
774 | ||
775 | local | |
776 | fun layoutCase ({test, cases, default}, layoutVar) = | |
777 | let | |
778 | open Layout | |
779 | fun doit (l, layout) = | |
780 | Vector.toListMap | |
781 | (l, fn (i, l) => | |
782 | seq [layout i, str " => ", Label.layout l]) | |
783 | datatype z = datatype Cases.t | |
784 | val cases = | |
785 | case cases of | |
786 | Con l => doit (l, Con.layout) | |
787 | | Word (_, l) => doit (l, WordX.layout) | |
788 | val cases = | |
789 | case default of | |
790 | NONE => cases | |
791 | | SOME j => | |
792 | cases @ [seq [str "_ => ", Label.layout j]] | |
793 | in | |
794 | align [seq [str "case ", layoutVar test, str " of"], | |
795 | indent (alignPrefix (cases, "| "), 2)] | |
796 | end | |
797 | in | |
798 | fun layout' (t, layoutVar) = | |
799 | let | |
800 | open Layout | |
801 | fun layoutArgs xs = Vector.layout layoutVar xs | |
802 | fun layoutPrim {prim, args} = | |
803 | Exp.layout' | |
804 | (Exp.PrimApp {prim = prim, | |
805 | targs = Vector.new0 (), | |
806 | args = args}, | |
807 | layoutVar) | |
808 | in | |
809 | case t of | |
810 | Arith {prim, args, overflow, success, ...} => | |
811 | seq [Label.layout success, str " ", | |
812 | tuple [layoutPrim {prim = prim, args = args}], | |
813 | str " handle Overflow => ", Label.layout overflow] | |
814 | | Bug => str "Bug" | |
815 | | Call {func, args, return} => | |
816 | let | |
817 | val call = seq [Func.layout func, str " ", layoutArgs args] | |
818 | in | |
819 | case return of | |
820 | Return.Dead => seq [str "dead ", paren call] | |
821 | | Return.NonTail {cont, handler} => | |
822 | seq [Label.layout cont, str " ", | |
823 | paren call, | |
824 | str " handle _ => ", | |
825 | case handler of | |
826 | Handler.Caller => str "raise" | |
827 | | Handler.Dead => str "dead" | |
828 | | Handler.Handle l => Label.layout l] | |
829 | | Return.Tail => seq [str "return ", paren call] | |
830 | end | |
831 | | Case arg => layoutCase (arg, layoutVar) | |
832 | | Goto {dst, args} => | |
833 | seq [Label.layout dst, str " ", layoutArgs args] | |
834 | | Raise xs => seq [str "raise ", layoutArgs xs] | |
835 | | Return xs => seq [str "return ", layoutArgs xs] | |
836 | | Runtime {prim, args, return} => | |
837 | seq [Label.layout return, str " ", | |
838 | tuple [layoutPrim {prim = prim, args = args}]] | |
839 | end | |
840 | end | |
841 | fun layout t = layout' (t, Var.layout) | |
842 | ||
843 | fun varsEquals (xs, xs') = Vector.equals (xs, xs', Var.equals) | |
844 | ||
845 | fun equals (e: t, e': t): bool = | |
846 | case (e, e') of | |
847 | (Arith {prim, args, overflow, success, ...}, | |
848 | Arith {prim = prim', args = args', | |
849 | overflow = overflow', success = success', ...}) => | |
850 | Prim.equals (prim, prim') andalso | |
851 | varsEquals (args, args') andalso | |
852 | Label.equals (overflow, overflow') andalso | |
853 | Label.equals (success, success') | |
854 | | (Bug, Bug) => true | |
855 | | (Call {func, args, return}, | |
856 | Call {func = func', args = args', return = return'}) => | |
857 | Func.equals (func, func') andalso | |
858 | varsEquals (args, args') andalso | |
859 | Return.equals (return, return') | |
860 | | (Case {test, cases, default}, | |
861 | Case {test = test', cases = cases', default = default'}) => | |
862 | Var.equals (test, test') | |
863 | andalso Cases.equals (cases, cases') | |
864 | andalso Option.equals (default, default', Label.equals) | |
865 | | (Goto {dst, args}, Goto {dst = dst', args = args'}) => | |
866 | Label.equals (dst, dst') andalso | |
867 | varsEquals (args, args') | |
868 | | (Raise xs, Raise xs') => varsEquals (xs, xs') | |
869 | | (Return xs, Return xs') => varsEquals (xs, xs') | |
870 | | (Runtime {prim, args, return}, | |
871 | Runtime {prim = prim', args = args', return = return'}) => | |
872 | Prim.equals (prim, prim') andalso | |
873 | varsEquals (args, args') andalso | |
874 | Label.equals (return, return') | |
875 | | _ => false | |
876 | ||
877 | local | |
878 | val newHash = Random.word | |
879 | val bug = newHash () | |
880 | val raisee = newHash () | |
881 | val return = newHash () | |
882 | fun hashVars (xs: Var.t vector, w: Word.t): Word.t = | |
883 | Vector.fold (xs, w, fn (x, w) => Word.xorb (w, Var.hash x)) | |
884 | fun hash2 (w1: Word.t, w2: Word.t) = Word.xorb (w1, w2) | |
885 | in | |
886 | val hash: t -> Word.t = | |
887 | fn Arith {args, overflow, success, ...} => | |
888 | hashVars (args, hash2 (Label.hash overflow, | |
889 | Label.hash success)) | |
890 | | Bug => bug | |
891 | | Call {func, args, return} => | |
892 | hashVars (args, hash2 (Func.hash func, Return.hash return)) | |
893 | | Case {test, cases, default} => | |
894 | hash2 (Var.hash test, | |
895 | Cases.fold | |
896 | (cases, | |
897 | Option.fold | |
898 | (default, 0wx55555555, | |
899 | fn (l, w) => | |
900 | hash2 (Label.hash l, w)), | |
901 | fn (l, w) => | |
902 | hash2 (Label.hash l, w))) | |
903 | | Goto {dst, args} => | |
904 | hashVars (args, Label.hash dst) | |
905 | | Raise xs => hashVars (xs, raisee) | |
906 | | Return xs => hashVars (xs, return) | |
907 | | Runtime {args, return, ...} => hashVars (args, Label.hash return) | |
908 | end | |
909 | ||
910 | val hash = Trace.trace ("SsaTree.Transfer.hash", layout, Word.layout) hash | |
911 | ||
912 | end | |
913 | datatype z = datatype Transfer.t | |
914 | ||
915 | local | |
916 | open Layout | |
917 | in | |
918 | fun layoutFormals (xts: (Var.t * Type.t) vector) = | |
919 | Vector.layout (fn (x, t) => | |
920 | seq [Var.layout x, | |
921 | if !Control.showTypes | |
922 | then seq [str ": ", Type.layout t] | |
923 | else empty]) | |
924 | xts | |
925 | end | |
926 | ||
927 | structure Block = | |
928 | struct | |
929 | datatype t = | |
930 | T of {args: (Var.t * Type.t) vector, | |
931 | label: Label.t, | |
932 | statements: Statement.t vector, | |
933 | transfer: Transfer.t} | |
934 | ||
935 | local | |
936 | fun make f (T r) = f r | |
937 | in | |
938 | val args = make #args | |
939 | val label = make #label | |
940 | val statements = make #statements | |
941 | val transfer = make #transfer | |
942 | end | |
943 | ||
944 | fun sizeAux (T {statements, transfer, ...}, | |
945 | acc, max, sizeExp, sizeTransfer) = | |
946 | Exn.withEscape | |
947 | (fn escape => | |
948 | Vector.fold | |
949 | (statements, Size.check (acc + sizeTransfer transfer, max), | |
950 | fn (stmt, (acc, chk)) => | |
951 | if chk | |
952 | then escape (acc, chk) | |
953 | else Statement.sizeAux (stmt, acc, max, sizeExp))) | |
954 | ||
955 | fun sizeAuxV (bs, acc, max, sizeExp, sizeTransfer) = | |
956 | Exn.withEscape | |
957 | (fn escape => | |
958 | Vector.fold | |
959 | (bs, (acc, false), fn (b, (acc, chk)) => | |
960 | if chk | |
961 | then escape (acc, chk) | |
962 | else sizeAux (b, acc, max, sizeExp, sizeTransfer))) | |
963 | ||
964 | fun sizeV (bs, {sizeExp, sizeTransfer}) = | |
965 | #1 (sizeAuxV (bs, 0, NONE, sizeExp, sizeTransfer)) | |
966 | ||
967 | fun layout' (T {label, args, statements, transfer}, layoutVar) = | |
968 | let | |
969 | open Layout | |
970 | fun layoutStatement s = Statement.layout' (s, layoutVar) | |
971 | fun layoutTransfer t = Transfer.layout' (t, layoutVar) | |
972 | in | |
973 | align [seq [Label.layout label, str " ", | |
974 | layoutFormals args], | |
975 | indent (align | |
976 | [align | |
977 | (Vector.toListMap (statements, layoutStatement)), | |
978 | layoutTransfer transfer], | |
979 | 2)] | |
980 | end | |
981 | fun layout b = layout' (b, Var.layout) | |
982 | ||
983 | fun clear (T {label, args, statements, ...}) = | |
984 | (Label.clear label | |
985 | ; Vector.foreach (args, Var.clear o #1) | |
986 | ; Vector.foreach (statements, Statement.clear)) | |
987 | end | |
988 | ||
989 | structure Datatype = | |
990 | struct | |
991 | datatype t = | |
992 | T of { | |
993 | tycon: Tycon.t, | |
994 | cons: {con: Con.t, | |
995 | args: Type.t vector} vector | |
996 | } | |
997 | ||
998 | fun layout (T {tycon, cons}) = | |
999 | let | |
1000 | open Layout | |
1001 | in | |
1002 | seq [Tycon.layout tycon, | |
1003 | str " = ", | |
1004 | alignPrefix | |
1005 | (Vector.toListMap | |
1006 | (cons, fn {con, args} => | |
1007 | seq [Con.layout con, | |
1008 | if Vector.isEmpty args | |
1009 | then empty | |
1010 | else seq [str " of ", | |
1011 | Vector.layout Type.layout args]]), | |
1012 | "| ")] | |
1013 | end | |
1014 | ||
1015 | fun clear (T {tycon, cons}) = | |
1016 | (Tycon.clear tycon | |
1017 | ; Vector.foreach (cons, Con.clear o #con)) | |
1018 | end | |
1019 | ||
1020 | structure Function = | |
1021 | struct | |
1022 | structure CPromise = ClearablePromise | |
1023 | ||
1024 | type dest = {args: (Var.t * Type.t) vector, | |
1025 | blocks: Block.t vector, | |
1026 | mayInline: bool, | |
1027 | name: Func.t, | |
1028 | raises: Type.t vector option, | |
1029 | returns: Type.t vector option, | |
1030 | start: Label.t} | |
1031 | ||
1032 | (* There is a messy interaction between the laziness used in controlFlow | |
1033 | * and the property lists on labels because the former stores | |
1034 | * stuff on the property lists. So, if you force the laziness, then | |
1035 | * clear the property lists, then try to use the lazy stuff, you will | |
1036 | * get screwed with undefined properties. The right thing to do is reset | |
1037 | * the laziness when the properties are cleared. | |
1038 | *) | |
1039 | datatype t = | |
1040 | T of {controlFlow: | |
1041 | {dfsTree: unit -> Block.t Tree.t, | |
1042 | dominatorTree: unit -> Block.t Tree.t, | |
1043 | graph: unit DirectedGraph.t, | |
1044 | labelNode: Label.t -> unit DirectedGraph.Node.t, | |
1045 | nodeBlock: unit DirectedGraph.Node.t -> Block.t} CPromise.t, | |
1046 | dest: dest} | |
1047 | ||
1048 | local | |
1049 | fun make f (T {dest, ...}) = f dest | |
1050 | in | |
1051 | val blocks = make #blocks | |
1052 | val dest = make (fn d => d) | |
1053 | val mayInline = make #mayInline | |
1054 | val name = make #name | |
1055 | end | |
1056 | ||
1057 | fun sizeAux (f, acc, max, sizeExp, sizeTransfer) = | |
1058 | Block.sizeAuxV (blocks f, acc, max, sizeExp, sizeTransfer) | |
1059 | ||
1060 | fun size (f, {sizeExp, sizeTransfer}) = | |
1061 | #1 (sizeAux (f, 0, NONE, sizeExp, sizeTransfer)) | |
1062 | ||
1063 | fun sizeMax (f, {max, sizeExp, sizeTransfer}) = | |
1064 | let | |
1065 | val (s, chk) = sizeAux (f, 0, max, sizeExp, sizeTransfer) | |
1066 | in | |
1067 | if chk | |
1068 | then NONE | |
1069 | else SOME s | |
1070 | end | |
1071 | ||
1072 | fun foreachVar (f: t, fx: Var.t * Type.t -> unit): unit = | |
1073 | let | |
1074 | val {args, blocks, ...} = dest f | |
1075 | val _ = Vector.foreach (args, fx) | |
1076 | val _ = | |
1077 | Vector.foreach | |
1078 | (blocks, fn Block.T {args, statements, ...} => | |
1079 | (Vector.foreach (args, fx) | |
1080 | ; Vector.foreach (statements, fn Statement.T {var, ty, ...} => | |
1081 | Option.app (var, fn x => fx (x, ty))))) | |
1082 | in | |
1083 | () | |
1084 | end | |
1085 | ||
1086 | fun controlFlow (T {controlFlow, ...}) = | |
1087 | let | |
1088 | val {graph, labelNode, nodeBlock, ...} = CPromise.force controlFlow | |
1089 | in | |
1090 | {graph = graph, labelNode = labelNode, nodeBlock = nodeBlock} | |
1091 | end | |
1092 | ||
1093 | local | |
1094 | fun make sel = | |
1095 | fn T {controlFlow, ...} => sel (CPromise.force controlFlow) () | |
1096 | in | |
1097 | val dominatorTree = make #dominatorTree | |
1098 | end | |
1099 | ||
1100 | fun dfs (f, v) = | |
1101 | let | |
1102 | val {blocks, start, ...} = dest f | |
1103 | val numBlocks = Vector.length blocks | |
1104 | val {get = labelIndex, set = setLabelIndex, rem, ...} = | |
1105 | Property.getSetOnce (Label.plist, | |
1106 | Property.initRaise ("index", Label.layout)) | |
1107 | val _ = Vector.foreachi (blocks, fn (i, Block.T {label, ...}) => | |
1108 | setLabelIndex (label, i)) | |
1109 | val visited = Array.array (numBlocks, false) | |
1110 | fun visit (l: Label.t): unit = | |
1111 | let | |
1112 | val i = labelIndex l | |
1113 | in | |
1114 | if Array.sub (visited, i) | |
1115 | then () | |
1116 | else | |
1117 | let | |
1118 | val _ = Array.update (visited, i, true) | |
1119 | val b as Block.T {transfer, ...} = | |
1120 | Vector.sub (blocks, i) | |
1121 | val v' = v b | |
1122 | val _ = Transfer.foreachLabel (transfer, visit) | |
1123 | val _ = v' () | |
1124 | in | |
1125 | () | |
1126 | end | |
1127 | end | |
1128 | val _ = visit start | |
1129 | val _ = Vector.foreach (blocks, rem o Block.label) | |
1130 | in | |
1131 | () | |
1132 | end | |
1133 | ||
1134 | local | |
1135 | structure Graph = DirectedGraph | |
1136 | structure Node = Graph.Node | |
1137 | structure Edge = Graph.Edge | |
1138 | in | |
1139 | fun determineControlFlow ({blocks, start, ...}: dest) = | |
1140 | let | |
1141 | open Dot | |
1142 | val g = Graph.new () | |
1143 | fun newNode () = Graph.newNode g | |
1144 | val {get = labelNode, ...} = | |
1145 | Property.get | |
1146 | (Label.plist, Property.initFun (fn _ => newNode ())) | |
1147 | val {get = nodeInfo: unit Node.t -> {block: Block.t}, | |
1148 | set = setNodeInfo, ...} = | |
1149 | Property.getSetOnce | |
1150 | (Node.plist, Property.initRaise ("info", Node.layout)) | |
1151 | val _ = | |
1152 | Vector.foreach | |
1153 | (blocks, fn b as Block.T {label, transfer, ...} => | |
1154 | let | |
1155 | val from = labelNode label | |
1156 | val _ = setNodeInfo (from, {block = b}) | |
1157 | val _ = | |
1158 | Transfer.foreachLabel | |
1159 | (transfer, fn to => | |
1160 | (ignore o Graph.addEdge) | |
1161 | (g, {from = from, to = labelNode to})) | |
1162 | in | |
1163 | () | |
1164 | end) | |
1165 | val root = labelNode start | |
1166 | val dfsTree = | |
1167 | Promise.lazy | |
1168 | (fn () => | |
1169 | Graph.dfsTree (g, {root = root, | |
1170 | nodeValue = #block o nodeInfo})) | |
1171 | val dominatorTree = | |
1172 | Promise.lazy | |
1173 | (fn () => | |
1174 | Graph.dominatorTree (g, {root = root, | |
1175 | nodeValue = #block o nodeInfo})) | |
1176 | in | |
1177 | {dfsTree = dfsTree, | |
1178 | dominatorTree = dominatorTree, | |
1179 | graph = g, | |
1180 | labelNode = labelNode, | |
1181 | nodeBlock = #block o nodeInfo} | |
1182 | end | |
1183 | ||
1184 | fun layoutDot (f, layoutVar) = | |
1185 | let | |
1186 | fun toStringStatement s = Layout.toString (Statement.layout' (s, layoutVar)) | |
1187 | fun toStringTransfer t = | |
1188 | Layout.toString | |
1189 | (case t of | |
1190 | Case {test, ...} => | |
1191 | Layout.seq [Layout.str "case ", layoutVar test] | |
1192 | | _ => Transfer.layout' (t, layoutVar)) | |
1193 | fun toStringFormals args = Layout.toString (layoutFormals args) | |
1194 | fun toStringHeader (name, args) = concat [name, " ", toStringFormals args] | |
1195 | val {name, args, start, blocks, returns, raises, ...} = dest f | |
1196 | open Dot | |
1197 | val graph = Graph.new () | |
1198 | val {get = nodeOptions, ...} = | |
1199 | Property.get (Node.plist, Property.initFun (fn _ => ref [])) | |
1200 | fun setNodeText (n: unit Node.t, l): unit = | |
1201 | List.push (nodeOptions n, NodeOption.Label l) | |
1202 | fun newNode () = Graph.newNode graph | |
1203 | val {destroy, get = labelNode} = | |
1204 | Property.destGet (Label.plist, | |
1205 | Property.initFun (fn _ => newNode ())) | |
1206 | val {get = edgeOptions, set = setEdgeOptions, ...} = | |
1207 | Property.getSetOnce (Edge.plist, Property.initConst []) | |
1208 | fun edge (from, to, label: string, style: style): unit = | |
1209 | let | |
1210 | val e = Graph.addEdge (graph, {from = from, | |
1211 | to = to}) | |
1212 | val _ = setEdgeOptions (e, [EdgeOption.label label, | |
1213 | EdgeOption.Style style]) | |
1214 | in | |
1215 | () | |
1216 | end | |
1217 | val _ = | |
1218 | Vector.foreach | |
1219 | (blocks, fn Block.T {label, args, statements, transfer} => | |
1220 | let | |
1221 | val from = labelNode label | |
1222 | val edge = fn (to, label, style) => | |
1223 | edge (from, labelNode to, label, style) | |
1224 | val () = | |
1225 | case transfer of | |
1226 | Arith {overflow, success, ...} => | |
1227 | (edge (success, "", Solid) | |
1228 | ; edge (overflow, "Overflow", Dashed)) | |
1229 | | Bug => () | |
1230 | | Call {return, ...} => | |
1231 | let | |
1232 | val _ = | |
1233 | case return of | |
1234 | Return.Dead => () | |
1235 | | Return.NonTail {cont, handler} => | |
1236 | (edge (cont, "", Dotted) | |
1237 | ; (Handler.foreachLabel | |
1238 | (handler, fn l => | |
1239 | edge (l, "Handle", Dashed)))) | |
1240 | | Return.Tail => () | |
1241 | in | |
1242 | () | |
1243 | end | |
1244 | | Case {cases, default, ...} => | |
1245 | let | |
1246 | fun doit (v, toString) = | |
1247 | Vector.foreach | |
1248 | (v, fn (x, j) => | |
1249 | edge (j, toString x, Solid)) | |
1250 | val _ = | |
1251 | case cases of | |
1252 | Cases.Con v => | |
1253 | doit (v, Con.toString) | |
1254 | | Cases.Word (_, v) => | |
1255 | doit (v, WordX.toString) | |
1256 | val _ = | |
1257 | case default of | |
1258 | NONE => () | |
1259 | | SOME j => | |
1260 | edge (j, "Default", Solid) | |
1261 | in | |
1262 | () | |
1263 | end | |
1264 | | Goto {dst, ...} => edge (dst, "", Solid) | |
1265 | | Raise _ => () | |
1266 | | Return _ => () | |
1267 | | Runtime {return, ...} => edge (return, "", Dotted) | |
1268 | val lab = | |
1269 | [(toStringTransfer transfer, Left)] | |
1270 | val lab = | |
1271 | Vector.foldr | |
1272 | (statements, lab, fn (s, ac) => | |
1273 | (toStringStatement s, Left) :: ac) | |
1274 | val lab = | |
1275 | (toStringHeader (Label.toString label, args), Left)::lab | |
1276 | val _ = setNodeText (from, lab) | |
1277 | in | |
1278 | () | |
1279 | end) | |
1280 | val startNode = labelNode start | |
1281 | val funNode = | |
1282 | let | |
1283 | val funNode = newNode () | |
1284 | val _ = edge (funNode, startNode, "Start", Solid) | |
1285 | val lab = | |
1286 | [(toStringTransfer (Transfer.Goto {dst = start, args = Vector.new0 ()}), Left)] | |
1287 | val lab = | |
1288 | if !Control.showTypes | |
1289 | then ((Layout.toString o Layout.seq) | |
1290 | [Layout.str ": ", | |
1291 | Layout.record [("returns", | |
1292 | Option.layout | |
1293 | (Vector.layout Type.layout) | |
1294 | returns), | |
1295 | ("raises", | |
1296 | Option.layout | |
1297 | (Vector.layout Type.layout) | |
1298 | raises)]], | |
1299 | Left)::lab | |
1300 | else lab | |
1301 | val lab = | |
1302 | (toStringHeader ("fun " ^ Func.toString name, args), Left):: | |
1303 | lab | |
1304 | val _ = setNodeText (funNode, lab) | |
1305 | in | |
1306 | funNode | |
1307 | end | |
1308 | val controlFlowGraphLayout = | |
1309 | Graph.layoutDot | |
1310 | (graph, fn {nodeName} => | |
1311 | {title = concat [Func.toString name, " control-flow graph"], | |
1312 | options = [GraphOption.Rank (Min, [{nodeName = nodeName funNode}])], | |
1313 | edgeOptions = edgeOptions, | |
1314 | nodeOptions = | |
1315 | fn n => let | |
1316 | val l = ! (nodeOptions n) | |
1317 | open NodeOption | |
1318 | in FontColor Black :: Shape Box :: l | |
1319 | end}) | |
1320 | val () = Graph.removeNode (graph, funNode) | |
1321 | fun dominatorTreeLayout () = | |
1322 | let | |
1323 | val {get = nodeOptions, set = setNodeOptions, ...} = | |
1324 | Property.getSetOnce (Node.plist, Property.initConst []) | |
1325 | val _ = | |
1326 | Vector.foreach | |
1327 | (blocks, fn Block.T {label, ...} => | |
1328 | setNodeOptions (labelNode label, | |
1329 | [NodeOption.label (Label.toString label)])) | |
1330 | val dominatorTreeLayout = | |
1331 | Tree.layoutDot | |
1332 | (Graph.dominatorTree (graph, | |
1333 | {root = startNode, | |
1334 | nodeValue = fn n => n}), | |
1335 | {title = concat [Func.toString name, " dominator tree"], | |
1336 | options = [], | |
1337 | nodeOptions = nodeOptions}) | |
1338 | in | |
1339 | dominatorTreeLayout | |
1340 | end | |
1341 | fun loopForestLayout () = | |
1342 | let | |
1343 | val {get = nodeName, set = setNodeName, ...} = | |
1344 | Property.getSetOnce (Node.plist, Property.initConst "") | |
1345 | val _ = | |
1346 | Vector.foreach | |
1347 | (blocks, fn Block.T {label, ...} => | |
1348 | setNodeName (labelNode label, Label.toString label)) | |
1349 | val loopForestLayout = | |
1350 | Graph.LoopForest.layoutDot | |
1351 | (Graph.loopForestSteensgaard (graph, | |
1352 | {root = startNode}), | |
1353 | {title = concat [Func.toString name, " loop forest"], | |
1354 | options = [], | |
1355 | nodeName = nodeName}) | |
1356 | in | |
1357 | loopForestLayout | |
1358 | end | |
1359 | in | |
1360 | {destroy = destroy, | |
1361 | controlFlowGraph = controlFlowGraphLayout, | |
1362 | dominatorTree = dominatorTreeLayout, | |
1363 | loopForest = loopForestLayout} | |
1364 | end | |
1365 | end | |
1366 | ||
1367 | fun new (dest: dest) = | |
1368 | let | |
1369 | val controlFlow = CPromise.delay (fn () => determineControlFlow dest) | |
1370 | in | |
1371 | T {controlFlow = controlFlow, | |
1372 | dest = dest} | |
1373 | end | |
1374 | ||
1375 | fun clear (T {controlFlow, dest, ...}) = | |
1376 | let | |
1377 | val {args, blocks, ...} = dest | |
1378 | val _ = (Vector.foreach (args, Var.clear o #1) | |
1379 | ; Vector.foreach (blocks, Block.clear)) | |
1380 | val _ = CPromise.clear controlFlow | |
1381 | in | |
1382 | () | |
1383 | end | |
1384 | ||
1385 | fun layoutHeader (f: t): Layout.t = | |
1386 | let | |
1387 | val {args, name, raises, returns, start, ...} = dest f | |
1388 | open Layout | |
1389 | val (sep, rty) = | |
1390 | if !Control.showTypes | |
1391 | then (str ":", | |
1392 | indent (seq [record [("returns", | |
1393 | Option.layout | |
1394 | (Vector.layout Type.layout) | |
1395 | returns), | |
1396 | ("raises", | |
1397 | Option.layout | |
1398 | (Vector.layout Type.layout) | |
1399 | raises)], | |
1400 | str " ="], | |
1401 | 2)) | |
1402 | else (str " =", empty) | |
1403 | in | |
1404 | mayAlign [mayAlign [seq [str "fun ", | |
1405 | Func.layout name, | |
1406 | str " ", | |
1407 | layoutFormals args, | |
1408 | sep], | |
1409 | rty], | |
1410 | Transfer.layout (Transfer.Goto {dst = start, args = Vector.new0 ()})] | |
1411 | end | |
1412 | ||
1413 | fun layout' (f: t, layoutVar) = | |
1414 | let | |
1415 | val {blocks, ...} = dest f | |
1416 | open Layout | |
1417 | fun layoutBlock b = Block.layout' (b, layoutVar) | |
1418 | in | |
1419 | align [layoutHeader f, | |
1420 | indent (align (Vector.toListMap (blocks, layoutBlock)), 2)] | |
1421 | end | |
1422 | fun layout f = layout' (f, Var.layout) | |
1423 | ||
1424 | fun layouts (f: t, layoutVar, output: Layout.t -> unit): unit = | |
1425 | let | |
1426 | val {blocks, name, ...} = dest f | |
1427 | val _ = output (layoutHeader f) | |
1428 | val _ = | |
1429 | Vector.foreach | |
1430 | (blocks, fn b => | |
1431 | output (Layout.indent (Block.layout' (b, layoutVar), 2))) | |
1432 | val _ = | |
1433 | if not (!Control.keepDot) | |
1434 | then () | |
1435 | else | |
1436 | let | |
1437 | val {destroy, controlFlowGraph, dominatorTree, loopForest} = | |
1438 | layoutDot (f, layoutVar) | |
1439 | val name = Func.toString name | |
1440 | fun doit (s, g) = | |
1441 | let | |
1442 | open Control | |
1443 | in | |
1444 | saveToFile | |
1445 | ({suffix = concat [name, ".", s, ".dot"]}, | |
1446 | Dot, (), Layout (fn () => g)) | |
1447 | end | |
1448 | val _ = doit ("cfg", controlFlowGraph) | |
1449 | handle _ => Error.warning "SsaTree.layouts: couldn't layout cfg" | |
1450 | val _ = doit ("dom", dominatorTree ()) | |
1451 | handle _ => Error.warning "SsaTree.layouts: couldn't layout dom" | |
1452 | val _ = doit ("lf", loopForest ()) | |
1453 | handle _ => Error.warning "SsaTree.layouts: couldn't layout lf" | |
1454 | val () = destroy () | |
1455 | in | |
1456 | () | |
1457 | end | |
1458 | in | |
1459 | () | |
1460 | end | |
1461 | ||
1462 | fun alphaRename f = | |
1463 | let | |
1464 | local | |
1465 | fun make (new, plist) = | |
1466 | let | |
1467 | val {get, set, destroy, ...} = | |
1468 | Property.destGetSetOnce (plist, Property.initConst NONE) | |
1469 | fun bind x = | |
1470 | let | |
1471 | val x' = new x | |
1472 | val _ = set (x, SOME x') | |
1473 | in | |
1474 | x' | |
1475 | end | |
1476 | fun lookup x = | |
1477 | case get x of | |
1478 | NONE => x | |
1479 | | SOME y => y | |
1480 | in (bind, lookup, destroy) | |
1481 | end | |
1482 | in | |
1483 | val (bindVar, lookupVar, destroyVar) = | |
1484 | make (Var.new, Var.plist) | |
1485 | val (bindLabel, lookupLabel, destroyLabel) = | |
1486 | make (Label.new, Label.plist) | |
1487 | end | |
1488 | val {args, blocks, mayInline, name, raises, returns, start, ...} = | |
1489 | dest f | |
1490 | val args = Vector.map (args, fn (x, ty) => (bindVar x, ty)) | |
1491 | val bindLabel = ignore o bindLabel | |
1492 | val bindVar = ignore o bindVar | |
1493 | val _ = | |
1494 | Vector.foreach | |
1495 | (blocks, fn Block.T {label, args, statements, ...} => | |
1496 | (bindLabel label | |
1497 | ; Vector.foreach (args, fn (x, _) => bindVar x) | |
1498 | ; Vector.foreach (statements, | |
1499 | fn Statement.T {var, ...} => | |
1500 | Option.app (var, bindVar)))) | |
1501 | val blocks = | |
1502 | Vector.map | |
1503 | (blocks, fn Block.T {label, args, statements, transfer} => | |
1504 | Block.T {label = lookupLabel label, | |
1505 | args = Vector.map (args, fn (x, ty) => | |
1506 | (lookupVar x, ty)), | |
1507 | statements = Vector.map | |
1508 | (statements, | |
1509 | fn Statement.T {var, ty, exp} => | |
1510 | Statement.T | |
1511 | {var = Option.map (var, lookupVar), | |
1512 | ty = ty, | |
1513 | exp = Exp.replaceVar | |
1514 | (exp, lookupVar)}), | |
1515 | transfer = Transfer.replaceLabelVar | |
1516 | (transfer, lookupLabel, lookupVar)}) | |
1517 | val start = lookupLabel start | |
1518 | val _ = destroyVar () | |
1519 | val _ = destroyLabel () | |
1520 | in | |
1521 | new {args = args, | |
1522 | blocks = blocks, | |
1523 | mayInline = mayInline, | |
1524 | name = name, | |
1525 | raises = raises, | |
1526 | returns = returns, | |
1527 | start = start} | |
1528 | end | |
1529 | ||
1530 | fun profile (f: t, sourceInfo): t = | |
1531 | if !Control.profile = Control.ProfileNone | |
1532 | orelse !Control.profileIL <> Control.ProfileSource | |
1533 | then f | |
1534 | else | |
1535 | let | |
1536 | val _ = Control.diagnostic (fn () => layout f) | |
1537 | val {args, blocks, mayInline, name, raises, returns, start} = dest f | |
1538 | val extraBlocks = ref [] | |
1539 | val {get = labelBlock, set = setLabelBlock, rem} = | |
1540 | Property.getSetOnce | |
1541 | (Label.plist, Property.initRaise ("block", Label.layout)) | |
1542 | val _ = | |
1543 | Vector.foreach | |
1544 | (blocks, fn block as Block.T {label, ...} => | |
1545 | setLabelBlock (label, block)) | |
1546 | val blocks = | |
1547 | Vector.map | |
1548 | (blocks, fn Block.T {args, label, statements, transfer} => | |
1549 | let | |
1550 | fun make (exp: Exp.t): Statement.t = | |
1551 | Statement.T {exp = exp, | |
1552 | ty = Type.unit, | |
1553 | var = NONE} | |
1554 | val statements = | |
1555 | if Label.equals (label, start) | |
1556 | then (Vector.concat | |
1557 | [Vector.new1 | |
1558 | (make (Exp.Profile | |
1559 | (ProfileExp.Enter sourceInfo))), | |
1560 | statements]) | |
1561 | else statements | |
1562 | fun leave () = | |
1563 | make (Exp.Profile (ProfileExp.Leave sourceInfo)) | |
1564 | fun prefix (l: Label.t, | |
1565 | statements: Statement.t vector): Label.t = | |
1566 | let | |
1567 | val Block.T {args, ...} = labelBlock l | |
1568 | val c = Label.newNoname () | |
1569 | val xs = Vector.map (args, fn (x, _) => Var.new x) | |
1570 | val _ = | |
1571 | List.push | |
1572 | (extraBlocks, | |
1573 | Block.T | |
1574 | {args = Vector.map2 (xs, args, fn (x, (_, t)) => | |
1575 | (x, t)), | |
1576 | label = c, | |
1577 | statements = statements, | |
1578 | transfer = Goto {args = xs, | |
1579 | dst = l}}) | |
1580 | in | |
1581 | c | |
1582 | end | |
1583 | fun genHandler (cont: Label.t) | |
1584 | : Statement.t vector * Label.t * Handler.t = | |
1585 | case raises of | |
1586 | NONE => (statements, cont, Handler.Caller) | |
1587 | | SOME ts => | |
1588 | let | |
1589 | val xs = Vector.map (ts, fn _ => Var.newNoname ()) | |
1590 | val l = Label.newNoname () | |
1591 | val _ = | |
1592 | List.push | |
1593 | (extraBlocks, | |
1594 | Block.T | |
1595 | {args = Vector.zip (xs, ts), | |
1596 | label = l, | |
1597 | statements = Vector.new1 (leave ()), | |
1598 | transfer = Transfer.Raise xs}) | |
1599 | in | |
1600 | (statements, | |
1601 | prefix (cont, Vector.new0 ()), | |
1602 | Handler.Handle l) | |
1603 | end | |
1604 | fun addLeave () = | |
1605 | (Vector.concat [statements, | |
1606 | Vector.new1 (leave ())], | |
1607 | transfer) | |
1608 | val (statements, transfer) = | |
1609 | case transfer of | |
1610 | Call {args, func, return} => | |
1611 | let | |
1612 | datatype z = datatype Return.t | |
1613 | in | |
1614 | case return of | |
1615 | Dead => (statements, transfer) | |
1616 | | NonTail {cont, handler} => | |
1617 | (case handler of | |
1618 | Handler.Dead => (statements, transfer) | |
1619 | | Handler.Caller => | |
1620 | let | |
1621 | val (statements, cont, handler) = | |
1622 | genHandler cont | |
1623 | val return = | |
1624 | Return.NonTail | |
1625 | {cont = cont, | |
1626 | handler = handler} | |
1627 | in | |
1628 | (statements, | |
1629 | Call {args = args, | |
1630 | func = func, | |
1631 | return = return}) | |
1632 | end | |
1633 | | Handler.Handle _ => | |
1634 | (statements, transfer)) | |
1635 | | Tail => addLeave () | |
1636 | end | |
1637 | | Raise _ => addLeave () | |
1638 | | Return _ => addLeave () | |
1639 | | _ => (statements, transfer) | |
1640 | in | |
1641 | Block.T {args = args, | |
1642 | label = label, | |
1643 | statements = statements, | |
1644 | transfer = transfer} | |
1645 | end) | |
1646 | val _ = Vector.foreach (blocks, rem o Block.label) | |
1647 | val blocks = Vector.concat [Vector.fromList (!extraBlocks), blocks] | |
1648 | val f = | |
1649 | new {args = args, | |
1650 | blocks = blocks, | |
1651 | mayInline = mayInline, | |
1652 | name = name, | |
1653 | raises = raises, | |
1654 | returns = returns, | |
1655 | start = start} | |
1656 | val _ = Control.diagnostic (fn () => layout f) | |
1657 | in | |
1658 | f | |
1659 | end | |
1660 | ||
1661 | val profile = | |
1662 | Trace.trace2 ("SsaTree.Function.profile", layout, SourceInfo.layout, layout) | |
1663 | profile | |
1664 | end | |
1665 | ||
1666 | structure Program = | |
1667 | struct | |
1668 | datatype t = | |
1669 | T of { | |
1670 | datatypes: Datatype.t vector, | |
1671 | globals: Statement.t vector, | |
1672 | functions: Function.t list, | |
1673 | main: Func.t | |
1674 | } | |
1675 | end | |
1676 | ||
1677 | structure Program = | |
1678 | struct | |
1679 | open Program | |
1680 | ||
1681 | local | |
1682 | structure Graph = DirectedGraph | |
1683 | structure Node = Graph.Node | |
1684 | structure Edge = Graph.Edge | |
1685 | in | |
1686 | fun layoutCallGraph (T {functions, main, ...}, | |
1687 | title: string): Layout.t = | |
1688 | let | |
1689 | open Dot | |
1690 | val graph = Graph.new () | |
1691 | val {get = nodeOptions, set = setNodeOptions, ...} = | |
1692 | Property.getSetOnce | |
1693 | (Node.plist, Property.initRaise ("options", Node.layout)) | |
1694 | val {get = funcNode, destroy} = | |
1695 | Property.destGet | |
1696 | (Func.plist, Property.initFun | |
1697 | (fn f => | |
1698 | let | |
1699 | val n = Graph.newNode graph | |
1700 | val _ = | |
1701 | setNodeOptions | |
1702 | (n, | |
1703 | let open NodeOption | |
1704 | in [FontColor Black, label (Func.toString f)] | |
1705 | end) | |
1706 | in | |
1707 | n | |
1708 | end)) | |
1709 | val {get = edgeOptions, set = setEdgeOptions, ...} = | |
1710 | Property.getSetOnce (Edge.plist, Property.initConst []) | |
1711 | val _ = | |
1712 | List.foreach | |
1713 | (functions, fn f => | |
1714 | let | |
1715 | val {name, blocks, ...} = Function.dest f | |
1716 | val from = funcNode name | |
1717 | val {get, destroy} = | |
1718 | Property.destGet | |
1719 | (Node.plist, | |
1720 | Property.initFun (fn _ => {nontail = ref false, | |
1721 | tail = ref false})) | |
1722 | val _ = | |
1723 | Vector.foreach | |
1724 | (blocks, fn Block.T {transfer, ...} => | |
1725 | case transfer of | |
1726 | Call {func, return, ...} => | |
1727 | let | |
1728 | val to = funcNode func | |
1729 | val {tail, nontail} = get to | |
1730 | datatype z = datatype Return.t | |
1731 | val is = | |
1732 | case return of | |
1733 | Dead => false | |
1734 | | NonTail _ => true | |
1735 | | Tail => false | |
1736 | val r = if is then nontail else tail | |
1737 | in | |
1738 | if !r | |
1739 | then () | |
1740 | else (r := true | |
1741 | ; (setEdgeOptions | |
1742 | (Graph.addEdge | |
1743 | (graph, {from = from, to = to}), | |
1744 | if is | |
1745 | then [] | |
1746 | else [EdgeOption.Style Dotted]))) | |
1747 | end | |
1748 | | _ => ()) | |
1749 | val _ = destroy () | |
1750 | in | |
1751 | () | |
1752 | end) | |
1753 | val root = funcNode main | |
1754 | val l = | |
1755 | Graph.layoutDot | |
1756 | (graph, fn {nodeName} => | |
1757 | {title = title, | |
1758 | options = [GraphOption.Rank (Min, [{nodeName = nodeName root}])], | |
1759 | edgeOptions = edgeOptions, | |
1760 | nodeOptions = nodeOptions}) | |
1761 | val _ = destroy () | |
1762 | in | |
1763 | l | |
1764 | end | |
1765 | end | |
1766 | ||
1767 | fun layouts (p as T {datatypes, globals, functions, main}, | |
1768 | output': Layout.t -> unit) = | |
1769 | let | |
1770 | val layoutVar = Statement.prettifyGlobals globals | |
1771 | open Layout | |
1772 | (* Layout includes an output function, so we need to rebind output | |
1773 | * to the one above. | |
1774 | *) | |
1775 | val output = output' | |
1776 | in | |
1777 | output (str "\n\nDatatypes:") | |
1778 | ; Vector.foreach (datatypes, output o Datatype.layout) | |
1779 | ; output (str "\n\nGlobals:") | |
1780 | ; Vector.foreach (globals, output o (fn s => Statement.layout' (s, layoutVar))) | |
1781 | ; output (seq [str "\n\nMain: ", Func.layout main]) | |
1782 | ; output (str "\n\nFunctions:") | |
1783 | ; List.foreach (functions, fn f => | |
1784 | Function.layouts (f, layoutVar, output)) | |
1785 | ; if not (!Control.keepDot) | |
1786 | then () | |
1787 | else | |
1788 | let | |
1789 | open Control | |
1790 | in | |
1791 | saveToFile | |
1792 | ({suffix = "call-graph.dot"}, | |
1793 | Dot, (), Layout (fn () => | |
1794 | layoutCallGraph (p, !Control.inputFile))) | |
1795 | end | |
1796 | end | |
1797 | ||
1798 | fun layoutStats (T {datatypes, globals, functions, main, ...}) = | |
1799 | let | |
1800 | val (mainNumVars, mainNumBlocks) = | |
1801 | case List.peek (functions, fn f => | |
1802 | Func.equals (main, Function.name f)) of | |
1803 | NONE => Error.bug "SsaTree.Program.layoutStats: no main" | |
1804 | | SOME f => | |
1805 | let | |
1806 | val numVars = ref 0 | |
1807 | val _ = Function.foreachVar (f, fn _ => Int.inc numVars) | |
1808 | val {blocks, ...} = Function.dest f | |
1809 | val numBlocks = Vector.length blocks | |
1810 | in | |
1811 | (!numVars, numBlocks) | |
1812 | end | |
1813 | val numTypes = ref 0 | |
1814 | val {get = countType, destroy} = | |
1815 | Property.destGet | |
1816 | (Type.plist, | |
1817 | Property.initRec | |
1818 | (fn (t, countType) => | |
1819 | let | |
1820 | datatype z = datatype Type.dest | |
1821 | val _ = | |
1822 | case Type.dest t of | |
1823 | Array t => countType t | |
1824 | | CPointer => () | |
1825 | | Datatype _ => () | |
1826 | | IntInf => () | |
1827 | | Real _ => () | |
1828 | | Ref t => countType t | |
1829 | | Thread => () | |
1830 | | Tuple ts => Vector.foreach (ts, countType) | |
1831 | | Vector t => countType t | |
1832 | | Weak t => countType t | |
1833 | | Word _ => () | |
1834 | val _ = Int.inc numTypes | |
1835 | in | |
1836 | () | |
1837 | end)) | |
1838 | val _ = | |
1839 | Vector.foreach | |
1840 | (datatypes, fn Datatype.T {cons, ...} => | |
1841 | Vector.foreach (cons, fn {args, ...} => | |
1842 | Vector.foreach (args, countType))) | |
1843 | val numStatements = ref (Vector.length globals) | |
1844 | val numBlocks = ref 0 | |
1845 | val _ = | |
1846 | List.foreach | |
1847 | (functions, fn f => | |
1848 | let | |
1849 | val {args, blocks, ...} = Function.dest f | |
1850 | val _ = Vector.foreach (args, countType o #2) | |
1851 | val _ = | |
1852 | Vector.foreach | |
1853 | (blocks, fn Block.T {args, statements, ...} => | |
1854 | let | |
1855 | val _ = Int.inc numBlocks | |
1856 | val _ = Vector.foreach (args, countType o #2) | |
1857 | val _ = | |
1858 | Vector.foreach | |
1859 | (statements, fn Statement.T {ty, ...} => | |
1860 | let | |
1861 | val _ = Int.inc numStatements | |
1862 | val _ = countType ty | |
1863 | in () end) | |
1864 | in () end) | |
1865 | in () end) | |
1866 | val numFunctions = List.length functions | |
1867 | val _ = destroy () | |
1868 | open Layout | |
1869 | in | |
1870 | align | |
1871 | [seq [str "num vars in main = ", Int.layout mainNumVars], | |
1872 | seq [str "num blocks in main = ", Int.layout mainNumBlocks], | |
1873 | seq [str "num functions in program = ", Int.layout numFunctions], | |
1874 | seq [str "num blocks in program = ", Int.layout (!numBlocks)], | |
1875 | seq [str "num statements in program = ", Int.layout (!numStatements)], | |
1876 | seq [str "num types in program = ", Int.layout (!numTypes)], | |
1877 | Type.stats ()] | |
1878 | end | |
1879 | ||
1880 | (* clear all property lists reachable from program *) | |
1881 | fun clear (T {datatypes, globals, functions, ...}) = | |
1882 | ((* Can't do Type.clear because it clears out the info needed for | |
1883 | * Type.dest. | |
1884 | *) | |
1885 | Vector.foreach (datatypes, Datatype.clear) | |
1886 | ; Vector.foreach (globals, Statement.clear) | |
1887 | ; List.foreach (functions, Function.clear)) | |
1888 | ||
1889 | fun clearGlobals (T {globals, ...}) = | |
1890 | Vector.foreach (globals, Statement.clear) | |
1891 | ||
1892 | fun clearTop (p as T {datatypes, functions, ...}) = | |
1893 | (Vector.foreach (datatypes, Datatype.clear) | |
1894 | ; List.foreach (functions, Func.clear o Function.name) | |
1895 | ; clearGlobals p) | |
1896 | ||
1897 | fun foreachVar (T {globals, functions, ...}, f) = | |
1898 | (Vector.foreach (globals, fn Statement.T {var, ty, ...} => | |
1899 | f (valOf var, ty)) | |
1900 | ; List.foreach (functions, fn g => Function.foreachVar (g, f))) | |
1901 | ||
1902 | fun foreachPrim (T {globals, functions, ...}, f) = | |
1903 | let | |
1904 | fun loopStatement (Statement.T {exp, ...}) = | |
1905 | case exp of | |
1906 | PrimApp {prim, ...} => f prim | |
1907 | | _ => () | |
1908 | fun loopTransfer t = | |
1909 | case t of | |
1910 | Arith {prim, ...} => f prim | |
1911 | | Runtime {prim, ...} => f prim | |
1912 | | _ => () | |
1913 | val _ = Vector.foreach (globals, loopStatement) | |
1914 | val _ = | |
1915 | List.foreach | |
1916 | (functions, fn f => | |
1917 | Vector.foreach | |
1918 | (Function.blocks f, fn Block.T {statements, transfer, ...} => | |
1919 | (Vector.foreach (statements, loopStatement); | |
1920 | loopTransfer transfer))) | |
1921 | in | |
1922 | () | |
1923 | end | |
1924 | ||
1925 | fun hasPrim (p, f) = | |
1926 | Exn.withEscape | |
1927 | (fn escape => | |
1928 | (foreachPrim (p, fn prim => if f prim then escape true else ()) | |
1929 | ; false)) | |
1930 | ||
1931 | fun mainFunction (T {functions, main, ...}) = | |
1932 | case List.peek (functions, fn f => | |
1933 | Func.equals (main, Function.name f)) of | |
1934 | NONE => Error.bug "SsaTree.Program.mainFunction: no main function" | |
1935 | | SOME f => f | |
1936 | ||
1937 | fun dfs (p, v) = | |
1938 | let | |
1939 | val T {functions, main, ...} = p | |
1940 | val functions = Vector.fromList functions | |
1941 | val numFunctions = Vector.length functions | |
1942 | val {get = funcIndex, set = setFuncIndex, rem, ...} = | |
1943 | Property.getSetOnce (Func.plist, | |
1944 | Property.initRaise ("index", Func.layout)) | |
1945 | val _ = Vector.foreachi (functions, fn (i, f) => | |
1946 | setFuncIndex (#name (Function.dest f), i)) | |
1947 | val visited = Array.array (numFunctions, false) | |
1948 | fun visit (f: Func.t): unit = | |
1949 | let | |
1950 | val i = funcIndex f | |
1951 | in | |
1952 | if Array.sub (visited, i) | |
1953 | then () | |
1954 | else | |
1955 | let | |
1956 | val _ = Array.update (visited, i, true) | |
1957 | val f = Vector.sub (functions, i) | |
1958 | val v' = v f | |
1959 | val _ = Function.dfs | |
1960 | (f, fn Block.T {transfer, ...} => | |
1961 | (Transfer.foreachFunc (transfer, visit) | |
1962 | ; fn () => ())) | |
1963 | val _ = v' () | |
1964 | in | |
1965 | () | |
1966 | end | |
1967 | end | |
1968 | val _ = visit main | |
1969 | val _ = Vector.foreach (functions, rem o Function.name) | |
1970 | in | |
1971 | () | |
1972 | end | |
1973 | end | |
1974 | ||
1975 | end |