Import Upstream version 20180207
[hcoop/debian/mlton.git] / mlton / ssa / simplify.fun
CommitLineData
7f918cf1
CE
1(* Copyright (C) 2009,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
10functor Simplify (S: SIMPLIFY_STRUCTS): SIMPLIFY =
11struct
12
13open S
14
15structure CommonArg = CommonArg (S)
16structure CommonBlock = CommonBlock (S)
17structure CommonSubexp = CommonSubexp (S)
18structure CombineConversions = CombineConversions (S)
19structure ConstantPropagation = ConstantPropagation (S)
20structure Contify = Contify (S)
21structure Flatten = Flatten (S)
22structure Inline = Inline (S)
23structure IntroduceLoops = IntroduceLoops (S)
24structure KnownCase = KnownCase (S)
25structure LocalFlatten = LocalFlatten (S)
26structure LocalRef = LocalRef (S)
27structure LoopInvariant = LoopInvariant (S)
28structure LoopUnroll = LoopUnroll (S)
29structure LoopUnswitch = LoopUnswitch (S)
30structure PolyEqual = PolyEqual (S)
31structure PolyHash = PolyHash (S)
32structure Profile = Profile (S)
33structure Redundant = Redundant (S)
34structure RedundantTests = RedundantTests (S)
35structure RemoveUnused = RemoveUnused (S)
36structure ShareZeroVec = ShareZeroVec (S)
37structure SimplifyTypes = SimplifyTypes (S)
38structure Useless = Useless (S)
39
40type pass = {name: string,
41 doit: Program.t -> Program.t,
42 execute: bool}
43
44val ssaPassesDefault =
45 {name = "removeUnused1", doit = RemoveUnused.transform, execute = true} ::
46 {name = "introduceLoops1", doit = IntroduceLoops.transform, execute = true} ::
47 {name = "loopInvariant1", doit = LoopInvariant.transform, execute = true} ::
48 {name = "inlineLeaf1", doit = fn p =>
49 Inline.inlineLeaf (p, !Control.inlineLeafA), execute = true} ::
50 {name = "inlineLeaf2", doit = fn p =>
51 Inline.inlineLeaf (p, !Control.inlineLeafB), execute = true} ::
52 {name = "contify1", doit = Contify.transform, execute = true} ::
53 {name = "localFlatten1", doit = LocalFlatten.transform, execute = true} ::
54 {name = "constantPropagation", doit = ConstantPropagation.transform, execute = true} ::
55 (* useless should run
56 * - after constant propagation because constant propagation makes
57 * slots of tuples that are constant useless
58 *)
59 {name = "useless", doit = Useless.transform, execute = true} ::
60 (* loopUnroll should run
61 * - after constants have been globalized
62 *)
63 {name = "loopUnroll1", doit = LoopUnroll.transform, execute = false} ::
64 {name = "removeUnused2", doit = RemoveUnused.transform, execute = true} ::
65 {name = "simplifyTypes", doit = SimplifyTypes.transform, execute = true} ::
66 (* polyEqual should run
67 * - after types are simplified so that many equals are turned into eqs
68 * - before inlining so that equality functions can be inlined
69 *)
70 {name = "polyEqual", doit = PolyEqual.transform, execute = true} ::
71 (* polyHash should run
72 * - after types are simplified
73 * - before inlining so that hash functions can be inlined
74 *)
75 {name = "polyHash", doit = PolyHash.transform, execute = true} ::
76 {name = "introduceLoops2", doit = IntroduceLoops.transform, execute = true} ::
77 {name = "loopInvariant2", doit = LoopInvariant.transform, execute = true} ::
78 (* loopUnswitch should run
79 * - after loop invariant code motion so invariant conditions are obvious
80 * - before a knownCase pass to cleanup after unswitching
81 *)
82 {name = "loopUnswitch1", doit = LoopUnswitch.transform, execute = false} ::
83 {name = "knownCase1", doit = KnownCase.transform, execute = false} ::
84 {name = "contify2", doit = Contify.transform, execute = true} ::
85 {name = "inlineNonRecursive", doit = fn p =>
86 Inline.inlineNonRecursive (p, !Control.inlineNonRec), execute = true} ::
87 {name = "localFlatten2", doit = LocalFlatten.transform, execute = true} ::
88 {name = "removeUnused3", doit = RemoveUnused.transform, execute = true} ::
89 {name = "contify3", doit = Contify.transform, execute = true} ::
90 {name = "introduceLoops3", doit = IntroduceLoops.transform, execute = true} ::
91 {name = "loopInvariant3", doit = LoopInvariant.transform, execute = true} ::
92 {name = "localRef", doit = LocalRef.transform, execute = true} ::
93 {name = "flatten", doit = Flatten.transform, execute = true} ::
94 {name = "localFlatten3", doit = LocalFlatten.transform, execute = true} ::
95 {name = "combineConversions", doit = CombineConversions.transform, execute = true} ::
96 {name = "commonArg", doit = CommonArg.transform, execute = true} ::
97 {name = "commonSubexp1", doit = CommonSubexp.transform, execute = true} ::
98 {name = "commonBlock", doit = CommonBlock.transform, execute = true} ::
99 (* shareZeroVec should run
100 * - after useless because sharing of zero-length array inhibits
101 * changing type of flow-disjoint vector data
102 * - after simplifyTypes because it may make previously distinct
103 * types equal and allow more sharing of zero-length arrays
104 * - after inlining because shareZeroVec (slightly) increases size
105 * - before redundantTests because shareZeroVec introduces
106 * comparisons with zero
107 *)
108 {name = "shareZeroVec", doit = ShareZeroVec.transform, execute = true} ::
109 {name = "redundantTests", doit = RedundantTests.transform, execute = true} ::
110 {name = "redundant", doit = Redundant.transform, execute = true} ::
111 {name = "loopUnswitch2", doit = LoopUnswitch.transform, execute = false} ::
112 {name = "knownCase2", doit = KnownCase.transform, execute = true} ::
113 {name = "loopUnroll2", doit = LoopUnroll.transform, execute = false} ::
114 {name = "commonSubexp2", doit = CommonSubexp.transform, execute = false} ::
115 {name = "removeUnused4", doit = RemoveUnused.transform, execute = true} ::
116 nil
117
118val ssaPassesMinimal =
119 (* polyEqual cannot be omitted. It implements MLton_equal. *)
120 {name = "polyEqual", doit = PolyEqual.transform, execute = true} ::
121 (* polyHash cannot be omitted. It implements MLton_hash. *)
122 {name = "polyHash", doit = PolyHash.transform, execute = true} ::
123 nil
124
125val ssaPasses : pass list ref = ref ssaPassesDefault
126
127local
128 type passGen = string -> pass option
129
130 fun mkSimplePassGen (name, doit): passGen =
131 let val count = Counter.new 1
132 in fn s => if s = name
133 then SOME {name = concat [name, "#",
134 Int.toString (Counter.next count)],
135 doit = doit,
136 execute = true}
137 else NONE
138 end
139
140 val inlinePassGen =
141 let
142 datatype t = Bool of bool | IntOpt of int option
143 val count = Counter.new 1
144 fun nums s =
145 Exn.withEscape
146 (fn escape =>
147 if s = ""
148 then SOME []
149 else let
150 val l = String.length s
151 in
152 if String.sub (s, 0) = #"("
153 andalso String.sub (s, l - 1)= #")"
154 then let
155 val s = String.substring2 (s, {start = 1, finish = l - 1})
156 fun doit s =
157 if s = "true"
158 then Bool true
159 else if s = "false"
160 then Bool false
161 else if s = "inf"
162 then IntOpt NONE
163 else if String.forall (s, Char.isDigit)
164 then IntOpt (Int.fromString s)
165 else escape NONE
166 in
167 case List.map (String.split (s, #","), doit) of
168 l as _::_ => SOME l
169 | _ => NONE
170 end
171 else NONE
172 end)
173 in
174 fn s =>
175 if String.hasPrefix (s, {prefix = "inlineNonRecursive"})
176 then let
177 fun mk (product, small) =
178 SOME {name = concat ["inlineNonRecursive(",
179 Int.toString product, ",",
180 Int.toString small, ")#",
181 Int.toString (Counter.next count)],
182 doit = (fn p =>
183 Inline.inlineNonRecursive
184 (p, {small = small, product = product})),
185 execute = true}
186 val s = String.dropPrefix (s, String.size "inlineNonRecursive")
187 in
188 case nums s of
189 SOME [IntOpt (SOME product), IntOpt (SOME small)] =>
190 mk (product, small)
191 | _ => NONE
192 end
193 else if String.hasPrefix (s, {prefix = "inlineLeaf"})
194 then let
195 fun mk (loops, repeat, size) =
196 SOME {name = concat ["inlineLeafRepeat(",
197 Bool.toString loops, ",",
198 Bool.toString repeat, ",",
199 Option.toString Int.toString size, ")#",
200 Int.toString (Counter.next count)],
201 doit = (fn p =>
202 Inline.inlineLeaf
203 (p, {loops = loops, repeat = repeat, size = size})),
204 execute = true}
205 val s = String.dropPrefix (s, String.size "inlineLeaf")
206 in
207 case nums s of
208 SOME [Bool loops, Bool repeat, IntOpt size] =>
209 mk (loops, repeat, size)
210 | _ => NONE
211 end
212 else NONE
213 end
214
215 val passGens =
216 inlinePassGen ::
217 (List.map([("combineConversions", CombineConversions.transform),
218 ("commonArg", CommonArg.transform),
219 ("commonBlock", CommonBlock.transform),
220 ("commonSubexp", CommonSubexp.transform),
221 ("constantPropagation", ConstantPropagation.transform),
222 ("contify", Contify.transform),
223 ("flatten", Flatten.transform),
224 ("introduceLoops", IntroduceLoops.transform),
225 ("knownCase", KnownCase.transform),
226 ("localFlatten", LocalFlatten.transform),
227 ("localRef", LocalRef.transform),
228 ("loopInvariant", LoopInvariant.transform),
229 ("loopUnroll", LoopUnroll.transform),
230 ("loopUnswitch", LoopUnswitch.transform),
231 ("polyEqual", PolyEqual.transform),
232 ("polyHash", PolyHash.transform),
233 ("redundant", Redundant.transform),
234 ("redundantTests", RedundantTests.transform),
235 ("removeUnused", RemoveUnused.transform),
236 ("shareZeroVec", ShareZeroVec.transform),
237 ("simplifyTypes", SimplifyTypes.transform),
238 ("useless", Useless.transform),
239 ("ssaAddProfile", Profile.addProfile),
240 ("ssaDropProfile", Profile.dropProfile),
241 ("ssaBreakCriticalEdges", fn p => S.breakCriticalEdges (p, {codeMotion = true})),
242 ("ssaEliminateDeadBlocks", S.eliminateDeadBlocks),
243 ("ssaOrderFunctions", S.orderFunctions),
244 ("ssaReverseFunctions", S.reverseFunctions),
245 ("ssaShrink", S.shrink)],
246 mkSimplePassGen))
247in
248 fun ssaPassesSetCustom s =
249 Exn.withEscape
250 (fn esc =>
251 (let val ss = String.split (s, #":")
252 in
253 ssaPasses :=
254 List.map(ss, fn s =>
255 case (List.peekMap (passGens, fn gen => gen s)) of
256 NONE => esc (Result.No s)
257 | SOME pass => pass)
258 ; Result.Yes ()
259 end))
260end
261
262val ssaPassesString = ref "default"
263val ssaPassesGet = fn () => !ssaPassesString
264val ssaPassesSet = fn s =>
265 let
266 val _ = ssaPassesString := s
267 in
268 case s of
269 "default" => (ssaPasses := ssaPassesDefault
270 ; Result.Yes ())
271 | "minimal" => (ssaPasses := ssaPassesMinimal
272 ; Result.Yes ())
273 | _ => ssaPassesSetCustom s
274 end
275val _ = List.push (Control.optimizationPasses,
276 {il = "ssa", get = ssaPassesGet, set = ssaPassesSet})
277
278fun pass ({name, doit, midfix}, p) =
279 let
280 val _ =
281 let open Control
282 in maybeSaveToFile
283 ({name = name,
284 suffix = midfix ^ "pre.ssa"},
285 Control.No, p, Control.Layouts Program.layouts)
286 end
287 val p =
288 Control.passTypeCheck
289 {display = Control.Layouts Program.layouts,
290 name = name,
291 stats = Program.layoutStats,
292 style = Control.No,
293 suffix = midfix ^ "post.ssa",
294 thunk = fn () => doit p,
295 typeCheck = typeCheck}
296 in
297 p
298 end
299fun maybePass ({name, doit, execute, midfix}, p) =
300 if List.foldr (!Control.executePasses, execute, fn ((re, new), old) =>
301 if Regexp.Compiled.matchesAll (re, name)
302 then new
303 else old)
304 then pass ({name = name, doit = doit, midfix = midfix}, p)
305 else (Control.messageStr (Control.Pass, name ^ " skipped"); p)
306
307fun simplify p =
308 let
309 fun simplify' n p =
310 let
311 val midfix = if !Control.loopSsaPasses = 1
312 then ""
313 else concat [Int.toString n, "."]
314 in
315 if n = !Control.loopSsaPasses
316 then p
317 else simplify'
318 (n + 1)
319 (List.fold
320 (!ssaPasses, p, fn ({name, doit, execute}, p) =>
321 maybePass ({name = name, doit = doit, execute = execute, midfix = midfix}, p)))
322 end
323 val p = simplify' 0 p
324 in
325 p
326 end
327
328val simplify = fn p => let
329 (* Always want to type check the initial and final SSA
330 * programs, even if type checking is turned off, just
331 * to catch bugs.
332 *)
333 val _ = typeCheck p
334 val p = simplify p
335 val p =
336 if !Control.profile <> Control.ProfileNone
337 andalso !Control.profileIL = Control.ProfileSSA
338 then pass ({name = "ssaAddProfile",
339 doit = Profile.addProfile,
340 midfix = ""}, p)
341 else p
342 val p = maybePass ({name = "ssaOrderFunctions",
343 doit = S.orderFunctions,
344 execute = true,
345 midfix = ""}, p)
346 val _ = typeCheck p
347 in
348 p
349 end
350end