summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/cmm/CmmBuildInfoTables.hs149
-rw-r--r--compiler/cmm/CmmPipeline.hs81
2 files changed, 96 insertions, 134 deletions
diff --git a/compiler/cmm/CmmBuildInfoTables.hs b/compiler/cmm/CmmBuildInfoTables.hs
index fb025b598d..651cc6f40f 100644
--- a/compiler/cmm/CmmBuildInfoTables.hs
+++ b/compiler/cmm/CmmBuildInfoTables.hs
@@ -13,16 +13,15 @@
-- Todo: remove -fno-warn-warnings-deprecations
{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
module CmmBuildInfoTables
- ( CAFSet, CAFEnv, cafAnal, localCAFInfo, mkTopCAFInfo
- , setInfoTableSRT
- , TopSRT, emptySRT, srtToData
- , bundleCAFs
- ) where
+ ( CAFSet, CAFEnv, cafAnal
+ , doSRTs, TopSRT, emptySRT, srtToData )
+where
#include "HsVersions.h"
-- These should not be imported here!
import StgCmmUtils
+import Hoopl
import Digraph
import qualified Prelude as P
@@ -40,13 +39,13 @@ import Name
import Outputable
import SMRep
import UniqSupply
-
-import Hoopl
+import Util
import Data.Map (Map)
import qualified Data.Map as Map
import Data.Set (Set)
import qualified Data.Set as Set
+import Control.Monad
foldSet :: (a -> b -> b) -> b -> Set a -> b
#if __GLASGOW_HASKELL__ < 704
@@ -184,16 +183,13 @@ srtToData srt = [CmmData RelocatableReadOnlyData (Statics (lbl srt) tbl)]
-- in the SRT. Then, if the number of CAFs is small enough to fit in a bitmap,
-- we make sure they're all close enough to the bottom of the table that the
-- bitmap will be able to cover all of them.
-buildSRTs :: TopSRT -> Map CLabel CAFSet -> CAFSet ->
- UniqSM (TopSRT, Maybe CmmDecl, C_SRT)
-buildSRTs topSRT topCAFMap cafs =
- do let liftCAF lbl z = -- get CAFs for functions without static closures
- case Map.lookup lbl topCAFMap of Just cafs -> z `Set.union` cafs
- Nothing -> Set.insert lbl z
+buildSRTs :: TopSRT -> CAFSet -> UniqSM (TopSRT, Maybe CmmDecl, C_SRT)
+buildSRTs topSRT cafs =
+ do let
-- For each label referring to a function f without a static closure,
-- replace it with the CAFs that are reachable from f.
sub_srt topSRT localCafs =
- let cafs = Set.elems (foldSet liftCAF Set.empty localCafs)
+ let cafs = Set.elems localCafs
mkSRT topSRT =
do localSRTs <- procpointSRT (lbl topSRT) (elt_map topSRT) cafs
return (topSRT, localSRTs)
@@ -267,15 +263,15 @@ to_SRT top_srt off len bmp
-- keep its CAFs live.)
-- Any procedure referring to a non-static CAF c must keep live
-- any CAF that is reachable from c.
-localCAFInfo :: CAFEnv -> CmmDecl -> Maybe (CLabel, CAFSet)
-localCAFInfo _ (CmmData _ _) = Nothing
+localCAFInfo :: CAFEnv -> CmmDecl -> (CAFSet, Maybe CLabel)
+localCAFInfo _ (CmmData _ _) = (Set.empty, Nothing)
localCAFInfo cafEnv (CmmProc top_info top_l (CmmGraph {g_entry=entry})) =
case info_tbl top_info of
- CmmInfoTable { cit_rep = rep }
- | not (isStaticRep rep)
- -> Just (toClosureLbl top_l,
- expectJust "maybeBindCAFs" $ mapLookup entry cafEnv)
- _ -> Nothing
+ CmmInfoTable { cit_rep = rep } | not (isStaticRep rep)
+ -> (cafs, Just (toClosureLbl top_l))
+ _other -> (cafs, Nothing)
+ where
+ cafs = expectJust "maybeBindCAFs" $ mapLookup entry cafEnv
-- Once we have the local CAF sets for some (possibly) mutually
-- recursive functions, we can create an environment mapping
@@ -288,54 +284,77 @@ localCAFInfo cafEnv (CmmProc top_info top_l (CmmGraph {g_entry=entry})) =
-- the environment with every reference to f replaced by its set of CAFs.
-- To do this replacement efficiently, we gather strongly connected
-- components, then we sort the components in topological order.
-mkTopCAFInfo :: [(CLabel, CAFSet)] -> Map CLabel CAFSet
+mkTopCAFInfo :: [(CAFSet, Maybe CLabel)] -> Map CLabel CAFSet
mkTopCAFInfo localCAFs = foldl addToTop Map.empty g
- where addToTop env (AcyclicSCC (l, cafset)) =
+ where
+ addToTop env (AcyclicSCC (l, cafset)) =
Map.insert l (flatten env cafset) env
addToTop env (CyclicSCC nodes) =
let (lbls, cafsets) = unzip nodes
cafset = foldr Set.delete (foldl Set.union Set.empty cafsets) lbls
in foldl (\env l -> Map.insert l (flatten env cafset) env) env lbls
- flatten env cafset = foldSet (lookup env) Set.empty cafset
- lookup env caf cafset' =
- case Map.lookup caf env of Just cafs -> foldSet add cafset' cafs
- Nothing -> add caf cafset'
- add caf cafset' = Set.insert caf cafset'
+
g = stronglyConnCompFromEdgedVertices
- (map (\n@(l, cafs) -> (n, l, Set.elems cafs)) localCAFs)
-
--- Bundle the CAFs used at a procpoint.
-bundleCAFs :: CAFEnv -> CmmDecl -> (CAFSet, CmmDecl)
-bundleCAFs cafEnv t@(CmmProc _ _ (CmmGraph {g_entry=entry})) =
- (expectJust "bundleCAFs" (mapLookup entry cafEnv), t)
-bundleCAFs _ t = (Set.empty, t)
-
--- Construct the SRTs for the given procedure.
-setInfoTableSRT :: Map CLabel CAFSet -> TopSRT -> (CAFSet, CmmDecl) ->
- UniqSM (TopSRT, [CmmDecl])
-setInfoTableSRT topCAFMap topSRT (cafs, t) =
- setSRT cafs topCAFMap topSRT t
-
-setSRT :: CAFSet -> Map CLabel CAFSet -> TopSRT ->
- CmmDecl -> UniqSM (TopSRT, [CmmDecl])
-setSRT cafs topCAFMap topSRT t =
- do (topSRT, cafTable, srt) <- buildSRTs topSRT topCAFMap cafs
- let t' = updInfo id (const srt) t
- case cafTable of
- Just tbl -> return (topSRT, [t', tbl])
- Nothing -> return (topSRT, [t'])
-
-type StackLayout = Liveness
-
-updInfo :: (StackLayout -> StackLayout) -> (C_SRT -> C_SRT) -> CmmDecl -> CmmDecl
-updInfo toVars toSrt (CmmProc top_info top_l g) =
- CmmProc (top_info {info_tbl=updInfoTbl toVars toSrt (info_tbl top_info)}) top_l g
-updInfo _ _ t = t
-
-updInfoTbl :: (StackLayout -> StackLayout) -> (C_SRT -> C_SRT) -> CmmInfoTable -> CmmInfoTable
-updInfoTbl toVars toSrt info_tbl@(CmmInfoTable {})
- = info_tbl { cit_srt = toSrt (cit_srt info_tbl)
- , cit_rep = case cit_rep info_tbl of
- StackRep ls -> StackRep (toVars ls)
- other -> other }
-updInfoTbl _ _ t@CmmNonInfoTable = t
+ [ ((l,cafs), l, Set.elems cafs) | (cafs, Just l) <- localCAFs ]
+
+flatten :: Map CLabel CAFSet -> CAFSet -> CAFSet
+flatten env cafset = foldSet (lookup env) Set.empty cafset
+ where
+ lookup env caf cafset' =
+ case Map.lookup caf env of
+ Just cafs -> foldSet Set.insert cafset' cafs
+ Nothing -> Set.insert caf cafset'
+
+bundle :: Map CLabel CAFSet
+ -> (CAFEnv, CmmDecl)
+ -> (CAFSet, Maybe CLabel)
+ -> (CAFSet, CmmDecl)
+bundle flatmap (_, decl) (cafs, Nothing)
+ = (flatten flatmap cafs, decl)
+bundle flatmap (_, decl) (_, Just l)
+ = (expectJust "bundle" $ Map.lookup l flatmap, decl)
+
+flattenCAFSets :: [(CAFEnv, [CmmDecl])] -> [(CAFSet, CmmDecl)]
+flattenCAFSets cpsdecls = zipWith (bundle flatmap) zipped localCAFs
+ where
+ zipped = [(e,d) | (e,ds) <- cpsdecls, d <- ds ]
+ localCAFs = unzipWith localCAFInfo zipped
+ flatmap = mkTopCAFInfo localCAFs -- transitive closure of localCAFs
+
+doSRTs :: TopSRT
+ -> [(CAFEnv, [CmmDecl])]
+ -> IO (TopSRT, [CmmDecl])
+
+doSRTs topSRT tops
+ = do
+ let caf_decls = flattenCAFSets tops
+ us <- mkSplitUniqSupply 'u'
+ let (topSRT', gs') = initUs_ us $ foldM setSRT (topSRT, []) caf_decls
+ return (topSRT', reverse gs' {- Note [reverse gs] -})
+ where
+ setSRT (topSRT, rst) (cafs, decl@(CmmProc{})) = do
+ (topSRT, cafTable, srt) <- buildSRTs topSRT cafs
+ let decl' = updInfo (const srt) decl
+ case cafTable of
+ Just tbl -> return (topSRT, decl': tbl : rst)
+ Nothing -> return (topSRT, decl' : rst)
+ setSRT (topSRT, rst) (_, decl) =
+ return (topSRT, decl : rst)
+
+{- Note [reverse gs]
+
+ It is important to keep the code blocks in the same order,
+ otherwise binary sizes get slightly bigger. I'm not completely
+ sure why this is, perhaps the assembler generates bigger jump
+ instructions for forward refs. --SDM
+-}
+
+updInfo :: (C_SRT -> C_SRT) -> CmmDecl -> CmmDecl
+updInfo toSrt (CmmProc top_info top_l g) =
+ CmmProc (top_info {info_tbl = updInfoTbl toSrt (info_tbl top_info)}) top_l g
+updInfo _ t = t
+
+updInfoTbl :: (C_SRT -> C_SRT) -> CmmInfoTable -> CmmInfoTable
+updInfoTbl toSrt info_tbl@(CmmInfoTable {})
+ = info_tbl { cit_srt = toSrt (cit_srt info_tbl) }
+updInfoTbl _ t@CmmNonInfoTable = t
diff --git a/compiler/cmm/CmmPipeline.hs b/compiler/cmm/CmmPipeline.hs
index 3b5a6ebbfc..f2a2855d7b 100644
--- a/compiler/cmm/CmmPipeline.hs
+++ b/compiler/cmm/CmmPipeline.hs
@@ -9,7 +9,6 @@ module CmmPipeline (
cmmPipeline
) where
-import CLabel
import Cmm
import CmmLint
import CmmBuildInfoTables
@@ -18,76 +17,41 @@ import CmmProcPoint
import CmmContFlowOpt
import CmmLayoutStack
import CmmSink
+import Hoopl
import UniqSupply
import DynFlags
import ErrUtils
import HscTypes
-import Data.Maybe
import Control.Monad
import Outputable
-import qualified Data.Set as Set
-import Data.Map (Map)
-
-----------------------------------------------------------------------------
-- | Top level driver for C-- pipeline
-----------------------------------------------------------------------------
--- There are two complications here:
--- 1. We need to compile the procedures in two stages because we need
--- an analysis of the procedures to tell us what CAFs they use.
--- The first stage returns a map from procedure labels to CAFs,
--- along with a closure that will compute SRTs and attach them to
--- the compiled procedures.
--- The second stage is to combine the CAF information into a top-level
--- CAF environment mapping non-static closures to the CAFs they keep live,
--- then pass that environment to the closures returned in the first
--- stage of compilation.
--- 2. We need to thread the module's SRT around when the SRT tables
--- are computed for each procedure.
--- The SRT needs to be threaded because it is grown lazily.
--- 3. We run control flow optimizations twice, once before any pipeline
--- work is done, and once again at the very end on all of the
--- resulting C-- blocks. EZY: It's unclear whether or not whether
--- we actually need to do the initial pass.
+
cmmPipeline :: HscEnv -- Compilation env including
-- dynamic flags: -dcmm-lint -ddump-cps-cmm
-> TopSRT -- SRT table and accumulating list of compiled procs
-> CmmGroup -- Input C-- with Procedures
-> IO (TopSRT, CmmGroup) -- Output CPS transformed C--
+
cmmPipeline hsc_env topSRT prog =
do let dflags = hsc_dflags hsc_env
- --
- showPass dflags "CPSZ"
-
- (cafEnvs, tops) <- {-# SCC "tops" #-} liftM unzip $ mapM (cpsTop hsc_env) prog
- -- tops :: [[(CmmDecl,CAFSet]] (one list per group)
- let topCAFEnv = {-# SCC "topCAFEnv" #-} mkTopCAFInfo (concat cafEnvs)
-
- -- folding over the groups
- (topSRT, tops) <- {-# SCC "toTops" #-} foldM (toTops topCAFEnv) (topSRT, []) tops
+ showPass dflags "CPSZ"
- let cmms :: CmmGroup
- cmms = reverse (concat tops)
+ tops <- {-# SCC "tops" #-} mapM (cpsTop hsc_env) prog
+ (topSRT, cmms) <- {-# SCC "toTops" #-} doSRTs topSRT tops
dumpIfSet_dyn dflags Opt_D_dump_cps_cmm "Post CPS Cmm" (ppr cmms)
return (topSRT, cmms)
-{- [Note global fuel]
-~~~~~~~~~~~~~~~~~~~~~
-The identity and the last pass are stored in
-mutable reference cells in an 'HscEnv' and are
-global to one compiler session.
--}
--- EZY: It might be helpful to have an easy way of dumping the "pre"
--- input for any given phase, besides just turning it all on with
--- -ddump-cmmz
-cpsTop :: HscEnv -> CmmDecl -> IO ([(CLabel, CAFSet)], [(CAFSet, CmmDecl)])
-cpsTop _ p@(CmmData {}) = return ([], [(Set.empty, p)])
+cpsTop :: HscEnv -> CmmDecl -> IO (CAFEnv, [CmmDecl])
+cpsTop _ p@(CmmData {}) = return (mapEmpty, [p])
cpsTop hsc_env (CmmProc h@(TopInfo {stack_info=StackInfo {arg_space=entry_off}}) l g) =
do
----------- Control-flow optimisations ---------------
@@ -132,31 +96,21 @@ cpsTop hsc_env (CmmProc h@(TopInfo {stack_info=StackInfo {arg_space=entry_off}})
splitAtProcPoints l callPPs procPoints procPointMap (CmmProc h l g)
dumps Opt_D_dump_cmmz_split "Post splitting" gs
- ------------- More CAFs ------------------------------
+ ------------- CAF analysis ------------------------------
let cafEnv = {-# SCC "cafAnal" #-} cafAnal g
- let localCAFs = {-# SCC "localCAFs" #-} catMaybes $ map (localCAFInfo cafEnv) gs
- mbpprTrace "localCAFs" (ppr localCAFs) $ return ()
- -- NO MORE GRAPH TRANSFORMATION AFTER HERE -- JUST MAKING INFOTABLES
+ ------------- Populate info tables with stack info ------
gs <- {-# SCC "setInfoTableStackMap" #-}
return $ map (setInfoTableStackMap stackmaps) gs
dumps Opt_D_dump_cmmz_info "after setInfoTableStackMap" gs
- ----------- Control-flow optimisations ---------------
+ ----------- Control-flow optimisations -----------------
gs <- {-# SCC "cmmCfgOpts(2)" #-} return $ map cmmCfgOptsProc gs
dumps Opt_D_dump_cmmz_cfg "Post control-flow optimsations" gs
- gs <- {-# SCC "bundleCAFs" #-} return $ map (bundleCAFs cafEnv) gs
- dumps Opt_D_dump_cmmz_cafs "after bundleCAFs" gs
-
- return (localCAFs, gs)
-
- -- gs :: [ (CAFSet, CmmDecl) ]
- -- localCAFs :: [ (CLabel, CAFSet) ] -- statics filtered out(?)
+ return (cafEnv, gs)
where dflags = hsc_dflags hsc_env
- mbpprTrace x y z | dopt Opt_D_dump_cmmz dflags = pprTrace x y z
- | otherwise = z
dump = dumpGraph dflags
dumps flag name
@@ -188,14 +142,3 @@ dumpWith dflags flag txt g = do
when (not (dopt flag dflags)) $
dumpIfSet_dyn dflags Opt_D_dump_cmmz txt (ppr g)
--- This probably belongs in CmmBuildInfoTables?
--- We're just finishing the job here: once we know what CAFs are defined
--- in non-static closures, we can build the SRTs.
-toTops :: Map CLabel CAFSet -> (TopSRT, [[CmmDecl]])
- -> [(CAFSet, CmmDecl)] -> IO (TopSRT, [[CmmDecl]])
-toTops topCAFEnv (topSRT, tops) gs =
- do let setSRT (topSRT, rst) g =
- do (topSRT, gs) <- setInfoTableSRT topCAFEnv topSRT g
- return (topSRT, gs : rst)
- (topSRT, gs') <- runUniqSM $ foldM setSRT (topSRT, []) gs
- return (topSRT, concat gs' : tops)