diff src/mono_reduce.sml @ 2084:0d48cfb59b29

More aggressive inlining of 'let' with record literals, plus some changes to Monoization of queries, to make inlining more common
author Adam Chlipala <adam@chlipala.net>
date Thu, 04 Dec 2014 02:47:24 -0500
parents 1b76ae703cbb
children 9e9c915f554c
line wrap: on
line diff
--- a/src/mono_reduce.sml	Wed Dec 03 21:21:37 2014 -0500
+++ b/src/mono_reduce.sml	Thu Dec 04 02:47:24 2014 -0500
@@ -39,6 +39,10 @@
 structure IM = IntBinaryMap
 structure IS = IntBinarySet
 
+structure SS = BinarySetFn(struct
+                            type ord_key = string
+                            val compare = String.compare
+                            end)
 
 fun simpleTypeImpure tsyms =
     U.Typ.exists (fn TFun _ => true
@@ -592,6 +596,75 @@
                                  case e' of
                                      (ECase _, _) => e
                                    | _ => doSub ())
+
+                        fun isRecord () =
+                            case #1 e' of
+                                ERecord _ => true
+                              | _ => false
+
+                        fun whichProj i (e : exp) =
+                            case #1 e of
+                                EPrim _ => SOME SS.empty
+                              | ERel i' => if i' = i then NONE else SOME SS.empty
+                              | ENamed _ => SOME SS.empty
+                              | ECon (_, _, NONE) => SOME SS.empty
+                              | ECon (_, _, SOME e') => whichProj i e'
+                              | ENone _ => SOME SS.empty
+                              | ESome (_, e') => whichProj i e'
+                              | EFfi _ => SOME SS.empty
+                              | EFfiApp (_, _, es) => whichProjs i (map #1 es)
+                              | EApp (e1, e2) => whichProjs i [e1, e2]
+                              | EAbs (_, _, _, e) => whichProj (i + 1) e
+                              | EUnop (_, e1) => whichProj i e1
+                              | EBinop (_, _, e1, e2) => whichProjs i [e1, e2]
+                              | ERecord xets => whichProjs i (map #2 xets)
+                              | EField ((ERel i', _), s) =>
+                                if i' = i then
+                                    SOME (SS.singleton s)
+                                else
+                                    SOME SS.empty
+                              | EField (e1, _) => whichProj i e1
+                              | ECase (e1, pes, _) =>
+                                whichProjs' i ((0, e1)
+                                               :: map (fn (p, e) => (patBinds p, e)) pes)
+                              | EStrcat (e1, e2) => whichProjs i [e1, e2]
+                              | EError (e1, _) => whichProj i e1
+                              | EReturnBlob {blob = NONE, mimeType = e2, ...} => whichProj i e2
+                              | EReturnBlob {blob = SOME e1, mimeType = e2, ...} => whichProjs i [e1, e2]
+                              | ERedirect (e1, _) => whichProj i e1
+                              | EWrite e1 => whichProj i e1
+                              | ESeq (e1, e2) => whichProjs i [e1, e2]
+                              | ELet (_, _, e1, e2) => whichProjs' i [(0, e1), (1, e2)]
+                              | EClosure (_, es) => whichProjs i es
+                              | EQuery {query = e1, body = e2, initial = e3, ...} =>
+                                whichProjs' i [(0, e1), (2, e2), (0, e3)]
+                              | EDml (e1, _) => whichProj i e1
+                              | ENextval e1 => whichProj i e1
+                              | ESetval (e1, e2) => whichProjs i [e1, e2]
+                              | EUnurlify (e1, _, _) => whichProj i e1
+                              | EJavaScript (_, e1) => whichProj i e1
+                              | ESignalReturn e1 => whichProj i e1
+                              | ESignalBind (e1, e2) => whichProjs i [e1, e2]
+                              | ESignalSource e1 => whichProj i e1
+                              | EServerCall (e1, _, _, _) => whichProj i e1
+                              | ERecv (e1, _) => whichProj i e1
+                              | ESleep e1 => whichProj i e1
+                              | ESpawn e1 => whichProj i e1
+
+                        and whichProjs i es =
+                            whichProjs' i (map (fn e => (0, e)) es)
+
+                        and whichProjs' i es =
+                            case es of
+                                [] => SOME SS.empty
+                              | (n, e) :: es' =>
+                                case (whichProj (i + n) e, whichProjs' i es') of
+                                    (SOME m1, SOME m2) =>
+                                    if SS.isEmpty (SS.intersection (m1, m2)) then
+                                        SOME (SS.union (m1, m2))
+                                    else
+                                        NONE
+                                  | _ => NONE
                     in
                         if impure env e' then
                             let
@@ -650,7 +723,10 @@
                                 else
                                     e
                             end
-                        else if countFree 0 0 b > 1 andalso not (!fullMode) andalso not (passive e') then
+                        else if countFree 0 0 b > 1
+                                andalso not (!fullMode)
+                                andalso not (passive e')
+                                andalso not (isRecord () andalso Option.isSome (whichProj 0 b)) then
                             e
                         else
                             trySub ()