Commit | Line | Data |
---|---|---|
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 | ||
10 | functor Simplify (S: SIMPLIFY_STRUCTS): SIMPLIFY = | |
11 | struct | |
12 | ||
13 | open S | |
14 | ||
15 | structure CommonArg = CommonArg (S) | |
16 | structure CommonBlock = CommonBlock (S) | |
17 | structure CommonSubexp = CommonSubexp (S) | |
18 | structure CombineConversions = CombineConversions (S) | |
19 | structure ConstantPropagation = ConstantPropagation (S) | |
20 | structure Contify = Contify (S) | |
21 | structure Flatten = Flatten (S) | |
22 | structure Inline = Inline (S) | |
23 | structure IntroduceLoops = IntroduceLoops (S) | |
24 | structure KnownCase = KnownCase (S) | |
25 | structure LocalFlatten = LocalFlatten (S) | |
26 | structure LocalRef = LocalRef (S) | |
27 | structure LoopInvariant = LoopInvariant (S) | |
28 | structure LoopUnroll = LoopUnroll (S) | |
29 | structure LoopUnswitch = LoopUnswitch (S) | |
30 | structure PolyEqual = PolyEqual (S) | |
31 | structure PolyHash = PolyHash (S) | |
32 | structure Profile = Profile (S) | |
33 | structure Redundant = Redundant (S) | |
34 | structure RedundantTests = RedundantTests (S) | |
35 | structure RemoveUnused = RemoveUnused (S) | |
36 | structure ShareZeroVec = ShareZeroVec (S) | |
37 | structure SimplifyTypes = SimplifyTypes (S) | |
38 | structure Useless = Useless (S) | |
39 | ||
40 | type pass = {name: string, | |
41 | doit: Program.t -> Program.t, | |
42 | execute: bool} | |
43 | ||
44 | val 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 | ||
118 | val 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 | ||
125 | val ssaPasses : pass list ref = ref ssaPassesDefault | |
126 | ||
127 | local | |
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)) | |
247 | in | |
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)) | |
260 | end | |
261 | ||
262 | val ssaPassesString = ref "default" | |
263 | val ssaPassesGet = fn () => !ssaPassesString | |
264 | val 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 | |
275 | val _ = List.push (Control.optimizationPasses, | |
276 | {il = "ssa", get = ssaPassesGet, set = ssaPassesSet}) | |
277 | ||
278 | fun 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 | |
299 | fun 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 | ||
307 | fun 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 | ||
328 | val 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 | |
350 | end |