Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 2009,2017 Matthew Fluet. |
2 | * Copyright (C) 1999-2006 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 | (* Restore SSA | |
11 | * | |
12 | * Based primarily on Section 19.1 of Appel's "Modern Compiler Implementation in ML", | |
13 | * (but see the caveats in the comments below). | |
14 | * The main deviation is the calculation of liveness of the violating variables, | |
15 | * which is used to predicate the insertion of phi arguments. This is due to | |
16 | * the algorithm's bias towards imperative languages, for which it makes the | |
17 | * assumption that all variables are defined in the start block and all variables | |
18 | * are "used" at exit. | |
19 | * This is "optimized" for restoration of functions with small numbers of violating | |
20 | * variables -- use bool vectors to represent sets of violating variables. | |
21 | * Also, we use a Promise.t to suspend part of the dominance frontier computation. | |
22 | * | |
23 | * Requirements: no violation in globals; this is checked. | |
24 | *) | |
25 | ||
26 | functor Restore2 (S: RESTORE2_STRUCTS): RESTORE2 = | |
27 | struct | |
28 | ||
29 | structure Control = | |
30 | struct | |
31 | open Control | |
32 | fun diagnostics _ = () | |
33 | end | |
34 | ||
35 | open S | |
36 | open Exp Transfer | |
37 | ||
38 | structure LabelInfo = | |
39 | struct | |
40 | datatype t = T of {args: (Var.t * Type.t) vector ref, | |
41 | preds: Label.t list ref, | |
42 | defs: bool vector ref, | |
43 | uses: bool vector ref, | |
44 | live: bool array ref, | |
45 | dtindex: int ref, | |
46 | df: Label.t vector Promise.t ref, | |
47 | phi: Var.t list ref, | |
48 | phiArgs: Var.t vector ref, | |
49 | queued: bool ref} | |
50 | ||
51 | fun layout (T {preds, defs, uses, live, dtindex, df, phiArgs, ...}) | |
52 | = let open Layout | |
53 | in record [("preds", List.layout Label.layout (!preds)), | |
54 | ("defs", Vector.layout Bool.layout (!defs)), | |
55 | ("uses", Vector.layout Bool.layout (!uses)), | |
56 | ("live", Array.layout Bool.layout (!live)), | |
57 | ("dtindex", Int.layout (!dtindex)), | |
58 | ("df", Promise.layout (Vector.layout Label.layout) (!df)), | |
59 | ("phiArgs", Vector.layout Var.layout (!phiArgs))] | |
60 | end | |
61 | ||
62 | local | |
63 | fun make f (T r) = f r | |
64 | fun make' f = (make f, ! o (make f)) | |
65 | in | |
66 | val (args, args') = make' #args | |
67 | val (preds, preds') = make' #preds | |
68 | val (defs, defs') = make' #defs | |
69 | val (uses, uses') = make' #uses | |
70 | val (live, live') = make' #live | |
71 | val (dtindex, dtindex') = make' #dtindex | |
72 | val (df, df') = make' #df | |
73 | val (phi, _) = make' #phi | |
74 | val (phiArgs, phiArgs') = make' #phiArgs | |
75 | val (queued, _) = make' #queued | |
76 | end | |
77 | ||
78 | fun new (): t = T {args = ref (Vector.new0 ()), | |
79 | preds = ref [], | |
80 | defs = ref (Vector.new0 ()), | |
81 | uses = ref (Vector.new0 ()), | |
82 | live = ref (Array.new0 ()), | |
83 | dtindex = ref ~1, | |
84 | df = ref (Promise.delay (fn () => Vector.new0 ())), | |
85 | phi = ref [], | |
86 | phiArgs = ref (Vector.new0 ()), | |
87 | queued = ref false} | |
88 | end | |
89 | ||
90 | structure Cardinality = | |
91 | struct | |
92 | structure L = ThreePointLattice(val bottom = "zero" | |
93 | val mid = "one" | |
94 | val top = "many") | |
95 | open L | |
96 | ||
97 | val isZero = isBottom | |
98 | val isOne = isMid | |
99 | val makeOne = makeMid | |
100 | val isMany = isTop | |
101 | val makeMany = makeTop | |
102 | val whenMany = whenTop | |
103 | ||
104 | val inc: t -> unit | |
105 | = fn c => if isZero c | |
106 | then makeOne c | |
107 | else if isOne c | |
108 | then makeMany c | |
109 | else () | |
110 | end | |
111 | ||
112 | structure VarInfo = | |
113 | struct | |
114 | datatype t = T of {defs: Cardinality.t, | |
115 | ty: Type.t ref, | |
116 | index: int ref, | |
117 | defSites: Label.t list ref, | |
118 | useSites: Label.t list ref, | |
119 | vars: Var.t list ref} | |
120 | ||
121 | fun layout (T {defs, index, defSites, useSites, vars, ...}) | |
122 | = let open Layout | |
123 | in record [("defs", Cardinality.layout defs), | |
124 | ("index", Int.layout (!index)), | |
125 | ("defSites", List.layout Label.layout (!defSites)), | |
126 | ("useSites", List.layout Label.layout (!useSites)), | |
127 | ("vars", List.layout Var.layout (!vars))] | |
128 | end | |
129 | ||
130 | local | |
131 | fun make f (T r) = f r | |
132 | fun make' f = (make f, ! o (make f)) | |
133 | in | |
134 | val defs = make #defs | |
135 | val (index,index') = make' #index | |
136 | val (_,defSites') = make' #defSites | |
137 | val (_,useSites') = make' #useSites | |
138 | val (ty,ty') = make' #ty | |
139 | end | |
140 | fun addDef (T {defs, ...}) = Cardinality.inc defs | |
141 | fun addDefSite (T {defSites, ...}, l) = List.push(defSites, l) | |
142 | fun addUseSite (T {useSites, ...}, l) = List.push(useSites, l) | |
143 | val violates = Cardinality.isMany o defs | |
144 | fun whenViolates (T {defs, ...}, th) = Cardinality.whenMany (defs, th) | |
145 | ||
146 | fun new (): t = T {defs = Cardinality.new (), | |
147 | index = ref ~1, | |
148 | defSites = ref [], | |
149 | useSites = ref [], | |
150 | ty = ref Type.unit, | |
151 | vars = ref []} | |
152 | ||
153 | fun pushVar (T {vars, ...}, var) = List.push (vars, var) | |
154 | fun popVar (T {vars, ...}) = ignore (List.pop vars) | |
155 | fun peekVar (T {vars, ...}) = case !vars | |
156 | of [] => NONE | |
157 | | h::_ => SOME h | |
158 | end | |
159 | ||
160 | fun restoreFunction {globals: Statement.t vector} | |
161 | = let | |
162 | exception NoViolations | |
163 | ||
164 | val {get = varInfo: Var.t -> VarInfo.t, ...} | |
165 | = Property.get | |
166 | (Var.plist, Property.initFun (fn _ => VarInfo.new ())) | |
167 | ||
168 | val {get = labelInfo: Label.t -> LabelInfo.t, ...} | |
169 | = Property.get | |
170 | (Label.plist, Property.initFun (fn _ => LabelInfo.new ())) | |
171 | ||
172 | fun mkQueue () | |
173 | = let | |
174 | val todo = ref [] | |
175 | in | |
176 | {enque = fn (l, li) => let | |
177 | val queued = LabelInfo.queued li | |
178 | in | |
179 | if !queued | |
180 | then () | |
181 | else (queued := true ; | |
182 | List.push (todo, (l,li))) | |
183 | end, | |
184 | deque = fn () => case !todo | |
185 | of [] => NONE | |
186 | | (l,li)::todo' | |
187 | => (todo := todo'; | |
188 | LabelInfo.queued li := false; | |
189 | SOME (l,li))} | |
190 | end | |
191 | ||
192 | fun mkPost () | |
193 | = let | |
194 | val post = ref [] | |
195 | in | |
196 | {addPost = fn th => List.push (post, th), | |
197 | post = fn () => List.foreach(!post, fn th => th ())} | |
198 | end | |
199 | ||
200 | (* check for violations in globals *) | |
201 | fun addDef (x, ty) | |
202 | = let | |
203 | val vi = varInfo x | |
204 | in | |
205 | VarInfo.ty vi := ty ; | |
206 | VarInfo.addDef vi ; | |
207 | VarInfo.whenViolates | |
208 | (vi, fn () => Error.bug "Restore2.restore: violation in globals") | |
209 | end | |
210 | val _ | |
211 | = Vector.foreach | |
212 | (globals, fn Statement.T {var, ty, ...} => | |
213 | Option.app (var, fn x => addDef (x, ty))) | |
214 | in | |
215 | fn (f: Function.t) => | |
216 | let | |
217 | val {args, blocks, name, returns, raises, start} = Function.dest f | |
218 | (* check for violations *) | |
219 | val violations = ref [] | |
220 | fun addDef (x, ty) | |
221 | = let | |
222 | val vi = varInfo x | |
223 | in | |
224 | if VarInfo.violates vi | |
225 | then () | |
226 | else (VarInfo.ty vi := ty ; | |
227 | VarInfo.addDef vi ; | |
228 | if VarInfo.violates vi | |
229 | then List.push (violations, x) | |
230 | else ()) | |
231 | end | |
232 | val _ = Function.foreachVar (f, addDef) | |
233 | ||
234 | (* escape early *) | |
235 | val _ = if List.isEmpty (!violations) | |
236 | then (Control.diagnostics | |
237 | (fn display => | |
238 | let | |
239 | open Layout | |
240 | in | |
241 | display (seq [Func.layout name, | |
242 | str " NoViolations"]) | |
243 | end); | |
244 | raise NoViolations) | |
245 | else () | |
246 | ||
247 | (* init violations *) | |
248 | val index = ref 0 | |
249 | val violations | |
250 | = Vector.fromListMap | |
251 | (!violations, fn x => | |
252 | let | |
253 | val vi = varInfo x | |
254 | val _ = VarInfo.index vi := (!index) | |
255 | val _ = Int.inc index | |
256 | in | |
257 | x | |
258 | end) | |
259 | val numViolations = !index | |
260 | ||
261 | (* Diagnostics *) | |
262 | val _ = Control.diagnostics | |
263 | (fn display => | |
264 | let | |
265 | open Layout | |
266 | in | |
267 | display (seq [Func.layout name, | |
268 | str " Violations: ", | |
269 | Vector.layout Var.layout violations]) | |
270 | end) | |
271 | ||
272 | (* init entryBlock *) | |
273 | val entry = Label.newNoname () | |
274 | val entryBlock = Block.T {label = entry, | |
275 | args = args, | |
276 | statements = Vector.new0 (), | |
277 | transfer = Goto {dst = start, | |
278 | args = Vector.new0 ()}} | |
279 | ||
280 | (* compute dominator tree *) | |
281 | val dt = Function.dominatorTree f | |
282 | val dt' = Tree.T (entryBlock, Vector.new1 dt) | |
283 | ||
284 | (* compute df (dominance frontier) *) | |
285 | (* based on section 19.1 of Appel's "Modern Compiler Implementation in ML" *) | |
286 | (* also computes defSites and useSites of violating variables *) | |
287 | (* also computes preds, defs, and uses *) | |
288 | val dtindex = ref 0 | |
289 | fun doitTree (Tree.T (Block.T {label, args, statements, transfer}, | |
290 | children)) | |
291 | = let | |
292 | val li = labelInfo label | |
293 | ||
294 | val _ = LabelInfo.args li := args | |
295 | ||
296 | val _ = Transfer.foreachLabel | |
297 | (transfer, fn l => | |
298 | List.push (LabelInfo.preds (labelInfo l), label)) | |
299 | ||
300 | val defs = Array.new (numViolations, false) | |
301 | val uses = Array.new (numViolations, false) | |
302 | fun addDef x | |
303 | = let | |
304 | val vi = varInfo x | |
305 | in | |
306 | if VarInfo.violates vi | |
307 | then let | |
308 | val index = VarInfo.index' vi | |
309 | in | |
310 | VarInfo.addDefSite (varInfo x, label); | |
311 | Array.update (defs, index, true); | |
312 | Array.update (uses, index, false) | |
313 | end | |
314 | else () | |
315 | end | |
316 | fun addUse x | |
317 | = let | |
318 | val vi = varInfo x | |
319 | in | |
320 | if VarInfo.violates vi | |
321 | then let | |
322 | val index = VarInfo.index' vi | |
323 | in | |
324 | VarInfo.addUseSite (varInfo x, label); | |
325 | Array.update (uses, index, true) | |
326 | end | |
327 | else () | |
328 | end | |
329 | val _ = Transfer.foreachVar (transfer, addUse) | |
330 | val _ = Vector.foreachr | |
331 | (statements, fn Statement.T {var, exp, ...} => | |
332 | (Option.app (var, addDef); | |
333 | Exp.foreachVar (exp, addUse))) | |
334 | val _ = Vector.foreach (args, addDef o #1) | |
335 | val _ = LabelInfo.defs li := Array.toVector defs | |
336 | val _ = LabelInfo.uses li := Array.toVector uses | |
337 | val _ = LabelInfo.live li := Array.new (numViolations, false) | |
338 | ||
339 | val _ = Int.inc dtindex | |
340 | val dtindexMin = !dtindex | |
341 | val _ = LabelInfo.dtindex li := dtindexMin | |
342 | val _ = Vector.foreach(children, doitTree) | |
343 | val dtindexMax = !dtindex | |
344 | fun dominates l | |
345 | = let val dtindex = LabelInfo.dtindex' (labelInfo l) | |
346 | in dtindexMin < dtindex andalso dtindex <= dtindexMax | |
347 | end | |
348 | ||
349 | fun promise () | |
350 | = let | |
351 | val df = ref [] | |
352 | fun addDF l | |
353 | = if List.contains(!df, l, Label.equals) | |
354 | then () | |
355 | else List.push(df,l) | |
356 | val _ = Transfer.foreachLabel | |
357 | (transfer, fn l => | |
358 | if Vector.exists | |
359 | (children, fn Tree.T (b, _) => | |
360 | Label.equals (Block.label b, l)) | |
361 | then () | |
362 | else addDF l) | |
363 | val _ = Vector.foreach | |
364 | (children, fn Tree.T (Block.T {label, ...}, _) => | |
365 | let | |
366 | val li = labelInfo label | |
367 | in | |
368 | Vector.foreach | |
369 | (Promise.force (LabelInfo.df' li), fn l => | |
370 | if dominates l | |
371 | then () | |
372 | else addDF l) | |
373 | end) | |
374 | in | |
375 | Vector.fromList (!df) | |
376 | end | |
377 | val _ = LabelInfo.df li := Promise.delay promise | |
378 | in | |
379 | () | |
380 | end | |
381 | val _ = doitTree dt' | |
382 | ||
383 | (* compute liveness *) | |
384 | val _ | |
385 | = Vector.foreach | |
386 | (violations, fn x => | |
387 | let | |
388 | val {enque, deque} = mkQueue () | |
389 | val enque = fn l => enque (l, labelInfo l) | |
390 | ||
391 | val vi = varInfo x | |
392 | val index = VarInfo.index' vi | |
393 | val useSites = VarInfo.useSites' vi | |
394 | val _ = List.foreach (useSites, enque) | |
395 | ||
396 | fun doit (_,li) | |
397 | = let | |
398 | val uses = LabelInfo.uses' li | |
399 | val defs = LabelInfo.defs' li | |
400 | val live = LabelInfo.live' li | |
401 | in | |
402 | if Array.sub (live, index) | |
403 | orelse | |
404 | (Vector.sub(defs, index) | |
405 | andalso | |
406 | not (Vector.sub (uses, index))) | |
407 | then () | |
408 | else (Array.update(live, index, true) ; | |
409 | List.foreach (LabelInfo.preds' li, enque)) | |
410 | end | |
411 | fun loop () | |
412 | = case deque () | |
413 | of NONE => () | |
414 | | SOME (l,li) => (doit (l, li); loop ()) | |
415 | in | |
416 | loop () | |
417 | end) | |
418 | ||
419 | (* insert phi-functions *) | |
420 | (* based on section 19.1 of Appel's "Modern Compiler Implementation in ML" | |
421 | * (beware: Alg. 19.6 (both in the book and as corrected by the | |
422 | * errata) has numerous typos; and this implementation computes sets of | |
423 | * variables that must have phi-functions at a node, which is close to | |
424 | * the algorithm in the book, but the reverse of the algorithm as | |
425 | * corrected by the errata, which computes sets of nodes that must have | |
426 | * a phi-functions for a variable.) | |
427 | *) | |
428 | val _ | |
429 | = Vector.foreach | |
430 | (violations, fn x => | |
431 | let | |
432 | val {enque, deque} = mkQueue () | |
433 | ||
434 | val vi = varInfo x | |
435 | val index = VarInfo.index' vi | |
436 | val defSites = VarInfo.defSites' vi | |
437 | val _ = List.foreach | |
438 | (defSites, fn l => | |
439 | enque (l, labelInfo l)) | |
440 | ||
441 | fun doit (_,li) | |
442 | = Vector.foreach | |
443 | (Promise.force (LabelInfo.df' li), fn l => | |
444 | let | |
445 | val li = labelInfo l | |
446 | val live = LabelInfo.live' li | |
447 | val phi = LabelInfo.phi li | |
448 | in | |
449 | if Array.sub(live, index) | |
450 | andalso | |
451 | not (List.contains(!phi, x, Var.equals)) | |
452 | then (List.push(phi, x); | |
453 | enque (l, li)) | |
454 | else () | |
455 | end) | |
456 | fun loop () | |
457 | = case deque () | |
458 | of NONE => () | |
459 | | SOME (l,li) => (doit (l, li); loop ()) | |
460 | in | |
461 | loop () | |
462 | end) | |
463 | ||
464 | (* finalize phi args *) | |
465 | fun visitBlock (Block.T {label, ...}) | |
466 | = let | |
467 | val li = labelInfo label | |
468 | val phi = LabelInfo.phi li | |
469 | val phiArgs = LabelInfo.phiArgs li | |
470 | in | |
471 | phiArgs := Vector.fromList (!phi) ; | |
472 | phi := [] | |
473 | end | |
474 | val _ = visitBlock entryBlock | |
475 | val _ = Vector.foreach (blocks, visitBlock) | |
476 | ||
477 | (* Diagnostics *) | |
478 | val _ = Control.diagnostics | |
479 | (fn display => | |
480 | let | |
481 | open Layout | |
482 | in | |
483 | Vector.foreach | |
484 | (violations, fn x => | |
485 | display (seq [Var.layout x, | |
486 | str " ", | |
487 | VarInfo.layout (varInfo x)])); | |
488 | Vector.foreach | |
489 | (blocks, fn Block.T {label, ...} => | |
490 | display (seq [Label.layout label, | |
491 | str " ", | |
492 | LabelInfo.layout (labelInfo label)])) | |
493 | end) | |
494 | ||
495 | (* rewrite *) | |
496 | val blocks = ref [] | |
497 | fun rewriteVar (x: Var.t) | |
498 | = case VarInfo.peekVar (varInfo x) | |
499 | of NONE => x | |
500 | | SOME x' => x' | |
501 | fun rewriteStatement addPost (Statement.T {var, ty, exp}) | |
502 | = let | |
503 | val exp = Exp.replaceVar (exp, rewriteVar) | |
504 | val var | |
505 | = case var | |
506 | of NONE => NONE | |
507 | | SOME x => let | |
508 | val vi = varInfo x | |
509 | in | |
510 | if VarInfo.violates vi | |
511 | then let | |
512 | val x' = Var.new x | |
513 | in | |
514 | addPost (fn _ => VarInfo.popVar vi) ; | |
515 | VarInfo.pushVar (vi, x'); | |
516 | SOME x' | |
517 | end | |
518 | else SOME x | |
519 | end | |
520 | in | |
521 | Statement.T {var = var, | |
522 | ty = ty, | |
523 | exp = exp} | |
524 | end | |
525 | local | |
526 | type t = {dst: Label.t, | |
527 | phiArgs: Var.t vector, | |
528 | route: Label.t, | |
529 | hash: Word.t} | |
530 | val routeTable : t HashSet.t = HashSet.new {hash = #hash} | |
531 | in | |
532 | fun route dst | |
533 | = let | |
534 | val li = labelInfo dst | |
535 | val phiArgs = LabelInfo.phiArgs' li | |
536 | in | |
537 | if Vector.isEmpty phiArgs | |
538 | then dst | |
539 | else let | |
540 | val phiArgs = Vector.map | |
541 | (phiArgs, valOf o VarInfo.peekVar o varInfo) | |
542 | val hash = Vector.fold | |
543 | (phiArgs, Label.hash dst, fn (x, h) => | |
544 | Word.xorb(Var.hash x, h)) | |
545 | val {route, ...} | |
546 | = HashSet.lookupOrInsert | |
547 | (routeTable, hash, | |
548 | fn {dst = dst', phiArgs = phiArgs', ... } => | |
549 | Label.equals (dst, dst') | |
550 | andalso | |
551 | Vector.equals (phiArgs, phiArgs', Var.equals), | |
552 | fn () => | |
553 | let | |
554 | val route = Label.new dst | |
555 | val args = Vector.map | |
556 | (LabelInfo.args' li, fn (x,ty) => | |
557 | (Var.new x, ty)) | |
558 | val args' = Vector.concat | |
559 | [Vector.map(args, #1), | |
560 | phiArgs] | |
561 | val block = Block.T | |
562 | {label = route, | |
563 | args = args, | |
564 | statements = Vector.new0 (), | |
565 | transfer = Goto {dst = dst, | |
566 | args = args'}} | |
567 | val _ = List.push (blocks, block) | |
568 | in | |
569 | {dst = dst, | |
570 | phiArgs = phiArgs, | |
571 | route = route, | |
572 | hash = hash} | |
573 | end) | |
574 | in | |
575 | route | |
576 | end | |
577 | end | |
578 | end | |
579 | fun rewriteTransfer (t: Transfer.t) | |
580 | = Transfer.replaceLabelVar (t, route, rewriteVar) | |
581 | fun visitBlock' (Block.T {label, args, statements, transfer}) | |
582 | = let | |
583 | val {addPost, post} = mkPost () | |
584 | val li = labelInfo label | |
585 | fun doit x = let | |
586 | val vi = varInfo x | |
587 | val ty = VarInfo.ty' vi | |
588 | in | |
589 | if VarInfo.violates vi | |
590 | then let | |
591 | val x' = Var.new x | |
592 | in | |
593 | addPost (fn _ => VarInfo.popVar vi) ; | |
594 | VarInfo.pushVar (vi, x') ; | |
595 | (x', ty) | |
596 | end | |
597 | else (x, ty) | |
598 | end | |
599 | val args = Vector.map | |
600 | (args, fn (x, _) => doit x) | |
601 | val phiArgs = Vector.map | |
602 | (LabelInfo.phiArgs' li, fn x => doit x) | |
603 | val args = Vector.concat [args, phiArgs] | |
604 | val statements | |
605 | = if Vector.exists(LabelInfo.defs' li, fn b => b) | |
606 | orelse | |
607 | Vector.exists(LabelInfo.uses' li, fn b => b) | |
608 | then Vector.map (statements, rewriteStatement addPost) | |
609 | else statements | |
610 | val transfer = rewriteTransfer transfer | |
611 | val block = Block.T {label = label, | |
612 | args = args, | |
613 | statements = statements, | |
614 | transfer = transfer} | |
615 | in | |
616 | (block, post) | |
617 | end | |
618 | fun visitBlock block | |
619 | = let val (block, post) = visitBlock' block | |
620 | in List.push (blocks, block) ; post | |
621 | end | |
622 | fun rewrite () | |
623 | = let | |
624 | local | |
625 | val (Block.T {label, args, statements, transfer}, post) | |
626 | = visitBlock' entryBlock | |
627 | val entryBlock = Block.T {label = label, | |
628 | args = Vector.new0 (), | |
629 | statements = statements, | |
630 | transfer = transfer} | |
631 | val _ = List.push (blocks, entryBlock) | |
632 | in | |
633 | val args = args | |
634 | val post = post | |
635 | end | |
636 | val _ = Tree.traverse (Function.dominatorTree f, visitBlock) | |
637 | val _ = post () | |
638 | in | |
639 | Function.new {args = args, | |
640 | blocks = Vector.fromList (!blocks), | |
641 | name = name, | |
642 | raises = raises, | |
643 | returns = returns, | |
644 | start = entry} | |
645 | end | |
646 | val f = rewrite () | |
647 | in | |
648 | f | |
649 | end | |
650 | handle NoViolations => f | |
651 | end | |
652 | ||
653 | val traceRestoreFunction | |
654 | = Trace.trace ("Restore2.restoreFunction", | |
655 | Func.layout o Function.name, | |
656 | Func.layout o Function.name) | |
657 | ||
658 | val restoreFunction | |
659 | = fn g => | |
660 | let | |
661 | val r = restoreFunction g | |
662 | in | |
663 | fn f => traceRestoreFunction r f | |
664 | end | |
665 | ||
666 | fun restore (Program.T {datatypes, globals, functions, main}) | |
667 | = let | |
668 | val r = restoreFunction globals | |
669 | in | |
670 | Program.T {datatypes = datatypes, | |
671 | globals = globals, | |
672 | functions = List.revMap (functions, r), | |
673 | main = main} | |
674 | end | |
675 | end |