lhc-0.10: src/Grin/Optimize/Inline.hs
{-# LANGUAGE OverloadedStrings #-}
module Grin.Optimize.Inline
( inlinePass
) where
import Grin.Types
import Traverse
import Grin.Transform
import Control.Monad.State
import Control.Monad.Reader
import Data.Monoid
import Debug.Trace
import Text.Printf
import Control.Applicative
import qualified Data.Map as Map
inlinePass :: Grin -> Grin
inlinePass = inlineSimple . inlineCAFs
-- Lower cheap CAFs to regular functions.
inlineCAFs :: Grin -> Grin
inlineCAFs grin
= let toInline = map funcDefName $ filter (\def -> funcCategory def `elem` [Cheap]) (grinFunctions grin)
cafsToInline = Map.fromList [ (cafName caf, tag) | caf@CAF{cafValue=Node tag FunctionNode 0 []} <- grinCAFs grin, tag `elem` toInline ]
in runTrans (runReaderT (inlineCAFs') cafsToInline) grin
type M = ReaderT (Map.Map Renamed Renamed) Transform
inlineCAFs' :: M ()
inlineCAFs' = transformExp inlineCAF
inlineCAF :: Expression -> M Expression
inlineCAF (Application fn args)
= inlineArgs args (Application fn)
inlineCAF (Unit v)
= inlineValue Unit v
inlineCAF (Store v)
= inlineValue Store v
inlineCAF e = tmapM inlineCAF e
inlineValue fn (Variable v)
= inlineArgs [v] $ \[v'] -> fn (Variable v')
inlineValue fn (Node tag nt missing args)
= inlineArgs args $ \args' -> fn (Node tag nt missing args')
inlineValue fn (Vector args)
= inlineArgs args $ \args' -> fn (Vector args')
inlineValue fn value
= return $ fn value
inlineArgs args fn
= do m <- ask
let worker acc [] = return (fn (reverse acc))
worker acc (x:xs) = case Map.lookup x m of
Nothing -> worker (x:acc) xs
Just caf -> do v <- newVariable
rest <- worker (v:acc) xs
return $ Store (Node caf FunctionNode 0 []) :>>= v :-> rest
worker [] args
---------------------------------
-- Inline cheap functions.
inlineSimple :: Grin -> Grin
inlineSimple grin
= let inp = Map.fromList [ (funcDefName def, (funcCategory def, def)) | def <- grinFunctions grin ]
in runTrans (runReaderT (transformExp inlineSimpleExp) inp) grin
type Simple = ReaderT (Map.Map Renamed (Category, FuncDef)) Transform
inlineSimpleExp :: Expression -> Simple Expression
inlineSimpleExp e@(Store (Node tag FunctionNode 0 args))
= do mbEntry <- findFunc tag
case mbEntry of
Just (Cheap, func) -> lazify =<< doInline func args
Just (Lazy, func) -> lazify =<< doInline func args
_ -> return e
inlineSimpleExp e = tmapM inlineSimpleExp e
doInline func args
= do let renamedArgs = Map.fromList (zip (funcDefArgs func) (args ++ repeat (Builtin "undefined")))
lift (renameExp renamedArgs (funcDefBody func))
lazify :: Expression -> Simple Expression
lazify (e1 :>>= bind :-> e2)
= do e2' <- lazify e2
return $ e1 :>>= bind :-> e2'
lazify (e1 :>> e2)
= do e2' <- lazify e2
return $ e1 :>> e2
lazify (Application fn args) | not (isBuiltin fn) && not (isExternal fn)
= return $ Store (Node fn FunctionNode 0 args)
lazify (Unit v)
= return $ Store v
lazify (Application (Builtin "eval") [arg])
= return $ Unit (Variable arg)
lazify e
= do v <- lift newVariable
return $ e :>>= v :-> Store (Variable v)
findFunc :: Renamed -> Simple (Maybe (Category, FuncDef))
findFunc name
= asks $ Map.lookup name
---------------------------------
-- Other stuff
threshold = 10
funcSize :: FuncDef -> Int
funcSize def = expressionSize (funcDefBody def)
expressionSize :: Expression -> Int
expressionSize (e1 :>>= bind :-> e2)
= expressionSize e1 + expressionSize e2
expressionSize (e1 :>> e2)
= expressionSize e1 + expressionSize e2
expressionSize (Application fn args)
= 1
expressionSize (Case scrut alts)
= sum [ expressionSize branch | _ :> branch <- alts ]
expressionSize Store{}
= 1
expressionSize Unit{}
= 1
data Category = NoInline | Lazy | Strict | Cheap deriving (Show,Eq)
instance Monoid Category where
mempty = Cheap
mappend NoInline _ = NoInline
mappend _ NoInline = NoInline
mappend Strict _ = Strict
mappend _ Strict = Strict
mappend Lazy _ = Lazy
mappend _ Lazy = Lazy
mappend Cheap Cheap = Cheap
bump :: Category -> Category
bump Cheap = Cheap
bump Lazy = Strict
bump Strict = Strict
bump NoInline = NoInline
funcCategory :: FuncDef -> Category
--funcCategory FuncDef{funcDefBody = Application (Builtin "eval") _}
-- = InlineLazy
funcCategory def = expressionCategory (funcDefBody def)
expressionCategory :: Expression -> Category
expressionCategory (e1 :>>= bind :-> e2)
= bump (expressionCategory e1) `mappend` expressionCategory e2
expressionCategory (e1 :>> e2)
= bump (expressionCategory e1) `mappend` expressionCategory e2
expressionCategory (Application fn args) | isExternal fn
= NoInline
expressionCategory (Application (Builtin "eval") _args)
= Lazy
expressionCategory (Application (Builtin "apply") _args)
= Lazy
expressionCategory (Application fn args) | isBuiltin fn
= Cheap
expressionCategory (Application fn args)
= Lazy
expressionCategory (Case scrut [_ :> branch])
= expressionCategory branch
expressionCategory (Case scrut alts)
= NoInline
expressionCategory (Store (Node _tag ConstructorNode _n _args))
= Cheap
expressionCategory (Store (Node _tag FunctionNode n _args)) | n >= 1
= Cheap
expressionCategory Store{}
= Lazy
expressionCategory Update{}
= Cheap
expressionCategory Unit{}
= Cheap