lhc-0.10: src/Grin/Stage2/DeadCode.hs
{-# LANGUAGE OverloadedStrings, FlexibleInstances, MultiParamTypeClasses, BangPatterns #-}
-- FIXME: Use HashSet instead of IntSet.
module Grin.Stage2.DeadCode
( trimDeadCode
, calcLiveNodes
) where
import Grin.Stage2.Types
import Control.Monad.State
import Control.Monad.Reader
import Control.Monad.Writer
import qualified Data.IntMap as IntMap
import qualified Data.IntSet as IntSet
import Debug.Trace
calcLiveNodes :: Grin -> IO ()
calcLiveNodes grin
= do let live = liveNodes grin
writeFile "livenodes.txt" (unlines (map show (IntSet.toList live)))
trimDeadCode :: Grin -> Grin
trimDeadCode grin
= grin { grinFunctions = map walkFunc [ fn | fn <- grinFunctions grin, nodeId (funcDefName fn) `IntSet.member` liveSet]
, grinCAFs = [ caf | caf <- grinCAFs grin, nodeId (cafName caf) `IntSet.member` liveSet ]
, grinNodes = [ node | node <- grinNodes grin, nodeId (nodeName node) `IntSet.member` liveSet ]
}
where walkFunc func
= func { funcDefBody = walkExp (funcDefBody func) }
walkExp (e1@Case{} :>>= binds :-> e2)
= walkExp e1 :>>= binds :-> walkExp e2
walkExp (e1@(Application (Builtin "update") args) :>>= binds :-> e2) | all isAlive args || True
= walkExp e1 :>>= binds :-> walkExp e2
walkExp (e1 :>>= binds :-> e2)
= if all isDead binds
then walkExp e2
else walkExp e1 :>>= binds :-> walkExp e2
walkExp (Case scrut alts)
= if nodeId scrut `IntSet.member` liveSet || True
then Case scrut (map walkAlt alts)
else Unit []
walkExp fn@(Application (Builtin "update") (ptr:_))
| nodeId ptr `IntSet.member` liveSet || True
= fn
| otherwise
= Unit []
walkExp fn = fn
walkAlt (alt :> exp) = alt :> walkExp exp
liveSet = liveNodes grin
isDead x = nodeId x `IntSet.notMember` liveSet
isAlive = not . isDead
liveNodes :: Grin -> IntSet.IntSet
liveNodes grin
= let entryPoint = nodeId (grinEntryPoint grin)
graph = execSM (grinGraph grin) entryPoint IntMap.empty
in reachable entryPoint graph
reachable :: Int -> DependencyGraph -> IntSet.IntSet
reachable entry graph
= loop (IntSet.singleton entry) (IntSet.singleton entry)
where loop marked new | IntSet.null new = marked
loop marked new
= let reachableByNew = IntSet.unions [ find node | node <- IntSet.toList new ]
unmarkedNew = reachableByNew `IntSet.difference` marked
in loop (marked `IntSet.union` unmarkedNew) unmarkedNew
find key = IntMap.findWithDefault IntSet.empty key graph
newtype SM a = SM { runSM :: Int -> DependencyGraph -> (a, DependencyGraph) }
instance Monad SM where
return x = SM $ \r s -> (x, s)
f >>= g = SM $ \r s -> case runSM f r s of
(a, !s') -> runSM (g a) r s'
instance MonadState (IntMap.IntMap IntSet.IntSet) SM where
get = SM $ \_ s -> (s, s)
put s = SM $ \_ _ -> ((), s)
instance MonadReader Int SM where
ask = SM $ \r s -> (r, s)
local fn m = SM $ \r s -> runSM m (fn r) s
execSM action r s
= case runSM action r s of
(a, s) -> s
type DependencyGraph = IntMap.IntMap IntSet.IntSet
type M a = SM a
top :: M Int
top = ask
grinGraph :: Grin -> M ()
grinGraph grin
= do mapM_ cafGraph (grinCAFs grin)
mapM_ funcGraph (grinFunctions grin)
insert k v m = let v' = IntMap.findWithDefault IntSet.empty k m
in IntMap.insertWith IntSet.union k v m
cafGraph :: CAF -> M ()
cafGraph caf
= do let deps = valueGraph (cafValue caf)
modify $ insert (nodeId (cafName caf)) deps
return ()
funcGraph :: FuncDef -> M ()
funcGraph func
= do bodyDeps <- local (const (nodeId (funcDefName func))) $ expGraph (funcDefBody func)
modify $ insert (nodeId (funcDefName func)) bodyDeps
return ()
expGraph :: Expression -> M IntSet.IntSet
expGraph (Unit vals)
= return $ IntSet.fromList (map nodeId vals)
expGraph (e1 :>>= binds :-> e2)
= do deps <- expGraph e1
forM_ binds $ \bind -> modify $ insert (nodeId bind) deps
expGraph e2
expGraph (Application (Builtin "updateMutVar") [ptr, val, realWorld])
= do --modify $ insert (nodeId ptr) (IntSet.singleton (nodeId val))
--modify $ insert (nodeId realWorld) (IntSet.singleton (nodeId ptr))
return $ IntSet.fromList [nodeId realWorld, nodeId ptr, nodeId val]
expGraph (Application (Builtin "update") args)
= do t <- top
let s = IntSet.fromList (map nodeId args)
modify $ insert t s
return IntSet.empty
expGraph (Application fn args)
= return $ IntSet.fromList (map nodeId (fn:args))
expGraph (Case scrut alts)
= do t <- top
modify $ insert t (IntSet.singleton (nodeId scrut))
depss <- mapM altGraph alts
forM_ depss $ \deps ->
do modify $ insert (nodeId scrut) deps
forM_ (IntSet.toList deps) $ \dep ->
modify $ insert dep (IntSet.singleton (nodeId scrut))
return $ IntSet.singleton (nodeId scrut)
expGraph (Fetch _idx hp)
= return $ IntSet.singleton (nodeId hp)
expGraph (Store vals)
= return $ IntSet.fromList (map nodeId vals)
expGraph (StoreHole _size)
= return IntSet.empty
expGraph (Constant value)
= return $ valueGraph value
nodeId :: Renamed -> Int
nodeId (Aliased uid _name) = uid
nodeId (Anonymous uid) = uid
nodeId (Builtin{}) = -1
nodeId (External{}) = -1
altGraph :: Alt -> M IntSet.IntSet
altGraph (value :> exp)
= IntSet.union (valueGraph value) `liftM` expGraph exp
valueGraph :: Value -> IntSet.IntSet
valueGraph (Node tag ConstructorNode _partial) = IntSet.singleton (nodeId tag)
valueGraph (Node tag FunctionNode _partial) = IntSet.singleton (nodeId tag)
valueGraph Lit{} = IntSet.empty
valueGraph Hole = IntSet.empty
valueGraph Empty = IntSet.empty