lhc-0.6.20081210: src/E/Inline.hs
module E.Inline(
app,
programMapRecGroups,
forceInline,
programDecomposedDs,
programMapProgGroups,
forceNoinline,
baseInlinability
) where
import Control.Monad.Writer
import Data.Monoid
import StringTable.Atom
import E.Annotate
import E.E
import E.Program
import E.Subst
import E.Values
import Support.FreeVars
import Info.Info(Info)
import Info.Types
import Name.Id
import Options
import Stats
import Util.Graph
import Util.SetLike
import qualified FlagOpts as FO
import qualified Info.Info as Info
-- | higher numbers mean we want to inline it more
baseInlinability t e
| forceNoinline t = -15
| forceSuperInline t = 10
| forceInline t = 7
| isAtomic e = 6
| whnfOrBot e = 4
| otherwise = 0
-- NOINLINE must take precidence because it is sometimes needed for correctness, while INLINE is surely an optimization.
forceInline :: HasProperties a => a -> Bool
forceInline x
| forceNoinline props = False
| not (fopts FO.InlinePragmas) = False
| otherwise = fromList [prop_INLINE,prop_WRAPPER,prop_SUPERINLINE] `intersects` props
where props = getProperties x
forceSuperInline :: HasProperties a => a -> Bool
forceSuperInline x
| forceNoinline props = False
| not (fopts FO.InlinePragmas) = False
| otherwise = member prop_SUPERINLINE props
where props = getProperties x
forceNoinline :: HasProperties a => a -> Bool
forceNoinline x = fromList [prop_HASRULE,prop_NOINLINE,prop_PLACEHOLDER] `intersects` getProperties x
app (e,[]) = return e
app (e,xs) = app' e xs
app' (ELit lc@LitCons { litName = n, litArgs = xs, litType = EPi ta tt }) (a:as) = do
mtick (toAtom $ "E.Simplify.typecon-reduce.{" ++ show n ++ "}" )
app (ELit (lc { litArgs = xs ++ [a], litType = subst ta a tt }),as)
app' (ELit LitCons { litName = n, litArgs = es, litAliasFor = Just af }) bs@(_:_) = do
mtick (toAtom $ "E.Simplify.newtype-reduce.{" ++ show n ++ "}" )
app (foldl eAp af (es ++ bs),[])
app' (ELam tvr e) (a:as) = do
mtick (toAtom "E.Simplify.beta-reduce")
app (subst tvr a e,as) -- TODO Fix quadradic substitution
--app (eLet tvr a e,as) -- TODO Fix quadradic substitution
app' (EPi tvr e) (a:as) = do
mtick (toAtom "E.Simplify.pi-reduce")
app (subst tvr a e,as) -- Okay, types are small
app' ec@ECase {} xs = do
mtick (toAtom "E.Simplify.case-application")
let f e = app' e xs
ec' <- caseBodiesMapM f ec
let t = foldl eAp (eCaseType ec') xs
return $ caseUpdate ec' { eCaseType = t }
app' (ELetRec ds e) xs = do
mtick (toAtom "E.Simplify.let-application")
e' <- app' e xs
return $ eLetRec ds e'
app' (EError s t) xs = do
mtick (toAtom "E.Simplify.error-application")
return $ EError s (foldl eAp t xs)
app' e as = do
return $ foldl EAp e as
-- | Map recursive groups, allowing an initial map to be passed in and it will
-- also propagate changes in the tvrInfo properly, and make sure nothing
-- shadows one of the global names.
programMapRecGroups :: Monad m =>
IdMap (Maybe E) -- ^ initial map to apply
-> (Id -> Info -> m Info) -- ^ annotate based on Id map
-> (E -> Info -> m Info) -- ^ annotate letbound bindings
-> (E -> Info -> m Info) -- ^ annotate lambdabound bindings
-> ((Bool,[Comb]) -> m [Comb]) -- ^ bool is true if group is recursive.
-> Program
-> m Program
programMapRecGroups imap idann letann lamann f prog = do
let g rs imap ((False,ds):rds) = do
ds' <- annotateCombs imap idann letann lamann ds
nds <- f (False,ds')
g (nds:rs) (bm nds imap) rds
g rs imap ((True,ds):rds) = do
ds' <- annotateCombs imap idann letann lamann ds
nds <- f (True,ds')
let imap' = (bm nds imap)
let smap = substMap' $ fromList [ (combIdent x,EVar (combHead x)) | x <- nds]
nds' = [ combBody_u smap x | x <- nds]
g (nds':rs) imap' rds
g rs _ [] = return $ concat rs
bm xs imap = fromList [ (combIdent c,Just $ EVar (combHead c)) | c <- xs ] `union` imap
ds <- g [] imap $ programDecomposedCombs prog
return $ programUpdate $ prog { progCombinators = ds }
{-
The boolean value represents whether the bindings are recursive.
-}
programDecomposedCombs :: Program -> [(Bool,[Comb])]
programDecomposedCombs prog = map f $ scc g where
--g = newGraph (progCombinators prog) combIdent ( toList . (union $ progSeasoning prog) . (freeVars :: Comb -> IdSet))
g = newGraph (progCombinators prog) combIdent ( toList . (freeVars :: Comb -> IdSet))
f (Left c) = (False,[c])
f (Right cs) = (True,cs)
programDecomposedDs :: Program -> [Either (TVr, E) [(TVr,E)]]
programDecomposedDs prog = decomposeDs $ programDs prog
programSubProgram prog rec ds = progCombinators_s ds prog { progType = SubProgram rec, progEntry = fromList (map combIdent ds) }
{-
Map recursive program groups.
Consider the program:
x = y
y = z
z = y
This would call 'f [x]' and 'f [y,z]'.
The code is made by the need for substitutions. The names of bindings can't change
but their types or other associated info might.
-}
programMapProgGroups :: Monad m =>
IdMap (Maybe E) -- ^ initial map to apply
-> (Program -> m Program)
-> Program
-> m Program
programMapProgGroups imap f prog = do
let g prog' rs imap ((False,ds):rds) = do
ds' <- annotateCombs imap nann nann nann ds
nprog <- f (programSubProgram prog' False ds')
let nds = progCombinators nprog
g (unames nds nprog) (nds:rs) (bm nds imap) rds
g prog' rs imap ((True,ds):rds) = do
ds' <- annotateCombs imap nann nann nann ds
nprog <- f (programSubProgram prog' True ds')
let imap' = bm nds imap
smap = substMap' $ fromList [ (combIdent x,EVar (combHead x)) | x <- nds]
nds = progCombinators nprog
nds' = [ combBody_u smap x | x <- nds]
g (unames nds' nprog) (nds':rs) imap' rds
g prog' rs _ [] = return $ (concat rs,prog')
bm xs imap = fromList [ (combIdent c,Just $ EVar (combHead c)) | c <- xs ] `union` imap
nann _ = return
unames ds prog = prog { progExternalNames = progExternalNames prog `mappend` fromList (map combIdent ds) }
(ds,prog'') <- g prog { progStats = mempty } [] imap $ programDecomposedCombs prog
return $ programUpdate $ prog { progCombinators = ds, progStats = progStats prog `mappend` progStats prog'' }