{-# LANGUAGE GADTs #-} {-# OPTIONS_GHC -Wall -fno-warn-name-shadowing #-} #if __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Safe #-} #endif module Compiler.Hoopl.Passes.Dominator ( Doms, DPath(..), domPath, domEntry, domLattice, extendDom , DominatorNode(..), DominatorTree(..), tree , immediateDominators , domPass ) where import Data.Maybe import Compiler.Hoopl type Doms = WithBot DPath -- ^ List of labels, extended with a standard bottom element -- | The fact that goes into the entry of a dominator analysis: the first node -- is dominated only by the entry point, which is represented by the empty list -- of labels. domEntry :: Doms domEntry = PElem (DPath []) newtype DPath = DPath [Label] -- ^ represents part of the domination relation: each label -- in a list is dominated by all its successors. This is a newtype only so -- we can give it a fancy Show instance. instance Show DPath where show (DPath ls) = concat (foldr (\l path -> show l : " -> " : path) ["entry"] ls) domPath :: Doms -> [Label] domPath Bot = [] -- lies: an unreachable node appears to be dominated by the entry domPath (PElem (DPath ls)) = ls extendDom :: Label -> DPath -> DPath extendDom l (DPath ls) = DPath (l:ls) domLattice :: DataflowLattice Doms domLattice = addPoints "dominators" extend extend :: JoinFun DPath extend _ (OldFact (DPath l)) (NewFact (DPath l')) = (changeIf (l `lengthDiffers` j), DPath j) where j = lcs l l' lcs :: [Label] -> [Label] -> [Label] -- longest common suffix lcs l l' | length l > length l' = lcs (drop (length l - length l') l) l' | length l < length l' = lcs l' l | otherwise = dropUnlike l l' l dropUnlike [] [] maybe_like = maybe_like dropUnlike (x:xs) (y:ys) maybe_like = dropUnlike xs ys (if x == y then maybe_like else xs) dropUnlike _ _ _ = error "this can't happen" lengthDiffers [] [] = False lengthDiffers (_:xs) (_:ys) = lengthDiffers xs ys lengthDiffers [] (_:_) = True lengthDiffers (_:_) [] = True -- | Dominator pass domPass :: (NonLocal n, Monad m) => FwdPass m n Doms domPass = FwdPass domLattice (mkFTransfer3 first (const id) distributeFact) noFwdRewrite where first n = fmap (extendDom $ entryLabel n) ---------------------------------------------------------------- data DominatorNode = Entry | Labelled Label data DominatorTree = Dominates DominatorNode [DominatorTree] -- ^ This data structure is a *rose tree* in which each node may have -- arbitrarily many children. Each node dominates all its descendants. -- | Map from a FactBase for dominator lists into a -- dominator tree. tree :: [(Label, Doms)] -> DominatorTree tree facts = Dominates Entry $ merge $ map reverse $ map mkList facts -- This code has been lightly tested. The key insight is this: to -- find lists that all have the same head, convert from a list of -- lists to a finite map, in 'children'. Then, to convert from the -- finite map to list of dominator trees, use the invariant that -- each key dominates all the lists of values. where merge lists = mapTree $ children $ filter (not . null) lists children = foldl addList noFacts addList :: FactBase [[Label]] -> [Label] -> FactBase [[Label]] addList map (x:xs) = mapInsert x (xs:existing) map where existing = fromMaybe [] $ lookupFact x map addList _ [] = error "this can't happen" mapTree :: FactBase [[Label]] -> [DominatorTree] mapTree map = [Dominates (Labelled x) (merge lists) | (x, lists) <- mapToList map] mkList (l, doms) = l : domPath doms instance Show DominatorTree where show = tree2dot -- | Given a dominator tree, produce a string representation, in the -- input language of dot, that will enable dot to produce a -- visualization of the tree. For more info about dot see -- http://www.graphviz.org. tree2dot :: DominatorTree -> String tree2dot t = concat $ "digraph {\n" : dot t ["}\n"] where dot :: DominatorTree -> [String] -> [String] dot (Dominates root trees) = (dotnode root :) . outedges trees . flip (foldl subtree) trees where outedges [] = id outedges (Dominates n _ : ts) = \s -> " " : show root : " -> " : show n : "\n" : outedges ts s dotnode Entry = " entryNode [shape=plaintext, label=\"entry\"]\n" dotnode (Labelled l) = " " ++ show l ++ "\n" subtree = flip dot instance Show DominatorNode where show Entry = "entryNode" show (Labelled l) = show l ---------------------------------------------------------------- -- | Takes FactBase from dominator analysis and returns a map from each -- label to its immediate dominator, if any immediateDominators :: FactBase Doms -> LabelMap Label immediateDominators = mapFoldWithKey add mapEmpty where add l (PElem (DPath (idom:_))) = mapInsert l idom add _ _ = id