annotate src/especialize.sml @ 519:23a88d81a1b5

Optimize CoreUntangle
author Adam Chlipala <adamc@hcoop.net>
date Thu, 27 Nov 2008 11:40:13 -0500
parents 5521bb0b4014
children 3f20c22098af
rev   line source
adamc@443 1 (* Copyright (c) 2008, Adam Chlipala
adamc@443 2 * All rights reserved.
adamc@443 3 *
adamc@443 4 * Redistribution and use in source and binary forms, with or without
adamc@443 5 * modification, are permitted provided that the following conditions are met:
adamc@443 6 *
adamc@443 7 * - Redistributions of source code must retain the above copyright notice,
adamc@443 8 * this list of conditions and the following disclaimer.
adamc@443 9 * - Redistributions in binary form must reproduce the above copyright notice,
adamc@443 10 * this list of conditions and the following disclaimer in the documentation
adamc@443 11 * and/or other materials provided with the distribution.
adamc@443 12 * - The names of contributors may not be used to endorse or promote products
adamc@443 13 * derived from this software without specific prior written permission.
adamc@443 14 *
adamc@443 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
adamc@443 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
adamc@443 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
adamc@443 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
adamc@443 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
adamc@443 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
adamc@443 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
adamc@443 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
adamc@443 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
adamc@443 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
adamc@443 25 * POSSIBILITY OF SUCH DAMAGE.
adamc@443 26 *)
adamc@443 27
adamc@443 28 structure ESpecialize :> ESPECIALIZE = struct
adamc@443 29
adamc@443 30 open Core
adamc@443 31
adamc@443 32 structure E = CoreEnv
adamc@443 33 structure U = CoreUtil
adamc@443 34
adamc@479 35 type skey = exp
adamc@453 36
adamc@453 37 structure K = struct
adamc@479 38 type ord_key = exp list
adamc@479 39 val compare = Order.joinL U.Exp.compare
adamc@443 40 end
adamc@443 41
adamc@453 42 structure KM = BinaryMapFn(K)
adamc@443 43 structure IM = IntBinaryMap
adamc@482 44 structure IS = IntBinarySet
adamc@443 45
adamc@488 46 val freeVars = U.Exp.foldB {kind = fn (_, xs) => xs,
adamc@488 47 con = fn (_, _, xs) => xs,
adamc@488 48 exp = fn (bound, e, xs) =>
adamc@488 49 case e of
adamc@488 50 ERel x =>
adamc@488 51 if x >= bound then
adamc@488 52 IS.add (xs, x - bound)
adamc@488 53 else
adamc@488 54 xs
adamc@488 55 | _ => xs,
adamc@488 56 bind = fn (bound, b) =>
adamc@488 57 case b of
adamc@488 58 U.Exp.RelE _ => bound + 1
adamc@488 59 | _ => bound}
adamc@488 60 0 IS.empty
adamc@479 61
adamc@488 62 fun positionOf (v : int, ls) =
adamc@488 63 let
adamc@488 64 fun pof (pos, ls) =
adamc@488 65 case ls of
adamc@488 66 [] => raise Fail "Defunc.positionOf"
adamc@488 67 | v' :: ls' =>
adamc@488 68 if v = v' then
adamc@488 69 pos
adamc@488 70 else
adamc@488 71 pof (pos + 1, ls')
adamc@488 72 in
adamc@488 73 pof (0, ls)
adamc@488 74 end
adamc@488 75
adamc@488 76 fun squish fvs =
adamc@488 77 U.Exp.mapB {kind = fn k => k,
adamc@488 78 con = fn _ => fn c => c,
adamc@488 79 exp = fn bound => fn e =>
adamc@479 80 case e of
adamc@488 81 ERel x =>
adamc@488 82 if x >= bound then
adamc@488 83 ERel (positionOf (x - bound, fvs) + bound)
adamc@488 84 else
adamc@488 85 e
adamc@488 86 | _ => e,
adamc@488 87 bind = fn (bound, b) =>
adamc@488 88 case b of
adamc@488 89 U.Exp.RelE _ => bound + 1
adamc@488 90 | _ => bound}
adamc@488 91 0
adamc@453 92
adamc@443 93 type func = {
adamc@443 94 name : string,
adamc@453 95 args : int KM.map,
adamc@443 96 body : exp,
adamc@443 97 typ : con,
adamc@443 98 tag : string
adamc@443 99 }
adamc@443 100
adamc@443 101 type state = {
adamc@443 102 maxName : int,
adamc@443 103 funcs : func IM.map,
adamc@443 104 decls : (string * int * con * exp * string) list
adamc@443 105 }
adamc@443 106
adamc@488 107 fun kind x = x
adamc@488 108 fun default (_, x, st) = (x, st)
adamc@443 109
adamc@453 110 fun specialize' file =
adamc@443 111 let
adamc@488 112 fun default' (_, fs) = fs
adamc@482 113
adamc@482 114 fun actionableExp (e, fs) =
adamc@482 115 case e of
adamc@482 116 ERecord xes =>
adamc@482 117 foldl (fn (((CName s, _), e, _), fs) =>
adamc@482 118 if s = "Action" orelse s = "Link" then
adamc@482 119 let
adamc@482 120 fun findHead (e, _) =
adamc@482 121 case e of
adamc@482 122 ENamed n => IS.add (fs, n)
adamc@482 123 | EApp (e, _) => findHead e
adamc@482 124 | _ => fs
adamc@482 125 in
adamc@482 126 findHead e
adamc@482 127 end
adamc@482 128 else
adamc@482 129 fs
adamc@482 130 | (_, fs) => fs)
adamc@482 131 fs xes
adamc@482 132 | _ => fs
adamc@482 133
adamc@482 134 val actionable =
adamc@488 135 U.File.fold {kind = default',
adamc@488 136 con = default',
adamc@482 137 exp = actionableExp,
adamc@488 138 decl = default'}
adamc@482 139 IS.empty file
adamc@482 140
adamc@488 141 fun bind (env, b) =
adamc@488 142 case b of
adamc@488 143 U.Decl.RelC (x, k) => E.pushCRel env x k
adamc@488 144 | U.Decl.NamedC (x, n, k, co) => E.pushCNamed env x n k co
adamc@488 145 | U.Decl.RelE (x, t) => E.pushERel env x t
adamc@488 146 | U.Decl.NamedE (x, n, t, eo, s) => E.pushENamed env x n t eo s
adamc@488 147
adamc@488 148 fun exp (env, e, st : state) =
adamc@482 149 let
adamc@488 150 fun getApp e =
adamc@482 151 case e of
adamc@488 152 ENamed f => SOME (f, [])
adamc@482 153 | EApp (e1, e2) =>
adamc@488 154 (case getApp (#1 e1) of
adamc@482 155 NONE => NONE
adamc@488 156 | SOME (f, xs) => SOME (f, xs @ [e2]))
adamc@482 157 | _ => NONE
adamc@482 158 in
adamc@482 159 case getApp e of
adamc@482 160 NONE => (e, st)
adamc@488 161 | SOME (f, xs) =>
adamc@485 162 case IM.find (#funcs st, f) of
adamc@485 163 NONE => (e, st)
adamc@485 164 | SOME {name, args, body, typ, tag} =>
adamc@488 165 let
adamc@488 166 val functionInside = U.Con.exists {kind = fn _ => false,
adamc@488 167 con = fn TFun _ => true
adamc@488 168 | CFfi ("Basis", "transaction") => true
adamc@488 169 | _ => false}
adamc@488 170 val loc = ErrorMsg.dummySpan
adamc@488 171
adamc@488 172 fun findSplit (xs, typ, fxs, fvs) =
adamc@488 173 case (#1 typ, xs) of
adamc@488 174 (TFun (dom, ran), e :: xs') =>
adamc@488 175 if functionInside dom then
adamc@488 176 findSplit (xs',
adamc@488 177 ran,
adamc@488 178 e :: fxs,
adamc@488 179 IS.union (fvs, freeVars e))
adamc@488 180 else
adamc@488 181 (rev fxs, xs, fvs)
adamc@488 182 | _ => (rev fxs, xs, fvs)
adamc@488 183
adamc@488 184 val (fxs, xs, fvs) = findSplit (xs, typ, [], IS.empty)
adamc@488 185
adamc@488 186 val fxs' = map (squish (IS.listItems fvs)) fxs
adamc@488 187
adamc@488 188 fun firstRel () =
adamc@488 189 case fxs' of
adamc@488 190 (ERel _, _) :: _ => true
adamc@488 191 | _ => false
adamc@488 192 in
adamc@488 193 if firstRel ()
adamc@488 194 orelse List.all (fn (ERel _, _) => true
adamc@488 195 | _ => false) fxs' then
adamc@488 196 (e, st)
adamc@488 197 else
adamc@488 198 case KM.find (args, fxs') of
adamc@488 199 SOME f' =>
adamc@485 200 let
adamc@488 201 val e = (ENamed f', loc)
adamc@488 202 val e = IS.foldr (fn (arg, e) => (EApp (e, (ERel arg, loc)), loc))
adamc@488 203 e fvs
adamc@488 204 val e = foldl (fn (arg, e) => (EApp (e, arg), loc))
adamc@488 205 e xs
adamc@488 206 in
adamc@488 207 (*Print.prefaces "Brand new (reuse)"
adamc@488 208 [("e'", CorePrint.p_exp env e)];*)
adamc@488 209 (#1 e, st)
adamc@488 210 end
adamc@488 211 | NONE =>
adamc@488 212 let
adamc@488 213 fun subBody (body, typ, fxs') =
adamc@488 214 case (#1 body, #1 typ, fxs') of
adamc@488 215 (_, _, []) => SOME (body, typ)
adamc@488 216 | (EAbs (_, _, _, body'), TFun (_, typ'), x :: fxs'') =>
adamc@488 217 let
adamc@488 218 val body'' = E.subExpInExp (0, x) body'
adamc@488 219 in
adamc@488 220 subBody (body'',
adamc@488 221 typ',
adamc@488 222 fxs'')
adamc@488 223 end
adamc@488 224 | _ => NONE
adamc@488 225 in
adamc@488 226 case subBody (body, typ, fxs') of
adamc@488 227 NONE => (e, st)
adamc@488 228 | SOME (body', typ') =>
adamc@488 229 let
adamc@488 230 val f' = #maxName st
adamc@488 231 val args = KM.insert (args, fxs', f')
adamc@488 232 val funcs = IM.insert (#funcs st, f, {name = name,
adamc@488 233 args = args,
adamc@488 234 body = body,
adamc@488 235 typ = typ,
adamc@488 236 tag = tag})
adamc@488 237 val st = {
adamc@488 238 maxName = f' + 1,
adamc@488 239 funcs = funcs,
adamc@488 240 decls = #decls st
adamc@488 241 }
adamc@487 242
adamc@488 243 (*val () = Print.prefaces "specExp"
adamc@488 244 [("f", CorePrint.p_exp env (ENamed f, loc)),
adamc@488 245 ("f'", CorePrint.p_exp env (ENamed f', loc)),
adamc@488 246 ("xs", Print.p_list (CorePrint.p_exp env) xs),
adamc@488 247 ("fxs'", Print.p_list
adamc@488 248 (CorePrint.p_exp E.empty) fxs'),
adamc@488 249 ("e", CorePrint.p_exp env (e, loc))]*)
adamc@488 250 val (body', typ') = IS.foldl (fn (n, (body', typ')) =>
adamc@488 251 let
adamc@488 252 val (x, xt) = E.lookupERel env n
adamc@488 253 in
adamc@488 254 ((EAbs (x, xt, typ', body'),
adamc@488 255 loc),
adamc@488 256 (TFun (xt, typ'), loc))
adamc@488 257 end)
adamc@488 258 (body', typ') fvs
adamc@488 259 val (body', st) = specExp env st body'
adamc@482 260
adamc@488 261 val e' = (ENamed f', loc)
adamc@488 262 val e' = IS.foldr (fn (arg, e) => (EApp (e, (ERel arg, loc)), loc))
adamc@488 263 e' fvs
adamc@488 264 val e' = foldl (fn (arg, e) => (EApp (e, arg), loc))
adamc@488 265 e' xs
adamc@488 266 (*val () = Print.prefaces "Brand new"
adamc@488 267 [("e'", CorePrint.p_exp env e'),
adamc@488 268 ("e", CorePrint.p_exp env (e, loc)),
adamc@488 269 ("body'", CorePrint.p_exp env body')]*)
adamc@488 270 in
adamc@488 271 (#1 e',
adamc@488 272 {maxName = #maxName st,
adamc@488 273 funcs = #funcs st,
adamc@488 274 decls = (name, f', typ', body', tag) :: #decls st})
adamc@488 275 end
adamc@485 276 end
adamc@488 277 end
adamc@485 278 end
adamc@482 279
adamc@488 280 and specExp env = U.Exp.foldMapB {kind = kind, con = default, exp = exp, bind = bind} env
adamc@482 281
adamc@488 282 val specDecl = U.Decl.foldMapB {kind = kind, con = default, exp = exp, decl = default, bind = bind}
adamc@482 283
adamc@488 284 fun doDecl (d, (env, st : state, changed)) =
adamc@488 285 let
adamc@488 286 val env = E.declBinds env d
adamc@482 287
adamc@453 288 val funcs = #funcs st
adamc@453 289 val funcs =
adamc@453 290 case #1 d of
adamc@453 291 DValRec vis =>
adamc@453 292 foldl (fn ((x, n, c, e, tag), funcs) =>
adamc@453 293 IM.insert (funcs, n, {name = x,
adamc@453 294 args = KM.empty,
adamc@453 295 body = e,
adamc@453 296 typ = c,
adamc@453 297 tag = tag}))
adamc@453 298 funcs vis
adamc@453 299 | _ => funcs
adamc@453 300
adamc@453 301 val st = {maxName = #maxName st,
adamc@453 302 funcs = funcs,
adamc@453 303 decls = []}
adamc@453 304
adamc@482 305 (*val () = Print.prefaces "decl" [("d", CorePrint.p_decl CoreEnv.empty d)]*)
adamc@488 306 val (d', st) = specDecl env st d
adamc@482 307 (*val () = print "/decl\n"*)
adamc@443 308
adamc@443 309 val funcs = #funcs st
adamc@443 310 val funcs =
adamc@443 311 case #1 d of
adamc@443 312 DVal (x, n, c, e as (EAbs _, _), tag) =>
adamc@443 313 IM.insert (funcs, n, {name = x,
adamc@453 314 args = KM.empty,
adamc@443 315 body = e,
adamc@443 316 typ = c,
adamc@443 317 tag = tag})
adamc@469 318 | DVal (_, n, _, (ENamed n', _), _) =>
adamc@469 319 (case IM.find (funcs, n') of
adamc@469 320 NONE => funcs
adamc@469 321 | SOME v => IM.insert (funcs, n, v))
adamc@443 322 | _ => funcs
adamc@443 323
adamc@453 324 val (changed, ds) =
adamc@443 325 case #decls st of
adamc@453 326 [] => (changed, [d'])
adamc@453 327 | vis =>
adamc@453 328 (true, case d' of
adamc@453 329 (DValRec vis', _) => [(DValRec (vis @ vis'), ErrorMsg.dummySpan)]
adamc@453 330 | _ => [(DValRec vis, ErrorMsg.dummySpan), d'])
adamc@443 331 in
adamc@488 332 (ds, (env,
adamc@488 333 {maxName = #maxName st,
adamc@453 334 funcs = funcs,
adamc@453 335 decls = []}, changed))
adamc@443 336 end
adamc@443 337
adamc@488 338 val (ds, (_, _, changed)) = ListUtil.foldlMapConcat doDecl
adamc@488 339 (E.empty,
adamc@488 340 {maxName = U.File.maxName file + 1,
adamc@488 341 funcs = IM.empty,
adamc@488 342 decls = []},
adamc@488 343 false)
adamc@488 344 file
adamc@443 345 in
adamc@453 346 (changed, ds)
adamc@443 347 end
adamc@443 348
adamc@453 349 fun specialize file =
adamc@453 350 let
adamc@487 351 (*val () = Print.prefaces "Intermediate" [("file", CorePrint.p_file CoreEnv.empty file)];*)
adamc@488 352 val file = ReduceLocal.reduce file
adamc@453 353 val (changed, file) = specialize' file
adamc@488 354 val file = ReduceLocal.reduce file
adamc@488 355 (*val file = CoreUntangle.untangle file
adamc@488 356 val file = Shake.shake file*)
adamc@453 357 in
adamc@488 358 (*print "Round over\n";*)
adamc@453 359 if changed then
adamc@488 360 specialize file
adamc@453 361 else
adamc@453 362 file
adamc@453 363 end
adamc@453 364
adamc@443 365 end