1 (* Copyright (C) 2009 Matthew Fluet.
2 * Copyright (C) 1999-2006, 2008 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 (* This simplifier is based on the following article.
11 * Shrinking Lambda Expressions in Linear Time.
12 * Journal of Functional Programming. Vol 7, no 5, 1997.
15 functor Shrink (S: SHRINK_STRUCTS): SHRINK =
21 val tracePrimApplyInfo = Trace.info "Xml.Shrink.Prim.apply"
24 Trace.trace ("Xml.Shrink.shrinkExp", Exp.layout, Exp.layout)
26 val traceShrinkLambda =
27 Trace.trace ("Xml.Shrink.shrinkLambda", Lambda.layout, Lambda.layout)
29 fun inc (r: int ref, n) =
31 in Assert.assert ("Xml.Shrink.inc", fn () => n >= 0)
41 ConApp of {con: Con.t,
45 | Lambda of {isInlined: bool ref,
48 withtype monoVarInfo = {numOccurrences: int ref,
49 value: value option ref,
56 fn Mono {numOccurrences, value, varExp} =>
57 record [("numOccurrences", Int.layout (!numOccurrences)),
58 ("value", Option.layout layoutValue (!value)),
59 ("varExp", VarExp.layout varExp)]
60 | Poly x => seq [str "Poly ", VarExp.layout x]
62 fn ConApp {con, arg, ...} =>
66 | SOME i => paren (layout i)]
67 | Const c => Const.layout c
68 | Lambda {isInlined, ...} =>
69 seq [str "Lambda ", Bool.layout (!isInlined)]
70 | Tuple is => Vector.layout layout is
76 Mono {numOccurrences = r, ...} => inc (r, n)
80 Trace.trace2 ("Xml.Shrink.VarInfo.inc", layout, Int.layout, Unit.layout) inc
82 fun inc1 i = inc (i, 1)
84 val inc1 = Trace.trace ("Xml.Shrink.VarInfo.inc1", layout, Unit.layout) inc1
86 fun delete i = inc (i, ~1)
88 val delete = Trace.trace ("Xml.Shrink.VarInfo.delete", layout, Unit.layout) delete
90 fun deletes is = Vector.foreach (is, delete)
93 fn Mono {varExp, ...} => varExp
96 fun equals (vi1, vi2) =
97 VarExp.equals (varExp vi1, varExp vi2)
100 structure InternalVarInfo =
107 fn VarInfo i => VarInfo.layout i
108 | Self => Layout.str "self"
111 structure MonoVarInfo =
113 type t = VarInfo.monoVarInfo
118 datatype t = datatype VarInfo.value
122 ConApp {con, targs, arg} =>
123 PrimExp.ConApp {con = con,
125 arg = Option.map (arg, VarInfo.varExp)}
126 | Const c => PrimExp.Const c
127 | Lambda {lam, ...} => PrimExp.Lambda lam
128 | Tuple vs => PrimExp.Tuple (Vector.map (vs, VarInfo.varExp))
131 fun shrinkOnce (Program.T {datatypes, body, overflow}) =
133 (* Keep track of the number of constuctors in each datatype so that
134 * we can eliminate redundant defaults.
136 val {get = conNumCons: Con.t -> int , set = setConNumCons, ...} =
137 Property.getSetOnce (Con.plist, Property.initConst ~1)
140 (datatypes, fn {cons, ...} =>
142 val n = Vector.length cons
144 Vector.foreach (cons, fn {con, ...} => setConNumCons (con, n))
146 fun isExhaustive (cases: exp Cases.t): bool =
150 andalso (Vector.length v
151 = conNumCons (Pat.con (#1 (Vector.first v)))))
153 val {get = varInfo: Var.t -> InternalVarInfo.t, set = setVarInfo, ...} =
154 Property.getSet (Var.plist,
155 Property.initRaise ("shrink varInfo", Var.layout))
157 Trace.trace2 ("Xml.Shrink.setVarInfo",
158 Var.layout, InternalVarInfo.layout, Unit.layout)
161 Trace.trace ("Xml.Shrink.varInfo", Var.layout, InternalVarInfo.layout)
165 InternalVarInfo.VarInfo (VarInfo.Mono i) => i
166 | _ => Error.bug "Xml.Shrink.monoVarInfo"
167 fun varExpInfo (x as VarExp.T {var, ...}): VarInfo.t =
169 InternalVarInfo.Self => VarInfo.Poly x
170 | InternalVarInfo.VarInfo i => i
172 Trace.trace ("Xml.Shrink.varExpInfo", VarExp.layout, VarInfo.layout) varExpInfo
173 fun varExpInfos xs = Vector.map (xs, varExpInfo)
174 fun replaceInfo (x: Var.t,
175 {numOccurrences = r, ...}: MonoVarInfo.t,
176 i: VarInfo.t): unit =
178 ; setVarInfo (x, InternalVarInfo.VarInfo i))
180 Trace.trace ("Xml.Shrink.replaceInfo",
181 fn (x, _, i) => Layout.tuple [Var.layout x,
185 fun replace (x, i) = replaceInfo (x, monoVarInfo x, i)
186 val shrinkVarExp = VarInfo.varExp o varExpInfo
188 fun handleBoundVar (x, ts, _) =
191 then (InternalVarInfo.VarInfo
192 (VarInfo.Mono {numOccurrences = ref 0,
194 varExp = VarExp.mono x}))
195 else InternalVarInfo.Self)
196 fun handleVarExp x = VarInfo.inc1 (varExpInfo x)
198 fun countExp (e: Exp.t): unit =
199 Exp.foreach {exp = e,
200 handleBoundVar = handleBoundVar,
201 handleExp = fn _ => (),
202 handlePrimExp = fn _ => (),
203 handleVarExp = handleVarExp}
205 fun deleteVarExp (x: VarExp.t): unit =
206 VarInfo.delete (varExpInfo x)
207 fun deleteExp (e: Exp.t): unit = Exp.foreachVarExp (e, deleteVarExp)
209 Trace.trace ("Xml.Shrink.deleteExp", Exp.layout, Unit.layout) deleteExp
210 fun deleteLambda l = deleteExp (Lambda.body l)
211 fun primApp (prim: Type.t Prim.t, args: VarInfo.t vector)
212 : (Type.t, VarInfo.t) Prim.ApplyResult.t =
218 VarInfo.Poly _ => Prim.ApplyArg.Var vi
219 | VarInfo.Mono {value, ...} =>
221 SOME (Value.ConApp {con, arg, ...}) =>
223 then Prim.ApplyArg.Var vi
224 else Prim.ApplyArg.Con {con = con,
226 | SOME (Value.Const c) =>
227 Prim.ApplyArg.Const c
228 | _ => Prim.ApplyArg.Var vi))
236 seq [Prim.layout p, str " ",
237 List.layout (Prim.ApplyArg.layout
238 (VarExp.layout o VarInfo.varExp)) args]
240 Prim.ApplyResult.layout (VarExp.layout o VarInfo.varExp))
242 (prim, Vector.toList args', VarInfo.equals)
244 (*---------------------------------------------------*)
246 (*---------------------------------------------------*)
247 fun shrinkExp arg: Exp.t =
251 val {decs, result} = Exp.dest e
253 Exp.make {decs = shrinkDecs decs,
254 result = shrinkVarExp result}
256 and shrinkDecs (decs: Dec.t list): Dec.t list =
261 Exception _ => dec :: shrinkDecs decs
262 | PolyVal {var, tyvars, ty, exp} =>
263 Dec.PolyVal {var = var, tyvars = tyvars, ty = ty,
266 | Fun {tyvars, decs = decs'} =>
267 if Vector.isEmpty tyvars
272 (decs', fn {lambda, var, ...} =>
274 val {numOccurrences, value, ...} =
276 in if 0 = !numOccurrences
277 then (deleteLambda lambda; false)
280 {isInlined = ref false,
284 val decs = shrinkDecs decs
285 (* Need to walk over all the decs and remove
286 * their value before shrinking any of them
287 * because they are mutually recursive.
291 (decs', fn {var, lambda, ...} =>
293 val {numOccurrences, value, ...} =
297 SOME (Value.Lambda {isInlined, ...}) =>
300 if 0 = !numOccurrences
301 then (deleteLambda lambda
303 else (value := NONE; true)
304 | _ => Error.bug "Xml.Shrink.shrinkDecs: should be a lambda"
307 if Vector.isEmpty decs'
310 Dec.Fun {tyvars = tyvars,
313 (decs', fn {var, ty, lambda} =>
316 lambda = shrinkLambda lambda})}
320 Dec.Fun {tyvars = tyvars,
323 (decs', fn {var, ty, lambda} =>
326 lambda = shrinkLambda lambda})}
329 shrinkMonoVal (b, fn () => shrinkDecs decs)
330 and shrinkMonoVal ({var, ty, exp},
331 rest: unit -> Dec.t list) =
333 val info as {numOccurrences, value, ...} = monoVarInfo var
334 fun finish (exp, decs) =
335 MonoVal {var = var, ty = ty, exp = exp} :: decs
336 fun nonExpansive (delete: unit -> unit,
337 set: unit -> (unit -> PrimExp.t) option) =
338 if 0 = !numOccurrences
339 then (delete (); rest ())
343 in if 0 = !numOccurrences
344 then (delete (); decs)
347 | SOME mk => finish (mk (), decs))
349 fun expansive (e: PrimExp.t) = finish (e, rest ())
350 fun nonExpansiveValue (delete, v: Value.t) =
353 fn () => (value := SOME v
354 ; SOME (fn () => Value.toPrimExp v)))
355 fun expression (e: Exp.t): Dec.t list =
357 val {decs = decs', result} = Exp.dest (shrinkExp e)
358 val _ = replaceInfo (var, info, varExpInfo result)
366 val arg = varExpInfo arg
368 expansive (App {func = func,
369 arg = VarInfo.varExp arg})
370 in case varExpInfo func of
371 VarInfo.Poly x => normal x
372 | VarInfo.Mono {numOccurrences, value, varExp, ...} =>
373 case (!numOccurrences, !value) of
374 (1, SOME (Value.Lambda {isInlined, lam = l})) =>
375 if not (Lambda.mayInline l)
379 val {arg = form, body, ...} = Lambda.dest l
382 ; replace (form, arg)
384 ; numOccurrences := 0
389 | Case {test, cases, default} =>
391 fun match (cases, f): Dec.t list =
393 val _ = deleteVarExp test
394 fun step (i, (c, e), ()) =
397 (Vector.foreachR (cases, i + 1,
400 ; Option.app (default, deleteExp o #1)
401 ; Vector.Done (expression e))
402 else (deleteExp e; Vector.Continue ())
405 SOME (e, _) => expression e
406 | NONE => Error.bug "Xml.Shrink.shrinkMonoVal: Case, match"
407 in Vector.fold' (cases, 0, (), step, done)
411 (* Eliminate redundant default case. *)
413 if isExhaustive cases
414 then (Option.app (default, deleteExp o #1)
416 else Option.map (default, fn (e, r) =>
421 cases = Cases.map (cases, shrinkExp),
425 case varExpInfo test of
426 VarInfo.Poly test => normal test
427 | VarInfo.Mono {value, varExp, ...} =>
428 case (cases, !value) of
430 SOME (Value.ConApp {con = c, arg, ...})) =>
435 fn Pat.T {con = c', arg, ...} =>
439 NONE => match Option.isNone
442 (fn SOME (x, _) => (replace (x, v); true)
445 | (_, SOME (Value.Const c)) =>
447 (Cases.Word (_, l), Const.Word w) =>
448 match (l, fn w' => WordX.equals (w, w'))
449 | _ => Error.bug "Xml.Shrink.shrinkMonoVal: Case, strange case")
450 | (_, NONE) => normal varExp
451 | _ => Error.bug "Xml.Shrink.shrinkMonoVal: Case, default"
453 | ConApp {con, targs, arg} =>
454 if Con.equals (con, Con.overflow)
460 arg = Option.map (arg, shrinkVarExp)})
463 val arg = Option.map (arg, varExpInfo)
465 (fn () => Option.app (arg, VarInfo.delete),
466 Value.ConApp {con = con, targs = targs, arg = arg})
468 | Const c => nonExpansiveValue (fn () => (), Value.Const c)
469 | Handle {try, catch, handler} =>
470 expansive (Handle {try = shrinkExp try,
472 handler = shrinkExp handler})
474 let val isInlined = ref false
476 (fn () => if !isInlined then () else deleteLambda l,
477 fn () => (value := SOME (Value.Lambda
478 {isInlined = isInlined,
480 ; SOME (fn () => Lambda (shrinkLambda l))))
482 | PrimApp {prim, args, targs} =>
484 val args = varExpInfos args
485 fun doit {prim, targs, args} =
488 PrimApp {prim = prim, targs = targs,
489 args = Vector.map (args, VarInfo.varExp)}
491 if Prim.maySideEffect prim
492 then expansive (make ())
493 else nonExpansive (fn () => VarInfo.deletes args,
496 fun default () = doit {prim = prim, targs = targs, args = args}
497 datatype z = datatype Prim.ApplyResult.t
499 case primApp (prim, args) of
500 Apply (prim, args') =>
502 val args' = Vector.fromList args'
503 val {no = unused, ...} =
508 VarInfo.equals (arg, arg')))
509 val _ = VarInfo.deletes unused
511 doit {prim = prim, targs = targs, args = args'}
515 val _ = VarInfo.deletes args
519 Value.ConApp {con = Con.fromBool b,
520 targs = Vector.new0 (),
525 val _ = VarInfo.deletes args
536 if VarInfo.equals (arg, x)
538 else VarInfo.delete arg)
540 replaceInfo (var, info, x)
546 | Profile _ => expansive exp
547 | Raise {exn, extend} =>
548 expansive (Raise {exn = shrinkVarExp exn, extend = extend})
549 | Select {tuple, offset} =>
551 fun normal x = Select {tuple = x, offset = offset}
552 in case varExpInfo tuple of
553 VarInfo.Poly x => finish (normal x, rest ())
554 | VarInfo.Mono {numOccurrences, value, varExp, ...} =>
556 (fn () => inc (numOccurrences, ~1),
559 NONE => SOME (fn () => normal varExp)
560 | SOME (Value.Tuple vs) =>
561 (inc (numOccurrences, ~1)
562 ; replaceInfo (var, info, Vector.sub (vs, offset))
564 | _ => Error.bug "Xml.Shrink.shrinkMonoVal: Select")
567 let val xs = varExpInfos xs
568 in nonExpansiveValue (fn () => VarInfo.deletes xs,
571 | Var x => let val x = varExpInfo x
572 in replaceInfo (var, info, x)
577 and shrinkLambda l: Lambda.t =
581 val {arg, argType, body, mayInline} = Lambda.dest l
583 Lambda.make {arg = arg,
585 body = shrinkExp body,
586 mayInline = mayInline}
588 val _ = countExp body
593 InternalVarInfo.VarInfo i => VarInfo.inc1 i
594 | _ => Error.bug "Xml.Shrink.shrinkOnce: strange overflow var")
595 val body = shrinkExp body
596 (* Must lookup the overflow variable again because it may have been set
603 InternalVarInfo.VarInfo i => VarExp.var (VarInfo.varExp i)
604 | _ => Error.bug "Xml.Shrink.shrinkOnce: strange overflow var")
605 val _ = Exp.clear body
606 val _ = Vector.foreach (datatypes, fn {cons, ...} =>
607 Vector.foreach (cons, Con.clear o #con))
609 Program.T {datatypes = datatypes,
615 Trace.trace ("Xml.Shrink.shrinkOnce", Program.layout, Program.layout) shrinkOnce
617 val shrink = shrinkOnce o shrinkOnce
619 structure SccFuns = SccFuns (S)
621 val shrink = shrink o SccFuns.sccFuns
624 Trace.trace ("Xml.Shrink.shrink", Program.layout, Program.layout) shrink