Import Upstream version 20180207
[hcoop/debian/mlton.git] / mlton / ssa / analyze2.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 2011,2017 Matthew Fluet.
2 * Copyright (C) 1999-2007 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
10functor Analyze2 (S: ANALYZE2_STRUCTS): ANALYZE2 =
11struct
12
13open S
14datatype z = datatype Exp.t
15datatype z = datatype Statement.t
16datatype z = datatype Transfer.t
17
18fun 'a analyze
19 {base, coerce, const, filter, filterWord, fromType, inject, layout, object, primApp,
20 program = Program.T {functions, globals, main, ...},
21 select, update, useFromTypeOnBinds} =
22 let
23 fun coerces (msg, from, to) =
24 if Vector.length from = Vector.length to
25 then Vector.foreach2 (from, to, fn (from, to) =>
26 coerce {from = from, to = to})
27 else Error.bug (concat ["Analyze2.coerces (length mismatch: ", msg, ")"])
28 val {get = value: Var.t -> 'a, set = setValue, ...} =
29 Property.getSetOnce
30 (Var.plist,
31 Property.initRaise ("Analyze2.value", Var.layout))
32 val value = Trace.trace ("Analyze2.value", Var.layout, layout) value
33 fun values xs = Vector.map (xs, value)
34 val {get = funcInfo, set = setFuncInfo, ...} =
35 Property.getSetOnce
36 (Func.plist, Property.initRaise ("Analyze2.funcInfo", Func.layout))
37 val {get = labelInfo, set = setLabelInfo, ...} =
38 Property.getSetOnce
39 (Label.plist, Property.initRaise ("Analyze2.labelInfo", Label.layout))
40 val labelArgs = #args o labelInfo
41 val labelValues = #values o labelInfo
42 fun loopArgs args =
43 Vector.map (args, fn (x, t) =>
44 let val v = fromType t
45 in setValue (x, v)
46 ; v
47 end)
48 val _ =
49 List.foreach
50 (functions, fn f =>
51 let
52 val {args, name, raises, returns, ...} = Function.dest f
53 in
54 setFuncInfo (name, {args = loopArgs args,
55 raises = Option.map (raises, fn ts =>
56 Vector.map (ts, fromType)),
57 returns = Option.map (returns, fn ts =>
58 Vector.map (ts, fromType))})
59 end)
60 fun loopTransfer (t: Transfer.t,
61 shouldReturns: 'a vector option,
62 shouldRaises: 'a vector option): unit =
63 (case t of
64 Arith {prim, args, overflow, success, ty} =>
65 (coerces ("arith overflow", Vector.new0 (), labelValues overflow)
66 ; coerce {from = primApp {prim = prim,
67 args = values args,
68 resultType = ty,
69 resultVar = NONE},
70 to = Vector.sub (labelValues success, 0)})
71 | Bug => ()
72 | Call {func, args, return, ...} =>
73 let
74 val {args = formals, raises, returns} = funcInfo func
75 val _ = coerces ("call args/formals", values args, formals)
76 fun noHandler () =
77 case (raises, shouldRaises) of
78 (NONE, NONE) => ()
79 | (NONE, SOME _) => ()
80 | (SOME _, NONE) =>
81 Error.bug "Analyze2.loopTransfer (raise mismatch)"
82 | (SOME vs, SOME vs') => coerces ("call caller/raises", vs, vs')
83 datatype z = datatype Return.t
84 in
85 case return of
86 Dead =>
87 if isSome returns orelse isSome raises
88 then Error.bug "Analyze2.loopTransfer (return mismatch at Dead)"
89 else ()
90 | NonTail {cont, handler} =>
91 (Option.app (returns, fn vs =>
92 coerces ("call non-tail/returns", vs, labelValues cont))
93 ; (case handler of
94 Handler.Caller => noHandler ()
95 | Handler.Dead =>
96 if isSome raises
97 then Error.bug "Analyze2.loopTransfer (raise mismatch at NonTail/Dead)"
98 else ()
99 | Handler.Handle h =>
100 let
101 val _ =
102 case raises of
103 NONE => ()
104 | SOME vs =>
105 coerces ("call handle/raises", vs, labelValues h)
106 in
107 ()
108 end))
109 | Tail =>
110 let
111 val _ = noHandler ()
112 val _ =
113 case (returns, shouldReturns) of
114 (NONE, NONE) => ()
115 | (NONE, SOME _) => ()
116 | (SOME _, NONE) =>
117 Error.bug "Analyze2.loopTransfer (return mismatch at Tail)"
118 | (SOME vs, SOME vs') =>
119 coerces ("call tail/return", vs, vs')
120 in
121 ()
122 end
123
124 end
125 | Case {test, cases, default, ...} =>
126 let
127 val test = value test
128 fun ensureSize (w, s) =
129 if WordSize.equals (s, WordX.size w)
130 then ()
131 else Error.bug (concat ["Analyze.loopTransfer (case ",
132 WordX.toString w,
133 " must be size ",
134 WordSize.toString s,
135 ")"])
136 fun ensureNullary j =
137 if Vector.isEmpty (labelValues j)
138 then ()
139 else Error.bug (concat ["Analyze2.loopTransfer (case:",
140 Label.toString j,
141 " must be nullary)"])
142 fun doitWord (s, cs) =
143 (ignore (filterWord (test, s))
144 ; Vector.foreach (cs, fn (w, j) =>
145 (ensureSize (w, s)
146 ; ensureNullary j)))
147 fun doitCon cs =
148 Vector.foreach
149 (cs, fn (c, j) =>
150 let
151 val v = labelValues j
152 val variant =
153 case Vector.length v of
154 0 => NONE
155 | 1 => SOME (Vector.first v)
156 | _ => Error.bug "Analyze2.loopTransfer (case conApp with >1 arg)"
157 in
158 filter {con = c,
159 test = test,
160 variant = variant}
161 end)
162 datatype z = datatype Cases.t
163 val _ =
164 case cases of
165 Con cs => doitCon cs
166 | Word (s, cs) => doitWord (s, cs)
167 val _ = Option.app (default, ensureNullary)
168 in ()
169 end
170 | Goto {dst, args} => coerces ("goto", values args, labelValues dst)
171 | Raise xs =>
172 (case shouldRaises of
173 NONE => Error.bug "Analyze2.loopTransfer (raise mismatch at Raise)"
174 | SOME vs => coerces ("raise", values xs, vs))
175 | Return xs =>
176 (case shouldReturns of
177 NONE => Error.bug "Analyze2.loopTransfer (return mismatch at Return)"
178 | SOME vs => coerces ("return", values xs, vs))
179 | Runtime {prim, args, return} =>
180 let
181 val xts = labelArgs return
182 val (resultVar, resultType) =
183 if Vector.isEmpty xts
184 then (NONE, Type.unit)
185 else
186 let
187 val (x, t) = Vector.first xts
188 in
189 (SOME x, t)
190 end
191 val _ =
192 primApp {prim = prim,
193 args = values args,
194 resultType = resultType,
195 resultVar = resultVar}
196 in
197 ()
198 end)
199 handle exn => Error.reraiseSuffix (exn, concat [" in ", Layout.toString (Transfer.layout t)])
200 val loopTransfer =
201 Trace.trace3
202 ("Analyze2.loopTransfer",
203 Transfer.layout,
204 Option.layout (Vector.layout layout),
205 Option.layout (Vector.layout layout),
206 Layout.ignore)
207 loopTransfer
208 fun baseValue b = base (Base.map (b, value))
209 fun loopBind {exp, ty, var}: 'a =
210 case exp of
211 Const c => const c
212 | Inject {sum, variant} =>
213 inject {sum = sum,
214 variant = value variant}
215 | Object {args, con} =>
216 let
217 val args =
218 case Type.dest ty of
219 Type.Object {args = ts, ...} =>
220 Prod.make
221 (Vector.map2
222 (args, Prod.dest ts,
223 fn (x, {isMutable, ...}) =>
224 {elt = value x,
225 isMutable = isMutable}))
226 | _ => Error.bug "Analyze2.loopBind (strange object)"
227 in
228 object {args = args,
229 con = con,
230 resultType = ty}
231 end
232 | PrimApp {prim, args, ...} =>
233 primApp {prim = prim,
234 args = values args,
235 resultType = ty,
236 resultVar = var}
237 | Select {base, offset} =>
238 select {base = baseValue base,
239 offset = offset,
240 resultType = ty}
241 | Var x => value x
242 fun loopStatement (s: Statement.t): unit =
243 (case s of
244 Bind (b as {ty, var, ...}) =>
245 let
246 val v = loopBind b
247 in
248 Option.app
249 (var, fn var =>
250 if useFromTypeOnBinds
251 then let
252 val v' = fromType ty
253 val _ = coerce {from = v, to = v'}
254 val _ = setValue (var, v')
255 in
256 ()
257 end
258 else setValue (var, v))
259 end
260 | Profile _ => ()
261 | Update {base, offset, value = v} =>
262 update {base = baseValue base,
263 offset = offset,
264 value = value v})
265 handle exn => Error.reraiseSuffix (exn, concat [" in ", Layout.toString (Statement.layout s)])
266 val loopStatement =
267 Trace.trace ("Analyze2.loopStatement",
268 Statement.layout,
269 Unit.layout)
270 loopStatement
271 val _ = coerces ("main", Vector.new0 (), #args (funcInfo main))
272 val _ = Vector.foreach (globals, loopStatement)
273 handle exn => Error.reraiseSuffix (exn, concat [" in Globals"])
274 val _ =
275 List.foreach
276 (functions, fn f =>
277 let
278 val {blocks, name, start, ...} = Function.dest f
279 val _ =
280 Vector.foreach
281 (blocks, fn b as Block.T {label, args, ...} =>
282 setLabelInfo (label, {args = args,
283 block = b,
284 values = loopArgs args,
285 visited = ref false}))
286 val {returns, raises, ...} = funcInfo name
287 fun visit (l: Label.t) =
288 let
289 val {block, visited, ...} = labelInfo l
290 in
291 if !visited
292 then ()
293 else
294 let
295 val _ = visited := true
296 val Block.T {statements, transfer, ...} = block
297 val _ = (Vector.foreach (statements, loopStatement)
298 ; loopTransfer (transfer, returns, raises))
299 handle exn => Error.reraiseSuffix (exn, concat [" in ", Label.toString l])
300 in
301 Transfer.foreachLabel (transfer, visit)
302 end
303 end
304 val _ = visit start
305 in
306 ()
307 end
308 handle exn => Error.reraiseSuffix (exn, concat [" in ", Func.toString (Function.name f)]))
309 in
310 {func = funcInfo,
311 label = labelValues,
312 value = value}
313 end
314
315end