Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / mlton / ssa / local-flatten.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
3 * Copyright (C) 1997-2000 NEC Research Institute.
4 *
5 * MLton is released under a BSD-style license.
6 * See the file MLton-LICENSE for details.
7 *)
8
9functor LocalFlatten (S: SSA_TRANSFORM_STRUCTS): SSA_TRANSFORM =
10struct
11
12open S
13open Exp Transfer
14
15(* Flatten a jump arg as long as it is only flows to selects and there is
16 * some tuple constructed in this function that flows to it.
17 *)
18
19structure ArgInfo =
20 struct
21 datatype t = T of {fromTuple: bool ref,
22 fromForce: t list ref,
23 toSelect: bool ref,
24 toForce: t list ref}
25
26 fun isFlat (T {fromTuple, toSelect, ...}) =
27 !fromTuple andalso !toSelect
28
29 val isTupled = not o isFlat
30
31 fun layout (i: t): Layout.t =
32 Layout.str (if isFlat i then "flat" else "tupled")
33
34 fun new () = T {fromTuple = ref false,
35 fromForce = ref [],
36 toSelect = ref true,
37 toForce = ref []}
38
39 fun tuple (T {fromTuple = f, fromForce, ...}) =
40 if !f
41 then ()
42 else (f := true; List.foreach (!fromForce, tuple))
43
44 fun nonSelect (T {toSelect = t, toForce, ...}) =
45 if !t
46 then (t := false; List.foreach (!toForce, nonSelect))
47 else ()
48
49 val op <= =
50 fn (lhs as T {fromTuple = f, fromForce, ...},
51 rhs as T {toSelect = t, toForce, ...}) =>
52 let
53 val _ =
54 if !f
55 then tuple rhs
56 else List.push (fromForce, rhs)
57 val _ =
58 if !t
59 then List.push (toForce, lhs)
60 else nonSelect lhs
61 in
62 ()
63 end
64 end
65
66structure VarInfo =
67 struct
68 datatype t =
69 None
70 | Arg of ArgInfo.t
71 | Tuple
72 end
73
74fun transform (Program.T {globals, datatypes, functions, main}) =
75 let
76 val {get = varInfo: Var.t -> VarInfo.t,
77 set = setVarInfo, ...} =
78 Property.getSetOnce (Var.plist, Property.initConst VarInfo.None)
79 type argsInfo = (ArgInfo.t * Type.t) option vector
80 val {get = labelArgs: Label.t -> argsInfo,
81 set = setLabelArgs, ...} =
82 Property.getSetOnce (Label.plist,
83 Property.initRaise ("args", Label.layout))
84 val shrink = shrinkFunction {globals = globals}
85 val functions =
86 List.revMap
87 (functions, fn f =>
88 let
89 val {args, blocks, mayInline, name, raises, returns, start} =
90 Function.dest f
91 val _ =
92 Vector.foreach
93 (blocks, fn Block.T {label, args, ...} =>
94 setLabelArgs (label,
95 Vector.map
96 (args, fn (x, t) =>
97 if Type.isTuple t
98 then
99 let
100 val i = ArgInfo.new ()
101 val _ = setVarInfo (x, VarInfo.Arg i)
102 in
103 SOME (i, t)
104 end
105 else NONE)))
106
107 fun force (x: Var.t): unit =
108 case varInfo x of
109 VarInfo.Arg i => ArgInfo.nonSelect i
110 | _ => ()
111 fun forces (xs: Var.t vector): unit =
112 Vector.foreach (xs, force)
113 fun forceArgs (l: Label.t): unit =
114 Vector.foreach (labelArgs l,
115 fn NONE => ()
116 | SOME (i, _) => ArgInfo.nonSelect i)
117
118 fun visit (Block.T {statements, transfer, ...}): unit -> unit =
119 let
120 val _ =
121 Vector.foreach
122 (statements, fn Statement.T {var, exp, ...} =>
123 case exp of
124 ConApp {args, ...} => forces args
125 | PrimApp {args, ...} => forces args
126 | Tuple args => (setVarInfo (valOf var, VarInfo.Tuple)
127 ; forces args)
128 | Var x => force x
129 | _ => ())
130 val _ =
131 case transfer of
132 Arith {args, overflow, success, ...} =>
133 (forces args
134 ; forceArgs overflow
135 ; forceArgs success)
136 | Bug => ()
137 | Call {args, return, ...} =>
138 (forces args
139 ; Return.foreachLabel (return, forceArgs))
140 | Case {cases, default, ...} =>
141 (Cases.foreach (cases, forceArgs)
142 ; Option.app (default, forceArgs))
143 | Goto {dst, args} =>
144 Vector.foreach2
145 (args, labelArgs dst,
146 fn (_, NONE) => ()
147 | (x, SOME (i, _)) =>
148 (case varInfo x of
149 VarInfo.Arg i' => ArgInfo.<= (i', i)
150 | VarInfo.None => ()
151 | VarInfo.Tuple => ArgInfo.tuple i))
152 | Raise xs => forces xs
153 | Return xs => forces xs
154 | Runtime {args, return, ...} =>
155 (forces args
156 ; forceArgs return)
157 in
158 fn () => ()
159 end
160 val _ = Function.dfs (f, visit)
161 val _ =
162 Control.diagnostics
163 (fn display =>
164 let
165 fun doit x =
166 case varInfo x of
167 VarInfo.Arg i => display (let open Layout
168 in seq [Var.layout x,
169 str " ",
170 ArgInfo.layout i]
171 end)
172 | _ => ()
173 in
174 Vector.foreach
175 (blocks, fn Block.T {args, statements, ...} =>
176 (Vector.foreach(args, doit o #1);
177 Vector.foreach(statements, fn Statement.T {var, ...} =>
178 Option.app(var, doit))))
179 end)
180
181 fun makeTuple (formals: (Var.t * Type.t) vector,
182 reps: argsInfo)
183 : (Var.t * Type.t) vector * Statement.t list =
184 let
185 val (argss, stmts) =
186 Vector.map2AndFold
187 (formals, reps, [], fn ((x, ty), rep, stmts) =>
188 case rep of
189 NONE => (Vector.new1 (x, ty), stmts)
190 | SOME (i, _) =>
191 if ArgInfo.isTupled i
192 then (Vector.new1 (x, ty), stmts)
193 else
194 let
195 val vars = Vector.map
196 (Type.deTuple ty, fn ty =>
197 (Var.newNoname (), ty))
198 in
199 (vars,
200 Statement.T
201 {var = SOME x,
202 ty = ty,
203 exp = Tuple (Vector.map (vars, #1))}
204 :: stmts)
205 end)
206 in (Vector.concatV argss, stmts)
207 end
208 fun makeSelects (args: Var.t vector,
209 formals: argsInfo)
210 : Var.t vector * Statement.t list =
211 let
212 val (argss, stmts) =
213 Vector.map2AndFold
214 (args, formals, [], fn (x, formal, stmts) =>
215 case formal of
216 NONE => (Vector.new1 x, stmts)
217 | SOME (i, t) =>
218 if ArgInfo.isTupled i
219 then (Vector.new1 x, stmts)
220 else
221 let
222 val (vars, stmts) =
223 Vector.foldi
224 (Type.deTuple t, ([], stmts),
225 fn (i, ty, (vars, stmts)) =>
226 let val var = Var.newNoname ()
227 in (var :: vars,
228 Statement.T
229 {var = SOME var,
230 ty = ty,
231 exp = Select {tuple = x,
232 offset = i}}
233 :: stmts)
234 end)
235 in (Vector.fromListRev vars, stmts)
236 end)
237 in (Vector.concatV argss, stmts)
238 end
239 fun anyFlat (v: argsInfo): bool =
240 Vector.exists (v,
241 fn NONE => false
242 | SOME (i, _) => ArgInfo.isFlat i)
243 val blocks =
244 Vector.map
245 (blocks, fn Block.T {label, args, statements, transfer} =>
246 let
247 val (args, pre) =
248 let
249 val formals = labelArgs label
250 in
251 if anyFlat formals
252 then makeTuple (args, formals)
253 else (args, [])
254 end
255 val (post, transfer) =
256 case transfer of
257 Goto {dst, args} =>
258 let
259 val formals = labelArgs dst
260 in
261 if anyFlat formals
262 then
263 let
264 val (args, stmts) =
265 makeSelects (args, formals)
266 in
267 (stmts, Goto {dst = dst, args = args})
268 end
269 else ([], transfer)
270 end
271 | _ => ([], transfer)
272 val statements =
273 Vector.concatV
274 (Vector.new3 (Vector.fromList pre,
275 statements,
276 Vector.fromList post))
277 in
278 Block.T {label = label,
279 args = args,
280 statements = statements,
281 transfer = transfer}
282 end)
283 in
284 shrink (Function.new {args = args,
285 blocks = blocks,
286 mayInline = mayInline,
287 name = name,
288 raises = raises,
289 returns = returns,
290 start = start})
291 end)
292 val program = Program.T {datatypes = datatypes,
293 globals = globals,
294 functions = functions,
295 main = main}
296 val _ = Program.clearTop program
297 in
298 program
299 end
300end