@@ -134,23 +134,33 @@ data ExternSpine
134134 | ExternPrimOp BackendOperator1
135135
136136data EvalRef
137− = EvalExtern (Qualified Ident) (Maybe BackendAccessor)
137+ = EvalExtern (Qualified Ident)
138138 | EvalLocal (Maybe Ident) Level
139139
140140derive instance Eq EvalRef
141141derive instance Ord EvalRef
142142
143+data InlineAccessor
144+ = InlineProp String
145+ | InlineSpineProp String
146+ | InlineRef
147+
148+derive instance Eq InlineAccessor
149+derive instance Ord InlineAccessor
150+
143151data InlineDirective
144152 = InlineDefault
145153 | InlineNever
146154 | InlineAlways
147155 | InlineArity Int
148156
157+type InlineDirectiveMap = Map EvalRef (Map InlineAccessor InlineDirective)
158+
149159newtype Env = Env
150160 { currentModule :: ModuleName
151161 , evalExtern :: Env -> Qualified Ident -> Array ExternSpine -> Maybe BackendSemantics
152162 , locals :: Array (LocalBinding BackendSemantics)
153− , directives :: Map EvalRef InlineDirective
163+ , directives :: InlineDirectiveMap
154164 , branchTry :: Maybe (SemTry BackendSemantics)
155165 }
156166
@@ -162,17 +172,23 @@ lookupLocal (Env { locals }) (Level lvl) = Array.index locals lvl
162172bindLocal :: Env -> LocalBinding BackendSemantics -> Env
163173bindLocal (Env env) sem = Env env { locals = Array.snoc env.locals sem }
164174
165−addDirective :: Env -> EvalRef -> InlineDirective -> Env
166−addDirective (Env env) ref dir = Env env { directives = Map.insert ref dir env.directives }
175+insertDirective :: EvalRef -> InlineAccessor -> InlineDirective -> InlineDirectiveMap -> InlineDirectiveMap
176+insertDirective ref acc dir = Map.alter
177+ case _ of
178+ Just dirs ->
179+ Just $ Map.insert acc dir dirs
180+ Nothing ->
181+ Just $ Map.singleton acc dir
182+ ref
167183
168−addStop :: Env -> EvalRef -> Env
169−addStop (Env env) ref = Env env
184+addStop :: Env -> EvalRef -> InlineAccessor -> Env
185+addStop (Env env) ref acc = Env env
170186 { directives = Map.alter
171187 case _ of
172− Just InlineAlways ->
173− Just InlineAlways
188+ Just dirs ->
189+ Just $ Map.insert acc InlineNever dirs
174190 _ ->
175− Just InlineNever
191+ Just $ Map.singleton acc InlineNever
176192 ref
177193 env.directives
178194 }
@@ -822,69 +838,153 @@ primOpOrdNot = case _ of
822838 OpGte -> OpLt
823839
824840evalExtern :: Env -> Qualified Ident -> Array ExternSpine -> BackendSemantics
825−evalExtern env@(Env e) qual spine = case spine of
826− [] | Just InlineNever <- Map.lookup (EvalExtern qual Nothing) e.directives ->
827− NeutStop qual
828− [ ExternAccessor acc ] | Just InlineNever <- Map.lookup (EvalExtern qual (Just acc)) e.directives ->
829− neutralSpine (NeutStop qual) spine
830− _ ->
831− case e.evalExtern env qual spine of
832− Just sem ->
833− sem
834− Nothing ->
835− SemExtern qual spine (defer \_ -> neutralSpine (NeutVar qual) spine)
841+evalExtern env@(Env e) qual spine = case e.evalExtern env qual spine of
842+ Nothing -> SemExtern qual spine (defer \_ -> neutralSpine (NeutVar qual) spine)
843+ Just sem -> sem
844+
845+envForGroup :: Env -> EvalRef -> InlineAccessor -> Array (Qualified Ident) -> Env
846+envForGroup env ref acc group
847+ | Array.null group = env
848+ | otherwise = addStop env ref acc
836849
837850evalExternFromImpl :: Env -> Qualified Ident -> Tuple BackendAnalysis ExternImpl -> Array ExternSpine -> Maybe BackendSemantics
838−evalExternFromImpl env@(Env e) qual (Tuple analysis impl) spine = case impl of
839− ExternExpr [] expr -> do
840− let directive = Map.lookup (EvalExtern qual Nothing) e.directives
841− case expr, spine of
842− NeutralExpr (Lit lit), [] | shouldInlineExternLiteral lit directive ->
843− Just $ eval env expr
844− _, [] | shouldInlineExternReference qual analysis expr directive ->
845− Just $ eval env expr
846− body, [ ExternApp args ] | shouldInlineExternApp qual analysis body args directive ->
847− Just $ evalApp env (eval env body) args
848− _, _ ->
849− Nothing
850− ExternCtor _ ct ty tag fields ->
851− case fields, spine of
852− [], [] ->
851+evalExternFromImpl env@(Env e) qual (Tuple analysis impl) spine = case spine of
852+ [] ->
853+ case impl of
854+ ExternExpr group expr -> do
855+ let ref = EvalExtern qual
856+ case Map.lookup ref e.directives >>= Map.lookup InlineRef of
857+ Just InlineNever ->
858+ Just $ NeutStop qual
859+ Just InlineAlways ->
860+ Just $ eval (envForGroup env ref InlineRef group) expr
861+ Just (InlineArity _) ->
862+ Nothing
863+ _ ->
864+ case expr of
865+ NeutralExpr (Lit lit) | shouldInlineExternLiteral lit ->
866+ Just $ eval (envForGroup env ref InlineRef group) expr
867+ _ | shouldInlineExternReference qual analysis expr ->
868+ Just $ eval (envForGroup env ref InlineRef group) expr
869+ _ ->
870+ Nothing
871+ ExternCtor _ ct ty tag [] ->
853872 Just $ NeutData qual ct ty tag []
854− _, [ ExternApp args ] | Array.length fields == Array.length args ->
873+ _ ->
874+ Nothing
875+ [ ExternAccessor acc@(GetProp prop) ] ->
876+ case impl of
877+ ExternExpr group expr -> do
878+ let ref = EvalExtern qual
879+ case Map.lookup ref e.directives >>= Map.lookup (InlineProp prop) of
880+ Just InlineNever ->
881+ Just $ neutralSpine (NeutStop qual) spine
882+ Just InlineAlways ->
883+ Just $ evalSpine env (eval (envForGroup env ref (InlineProp prop) group) expr) spine
884+ _ ->
885+ Nothing
886+ ExternDict group props | Just (Tuple analysis' body) <- findProp prop props -> do
887+ let ref = EvalExtern qual
888+ case Map.lookup ref e.directives >>= Map.lookup (InlineProp prop) of
889+ Just InlineNever ->
890+ Just $ neutralSpine (NeutStop qual) spine
891+ Just InlineAlways ->
892+ Just $ eval (envForGroup env ref (InlineProp prop) group) body
893+ Just (InlineArity _) ->
894+ Nothing
895+ _ | shouldInlineExternAccessor qual analysis' body acc ->
896+ Just $ eval (envForGroup env ref (InlineProp prop) group) body
897+ _ ->
898+ Nothing
899+ _ ->
900+ Nothing
901+ [ ExternAccessor (GetProp prop), ExternApp args ] ->
902+ case impl of
903+ ExternExpr group expr -> do
904+ let ref = EvalExtern qual
905+ case Map.lookup ref e.directives >>= Map.lookup (InlineProp prop) of
906+ Just InlineNever ->
907+ Just $ neutralSpine (NeutStop qual) spine
908+ Just InlineAlways ->
909+ Just $ evalSpine env (eval (envForGroup env ref (InlineProp prop) group) expr) spine
910+ Just (InlineArity n)
911+ | Array.length args >= n ->
912+ Just $ evalSpine env (eval (envForGroup env ref (InlineProp prop) group) expr) spine
913+ | otherwise ->
914+ Nothing
915+ _ ->
916+ Nothing
917+ ExternDict group props | Just (Tuple analysis' body) <- findProp prop props -> do
918+ let ref = EvalExtern qual
919+ case Map.lookup ref e.directives >>= Map.lookup (InlineProp prop) of
920+ Just InlineNever ->
921+ Just $ neutralSpine (NeutStop qual) spine
922+ Just InlineAlways ->
923+ Just $ evalApp env (eval (envForGroup env ref (InlineProp prop) group) body) args
924+ Just (InlineArity n)
925+ | Array.length args >= n ->
926+ Just $ evalApp env (eval (envForGroup env ref (InlineProp prop) group) body) args
927+ | otherwise ->
928+ Nothing
929+ _ | shouldInlineExternApp qual analysis' body args ->
930+ Just $ evalApp env (eval (envForGroup env ref (InlineProp prop) group) body) args
931+ _ ->
932+ Nothing
933+ _ ->
934+ Nothing
935+ [ ExternApp args ] ->
936+ case impl of
937+ ExternExpr group expr -> do
938+ let ref = EvalExtern qual
939+ case Map.lookup ref e.directives >>= Map.lookup InlineRef of
940+ Just InlineNever ->
941+ Just $ neutralSpine (NeutStop qual) spine
942+ Just InlineAlways ->
943+ Just $ evalApp env (eval (envForGroup env ref InlineRef group) expr) args
944+ Just (InlineArity n)
945+ | Array.length args >= n ->
946+ Just $ evalApp env (eval (envForGroup env ref InlineRef group) expr) args
947+ | otherwise ->
948+ Nothing
949+ _ | shouldInlineExternApp qual analysis expr args ->
950+ Just $ evalApp env (eval (envForGroup env ref InlineRef group) expr) args
951+ _ ->
952+ Nothing
953+ ExternCtor _ ct ty tag fields | Array.length fields == Array.length args ->
855954 Just $ NeutData qual ct ty tag $ Array.zip fields args
856− _, _ ->
955+ _ ->
857956 Nothing
858− ExternDict group props ->
859− case spine of
860− [ ExternAccessor acc@(GetProp prop), ExternApp args ] | Just (Tuple analysis' body) <- findProp prop props -> do
861− let ref = EvalExtern qual (Just acc)
862− let directive = Map.lookup ref e.directives
863− if shouldInlineExternApp qual analysis' body args directive then do
864− let env' = if Array.null group then env else addStop env ref
865− Just $ evalApp env (eval env' body) args
866− else
867− Nothing
868− [ ExternAccessor acc@(GetProp prop) ] | Just (Tuple analysis' body) <- findProp prop props -> do
869− let ref = EvalExtern qual (Just acc)
870− let directive = Map.lookup ref e.directives
871− if shouldInlineExternAccessor qual analysis' body acc directive then do
872− let env' = if Array.null group then env else addStop env ref
873− Just $ eval env' body
874− else
875− Nothing
957+ [ ExternApp _, ExternAccessor (GetProp prop) ] ->
958+ case impl of
959+ ExternExpr group fn -> do
960+ let ref = EvalExtern qual
961+ case Map.lookup ref e.directives >>= Map.lookup (InlineSpineProp prop) of
962+ Just InlineNever ->
963+ Just $ neutralSpine (NeutStop qual) spine
964+ Just InlineAlways ->
965+ Just $ evalSpine env (eval (envForGroup env ref (InlineSpineProp prop) group) fn) spine
966+ _ ->
967+ Nothing
968+ _ ->
969+ Nothing
970+ [ ExternApp _, ExternAccessor (GetProp prop), ExternApp args2 ] ->
971+ case impl of
972+ ExternExpr group fn -> do
973+ let ref = EvalExtern qual
974+ case Map.lookup ref e.directives >>= Map.lookup (InlineSpineProp prop) of
975+ Just InlineNever ->
976+ Just $ neutralSpine (NeutStop qual) spine
977+ Just InlineAlways ->
978+ Just $ evalSpine env (eval (envForGroup env ref (InlineSpineProp prop) group) fn) spine
979+ Just (InlineArity n) | Array.length args2 >= n ->
980+ Just $ evalSpine env (eval (envForGroup env ref (InlineSpineProp prop) group) fn) spine
981+ _ ->
982+ Nothing
876983 _ ->
877984 Nothing
878985 _ ->
879986 Nothing
880987
881−externRefFromSpine :: Qualified Ident -> Array ExternSpine -> EvalRef
882−externRefFromSpine qual spine = case Array.head spine of
883− Just (ExternAccessor acc) ->
884− EvalExtern qual (Just acc)
885− _ ->
886− EvalExtern qual Nothing
887−
888988analysisFromDirective :: BackendAnalysis -> InlineDirective -> BackendAnalysis
889989analysisFromDirective (BackendAnalysis analysis) = case _ of
890990 InlineAlways ->
@@ -1353,52 +1453,37 @@ shouldInlineLet level a b = do
13531453 || (isAbs a && (total == 1 || Map.isEmpty s1.usages || s1.size < 16))
13541454 || (isKnownEffect a && total == 1)
13551455
1356−shouldInlineExternReference :: Qualified Ident -> BackendAnalysis -> NeutralExpr -> Maybe InlineDirective -> Boolean
1357−shouldInlineExternReference _ (BackendAnalysis s) _ = case _ of
1358− Just InlineAlways -> true
1359− Just InlineNever -> false
1360− Just (InlineArity _) -> false
1361− _ ->
1362− s.complexity <= Deref && s.size < 16
1456+shouldInlineExternReference :: Qualified Ident -> BackendAnalysis -> NeutralExpr -> Boolean
1457+shouldInlineExternReference _ (BackendAnalysis s) _ =
1458+ s.complexity <= Deref && s.size < 16
13631459
1364−shouldInlineExternApp :: Qualified Ident -> BackendAnalysis -> NeutralExpr -> Spine BackendSemantics -> Maybe InlineDirective -> Boolean
1365−shouldInlineExternApp _ (BackendAnalysis s) _ args = case _ of
1366− Just InlineAlways -> true
1367− Just InlineNever -> false
1368− Just (InlineArity n) -> Array.length args == n
1369− _ ->
1370− (s.complexity <= Deref && s.size < 16)
1371− || (Map.isEmpty s.usages && Set.isEmpty s.deps && s.size < 64)
1372− || (delayed && Array.length s.args <= Array.length args && s.size < 16)
1373− || (delayed && or (Array.zipWith shouldInlineExternAppArg s.args args) && s.size < 16)
1374− where
1375− delayed = Array.length s.args > 0
1460+shouldInlineExternApp :: Qualified Ident -> BackendAnalysis -> NeutralExpr -> Spine BackendSemantics -> Boolean
1461+shouldInlineExternApp _ (BackendAnalysis s) _ args =
1462+ (s.complexity <= Deref && s.size < 16)
1463+ || (Map.isEmpty s.usages && Set.isEmpty s.deps && s.size < 64)
1464+ || (delayed && Array.length s.args <= Array.length args && s.size < 16)
1465+ || (delayed && or (Array.zipWith shouldInlineExternAppArg s.args args) && s.size < 16)
1466+ where
1467+ delayed = Array.length s.args > 0
13761468
13771469shouldInlineExternAppArg :: Usage -> BackendSemantics -> Boolean
13781470shouldInlineExternAppArg (Usage u) = case _ of
13791471 SemLam _ _ -> u.captured <= CaptureBranch && u.total > 0 && u.call == u.total
13801472 _ -> false
13811473
1382−shouldInlineExternAccessor :: Qualified Ident -> BackendAnalysis -> NeutralExpr -> BackendAccessor -> Maybe InlineDirective -> Boolean
1383−shouldInlineExternAccessor _ (BackendAnalysis s) _ _ = case _ of
1384− Just InlineAlways -> true
1385− Just InlineNever -> false
1386− _ ->
1387− s.complexity <= Deref && s.size < 16
1388−
1389−shouldInlineExternLiteral :: Literal NeutralExpr -> Maybe InlineDirective -> Boolean
1390−shouldInlineExternLiteral lit = case _ of
1391− Just InlineAlways -> true
1392− Just InlineNever -> false
1393− _ ->
1394− case lit of
1395− LitInt _ -> true
1396− LitNumber _ -> true
1397− LitString s -> String.length s <= 32
1398− LitChar _ -> true
1399− LitBoolean _ -> true
1400− LitArray a -> Array.null a
1401− LitRecord r -> Array.null r
1474+shouldInlineExternAccessor :: Qualified Ident -> BackendAnalysis -> NeutralExpr -> BackendAccessor -> Boolean
1475+shouldInlineExternAccessor _ (BackendAnalysis s) _ _ =
1476+ s.complexity <= Deref && s.size < 16
1477+
1478+shouldInlineExternLiteral :: Literal NeutralExpr -> Boolean
1479+shouldInlineExternLiteral = case _ of
1480+ LitInt _ -> true
1481+ LitNumber _ -> true
1482+ LitString s -> String.length s <= 32
1483+ LitChar _ -> true
1484+ LitBoolean _ -> true
1485+ LitArray a -> Array.null a
1486+ LitRecord r -> Array.null r
14021487
14031488isAbs :: BackendExpr -> Boolean
14041489isAbs = syntaxOf >>> case _ of