module CmmContFlowOpt
( runCmmContFlowOpts
, removeUnreachableBlocks, replaceBranches
)
where
import BlockId
import Cmm
import CmmUtils
import Digraph
import Maybes
import Outputable
import Compiler.Hoopl
import Control.Monad
import Prelude hiding (succ, unzip, zip)
runCmmContFlowOpts :: CmmGroup -> CmmGroup
runCmmContFlowOpts = map (optProc cmmCfgOpts)
cmmCfgOpts :: CmmGraph -> CmmGraph
cmmCfgOpts = removeUnreachableBlocks . blockConcat . branchChainElim
optProc :: (g -> g) -> GenCmmDecl d h g -> GenCmmDecl d h g
optProc opt (CmmProc info lbl g) = CmmProc info lbl (opt g)
optProc _ top = top
branchChainElim :: CmmGraph -> CmmGraph
branchChainElim g
| null lone_branch_blocks = g
| otherwise =
replaceLabels (mapFromList edges) g
where
blocks = toBlockList g
lone_branch_blocks :: [(BlockId, BlockId)]
lone_branch_blocks = mapCatMaybes isLoneBranch blocks
call_succs = foldl add emptyBlockSet blocks
where add :: BlockSet -> CmmBlock -> BlockSet
add succs b =
case lastNode b of
(CmmCall _ (Just k) _ _ _) -> setInsert k succs
(CmmForeignCall {succ=k}) -> setInsert k succs
_ -> succs
isLoneBranch :: CmmBlock -> Maybe (BlockId, BlockId)
isLoneBranch block
| (JustC (CmmEntry id), [], JustC (CmmBranch target)) <- blockToNodeList block
, not (setMember id call_succs)
= Just (id,target)
| otherwise
= Nothing
fromNode (b,_) = b
toNode a = (a,a)
all_block_ids :: LabelSet
all_block_ids = setFromList (map fst lone_branch_blocks)
`setUnion`
setFromList (map snd lone_branch_blocks)
forest = dfsTopSortG $ graphFromVerticesAndAdjacency nodes lone_branch_blocks
where nodes = map toNode $ setElems $ all_block_ids
edges = [ (fromNode y, fromNode x)
| (x:xs) <- map reverse forest, y <- xs ]
replaceLabels :: BlockEnv BlockId -> CmmGraph -> CmmGraph
replaceLabels env =
replace_eid . mapGraphNodes1 txnode
where
replace_eid g = g {g_entry = lookup (g_entry g)}
lookup id = mapLookup id env `orElse` id
txnode :: CmmNode e x -> CmmNode e x
txnode (CmmBranch bid) = CmmBranch (lookup bid)
txnode (CmmCondBranch p t f) = CmmCondBranch (exp p) (lookup t) (lookup f)
txnode (CmmSwitch e arms) = CmmSwitch (exp e) (map (liftM lookup) arms)
txnode (CmmCall t k a res r) = CmmCall (exp t) (liftM lookup k) a res r
txnode fc@CmmForeignCall{} = fc{ args = map exp (args fc)
, succ = lookup (succ fc) }
txnode other = mapExpDeep exp other
exp :: CmmExpr -> CmmExpr
exp (CmmLit (CmmBlock bid)) = CmmLit (CmmBlock (lookup bid))
exp (CmmStackSlot (CallArea (Young id)) i) = CmmStackSlot (CallArea (Young (lookup id))) i
exp e = e
replaceBranches :: BlockEnv BlockId -> CmmGraph -> CmmGraph
replaceBranches env g = mapGraphNodes (id, id, last) g
where
last :: CmmNode O C -> CmmNode O C
last (CmmBranch id) = CmmBranch (lookup id)
last (CmmCondBranch e ti fi) = CmmCondBranch e (lookup ti) (lookup fi)
last (CmmSwitch e tbl) = CmmSwitch e (map (fmap lookup) tbl)
last l@(CmmCall {}) = l
last l@(CmmForeignCall {}) = l
lookup id = fmap lookup (mapLookup id env) `orElse` id
predMap :: [CmmBlock] -> BlockEnv BlockSet
predMap blocks = foldr add_preds mapEmpty blocks
where add_preds block env = foldl (add (entryLabel block)) env (successors block)
add bid env b' =
mapInsert b' (setInsert bid (mapLookup b' env `orElse` setEmpty)) env
blockConcat :: CmmGraph -> CmmGraph
blockConcat g@(CmmGraph {g_entry=eid}) =
replaceLabels concatMap $ ofBlockMap (g_entry g) blocks'
where
blocks = postorderDfs g
(blocks', concatMap) =
foldr maybe_concat (toBlockMap g, mapEmpty) $ blocks
maybe_concat :: CmmBlock -> (LabelMap CmmBlock, LabelMap Label) -> (LabelMap CmmBlock, LabelMap Label)
maybe_concat b unchanged@(blocks', concatMap) =
let bid = entryLabel b
in case blockToNodeList b of
(JustC h, m, JustC (CmmBranch b')) ->
if canConcatWith b' then
(mapInsert bid (splice blocks' h m b') blocks',
mapInsert b' bid concatMap)
else unchanged
_ -> unchanged
num_preds bid = liftM setSize (mapLookup bid backEdges) `orElse` 0
canConcatWith b' = b' /= eid && num_preds b' == 1
backEdges = predMap blocks
splice :: forall map n e x.
IsMap map =>
map (Block n e x) -> n C O -> [n O O] -> KeyOf map -> Block n C x
splice blocks' h m bid' =
case mapLookup bid' blocks' of
Nothing -> panic "unknown successor block"
Just block | (_, m', l') <- blockToNodeList block
-> blockOfNodeList (JustC h, (m ++ m'), l')
removeUnreachableBlocks :: CmmGraph -> CmmGraph
removeUnreachableBlocks g
| length blocks < mapSize (toBlockMap g) = ofBlockList (g_entry g) blocks
| otherwise = g
where blocks = postorderDfs g