+#if __GLASGOW_HASKELL__ >= 611
+{-# OPTIONS_GHC -XNoMonoLocalBinds #-}
+#endif
+-- Norman likes local bindings
+-- If this module lives on I'd like to get rid of this flag in due course
+
module CmmBuildInfoTables
( CAFSet, CAFEnv, CmmTopForInfoTables(..), cafAnal, localCAFInfo, mkTopCAFInfo
, setInfoTableSRT, setInfoTableStackMap
import DFMonad
import Module
import FastString
-import FiniteMap
import ForeignCall
import IdInfo
import Data.List
import ZipCfgCmmRep
import ZipDataflow
+import Data.Map (Map)
+import qualified Data.Map as Map
+import qualified FiniteMap as Map
+
----------------------------------------------------------------
-- Building InfoTables
liveSlots :: [RegSlotInfo]
liveSlots = sortBy (\ (off,_,_) (off',_,_) -> compare off' off)
- (foldFM (\_ -> flip $ foldl add_slot) [] slots)
+ (Map.foldRightWithKey (\_ -> flip $ foldl add_slot) [] slots)
add_slot :: [RegSlotInfo] -> SubArea -> [RegSlotInfo]
add_slot rst (a@(RegSlot r@(LocalReg _ ty)), off, w) =
if off == w && widthInBytes (typeWidth ty) == w then
- (expectJust "add_slot" (lookupFM areaMap a), r, w) : rst
+ (expectJust "add_slot" (Map.lookup a areaMap), r, w) : rst
else panic "live_ptrs: only part of a variable live at a proc point"
add_slot rst (CallArea Old, _, _) =
rst -- the update frame (or return infotable) should be live
slots :: SubAreaSet -- The SubAreaSet for 'bid'
slots = expectJust "live_ptrs slots" $ lookupBlockEnv slotEnv bid
- youngByte = expectJust "live_ptrs bid_pos" $ lookupFM areaMap (CallArea (Young bid))
+ youngByte = expectJust "live_ptrs bid_pos" $ Map.lookup (CallArea (Young bid)) areaMap
-- Construct the stack maps for the given procedure.
setInfoTableStackMap :: SlotEnv -> AreaMap -> CmmTopForInfoTables -> CmmTopForInfoTables
-----------------------------------------------------------------------
-- Finding the CAFs used by a procedure
-type CAFSet = FiniteMap CLabel ()
+type CAFSet = Map CLabel ()
type CAFEnv = BlockEnv CAFSet
-- First, an analysis to find live CAFs.
cafLattice :: DataflowLattice CAFSet
-cafLattice = DataflowLattice "live cafs" emptyFM add False
- where add new old = if sizeFM new' > sizeFM old then aTx new' else noTx new'
- where new' = new `plusFM` old
+cafLattice = DataflowLattice "live cafs" Map.empty add False
+ where add new old = if Map.size new' > Map.size old
+ then aTx new'
+ else noTx new'
+ where new' = new `Map.union` old
cafTransfers :: BackwardTransfers Middle Last CAFSet
cafTransfers = BackwardTransfers first middle last
CmmLit (CmmLabelOff c _) -> add c set
CmmLit (CmmLabelDiffOff c1 c2 _) -> add c1 $ add c2 set
_ -> set
- add l s = if hasCAF l then addToFM s (cvtToClosureLbl l) () else s
+ add l s = if hasCAF l then Map.insert (cvtToClosureLbl l) () s else s
type CafFix a = FuelMonad (BackwardFixedPoint Middle Last CAFSet a)
cafAnal :: LGraph Middle Last -> FuelMonad CAFEnv
data TopSRT = TopSRT { lbl :: CLabel
, next_elt :: Int -- the next entry in the table
, rev_elts :: [CLabel]
- , elt_map :: FiniteMap CLabel Int }
+ , elt_map :: Map CLabel Int }
-- map: CLabel -> its last entry in the table
instance Outputable TopSRT where
ppr (TopSRT lbl next elts eltmap) =
emptySRT :: MonadUnique m => m TopSRT
emptySRT =
do top_lbl <- getUniqueM >>= \ u -> return $ mkSRTLabel (mkFCallName u "srt") NoCafRefs
- return TopSRT { lbl = top_lbl, next_elt = 0, rev_elts = [], elt_map = emptyFM }
+ return TopSRT { lbl = top_lbl, next_elt = 0, rev_elts = [], elt_map = Map.empty }
cafMember :: TopSRT -> CLabel -> Bool
-cafMember srt lbl = elemFM lbl (elt_map srt)
+cafMember srt lbl = Map.member lbl (elt_map srt)
cafOffset :: TopSRT -> CLabel -> Maybe Int
-cafOffset srt lbl = lookupFM (elt_map srt) lbl
+cafOffset srt lbl = Map.lookup lbl (elt_map srt)
addCAF :: CLabel -> TopSRT -> TopSRT
addCAF caf srt =
srt { next_elt = last + 1
, rev_elts = caf : rev_elts srt
- , elt_map = addToFM (elt_map srt) caf last }
+ , elt_map = Map.insert caf last (elt_map srt) }
where last = next_elt srt
srtToData :: TopSRT -> CmmZ
-- 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 -> FiniteMap CLabel CAFSet -> CAFSet ->
+buildSRTs :: TopSRT -> Map CLabel CAFSet -> CAFSet ->
FuelMonad (TopSRT, Maybe CmmTopZ, C_SRT)
buildSRTs topSRT topCAFMap cafs =
do let liftCAF lbl () z = -- get CAFs for functions without static closures
- case lookupFM topCAFMap lbl of Just cafs -> z `plusFM` cafs
- Nothing -> addToFM z lbl ()
+ case Map.lookup lbl topCAFMap of Just cafs -> z `Map.union` cafs
+ Nothing -> Map.insert lbl () z
-- 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 = keysFM (foldFM liftCAF emptyFM localCafs)
+ let cafs = Map.keys (Map.foldRightWithKey liftCAF Map.empty localCafs)
mkSRT topSRT =
do localSRTs <- procpointSRT (lbl topSRT) (elt_map topSRT) cafs
return (topSRT, localSRTs)
add_if_too_far srt@(TopSRT {elt_map = m}) cafs =
add srt (sortBy farthestFst cafs)
where
- farthestFst x y = case (lookupFM m x, lookupFM m y) of
+ farthestFst x y = case (Map.lookup x m, Map.lookup y m) of
(Nothing, Nothing) -> EQ
(Nothing, Just _) -> LT
(Just _, Nothing) -> GT
-- Construct an SRT bitmap.
-- Adapted from simpleStg/SRT.lhs, which expects Id's.
-procpointSRT :: CLabel -> FiniteMap CLabel Int -> [CLabel] ->
+procpointSRT :: CLabel -> Map CLabel Int -> [CLabel] ->
FuelMonad (Maybe CmmTopZ, C_SRT)
procpointSRT _ _ [] =
return (Nothing, NoC_SRT)
do (top, srt) <- bitmap `seq` to_SRT top_srt offset len bitmap
return (top, srt)
where
- ints = map (expectJust "constructSRT" . lookupFM top_table) entries
+ ints = map (expectJust "constructSRT" . flip Map.lookup top_table) entries
sorted_ints = sortLe (<=) ints
offset = head sorted_ints
bitmap_entries = map (subtract offset) sorted_ints
-- 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)] -> FiniteMap CLabel CAFSet
-mkTopCAFInfo localCAFs = foldl addToTop emptyFM g
+mkTopCAFInfo :: [(CLabel, CAFSet)] -> Map CLabel CAFSet
+mkTopCAFInfo localCAFs = foldl addToTop Map.empty g
where addToTop env (AcyclicSCC (l, cafset)) =
- addToFM env l (flatten env cafset)
+ Map.insert l (flatten env cafset) env
addToTop env (CyclicSCC nodes) =
let (lbls, cafsets) = unzip nodes
- cafset = foldl plusFM emptyFM cafsets `delListFromFM` lbls
- in foldl (\env l -> addToFM env l (flatten env cafset)) env lbls
- flatten env cafset = foldFM (lookup env) emptyFM cafset
+ cafset = lbls `Map.deleteList` foldl Map.union Map.empty cafsets
+ in foldl (\env l -> Map.insert l (flatten env cafset) env) env lbls
+ flatten env cafset = Map.foldRightWithKey (lookup env) Map.empty cafset
lookup env caf () cafset' =
- case lookupFM env caf of Just cafs -> foldFM add cafset' cafs
- Nothing -> add caf () cafset'
- add caf () cafset' = addToFM cafset' caf ()
+ case Map.lookup caf env of Just cafs -> Map.foldRightWithKey add cafset' cafs
+ Nothing -> add caf () cafset'
+ add caf () cafset' = Map.insert caf () cafset'
g = stronglyConnCompFromEdgedVertices
- (map (\n@(l, cafs) -> (n, l, keysFM cafs)) localCAFs)
+ (map (\n@(l, cafs) -> (n, l, Map.keys cafs)) localCAFs)
type StackLayout = [Maybe LocalReg]
-- until we stop splitting the graphs at procpoints in the native path
bundleCAFs cafEnv t@(FloatingInfoTable _ bid _) =
(expectJust "bundleCAFs " (lookupBlockEnv cafEnv bid), t)
-bundleCAFs _ t@(NoInfoTable _) = (emptyFM, t)
+bundleCAFs _ t@(NoInfoTable _) = (Map.empty, t)
-- Construct the SRTs for the given procedure.
-setInfoTableSRT :: FiniteMap CLabel CAFSet -> TopSRT -> (CAFSet, CmmTopForInfoTables) ->
+setInfoTableSRT :: Map CLabel CAFSet -> TopSRT -> (CAFSet, CmmTopForInfoTables) ->
FuelMonad (TopSRT, [CmmTopForInfoTables])
setInfoTableSRT topCAFMap topSRT (cafs, t@(ProcInfoTable _ procpoints)) =
case blockSetToList procpoints of
setSRT cafs topCAFMap topSRT t
setInfoTableSRT _ topSRT (_, t@(NoInfoTable _)) = return (topSRT, [t])
-setSRT :: CAFSet -> FiniteMap CLabel CAFSet -> TopSRT ->
+setSRT :: CAFSet -> Map CLabel CAFSet -> TopSRT ->
CmmTopForInfoTables -> FuelMonad (TopSRT, [CmmTopForInfoTables])
setSRT cafs topCAFMap topSRT t =
do (topSRT, cafTable, srt) <- buildSRTs topSRT topCAFMap cafs
l = case last of LastOther l -> l
LastExit -> panic "extendEnvs lastExit"
tail _ z (ZFirst _) = z
- tail fact env (ZHead h m@(MidForeignCall (Safe bid _) _ _ _)) =
+ tail fact env (ZHead h m@(MidForeignCall (Safe bid _ _) _ _ _)) =
tail (mid m fact) (extendBlockEnv env bid fact) h
tail fact env (ZHead h m) = tail (mid m fact) env h
lookup map k = expectJust "extendEnvWithSafeFCalls" $ lookupBlockEnv map k
LastExit -> panic "extendEnvs lastExit"
tail _ z (ZFirst _) = z
tail lives@(cafs, slots) (cafEnv, slotEnv)
- (ZHead h m@(MidForeignCall (Safe bid _) _ _ _)) =
+ (ZHead h m@(MidForeignCall (Safe bid _ _) _ _ _)) =
let slots' = removeLiveSlotDefs slots m
slotEnv' = extendBlockEnv slotEnv bid slots'
cafEnv' = extendBlockEnv cafEnv bid cafs
-- Check for foreign calls -- if none, then we can avoid copying the block.
hasSafeForeignCall :: CmmBlock -> Bool
hasSafeForeignCall (Block _ t) = tail t
- where tail (ZTail (MidForeignCall (Safe _ _) _ _ _) _) = True
+ where tail (ZTail (MidForeignCall (Safe _ _ _) _ _ _) _) = True
tail (ZTail _ t) = tail t
tail (ZLast _) = False
tail s b@(ZBlock (ZFirst _) _) =
do state <- s
return $ state { s_blocks = insertBlock (G.zip b) (s_blocks state) }
- tail s (ZBlock (ZHead h m@(MidForeignCall (Safe bid updfr_off) _ _ _)) t) =
+ tail s (ZBlock (ZHead h m@(MidForeignCall (Safe bid updfr_off _) _ _ _)) t) =
do state <- s
let state' = state
{ s_safeCalls = FloatingInfoTable emptyContInfoTable bid updfr_off :
-- to lower a safe foreign call to a sequence of unsafe calls.
lowerSafeForeignCall ::
SafeState -> Middle -> ZTail Middle Last -> FuelMonad (SafeState, ZTail Middle Last)
-lowerSafeForeignCall state m@(MidForeignCall (Safe infotable _) _ _ _) tail = do
+lowerSafeForeignCall state m@(MidForeignCall (Safe infotable _ interruptible) _ _ _) tail = do
let newTemp rep = getUniqueM >>= \u -> return (LocalReg u rep)
-- Both 'id' and 'new_base' are KindNonPtr because they're
-- RTS-only objects and are not subject to garbage collection
saveThreadState <*>
caller_save <*>
mkUnsafeCall (ForeignTarget suspendThread
- (ForeignConvention CCallConv [AddrHint] [AddrHint]))
- [id] [CmmReg (CmmGlobal BaseReg)]
+ (ForeignConvention CCallConv [AddrHint, NoHint] [AddrHint]))
+ -- XXX Not sure if the size of the CmmInt is correct
+ [id] [CmmReg (CmmGlobal BaseReg), CmmLit (CmmInt (fromIntegral (fromEnum interruptible)) wordWidth)]
resume = mkUnsafeCall (ForeignTarget resumeThread
(ForeignConvention CCallConv [AddrHint] [AddrHint]))
[new_base] [CmmReg (CmmLocal id)] <*>