1 (* Copyright (C) 2009 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.
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
10 functor KnownCase (S: SSA_TRANSFORM_STRUCTS): SSA_TRANSFORM =
20 {addPost = fn th => List.push (post, th),
21 post = fn () => List.foreach(!post, fn th => th ())}
26 datatype t = T of {cons: Con.t vector}
29 fun make f (T r) = f r
34 fun layout (T {cons, ...})
35 = Layout.record [("cons", Vector.layout Con.layout cons)]
40 datatype t = T of {args: Type.t vector,
45 fun make f (T r) = f r
48 val index = make #index
51 fun layout (T {index, ...})
52 = Layout.record [("index", Int.layout index)]
57 type w = Var.t ref vector
62 val equalsW : w * w -> bool
63 = fn (x, y) => Vector.equals (x, y, fn (x, y) => Var.equals (!x, !y))
65 val layoutW = Vector.layout (Var.layout o !)
66 val layoutV = Option.layout layoutW
67 val layoutU = Option.layout layoutV
68 val layout : t -> Layout.t = Layout.tuple2 (Con.layout, layoutU)
70 val joinV : v * v -> v
77 val joinU : u * u -> u
78 = fn (SOME x, SOME y) => SOME (joinV (x, y))
82 = fn ((conx, x), (cony, y)) =>
83 if Con.equals (conx, cony)
84 then (conx, joinU (x, y))
85 else Error.bug "KnownCase.ConValue.join"
87 fun newKnown (con, args) : t = (con, SOME (SOME args))
88 fun newUnknown con : t = (con, SOME NONE)
89 fun new con : t = (con, NONE)
91 fun isTop ((_, x) : t) = isSome x
93 val con : t -> Con.t = fn (conx, _) => conx
96 structure TyconValue =
98 type t = ConValue.t vector
100 val layout : t -> Layout.t = Vector.layout ConValue.layout
102 val join : t * t -> t
103 = fn (x, y) => Vector.map2 (x, y, ConValue.join)
105 fun newKnown (cons, con, args)
108 if Con.equals (con, con')
109 then ConValue.newKnown (con, args)
110 else ConValue.new con')
112 fun newUnknown cons = Vector.map (cons, ConValue.newUnknown)
114 val cons : t -> Con.t vector
115 = fn x => Vector.map (x, ConValue.con)
120 datatype t = T of {active: bool ref,
121 tyconValues: TyconValue.t list ref,
125 fun make f (T r) = f r
126 fun make' f = (make f, ! o (make f))
128 val (_, active') = make' #active
131 fun layout (T {active, tyconValues, var, ...})
132 = Layout.record [("active", Bool.layout (!active)),
133 ("tyconValues", List.layout TyconValue.layout (!tyconValues)),
134 ("var", Var.layout var)]
136 fun new var = T {active = ref false,
137 tyconValues = ref [],
140 fun deactivate (T {active, ...}) = active := false
141 fun activate (T {active, ...}) = active := true
142 fun activate' (vi, addPost: (unit -> unit) -> unit)
143 = (addPost (fn () => deactivate vi);
147 fun tyconValue (T {tyconValues, ...})
148 = case !tyconValues of h::_ => SOME h | _ => NONE
149 fun popTyconValue (T {tyconValues, ...}) = ignore (List.pop tyconValues)
150 fun pushTyconValue (T {tyconValues, ...}, tcv) = List.push (tyconValues, tcv)
151 fun pushTyconValue' (vi, tcv, addPost)
153 val _ = pushTyconValue (vi, tcv)
154 val _ = addPost (fn () => popTyconValue vi)
158 fun joinActiveTyconValue (vi, tcv, addPost, addPost')
160 then let val tcv' = valOf (tyconValue vi)
163 pushTyconValue (vi, TyconValue.join (tcv, tcv'))
165 else (activate' (vi, addPost');
166 pushTyconValue' (vi, tcv, addPost))
169 structure ReplaceInfo =
171 datatype t = T of {replaces: Var.t ref list ref}
173 fun new var = T {replaces = ref [ref var]}
175 fun replace (T {replaces, ...})
176 = case !replaces of h::_ => h | _ => Error.bug "KnownCase.ReplaceInfo.replace"
177 fun popReplace (T {replaces, ...}) = ignore (List.pop replaces)
178 fun pushReplace (T {replaces, ...}, rep) = List.push (replaces, ref rep)
179 fun pushReplace' (vi, rep, addPost)
181 val _ = pushReplace (vi, rep)
182 val _ = addPost (fn () => popReplace vi)
186 fun flipReplace (vi, rep)
187 = let val r = replace vi
188 in !r before (r := rep)
190 fun flipReplace' (vi, rep, addPost)
192 val rep = flipReplace (vi, rep)
193 val _ = addPost (fn () => ignore (flipReplace (vi, rep)))
197 fun nextReplace' (vi, rep, addPost)
199 val rep = flipReplace' (vi, rep, addPost)
200 val _ = pushReplace' (vi, rep, addPost)
206 structure LabelInfo =
208 datatype t = T of {activations: (VarInfo.t * TyconValue.t) list ref,
211 pred: Label.t option option ref}
214 fun make f (T r) = f r
215 fun make' f = (make f, ! o (make f))
217 val block = make #block
218 val (_, depth') = make' #depth
221 fun layout (T {pred, ...})
223 [("pred", Option.layout (Option.layout Label.layout) (!pred))]
225 fun new block = T {activations = ref [],
230 fun popDepth (T {depth, ...}) = Int.dec depth
231 fun pushDepth (T {depth, ...}) = Int.inc depth
232 fun pushDepth' (li, addPost)
235 val _ = addPost (fn () => popDepth li)
240 fun addPred (T {pred, ...}, l)
242 of NONE => pred := SOME (SOME l)
244 | SOME (SOME l') => if Label.equals (l, l')
246 else pred := SOME NONE
247 fun onePred (T {pred, ...})
249 of SOME (SOME _) => true
252 fun addActivation (T {activations, ...}, activation)
253 = List.push (activations, activation)
254 fun activate (T {activations, ...}, addPost)
256 val {addPost = addPost', post = post'} = mkPost ()
259 (!activations, fn (vi, tcv) =>
260 VarInfo.joinActiveTyconValue (vi, tcv, addPost, addPost'));
263 val activate : t * ((unit -> unit) -> unit) -> unit
265 ("KnownCase.LabelInfo.activate",
266 fn (T {activations, block = Block.T {label, ...}, ...}, _) =>
269 seq [Label.layout label,
271 (List.layout (tuple2 (VarInfo.layout,
279 fun transform (Program.T {globals, datatypes, functions, main})
281 (* restore and shrink *)
282 val restore = restoreFunction {globals = globals}
283 val shrink = shrinkFunction {globals = globals}
285 (* tyconInfo and conInfo *)
286 val {get = tyconInfo: Tycon.t -> TyconInfo.t,
287 set = setTyconInfo, ...}
288 = Property.getSetOnce
289 (Tycon.plist, Property.initRaise ("knownCase.tyconInfo", Tycon.layout))
290 val {get = conInfo: Con.t -> ConInfo.t,
291 set = setConInfo, ...}
292 = Property.getSetOnce
293 (Con.plist, Property.initRaise ("knownCase.conInfo", Con.layout))
294 val _ = Vector.foreach
295 (datatypes, fn Datatype.T {tycon, cons} =>
296 (setTyconInfo (tycon, TyconInfo.T {cons = Vector.map (cons, #con)});
298 (cons, fn (i, {con, args}) =>
299 setConInfo (con, ConInfo.T {args = args,
303 val _ = Control.diagnostics
308 (datatypes, fn Datatype.T {tycon, cons} =>
309 let val tci = tyconInfo tycon
311 display (seq [Tycon.layout tycon, str " ",
312 TyconInfo.layout tci,
315 let val ci = conInfo con
317 seq [Con.layout con, str " ",
323 fun optimizeTycon _ = true
324 fun optimizeType ty = case Type.dest ty
325 of Type.Datatype tycon => optimizeTycon tycon
329 val {get = varInfo: Var.t -> VarInfo.t, ...}
330 = Property.getSetOnce
331 (Var.plist, Property.initFun (fn x => VarInfo.new x))
333 val {get = replaceInfo: Var.t -> ReplaceInfo.t, ...}
335 (Var.plist, Property.initFun (fn x => ReplaceInfo.new x))
338 fun bindVar' (x, ty, exp, addPost)
340 of Type.Datatype tycon
341 => if optimizeTycon tycon
343 val cons = TyconInfo.cons (tyconInfo tycon)
346 of SOME (ConApp {con, args})
347 => TyconValue.newKnown
350 (args, ReplaceInfo.replace o replaceInfo))
351 | _ => TyconValue.newUnknown cons
353 VarInfo.pushTyconValue'
354 (varInfo x, tyconValue, addPost)
359 fun bindVarArgs' (args, addPost)
362 bindVar' (x, ty, NONE, addPost))
363 fun bindVarArgs args = bindVarArgs' (args, ignore)
364 fun bindVarStatement' (Statement.T {var, ty, exp}, addPost)
367 bindVar' (x, ty, SOME exp, addPost))
368 fun bindVarStatements' (statements, addPost)
370 (statements, fn statement =>
371 bindVarStatement' (statement, addPost))
372 fun bindVarStatements statements = bindVarStatements' (statements, ignore)
374 val _ = bindVarStatements globals
376 val _ = Control.diagnostics
381 (globals, fn Statement.T {var, ...} =>
384 let val vi = varInfo x
386 display (seq [Var.layout x, str " ",
392 val {get = labelInfo: Label.t -> LabelInfo.t,
393 set = setLabelInfo, ...}
394 = Property.getSetOnce
395 (Label.plist, Property.initRaise ("knownCase.labelInfo", Label.layout))
401 val {args, blocks, mayInline, name, raises, returns, start} =
403 val _ = Vector.foreach
404 (blocks, fn block as Block.T {label, ...} =>
405 setLabelInfo (label, LabelInfo.new block))
406 val _ = Vector.foreach
407 (blocks, fn Block.T {label, transfer, ...} =>
408 Transfer.foreachLabel
410 let val li = labelInfo l
411 in LabelInfo.addPred (li, label)
414 val _ = Control.diagnostics
419 (blocks, fn Block.T {label, ...} =>
420 let val li = labelInfo label
422 display (seq [Label.layout label, str " ",
423 LabelInfo.layout li])
427 val newBlocks = ref []
428 fun addBlock block = List.push (newBlocks, block)
429 fun addNewBlock (block as Block.T {label, ...})
430 = (setLabelInfo (label, LabelInfo.new block);
433 val table: {hash: word,
434 transfer: Transfer.t,
435 label: Label.t} HashSet.t
436 = HashSet.new {hash = #hash}
438 fun newBlock transfer =
440 val label = Label.newNoname ()
441 val block = Block.T {label = label,
442 args = Vector.new0 (),
443 statements = Vector.new0 (),
445 val _ = addNewBlock block
449 (* newBlock' isn't used, because it shares blocks that causes
450 * violation of the requirements for profiling information --
451 * namely that each block correspond to a unique sequence of
452 * source infos at it' start.
454 * I left the code in case we want to enable it when compiling
457 fun newBlock' transfer
459 val hash = Transfer.hash transfer
461 = HashSet.lookupOrInsert
463 fn {transfer = transfer', ...} =>
464 Transfer.equals (transfer, transfer'),
465 fn () => {hash = hash,
466 label = newBlock transfer,
467 transfer = transfer})
471 val _ = newBlock' (* quell unused variable warning *)
472 fun bugBlock () = newBlock Bug
477 ("KnownCase.rewriteGoto",
480 [("dst", Label.layout dst),
481 ("args", Vector.layout Var.layout args)],
484 (Vector.layout Statement.layout,
488 ("KnownCase.rewriteCase",
489 fn {test, cases, default} =>
491 [("test", Var.layout test),
492 ("cases", Vector.layout
493 (Layout.tuple2 (Con.layout, Label.layout))
495 ("default", Option.layout Label.layout default)],
498 (Vector.layout Statement.layout,
500 val traceRewriteTransfer
502 ("KnownCase.rewriteTransfer",
506 (Vector.layout Statement.layout,
509 fun rewriteGoto' {dst, args} :
510 (Statement.t vector * Transfer.t) option
512 val li = labelInfo dst
513 val Block.T {args = argsDst,
514 statements = statementsDst,
515 transfer = transferDst, ...}
517 val depthDst = LabelInfo.depth' li
523 fn (Statement.T {exp = Profile _, ...}, i) => i
524 | (_, i) => i + 1) <= 0
526 val {addPost, post} = mkPost ()
527 val _ = LabelInfo.pushDepth' (li, addPost)
529 val vars = Vector.map2
532 (x, Var.newNoname (),
533 z, Var.newNoname (), ty))
538 (vars, fn (_, _, z, t, ty) =>
544 VarInfo.pushTyconValue'
546 valOf (VarInfo.tyconValue zvi),
550 ReplaceInfo.nextReplace'
551 (replaceInfo z, t, addPost);
552 Statement.T {var = SOME t,
558 (vars, fn (x, t, _, _, ty) =>
564 VarInfo.pushTyconValue'
566 valOf (VarInfo.tyconValue xvi),
570 Statement.T {var = SOME t,
575 (vars, fn (_, t, z, _, ty) =>
581 VarInfo.pushTyconValue'
583 valOf (VarInfo.tyconValue tvi),
587 Statement.T {var = SOME z,
590 val _ = bindVarStatements' (statementsDst, addPost)
592 (case rewriteTransfer transferDst
594 | SOME (newStatements, newTransfer)
595 => SOME (Vector.concat [moves1, moves2, moves3,
603 and rewriteGoto goto = traceRewriteGoto
607 and rewriteCase' {test, cases, default} :
608 (Statement.t vector * Transfer.t) option
611 val {addPost, post} = mkPost ()
613 val testvi = varInfo test
614 val tyconValue as conValues
615 = case VarInfo.tyconValue testvi
616 of SOME tyconValue => tyconValue
617 | _ => Error.bug "KnownCase.rewriteCase: tyconValue"
618 val cons = TyconValue.cons tyconValue
619 val numCons = Vector.length cons
622 | One of (Con.t * ConValue.v)
625 fun doOneSome (con, args)
629 (cases, fn (con', _) =>
630 Con.equals (con, con'))
632 => {dst = dst, args = Vector.map (args, !)}
634 => {dst = valOf default,
635 args = Vector.new0 ()}
637 case rewriteGoto goto
638 of NONE => SOME (Vector.new0 (), Transfer.Goto goto)
643 ("KnownCase.doOneSome",
644 Layout.ignore, Layout.ignore)
647 fun rewriteDefault conValues'
649 val _ = VarInfo.pushTyconValue'
650 (testvi, conValues', addPost)
652 rewriteGoto {dst = valOf default, args = Vector.new0 ()}
656 ("KnownCase.rewriteCase.rewriteDefault",
657 Layout.ignore, Layout.ignore)
663 = SOME (Vector.new0 (),
666 cases = Cases.Con (Vector.new1 (con, dst)),
667 default = if numCons = 1
669 else SOME (bugBlock ())})
672 (cases, fn (con', _) =>
673 Con.equals (con, con'))
674 of SOME (_, dst) => doit dst
679 (ConInfo.args (conInfo con),
682 val x = Var.newNoname ()
684 val _ = case Type.dest ty
685 of Type.Datatype tycon
686 => if optimizeTycon tycon
687 then VarInfo.pushTyconValue'
689 TyconValue.newUnknown
690 (TyconInfo.cons (tyconInfo tycon)),
697 val (xs, _) = Vector.unzip args
698 val conValues' = TyconValue.newKnown
701 (xs, ReplaceInfo.replace o replaceInfo))
702 val label = Label.newNoname ()
703 val (statements, transfer)
704 = case rewriteDefault conValues'
706 | NONE => (Vector.new0 (),
707 Goto {dst = valOf default,
708 args = Vector.new0 ()})
712 statements = statements,
714 val _ = addNewBlock block
721 ("KnownCase.rewriteCase.doOneNone",
722 Layout.ignore, Layout.ignore)
727 val usedCons = Array.new (numCons, false)
728 val cases = Vector.keepAllMap
729 (cases, fn (con, dst) =>
731 val conIndex = ConInfo.index (conInfo con)
732 val _ = Array.update (usedCons, conIndex, true)
734 if ConValue.isTop (Vector.sub (conValues, conIndex))
740 of NONE => (cases, NONE)
743 val conValues' = Vector.mapi
744 (cons, fn (i, con) =>
745 if Array.sub (usedCons, i)
746 then ConValue.new con
747 else Vector.sub (conValues, i))
749 fun route (statements, (cases, default))
750 = if Vector.isEmpty statements
751 then (cases, default)
755 val Block.T {args, ...}
756 = LabelInfo.block (labelInfo dst)
758 val label = Label.newNoname ()
759 val args = Vector.map
761 (Var.newNoname (), ty))
762 val xs = Vector.map (args, #1)
766 statements = statements,
767 transfer = Goto {dst = dst,
769 val _ = addNewBlock block
774 (Vector.map (cases, fn (con, dst) => (con, route' dst)),
775 Option.map (default, route'))
779 case rewriteDefault conValues'
782 cases = Cases.Con cases',
787 (statements, SOME test',
788 fn (Statement.T _, NONE) => NONE
789 | (Statement.T {var, exp, ...}, SOME test') =>
790 if Option.equals (var, SOME test', Var.equals)
792 of Var test' => SOME test'
797 val (cases', default')
798 = route (statements, (cases', default'))
800 (Vector.concat [cases, cases'], default')
802 else (cases, SOME dst)
803 | SOME (statements, transfer)
806 = if Vector.isEmpty statements
807 then newBlock transfer
809 val label = Label.newNoname ()
812 args = Vector.new0 (),
813 statements = statements,
815 val _ = addNewBlock block
822 | NONE => (cases, SOME dst)
824 val numCases = Vector.length cases
825 fun doit (cases, default)
826 = SOME (Vector.new0 (),
828 cases = Cases.Con cases,
831 if numCases = numCons
832 then doit (cases, NONE)
836 | NONE => SOME (bugBlock ()))
840 ("KnownCase.rewriteCase.doMany",
841 Layout.ignore, Layout.ignore)
847 (conValues, ConValue.isTop)
851 else case Vector.foldi
853 fn (_, _, Many) => Many
854 | (_, conValue, One ccv)
856 of (_, NONE) => One ccv
857 | (_, SOME _) => Many)
858 | (_, conValue, None)
861 | (con, SOME cv) => One (con, cv)))
862 of None => SOME (Vector.new0 (), Bug)
863 | One (con, SOME args) => doOneSome (con, args)
864 | One (con, NONE) => doOneNone con
868 and rewriteCase casee = traceRewriteCase
872 and rewriteTransfer' (transfer: Transfer.t) :
873 (Statement.t vector * Transfer.t) option
875 of Goto {dst, args} => rewriteGoto {dst = dst, args = args}
876 | Case {test, cases = Cases.Con cases, default}
877 => rewriteCase {test = test, cases = cases, default = default}
879 and rewriteTransfer transfer = traceRewriteTransfer
883 fun activateGoto {dst, args}
885 val liDst = labelInfo dst
886 val Block.T {args = argsDst, ...}
887 = LabelInfo.block liDst
889 if LabelInfo.onePred liDst
891 (args, argsDst, fn (x, (y, ty)) =>
897 = valOf (VarInfo.tyconValue xvi)
899 LabelInfo.addActivation
900 (liDst, (yvi, conValues'))
905 fun activateCase {test, cases, default}
907 val testvi = varInfo test
908 val tyconValue as conValues
909 = case VarInfo.tyconValue testvi
910 of NONE => Error.bug "KnownCase.activateCase: tyconValue"
911 | SOME tyconValue => tyconValue
912 val cons = TyconValue.cons tyconValue
913 val numCons = Vector.length cons
915 val usedCons = Array.new (numCons, false)
918 (cases, fn (con, dst) =>
920 val conIndex = ConInfo.index (conInfo con)
921 val _ = Array.update (usedCons, conIndex, true)
922 val liDst = labelInfo dst
923 val Block.T {args = argsDst, ...}
924 = LabelInfo.block liDst
926 = TyconValue.newKnown
929 (argsDst, ReplaceInfo.replace o replaceInfo o #1))
931 if LabelInfo.onePred liDst
932 then LabelInfo.addActivation
933 (liDst, (testvi, conValues'))
939 val liDst = labelInfo dst
940 val conValues' = Vector.mapi
941 (cons, fn (i, con) =>
942 if Array.sub (usedCons, i)
943 then ConValue.new con
944 else Vector.sub (conValues, i))
946 if LabelInfo.onePred liDst
947 then LabelInfo.addActivation
948 (liDst, (testvi, conValues'))
952 fun activateTransfer transfer
955 => activateGoto {dst = dst, args = args}
956 | Case {test, cases = Cases.Con cases, default}
957 => activateCase {test = test, cases = cases, default = default}
960 fun rewriteBlock (Block.T {label, args, statements, transfer},
963 val li = labelInfo label
964 val _ = LabelInfo.pushDepth' (li, addPost)
965 val _ = bindVarArgs' (args, addPost)
966 val _ = LabelInfo.activate (li, addPost)
967 val _ = bindVarStatements' (statements, addPost)
968 val _ = activateTransfer transfer
969 val (statements, transfer)
970 = case rewriteTransfer transfer
971 of NONE => (statements, transfer)
972 | SOME (newStatements, newTransfer)
973 => (Vector.concat [statements,newStatements],
976 Block.T {label = label,
978 statements = statements,
983 ("KnownCase.rewriteBlock",
984 Layout.tuple2 (Block.layout, Layout.ignore),
990 fun loop (Tree.T (block, children))
992 val {addPost, post} = mkPost ()
993 val block = rewriteBlock (block, addPost)
996 Vector.foreach (children, loop) ;
1001 Vector.fromListRev (!newBlocks)
1003 val _ = bindVarArgs args
1004 val blocks = doitTree (Function.dominatorTree f)
1006 val f = Function.new {args = args,
1008 mayInline = mayInline,
1013 val _ = Control.diagnostics
1015 display (Function.layout f))
1016 val f = eliminateDeadBlocksFunction f
1017 val _ = Control.diagnostics
1019 display (Function.layout f))
1021 val _ = Control.diagnostics
1023 display (Function.layout f))
1025 val _ = Control.diagnostics
1027 display (Function.layout f))
1028 val _ = Function.clear f
1032 val program = Program.T {datatypes = datatypes,
1034 functions = functions,
1036 val _ = Program.clearTop program