module BlockId
   ( BlockId(..), mkBlockId     -- ToDo: BlockId should be abstract, but it isn't yet
-  , BlockEnv, emptyBlockEnv, lookupBlockEnv, extendBlockEnv, mkBlockEnv, mapBlockEnv
-  , BlockSet, emptyBlockSet, elemBlockSet, extendBlockSet, sizeBlockSet, mkBlockSet
-  , foldBlockEnv, blockLbl, infoTblLbl
+  , BlockEnv, emptyBlockEnv, elemBlockEnv, lookupBlockEnv, extendBlockEnv
+  , mkBlockEnv, mapBlockEnv
+  , eltsBlockEnv, plusBlockEnv, delFromBlockEnv, blockEnvToList, lookupWithDefaultBEnv
+  , isNullBEnv, sizeBEnv, foldBlockEnv, foldBlockEnv', addToBEnv_Acc
+  , BlockSet, emptyBlockSet, unitBlockSet, isEmptyBlockSet
+  , elemBlockSet, extendBlockSet, sizeBlockSet, unionBlockSets
+  , removeBlockSet, mkBlockSet, blockSetToList, foldBlockSet
+  , blockLbl, infoTblLbl, retPtLbl
   ) where
 
 import CLabel
 import IdInfo
+import Maybes
 import Name
 import Outputable
 import UniqFM
 Although a 'BlockId' is a local label, for reasons of implementation,
 'BlockId's must be unique within an entire compilation unit.  The reason
 is that each local label is mapped to an assembly-language label, and in
-most assembly languages allow, a label is visible throughout the enitre
+most assembly languages allow, a label is visible throughout the entire
 compilation unit in which it appears.
 -}
 
-newtype BlockId = BlockId Unique
+data BlockId = BlockId Unique
   deriving (Eq,Ord)
 
 instance Uniquable BlockId where
-  getUnique (BlockId u) = u
+  getUnique (BlockId id) = id
 
 mkBlockId :: Unique -> BlockId
 mkBlockId uniq = BlockId uniq
   show (BlockId u) = show u
 
 instance Outputable BlockId where
-  ppr = ppr . getUnique
+  ppr (BlockId id) = ppr id
+
+retPtLbl :: BlockId -> CLabel
+retPtLbl (BlockId id) = mkReturnPtLabel id
 
 blockLbl :: BlockId -> CLabel
-blockLbl id = mkEntryLabel (mkFCallName (getUnique id) "block") NoCafRefs
+blockLbl (BlockId id) = mkEntryLabel (mkFCallName id "block") NoCafRefs
 
 infoTblLbl :: BlockId -> CLabel
-infoTblLbl id = mkInfoTableLabel (mkFCallName (getUnique id) "block") NoCafRefs
+infoTblLbl (BlockId id) = mkInfoTableLabel (mkFCallName id "block") NoCafRefs
+
+-- Block environments: Id blocks
+newtype BlockEnv a = BlockEnv (UniqFM {- id -} a)
 
-type BlockEnv a = UniqFM {- BlockId -} a
+instance Outputable a => Outputable (BlockEnv a) where
+  ppr (BlockEnv env) = ppr env
+
+-- This is pretty horrid. There must be common patterns here that can be
+-- abstracted into wrappers.
 emptyBlockEnv :: BlockEnv a
-emptyBlockEnv = emptyUFM
+emptyBlockEnv = BlockEnv emptyUFM
+
+isNullBEnv :: BlockEnv a -> Bool
+isNullBEnv (BlockEnv env) = isNullUFM env
+
+sizeBEnv :: BlockEnv a -> Int
+sizeBEnv (BlockEnv env)  = sizeUFM env
+
 mkBlockEnv :: [(BlockId,a)] -> BlockEnv a
-mkBlockEnv = listToUFM
+mkBlockEnv = foldl (uncurry . extendBlockEnv) emptyBlockEnv
+
+eltsBlockEnv :: BlockEnv elt -> [elt]
+eltsBlockEnv (BlockEnv env) = eltsUFM env
+
+delFromBlockEnv        :: BlockEnv elt -> BlockId -> BlockEnv elt
+delFromBlockEnv          (BlockEnv env) (BlockId id) = BlockEnv (delFromUFM env id)
+
 lookupBlockEnv :: BlockEnv a -> BlockId -> Maybe a
-lookupBlockEnv = lookupUFM
+lookupBlockEnv (BlockEnv env) (BlockId id) = lookupUFM env id
+
+elemBlockEnv :: BlockEnv a -> BlockId -> Bool
+elemBlockEnv (BlockEnv env) (BlockId id) = isJust $ lookupUFM env id
+
+lookupWithDefaultBEnv :: BlockEnv a -> a -> BlockId -> a
+lookupWithDefaultBEnv env x id = lookupBlockEnv env id `orElse` x
+
 extendBlockEnv :: BlockEnv a -> BlockId -> a -> BlockEnv a
-extendBlockEnv = addToUFM
+extendBlockEnv (BlockEnv env) (BlockId id) x = BlockEnv (addToUFM env id x)
+
 mapBlockEnv :: (a -> b) -> BlockEnv a -> BlockEnv b
-mapBlockEnv = mapUFM
+mapBlockEnv f (BlockEnv env) = BlockEnv (mapUFM f env)
+
 foldBlockEnv :: (BlockId -> a -> b -> b) -> b -> BlockEnv a -> b
-foldBlockEnv f = foldUFM_Directly (\u x y -> f (mkBlockId u) x y)
+foldBlockEnv f b (BlockEnv env) = 
+  foldUFM_Directly (\u x y -> f (mkBlockId u) x y) b env
+
+foldBlockEnv' :: (a -> b -> b) -> b -> BlockEnv a -> b
+foldBlockEnv' f b (BlockEnv env) = foldUFM f b env
+
+plusBlockEnv :: BlockEnv elt -> BlockEnv elt -> BlockEnv elt
+plusBlockEnv (BlockEnv x) (BlockEnv y) = BlockEnv (plusUFM x y)
+
+blockEnvToList :: BlockEnv elt -> [(BlockId, elt)]
+blockEnvToList (BlockEnv env) =
+  map (\ (id, elt) -> (BlockId id, elt)) $ ufmToList env
+
+addToBEnv_Acc  :: (elt -> elts -> elts)        -- Add to existing
+                          -> (elt -> elts)             -- New element
+                          -> BlockEnv elts             -- old
+                          -> BlockId -> elt            -- new
+                          -> BlockEnv elts             -- result
+addToBEnv_Acc add new (BlockEnv old) (BlockId k) v =
+  BlockEnv (addToUFM_Acc add new old k v)
+  -- I believe this is only used by obsolete code.
+
+
+newtype BlockSet = BlockSet (UniqSet Unique)
+instance Outputable BlockSet where
+  ppr (BlockSet set) = ppr set
+
 
-type BlockSet = UniqSet BlockId
 emptyBlockSet :: BlockSet
-emptyBlockSet = emptyUniqSet
+emptyBlockSet = BlockSet emptyUniqSet
+
+isEmptyBlockSet :: BlockSet -> Bool
+isEmptyBlockSet (BlockSet s) = isEmptyUniqSet s
+
+unitBlockSet :: BlockId -> BlockSet
+unitBlockSet = extendBlockSet emptyBlockSet
+
 elemBlockSet :: BlockId -> BlockSet -> Bool
-elemBlockSet = elementOfUniqSet
+elemBlockSet (BlockId id) (BlockSet set) = elementOfUniqSet id set
+
 extendBlockSet :: BlockSet -> BlockId -> BlockSet
-extendBlockSet = addOneToUniqSet
+extendBlockSet (BlockSet set) (BlockId id) = BlockSet (addOneToUniqSet set id)
+
+removeBlockSet :: BlockSet -> BlockId -> BlockSet
+removeBlockSet (BlockSet set) (BlockId id) = BlockSet (delOneFromUniqSet set id)
+
 mkBlockSet :: [BlockId] -> BlockSet
-mkBlockSet = mkUniqSet
+mkBlockSet = foldl extendBlockSet emptyBlockSet
+
+unionBlockSets :: BlockSet -> BlockSet -> BlockSet
+unionBlockSets (BlockSet s) (BlockSet s') = BlockSet (unionUniqSets s s')
+
 sizeBlockSet :: BlockSet -> Int
-sizeBlockSet = sizeUniqSet
+sizeBlockSet (BlockSet set) = sizeUniqSet set
+
+blockSetToList :: BlockSet -> [BlockId]
+blockSetToList (BlockSet set) = map BlockId $ uniqSetToList set
+
+foldBlockSet :: (BlockId -> b -> b) -> b -> BlockSet -> b
+foldBlockSet f z (BlockSet set) = foldUniqSet (f . BlockId) z set
 
         mkHpcModuleNameLabel,
 
         hasCAF,
-       infoLblToEntryLbl, entryLblToInfoLbl,
+       infoLblToEntryLbl, entryLblToInfoLbl, cvtToClosureLbl, cvtToSRTLbl,
        needsCDecl, isAsmTemp, maybeAsmTemp, externallyVisibleCLabel,
         isMathFun,
        isCFunctionLabel, isGcPtrLabel, labelDynamic,
 entryLblToInfoLbl (RtsLabel (RtsRetFS s)) = RtsLabel (RtsRetInfoFS s)
 entryLblToInfoLbl l = pprPanic "CLabel.entryLblToInfoLbl" (pprCLabel l)
 
+cvtToClosureLbl   (IdLabel n c InfoTable) = IdLabel n c Closure
+cvtToClosureLbl   (IdLabel n c Entry)     = IdLabel n c Closure
+cvtToClosureLbl   (IdLabel n c ConEntry)  = IdLabel n c Closure
+cvtToClosureLbl l@(IdLabel n c Closure)   = l
+cvtToClosureLbl l = pprPanic "cvtToClosureLbl" (pprCLabel l)
+
+cvtToSRTLbl   (IdLabel n c InfoTable) = mkSRTLabel n c
+cvtToSRTLbl   (IdLabel n c Entry)     = mkSRTLabel n c
+cvtToSRTLbl   (IdLabel n c ConEntry)  = mkSRTLabel n c
+cvtToSRTLbl l@(IdLabel n c Closure)   = mkSRTLabel n c
+cvtToSRTLbl l = pprPanic "cvtToSRTLbl" (pprCLabel l)
+
 -- -----------------------------------------------------------------------------
 -- Does a CLabel refer to a CAF?
 hasCAF :: CLabel -> Bool
-hasCAF (IdLabel _ MayHaveCafRefs Closure) = True
-hasCAF _                                  = False
+hasCAF (IdLabel _ MayHaveCafRefs _) = True
+hasCAF _                            = False
 
 -- -----------------------------------------------------------------------------
 -- Does a CLabel need declaring before use or not?
 pprCLbl (ForeignLabel str _ _)
   = ftext str
 
-pprCLbl (IdLabel name _ flavor) = ppr name <> ppIdFlavor flavor
+pprCLbl (IdLabel name cafs flavor) = ppr name <> ppIdFlavor flavor
 
 pprCLbl (CC_Label cc)          = ppr cc
 pprCLbl (CCS_Label ccs)        = ppr ccs
 
         cmmMapGraph, cmmTopMapGraph,
         cmmMapGraphM, cmmTopMapGraphM,
         CmmInfo(..), UpdateFrame(..),
-        CmmInfoTable(..), ClosureTypeInfo(..), ProfilingInfo(..), ClosureTypeTag,
+        CmmInfoTable(..), HasStaticClosure, ClosureTypeInfo(..), ConstrDescription,
+        ProfilingInfo(..), ClosureTypeTag,
         GenBasicBlock(..), CmmBasicBlock, blockId, blockStmts, mapBlockStmts,
         CmmReturnInfo(..),
         CmmStmt(..), CmmActual, CmmActuals, CmmFormal, CmmFormals, 
 cmmTopMapGraph _ (CmmData s ds)       = CmmData s ds
 
 cmmMapGraphM f (Cmm tops) = mapM (cmmTopMapGraphM f) tops >>= return . Cmm
-cmmTopMapGraphM f (CmmProc h l args g) = f (showSDoc $ ppr l) g >>= return . CmmProc h l args
+cmmTopMapGraphM f (CmmProc h l args g) =
+  f (showSDoc $ ppr l) g >>= return . CmmProc h l args
 cmmTopMapGraphM _ (CmmData s ds)       = return $ CmmData s ds
 
 -----------------------------------------------------------------------------
 data CmmInfo
   = CmmInfo
       (Maybe BlockId)     -- GC target. Nothing <=> CPS won't do stack check
+                          -- JD: NOT USED BY NEW CODE GEN
       (Maybe UpdateFrame) -- Update frame
       CmmInfoTable        -- Info table
 
 -- Info table as a haskell data type
 data CmmInfoTable
   = CmmInfoTable
+      HasStaticClosure
       ProfilingInfo
       ClosureTypeTag -- Int
       ClosureTypeInfo
   | CmmNonInfoTable   -- Procedure doesn't need an info table
 
+type HasStaticClosure = Bool
+
 -- TODO: The GC target shouldn't really be part of CmmInfo
 -- as it doesn't appear in the resulting info table.
 -- It should be factored out.
 
 -----------------------------------------------------------------------------
 -- | Build a mapping so we can lookup a 'BrokenBlock' by its 'BlockId'
 blocksToBlockEnv :: [BrokenBlock] -> BlockEnv BrokenBlock
-blocksToBlockEnv blocks = listToUFM $ map (\b -> (brokenBlockId b, b)) blocks
+blocksToBlockEnv blocks = mkBlockEnv $ map (\b -> (brokenBlockId b, b)) blocks
 
                 new_targets
                 (map (:[]) targets)
     where
-      blocks' = map (lookupWithDefaultUFM blocks (panic "TODO")) new_blocks
+      blocks' = map (lookupWithDefaultBEnv blocks (panic "TODO")) new_blocks
       targets =
         -- Note the subtlety that since the extra branch after a call
         -- will always be to a block that is a proc-point,
   Continuation info_table clabel params is_gc_cont body
     where
       children = (collectNonProcPointTargets proc_points blocks (unitUniqSet start) [start]) `minusUniqSet` (unitUniqSet start)
-      start_block = lookupWithDefaultUFM blocks unknown_block start
-      children_blocks = map (lookupWithDefaultUFM blocks unknown_block) (uniqSetToList children)
+      start_block = lookupWithDefaultBEnv blocks unknown_block start
+      children_blocks = map (lookupWithDefaultBEnv blocks unknown_block) (uniqSetToList children)
       unknown_block = panic "unknown block in gatherBlocksIntoContinuation"
       body = start_block : children_blocks
 
                  ContinuationEntry args _ _ -> args
                  ControlEntry ->
                      uniqSetToList $
-                     lookupWithDefaultUFM live unknown_block start
+                     lookupWithDefaultBEnv live unknown_block start
                      -- it's a proc-point, pass lives in parameter registers
 
 --------------------------------------------------------------------------------
     where
       -- User written continuations
       selectContinuationFormat' (Continuation
-                          (Right (CmmInfo _ _ (CmmInfoTable _ _ (ContInfo format srt))))
+                          (Right (CmmInfo _ _ (CmmInfoTable _ _ _ (ContInfo format srt))))
                           label formals _ _) =
           (formals, Just label, format)
       -- Either user written non-continuation code
           in (formals,
               Just label,
               map Just $ uniqSetToList $
-              lookupWithDefaultUFM live unknown_block ident)
+              lookupWithDefaultBEnv live unknown_block ident)
 
       unknown_block = panic "unknown BlockId in selectContinuationFormat"
 
                  -> Continuation CmmInfo
 
 -- User written continuations
-applyContinuationFormat formats (Continuation
-                          (Right (CmmInfo gc update_frame (CmmInfoTable prof tag (ContInfo _ srt))))
-                          label formals is_gc blocks) =
-    Continuation (CmmInfo gc update_frame (CmmInfoTable prof tag (ContInfo format srt)))
+applyContinuationFormat formats
+   (Continuation (Right (CmmInfo gc update_frame
+                             (CmmInfoTable clos prof tag (ContInfo _ srt))))
+                 label formals is_gc blocks) =
+    Continuation (CmmInfo gc update_frame (CmmInfoTable clos prof tag (ContInfo format srt)))
                  label formals is_gc blocks
     where
       format = continuation_stack $ maybe unknown_block id $ lookup label formats
 -- CPS generated continuations
 applyContinuationFormat formats (Continuation
                           (Left srt) label formals is_gc blocks) =
-    Continuation (CmmInfo gc Nothing (CmmInfoTable prof tag (ContInfo (continuation_stack $ format) srt)))
+    Continuation (CmmInfo gc Nothing (CmmInfoTable undefined prof tag (ContInfo (continuation_stack $ format) srt)))
                  label formals is_gc blocks
     where
       gc = Nothing -- Generated continuations never need a stack check
 
   protoCmmCPSZ
 ) where
 
+import CLabel
 import Cmm
+import CmmBuildInfoTables
 import CmmCommonBlockElimZ
 import CmmProcPointZ
 import CmmSpillReload
+import CmmStackLayout
 import DFMonad
 import PprCmmZ()
 import ZipCfgCmmRep
 
 import DynFlags
 import ErrUtils
+import FiniteMap
 import HscTypes
+import Maybe
 import Monad
 import Outputable
+import StaticFlags
 
 -----------------------------------------------------------------------------
 -- |Top level driver for the CPS pass
 -----------------------------------------------------------------------------
+-- 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.
 protoCmmCPSZ :: HscEnv -- Compilation env including
                        -- dynamic flags: -dcmm-lint -ddump-cps-cmm
-             -> CmmZ     -- Input C-- with Proceedures
-             -> IO CmmZ  -- Output CPS transformed C--
-protoCmmCPSZ hsc_env (Cmm tops)
+             -> (TopSRT, [CmmZ])  -- SRT table and 
+             -> CmmZ              -- Input C-- with Procedures
+             -> IO (TopSRT, [CmmZ]) -- Output CPS transformed C--
+protoCmmCPSZ hsc_env (topSRT, rst) (Cmm tops)
   | not (dopt Opt_RunCPSZ (hsc_dflags hsc_env))
-  = return (Cmm tops)                -- Only if -frun-cps
+  = return (topSRT, Cmm tops : rst)                -- Only if -frun-cps
   | otherwise
   = do let dflags = hsc_dflags hsc_env
         showPass dflags "CPSZ"
-        tops <- liftM concat $ mapM (cpsTop hsc_env) tops
-        dumpIfSet_dyn dflags Opt_D_dump_cps_cmm "Post CPS Cmm" (ppr (Cmm tops))
-        return $ Cmm tops
+        (cafEnvs, toTops) <- liftM unzip $ mapM (cpsTop hsc_env) tops
+        let topCAFEnv = mkTopCAFInfo (concat cafEnvs)
+        (topSRT, tops) <- foldM (\ z f -> f topCAFEnv z) (topSRT, []) toTops 
+        let cmms = Cmm (reverse (concat tops))
+        dumpIfSet_dyn dflags Opt_D_dump_cps_cmm "Post CPS Cmm" (ppr cmms)
+        return (topSRT, cmms : rst)
 
 {- [Note global fuel]
 ~~~~~~~~~~~~~~~~~~~~~
 global to one compiler session.
 -}
 
-cpsTop :: HscEnv -> CmmTopZ -> IO [CmmTopZ]
-cpsTop _ p@(CmmData {}) = return [p]
+cpsTop :: HscEnv -> CmmTopZ ->
+          IO ([(CLabel, CAFSet)],
+              (FiniteMap CLabel CAFSet -> (TopSRT, [[CmmTopZ]]) -> IO (TopSRT, [[CmmTopZ]])))
+cpsTop _ p@(CmmData {}) =
+  return ([], (\ _ (topSRT, tops) -> return (topSRT, [p] : tops)))
 cpsTop hsc_env (CmmProc h l args g) =
-    do dump Opt_D_dump_cmmz "Pre Proc Points Added"  g
+    do 
+       dump Opt_D_dump_cmmz "Pre Proc Points Added"  g
        let callPPs = callProcPoints g
        g <- dual_rewrite Opt_D_dump_cmmz "spills and reloads"
                              (dualLivenessWithInsertion callPPs) g
+       g <- dual_rewrite Opt_D_dump_cmmz "Dead Assignment Elimination"
+                         (removeDeadAssignmentsAndReloads callPPs) g
        dump Opt_D_dump_cmmz "Pre common block elimination" g
        g <- return $ elimCommonBlocks g
        dump Opt_D_dump_cmmz "Post common block elimination" g
        procPoints <- run $ minimalProcPointSet callPPs g
-       print $ "call procPoints: " ++ (showSDoc $ ppr procPoints)
+       -- print $ "call procPoints: " ++ (showSDoc $ ppr procPoints)
        g <- run $ addProcPointProtocols callPPs procPoints g
        dump Opt_D_dump_cmmz "Post Proc Points Added" g
        g     <- dual_rewrite Opt_D_dump_cmmz "spills and reloads"
                              (dualLivenessWithInsertion procPoints) g
                     -- Insert spills at defns; reloads at return points
-       g     <- run $ insertLateReloads' g -- Duplicate reloads just before uses
+       g     <- run $ insertLateReloads g -- Duplicate reloads just before uses
        dump Opt_D_dump_cmmz "Post late reloads" g
        g     <- dual_rewrite Opt_D_dump_cmmz "Dead Assignment Elimination"
                                         (removeDeadAssignmentsAndReloads procPoints) g
                     -- Remove redundant reloads (and any other redundant asst)
+       -- Debugging: stubbing slots on death can cause crashes early
+       g <-  if opt_StubDeadValues then run $ stubSlotsOnDeath g else return g
+       mbpprTrace "graph before procPointMap: " (ppr g) $ return ()
+       procPointMap <- run $ procPointAnalysis procPoints g
        slotEnv <- run $ liveSlotAnal g
-       print $ "live slot analysis results: " ++ (showSDoc $ ppr slotEnv)
+       mbpprTrace "live slot analysis results: " (ppr slotEnv) $ return ()
        cafEnv <- run $ cafAnal g
-       print $ "live CAF analysis results: " ++ (showSDoc $ ppr cafEnv)
-       slotIGraph <- return $ igraph areaBuilder slotEnv g
-       print $ "slot IGraph: " ++ (showSDoc $ ppr slotIGraph)
-       print $ "graph before procPointMap: " ++ (showSDoc $ ppr g)
-       procPointMap <- run $ procPointAnalysis procPoints g
+       (cafEnv, slotEnv) <- return $ extendEnvsForSafeForeignCalls cafEnv slotEnv g
+       mbpprTrace "slotEnv extended for safe foreign calls: " (ppr slotEnv) $ return ()
        let areaMap = layout procPoints slotEnv g
+       mbpprTrace "areaMap" (ppr areaMap) $ return ()
        g  <- run $ manifestSP procPoints procPointMap areaMap g
-       procPointMap <- run $ procPointAnalysis procPoints g
-       gs <- run $ splitAtProcPoints l callPPs procPoints procPointMap slotEnv areaMap
-                                     (CmmProc h l args g)
-       return gs
-       --return $ [CmmProc h l args (runTx cmmCfgOptsZ g)]
+       dump Opt_D_dump_cmmz "after manifestSP" g
+       -- UGH... manifestSP can require updates to the procPointMap.
+       -- We can probably do something quicker here for the update...
+       procPointMap  <- run $ procPointAnalysis procPoints g
+       gs <- pprTrace "procPointMap" (ppr procPointMap) $
+               run $ splitAtProcPoints l callPPs procPoints procPointMap areaMap
+                                       (CmmProc h l args g)
+       mapM (dump Opt_D_dump_cmmz "after splitting") gs
+       let localCAFs = catMaybes $ map (localCAFInfo cafEnv) gs
+       mbpprTrace "localCAFs" (ppr localCAFs) $ return ()
+       gs <- liftM concat $ run $ foldM (lowerSafeForeignCalls procPoints) [] gs
+       mapM (dump Opt_D_dump_cmmz "after lowerSafeForeignCalls") gs
+
+       -- NO MORE GRAPH TRANSFORMATION AFTER HERE -- JUST MAKING INFOTABLES
+       let gs' = map (setInfoTableStackMap slotEnv areaMap) gs
+       mapM (dump Opt_D_dump_cmmz "after setInfoTableStackMap") gs'
+       -- Return: (a) CAFs used by this proc (b) a closure that will compute
+       --  a new SRT for the procedure.
+       let toTops topCAFEnv (topSRT, tops) =
+             do let setSRT (topSRT, rst) g =
+                      do (topSRT, gs) <- setInfoTableSRT cafEnv topCAFEnv topSRT g
+                         return (topSRT, gs : rst)
+                (topSRT, gs') <- run $ foldM setSRT (topSRT, []) gs'
+                gs' <- mapM finishInfoTables (concat gs')
+                pprTrace "localCAFs" (ppr localCAFs <+> ppr topSRT) $
+                  return (topSRT, concat gs' : tops)
+       return (localCAFs, toTops)
   where dflags = hsc_dflags hsc_env
+        mbpprTrace x y z = if dopt Opt_D_dump_cmmz dflags then pprTrace x y z else z
         dump f txt g = dumpIfSet_dyn dflags f txt (ppr g)
         run = runFuelIO (hsc_OptFuel hsc_env)
         dual_rewrite flag txt pass g =
 
 
 import Cmm
 import SMRep
+import ZipCfgCmmRep (Convention(..))
 
 import Constants
 import StaticFlags (opt_Unregisterised)
   = RegisterParam GlobalReg
   | StackParam a
 
+instance (Outputable a) => Outputable (ParamLocation a) where
+  ppr (RegisterParam g) = ppr g
+  ppr (StackParam p)    = ppr p
+
 type ArgumentFormat a b = [(a, ParamLocation b)]
 
 -- Stack parameters are returned as word offsets.
 assignArguments :: (a -> CmmType) -> [a] -> ArgumentFormat a WordOff
 assignArguments f reps = assignments
     where
+      availRegs = getRegs False
       (sizes, assignments) = unzip $ assignArguments' reps (negate (sum sizes)) availRegs
       assignArguments' [] offset availRegs = []
       assignArguments' (r:rs) offset availRegs =
           (size,(r,assignment)):assignArguments' rs new_offset remaining
           where 
             (assignment, new_offset, size, remaining) =
-                assign_reg False assign_slot_up (f r) offset availRegs
+                assign_reg assign_slot_neg (f r) offset availRegs
 
 -- | JD: For the new stack story, I want arguments passed on the stack to manifest as
 -- positive offsets in a CallArea, not negative offsets from the stack pointer.
 -- Also, I want byte offsets, not word offsets.
 -- The first argument tells us whether we are assigning positions for call arguments
--- or return results. The distinction matters because we reserve different
--- global registers in each case.
-assignArgumentsPos :: Bool -> (a -> CmmType) -> [a] -> ArgumentFormat a ByteOff
-assignArgumentsPos isCall arg_ty reps = map cvt assignments
+-- or return results. The distinction matters because some conventions use different
+-- global registers in each case. In particular, the native calling convention
+-- uses the `node' register to pass the closure environment.
+assignArgumentsPos :: (Outputable a) => Convention -> Bool -> (a -> CmmType) -> [a] ->
+                      ArgumentFormat a ByteOff
+assignArgumentsPos conv isCall arg_ty reps = map cvt assignments
     where
-      (sizes, assignments) = unzip $ assignArguments' reps 0 availRegs
+      regs = case conv of Native -> getRegs isCall
+                          GC     -> getRegs False
+                          PrimOp -> noStack
+                          Slow   -> noRegs
+                          _      -> panic "unrecognized calling convention"
+      (sizes, assignments) = unzip $ assignArguments' reps (sum sizes) regs
       assignArguments' [] _ _ = []
       assignArguments' (r:rs) offset avails =
-          (size,(r,assignment)):assignArguments' rs new_offset remaining
+          (size, (r,assignment)):assignArguments' rs new_offset remaining
           where 
             (assignment, new_offset, size, remaining) =
-                assign_reg isCall assign_slot_down (arg_ty r) offset avails
+                assign_reg assign_slot_pos (arg_ty r) offset avails
       cvt (l, RegisterParam r) = (l, RegisterParam r)
       cvt (l, StackParam off)  = (l, StackParam $ off * wORD_SIZE)
 
 useLongRegs    | opt_Unregisterised = 0
               | otherwise          = mAX_Real_Long_REG
 
-availRegs = (regList VanillaReg useVanillaRegs,
-             regList FloatReg useFloatRegs,
-             regList DoubleReg useDoubleRegs,
-             regList LongReg useLongRegs)
+getRegs reserveNode =
+  (if reserveNode then filter (\r -> r VGcPtr /= node) intRegs else intRegs,
+   regList FloatReg  useFloatRegs,
+   regList DoubleReg useDoubleRegs,
+   regList LongReg   useLongRegs)
     where
       regList f max = map f [1 .. max]
+      intRegs = regList VanillaReg useVanillaRegs
+
+noStack = (map VanillaReg any, map FloatReg any, map DoubleReg any, map LongReg any)
+  where any = [1 .. ]
+noRegs    = ([], [], [], [])
 
 -- Round the size of a local register up to the nearest word.
 slot_size :: LocalReg -> Int
 type Assignment = (ParamLocation WordOff, WordOff, WordOff, AvailRegs)
 type SlotAssigner = Width -> Int -> AvailRegs -> Assignment
 
-assign_reg :: Bool -> SlotAssigner -> CmmType -> WordOff -> AvailRegs -> Assignment
-assign_reg isCall slot ty off avails
-  | isFloatType ty = assign_float_reg        slot width off avails
-  | otherwise      = assign_bits_reg  isCall slot width off gcp avails
+assign_reg :: SlotAssigner -> CmmType -> WordOff -> AvailRegs -> Assignment
+assign_reg slot ty off avails
+  | isFloatType ty = assign_float_reg slot width off avails
+  | otherwise      = assign_bits_reg  slot width off gcp avails
   where
     width = typeWidth ty
     gcp | isGcPtrType ty = VGcPtr
        | otherwise      = VNonGcPtr
 
--- Assigning a slot on a stack that grows up:
+-- Assigning a slot using negative offsets from the stack pointer.
 -- JD: I don't know why this convention stops using all the registers
 --     after running out of one class of registers.
-assign_slot_up :: SlotAssigner
-assign_slot_up width off regs =
+assign_slot_neg :: SlotAssigner
+assign_slot_neg width off regs =
   (StackParam $ off, off + size, size, ([], [], [], [])) where size = slot_size' width
 
--- Assigning a slot on a stack that grows down:
-assign_slot_down :: SlotAssigner
-assign_slot_down width off regs =
-  (StackParam $ off + size, off + size, size, ([], [], [], []))
+-- Assigning a slot using positive offsets into a CallArea.
+assign_slot_pos :: SlotAssigner
+assign_slot_pos width off regs =
+  (StackParam $ off, off - size, size, ([], [], [], []))
   where size = slot_size' width
 
--- On calls, `node` is used to hold the closure that is entered, so we can't
--- pass arguments in that register.
-assign_bits_reg _ _ W128 _ _ _ = panic "I128 is not a supported register type"
-assign_bits_reg isCall assign_slot w off gcp regs@(v:vs, fs, ds, ls) =
-  if isCall && v gcp == node then
-    assign_bits_reg isCall assign_slot w off gcp (vs, fs, ds, ls)
-  else if widthInBits w <= widthInBits wordWidth then
+-- On calls in the native convention, `node` is used to hold the environment
+-- for the closure, so we can't pass arguments in that register.
+assign_bits_reg _ W128 _ _ _ = panic "W128 is not a supported register type"
+assign_bits_reg assign_slot w off gcp regs@(v:vs, fs, ds, ls) =
+  if widthInBits w <= widthInBits wordWidth then
     (RegisterParam (v gcp), off, 0, (vs, fs, ds, ls))
   else assign_slot w off regs
+assign_bits_reg assign_slot w off gcp regs@([], _, _, _) =
+  assign_slot w off regs
 
 assign_float_reg _ W32 off (vs, f:fs, ds, ls) = (RegisterParam $ f, off, 0, (vs, fs, ds, ls))
 assign_float_reg _ W64 off (vs, fs, d:ds, ls) = (RegisterParam $ d, off, 0, (vs, fs, ds, ls))
 
 import ZipCfg
 import ZipCfgCmmRep
 
+import Data.Bits
+import Data.Word
 import FastString
-import FiniteMap
 import List hiding (iterate)
 import Monad
 import Outputable
 import Unique
 
 my_trace :: String -> SDoc -> a -> a
-my_trace = if True then pprTrace else \_ _ a -> a
+my_trace = if False then pprTrace else \_ _ a -> a
 
 -- Eliminate common blocks:
 -- If two blocks are identical except for the label on the first node,
 -- TODO: Use optimization fuel
 elimCommonBlocks :: CmmGraph -> CmmGraph
 elimCommonBlocks g =
-    upd_graph g . snd $ iterate common_block reset hashed_blocks (emptyUFM, emptyFM)
+    upd_graph g . snd $ iterate common_block reset hashed_blocks
+                                (emptyUFM, emptyBlockEnv)
       where hashed_blocks    = map (\b -> (hash_block b, b)) (reverse (postorder_dfs g))
             reset (_, subst) = (emptyUFM, subst)
 
   where upd' (b, s) a = let (b', s') = upd s a in (b || b', s') -- lift to track changes
 
 -- Try to find a block that is equal (or ``common'') to b.
-type BidMap = FiniteMap BlockId BlockId
+type BidMap = BlockEnv BlockId
 type State  = (UniqFM [CmmBlock], BidMap)
 common_block :: (Outputable h, Uniquable h) =>  State -> (h, CmmBlock) -> (Bool, State)
 common_block (bmap, subst) (hash, b) =
-  case lookupUFM bmap $ my_trace "common_block" (ppr bid <+> ppr subst <+> ppr hash) $ hash of
-    Just bs -> case (find (eqBlockBodyWith (eqBid subst) b) bs, lookupFM subst bid) of
+  case lookupUFM bmap hash of
+    Just bs -> case (find (eqBlockBodyWith (eqBid subst) b) bs,
+                     lookupBlockEnv subst bid) of
                  (Just b', Nothing)                      -> addSubst b'
                  (Just b', Just b'') | blockId b' /= b'' -> addSubst b'
                  _ -> (False, (addToUFM bmap hash (b : bs), subst))
     Nothing -> (False, (addToUFM bmap hash [b], subst))
   where bid = blockId b
         addSubst b' = my_trace "found new common block" (ppr (blockId b')) $
-                      (True, (bmap, addToFM subst bid (blockId b')))
+                      (True, (bmap, extendBlockEnv subst bid (blockId b')))
 
 -- Given the map ``subst'' from BlockId -> BlockId, we rewrite the graph.
 upd_graph :: CmmGraph -> BidMap -> CmmGraph
 upd_graph g subst = map_nodes id middle last g
-  where middle m = m
-        last (LastBranch bid)       = LastBranch $ sub bid
-        last (LastCondBranch p t f) = cond p (sub t) (sub f)
-        last (LastCall t bid s)     = LastCall   t (liftM sub bid) s
-        last (LastSwitch e bs)      = LastSwitch e $ map (liftM sub) bs
-        last l = l
+  where middle = mapExpDeepMiddle exp
+        last l = last' (mapExpDeepLast exp l)
+        last' (LastBranch bid)            = LastBranch $ sub bid
+        last' (LastCondBranch p t f)      = cond p (sub t) (sub f)
+        last' (LastCall t (Just bid) s u) = LastCall t (Just $ sub bid) s u
+        last' l@(LastCall _ Nothing _ _)  = l
+        last' (LastSwitch e bs)           = LastSwitch e $ map (liftM sub) bs
         cond p t f = if t == f then LastBranch t else LastCondBranch p t f
+        exp (CmmStackSlot (CallArea (Young id))       off) =
+             CmmStackSlot (CallArea (Young (sub id))) off
+        exp (CmmLit (CmmBlock id)) = CmmLit (CmmBlock (sub id))
+        exp e = e
         sub = lookupBid subst
 
 -- To speed up comparisons, we hash each basic block modulo labels.
 -- The hashing is a bit arbitrary (the numbers are completely arbitrary),
 -- but it should be fast and good enough.
 hash_block :: CmmBlock -> Int
-hash_block (Block _ _ t) = hash_tail t 0
-  where hash_mid   (MidComment (FastString u _ _ _ _)) = u
+hash_block (Block _ _ t) =
+  fromIntegral (hash_tail t (0 :: Word32) .&. (0x7fffffff :: Word32))
+  -- UniqFM doesn't like negative Ints
+  where hash_mid   (MidComment (FastString u _ _ _ _)) = cvt u
         hash_mid   (MidAssign r e) = hash_reg r + hash_e e
         hash_mid   (MidStore e e') = hash_e e + hash_e e'
-        hash_mid   (MidUnsafeCall t _ as) = hash_tgt t + hash_lst hash_e as
-        hash_mid   (MidAddToContext e es) = hash_e e + hash_lst hash_e es
+        hash_mid   (MidForeignCall _ t _ as) = hash_tgt t + hash_lst hash_e as
+        hash_reg :: CmmReg -> Word32
         hash_reg   (CmmLocal l) = hash_local l
         hash_reg   (CmmGlobal _)    = 19
         hash_local (LocalReg _ _) = 117
+        hash_e :: CmmExpr -> Word32
         hash_e (CmmLit l) = hash_lit l
         hash_e (CmmLoad e _) = 67 + hash_e e
         hash_e (CmmReg r) = hash_reg r
         hash_e (CmmMachOp _ es) = hash_lst hash_e es -- pessimal - no operator check
-        hash_e (CmmRegOff r i) = hash_reg r + i
+        hash_e (CmmRegOff r i) = hash_reg r + cvt i
         hash_e (CmmStackSlot _ _) = 13
+        hash_lit :: CmmLit -> Word32
         hash_lit (CmmInt i _) = fromInteger i
         hash_lit (CmmFloat r _) = truncate r
         hash_lit (CmmLabel _) = 119 -- ugh
-        hash_lit (CmmLabelOff _ i) = 199 + i
-        hash_lit (CmmLabelDiffOff _ _ i) = 299 + i
+        hash_lit (CmmLabelOff _ i) = cvt $ 199 + i
+        hash_lit (CmmLabelDiffOff _ _ i) = cvt $ 299 + i
+        hash_lit (CmmBlock id) = 191 -- ugh
+        hash_lit (CmmHighStackMark) = cvt 313
         hash_tgt (ForeignTarget e _) = hash_e e
         hash_tgt (PrimTarget _) = 31 -- lots of these
-        hash_lst f = foldl (\z x -> f x + z) (0::Int)
+        hash_lst f = foldl (\z x -> f x + z) (0::Word32)
         hash_last (LastBranch _) = 23 -- would be great to hash these properly
         hash_last (LastCondBranch p _ _) = hash_e p 
-        hash_last (LastReturn _) = 17 -- better ideas?
-        hash_last (LastJump e _) = hash_e e
-        hash_last (LastCall e _ _) = hash_e e
+        hash_last (LastCall e _ _ _) = hash_e e
         hash_last (LastSwitch e _) = hash_e e
-        hash_tail (ZLast LastExit) v = 29 + v * 2
-        hash_tail (ZLast (LastOther l)) v = hash_last l + (v * 2)
-        hash_tail (ZTail m t) v = hash_tail t (hash_mid m + (v * 2))
-
+        hash_tail (ZLast LastExit) v = 29 + v `shiftL` 1
+        hash_tail (ZLast (LastOther l)) v = hash_last l + (v `shiftL` 1)
+        hash_tail (ZTail m t) v = hash_tail t (hash_mid m + (v `shiftL` 1))
+        cvt = fromInteger . toInteger
 -- Utilities: equality and substitution on the graph.
 
 -- Given a map ``subst'' from BlockID -> BlockID, we define equality.
 eqBid :: BidMap -> BlockId -> BlockId -> Bool
 eqBid subst bid bid' = lookupBid subst bid == lookupBid subst bid'
 lookupBid :: BidMap -> BlockId -> BlockId
-lookupBid subst bid = case lookupFM subst bid of
+lookupBid subst bid = case lookupBlockEnv subst bid of
                         Just bid  -> lookupBid subst bid
                         Nothing -> bid
 
 -- Equality on the body of a block, modulo a function mapping block IDs to block IDs.
 eqBlockBodyWith :: (BlockId -> BlockId -> Bool) -> CmmBlock -> CmmBlock -> Bool
-eqBlockBodyWith eqBid (Block _ Nothing t) (Block _ Nothing t') = eqTailWith eqBid t t'
-eqBlockBodyWith _ _ _ = False
+eqBlockBodyWith eqBid (Block _ sinfo t) (Block _ sinfo' t') =
+  sinfo == sinfo' && eqTailWith eqBid t t'
 
 type CmmTail = ZTail Middle Last
 eqTailWith :: (BlockId -> BlockId -> Bool) -> CmmTail -> CmmTail -> Bool
 eqTailWith _ _ _ = False
 
 eqLastWith :: (BlockId -> BlockId -> Bool) -> Last -> Last -> Bool
-eqLastWith eqBid (LastBranch bid) (LastBranch bid') = eqBid bid bid'
-eqLastWith eqBid c@(LastCondBranch _ _ _) c'@(LastCondBranch _ _ _) =
-  eqBid (cml_true c) (cml_true c')  && eqBid (cml_false c) (cml_false c') 
-eqLastWith _ (LastReturn s) (LastReturn s') = s == s'
-eqLastWith _ (LastJump e s) (LastJump e' s') = e == e' && s == s'
-eqLastWith eqBid c@(LastCall _ _ s) c'@(LastCall _ _ s') =
-  cml_target c == cml_target c' && eqMaybeWith eqBid (cml_cont c) (cml_cont c') &&
-  s == s'
-eqLastWith eqBid (LastSwitch e bs) (LastSwitch e' bs') =
-  e == e' && eqLstWith (eqMaybeWith eqBid) bs bs'
+eqLastWith eqBid (LastBranch bid1) (LastBranch bid2) = eqBid bid1 bid2
+eqLastWith eqBid (LastCondBranch c1 t1 f1) (LastCondBranch c2 t2 f2) =
+  c1 == c2 && eqBid t1 t2 && eqBid f1 f2
+eqLastWith eqBid (LastCall t1 c1 s1 u1) (LastCall t2 c2 s2 u2) =
+  t1 == t2 && eqMaybeWith eqBid c1 c2 && s1 == s2 && u1 == u2
+eqLastWith eqBid (LastSwitch e1 bs1) (LastSwitch e2 bs2) =
+  e1 == e2 && eqLstWith (eqMaybeWith eqBid) bs1 bs2
 eqLastWith _ _ _ = False
 
 eqLstWith :: (a -> b -> Bool) -> [a] -> [b] -> Bool
 
 module CmmContFlowOpt
     ( runCmmOpts, cmmCfgOpts, cmmCfgOptsZ
     , branchChainElimZ, removeUnreachableBlocksZ, predMap
-    , replaceLabelsZ, runCmmContFlowOptsZs
+    , replaceLabelsZ, replaceBranches, runCmmContFlowOptsZs
     )
 where
 
 import Panic
 import Prelude hiding (unzip, zip)
 import Util
-import UniqFM
 
 ------------------------------------
 runCmmContFlowOptsZs :: [CmmZ] -> [CmmZ]
 cmmCfgOptsZ :: Tx CmmGraph
 
 cmmCfgOpts  = branchChainElim  -- boring, but will get more exciting later
-cmmCfgOptsZ = branchChainElimZ `seqTx` blockConcatZ `seqTx` removeUnreachableBlocksZ
+cmmCfgOptsZ g =
+    (branchChainElimZ `seqTx` blockConcatZ `seqTx` removeUnreachableBlocksZ) g
         -- Here branchChainElim can ultimately be replaced
         -- with a more exciting combination of optimisations
 
     (lone_branch_blocks, others) = partitionWith isLoneBranchZ (G.to_block_list g)
     env = mkClosureBlockEnvZ lone_branch_blocks
     self_branches =
-        let loop_to (id, _) =
-                if lookup id == id then
-                    Just (G.Block id Nothing (G.ZLast (G.mkBranchNode id)))
-                else
-                    Nothing
-        in  mapMaybe loop_to lone_branch_blocks
+      let loop_to (id, _) =
+            if lookup id == id then
+              Just (G.Block id emptyStackInfo (G.ZLast (G.mkBranchNode id)))
+            else
+              Nothing
+      in  mapMaybe loop_to lone_branch_blocks
     lookup id = lookupBlockEnv env id `orElse` id 
 
+-- Be careful not to mark a block as a lone branch if it carries
+-- important information about incoming arguments or the update frame.
 isLoneBranchZ :: CmmBlock -> Either (BlockId, BlockId) CmmBlock
-isLoneBranchZ (G.Block id Nothing (G.ZLast (G.LastOther (LastBranch target))))
+isLoneBranchZ (G.Block id (StackInfo {argBytes = Nothing, returnOff = Nothing})
+              (G.ZLast (G.LastOther (LastBranch target))))
     | id /= target  = Left (id,target)
 isLoneBranchZ other = Right other
    -- An infinite loop is not a link in a branch chain!
 replaceLabelsZ env = replace_eid . G.map_nodes id middle last
   where
     replace_eid (G.LGraph eid off blocks) = G.LGraph (lookup eid) off blocks
-    middle m@(MidComment _)            = m
-    middle   (MidAssign r e)           = MidAssign r (exp e)
-    middle   (MidStore addr e)         = MidStore (exp addr) (exp e)
-    middle   (MidUnsafeCall tgt fs as) = MidUnsafeCall (midcall tgt) fs (map exp as)
-    middle   (MidAddToContext e es)    = MidAddToContext (exp e) (map exp es)
-    last (LastBranch id)             = LastBranch (lookup id)
-    last (LastCondBranch e ti fi)    = LastCondBranch (exp e) (lookup ti) (lookup fi)
-    last (LastSwitch e tbl)          = LastSwitch (exp e) (map (fmap lookup) tbl)
-    last (LastCall tgt mb_id s)      = LastCall (exp tgt) (fmap lookup mb_id) s
-    last (LastJump e s)              = LastJump (exp e) s
-    last (LastReturn s)              = LastReturn s
-    midcall   (ForeignTarget e c)    = ForeignTarget (exp e) c
-    midcall m@(PrimTarget _)         = m
-    exp e@(CmmLit _)         = e
-    exp   (CmmLoad addr ty)  = CmmLoad (exp addr) ty
-    exp e@(CmmReg _)         = e
-    exp   (CmmMachOp op es)  = CmmMachOp op $ map exp es
-    exp e@(CmmRegOff _ _)    = e
+    middle = mapExpDeepMiddle exp
+    last l = mapExpDeepLast   exp (last' l)
+    last' (LastBranch bid) = LastBranch (lookup bid)
+    last' (LastCondBranch p t f) = LastCondBranch p (lookup t) (lookup f)
+    last' (LastSwitch e arms) = LastSwitch e (map (liftM lookup) arms)
+    last' (LastCall t k a r) = LastCall t (liftM lookup k) a r
+    exp (CmmLit (CmmBlock bid)) = CmmLit (CmmBlock (lookup bid))
     exp   (CmmStackSlot (CallArea (Young id)) i) =
       CmmStackSlot (CallArea (Young (lookup id))) i
-    exp e@(CmmStackSlot _ _) = e
+    exp e = e
+    lookup id = fmap lookup (lookupBlockEnv env id) `orElse` id 
+
+replaceBranches :: BlockEnv BlockId -> CmmGraph -> CmmGraph
+replaceBranches env g = map_nodes id id last g
+  where
+    last (LastBranch id)          = LastBranch (lookup id)
+    last (LastCondBranch e ti fi) = LastCondBranch e (lookup ti) (lookup fi)
+    last (LastSwitch e tbl)       = LastSwitch e (map (fmap lookup) tbl)
+    last l@(LastCall {})          = l
     lookup id = fmap lookup (lookupBlockEnv env id) `orElse` id 
 
 ----------------------------------------------------------------
 -- Order matters, so we work bottom up (reverse postorder DFS).
 --
 -- To ensure correctness, we have to make sure that the BlockId of the block
--- we are about to eliminate is not named in another instruction
--- (except an adjacent stack pointer adjustment, which we expect and also eliminate).
--- For 
+-- we are about to eliminate is not named in another instruction.
 --
 -- Note: This optimization does _not_ subsume branch chain elimination.
 blockConcatZ  :: Tx CmmGraph
 blockConcatZ = removeUnreachableBlocksZ `seqTx` blockConcatZ'
 blockConcatZ' :: Tx CmmGraph
 blockConcatZ' g@(G.LGraph eid off blocks) =
-  tx $ pprTrace "concatMap" (ppr concatMap) $ replaceLabelsZ concatMap $ G.LGraph eid off blocks'
+  tx $ replaceLabelsZ concatMap $ G.LGraph eid off blocks'
   where (changed, blocks', concatMap) =
            foldr maybe_concat (False, blocks, emptyBlockEnv) $ G.postorder_dfs g
         maybe_concat b@(G.Block bid _ _) (changed, blocks', concatMap) =
           let unchanged = (changed, extendBlockEnv blocks' bid b, concatMap)
           in case G.goto_end $ G.unzip b of
                (h, G.LastOther (LastBranch b')) ->
-                  if num_preds b' == 1 then
+                  if canConcatWith b' then
                     (True, extendBlockEnv blocks' bid $ splice blocks' h b',
                      extendBlockEnv concatMap b' bid)
                   else unchanged
                _ -> unchanged
         num_preds bid = liftM sizeBlockSet (lookupBlockEnv backEdges bid) `orElse` 0
+        canConcatWith b' =
+          case lookupBlockEnv blocks b' of
+            Just (G.Block _ (StackInfo {returnOff = Nothing}) _) -> num_preds b' == 1
+            _ -> False
         backEdges = predMap g
         splice blocks' h bid' =
           case lookupBlockEnv blocks' bid' of
-            Just (G.Block _ Nothing t) -> G.zip $ G.ZBlock h t
-            Just (G.Block _ (Just _) _) ->
+            Just (G.Block _ (StackInfo {returnOff = Nothing}) t) ->
+              G.zip $ G.ZBlock h t
+            Just (G.Block _ _ _) ->
               panic "trying to concatenate but successor block has incoming args"
-            Nothing -> panic "unknown successor block"
+            Nothing -> pprPanic "unknown successor block" (ppr bid' <+> ppr blocks' <+> ppr blocks)
         tx = if changed then aTx else noTx
 ----------------------------------------------------------------
 mkClosureBlockEnv :: [(BlockId, BlockId)] -> BlockEnv BlockId
 ----------------------------------------------------------------
 removeUnreachableBlocksZ :: Tx CmmGraph
 removeUnreachableBlocksZ g@(G.LGraph id off blocks) =
-      if length blocks' < sizeUFM blocks then aTx $ G.of_block_list id off blocks'
-      else noTx g
+  if length blocks' < sizeBEnv blocks then aTx $ G.of_block_list id off blocks'
+  else noTx g
     where blocks' = G.postorder_dfs g
 
 where
 
 import BlockId
-import ClosureInfo (C_SRT(..))
 import Cmm
 import CmmExpr
 import MkZipCfgCmm hiding (CmmGraph)
+import ZipCfg       -- imported for reverse conversion
 import ZipCfgCmmRep -- imported for reverse conversion
 import CmmZipUtil
-import ForeignCall
 import PprCmm()
 import qualified ZipCfg as G
 
 import Monad
 import Outputable
 import Panic
-import UniqSet
 import UniqSupply
 
 import Maybe
            let (offset, entry) = mkEntry id Native args in
            labelAGraph id offset $
               entry <*> mkStmts ss <*> foldr addBlock emptyAGraph other_blocks
-  where addBlock (BasicBlock id ss) g = mkLabel id Nothing  <*> mkStmts ss <*> g
+  where addBlock (BasicBlock id ss) g =
+          mkLabel id emptyStackInfo <*> mkStmts ss <*> g
+        updfr_sz = panic "upd frame size lost in cmm conversion"
         mkStmts (CmmNop        : ss)  = mkNop        <*> mkStmts ss 
         mkStmts (CmmComment s  : ss)  = mkComment s  <*> mkStmts ss
         mkStmts (CmmAssign l r : ss)  = mkAssign l r <*> mkStmts ss
         mkStmts (CmmStore  l r : ss)  = mkStore  l r <*> mkStmts ss
         mkStmts (CmmCall (CmmCallee f conv) res args (CmmSafe srt) CmmMayReturn : ss) =
-            mkCall f conv (map hintlessCmm res) (map hintlessCmm args) srt <*> mkStmts ss 
+            mkCall f conv' (map hintlessCmm res) (map hintlessCmm args) updfr_sz
+            <*> mkStmts ss 
+              where conv' = Foreign (ForeignConvention conv [] []) -- JD: DUBIOUS
         mkStmts (CmmCall (CmmPrim {}) _ _ (CmmSafe _) _ : _) =
             panic "safe call to a primitive CmmPrim CallishMachOp"
         mkStmts (CmmCall f res args CmmUnsafe CmmMayReturn : ss) =
                       mkUnsafeCall (convert_target f res args)
-                       (strip_hints res) (strip_hints args) <*> mkStmts ss
+                       (strip_hints res) (strip_hints args)
+                      <*> mkStmts ss
         mkStmts (CmmCondBranch e l : fbranch) =
             mkCmmIfThenElse e (mkBranch l) (mkStmts fbranch)
         mkStmts (last : []) = mkLast last
         mkStmts (_ : _ : _) = bad "last node not at end"
         bad msg = pprPanic (msg ++ " in function " ++ fun_name) (ppr g)
         mkLast (CmmCall (CmmCallee f conv) []     args _ CmmNeverReturns) =
-            mkFinalCall f conv $ map hintlessCmm args
+            mkFinalCall f conv (map hintlessCmm args) updfr_sz
         mkLast (CmmCall (CmmPrim {}) _ _ _ CmmNeverReturns) =
             panic "Call to CmmPrim never returns?!"
         mkLast (CmmSwitch scrutinee table) = mkSwitch scrutinee table
         -- SURELY, THESE HINTLESS ARGS ARE WRONG AND WILL BE FIXED WHEN CALLING
         -- CONVENTIONS ARE HONORED?
-        mkLast (CmmJump tgt args)          = mkJump   tgt $ map hintlessCmm args
-        mkLast (CmmReturn ress)            = mkReturn $ map hintlessCmm ress
+        mkLast (CmmJump tgt args)          = mkJump   tgt (map hintlessCmm args) updfr_sz
+        mkLast (CmmReturn ress)            =
+          mkReturnSimple (map hintlessCmm ress) updfr_sz
         mkLast (CmmBranch tgt)             = mkBranch tgt
         mkLast (CmmCall _f (_:_) _args _ CmmNeverReturns) =
                    panic "Call never returns but has results?!"
           showblocks = "LGraph has " ++ show (length blocks) ++ " blocks:" ++
                        concat (map (\(G.Block id _ _) -> " " ++ show id) blocks)
           cscomm = "Call successors are" ++
-                   (concat $ map (\id -> " " ++ show id) $ uniqSetToList call_succs)
+                   (concat $ map (\id -> " " ++ show id) $ blockSetToList call_succs)
           swallow [] = []
           swallow (G.Block id _ t : rest) = tail id [] t rest
           tail id prev' (G.ZTail m t)             rest = tail id (mid m : prev') t rest
           mid (MidComment s)  = CmmComment s
           mid (MidAssign l r) = CmmAssign l r
           mid (MidStore  l r) = CmmStore  l r
-          mid (MidUnsafeCall target ress args)
+          mid (MidForeignCall _ target ress args)
                = CmmCall (cmm_target target)
                          (add_hints conv Results   ress) 
                          (add_hints conv Arguments args) 
                          CmmUnsafe CmmMayReturn
                where
                  conv = get_conv target
-          mid m@(MidAddToContext {}) = pcomment (ppr m)
-          pcomment p = scomment $ showSDoc p
           block' id prev'
               | id == G.lg_entry g = BasicBlock id $ extend_entry    (reverse prev')
               | otherwise          = BasicBlock id $ extend_block id (reverse prev')
             case l of
               LastBranch tgt ->
                   case n of
-                    -- THIS IS NOW WRONG -- LABELS CAN SHOW UP ELSEWHERE IN THE GRAPH
+                    -- THIS OPT IS WRONG -- LABELS CAN SHOW UP ELSEWHERE IN THE GRAPH
                     --G.Block id' _ t : bs
                     --    | tgt == id', unique_pred id' 
                     --    -> tail id prev' t bs -- optimize out redundant labels
               LastCondBranch expr tid fid ->
                   case n of
                     G.Block id' _ t : bs
+                      -- It would be better to handle earlier, but we still must
+                      -- generate correct code here.
+                      | id' == fid, tid == fid, unique_pred id' ->
+                                 tail id prev' t bs
                       | id' == fid, unique_pred id' ->
                                  tail id (CmmCondBranch expr tid : prev') t bs
                       | id' == tid, unique_pred id',
                                  tail id (CmmCondBranch e'   fid : prev') t bs
                     _ -> let instrs' = CmmBranch fid : CmmCondBranch expr tid : prev'
                          in block' id instrs' : swallow n
-              LastJump expr _      -> endblock $ CmmJump expr []
-              LastReturn _         -> endblock $ CmmReturn []
               LastSwitch arg ids   -> endblock $ CmmSwitch arg $ ids
-              LastCall e cont _ ->
-                let tgt = CmmCallee e CCallConv in
-                case cont of
-                  Nothing ->
-                      endblock $ CmmCall tgt [] [] CmmUnsafe CmmNeverReturns
-                  Just _ ->
-                       endblock $ CmmCall tgt [] [] (CmmSafe NoC_SRT) CmmMayReturn
+              LastCall e _ _ _ -> endblock $ CmmJump e []
           exit id prev' n = -- highly irregular (assertion violation?)
               let endblock stmt = block' id (stmt : prev') : swallow n in
               case n of [] -> endblock (scomment "procedure falls off end")
                     let id = G.blockId b
                     in  case lookupBlockEnv preds id of
                           Nothing -> single
-                          Just s -> if sizeUniqSet s == 1 then
+                          Just s -> if sizeBlockSet s == 1 then
                                         extendBlockSet single id
                                     else single
               in  G.fold_blocks add emptyBlockSet g
           call_succs = 
               let add b succs =
                       case G.last (G.unzip b) of
-                        G.LastOther (LastCall _ (Just id) _) -> extendBlockSet succs id
+                        G.LastOther (LastCall _ (Just id) _ _) ->
+                          extendBlockSet succs id
                         _ -> succs
               in  G.fold_blocks add emptyBlockSet g
           _is_call_succ id = elemBlockSet id call_succs
 
 
 module CmmExpr
     ( CmmType  -- Abstract 
-         , b8, b16, b32, b64, f32, f64, bWord, bHalfWord, gcWord
-         , cInt, cLong
-         , cmmBits, cmmFloat
-         , typeWidth, cmmEqType, cmmEqType_ignoring_ptrhood
-         , isFloatType, isGcPtrType, isWord32, isWord64, isFloat64, isFloat32
+    , b8, b16, b32, b64, f32, f64, bWord, bHalfWord, gcWord
+    , cInt, cLong
+    , cmmBits, cmmFloat
+    , typeWidth, cmmEqType, cmmEqType_ignoring_ptrhood
+    , isFloatType, isGcPtrType, isWord32, isWord64, isFloat64, isFloat32
  
     , Width(..)
-         , widthInBits, widthInBytes, widthInLog
-         , wordWidth, halfWordWidth, cIntWidth, cLongWidth
+    , widthInBits, widthInBytes, widthInLog, widthFromBytes
+    , wordWidth, halfWordWidth, cIntWidth, cLongWidth
  
     , CmmExpr(..), cmmExprType, cmmExprWidth, maybeInvertCmmExpr
     , CmmReg(..), cmmRegType
     , DefinerOfSlots, UserOfSlots, foldSlotsDefd, foldSlotsUsed
     , RegSet, emptyRegSet, elemRegSet, extendRegSet, deleteFromRegSet, mkRegSet
             , plusRegSet, minusRegSet, timesRegSet
-    , Area(..), AreaId(..), SubArea, StackSlotMap, getSlot
+    , Area(..), AreaId(..), SubArea, SubAreaSet, AreaMap, StackSlotMap, getSlot
  
    -- MachOp
     , MachOp(..) 
   | Young BlockId
   deriving (Eq, Ord)
 
-type SubArea = (Area, Int, Int) -- area, offset, width
+type SubArea    = (Area, Int, Int) -- area, offset, width
+type SubAreaSet = FiniteMap Area [SubArea]
+type AreaMap    = FiniteMap Area Int
 
 data CmmLit
   = CmmInt Integer  Width
         -- It is also used inside the NCG during when generating
         -- position-independent code. 
   | CmmLabelDiffOff CLabel CLabel Int   -- label1 - label2 + offset
+  | CmmBlock BlockId                   -- Code label
+  | CmmHighStackMark -- stands for the max stack space used during a procedure
   deriving Eq
 
 cmmExprType :: CmmExpr -> CmmType
 cmmLitType (CmmLabel lbl)      = cmmLabelType lbl
 cmmLitType (CmmLabelOff lbl _)  = cmmLabelType lbl
 cmmLitType (CmmLabelDiffOff {}) = bWord
+cmmLitType (CmmBlock _)        = bWord
+cmmLitType (CmmHighStackMark)   = bWord
 
 cmmLabelType :: CLabel -> CmmType
 cmmLabelType lbl | isGcPtrLabel lbl = gcWord
   foldRegsDefd _ set [] = set
   foldRegsDefd f set (x:xs) = foldRegsDefd f (foldRegsDefd f set x) xs
 
+instance DefinerOfLocalRegs a => DefinerOfLocalRegs (Maybe a) where
+  foldRegsDefd _ set Nothing  = set
+  foldRegsDefd f set (Just x) = foldRegsDefd f set x
+
 
 -----------------------------------------------------------------------------
 --    Stack slots
 widthInBytes W128 = 16
 widthInBytes W80  = 10
 
+widthFromBytes :: Int -> Width
+widthFromBytes 1  = W8
+widthFromBytes 2  = W16
+widthFromBytes 4  = W32
+widthFromBytes 8  = W64
+widthFromBytes 16 = W128
+widthFromBytes 10 = W80
+widthFromBytes n  = pprPanic "no width for given number of bytes" (ppr n)
+
 -- log_2 of the width in bytes, useful for generating shifts.
 widthInLog :: Width -> Int
 widthInLog W8   = 0
 
 -- for details
 
 module CmmInfo (
+  emptyContInfoTable,
   cmmToRawCmm,
-  mkInfoTable
+  mkInfoTable,
+  mkBareInfoTable
 ) where
 
 #include "HsVersions.h"
 import CgCallConv
 import CgUtils
 import SMRep
+import ZipCfgCmmRep
 
 import Constants
 import Outputable
 
 import Data.Bits
 
+-- When we split at proc points, we need an empty info table.
+emptyContInfoTable :: CmmInfo
+emptyContInfoTable =
+  CmmInfo Nothing Nothing (CmmInfoTable False (ProfilingInfo zero zero) rET_SMALL
+                                              (ContInfo [] NoC_SRT))
+    where zero = CmmInt 0 wordWidth
+
 cmmToRawCmm :: [Cmm] -> IO [RawCmm]
 cmmToRawCmm cmm = do
   info_tbl_uniques <- mkSplitUniqSupply 'i'
       -- Code without an info table.  Easy.
       CmmNonInfoTable -> [CmmProc [] entry_label arguments blocks]
 
-      CmmInfoTable (ProfilingInfo ty_prof cl_prof) type_tag type_info ->
+      CmmInfoTable _ (ProfilingInfo ty_prof cl_prof) type_tag type_info ->
           let info_label = entryLblToInfoLbl entry_label
               ty_prof'   = makeRelativeRefTo info_label ty_prof
               cl_prof'   = makeRelativeRefTo info_label cl_prof
                                      else type_tag
                 (srt_label, srt_bitmap) = mkSRTLit info_label srt
 
+-- Generate a bare info table, not attached to any procedure.
+mkBareInfoTable :: CLabel -> Unique -> CmmInfoTable -> [CmmTopZ]
+mkBareInfoTable lbl uniq info =
+  case mkInfoTable uniq (CmmProc (CmmInfo Nothing Nothing info) lbl [] (ListGraph [])) of
+    [CmmProc d _ _ _] ->
+      ASSERT (tablesNextToCode)
+      [CmmData Data (d ++ [CmmDataLabel (entryLblToInfoLbl lbl)])]
+    [CmmData d s]     -> [CmmData d s]
+    _ -> panic "mkBareInfoTable expected to produce only data"
+
+
 -- Handle the differences between tables-next-to-code
 -- and not tables-next-to-code
 mkInfoTableAndCode :: CLabel
 
 import Maybe
 import Outputable
 import PprCmm
-import Unique
 import Constants
 import FastString
 
 
 lintCmmBlock :: BlockSet -> GenBasicBlock CmmStmt -> CmmLint ()
 lintCmmBlock labels (BasicBlock id stmts)
-  = addLintInfo (text "in basic block " <> ppr (getUnique id)) $
+  = addLintInfo (text "in basic block " <> ppr id) $
        mapM_ (lintCmmStmt labels) stmts
 
 -- -----------------------------------------------------------------------------
 
 -- Check for some common byte/word mismatches (eg. Sp + 1)
 cmmCheckMachOp   :: MachOp -> [CmmExpr] -> [CmmType] -> CmmLint CmmType
-cmmCheckMachOp  op args@[CmmReg reg, CmmLit (CmmInt i _)] _
-  | isWordOffsetReg reg && isOffsetOp op && i `rem` fromIntegral wORD_SIZE /= 0
-  = cmmLintDubiousWordOffset (CmmMachOp op args)
 cmmCheckMachOp op [lit@(CmmLit (CmmInt { })), reg@(CmmReg _)] tys
   = cmmCheckMachOp op [reg, lit] tys
 cmmCheckMachOp op _ tys
   = return (machOpResultType op tys)
 
-isWordOffsetReg  :: CmmReg -> Bool
-isWordOffsetReg (CmmGlobal Sp) = True
--- No warnings for unaligned arithmetic, which is used to tag dynamic constructor closures.
---isWordOffsetReg (CmmGlobal Hp) = True
-isWordOffsetReg _ = False
-
 isOffsetOp :: MachOp -> Bool
 isOffsetOp (MO_Add _) = True
 isOffsetOp (MO_Sub _) = True
 
     fixedpoint (cmmBlockDependants sources)
                (cmmBlockUpdate blocks')
                (map blockId blocks)
-               (listToUFM [(blockId b, emptyUniqSet) | b <- blocks])
+               (mkBlockEnv [(blockId b, emptyUniqSet) | b <- blocks])
     where
       sources :: BlockSources
       sources = cmmBlockSources blocks
 
       blocks' :: BlockStmts
-      blocks' = listToUFM $ map block_name blocks
+      blocks' = mkBlockEnv $ map block_name blocks
 
       block_name :: CmmBasicBlock -> (BlockId, [CmmStmt])
       block_name b = (blockId b, blockStmts b)
 -- need updating after a given block is updated in the liveness analysis
 -----------------------------------------------------------------------------
 cmmBlockSources :: [CmmBasicBlock] -> BlockSources
-cmmBlockSources blocks = foldr aux emptyUFM blocks
+cmmBlockSources blocks = foldr aux emptyBlockEnv blocks
     where
       aux :: CmmBasicBlock
           -> BlockSources
                        -> BlockSources
                        -> BlockSources
       add_source_edges source target ufm =
-          addToUFM_Acc (flip addOneToUniqSet) unitUniqSet ufm target source
+          addToBEnv_Acc (flip addOneToUniqSet) unitUniqSet ufm target source
 
       branch_targets :: [CmmStmt] -> UniqSet BlockId
       branch_targets stmts =
 -----------------------------------------------------------------------------
 cmmBlockDependants :: BlockSources -> BlockId -> [BlockId]
 cmmBlockDependants sources ident =
-    uniqSetToList $ lookupWithDefaultUFM sources emptyUniqSet ident
+    uniqSetToList $ lookupWithDefaultBEnv sources emptyUniqSet ident
 
 -----------------------------------------------------------------------------
 -- | Given the table of type 'BlockStmts' and a block that was updated,
 cmmBlockUpdate blocks node _ state =
     if (sizeUniqSet old_live) == (sizeUniqSet new_live)
       then Nothing
-      else Just $ addToUFM state node new_live
+      else Just $ extendBlockEnv state node new_live
     where
       new_live, old_live :: CmmLive
       new_live = cmmStmtListLive state block_stmts
-      old_live = lookupWithDefaultUFM state missing_live node
+      old_live = lookupWithDefaultBEnv state missing_live node
 
       block_stmts :: [CmmStmt]
-      block_stmts = lookupWithDefaultUFM blocks missing_block node
+      block_stmts = lookupWithDefaultBEnv blocks missing_block node
 
       missing_live = panic "unknown block id during liveness analysis"
       missing_block = panic "unknown block id during liveness analysis"
               (CmmCallee target _) -> cmmExprLive target
               (CmmPrim _) -> id
 cmmStmtLive other_live (CmmBranch target) =
-    addLive (lookupWithDefaultUFM other_live emptyUniqSet target)
+    addLive (lookupWithDefaultBEnv other_live emptyUniqSet target)
 cmmStmtLive other_live (CmmCondBranch expr target) =
     cmmExprLive expr .
-    addLive (lookupWithDefaultUFM other_live emptyUniqSet target)
+    addLive (lookupWithDefaultBEnv other_live emptyUniqSet target)
 cmmStmtLive other_live (CmmSwitch expr targets) =
     cmmExprLive expr .
     (foldr ((.) . (addLive .
-                   lookupWithDefaultUFM other_live emptyUniqSet))
+                   lookupWithDefaultBEnv other_live emptyUniqSet))
            id
            (mapCatMaybes id targets))
 cmmStmtLive _ (CmmJump expr params) =
 
     ( CmmLive
     , cmmLivenessZ
     , liveLattice
-    , middleLiveness, lastLiveness
+    , middleLiveness, lastLiveness, noLiveOnEntry
     ) 
 where
 
 import ZipCfgCmmRep
 
 import Maybes
+import Outputable
 import UniqSet
 
 -----------------------------------------------------------------------------
 
 -- | The dataflow lattice
 liveLattice :: DataflowLattice CmmLive
-liveLattice = DataflowLattice "live LocalReg's" emptyUniqSet add False
+liveLattice = DataflowLattice "live LocalReg's" emptyUniqSet add True
     where add new old =
             let join = unionUniqSets new old in
             (if sizeUniqSet join > sizeUniqSet old then aTx else noTx) join
 -- | Calculated liveness info for a CmmGraph
 -----------------------------------------------------------------------------
 cmmLivenessZ :: CmmGraph -> FuelMonad BlockEntryLiveness
-cmmLivenessZ g = liftM zdfFpFacts $ (res :: FuelMonad (CmmBackwardFixedPoint CmmLive))
+cmmLivenessZ g@(LGraph entry _ _) =
+  liftM (check . zdfFpFacts) (res :: FuelMonad (CmmBackwardFixedPoint CmmLive))
   where res = zdfSolveFrom emptyBlockEnv "liveness analysis" liveLattice transfers
                            emptyUniqSet (graphOfLGraph g)
         transfers = BackwardTransfers first middle last
         first live _ = live
         middle       = flip middleLiveness
         last         = flip lastLiveness
+        check facts  =
+          noLiveOnEntry entry (expectJust "check" $ lookupBlockEnv facts entry) facts
+
+-- | On entry to the procedure, there had better not be any LocalReg's live-in.
+noLiveOnEntry :: BlockId -> CmmLive -> a -> a
+noLiveOnEntry bid in_fact x =
+  if isEmptyUniqSet in_fact then x
+  else pprPanic "LocalReg's live-in to graph" (ppr bid <+> ppr in_fact)
 
 -- | The transfer equations use the traditional 'gen' and 'kill'
 -- notations, which should be familiar from the dragon book.
 gen  a live = foldRegsUsed extendRegSet      live a
 kill a live = foldRegsUsed delOneFromUniqSet live a
 
+-- Why aren't these function using the typeclasses on Middle and Last?
 middleLiveness :: Middle -> CmmLive -> CmmLive
-middleLiveness m = middle m
-  where middle (MidComment {})               = id
-        middle (MidAssign lhs expr)          = gen expr . kill lhs
-        middle (MidStore addr rval)          = gen addr . gen rval
-        middle (MidUnsafeCall tgt ress args) = gen tgt . gen args . kill ress
-        middle (MidAddToContext ra args)     = gen ra . gen args
+middleLiveness (MidComment {})            live = live
+middleLiveness (MidAssign lhs expr)       live = gen expr $ kill lhs live
+middleLiveness (MidStore addr rval)       live = gen addr $ gen rval live
+middleLiveness (MidForeignCall _ tgt _ args) _ = gen tgt $ gen args emptyUniqSet
 
 lastLiveness :: Last -> (BlockId -> CmmLive) -> CmmLive
 lastLiveness l env = last l
-  where last (LastReturn _)            = emptyUniqSet
-        last (LastJump e _)            = gen e $ emptyUniqSet
-        last (LastBranch id)           = env id
-        last (LastCall tgt (Just k) _) = gen tgt $ env k
-        last (LastCall tgt Nothing _)  = gen tgt $ emptyUniqSet
-        last (LastCondBranch e t f)    = gen e $ unionUniqSets (env t) (env f)
-        last (LastSwitch e tbl) = gen e $ unionManyUniqSets $ map env (catMaybes tbl)
+  where last (LastBranch id)             = env id
+        last (LastCall tgt Nothing  _ _) = gen tgt $ emptyUniqSet
+        last (LastCall tgt (Just k) _ _) = gen tgt $ env k
+        last (LastCondBranch e t f)      = gen e $ unionUniqSets (env t) (env f)
+        last (LastSwitch e tbl)          =
+          gen e $ unionManyUniqSets $ map env (catMaybes tbl)
 
 -}
 
 cmmLoopifyForC :: RawCmmTop -> RawCmmTop
-cmmLoopifyForC p@(CmmProc info entry_lbl [] (ListGraph blocks@(BasicBlock top_id _ : _)))
+cmmLoopifyForC p@(CmmProc info entry_lbl []
+                 (ListGraph blocks@(BasicBlock top_id _ : _)))
   | null info = p  -- only if there's an info table, ignore case alts
   | otherwise =  
 --  pprTrace "jump_lbl" (ppr jump_lbl <+> ppr entry_lbl) $
 
                -- ptrs, nptrs, closure type, description, type
                { do prof <- profilingInfo $11 $13
                     return (mkRtsEntryLabelFS $3,
-                       CmmInfoTable prof (fromIntegral $9)
+                       CmmInfoTable False prof (fromIntegral $9)
                                     (ThunkInfo (fromIntegral $5, fromIntegral $7) NoC_SRT),
                        []) }
        
                -- ptrs, nptrs, closure type, description, type, fun type
                { do prof <- profilingInfo $11 $13
                     return (mkRtsEntryLabelFS $3,
-                       CmmInfoTable prof (fromIntegral $9)
+                       CmmInfoTable False prof (fromIntegral $9)
                                     (FunInfo (fromIntegral $5, fromIntegral $7) NoC_SRT
                                      0  -- Arity zero
                                      (ArgSpec (fromIntegral $15))
                -- ptrs, nptrs, closure type, description, type, fun type, arity
                { do prof <- profilingInfo $11 $13
                     return (mkRtsEntryLabelFS $3,
-                       CmmInfoTable prof (fromIntegral $9)
+                       CmmInfoTable False prof (fromIntegral $9)
                                     (FunInfo (fromIntegral $5, fromIntegral $7) NoC_SRT (fromIntegral $17)
                                      (ArgSpec (fromIntegral $15))
                                      zeroCLit),
                     -- but that's the way the old code did it we can fix it some other time.
                     desc_lit <- code $ mkStringCLit $13
                     return (mkRtsEntryLabelFS $3,
-                       CmmInfoTable prof (fromIntegral $11)
+                       CmmInfoTable False prof (fromIntegral $11)
                                     (ConstrInfo (fromIntegral $5, fromIntegral $7) (fromIntegral $9) desc_lit),
                        []) }
        
                -- selector, closure type, description, type
                { do prof <- profilingInfo $9 $11
                     return (mkRtsEntryLabelFS $3,
-                       CmmInfoTable prof (fromIntegral $7)
+                       CmmInfoTable False prof (fromIntegral $7)
                                     (ThunkSelectorInfo (fromIntegral $5) NoC_SRT),
                        []) }
 
                -- closure type (no live regs)
                { do let infoLabel = mkRtsInfoLabelFS $3
                     return (mkRtsRetLabelFS $3,
-                       CmmInfoTable (ProfilingInfo zeroCLit zeroCLit) (fromIntegral $5)
+                       CmmInfoTable False (ProfilingInfo zeroCLit zeroCLit) (fromIntegral $5)
                                     (ContInfo [] NoC_SRT),
                        []) }
 
                -- closure type, live regs
                { do live <- sequence (map (liftM Just) $7)
                     return (mkRtsRetLabelFS $3,
-                       CmmInfoTable (ProfilingInfo zeroCLit zeroCLit) (fromIntegral $5)
+                       CmmInfoTable False (ProfilingInfo zeroCLit zeroCLit) (fromIntegral $5)
                                     (ContInfo live NoC_SRT),
                        live) }
 
 
             then unitUniqSet child_id
             else emptyUniqSet
           where
-            parent_owners = lookupWithDefaultUFM owners emptyUniqSet parent_id
-            child_owners = lookupWithDefaultUFM owners emptyUniqSet child_id
+            parent_owners = lookupWithDefaultBEnv owners emptyUniqSet parent_id
+            child_owners = lookupWithDefaultBEnv owners emptyUniqSet child_id
             needs_proc_point =
                 -- only if parent isn't dead
                 (not $ isEmptyUniqSet parent_owners) &&
                    -> [BrokenBlock]
                    -> BlockEnv (UniqSet BlockId)
 calculateOwnership blocks_ufm proc_points blocks =
-    fixedpoint dependants update (map brokenBlockId blocks) emptyUFM
+    fixedpoint dependants update (map brokenBlockId blocks) emptyBlockEnv
     where
       dependants :: BlockId -> [BlockId]
       dependants ident =
-          brokenBlockTargets $ lookupWithDefaultUFM
+          brokenBlockTargets $ lookupWithDefaultBEnv
                                  blocks_ufm unknown_block ident
 
       update :: BlockId
       update ident cause owners =
           case (cause, ident `elementOfUniqSet` proc_points) of
             (Nothing, True) ->
-                Just $ addToUFM owners ident (unitUniqSet ident)
+                Just $ extendBlockEnv owners ident (unitUniqSet ident)
             (Nothing, False) -> Nothing
             (Just cause', True) -> Nothing
             (Just cause', False) ->
                 if (sizeUniqSet old) == (sizeUniqSet new)
                    then Nothing
-                   else Just $ addToUFM owners ident new
+                   else Just $ extendBlockEnv owners ident new
                 where
-                  old = lookupWithDefaultUFM owners emptyUniqSet ident
+                  old = lookupWithDefaultBEnv owners emptyUniqSet ident
                   new = old `unionUniqSets`
-                        lookupWithDefaultUFM owners emptyUniqSet cause'
+                        lookupWithDefaultBEnv owners emptyUniqSet cause'
 
       unknown_block = panic "unknown BlockId in calculateOwnership"
 
-
 module CmmProcPointZ
-    ( callProcPoints, minimalProcPointSet
+    ( ProcPointSet, Status(..)
+    , callProcPoints, minimalProcPointSet
     , addProcPointProtocols, splitAtProcPoints, procPointAnalysis
-    , liveSlotAnal, cafAnal, layout, manifestSP, igraph, areaBuilder
     )
 where
 
-import Constants
 import qualified Prelude as P
 import Prelude hiding (zip, unzip, last)
-import Util (sortLe)
 
 import BlockId
-import Bitmap
 import CLabel
 import Cmm hiding (blockId)
-import CmmExpr
 import CmmContFlowOpt
+import CmmExpr
+import CmmInfo
 import CmmLiveZ
 import CmmTx
 import DFMonad
 import FiniteMap
-import IdInfo
 import List (sortBy)
 import Maybes
+import MkZipCfg
 import MkZipCfgCmm hiding (CmmBlock, CmmGraph, CmmTopZ)
 import Monad
-import Name
 import Outputable
 import Panic
-import SMRep (rET_SMALL)
-import StgCmmClosure
-import StgCmmUtils
-import UniqFM
 import UniqSet
 import UniqSupply
 import ZipCfg
 
 instance Outputable Status where
   ppr (ReachedBy ps)
-      | isEmptyUniqSet ps = text "<not-reached>"
+      | isEmptyBlockSet ps = text "<not-reached>"
       | otherwise = text "reached by" <+>
-                    (hsep $ punctuate comma $ map ppr $ uniqSetToList ps)
+                    (hsep $ punctuate comma $ map ppr $ blockSetToList ps)
   ppr ProcPoint = text "<procpt>"
 
 
           add_to _ ProcPoint = noTx ProcPoint
           add_to ProcPoint _ = aTx ProcPoint -- aTx because of previous case again
           add_to (ReachedBy p) (ReachedBy p') =
-              let union = unionUniqSets p p'
-              in  if sizeUniqSet union > sizeUniqSet p' then
+              let union = unionBlockSets p p'
+              in  if sizeBlockSet union > sizeBlockSet p' then
                       aTx (ReachedBy union)
                   else
                       noTx (ReachedBy p')
 
 forward :: ForwardTransfers Middle Last Status
 forward = ForwardTransfers first middle last exit
-    where first ProcPoint id = ReachedBy $ unitUniqSet id
+    where first ProcPoint id = ReachedBy $ unitBlockSet id
           first  x _ = x
           middle x _ = x
-          last _ (LastCall _ (Just id) _) = LastOutFacts [(id, ProcPoint)]
+          last _ (LastCall _ (Just id) _ _) = LastOutFacts [(id, ProcPoint)]
           last x l = LastOutFacts $ map (\id -> (id, x)) (succs l)
           exit x   = x
                 
 callProcPoints      :: CmmGraph -> ProcPointSet
 minimalProcPointSet :: ProcPointSet -> CmmGraph -> FuelMonad ProcPointSet
 
-callProcPoints g = fold_blocks add entryPoint g
-  where entryPoint = unitUniqSet (lg_entry g)
-        add b set = case last $ unzip b of
-                      LastOther (LastCall _ (Just k) _) -> extendBlockSet set k
+callProcPoints g = fold_blocks add (unitBlockSet (lg_entry g)) g
+  where add b set = case last $ unzip b of
+                      LastOther (LastCall _ (Just k) _ _) -> extendBlockSet set k
                       _ -> set
 
 minimalProcPointSet callProcPoints g = extendPPSet g (postorder_dfs g) callProcPoints
 procPointAnalysis :: ProcPointSet -> CmmGraph -> FuelMonad (BlockEnv Status)
 procPointAnalysis procPoints g =
   let addPP env id = extendBlockEnv env id ProcPoint
-      initProcPoints = foldl addPP emptyBlockEnv (uniqSetToList procPoints)
+      initProcPoints = foldl addPP emptyBlockEnv (blockSetToList procPoints)
   in liftM zdfFpFacts $
         (zdfSolveFrom initProcPoints "proc-point reachability" lattice
                               forward (fact_bot lattice) $ graphOfLGraph g :: PPFix)
                                  Just ProcPoint -> extendBlockSet pps id
                                  _ -> pps
            procPoints' = fold_blocks add emptyBlockSet g
-           newPoint = listToMaybe (mapMaybe ppSuccessor blocks)
-           ppSuccessor b@(Block id _ _) =
-               let nreached id = case lookupBlockEnv env id `orElse` panic "no ppt" of
+           newPoints = mapMaybe ppSuccessor blocks
+           newPoint  = listToMaybe newPoints 
+           ppSuccessor b@(Block bid _ _) =
+               let nreached id = case lookupBlockEnv env id `orElse`
+                                       pprPanic "no ppt" (ppr id <+> ppr b) of
                                    ProcPoint -> 1
-                                   ReachedBy ps -> sizeUniqSet ps
-                   my_nreached = nreached id
+                                   ReachedBy ps -> sizeBlockSet ps
+                   block_procpoints = nreached bid
                    -- | Looking for a successor of b that is reached by
                    -- more proc points than b and is not already a proc
                    -- point.  If found, it can become a proc point.
                    newId succ_id = not (elemBlockSet succ_id procPoints') &&
-                                   nreached succ_id > my_nreached
+                                   nreached succ_id > block_procpoints
                in  listToMaybe $ filter newId $ succs b
+{-
+       case newPoints of
+           []  -> return procPoints'
+           pps -> extendPPSet g blocks
+                    (foldl extendBlockSet procPoints' pps)
+-}
        case newPoint of Just id ->
                           if elemBlockSet id procPoints' then panic "added old proc pt"
                           else extendPPSet g blocks (extendBlockSet procPoints' id)
 addProcPointProtocols :: ProcPointSet -> ProcPointSet -> CmmGraph -> FuelMonad CmmGraph
 addProcPointProtocols callPPs procPoints g =
   do liveness <- cmmLivenessZ g
-     (protos, g') <- return $ optimize_calls liveness g
+     (protos, g') <- optimize_calls liveness g
      blocks'' <- add_CopyOuts protos procPoints g'
      return $ LGraph (lg_entry g) (lg_argoffset g) blocks''
     where optimize_calls liveness g =  -- see Note [Separate Adams optimization]
-              let (protos, blocks') =
-                      fold_blocks maybe_add_call (init_protocols, emptyBlockEnv) g
-                  protos' = add_unassigned liveness procPoints protos
-                  g'  = LGraph (lg_entry g) (lg_argoffset g) $
-                               add_CopyIns callPPs protos' blocks'
-              in  (protos', runTx removeUnreachableBlocksZ g')
+            do let (protos, blocks') =
+                       fold_blocks maybe_add_call (init_protocols, emptyBlockEnv) g
+                   protos' = add_unassigned liveness procPoints protos
+               blocks <- add_CopyIns callPPs protos' blocks'
+               let g' = LGraph (lg_entry g) (lg_argoffset g)
+                               (mkBlockEnv (map withKey (concat blocks)))
+                   withKey b@(Block bid _ _) = (bid, b)
+               return (protos', runTx removeUnreachableBlocksZ g')
           maybe_add_call :: CmmBlock -> (BlockEnv Protocol, BlockEnv CmmBlock)
                          -> (BlockEnv Protocol, BlockEnv CmmBlock)
           -- ^ If the block is a call whose continuation goes to a proc point
           -- redirect the call (cf 'newblock') and set the protocol if necessary
           maybe_add_call block (protos, blocks) =
               case goto_end $ unzip block of
-                (h, LastOther (LastCall tgt (Just k) s))
+                (h, LastOther (LastCall tgt (Just k) u s))
                     | Just proto <- lookupBlockEnv protos k,
                       Just pee   <- branchesToProcPoint k
-                    -> let newblock = zipht h (tailOfLast (LastCall tgt (Just pee) s))
+                    -> let newblock = zipht h (tailOfLast (LastCall tgt (Just pee) u s))
                            changed_blocks   = insertBlock newblock blocks
                            unchanged_blocks = insertBlock block    blocks
                        in case lookupBlockEnv protos pee of
           -- ^ Tells whether the named block is just a branch to a proc point
           branchesToProcPoint id =
               let (Block _ _ t) = lookupBlockEnv (lg_blocks g) id `orElse`
-                                  panic "branch out of graph"
+                                    panic "branch out of graph"
               in case t of
                    ZLast (LastOther (LastBranch pee))
                        | elemBlockSet pee procPoints -> Just pee
 pass_live_vars_as_args :: BlockEnv CmmLive -> ProcPointSet ->
                           BlockEnv Protocol -> BlockEnv Protocol
 pass_live_vars_as_args _liveness procPoints protos = protos'
-  where protos' = foldUniqSet addLiveVars protos procPoints
+  where protos' = foldBlockSet addLiveVars protos procPoints
         addLiveVars :: BlockId -> BlockEnv Protocol -> BlockEnv Protocol
         addLiveVars id protos =
             case lookupBlockEnv protos id of
               Just _  -> protos
-              Nothing -> let live = emptyBlockEnv
+              Nothing -> let live = emptyRegSet
                                     --lookupBlockEnv _liveness id `orElse`
                                     --panic ("no liveness at block " ++ show id)
                              formals = uniqSetToList live
 -- | Add copy-in instructions to each proc point that did not arise from a call
 -- instruction. (Proc-points that arise from calls already have their copy-in instructions.)
 
-add_CopyIns :: ProcPointSet -> BlockEnv Protocol -> BlockEnv CmmBlock -> BlockEnv CmmBlock
-add_CopyIns callPPs protos blocks = mapUFM maybe_insert_CopyIns blocks
-    where maybe_insert_CopyIns :: CmmBlock -> CmmBlock
-          maybe_insert_CopyIns b@(Block id off t) | not $ elementOfUniqSet id callPPs =
-            case (off, lookupBlockEnv protos id) of
-              (Just _, _) -> panic "shouldn't copy arguments twice into a block"
-              (_, Just (Protocol c fs area)) -> Block id (Just off) $ foldr ZTail t copies
-                where (off, copies) = copyIn c False area fs
-              (_, Nothing) -> b
-          maybe_insert_CopyIns b = b
+add_CopyIns :: ProcPointSet -> BlockEnv Protocol -> BlockEnv CmmBlock ->
+               FuelMonad [[CmmBlock]]
+add_CopyIns callPPs protos blocks =
+  liftUniq $ mapM maybe_insert_CopyIns (blockEnvToList blocks)
+    where maybe_insert_CopyIns (_, b@(Block id stackInfo t))
+           | not $ elemBlockSet id callPPs
+           = case (argBytes stackInfo, lookupBlockEnv protos id) of
+               (Just _, _) -> panic "shouldn't copy arguments twice into a block"
+               (_, Just (Protocol c fs area)) ->
+                 do let (off, copies) = copyIn c False area fs
+                        stackInfo' = stackInfo {argBytes = Just off}
+                    LGraph _ _ blocks <-
+                      lgraphOfAGraph 0 (mkLabel id stackInfo' <*>
+                      copies <*> mkZTail t)
+                    return (map snd $ blockEnvToList blocks)
+               (_, Nothing) -> return [b]
+           | otherwise = return [b]
 
 -- | Add a CopyOut node before each procpoint.
 -- If the predecessor is a call, then the copy outs should already be done by the callee.
           mb_copy_out b@(Block bid _ _) z | bid == lg_entry g = skip b z 
           mb_copy_out b z =
             case last $ unzip b of
-              LastOther (LastCall _ _ _) -> skip b z -- copy out done by callee
+              LastOther (LastCall _ _ _ _) -> skip b z -- copy out done by callee
               _ -> mb_copy_out' b z
           mb_copy_out' b z = fold_succs trySucc b init >>= finish
             where init = z >>= (\bmap -> return (b, bmap))
                       case lookupBlockEnv protos succId of
                         Nothing -> z
                         Just (Protocol c fs area) ->
-                          let (_, copies) = copyOut c Jump area $ map (CmmReg . CmmLocal) fs
+                          let (_, copies) =
+                                copyOut c Jump area (map (CmmReg . CmmLocal) fs) 0
                           in  insert z succId copies
                     else z
                   insert z succId m =
 --    the SRTs in the entry procedure as well.
 -- Input invariant: A block should only be reachable from a single ProcPoint.
 splitAtProcPoints :: CLabel -> ProcPointSet-> ProcPointSet -> BlockEnv Status ->
-                     BlockEnv SubAreaSet -> AreaMap -> CmmTopZ -> FuelMonad [CmmTopZ]
-splitAtProcPoints entry_label callPPs procPoints procMap slotEnv areaMap
-                  (CmmProc top_info top_l top_args g@(LGraph entry e_off blocks)) =
+                     AreaMap -> CmmTopZ -> FuelMonad [CmmTopZ]
+splitAtProcPoints entry_label callPPs procPoints procMap areaMap
+                  (CmmProc (CmmInfo gc upd_fr info_tbl) top_l top_args
+                           g@(LGraph entry e_off blocks)) =
   do -- Build a map from procpoints to the blocks they reach
      let addBlock b@(Block bid _ _) graphEnv =
            case lookupBlockEnv procMap bid of
              Just ProcPoint -> add graphEnv bid bid b
              Just (ReachedBy set) ->
-               case uniqSetToList set of
+               case blockSetToList set of
                  []   -> graphEnv
                  [id] -> add graphEnv id bid b 
-                 _ -> panic "Each block should be reachable from only one ProcPoint"
+                 _    -> panic "Each block should be reachable from only one ProcPoint"
              Nothing -> pprPanic "block not reached by a proc point?" (ppr bid)
          add graphEnv procId bid b = extendBlockEnv graphEnv procId graph'
                where graph  = lookupBlockEnv graphEnv procId `orElse` emptyBlockEnv
                      graph' = extendBlockEnv graph bid b
-     graphEnv <- return $ fold_blocks addBlock emptyBlockEnv g
+     graphEnv_pre <- return $ fold_blocks addBlock emptyBlockEnv g
+     graphEnv <- return $ pprTrace "graphEnv" (ppr graphEnv_pre) graphEnv_pre
      -- Build a map from proc point BlockId to labels for their new procedures
      let add_label map pp = return $ addToFM map pp lbl
            where lbl = if pp == entry then entry_label else blockLbl pp
-     procLabels <- foldM add_label emptyFM (uniqSetToList procPoints)
-     -- Convert call and return instructions to jumps.
-     let last (LastCall e _ n) = LastJump e n
-         last l = l
-     graphEnv <- return $ mapUFM (mapUFM (map_one_block id id last)) graphEnv
+     -- Due to common blockification, we may overestimate the set of procpoints.
+     procLabels <- foldM add_label emptyFM
+                         (filter (elemBlockEnv blocks) (blockSetToList procPoints))
      -- In each new graph, add blocks jumping off to the new procedures,
      -- and replace branches to procpoints with branches to the jump-off blocks
      let add_jump_block (env, bs) (pp, l) =
            do bid <- liftM mkBlockId getUniqueM
-              let b = Block bid Nothing (ZLast (LastOther jump))
-                  argSpace = case lookupBlockEnv blocks pp of
-                               Just (Block _ (Just s) _) -> s
-                               Just (Block _ Nothing  _) -> panic "no args at procpoint"
-                               _ -> panic "can't find procpoint block"
-                  jump = LastJump (CmmLit (CmmLabel l)) argSpace
-              return $ (extendBlockEnv env pp bid, b : bs)
-         add_jumps newGraphEnv (guniq, blockEnv) =
-           do (jumpEnv, jumpBlocks) <- foldM add_jump_block (emptyBlockEnv, [])
-                                           $ fmToList procLabels
-              let ppId = mkBlockId guniq
-                  (b_off, b) =
-                    case lookupBlockEnv blockEnv ppId of
-                      Just (Block id (Just b_off) t) -> (b_off, Block id Nothing t)
-                      Just b@(Block _ Nothing _)     -> (0, b)
+              let b = Block bid emptyStackInfo (ZLast (LastOther jump))
+                  argSpace =
+                    case lookupBlockEnv blocks pp of
+                      Just (Block _ (StackInfo {argBytes = Just s}) _) -> s
+                      Just (Block _ _ _) -> panic "no args at procpoint"
+                      _ -> panic "can't find procpoint block"
+                  jump = LastCall (CmmLit (CmmLabel l')) Nothing argSpace Nothing
+                  l' = if elemBlockSet pp callPPs then entryLblToInfoLbl l else l
+              return (extendBlockEnv env pp bid, b : bs)
+         add_jumps (newGraphEnv) (ppId, blockEnv) =
+           do (jumpEnv, jumpBlocks) <-
+                 foldM add_jump_block (emptyBlockEnv, []) (fmToList procLabels)
+              let (b_off, b) = -- get the stack offset on entry into the block and
+                               -- remove the offset from the block (it goes in new graph)
+                    case lookupBlockEnv blockEnv ppId of -- get the procpoint block
+                      Just (Block id sinfo@(StackInfo {argBytes = Just b_off}) t) ->
+                        (b_off, Block id (sinfo {argBytes = Nothing}) t)
+                      Just b@(Block _ _ _) -> (0, b)
                       Nothing -> panic "couldn't find entry block while splitting"
+                  blockEnv' = extendBlockEnv blockEnv ppId b
                   off = if ppId == entry then e_off else b_off
-                  LGraph _ _ blockEnv' = pprTrace "jumpEnv" (ppr jumpEnv) $
-                                         replaceLabelsZ jumpEnv $ LGraph ppId off blockEnv
-                  blockEnv'' = foldl (flip insertBlock) (extendBlockEnv blockEnv' ppId b)
-                                     jumpBlocks
-              return $ extendBlockEnv newGraphEnv ppId $
-                       runTx cmmCfgOptsZ $ LGraph ppId off blockEnv''
-         upd_info_tbl srt' (CmmInfoTable p t typeinfo) = CmmInfoTable p t typeinfo'
-           where typeinfo' = case typeinfo of
-                   t@(ConstrInfo _ _ _)    -> t
-                   (FunInfo    c _ a d e)  -> FunInfo c srt' a d e
-                   (ThunkInfo  c _)        -> ThunkInfo c srt'
-                   (ThunkSelectorInfo s _) -> ThunkSelectorInfo s srt'
-                   (ContInfo vars _)       -> ContInfo vars srt'
-         upd_info_tbl _ CmmNonInfoTable = CmmNonInfoTable 
-         to_proc cafMap (ppUniq, g) | elementOfUniqSet bid callPPs =
+                  LGraph _ _ blockEnv'' = 
+                    replaceBranches jumpEnv $ LGraph ppId off blockEnv'
+                  blockEnv''' = foldl (flip insertBlock) blockEnv'' jumpBlocks
+              let g' = LGraph ppId off blockEnv'''
+              pprTrace "g' pre jumps" (ppr g') $
+               return (extendBlockEnv newGraphEnv ppId g')
+     graphEnv_pre <- foldM add_jumps emptyBlockEnv $ blockEnvToList graphEnv
+     graphEnv <- return $ pprTrace "graphEnv with jump blocks" (ppr graphEnv_pre)
+                                         graphEnv_pre
+     let to_proc (bid, g@(LGraph g_entry _ blocks)) | elemBlockSet bid callPPs =
            if bid == entry then 
-             CmmProc (CmmInfo gc upd_fr (upd_info_tbl srt' info_tbl)) top_l top_args g
+             CmmProc (CmmInfo gc upd_fr info_tbl) top_l top_args g
            else
-            pprTrace "adding infotable for" (ppr bid) $
-             CmmProc (CmmInfo Nothing Nothing $ infoTbl) lbl [] g
-           where bid = mkBlockId ppUniq
-                 lbl = expectJust "pp label" $ lookupFM procLabels bid
-                 infoTbl = CmmInfoTable (ProfilingInfo zero zero) rET_SMALL
-                                        (ContInfo stack_vars srt')
-                 stack_vars = pprTrace "slotEnv" (ppr slotEnv) $
-                               live_vars slotEnv areaMap bid
-                 zero = CmmInt 0 wordWidth
-                 srt' = expectJust "procpoint.infoTbl" $ lookupBlockEnv cafMap bid
-                 CmmInfo gc upd_fr info_tbl = top_info
-         to_proc _ (ppUniq, g) =
-          pprTrace "not adding infotable for" (ppr bid) $
+             CmmProc emptyContInfoTable lbl [] g
+           where lbl = expectJust "pp label" $ lookupFM procLabels bid
+         to_proc (bid, g) =
            CmmProc (CmmInfo Nothing Nothing CmmNonInfoTable) lbl [] g
-             where bid = mkBlockId ppUniq
-                   lbl = expectJust "pp label" $ lookupFM procLabels bid
-     graphEnv <- foldM add_jumps emptyBlockEnv $ ufmToList graphEnv
-     cafEnv <- cafAnal g
-     (cafTable, blockCafs) <- buildCafs cafEnv
-     procs <- return $ map (to_proc blockCafs) $ ufmToList graphEnv
-     return $ pprTrace "procLabels" (ppr procLabels) $
-              pprTrace "splitting graphs" (ppr graphEnv) $ cafTable ++ procs
-splitAtProcPoints _ _ _ _ _ _ t@(CmmData _ _) = return [t]
-
-------------------------------------------------------------------------
---                    Stack Layout                                    --
-------------------------------------------------------------------------
-
--- | Before we lay out the stack, we need to know something about the
--- liveness of the stack slots. In particular, to decide whether we can
--- reuse a stack location to hold multiple stack slots, we need to know
--- when each of the stack slots is used.
--- Although tempted to use something simpler, we really need a full interference
--- graph. Consider the following case:
---   case <...> of
---     1 -> <spill x>; // y is dead out
---     2 -> <spill y>; // x is dead out
---     3 -> <spill x and y>
--- If we consider the arms in order and we use just the deadness information given by a
--- dataflow analysis, we might decide to allocate the stack slots for x and y
--- to the same stack location, which will lead to incorrect code in the third arm.
--- We won't make this mistake with an interference graph.
-
--- First, the liveness analysis.
--- We represent a slot with an area, an offset into the area, and a width.
--- Tracking the live slots is a bit tricky because there may be loads and stores
--- into only a part of a stack slot (e.g. loading the low word of a 2-word long),
--- e.g. Slot A 0 8 overlaps with Slot A 4 4.
---
--- The definition of a slot set is intended to reduce the number of overlap
--- checks we have to make. There's no reason to check for overlap between
--- slots in different areas, so we segregate the map by Area's.
--- We expect few slots in each Area, so we collect them in an unordered list.
--- To keep these lists short, any contiguous live slots are coalesced into
--- a single slot, on insertion.
-
-type SubAreaSet   = FiniteMap Area [SubArea]
-fold_subareas :: (SubArea -> z -> z) -> SubAreaSet -> z -> z
-fold_subareas f m z = foldFM (\_ s z -> foldr (\a z -> f a z) z s) z m
-
-liveGen :: SubArea -> [SubArea] -> (Bool, [SubArea])
-liveGen s set = liveGen' s set []
-  where liveGen' s [] z = (True, s : z)
-        liveGen' s@(a, hi, w) (s'@(a', hi', w') : rst) z =
-          if a /= a' || hi < lo' || lo > hi' then    -- no overlap
-            liveGen' s rst (s' : z)
-          else if s' `contains` s then               -- old contains new
-            (False, set)
-          else                                       -- overlap: coalesce the slots
-            let new_hi = max hi hi'
-                new_lo = min lo lo'
-            in liveGen' (a, new_hi, new_hi - new_lo) rst z
-          where lo  = hi  - w  -- remember: areas grow down
-                lo' = hi' - w'
-        contains (a, hi, w) (a', hi', w') =
-          a == a' && hi >= hi' && hi - w <= hi' - w'
-
-liveKill :: SubArea -> [SubArea] -> [SubArea]
-liveKill (a, hi, w) set = pprTrace "killing slots in area" (ppr a) $ liveKill' set []
-  where liveKill' [] z = z
-        liveKill' (s'@(a', hi', w') : rst) z =
-          if a /= a' || hi < lo' || lo > hi' then    -- no overlap
-            liveKill' rst (s' : z)
-          else                                       -- overlap: split the old slot
-            let z'  = if hi' > hi  then (a, hi', hi' - hi)  : z else z
-                z'' = if lo  > lo' then (a, lo,  lo  - lo') : z' else z'
-            in liveKill' rst z''
-          where lo  = hi  - w  -- remember: areas grow down
-                lo' = hi' - w'
-
-slotLattice :: DataflowLattice SubAreaSet
-slotLattice = DataflowLattice "live slots" emptyFM add True
-  where add new old = case foldFM addArea (False, old) new of
-                        (True,  x) -> aTx  x
-                        (False, x) -> noTx x
-        addArea a newSlots z = foldr (addSlot a) z newSlots
-        addSlot a slot (changed, map) =
-          let (c, live) = liveGen slot $ lookupWithDefaultFM map [] a
-          in (c || changed, addToFM map a live)
-
-liveInSlots :: (DefinerOfSlots s, UserOfSlots s) => SubAreaSet -> s -> SubAreaSet
-liveInSlots live x = foldSlotsUsed add (foldSlotsDefd remove live x) x
-  where add    live (a, i, w) = liftToArea a (snd . liveGen  (a, i, w)) live
-        remove live (a, i, w) = liftToArea a       (liveKill (a, i, w)) live
-        liftToArea a f map = addToFM map a $ f (lookupWithDefaultFM map [] a)
-
--- Unlike the liveness transfer functions @gen@ and @kill@, this function collects
--- _any_ slot that is named.
---addNamedSlots :: (DefinerOfSlots s, UserOfSlots s) => SubAreaSet -> s -> SubAreaSet
---addNamedSlots live x = foldSlotsUsed add (foldSlotsDefd add live x) x
---  where add    live (a, i, w) = liftToArea a (snd . liveGen  (a, i, w)) live
---        liftToArea a f map = addToFM map a $ f (lookupWithDefaultFM map [] a)
-
--- Note: the stack slots that hold variables returned on the stack are not
--- considered live in to the block -- we treat the first node as a definition site.
--- BEWARE: I'm being a little careless here in failing to check for the
--- entry Id (which would use the CallArea Old).
-liveTransfers :: BackwardTransfers Middle Last SubAreaSet
-liveTransfers = BackwardTransfers first liveInSlots liveLastIn
-    where first live id = delFromFM live (CallArea (Young id))
-
-liveLastIn :: (BlockId -> SubAreaSet) -> Last -> SubAreaSet
-liveLastIn env l = liveInSlots (liveLastOut env l) l
-
--- Don't forget to keep the outgoing parameters in the CallArea live.
-liveLastOut :: (BlockId -> SubAreaSet) -> Last -> SubAreaSet
-liveLastOut env l =
-  case l of
-    LastReturn n          -> add_area (CallArea Old)       n out
-    LastJump _ n          -> add_area (CallArea Old)       n out
-    LastCall _ Nothing  n -> add_area (CallArea Old)       n out
-    LastCall _ (Just k) n -> add_area (CallArea (Young k)) n out
-    _                     -> out
-  where out = joinOuts slotLattice env l
-add_area :: Area -> Int -> SubAreaSet -> SubAreaSet
-add_area a n live =
-  addToFM live a $ snd $ liveGen (a, n, n) $ lookupWithDefaultFM live [] a
-
-type SlotFix a = FuelMonad (BackwardFixedPoint Middle Last SubAreaSet a)
-liveSlotAnal :: LGraph Middle Last -> FuelMonad (BlockEnv SubAreaSet)
-liveSlotAnal g = liftM zdfFpFacts (res :: SlotFix ())
-  where res = zdfSolveFromL emptyBlockEnv "live slot analysis" slotLattice
-                            liveTransfers (fact_bot slotLattice) g
-
--- The liveness analysis must be precise: otherwise, we won't know if a definition
--- should really kill a live-out stack slot.
--- But the interference graph does not have to be precise -- it might decide that
--- any live areas interfere. To maintain both a precise analysis and an imprecise
--- interference graph, we need to convert the live-out stack slots to graph nodes
--- at each and every instruction; rather than reconstruct a new list of nodes
--- every time, I provide a function to fold over the nodes, which should be a
--- reasonably efficient approach for the implementations we envision.
--- Of course, it will probably be much easier to program if we just return a list...
-type Set x = FiniteMap x ()
-type AreaMap = FiniteMap Area Int
-data IGraphBuilder n =
-  Builder { foldNodes     :: forall z. SubArea -> (n -> z -> z) -> z -> z
-          , _wordsOccupied :: AreaMap -> AreaMap -> n -> [Int]
-          }
-
-areaBuilder :: IGraphBuilder Area
-areaBuilder = Builder fold words
-  where fold (a, _, _) f z = f a z
-        words areaSize areaMap a =
-          case lookupFM areaMap a of
-            Just addr -> [addr .. addr + (lookupFM areaSize a `orElse`
-                                          pprPanic "wordsOccupied: unknown area" (ppr a))]
-            Nothing   -> []
-
---slotBuilder :: IGraphBuilder (Area, Int)
---slotBuilder = undefined
-
--- Now, we can build the interference graph.
--- The usual story: a definition interferes with all live outs and all other
--- definitions.
-type IGraph x = FiniteMap x (Set x)
-type IGPair x = (IGraph x, IGraphBuilder x)
-igraph :: (Ord x) => IGraphBuilder x -> BlockEnv SubAreaSet -> LGraph Middle Last -> IGraph x
-igraph builder env g = foldr interfere emptyFM (postorder_dfs g)
-  where foldN = foldNodes builder
-        interfere block igraph =
-          let (h, l) = goto_end (unzip block)
-              --heads :: ZHead Middle -> (IGraph x, SubAreaSet) -> IGraph x
-              heads (ZFirst _ _) (igraph, _)       = igraph
-              heads (ZHead h m)  (igraph, liveOut) =
-                heads h (addEdges igraph m liveOut, liveInSlots liveOut m)
-              -- add edges between a def and the other defs and liveouts
-              addEdges igraph i out = fst $ foldSlotsDefd addDef (igraph, out) i
-              addDef (igraph, out) def@(a, _, _) =
-                (foldN def (addDefN out) igraph,
-                 addToFM out a (snd $ liveGen def (lookupWithDefaultFM out [] a)))
-              addDefN out n igraph =
-                let addEdgeNO o igraph = foldN o addEdgeNN igraph
-                    addEdgeNN n' igraph = addEdgeNN' n n' $ addEdgeNN' n' n igraph
-                    addEdgeNN' n n' igraph = addToFM igraph n (addToFM set n' ())
-                      where set = lookupWithDefaultFM igraph emptyFM n
-                in foldFM (\ _ os igraph -> foldr addEdgeNO igraph os) igraph out
-              env' bid = lookupBlockEnv env bid `orElse` panic "unknown blockId in igraph"
-          in heads h $ case l of LastExit    -> (igraph, emptyFM)
-                                 LastOther l -> (addEdges igraph l $ liveLastOut env' l,
-                                                 liveLastIn env' l)
-
--- Before allocating stack slots, we need to collect one more piece of information:
--- what's the highest offset (in bytes) used in each Area?
--- We'll need to allocate that much space for each Area.
-getAreaSize :: LGraph Middle Last -> AreaMap
-getAreaSize g@(LGraph _ off _) =
-  fold_blocks (fold_fwd_block first add add) (unitFM (CallArea Old) off) g
-  where first _ z = z
-        add   x z = foldSlotsUsed addSlot (foldSlotsDefd addSlot z x) x
-        addSlot z (a, off, _) = addToFM z a $ max off $ lookupWithDefaultFM z 0 a
-
-
--- Find the Stack slots occupied by the subarea's conflicts
-conflictSlots :: Ord x => IGPair x -> AreaMap -> AreaMap -> SubArea -> Set Int
-conflictSlots (ig, Builder foldNodes wordsOccupied) areaSize areaMap subarea =
-  foldNodes subarea foldNode emptyFM
-  where foldNode n set = foldFM conflict set $ lookupWithDefaultFM ig emptyFM n
-        conflict n' () set = liveInSlots areaMap n' set
-        -- Add stack slots occupied by igraph node n
-        liveInSlots areaMap n set = foldr setAdd set (wordsOccupied areaSize areaMap n)
-        setAdd w s = addToFM s w ()
-
--- Find any open space on the stack, starting from the offset.
-freeSlotFrom :: Ord x => IGPair x -> AreaMap -> Int -> AreaMap -> Area -> Int
-freeSlotFrom ig areaSize offset areaMap area =
-  let size = lookupFM areaSize area `orElse` 0
-      conflicts = conflictSlots ig areaSize areaMap (area, size, size)
-      -- Find a space big enough to hold the area
-      findSpace curr 0 = curr
-      findSpace curr cnt = -- target slot, considerand, # left to check
-        if elemFM curr conflicts then
-          findSpace (curr + size) size
-        else findSpace (curr - 1) (cnt - 1)
-  in findSpace (offset + size) size
-
--- Find an open space on the stack, and assign it to the area.
-allocSlotFrom :: Ord x => IGPair x -> AreaMap -> Int -> AreaMap -> Area -> AreaMap
-allocSlotFrom ig areaSize from areaMap area =
-  if elemFM area areaMap then areaMap
-  else addToFM areaMap area $ freeSlotFrom ig areaSize from areaMap area
-
--- | Greedy stack layout.
--- Compute liveness, build the interference graph, and allocate slots for the areas.
--- We visit each basic block in a (generally) forward order.
--- At each instruction that names a register subarea r, we immediately allocate
--- any available slot on the stack by the following procedure:
---  1. Find the nodes N' that conflict with r
---  2. Find the stack slots used for N'
---  3. Choose a contiguous stack space s not in N' (s must be large enough to hold r)
--- For a CallArea, we allocate the stack space only when we reach a function
--- call that returns to the CallArea's blockId.
--- We use a similar procedure, with one exception: the stack space
--- must be allocated below the youngest stack slot that is live out.
-
--- Note: The stack pointer only has to be younger than the youngest live stack slot
--- at proc points. Otherwise, the stack pointer can point anywhere.
-layout :: ProcPointSet -> BlockEnv SubAreaSet -> LGraph Middle Last -> AreaMap
-layout procPoints env g@(LGraph _ entrySp _) =
-  let builder = areaBuilder
-      ig = (igraph builder env g, builder)
-      env' bid = lookupBlockEnv env bid `orElse` panic "unknown blockId in igraph"
-      areaSize = getAreaSize g
-      -- Find the slots that are live-in to the block
-      live_in (ZTail m l) = liveInSlots (live_in l) m
-      live_in (ZLast (LastOther l)) = liveLastIn env' l
-      live_in (ZLast LastExit) = emptyFM 
-      -- Find the youngest live stack slot
-      youngest_live areaMap live = fold_subareas young_slot live 0
-        where young_slot (a, o, _) z = case lookupFM areaMap a of
-                                         Just top -> max z $ top + o
-                                         Nothing  -> z
-      -- Allocate space for spill slots and call areas
-      allocVarSlot = allocSlotFrom ig areaSize 0
-      allocCallSlot areaMap (Block id _ t) | elemBlockSet id procPoints =
-        allocSlotFrom ig areaSize (youngest_live areaMap $ live_in t)
-                      areaMap (CallArea (Young id))
-      allocCallSlot areaMap _ = areaMap
-      alloc i areaMap = foldSlotsDefd alloc' (foldSlotsUsed alloc' areaMap i) i
-        where alloc' areaMap (a@(RegSlot _), _, _) = allocVarSlot areaMap a
-              alloc' areaMap _ = areaMap
-      layoutAreas areaMap b@(Block _ _ t) = layout areaMap t
-        where layout areaMap (ZTail m t) = layout (alloc m areaMap) t
-              layout areaMap (ZLast _) = allocCallSlot areaMap b
-      areaMap = foldl layoutAreas (addToFM emptyFM (CallArea Old) 0) $ postorder_dfs g
-  in pprTrace "ProcPoints" (ppr procPoints) $
-       pprTrace "Area SizeMap" (ppr areaSize) $
-         pprTrace "Entry SP" (ppr entrySp) $
-           pprTrace "Area Map" (ppr areaMap) $ areaMap
-
--- After determining the stack layout, we can:
--- 1. Replace references to stack Areas with addresses relative to the stack
---    pointer.
--- 2. Insert adjustments to the stack pointer to ensure that it is at a
---    conventional location at each proc point.
---    Because we don't take interrupts on the execution stack, we only need the
---    stack pointer to be younger than the live values on the stack at proc points.
--- 3. At some point, we should check for stack overflow, but not just yet.
-manifestSP :: ProcPointSet -> BlockEnv Status -> AreaMap ->
-                LGraph Middle Last -> FuelMonad (LGraph Middle Last)
-manifestSP procPoints procMap areaMap g@(LGraph entry args blocks) =
-  liftM (LGraph entry args) blocks'
-  where blocks' = foldl replB (return emptyBlockEnv) (postorder_dfs g)
-        slot a = pprTrace "slot" (ppr a) $ lookupFM areaMap a `orElse` panic "unallocated Area"
-        slot' id = pprTrace "slot'" (ppr id)$ slot $ CallArea (Young id)
-        sp_on_entry id | id == entry = slot (CallArea Old) + args
-        sp_on_entry id | elemBlockSet id procPoints =
-          case lookupBlockEnv blocks id of
-            Just (Block _ (Just o) _) -> slot' id + o
-            Just (Block _ Nothing  _) -> slot' id
-            Nothing -> panic "procpoint dropped from block env"
-        sp_on_entry id =
-          case lookupBlockEnv procMap id of
-            Just (ReachedBy pp) -> case uniqSetToList pp of
-                                     [id] -> sp_on_entry id
-                                     _    -> panic "block not reached by single proc point"
-            Just ProcPoint -> panic "procpoint not in procpoint set"
-            Nothing -> panic "block not found in procmap"
-        -- On entry to procpoints, the stack pointer is conventional;
-        -- otherwise, we check the SP set by predecessors.
-        replB :: FuelMonad (BlockEnv CmmBlock) -> CmmBlock -> FuelMonad (BlockEnv CmmBlock)
-        replB blocks (Block id o t) =
-          do bs <- replTail (Block id o) spIn t
-             pprTrace "spIn" (ppr id <+> ppr spIn)$ liftM (flip (foldr insertBlock) bs) blocks
-          where spIn = sp_on_entry id
-        replTail :: (ZTail Middle Last -> CmmBlock) -> Int -> (ZTail Middle Last) -> 
-                    FuelMonad ([CmmBlock])
-        replTail h spOff (ZTail m t) = replTail (h . ZTail (middle spOff m)) spOff t
-        replTail h spOff (ZLast (LastOther l)) = fixSp h spOff l
-        replTail h _   l@(ZLast LastExit) = return [h l]
-        middle spOff m = mapExpDeepMiddle (replSlot spOff) m
-        last   spOff l = mapExpDeepLast   (replSlot spOff) l
-        replSlot spOff (CmmStackSlot a i) = CmmRegOff (CmmGlobal Sp) (spOff - (slot a + i))
-        replSlot _ e = e
-        -- The block must establish the SP expected at each successsor.
-        fixSp :: (ZTail Middle Last -> CmmBlock) -> Int -> Last -> FuelMonad ([CmmBlock])
-        fixSp h spOff l@(LastReturn n)          = updSp h spOff (slot (CallArea Old) + n) l
-        fixSp h spOff l@(LastJump _ n)          = updSp h spOff (slot (CallArea Old) + n) l
-        fixSp h spOff l@(LastCall _ (Just k) n) = updSp h spOff (slot' k + n)             l
-        fixSp h spOff l@(LastCall _ Nothing  n) = updSp h spOff (slot (CallArea Old) + n) l
-        fixSp h spOff l@(LastBranch k) | elemBlockSet k procPoints =
-          pprTrace "updSp" (ppr k <> ppr spOff <> ppr (sp_on_entry k)) $ updSp h spOff (sp_on_entry k) l
-        fixSp h spOff l = liftM (uncurry (:)) $ fold_succs succ l $ return (b, [])
-          where b = h (ZLast (LastOther (last spOff l)))
-                succ succId z =
-                  let succSp = sp_on_entry succId in
-                  if elemBlockSet succId procPoints && succSp /= spOff then
-                    do (b,  bs)  <- z
-                       (b', bs') <- insertBetween b [setSpMid spOff succSp] succId
-                       return (b', bs ++ bs')
-                  else z
-        updSp h old new l = return [h $ setSp old new $ ZLast $ LastOther (last new l)]
-        setSpMid sp sp' = MidAssign (CmmGlobal Sp) e
-          where e = CmmMachOp (MO_Add wordWidth) [CmmReg (CmmGlobal Sp), off]
-                off = CmmLit $ CmmInt (toInteger $ sp - sp') wordWidth
-        setSp sp sp' t = if sp == sp' then t else ZTail (setSpMid sp sp') t
-
-----------------------------------------------------------------
--- Building InfoTables
-
-type CAFSet = FiniteMap CLabel ()
-
--- First, an analysis to find live CAFs.
-cafLattice :: DataflowLattice CAFSet
-cafLattice = DataflowLattice "live cafs" emptyFM add True
-  where add new old = if sizeFM new' > sizeFM old then aTx new' else noTx new'
-          where new' = new `plusFM` old
-
-cafTransfers :: BackwardTransfers Middle Last CAFSet
-cafTransfers = BackwardTransfers first middle last
-    where first  live _ = live
-          middle live m = pprTrace "cafmiddle" (ppr m) $ foldExpDeepMiddle addCaf m live
-          last   env  l = foldExpDeepLast addCaf l (joinOuts cafLattice env l)
-          addCaf e set = case e of
-                 CmmLit (CmmLabel c) -> add c set
-                 CmmLit (CmmLabelOff c _) -> add c set
-                 CmmLit (CmmLabelDiffOff c1 c2 _) -> add c1 $ add c2 set
-                 _ -> set
-          add c s = pprTrace "CAF analysis saw label" (ppr c) $
-                     if hasCAF c then (pprTrace "has caf" (ppr c) $ addToFM s c ()) else (pprTrace "no cafs" (ppr c) $ s)
-
-type CafFix a = FuelMonad (BackwardFixedPoint Middle Last CAFSet a)
-cafAnal :: LGraph Middle Last -> FuelMonad (BlockEnv CAFSet)
-cafAnal g = liftM zdfFpFacts (res :: CafFix ())
-  where res = zdfSolveFromL emptyBlockEnv "live CAF analysis" cafLattice
-                            cafTransfers (fact_bot cafLattice) g
-
--- Once we have found the CAFs, we need to do two things:
--- 1. Build a table of all the CAFs used in the procedure.
--- 2. Compute the C_SRT describing the subset of CAFs live at each procpoint.
-buildCafs :: (BlockEnv CAFSet) -> FuelMonad ([CmmTopZ], BlockEnv C_SRT)
-buildCafs blockCafs =
-  -- This is surely the wrong way to get names, as in BlockId
-  do top_lbl <- getUniqueM >>= \ u -> return $ mkSRTLabel (mkFCallName u "srt") MayHaveCafRefs
-     let allCafs = foldBlockEnv (\_ x y -> plusFM x y) emptyFM blockCafs
-         caf_entry (ix, map, tbl') caf = (ix + 1, addToFM map caf ix, entry : tbl')
-           where entry = CmmStaticLit $ CmmLabel caf
-         (_::Int, cafMap, tbl') = foldl caf_entry (0, emptyFM, []) $ keysFM allCafs
-         top_tbl = CmmData RelocatableReadOnlyData $ CmmDataLabel top_lbl : reverse tbl'
-         sub_srt id cafs z =
-           do (tbls, blocks) <- z
-              (top, srt)     <- procpointSRT top_lbl cafMap cafs
-              let blocks' = extendBlockEnv blocks id srt
-              case top of Just t  -> return (t:tbls, blocks')
-                          Nothing -> return (tbls,   blocks')
-     (sub_tbls, blockSRTs) <- foldBlockEnv sub_srt (return ([], emptyBlockEnv)) blockCafs
-     return (top_tbl :  sub_tbls, blockSRTs) 
-
--- Construct an SRT bitmap.
--- Adapted from simpleStg/SRT.lhs, which expects Id's.
-procpointSRT :: CLabel -> FiniteMap CLabel Int -> FiniteMap CLabel () ->
-                FuelMonad (Maybe CmmTopZ, C_SRT)
-procpointSRT top_srt top_table entries
- | isEmptyFM entries = pprTrace "nil SRT" (ppr top_srt) $ return (Nothing, NoC_SRT)
- | otherwise  = pprTrace "non-nil SRT" (ppr top_srt) $ bitmap `seq` to_SRT top_srt offset len bitmap
-  where
-    ints = map (expectJust "constructSRT" . lookupFM top_table) (keysFM entries)
-    sorted_ints = sortLe (<=) ints
-    offset = head sorted_ints
-    bitmap_entries = map (subtract offset) sorted_ints
-    len = P.last bitmap_entries + 1
-    bitmap = intsToBitmap len bitmap_entries
-
--- Adapted from codeGen/StgCmmUtils, which converts from SRT to C_SRT.
-to_SRT :: CLabel -> Int -> Int -> Bitmap -> FuelMonad (Maybe CmmTopZ, C_SRT)
-to_SRT top_srt off len bmp
-  | len > widthInBits wordWidth `div` 2 || bmp == [fromIntegral srt_escape]
-  = do id <- getUniqueM
-       let srt_desc_lbl = mkLargeSRTLabel id
-           tbl = CmmData RelocatableReadOnlyData $
-                   CmmDataLabel srt_desc_lbl : map CmmStaticLit
-                     ( cmmLabelOffW top_srt off
-                     : mkWordCLit (fromIntegral len)
-                     : map mkWordCLit bmp)
-       return (Just tbl, C_SRT srt_desc_lbl 0 srt_escape)
-  | otherwise
-  = return (Nothing, C_SRT top_srt off (fromIntegral (head bmp)))
-       -- The fromIntegral converts to StgHalfWord
-
--- Given a block ID, we return a representation of the layout of the stack.
--- If the element is `Nothing`, then it represents an empty or dead
--- word on the stack.
--- If the element is `Just` a register, then it represents a live spill slot
--- for the register; note that a register may occupy multiple words.
--- The head of the list represents the young end of the stack where the infotable
--- pointer for the block `Bid` is stored.
--- The infotable pointer itself is not included in the list.
-live_vars :: BlockEnv SubAreaSet -> AreaMap -> BlockId -> [Maybe LocalReg]
-live_vars slotEnv areaMap bid = slotsToList youngByte liveSlots
-  where slotsToList 0 [] = []
-        slotsToList 0 ((_, r, _) : _)  = pprPanic "slot left off live_vars" (ppr r)
-        slotsToList n _ | n < 0 = panic "stack slots not allocated on word boundaries?"
-        slotsToList n ((n', r, w) : rst) =
-          if n == n' then Just r : slotsToList (n - w) rst
-          else Nothing : slotsToList (n - wORD_SIZE) rst
-        slotsToList n [] = Nothing : slotsToList (n - wORD_SIZE) []
-        liveSlots = sortBy (\ (_,off,_) (_,off',_) -> compare off' off)
-                      (foldFM (\_ -> flip $ foldr add_slot) [] slots)
-        add_slot (a@(RegSlot r@(LocalReg _ ty)), off, w) rst = 
-          if off == w && widthInBytes (typeWidth ty) == w then
-            (expectJust "add_slot" (lookupFM areaMap a), r, w) : rst
-          else panic "live_vars: only part of a variable live at a proc point"
-        add_slot (CallArea Old, off, w) rst =
-          if off == wORD_SIZE && w == wORD_SIZE then
-             rst -- the return infotable should be live
-          else pprPanic "CallAreas must not be live across function calls" (ppr bid)
-        add_slot (CallArea (Young _), _, _) _ =
-          pprPanic "CallAreas must not be live across function calls" (ppr bid)
-        slots = expectJust "live_vars slots" $ lookupBlockEnv slotEnv bid
-        youngByte = expectJust "live_vars bid_pos" $ lookupFM areaMap (CallArea (Young bid))
+             where lbl = expectJust "pp label" $ lookupFM procLabels bid
+     -- The C back end expects to see return continuations before the call sites.
+     -- Here, we sort them in reverse order -- it gets reversed later.
+     let (_, block_order) = foldl add_block_num (0::Int, emptyBlockEnv) (postorder_dfs g)
+         add_block_num (i, map) (Block bid _ _) = (i+1, extendBlockEnv map bid i)
+         sort_fn (bid, _) (bid', _) =
+           compare (expectJust "block_order" $ lookupBlockEnv block_order bid)
+                   (expectJust "block_order" $ lookupBlockEnv block_order bid')
+     procs <- return $ map to_proc $ sortBy sort_fn $ blockEnvToList graphEnv
+     return $ pprTrace "procLabels" (ppr procLabels)
+            $ pprTrace "splitting graphs" (ppr procs)
+            $ procs
+splitAtProcPoints _ _ _ _ _ t@(CmmData _ _) = return [t]
 
 ----------------------------------------------------------------
 
 
   , availRegsLattice
   , cmmAvailableReloads
   , insertLateReloads
-  , insertLateReloads'
   , removeDeadAssignmentsAndReloads
   )
 where
 import ZipCfgCmmRep
 import ZipDataflow
 
-import Maybes
 import Monad
 import Outputable hiding (empty)
 import qualified Outputable as PP
 
 changeStack, changeRegs :: (RegSet -> RegSet) -> DualLive -> DualLive
 changeStack f live = live { on_stack = f (on_stack live) }
-changeRegs   f live = live { in_regs  = f (in_regs  live) }
+changeRegs  f live = live { in_regs  = f (in_regs  live) }
 
 
 dualLiveLattice :: DataflowLattice DualLive
 type LiveReloadFix a = FuelMonad (BackwardFixedPoint Middle Last DualLive a)
 
 dualLivenessWithInsertion :: BlockSet -> (LGraph Middle Last) -> FuelMonad (LGraph Middle Last)
-dualLivenessWithInsertion procPoints g =
+dualLivenessWithInsertion procPoints g@(LGraph entry _ _) =
   liftM zdfFpContents $ (res :: LiveReloadFix (LGraph Middle Last))
     where res = zdfBRewriteFromL RewriteDeep emptyBlockEnv "dual liveness with insertion"
-                                 dualLiveLattice (dualLiveTransfers procPoints)
-                                 (insertSpillAndReloadRewrites procPoints) empty g
+                                 dualLiveLattice (dualLiveTransfers entry procPoints)
+                                 (insertSpillAndReloadRewrites entry procPoints) empty g
           empty = fact_bot dualLiveLattice
 
 dualLiveness :: BlockSet -> LGraph Middle Last -> FuelMonad (BlockEnv DualLive)
-dualLiveness procPoints g = liftM zdfFpFacts $ (res :: LiveReloadFix ())
+dualLiveness procPoints g@(LGraph entry _ _) =
+  liftM zdfFpFacts $ (res :: LiveReloadFix ())
     where res = zdfSolveFromL emptyBlockEnv "dual liveness" dualLiveLattice
-                              (dualLiveTransfers procPoints) empty g
+                              (dualLiveTransfers entry procPoints) empty g
           empty = fact_bot dualLiveLattice
 
-dualLiveTransfers :: BlockSet -> BackwardTransfers Middle Last DualLive
-dualLiveTransfers procPoints = BackwardTransfers first middle last
+dualLiveTransfers :: BlockId -> BlockSet -> BackwardTransfers Middle Last DualLive
+dualLiveTransfers entry procPoints = BackwardTransfers first middle last
     where last   = lastDualLiveness
           middle = middleDualLiveness
-          first live _id =
-            if elemBlockSet _id procPoints then -- live at procPoint => spill
+          first live id = check live id $  -- live at procPoint => spill
+            if id /= entry && elemBlockSet id procPoints then
               DualLive { on_stack = on_stack live `plusRegSet` in_regs live
                        , in_regs  = emptyRegSet }
             else live
+          check live id x = if id == entry then noLiveOnEntry id (in_regs live) x else x
   
 middleDualLiveness :: DualLive -> Middle -> DualLive
 middleDualLiveness live m =
-  changeStack updSlots $ changeRegs (middleLiveness m) live
-    where updSlots live = foldSlotsUsed reload (foldSlotsDefd spill live m) m
+  changeStack updSlots $ changeRegs (middleLiveness m) (changeRegs regs_in live)
+    where regs_in live = case m of MidForeignCall {} -> emptyRegSet
+                                   _ -> live
+          updSlots live = foldSlotsUsed reload (foldSlotsDefd spill live m) m
           spill  live s@(RegSlot r, _, _) = check s $ deleteFromRegSet live r
           spill  live _ = live
           reload live s@(RegSlot r, _, _) = check s $ extendRegSet live r
 
 lastDualLiveness :: (BlockId -> DualLive) -> Last -> DualLive
 lastDualLiveness env l = last l
-  where last (LastReturn _)            = empty
-        last (LastJump e _)            = changeRegs (gen e) empty
-        last (LastBranch id)           = env id
-        last (LastCall tgt Nothing _)  = changeRegs (gen tgt) empty
-        last (LastCall tgt (Just k) _) = 
-            -- nothing can be live in registers at this point
-            let live = env k in
-            if  isEmptyUniqSet (in_regs live) then
-                DualLive (on_stack live) (gen tgt emptyRegSet)
-            else
-                pprTrace "Offending party:" (ppr k <+> ppr live) $
-                panic "live values in registers at call continuation"
-        last (LastCondBranch e t f)   = changeRegs (gen e) $ dualUnion (env t) (env f)
-        last (LastSwitch e tbl)       = changeRegs (gen e) $ dualUnionList $
+  where last (LastBranch id)          = env id
+        last l@(LastCall tgt Nothing  _ _) = changeRegs (gen l . kill l) empty
+        last l@(LastCall tgt (Just k) _ _) = 
+            -- nothing can be live in registers at this point, unless safe foreign call
+            let live = env k
+                live_in = DualLive (on_stack live) (gen l emptyRegSet)
+            in if isEmptyUniqSet (in_regs live) then live_in
+               else pprTrace "Offending party:" (ppr k <+> ppr live) $
+                    panic "live values in registers at call continuation"
+        last l@(LastCondBranch e t f)   =
+            changeRegs (gen l . kill l) $ dualUnion (env t) (env f)
+        last l@(LastSwitch e tbl)       = changeRegs (gen l . kill l) $ dualUnionList $
                                                              map env (catMaybes tbl)
         empty = fact_bot dualLiveLattice
                       
-gen :: UserOfLocalRegs a => a -> RegSet -> RegSet
-gen a live = foldRegsUsed extendRegSet      live a
-
-insertSpillAndReloadRewrites :: BlockSet -> BackwardRewrites Middle Last DualLive
-insertSpillAndReloadRewrites procPoints = BackwardRewrites first middle last exit
+gen  :: UserOfLocalRegs    a => a -> RegSet -> RegSet
+gen  a live = foldRegsUsed extendRegSet     live a
+kill :: DefinerOfLocalRegs a => a -> RegSet -> RegSet
+kill a live = foldRegsDefd deleteFromRegSet live a
+
+insertSpillAndReloadRewrites ::
+  BlockId -> BlockSet -> BackwardRewrites Middle Last DualLive
+insertSpillAndReloadRewrites entry procPoints =
+  BackwardRewrites first middle last exit
     where middle = middleInsertSpillsAndReloads
-          last   = \_ _ -> Nothing
-          exit = Nothing
+          last _ _ = Nothing
+          exit     = Nothing
           first live id =
-            if elemBlockSet id procPoints && not (isEmptyUniqSet reloads) then
-              Just $ mkMiddles $ map reload $ uniqSetToList reloads
+            if id /= entry && elemBlockSet id procPoints then
+              case map reload (uniqSetToList (in_regs live)) of
+                [] -> Nothing
+                is -> Just (mkMiddles is)
             else Nothing
-            where reloads = in_regs live
-
 
 middleInsertSpillsAndReloads :: DualLive -> Middle -> Maybe (AGraph Middle Last)
 middleInsertSpillsAndReloads live m = middle m
                                              text "after", ppr m]) $
                  Just $ mkMiddles $ [m, spill reg]
             else Nothing
+        middle (MidForeignCall _ _ fs _) =
+          case map spill  (filter (flip elemRegSet (on_stack live)) fs) ++
+               map reload (uniqSetToList (kill fs (in_regs live))) of
+            []      -> Nothing
+            reloads -> Just (mkMiddles (m : reloads))
         middle _ = Nothing
                       
 -- Generating spill and reload code
 spill  r = MidStore  (regSlot r) (CmmReg $ CmmLocal r)
 reload r = MidAssign (CmmLocal r) (CmmLoad (regSlot r) $ localRegType r)
 
-spillHead  :: ZHead Middle -> RegSet            -> ZHead Middle
 reloadTail :: RegSet       -> ZTail Middle Last -> ZTail Middle Last
-spillHead h regset = foldl spl h $ uniqSetToList regset
-  where spl h r = ZHead h $ spill r
 reloadTail regset t = foldl rel t $ uniqSetToList regset
   where rel t r = ZTail (reload r) t
 
 
 
 availRegsLattice :: DataflowLattice AvailRegs
-availRegsLattice = DataflowLattice "register gotten from reloads" empty add False
+availRegsLattice = DataflowLattice "register gotten from reloads" empty add True
                             -- last True <==> debugging on
     where empty = UniverseMinus emptyRegSet
           -- | compute in the Tx monad to track whether anything has changed
 cmmAvailableReloads g = liftM zdfFpFacts $ (res :: AvailFix)
     where res = zdfSolveFromL emptyBlockEnv "available reloads" availRegsLattice
                               avail_reloads_transfer empty g
-          empty = (fact_bot availRegsLattice)
+          empty = fact_bot availRegsLattice
 
 avail_reloads_transfer :: ForwardTransfers Middle Last AvailRegs
 avail_reloads_transfer = ForwardTransfers first middle last id
 middleAvail :: Middle -> AvailRegs -> AvailRegs
 middleAvail m = middle m
   where middle m live = middle' m $ foldRegsUsed deleteFromAvail live m
-        middle' (MidComment {})                 = id
-        middle' (MidAssign lhs _expr)           = akill lhs
-        middle' (MidStore {})                   = id
-        middle' (MidUnsafeCall _tgt ress _args) = akill ress
-        middle' (MidAddToContext {})            = id
+        middle' (MidComment {})                 live = live
+        middle' (MidAssign lhs _expr)           live = akill lhs live
+        middle' (MidStore {})                   live = live
+        middle' (MidForeignCall _ _tgt ress _args) _ = AvailRegs emptyRegSet
 
 lastAvail :: AvailRegs -> Last -> LastOutFacts AvailRegs
-lastAvail _ (LastCall _ (Just k) _) = LastOutFacts [(k, AvailRegs emptyRegSet)]
+lastAvail _ (LastCall _ (Just k) _ _) = LastOutFacts [(k, AvailRegs emptyRegSet)]
 lastAvail avail l = LastOutFacts $ map (\id -> (id, avail)) $ succs l
 
-insertLateReloads :: LGraph Middle Last -> FuelMonad (LGraph Middle Last)
-insertLateReloads g =
-  do env <- cmmAvailableReloads g
-     mapM_blocks (insertM env) g
-    where insertM env b = fuelConsumingPass "late reloads" (insert b)
-            where avail id = lookupBlockEnv env id `orElse` AvailRegs emptyRegSet
-                  insert (Block id off tail) fuel =
-                    propagate (ZFirst id off) (avail id) tail fuel
-                  propagate h avail (ZTail m t) fuel =
-                      let (h', fuel') = maybe_add_reload h avail m fuel in
-                      propagate (ZHead h' m) (middleAvail m avail) t fuel'
-                  propagate h avail (ZLast l) fuel =
-                      let (h', fuel') = maybe_add_reload h avail l fuel in
-                      (zipht h' (ZLast l), fuel')
-                  maybe_add_reload h avail node fuel =
-                      let used = filterRegsUsed (elemAvail avail) node
-                      in  if not (canRewriteWithFuel fuel) || isEmptyUniqSet used
-                          then (h,fuel)
-                          else (spillHead h used, oneLessFuel fuel)
-
-type LateReloadFix = FuelMonad (ForwardFixedPoint Middle Last AvailRegs (LGraph Middle Last))
-
-insertLateReloads' :: (LGraph Middle Last) -> FuelMonad (LGraph Middle Last)
-insertLateReloads' g = liftM zdfFpContents $ (res :: LateReloadFix)
+type LateReloadFix = FuelMonad (ForwardFixedPoint Middle Last AvailRegs CmmGraph)
+
+insertLateReloads :: (LGraph Middle Last) -> FuelMonad (LGraph Middle Last)
+insertLateReloads g = liftM zdfFpContents $ (res :: LateReloadFix)
     where res = zdfFRewriteFromL RewriteShallow emptyBlockEnv "insert late reloads"
                                  availRegsLattice avail_reloads_transfer rewrites bot g
           bot = fact_bot availRegsLattice
           middle :: AvailRegs -> Middle -> Maybe (AGraph Middle Last)
           last   :: AvailRegs -> Last -> Maybe (AGraph Middle Last)
           middle avail m = maybe_reload_before avail m (ZTail m (ZLast LastExit))
-          last avail l   = maybe_reload_before avail l (ZLast (LastOther l))
+          last   avail l = maybe_reload_before avail l (ZLast (LastOther l))
           exit _ = Nothing
           maybe_reload_before avail node tail =
               let used = filterRegsUsed (elemAvail avail) node
                   else Just $ mkZTail $ reloadTail used tail
           
 removeDeadAssignmentsAndReloads :: BlockSet -> (LGraph Middle Last) -> FuelMonad (LGraph Middle Last)
-removeDeadAssignmentsAndReloads procPoints g =
+removeDeadAssignmentsAndReloads procPoints g@(LGraph entry _ _) =
    liftM zdfFpContents $ (res :: LiveReloadFix (LGraph Middle Last))
      where res = zdfBRewriteFromL RewriteDeep emptyBlockEnv "dead-assignment & -reload elim"
-                   dualLiveLattice (dualLiveTransfers procPoints)
+                   dualLiveLattice (dualLiveTransfers entry procPoints)
                    rewrites (fact_bot dualLiveLattice) g
            rewrites = BackwardRewrites first middle last exit
            exit   = Nothing
 
 import ZipCfg
 
 import Maybes
-import UniqSet
 
 -- | Compute the predecessors of each /reachable/ block
 zipPreds :: LastNode l => LGraph m l -> BlockEnv BlockSet
           add_pred pair@(single, multi) id =
               if elemBlockSet id multi then pair
               else if elemBlockSet id single then
-                       (delOneFromUniqSet single id, extendBlockSet multi id)
+                       (removeBlockSet single id, extendBlockSet multi id)
                    else
                        (extendBlockSet single id, multi)
               
 
 import Control.Monad
 import Maybes
 import Outputable
-import UniqFM
 import UniqSupply
 
 {-
 
 runDFM :: Monad m => DataflowLattice f -> DFM' m f a -> m a
 runDFM lattice (DFM' f) =
-  (f lattice $ DFState NoChange emptyBlockEnv (fact_bot lattice)[] NoChange)
+  (f lattice $ DFState NoChange emptyBlockEnv (fact_bot lattice) [] NoChange)
   >>= return . fst
 
 class DataflowAnalysis m where
   botFact = DFM' f
     where f lattice s = return (fact_bot lattice, s)
   forgetFact id = DFM' f 
-    where f _ s = return ((), s { df_facts = delFromUFM (df_facts s) id })
+    where f _ s = return ((), s { df_facts = delFromBlockEnv (df_facts s) id })
   addLastOutFact pair = DFM' f
     where f _ s = return ((), s { df_last_outs = pair : df_last_outs s })
   bareLastOutFacts = DFM' f
                                     text "env is", pprFacts facts]) 
                   ; setFact id a }
          }
-    where pprFacts env = vcat (map pprFact (ufmToList env))
+    where pprFacts env = vcat (map pprFact (blockEnvToList env))
           pprFact (id, a) = hang (ppr id <> colon) 4 (ppr a)
 
   lattice = DFM' f
 
     , mkMiddle, mkMiddles, mkLast, mkZTail, mkBranch, mkLabel, mkIfThenElse, mkWhileDo
     , outOfLine
     , emptyGraph, graphOfMiddles, graphOfZTail
-    , lgraphOfAGraph, graphOfAGraph, labelAGraph
+    , lgraphOfAGraph, graphOfAGraph, labelAGraph, pprAGraph
     )
 where
 
-import BlockId (BlockId(..), emptyBlockEnv)
+import BlockId (BlockId(..), emptyBlockEnv, plusBlockEnv)
 import ZipCfg
 
 import Outputable
 import Unique
-import UniqFM
 import UniqSupply
 import Util
 
 
 emptyAGraph :: AGraph m l
 mkLabel     :: (LastNode l) =>
-               BlockId -> Maybe Int -> AGraph m l -- graph contains the label
+               BlockId -> StackInfo -> AGraph m l -- graph contains the label
 mkMiddle    :: m -> AGraph m l   -- graph contains the node
 mkLast      :: (Outputable m, Outputable l, LastNode l) =>
                l       -> AGraph m l              -- graph contains the node
 
 labelAGraph id args g =
     do Graph tail blocks <- graphOfAGraph g
-       return $ LGraph id args $ insertBlock (Block id Nothing tail) blocks
+       return $ LGraph id args $ insertBlock (Block id stackInfo tail) blocks
+    where stackInfo = StackInfo Nothing Nothing
 
 lgraphOfAGraph args g = do id <- freshBlockId "graph entry"
                            labelAGraph id args g
 
 mkLast l = AGraph f
     where f (Graph tail blocks) =
-            do note_this_code_becomes_unreachable tail
+            do note_this_code_becomes_unreachable "mkLast" (ppr l <+> ppr blocks) tail
                return $ Graph (ZLast (LastOther l)) blocks
 
 mkZTail tail = AGraph f
     where f (Graph utail blocks) =
-            do note_this_code_becomes_unreachable utail
+            do note_this_code_becomes_unreachable "mkZTail" (ppr tail) utail
                return $ Graph tail blocks
 
 withFreshLabel name ofId = AGraph f
                  f' g
 
 outOfLine (AGraph f) = AGraph f'
-    where f' (Graph tail' blocks') =
+    where f' g@(Graph tail' blocks') =
             do Graph emptyEntrance blocks <- f emptyGraph
-               note_this_code_becomes_unreachable emptyEntrance
-               return $ Graph tail' (blocks `plusUFM` blocks')
-                                                       
+               note_this_code_becomes_unreachable "outOfLine" (ppr tail') emptyEntrance
+               return $ Graph tail' (blocks `plusBlockEnv` blocks')
+
 mkIfThenElse cbranch tbranch fbranch = 
     withFreshLabel "end of if"     $ \endif ->
     withFreshLabel "start of then" $ \tid ->
     withFreshLabel "start of else" $ \fid ->
         cbranch tid fid <*>
-        mkLabel tid Nothing <*> tbranch <*> mkBranch endif <*>
-        mkLabel fid Nothing <*> fbranch <*> mkLabel endif Nothing
+        mkLabel tid emptyStackInfo <*> tbranch <*> mkBranch endif <*>
+        mkLabel fid emptyStackInfo <*> fbranch <*>
+        mkLabel endif emptyStackInfo 
 
 mkWhileDo cbranch body = 
   withFreshLabel "loop test" $ \test ->
   withFreshLabel "loop head" $ \head ->
   withFreshLabel "end while" $ \endwhile ->
      -- Forrest Baskett's while-loop layout
-     mkBranch test <*> mkLabel head Nothing <*> body <*> mkLabel test Nothing
-                   <*> cbranch head endwhile <*> mkLabel endwhile Nothing
+     mkBranch test <*> mkLabel head emptyStackInfo <*> body
+                   <*> mkLabel test emptyStackInfo <*> cbranch head endwhile
+                   <*> mkLabel endwhile emptyStackInfo 
 
 -- | Bleat if the insertion of a last node will create unreachable code
 note_this_code_becomes_unreachable ::
-    (Monad m, LastNode l, Outputable middle, Outputable l) => ZTail middle l -> m ()
+    (Monad m, LastNode l, Outputable middle, Outputable l) =>
+       String -> SDoc -> ZTail middle l -> m ()
 
-note_this_code_becomes_unreachable = if debugIsOn then u else \_ -> return ()
+note_this_code_becomes_unreachable str old = if debugIsOn then u else \_ -> return ()
     where u (ZLast LastExit)                       = return ()
           u (ZLast (LastOther l)) | isBranchNode l = return ()
                                     -- Note [Branch follows branch]
-          u tail = fail ("unreachable code: " ++ showSDoc (ppr tail))
+          u tail = fail ("unreachable code in " ++ str ++ ": " ++
+                         (showSDoc ((ppr tail) <+> old)))
+
+-- | The string argument to 'freshBlockId' was originally helpful in debugging
+-- the Quick C-- compiler, so I have kept it here even though at present it is
+-- thrown away at this spot---there's no reason a BlockId couldn't one day carry
+-- a string.  
+
+freshBlockId :: MonadUnique m => String -> m BlockId
+freshBlockId _s = getUniqueM >>= return . BlockId
+
+-------------------------------------
+-- Debugging
+
+pprAGraph :: (Outputable m, LastNode l, Outputable l) => AGraph m l -> UniqSM SDoc
+pprAGraph g = graphOfAGraph g >>= return . ppr
 
 {-
 Note [Branch follows branch]
 -}
 
 
--- | The string argument to 'freshBlockId' was originally helpful in debugging
--- the Quick C-- compiler, so I have kept it here even though at present it is
--- thrown away at this spot---there's no reason a BlockId couldn't one day carry
--- a string.  
-
-freshBlockId :: MonadUnique m => String -> m BlockId
-freshBlockId _s = getUniqueM >>= return . BlockId
-
 
 -- complain to Norman Ramsey.
 
 module MkZipCfgCmm
-  ( mkNop, mkAssign, mkStore, mkCall, mkCmmCall, mkUnsafeCall, mkFinalCall
-         , mkJump, mkCbranch, mkSwitch, mkReturn, mkComment, copyIn, copyOut, mkEntry 
-        , mkCmmIfThenElse, mkCmmIfThen, mkCmmWhileDo
-        , mkAddToContext
+  ( mkNop, mkAssign, mkStore, mkCall, mkCmmCall, mkSafeCall, mkUnsafeCall, mkFinalCall
+         , mkJump, mkForeignJump, mkJumpGC, mkCbranch, mkSwitch, mkReturn
+         , mkReturnSimple, mkComment, copyIn, copyOut
+         , mkEntry, mkCmmIfThenElse, mkCmmIfThen, mkCmmWhileDo
   , (<*>), catAGraphs, mkLabel, mkBranch
   , emptyAGraph, withFreshLabel, withUnique, outOfLine
   , lgraphOfAGraph, graphOfAGraph, labelAGraph
   , CmmZ, CmmTopZ, CmmGraph, CmmBlock, CmmAGraph
   , Middle, Last, Convention(..), ForeignConvention(..), MidCallTarget(..), Transfer(..)
+  , emptyStackInfo, stackStubExpr, pprAGraph
   )
 where
 
   -- duplicated below
 import PprCmm()
 
-import ClosureInfo
 import FastString
 import ForeignCall
 import MkZipCfg
 import Panic 
+import StaticFlags 
 import ZipCfg 
 
 type CmmGraph  = LGraph Middle Last
 mkStore      :: CmmExpr -> CmmExpr -> CmmAGraph
 
 ---------- Calls
-mkCall       :: CmmExpr -> CCallConv -> CmmFormals -> CmmActuals -> C_SRT -> CmmAGraph
-mkCmmCall    :: CmmExpr -> CmmFormals -> CmmActuals -> C_SRT -> CmmAGraph
+mkCall       :: CmmExpr -> Convention -> CmmFormals -> CmmActuals ->
+                  UpdFrameOffset -> CmmAGraph
+mkCmmCall    :: CmmExpr ->              CmmFormals -> CmmActuals ->
+                  UpdFrameOffset -> CmmAGraph
                        -- Native C-- calling convention
-mkUnsafeCall :: MidCallTarget -> CmmFormals -> CmmActuals -> CmmAGraph
-mkFinalCall  :: CmmExpr -> CCallConv -> CmmActuals -> CmmAGraph
+mkSafeCall    :: MidCallTarget -> CmmFormals -> CmmActuals -> UpdFrameOffset -> CmmAGraph
+mkUnsafeCall  :: MidCallTarget -> CmmFormals -> CmmActuals -> CmmAGraph
+mkFinalCall   :: CmmExpr -> CCallConv -> CmmActuals -> UpdFrameOffset -> CmmAGraph
                 -- Never returns; like exit() or barf()
 
----------- Context manipulation ("return via")
-mkAddToContext :: CmmExpr -> [CmmExpr] -> CmmAGraph
-
 ---------- Control transfer
-mkJump         :: CmmExpr -> CmmActuals -> CmmAGraph
+mkJump         ::               CmmExpr -> CmmActuals -> UpdFrameOffset -> CmmAGraph
+mkJumpGC               ::               CmmExpr -> CmmActuals -> UpdFrameOffset -> CmmAGraph
+mkForeignJump   :: Convention -> CmmExpr -> CmmActuals -> UpdFrameOffset -> CmmAGraph
 mkCbranch      :: CmmExpr -> BlockId -> BlockId          -> CmmAGraph
 mkSwitch       :: CmmExpr -> [Maybe BlockId]             -> CmmAGraph
-mkReturn       :: CmmActuals -> CmmAGraph
+mkReturn       :: CmmExpr -> CmmActuals -> UpdFrameOffset -> CmmAGraph
+mkReturnSimple  :: CmmActuals -> UpdFrameOffset -> CmmAGraph
 
 mkCmmIfThenElse :: CmmExpr -> CmmAGraph -> CmmAGraph -> CmmAGraph
 mkCmmIfThen     :: CmmExpr -> CmmAGraph -> CmmAGraph
   = withFreshLabel "end of if"     $ \endif ->
     withFreshLabel "start of then" $ \tid ->
     mkCbranch e tid endif <*>
-    mkLabel tid Nothing <*> tbranch <*> mkBranch endif <*>
-    mkLabel endif Nothing
+    mkLabel tid   emptyStackInfo <*> tbranch <*> mkBranch endif <*>
+    mkLabel endif emptyStackInfo
 
 
 
 
 mkNop                     = emptyAGraph
 mkComment fs              = mkMiddle $ MidComment fs
-mkAssign l r              = mkMiddle $ MidAssign l r
 mkStore  l r              = mkMiddle $ MidStore  l r
 
+-- NEED A COMPILER-DEBUGGING FLAG HERE
+-- Sanity check: any value assigned to a pointer must be non-zero.
+-- If it's 0, cause a crash immediately.
+mkAssign l r = if opt_StubDeadValues then assign l r <*> check l else assign l r
+  where assign l r = mkMiddle (MidAssign l r)
+        check (CmmGlobal _) = mkNop
+        check l@(CmmLocal reg) = -- if a ptr arg is NULL, cause a crash!
+          if isGcPtrType ty then
+            mkCmmIfThen (CmmMachOp (MO_Eq w) [r, stackStubExpr w])
+                        (assign l (CmmLoad (CmmLit (CmmInt 0 w)) ty))
+          else mkNop
+            where ty = localRegType reg
+                  w  = typeWidth ty
+                  r  = CmmReg l
+
 
 -- Why are we inserting extra blocks that simply branch to the successors?
 -- Because in addition to the branch instruction, @mkBranch@ will insert
 -- a necessary adjustment to the stack pointer.
 mkCbranch pred ifso ifnot = mkLast (LastCondBranch pred ifso ifnot)
-mkSwitch e tbl            = mkLast   $ LastSwitch e tbl
+mkSwitch e tbl            = mkLast $ LastSwitch e tbl
 
-mkUnsafeCall tgt results actuals = mkMiddle $ MidUnsafeCall tgt results actuals
-mkAddToContext ra actuals        = mkMiddle $ MidAddToContext ra actuals
+mkSafeCall   t fs as upd =
+  withFreshLabel "safe call" $ \k ->
+    mkMiddle $ MidForeignCall (Safe k upd) t fs as
+mkUnsafeCall t fs as = mkMiddle $ MidForeignCall Unsafe t fs as
 
-cmmResConv :: Convention
-cmmResConv = Native
+-- For debugging purposes, we can stub out dead stack slots:
+stackStubExpr :: Width -> CmmExpr
+stackStubExpr w = CmmLit (CmmInt 0 w)
 
 -- Return the number of bytes used for copying arguments, as well as the
 -- instructions to copy the arguments.
-copyIn :: Convention -> Bool -> Area -> CmmFormals -> (Int, [Middle])
-copyIn _ isCall area formals =
-  foldr ci (init_offset, []) $ assignArgumentsPos isCall localRegType formals
+copyIn :: Convention -> Bool -> Area -> CmmFormals -> (Int, AGraph Middle Last)
+copyIn conv isCall area formals =
+  foldr ci (init_offset, mkNop) $ assignArgumentsPos conv isCall localRegType formals
   where ci (reg, RegisterParam r) (n, ms) =
-          (n, MidAssign (CmmLocal reg) (CmmReg $ CmmGlobal r) : ms)
+          (n, mkAssign (CmmLocal reg) (CmmReg $ CmmGlobal r) <*> ms)
         ci (reg, StackParam off) (n, ms) =
           let ty = localRegType reg
               off' = off + init_offset
           in (max n off',
-              MidAssign (CmmLocal reg) (CmmLoad (CmmStackSlot area off') ty) : ms)
+              mkAssign (CmmLocal reg) (CmmLoad (CmmStackSlot area off') ty) <*> ms)
         init_offset = widthInBytes wordWidth
 
 -- The argument layout function ignores the pointer to the info table, so we slot that
 -- in here. When copying-out to a young area, we set the info table for return
 -- and adjust the offsets of the other parameters.
 -- If this is a call instruction, we adjust the offsets of the other parameters.
-copyOut :: Convention -> Transfer -> Area -> CmmActuals -> (Int, [Middle])
-copyOut _ transfer area@(CallArea a) actuals =
+copyOut :: Convention -> Transfer -> Area -> CmmActuals -> UpdFrameOffset -> (Int, [Middle])
+copyOut conv transfer area@(CallArea a) actuals updfr_off =
   foldr co (init_offset, []) args'
-  where args = assignArgumentsPos skip_node cmmExprType actuals
+  where args = assignArgumentsPos conv skip_node cmmExprType actuals
         skip_node = transfer /= Ret
         (setRA, init_offset) =
-          case a of Young id -> -- set RA if making a call
+          case a of Young id@(BlockId _) -> -- set RA if making a call
                       if transfer == Call then
-                        ([(CmmLit (CmmLabel (infoTblLbl id)),
-                           StackParam init_offset)], ra_width)
+                        ([(CmmLit (CmmBlock id), StackParam init_offset)], ra_width)
                       else ([], 0)
-                    Old -> ([], ra_width)
+                    Old -> ([], updfr_off)
         ra_width = widthInBytes wordWidth
         args' = foldl adjust setRA args
           where adjust rst (v, StackParam off) = (v, StackParam (off + init_offset)) : rst
         co (v, RegisterParam r) (n, ms) = (n, MidAssign (CmmGlobal r) v : ms)
         co (v, StackParam off)  (n, ms) =
           (max n off, MidStore (CmmStackSlot area off) v : ms)
-copyOut _ _ (RegSlot _) _ = panic "cannot copy arguments into a register slot"
+copyOut _ _ (RegSlot _) _ _ = panic "cannot copy arguments into a register slot"
 
 mkEntry :: BlockId -> Convention -> CmmFormals -> (Int, CmmAGraph)
-mkEntry _ conv formals =
-  let (off, copies) = copyIn conv False (CallArea Old) formals in
-  (off, mkMiddles copies)
-
--- I'm not sure how to get the calling conventions right yet,
--- and I suspect this should not be resolved until sometime after
--- Simon's patch is applied.
--- For now, I apply a bogus calling convention: all arguments go on the
--- stack, using the same amount of stack space.
-
-lastWithArgs :: Transfer -> Area -> Convention -> CmmActuals -> (Int -> Last) -> CmmAGraph
-lastWithArgs transfer area conv actuals last =
-  let (outArgs, copies) = copyOut conv transfer area actuals in
+mkEntry _ conv formals = copyIn conv False (CallArea Old) formals
+
+lastWithArgs :: Transfer -> Area -> Convention -> CmmActuals -> UpdFrameOffset ->
+                (Int -> Last) -> CmmAGraph
+lastWithArgs transfer area conv actuals updfr_off last =
+  let (outArgs, copies) = copyOut conv transfer area actuals updfr_off in
   mkMiddles copies <*> mkLast (last outArgs)
 
 -- The area created for the jump and return arguments is the same area as the
 -- procedure entry.
-mkJump e actuals = lastWithArgs Jump (CallArea Old) cmmResConv actuals $ LastJump e
-mkReturn actuals = lastWithArgs Ret  (CallArea Old) cmmResConv actuals $ LastJump e
-  where e = CmmStackSlot (CallArea Old) (widthInBytes wordWidth)
-
-mkFinalCall f _ actuals =
-  lastWithArgs Call (CallArea Old) Native actuals $ LastCall f Nothing
-
-mkCmmCall f results actuals srt = mkCall f CmmCallConv results actuals srt
+old :: Area
+old = CallArea Old
+toCall :: CmmExpr -> Maybe BlockId -> UpdFrameOffset -> Int -> Last
+toCall e cont updfr_off arg_space = LastCall e cont arg_space (Just updfr_off)
+mkJump e actuals updfr_off =
+  lastWithArgs Jump old Native actuals updfr_off $ toCall e Nothing updfr_off
+mkJumpGC e actuals updfr_off =
+  lastWithArgs Jump old GC actuals updfr_off $ toCall e Nothing updfr_off
+mkForeignJump conv e actuals updfr_off =
+  lastWithArgs Jump old conv actuals updfr_off $ toCall e Nothing updfr_off
+mkReturn e actuals updfr_off =
+  lastWithArgs Ret  old Native actuals updfr_off $ toCall e Nothing updfr_off
+    -- where e = CmmLoad (CmmStackSlot (CallArea Old) updfr_off) gcWord
+mkReturnSimple actuals updfr_off =
+  lastWithArgs Ret  old Native actuals updfr_off $ toCall e Nothing updfr_off
+    where e = CmmLoad (CmmStackSlot (CallArea Old) updfr_off) gcWord
+
+mkFinalCall f _ actuals updfr_off =
+  lastWithArgs Call old Native actuals updfr_off $ toCall f Nothing updfr_off
+
+mkCmmCall f results actuals = mkCall f Native results actuals
 
 -- I'm dropping the SRT, but that should be okay: we plan to reconstruct it later.
-mkCall f _ results actuals _ =
+mkCall f conv results actuals updfr_off =
   withFreshLabel "call successor" $ \k ->
-  let area = CallArea $ Young k
-      (off, copyin) = copyIn Native False area results
-      copyout = lastWithArgs Call area Native actuals $ LastCall f (Just k)
-  in copyout <*> mkLabel k (Just off) <*> (mkMiddles copyin)
+    let area = CallArea $ Young k
+        (off, copyin) = copyIn conv False area results
+        copyout = lastWithArgs Call area conv actuals updfr_off 
+                               (toCall f (Just k) updfr_off)
+    in (copyout <*> mkLabel k (StackInfo (Just off) (Just updfr_off))
+                <*> copyin)
 
 -- type OptimizationFuel = State# () -- would like this, but it won't work
 data OptimizationFuel = OptimizationFuel
   deriving Show
-tankFilledTo _ = undefined -- should be impossible to evaluate
+tankFilledTo _ = panic "tankFilledTo" -- should be impossible to evaluate
   -- realWorld# might come in handy, too...
 canRewriteWithFuel OptimizationFuel = True
 maybeRewriteWithFuel _ ma = ma
 lGraphOfGraph :: Graph m l -> Int -> FuelMonad (LGraph m l)
 lGraphOfGraph (Graph tail blocks) args =
   do entry <- liftM BlockId $ getUniqueM
-     return $ LGraph entry args (insertBlock (Block entry Nothing tail) blocks)
+     return $ LGraph entry args
+                     (insertBlock (Block entry emptyStackInfo tail) blocks)
 
   pprDataExterns lits $$
   pprWordArray lbl lits  
 
+-- Floating info table for safe a foreign call.
+pprTop top@(CmmData _section d@(_ : _))
+  | CmmDataLabel lbl : lits <- reverse d = 
+  pprDataExterns lits $$
+  pprWordArray lbl lits  
+
 -- these shouldn't appear?
 pprTop (CmmData _ _) = panic "PprC.pprTop: can't handle this data"
 
                 -- these constants come from <math.h>
                 -- see #1861
 
+    CmmBlock bid       -> mkW_ <> pprCLabelAddr (infoTblLbl bid)
+    CmmHighStackMark   -> panic "PprC printing high stack mark"
     CmmLabel clbl      -> mkW_ <> pprCLabelAddr clbl
     CmmLabelOff clbl i -> mkW_ <> pprCLabelAddr clbl <> char '+' <> int i
     CmmLabelDiffOff clbl1 clbl2 i
 
 
 
 import ForeignCall
-import Unique
 import Outputable
 import FastString
 
 
 pprTop (CmmProc info lbl params graph )
 
-  = vcat [ pprCLabel lbl <> parens (commafy $ map ppr params) <+> lbrace
+  = vcat [ pprCLabel lbl <> parens (commafy $ map ppr params)
          , nest 8 $ lbrace <+> ppr info $$ rbrace
          , nest 4 $ ppr graph
          , rbrace ]
 pprInfo :: CmmInfo -> SDoc
 pprInfo (CmmInfo _gc_target update_frame CmmNonInfoTable) =
     vcat [{-ptext (sLit "gc_target: ") <>
-                maybe (ptext (sLit "<none>")) pprBlockId gc_target,-}
+                maybe (ptext (sLit "<none>")) ppr gc_target,-}
           ptext (sLit "update_frame: ") <>
                 maybe (ptext (sLit "<none>")) pprUpdateFrame update_frame]
 pprInfo (CmmInfo _gc_target update_frame
-         (CmmInfoTable (ProfilingInfo closure_type closure_desc) tag info)) =
+         (CmmInfoTable stat_clos (ProfilingInfo closure_type closure_desc) tag info)) =
     vcat [{-ptext (sLit "gc_target: ") <>
-                maybe (ptext (sLit "<none>")) pprBlockId gc_target,-}
+                maybe (ptext (sLit "<none>")) ppr gc_target,-}
+          ptext (sLit "has static closure: ") <> ppr stat_clos <+>
           ptext (sLit "update_frame: ") <>
                 maybe (ptext (sLit "<none>")) pprUpdateFrame update_frame,
           ptext (sLit "type: ") <> pprLit closure_type,
 --      lbl: stmt ; stmt ; .. 
 pprBBlock :: Outputable stmt => GenBasicBlock stmt -> SDoc
 pprBBlock (BasicBlock ident stmts) =
-    hang (pprBlockId ident <> colon) 4 (vcat (map ppr stmts))
+    hang (ppr ident <> colon) 4 (vcat (map ppr stmts))
 
 -- --------------------------------------------------------------------------
 -- Statements. C-- usually, exceptions to this should be obvious.
 --
 genBranch :: BlockId -> SDoc
 genBranch ident = 
-    ptext (sLit "goto") <+> pprBlockId ident <> semi
+    ptext (sLit "goto") <+> ppr ident <> semi
 
 -- --------------------------------------------------------------------------
 -- Conditional. [1], section 6.4
     hsep [ ptext (sLit "if")
          , parens(ppr expr)
          , ptext (sLit "goto")
-         , pprBlockId ident <> semi ]
+         , ppr ident <> semi ]
 
 -- --------------------------------------------------------------------------
 -- A tail call. [1], Section 6.9
           in hsep [ ptext (sLit "case")
                   , hcat (punctuate comma (map int is))
                   , ptext (sLit ": goto")
-                  , pprBlockId (head [ id | Just id <- ids]) <> semi ]
+                  , ppr (head [ id | Just id <- ids]) <> semi ]
 
 -- --------------------------------------------------------------------------
 -- Expressions
     CmmLabelOff clbl i -> pprCLabel clbl <> ppr_offset i
     CmmLabelDiffOff clbl1 clbl2 i -> pprCLabel clbl1 <> char '-'  
                                   <> pprCLabel clbl2 <> ppr_offset i
+    CmmBlock id        -> ppr id
+    CmmHighStackMark -> text "<highSp>"
 
 pprLit1 :: CmmLit -> SDoc
 pprLit1 lit@(CmmLabelOff {}) = parens (pprLit lit)
  where
     section = ptext (sLit "section")
 
--- --------------------------------------------------------------------------
--- Basic block ids
---
-pprBlockId :: BlockId -> SDoc
-pprBlockId b = ppr $ getUnique b
-
 -----------------------------------------------------------------------------
 
 commafy :: [SDoc] -> SDoc
 
 import CmmZipUtil
 
 import Maybe
-import UniqSet
 import FastString
 
 ----------------------------------------------------------------
                       | id' == tid, Just e' <- maybeInvertCmmExpr expr, isNothing out->
                           tail id (ft tid : ppr (CmmCondBranch e'   fid) : prev') Nothing t bs
                     _ -> endblock $ with_out out l
-                l@(G.LastJump   {}) -> endblock $ with_out out l
-                l@(G.LastReturn {}) -> endblock $ with_out out l
-                l@(G.LastSwitch {}) -> endblock $ with_out out l
-                l@(G.LastCall _ _ _)-> endblock $ with_out out l
+                l@(G.LastSwitch {})   -> endblock $ with_out out l
+                l@(G.LastCall _ _ _ _)-> endblock $ with_out out l
           exit id prev' n = -- highly irregular (assertion violation?)
               let endblock stmt = block' id (stmt : prev') : swallow n in
               endblock (text "// <exit>")
           preds = zipPreds g
           entry_has_no_pred = case lookupBlockEnv preds (Z.lg_entry g) of
                                 Nothing -> True
-                                Just s -> isEmptyUniqSet s
+                                Just s -> isEmptyBlockSet s
           single_preds =
               let add b single =
                     let id = Z.blockId b
                     in  case lookupBlockEnv preds id of
                           Nothing -> single
-                          Just s -> if sizeUniqSet s == 1 then
+                          Just s -> if sizeBlockSet s == 1 then
                                         extendBlockSet single id
                                     else single
               in  Z.fold_blocks add emptyBlockSet g
 with_out :: Maybe (G.Convention, CmmActuals) -> G.Last -> SDoc
 with_out Nothing l = ptext (sLit "??no-arguments??") <+> ppr l
 with_out (Just (conv, args)) l = last l
-    where last (G.LastCall e k _) =
+    where last (G.LastCall e k _ _) =
               hcat [ptext (sLit "... = foreign "),
                     doubleQuotes(ppr conv), space,
                     ppr_target e, parens ( commafy $ map ppr args ),
                     ptext (sLit " \"safe\""),
-                    case k of Nothing -> ptext (sLit " never returns")
-                              Just _ -> empty,
+                    text " returns to " <+> ppr k,
                     semi ]
-          last (G.LastReturn _) = ppr (CmmReturn $ noHints args)
-          last (G.LastJump e _) = ppr (CmmJump e $ noHints args)
           last l = ppr l
           ppr_target (CmmLit lit) = pprLit lit
           ppr_target fn'          = parens (ppr fn')
           commafy xs = hsep $ punctuate comma xs
-
--- Anything that uses this is bogus!
-noHints :: [a] -> [CmmHinted a]
-noHints = map (\v -> CmmHinted v NoHint)
 
     head_fold (ZFirst id _) out z = f (bt_first_in comp out id) (f out z)
 
 foldConflicts :: (RegSet -> a -> a) -> a -> LGraph Middle Last -> FuelMonad a
-foldConflicts f z g =
+foldConflicts f z g@(LGraph entry _ _) =
   do env <- dualLiveness emptyBlockSet g
      let lookup id = lookupBlockEnv env id `orElse` fact_bot dualLiveLattice
          f' dual z = f (on_stack dual) z
-     return $ fold_edge_facts_b f' (dualLiveTransfers emptyBlockSet) g lookup z
+     return $ fold_edge_facts_b f' (dualLiveTransfers entry emptyBlockSet) g lookup z
   --let env = runDFA dualLiveLattice (run_b_anal dualLiveness g >> getAllFacts)
   --    lookup id = lookupBlockEnv env id `orElse` fact_bot dualLiveLattice
   --    f' dual z = f (on_stack dual) z
 
     (  -- These data types and names are carefully thought out
       Graph(..), LGraph(..), FGraph(..)
     , Block(..), ZBlock(..), ZHead(..), ZTail(..), ZLast(..)
+    , StackInfo(..), emptyStackInfo
     , insertBlock
     , HavingSuccessors, succs, fold_succs
     , LastNode, mkBranchNode, isBranchNode, branchNodeTarget
 #include "HsVersions.h"
 
 import BlockId ( BlockId, BlockEnv, emptyBlockEnv, lookupBlockEnv, extendBlockEnv
-               , BlockSet, emptyBlockSet, elemBlockSet, extendBlockSet)
+               , BlockSet, emptyBlockSet, unitBlockSet, elemBlockSet, extendBlockSet
+               , delFromBlockEnv, foldBlockEnv', mapBlockEnv
+               , eltsBlockEnv, isNullBEnv, plusBlockEnv)
 import CmmExpr ( UserOfLocalRegs(..) )
 import PprCmm()
 
 import Outputable hiding (empty)
 import Panic
-import UniqFM
-import UniqSet
 
 import Maybe
 import Prelude hiding (zip, unzip, last)
 'LastExit' node, and a graph representing a full procedure should not
 contain any 'LastExit' nodes.  'LastExit' nodes are used only to splice
 graphs together, either during graph construction (see module 'MkZipCfg')
-or during optimization (see module 'ZipDataflow0').
+or during optimization (see module 'ZipDataflow').
 
 A graph is parameterized over the types of middle and last nodes.  Each of
 these types will typically be instantiated with a subset of C-- statements
     foldRegsUsed _f z LastExit      = z
 
 
-data ZHead m   = ZFirst BlockId  (Maybe Int)
+data ZHead m   = ZFirst BlockId StackInfo
                | ZHead (ZHead m) m
     -- ZHead is a (reversed) sequence of middle nodes labeled by a BlockId
 data ZTail m l = ZLast (ZLast l) | ZTail m (ZTail m l)
     -- ZTail is a sequence of middle nodes followed by a last node
 
 -- | Blocks and flow graphs; see Note [Kinds of graphs]
--- In addition to its id, the block carries the number of bytes of stack space
--- used for incoming parameters on entry to the block.
-data Block m l = Block BlockId (Maybe Int) (ZTail m l)
+
+-- For each block, we may need two pieces of information about the stack:
+-- 1. If the block is a procpoint, how many bytes are used to pass
+--    arguments on the stack?
+-- 2. If the block succeeds a call, we need to generate an infotable
+--    that describes the stack layout... but only up to the update frame!
+-- Note that a block can be a proc point without requiring an infotable.
+data StackInfo = StackInfo { argBytes  :: Maybe Int
+                           , returnOff :: Maybe Int }
+  deriving ( Eq )
+emptyStackInfo :: StackInfo
+emptyStackInfo = StackInfo Nothing Nothing
+
+data Block m l = Block { bid       :: BlockId
+                       , stackInfo :: StackInfo
+                       , tail      :: ZTail m l }
 
 data Graph m l = Graph { g_entry :: (ZTail m l), g_blocks :: (BlockEnv (Block m l)) }
 
 fold_blocks :: (Block m l -> a -> a) -> a -> LGraph m l -> a
 
 -- | Fold from first to last
-fold_fwd_block ::
-  (BlockId -> a -> a) -> (m -> a -> a) -> (ZLast l -> a -> a) -> Block m l -> a -> a
+fold_fwd_block :: (BlockId -> StackInfo -> a -> a) -> (m -> a -> a) ->
+                  (ZLast l -> a -> a) -> Block m l -> a -> a
 
 map_one_block :: (BlockId -> BlockId) -> (m -> m') -> (l -> l') -> Block m l -> Block m' l'
 
 
 head_id :: ZHead m -> BlockId
 head_id (ZFirst id _) = id
-head_id (ZHead  h  _) = head_id h
+head_id (ZHead  h  _)   = head_id h
 
 last (ZBlock _ t) = lastTail t
 
 focus :: BlockId -> LGraph m l -> FGraph m l -- focus on edge out of node with id 
 focus id (LGraph entry _ blocks) =
     case lookupBlockEnv blocks id of
-      Just b -> FGraph entry (unzip b) (delFromUFM blocks id)
+      Just b -> FGraph entry (unzip b) (delFromBlockEnv blocks id)
       Nothing -> panic "asked for nonexistent block in flow graph"
 
 entry   :: LGraph m l -> FGraph m l         -- focus on edge out of entry node 
 -- | pull out a block satisfying the predicate, if any
 splitp_blocks :: (Block m l -> Bool) -> BlockEnv (Block m l) ->
                  Maybe (Block m l, BlockEnv (Block m l))
-splitp_blocks p blocks = lift $ foldUFM scan (Nothing, emptyBlockEnv) blocks 
+splitp_blocks p blocks = lift $ foldBlockEnv' scan (Nothing, emptyBlockEnv) blocks 
     where scan b (yes, no) =
               case yes of
                 Nothing | p b -> (Just b, no)
 
 -- | Used in assertions; tells if a graph has exactly one exit
 single_exit :: LGraph l m -> Bool
-single_exit g = foldUFM check 0 (lg_blocks g) == 1
+single_exit g = foldBlockEnv' check 0 (lg_blocks g) == 1
     where check block count = case last (unzip block) of
                                 LastExit -> count + (1 :: Int)
                                 _ -> count
 
 -- | Used in assertions; tells if a graph has exactly one exit
 single_exitg :: Graph l m -> Bool
-single_exitg (Graph tail blocks) = foldUFM add (exit_count (lastTail tail)) blocks == 1
+single_exitg (Graph tail blocks) = foldBlockEnv' add (exit_count (lastTail tail)) blocks == 1
     where add block count = count + exit_count (last (unzip block))
           exit_count LastExit = 1 :: Int
           exit_count _        = 0
 --     C -> D
 -- @
 -- Then ordinary dfs would give [A,B,D,C] which has a back ref from C to D.
--- Better to geot [A,B,C,D]
+-- Better to get [A,B,C,D]
 
 
 postorder_dfs g@(LGraph _ _ blockenv) =
     let FGraph id eblock _ = entry g in
-     zip eblock : postorder_dfs_from_except blockenv eblock (unitUniqSet id)
+     zip eblock : postorder_dfs_from_except blockenv eblock (unitBlockSet id)
 
 postorder_dfs_from_except :: (HavingSuccessors b, LastNode l)
                           => BlockEnv (Block m l) -> b -> BlockSet -> [Block m l]
 
 -- | The rest of the traversals are straightforward
 
-map_blocks f (LGraph eid off blocks) = LGraph eid off (mapUFM f blocks)
+map_blocks f (LGraph eid off blocks) = LGraph eid off (mapBlockEnv f blocks)
 
 map_nodes idm middle last (LGraph eid off blocks) =
-  LGraph (idm eid) off (mapUFM (map_one_block idm middle last) blocks)
+  LGraph (idm eid) off (mapBlockEnv (map_one_block idm middle last) blocks)
 
 map_one_block idm middle last (Block id off t) = Block (idm id) off (tail t)
     where tail (ZTail m t) = ZTail (middle m) (tail t)
 
 mapM_blocks f (LGraph eid off blocks) = blocks' >>= return . LGraph eid off
     where blocks' =
-            foldUFM (\b mblocks -> do { blocks <- mblocks
+            foldBlockEnv' (\b mblocks -> do { blocks <- mblocks
                                       ; b <- f b
                                       ; return $ insertBlock b blocks })
                     (return emptyBlockEnv) blocks
 
-fold_blocks f z (LGraph _ _ blocks) = foldUFM f z blocks
-fold_fwd_block first middle last (Block id _ t) z = tail t (first id z)
+fold_blocks f z (LGraph _ _ blocks) = foldBlockEnv' f z blocks
+fold_fwd_block first middle last (Block id off t) z = tail t (first id off z)
     where tail (ZTail m t) z = tail t (middle m z)
           tail (ZLast l)   z = last l z
 
 of_block_list e off blocks = LGraph e off $ foldr insertBlock emptyBlockEnv blocks 
-to_block_list (LGraph _ _ blocks) = eltsUFM blocks
+to_block_list (LGraph _ _ blocks) = eltsBlockEnv blocks
 
 
 -- We want to be able to scrutinize a single-entry, single-exit 'LGraph' for
 prepare_for_splicing g single multi =
   let FGraph _ gentry gblocks = entry g 
       ZBlock _ etail = gentry
-  in if isNullUFM gblocks then
+  in if isNullBEnv gblocks then
          case last gentry of
            LastExit -> single etail
            _ -> panic "bad single block"
   Graph m l -> (ZTail m l -> a) -> (ZTail m l -> ZHead m -> BlockEnv (Block m l) -> a)
   -> a
 prepare_for_splicing' (Graph etail gblocks) single multi =
-   if isNullUFM gblocks then
+   if isNullBEnv gblocks then
        case lastTail etail of
          LastExit -> single etail
          _ -> panic "bad single block"
 --- Translation
 
 translate txm txl (LGraph eid off blocks) =
-    do blocks' <- foldUFM txblock (return emptyBlockEnv) blocks
+    do blocks' <- foldBlockEnv' txblock (return emptyBlockEnv) blocks
        return $ LGraph eid off blocks'
     where
       -- txblock ::
       txtail h (ZTail m t) blocks' =
         do m' <- txm m 
            let (g, h') = splice_head h m' 
-           txtail h' t (plusUFM (lg_blocks g) blocks')
+           txtail h' t (plusBlockEnv (lg_blocks g) blocks')
       txtail h (ZLast (LastOther l)) blocks' =
         do l' <- txl l
-           return $ plusUFM (lg_blocks (splice_head_only h l')) blocks'
+           return $ plusBlockEnv (lg_blocks (splice_head_only h l')) blocks'
       txtail h (ZLast LastExit) blocks' =
         return $ insertBlock (zipht h (ZLast LastExit)) blocks'
 
 instance (Outputable m, Outputable l, LastNode l) => Outputable (Block m l) where
     ppr = pprBlock
 
+instance Outputable StackInfo where
+    ppr = pprStackInfo
+
 instance (Outputable l) => Outputable (ZLast l) where
     ppr = pprLast
 
 pprLast LastExit = text "<exit>"
 pprLast (LastOther l) = ppr l
 
+pprStackInfo :: StackInfo -> SDoc
+pprStackInfo cs =
+  text "<arg bytes:" <+> ppr (argBytes  cs) <+>
+  text "ret offset:" <+> ppr (returnOff cs) <> text ">"
+
 pprBlock :: (Outputable m, Outputable l, LastNode l) => Block m l -> SDoc
-pprBlock (Block id args tail) = ppr id <> parens (ppr args) <> colon $$ ppr tail
+pprBlock (Block id stackInfo tail) =
+  ppr id <>  parens (ppr stackInfo) <> colon
+         $$  (nest 3 (ppr tail))
 
 pprLgraph :: (Outputable m, Outputable l, LastNode l) => LGraph m l -> SDoc
 pprLgraph g = text "{" <> text "offset" <> parens (ppr $ lg_argoffset g) $$
 
- 
-
 -- This module is pure representation and should be imported only by
 -- clients that need to manipulate representation and know what
 -- they're doing.  Clients that need to create flow graphs should
 
 module ZipCfgCmmRep
   ( CmmZ, CmmTopZ, CmmGraph, CmmBlock, CmmAGraph
-  , Middle(..), Last(..), MidCallTarget(..)
-  , Convention(..), ForeignConvention(..)
+  , Middle(..), Last(..), MidCallTarget(..), UpdFrameOffset
+  , Convention(..), ForeignConvention(..), ForeignSafety(..)
   , ValueDirection(..), ForeignHint(..)
   , CmmBackwardFixedPoint, CmmForwardFixedPoint, pprHinted
   , insertBetween, mapExpMiddle, mapExpLast, mapExpDeepMiddle, mapExpDeepLast
-  , foldExpMiddle, foldExpLast, foldExpDeepMiddle, foldExpDeepLast
-  , joinOuts
+  , foldExpMiddle, foldExpLast, foldExpDeepMiddle, foldExpDeepLast, joinOuts
   )
 where
 
 import Outputable
 import Prelude hiding (zip, unzip, last)
 import qualified Data.List as L
+import SMRep (ByteOff)
 import UniqSupply
 
 ----------------------------------------------------------------------
 type CmmBackwardFixedPoint a = DF.BackwardFixedPoint Middle Last a ()
 type CmmForwardFixedPoint  a = DF.ForwardFixedPoint  Middle Last a ()
 
+type UpdFrameOffset = ByteOff
+
 data Middle
   = MidComment FastString
 
   | MidStore  CmmExpr CmmExpr    -- Assign to memory location.  Size is
                                  -- given by cmmExprType of the rhs.
 
-  | MidUnsafeCall                -- An "unsafe" foreign call;
-     MidCallTarget               -- just a fat machine instructoin
+  | MidForeignCall               -- A foreign call;
+     ForeignSafety               -- Is it a safe or unsafe call?
+     MidCallTarget               -- call target and convention
      CmmFormals                  -- zero or more results
      CmmActuals                  -- zero or more arguments
-
-  | MidAddToContext              -- Push a frame on the stack;
-                                 --    I will return to this frame
-     CmmExpr                     -- The frame's return address; it must be
-                                 -- preceded by an info table that describes the
-                                 -- live variables.
-     [CmmExpr]                   -- The frame's live variables, to go on the 
-                                 -- stack with the first one at the young end
   deriving Eq
 
 data Last
         --      zero -> first block
         --      one  -> second block etc
         -- Undefined outside range, and when there's a Nothing
-  | LastReturn Int       -- Return from a function; values in previous copy middles
-  | LastJump CmmExpr Int -- Tail call to another procedure; args in a copy middles
-  | LastCall {                      -- A call (native or safe foreign); args in copy middles
-        cml_target :: CmmExpr,      -- never a CmmPrim to a CallishMachOp!
-        cml_cont   :: Maybe BlockId,-- BlockId of continuation, if call returns
-        cml_args   :: Int }     -- liveness info for outgoing args
-  -- All the last nodes that pass arguments carry the size of the outgoing CallArea
+  | LastCall {                   -- A call (native or safe foreign)
+        cml_target  :: CmmExpr,  -- never a CmmPrim to a CallishMachOp!
+        cml_cont    :: Maybe BlockId,
+            -- BlockId of continuation (Nothing for return or tail call)
+        cml_args    :: ByteOff,  -- bytes offset for youngest outgoing arg
+        cml_ret_off :: Maybe UpdFrameOffset}
+          -- stack offset for return (update frames);
+          -- The return offset should be Nothing only if we have to create
+          -- a new call, e.g. for a procpoint, in which case it's an invariant
+          -- that the call does not stand for a return or a tail call,
+          -- and the successor does not need an info table.
 
 data MidCallTarget     -- The target of a MidUnsafeCall
   = ForeignTarget      -- A foreign procedure
 data Convention
   = Native             -- Native C-- call/return
 
+  | Slow               -- Slow entry points: all args pushed on the stack
+
+  | GC                         -- Entry to the garbage collector: uses the node reg!
+
+  | PrimOp             -- Calling prim ops
+
   | Foreign            -- Foreign call/return
        ForeignConvention
 
        [ForeignHint]           -- Extra info about the result
   deriving Eq 
 
+data ForeignSafety
+  = Unsafe              -- unsafe call
+  | Safe BlockId        -- making infotable requires: 1. label 
+         UpdFrameOffset --                            2. where the upd frame is
+  deriving Eq
+
 data ValueDirection = Arguments | Results
   -- Arguments go with procedure definitions, jumps, and arguments to calls
   -- Results go with returns and with results of calls.
         insert (h, LastOther (LastSwitch e ks)) =
           do (ids, bs) <- mapAndUnzipM mbNewBlocks ks
              return (zipht h $ ZLast $ LastOther (LastSwitch e ids), join bs)
-        insert (_, LastOther (LastCall _ _ _)) =
+        insert (_, LastOther (LastCall {})) =
           panic "unimp: insertBetween after a call -- probably not a good idea"
-        insert (_, LastOther (LastReturn _)) = panic "cannot insert after return"
-        insert (_, LastOther (LastJump _ _)) = panic "cannot insert after jump"
         insert (_, LastExit) = panic "cannot insert after exit"
         newBlocks = do id <- liftM BlockId $ getUniqueM
-                       return $ (id, [Block id Nothing $
+                       return $ (id, [Block id emptyStackInfo $
                                    foldr ZTail (ZLast (LastOther (LastBranch succId))) ms])
         mbNewBlocks (Just k) = if k == succId then liftM lift newBlocks
                                else return (Just k, [])
     branchNodeTarget _ = panic "asked for target of non-branch"
 
 cmmSuccs :: Last -> [BlockId]
-cmmSuccs (LastReturn _)           = []
-cmmSuccs (LastJump {})            = [] 
-cmmSuccs (LastBranch id)          = [id]
-cmmSuccs (LastCall _ (Just id) _) = [id]
-cmmSuccs (LastCall _ Nothing _)   = []
-cmmSuccs (LastCondBranch _ t f)   = [f, t]  -- meets layout constraint
-cmmSuccs (LastSwitch _ edges)     = catMaybes edges
+cmmSuccs (LastBranch id)            = [id]
+cmmSuccs (LastCall _ Nothing _ _)   = []
+cmmSuccs (LastCall _ (Just id) _ _) = [id]
+cmmSuccs (LastCondBranch _ t f)     = [f, t]  -- meets layout constraint
+cmmSuccs (LastSwitch _ edges)       = catMaybes edges
 
 fold_cmm_succs :: (BlockId -> a -> a) -> Last -> a -> a
-fold_cmm_succs _f (LastReturn _)           z = z
-fold_cmm_succs _f (LastJump {})            z = z
-fold_cmm_succs  f (LastBranch id)          z = f id z
-fold_cmm_succs  f (LastCall _ (Just id) _) z = f id z
-fold_cmm_succs _f (LastCall _ Nothing _)   z = z
-fold_cmm_succs  f (LastCondBranch _ te fe) z = f te (f fe z)
-fold_cmm_succs  f (LastSwitch _ edges)     z = foldl (flip f) z $ catMaybes edges
+fold_cmm_succs  f (LastBranch id)            z = f id z
+fold_cmm_succs  _ (LastCall _ Nothing _ _)   z = z
+fold_cmm_succs  f (LastCall _ (Just id) _ _) z = f id z
+fold_cmm_succs  f (LastCondBranch _ te fe)   z = f te (f fe z)
+fold_cmm_succs  f (LastSwitch _ edges)       z = foldl (flip f) z $ catMaybes edges
 
 ----------------------------------------------------------------------
 ----- Instance declarations for register use
 
 instance UserOfLocalRegs Middle where
     foldRegsUsed f z m = middle m
-      where middle (MidComment {})            = z
-            middle (MidAssign _lhs expr)      = fold f z expr
-            middle (MidStore addr rval)       = fold f (fold f z addr) rval
-            middle (MidUnsafeCall tgt _ args) = fold f (fold f z tgt) args
-            middle (MidAddToContext ra args)  = fold f (fold f z ra) args
+      where middle (MidComment {})               = z
+            middle (MidAssign _lhs expr)         = fold f z expr
+            middle (MidStore addr rval)          = fold f (fold f z addr) rval
+            middle (MidForeignCall _ tgt _ args) = fold f (fold f z tgt) args
             fold f z m = foldRegsUsed f z m  -- avoid monomorphism restriction
 
 instance UserOfLocalRegs MidCallTarget where
   foldSlotsUsed _f z (PrimTarget _)      = z
   foldSlotsUsed f  z (ForeignTarget e _) = foldSlotsUsed f z e
 
+instance (UserOfLocalRegs a) => UserOfLocalRegs (Maybe a) where
+  foldRegsUsed f z (Just x) = foldRegsUsed f z x
+  foldRegsUsed _ z Nothing  = z
+
+instance (UserOfSlots a) => UserOfSlots (Maybe a) where
+  foldSlotsUsed f z (Just x) = foldSlotsUsed f z x
+  foldSlotsUsed _ z Nothing  = z
+
 instance UserOfLocalRegs Last where
     foldRegsUsed f z l = last l
-      where last (LastReturn _)         = z
-            last (LastJump e _)         = foldRegsUsed f z e
-            last (LastBranch _id)       = z
-            last (LastCall tgt _ _)     = foldRegsUsed f z tgt
+      where last (LastBranch _id)       = z
+            last (LastCall tgt _ _ _)   = foldRegsUsed f z tgt
             last (LastCondBranch e _ _) = foldRegsUsed f z e
             last (LastSwitch e _tbl)    = foldRegsUsed f z e
 
 instance DefinerOfLocalRegs Middle where
     foldRegsDefd f z m = middle m
-      where middle (MidComment {})         = z
-            middle (MidAssign _lhs _)      = fold f z _lhs
-            middle (MidStore _ _)          = z
-            middle (MidUnsafeCall _ _ _)   = z
-            middle (MidAddToContext _ _)   = z
+      where middle (MidComment {})            = z
+            middle (MidAssign _lhs _)         = fold f z _lhs
+            middle (MidStore _ _)             = z
+            middle (MidForeignCall _ _ fs _)  = fold f z fs
             fold f z m = foldRegsDefd f z m  -- avoid monomorphism restriction
 
 instance DefinerOfLocalRegs Last where
 
 instance UserOfSlots Middle where
     foldSlotsUsed f z m = middle m
-      where middle (MidComment {})                = z
-            middle (MidAssign _lhs expr)          = fold f z expr
-            middle (MidStore addr rval)           = fold f (fold f z addr) rval
-            middle (MidUnsafeCall tgt _ress args) = fold f (fold f z tgt) args
-            middle (MidAddToContext ra args)      = fold f (fold f z ra) args
+      where middle (MidComment {})                   = z
+            middle (MidAssign _lhs expr)             = fold f z expr
+            middle (MidStore addr rval)              = fold f (fold f z addr) rval
+            middle (MidForeignCall _ tgt _ress args) = fold f (fold f z tgt) args
             fold f z e = foldSlotsUsed f z e  -- avoid monomorphism restriction
 
 instance UserOfSlots Last where
     foldSlotsUsed f z l = last l
-      where last (LastReturn _)         = z
-            last (LastJump e _)         = foldSlotsUsed f z e
-            last (LastBranch _id)       = z
-            last (LastCall tgt _ _)     = foldSlotsUsed f z tgt
+      where last (LastBranch _id)       = z
+            last (LastCall tgt _ _ _)   = foldSlotsUsed f z tgt
             last (LastCondBranch e _ _) = foldSlotsUsed f z e
             last (LastSwitch e _tbl)    = foldSlotsUsed f z e
 
 
 instance DefinerOfSlots Middle where
     foldSlotsDefd f z m = middle m
-      where middle (MidComment {})       = z
-            middle (MidAssign _ _)       = z
+      where middle (MidComment {})    = z
+            middle (MidAssign _ _)    = z
+            middle (MidForeignCall {}) = z
             middle (MidStore (CmmStackSlot a i) e) =
               f z (a, i, widthInBytes $ typeWidth $ cmmExprType e)
-            middle (MidStore _ _)        = z
-            middle (MidUnsafeCall _ _ _) = z
-            middle (MidAddToContext _ _) = z
+            middle (MidStore _ _)     = z
 
 instance DefinerOfSlots Last where
     foldSlotsDefd _ z _ = z
 mapExpMiddle _   m@(MidComment _)            = m
 mapExpMiddle exp   (MidAssign r e)           = MidAssign r (exp e)
 mapExpMiddle exp   (MidStore addr e)         = MidStore (exp addr) (exp e)
-mapExpMiddle exp   (MidUnsafeCall tgt fs as) =
-  MidUnsafeCall (mapExpMidcall exp tgt) fs (map exp as)
-mapExpMiddle exp   (MidAddToContext e es)    = MidAddToContext (exp e) (map exp es)
+mapExpMiddle exp   (MidForeignCall s tgt fs as) =
+  MidForeignCall s (mapExpMidcall exp tgt) fs (map exp as)
 
 foldExpMiddle :: (CmmExpr -> z -> z) -> Middle -> z -> z
-foldExpMiddle _   (MidComment _)           z = z
-foldExpMiddle exp (MidAssign _ e)          z = exp e z
-foldExpMiddle exp (MidStore addr e)        z = exp addr $ exp e z
-foldExpMiddle exp (MidUnsafeCall tgt _ as) z = foldExpMidcall exp tgt $ foldr exp z as
-foldExpMiddle exp (MidAddToContext e es)   z = exp e $ foldr exp z es
+foldExpMiddle _   (MidComment _)              z = z
+foldExpMiddle exp (MidAssign _ e)             z = exp e z
+foldExpMiddle exp (MidStore addr e)           z = exp addr $ exp e z
+foldExpMiddle exp (MidForeignCall _ tgt _ as) z = foldExpMidcall exp tgt $ foldr exp z as
 
 mapExpLast :: (CmmExpr -> CmmExpr) -> Last -> Last
-mapExpLast _   l@(LastBranch _)         = l
-mapExpLast exp (LastCondBranch e ti fi) = LastCondBranch (exp e) ti fi
-mapExpLast exp (LastSwitch e tbl)       = LastSwitch (exp e) tbl
-mapExpLast exp (LastCall tgt mb_id s)   = LastCall (exp tgt) mb_id s
-mapExpLast exp (LastJump e s)           = LastJump (exp e) s
-mapExpLast _   (LastReturn s)           = LastReturn s
+mapExpLast _   l@(LastBranch _)           = l
+mapExpLast exp (LastCondBranch e ti fi)   = LastCondBranch (exp e) ti fi
+mapExpLast exp (LastSwitch e tbl)         = LastSwitch (exp e) tbl
+mapExpLast exp (LastCall tgt mb_id u s) = LastCall (exp tgt) mb_id u s
 
 foldExpLast :: (CmmExpr -> z -> z) -> Last -> z -> z
 foldExpLast _   (LastBranch _)         z = z
 foldExpLast exp (LastCondBranch e _ _) z = exp e z
 foldExpLast exp (LastSwitch e _)       z = exp e z
-foldExpLast exp (LastCall tgt _ _)     z = exp tgt z
-foldExpLast exp (LastJump e _)         z = exp e z
-foldExpLast _   (LastReturn _)         z = z
+foldExpLast exp (LastCall tgt _ _ _)   z = exp tgt z
 
 mapExpMidcall :: (CmmExpr -> CmmExpr) -> MidCallTarget -> MidCallTarget 
 mapExpMidcall exp   (ForeignTarget e c) = ForeignTarget (exp e) c
 
 -- Take a transformer on expressions and apply it recursively.
 wrapRecExp :: (CmmExpr -> CmmExpr) -> CmmExpr -> CmmExpr
-wrapRecExp f (CmmMachOp op es)    = f (CmmMachOp op $ map f es)
-wrapRecExp f (CmmLoad addr ty)    = f (CmmLoad (f addr) ty)
+wrapRecExp f (CmmMachOp op es)    = f (CmmMachOp op $ map (wrapRecExp f) es)
+wrapRecExp f (CmmLoad addr ty)    = f (CmmLoad (wrapRecExp f addr) ty)
 wrapRecExp f e                    = f e
 
 mapExpDeepMiddle :: (CmmExpr -> CmmExpr) -> Middle -> Middle
 
 -- Take a folder on expressions and apply it recursively.
 wrapRecExpf :: (CmmExpr -> z -> z) -> CmmExpr -> z -> z
-wrapRecExpf f e@(CmmMachOp _ es) z = foldr f (f e z) es
-wrapRecExpf f e@(CmmLoad addr _) z = f addr  (f e z)
+wrapRecExpf f e@(CmmMachOp _ es) z = foldr (wrapRecExpf f) (f e z) es
+wrapRecExpf f e@(CmmLoad addr _) z = wrapRecExpf f addr (f e z)
 wrapRecExpf f e                  z = f e z
 
 foldExpDeepMiddle :: (CmmExpr -> z -> z) -> Middle -> z -> z
   let bot  = fact_bot lattice
       join x y = txVal $ fact_add_to lattice x y
   in case l of
-       (LastReturn _)          -> bot
-       (LastJump _ _)          -> bot
-       (LastBranch id)         -> env id
-       (LastCall _ Nothing _)  -> bot
-       (LastCall _ (Just k) _) -> env k
-       (LastCondBranch _ t f)  -> join (env t) (env f)
-       (LastSwitch _ tbl)      -> foldr join bot (map env $ catMaybes tbl)
+       (LastBranch id)           -> env id
+       (LastCall _ Nothing _ _)  -> bot
+       (LastCall _ (Just k) _ _) -> env k
+       (LastCondBranch _ t f)    -> join (env t) (env f)
+       (LastSwitch _ tbl)        -> foldr join bot (map env $ catMaybes tbl)
 
 ----------------------------------------------------------------------
 ----- Instance declarations for prettyprinting (avoids recursive imports)
 
        -- call "ccall" foo(x, y)[r1, r2];
        -- ToDo ppr volatile
-       MidUnsafeCall target results args ->
+       MidForeignCall safety target results args ->
            hsep [ if null results
                      then empty
                      else parens (commafy $ map ppr results) <+> equals,
+                      ppr_safety safety,
                   ptext $ sLit "call", 
                   ppr_call_target target <> parens (commafy $ map ppr args) <> semi]
 
-       MidAddToContext ra args ->
-           hcat [ ptext $ sLit "return via "
-                , ppr_target ra, parens (commafy $ map ppr args), semi ]
-  
     pp_debug =
       if not debugPpr then empty
       else text " //" <+>
            case stmt of
-             MidComment {} -> text "MidComment"
-             MidAssign {}  -> text "MidAssign"
-             MidStore {}   -> text "MidStore"
-             MidUnsafeCall  {} -> text "MidUnsafeCall"
-             MidAddToContext {} -> text "MidAddToContext"
+             MidComment     {} -> text "MidComment"
+             MidAssign      {} -> text "MidAssign"
+             MidStore       {} -> text "MidStore"
+             MidForeignCall {} -> text "MidForeignCall"
 
 ppr_fc :: ForeignConvention -> SDoc
 ppr_fc (ForeignConvention c _ _) = doubleQuotes (ppr c)
 
+ppr_safety :: ForeignSafety -> SDoc
+ppr_safety (Safe bid upd) = text "safe<" <> ppr bid <> text ", " <> ppr upd <> text ">"
+ppr_safety Unsafe         = text "unsafe"
+
 ppr_call_target :: MidCallTarget -> SDoc
 ppr_call_target (ForeignTarget fn c) = ppr_fc c <+> ppr_target fn
 ppr_call_target (PrimTarget op)      = ppr (CmmLabel (mkForeignLabel (mkFastString (show op)) Nothing False))
 pprLast stmt = pp_stmt <+> pp_debug
   where
     pp_stmt = case stmt of
-       LastBranch ident          -> ptext (sLit "goto") <+> ppr ident <> semi
-       LastCondBranch expr t f   -> genFullCondBranch expr t f
-       LastJump expr _           -> hcat [ ptext (sLit "jump"), space, pprFun expr
-                                         , ptext (sLit "(...)"), semi]
-       LastReturn _              -> hcat [ ptext (sLit "return"), space 
-                                         , ptext (sLit "(...)"), semi]
-       LastSwitch arg ids        -> ppr $ CmmSwitch arg ids
-       LastCall tgt k _          -> genBareCall tgt k
+       LastBranch ident             -> ptext (sLit "goto") <+> ppr ident <> semi
+       LastCondBranch expr t f      -> genFullCondBranch expr t f
+       LastSwitch arg ids           -> ppr $ CmmSwitch arg ids
+       LastCall tgt k off updfr_off -> genBareCall tgt k off updfr_off
 
     pp_debug = text " //" <+> case stmt of
            LastBranch {} -> text "LastBranch"
            LastCondBranch {} -> text "LastCondBranch"
-           LastJump {} -> text "LastJump"
-           LastReturn {} -> text "LastReturn"
            LastSwitch {} -> text "LastSwitch"
            LastCall {} -> text "LastCall"
 
-genBareCall :: CmmExpr -> Maybe BlockId -> SDoc
-genBareCall fn k =
+genBareCall :: CmmExpr -> Maybe BlockId -> Int -> Maybe UpdFrameOffset -> SDoc
+genBareCall fn k off updfr_off =
         hcat [ ptext (sLit "call"), space
              , pprFun fn, ptext (sLit "(...)"), space
-             , case k of Nothing -> ptext (sLit "never returns")
-                         Just k -> ptext (sLit "returns to") <+> ppr k
+             , ptext (sLit "returns to") <+> ppr k <+> parens (ppr off)
+             , ptext (sLit " with update frame") <+> ppr updfr_off
              , semi ]
-        where
 
 pprFun :: CmmExpr -> SDoc
 pprFun f@(CmmLit _) = ppr f
          ]
 
 pprConvention :: Convention -> SDoc
-pprConvention (Native {})  = empty
+pprConvention (Native {})  = text "<native-convention>"
+pprConvention  Slow        = text "<slow-convention>"
+pprConvention  GC          = text "<gc-convention>"
+pprConvention  PrimOp      = text "<primop-convention>"
 pprConvention (Foreign c)  = ppr c
 pprConvention (Private {}) = text "<private-convention>"
 
 
 
 splitp_blocks :: (Block m l -> Bool) -> BlockEnv (Block m l) ->
                  Maybe (Block m l, BlockEnv (Block m l))
-splitp_blocks = undefined -- implemented in ZipCfg but not exported
+splitp_blocks = panic "splitp_blocks" -- implemented in ZipCfg but not exported
 is_exit :: Block m l -> Bool
-is_exit = undefined -- implemented in ZipCfg but not exported
+is_exit = panic "is_exit" -- implemented in ZipCfg but not exported
 
 import Maybes
 import Outputable
 import Panic
-import UniqFM
 
 import Control.Monad
 import Maybe
 
 -- | A backward rewrite takes the same inputs as a backward transfer,
 -- but instead of producing a fact, it produces a replacement graph or Nothing.
--- The type of the replacement graph is given as a type parameter 'g'
--- of kind * -> * -> *.  This design offers great flexibility to clients, 
--- but it might be worth simplifying this module by replacing this type
--- parameter with AGraph everywhere (SLPJ 19 May 2008).
 
 data BackwardRewrites middle last a = BackwardRewrites
     { br_first  :: a              -> BlockId -> Maybe (AGraph middle last)
 -- want to stress out the finite map more than necessary
 lgraphToGraph :: LastNode l => LGraph m l -> Graph m l
 lgraphToGraph (LGraph eid _ blocks) =
-    if flip any (eltsUFM blocks) $ \block -> any (== eid) (succs block) then
+    if flip any (eltsBlockEnv blocks) $ \block -> any (== eid) (succs block) then
         Graph (ZLast (mkBranchNode eid)) blocks
     else -- common case: entry is not a branch target
         let Block _ _ entry = lookupBlockEnv blocks eid `orElse` panic "missing entry!"
-        in  Graph entry (delFromUFM blocks eid)
+        in  Graph entry (delFromBlockEnv blocks eid)
     
 
 class (Outputable m, Outputable l, LastNode l, Outputable (LGraph m l)) => DebugNodes m l
 fwd_pure_anal name env transfers in_fact g =
     do (fp, _) <- anal_f name env transfers panic_rewrites in_fact g panic_fuel
        return fp
-  where -- definitiely a case of "I love lazy evaluation"
+  where -- definitely a case of "I love lazy evaluation"
     anal_f = forward_sol (\_ _ -> Nothing) panic_depth
     panic_rewrites = panic "pure analysis asked for a rewrite function"
     panic_fuel     = panic "pure analysis asked for fuel"
             in do { solve depth name start transfers rewrites in_fact g fuel
                   ; eid <- freshBlockId "temporary entry id"
                   ; (rewritten, fuel) <-
-                      rew_tail (ZFirst eid Nothing) in_fact entry emptyBlockEnv fuel
+                      rew_tail (ZFirst eid emptyStackInfo)
+                               in_fact entry emptyBlockEnv fuel
                   ; (rewritten, fuel) <- rewrite_blocks blocks rewritten fuel
                   ; a <- finish
                   ; return (a, lgraphToGraph (LGraph eid 0 rewritten), fuel)
                                ; (outfact, g, fuel) <- inner_rew getExitFact a g fuel
                                ; let (blocks, h) = splice_head' h g
                                ; (rewritten, fuel) <-
-                                 rew_tail h outfact t (blocks `plusUFM` rewritten) fuel
+                                 rew_tail h outfact t (blocks `plusBlockEnv` rewritten) fuel
                                ; rewrite_blocks bs rewritten fuel }
 
           rew_tail head in' (G.ZTail m t) rewritten fuel =
                            ; g <- areturn g
                            ; (a, g, fuel) <- inner_rew getExitFact in' g fuel
                            ; let (blocks, h) = G.splice_head' head g
-                           ; rew_tail h a t (blocks `plusUFM` rewritten) fuel
+                           ; rew_tail h a t (blocks `plusBlockEnv` rewritten) fuel
                            }
           rew_tail h in' (G.ZLast l) rewritten fuel = 
             my_trace "Rewriting last node" (ppr l) $
                            ; g <- areturn g
                            ; ((), g, fuel) <- inner_rew (return ()) in' g fuel
                            ; let g' = G.splice_head_only' h g
-                           ; return (G.lg_blocks g' `plusUFM` rewritten, fuel)
+                           ; return (G.lg_blocks g' `plusBlockEnv` rewritten, fuel)
                            }
           either_last rewrites in' (LastExit) = fr_exit rewrites in'
           either_last rewrites in' (LastOther l) = fr_last rewrites in' l
                     ; (a, fuel) <-
                       case check_maybe fuel $ last_rew env l of
                         Nothing -> return (last_in env l, fuel)
-                        Just g -> subsolve g exit_fact fuel
+                        Just g -> do g' <- areturn g
+                                     my_trace "analysis rewrites last node"
+                                      (ppr l <+> pprGraph g') $
+                                      subsolve g exit_fact fuel
                     ; set_head_fact h a fuel
                     ; return fuel }
 
          in do { fuel <- run "backward" name set_block_fact blocks fuel
                ; eid <- freshBlockId "temporary entry id"
-               ; fuel <- set_block_fact (Block eid Nothing entry) fuel
+               ; fuel <- set_block_fact (Block eid emptyStackInfo entry) fuel
                ; a <- getFact eid
                ; forgetFact eid
                ; return (a, fuel)
                                                      ppr (bt_first_in transfers a id)) $
                            setFact id $ bt_first_in transfers a id
                          ; return fuel }
-           Just g  -> do { (a, fuel) <- subsolve g a fuel
-                         ; setFact id a
+           Just g  -> do { g' <- areturn g
+                         ; (a, fuel) <- my_trace "analysis rewrites first node"
+                                      (ppr id <+> pprGraph g') $
+                                      subsolve g a fuel
+                         ; setFact id $ bt_first_in transfers a id
                          ; return fuel
                          }
        set_head_fact (G.ZHead h m) a fuel =
          case check_maybe fuel $ br_middle rewrites a m of
            Nothing -> set_head_fact h (bt_middle_in transfers a m) fuel
-           Just g -> do { (a, fuel) <- subsolve g a fuel
+           Just g -> do { g' <- areturn g
+                        ; (a, fuel) <- my_trace "analysis rewrites middle node"
+                                      (ppr m <+> pprGraph g') $
+                                      subsolve g a fuel
                         ; set_head_fact h a fuel }
 
        fixed_point g exit_fact fuel =
            in do { (FP env in_fact _ _ _, _) <-    -- don't drop the entry fact!
                      solve depth name start transfers rewrites g exit_fact fuel
                  --; env <- getAllFacts
-                 ; my_trace "facts after solving" (ppr env) $ return ()
+                 -- ; my_trace "facts after solving" (ppr env) $ return ()
                  ; eid <- freshBlockId "temporary entry id"
                  ; (rewritten, fuel) <- rewrite_blocks True blocks emptyBlockEnv fuel
                  -- We can't have the fact check fail on the bogus entry, which _may_ change
-                 ; (rewritten, fuel) <- rewrite_blocks False [Block eid Nothing entry] rewritten fuel
+                 ; (rewritten, fuel) <-
+                     rewrite_blocks False [Block eid emptyStackInfo entry]
+                                    rewritten fuel
                  ; my_trace "eid" (ppr eid) $ return ()
                  ; my_trace "exit_fact" (ppr exit_fact) $ return ()
                  ; my_trace "in_fact" (ppr in_fact) $ return ()
                    ; g <- areturn g
                    ; (a, g, fuel) <- inner_rew g exit_fact fuel
                    ; let G.Graph t new_blocks = g
-                   ; let rewritten' = new_blocks `plusUFM` rewritten
+                   ; let rewritten' = new_blocks `plusBlockEnv` rewritten
                    ; propagate check fuel h a t rewritten' -- continue at entry of g
                    } 
           either_last _env (LastExit)    = br_exit rewrites 
                    ; (a, g, fuel) <- inner_rew g a fuel
                    ; let Graph t newblocks = G.splice_tail g tail
                    ; my_trace "propagating facts" (ppr a) $
-                     propagate check fuel h a t (newblocks `plusUFM` rewritten) }
+                     propagate check fuel h a t (newblocks `plusBlockEnv` rewritten) }
           propagate check fuel (ZFirst id off) a tail rewritten =
             case maybeRewriteWithFuel fuel $ br_first rewrites a id of
-              Nothing -> do { if check then checkFactMatch id $ bt_first_in transfers a id
+              Nothing -> do { if check then
+                                checkFactMatch id $ bt_first_in transfers a id
                               else return ()
                             ; return (insertBlock (Block id off tail) rewritten, fuel) }
               Just g ->
                    ; my_trace "Rewrote first node"
                      (f4sep [ppr id <> colon, text "to", pprGraph g]) $ return ()
                    ; (a, g, fuel) <- inner_rew g a fuel
-                   ; if check then checkFactMatch id a else return ()
+                   ; if check then checkFactMatch id (bt_first_in transfers a id)
+                     else return ()
                    ; let Graph t newblocks = G.splice_tail g tail
-                   ; let r = insertBlock (Block id off t) (newblocks `plusUFM` rewritten)
+                   ; let r = insertBlock (Block id off t) (newblocks `plusBlockEnv` rewritten)
                    ; return (r, fuel) }
       in  fixed_pt_and_fuel
 
    where
      -- N.B. Each iteration starts with the same transaction limit;
      -- only the rewrites in the final iteration actually count
-     trace_block b block =
-         my_trace "about to do" (text name <+> text "on" <+> ppr (blockId block)) $
-         do_block block b
+     trace_block (b, cnt) block =
+         do b' <- my_trace "about to do" (text name <+> text "on" <+>
+                     ppr (blockId block) <+> ppr cnt) $
+                    do_block block b
+            return (b', cnt + 1)
      iterate n = 
          do { markFactsUnchanged
-            ; b <- foldM trace_block b blocks
+            ; (b, _) <-
+                 my_trace "block count:" (ppr (length blocks)) $
+                   foldM trace_block (b, 0 :: Int) blocks
             ; changed <- factsStatus
             ; facts <- getAllFacts
             ; let depth = 0 -- was nesting depth
      pprBlock (Block id off t) = nest 2 (pprFact' (id, off, t))
      pprFacts depth n env =
          my_nest depth (text "facts for iteration" <+> pp_i n <+> text "are:" $$
-                        (nest 2 $ vcat $ map pprFact $ ufmToList env))
+                        (nest 2 $ vcat $ map pprFact $ blockEnvToList env))
      pprFact  (id, a) = hang (ppr id <> colon) 4 (ppr a)
      pprFact' (id, off, a) = hang (ppr id <> parens (ppr off) <> colon) 4 (ppr a)
 
 subAnalysis' m =
     do { a <- subAnalysis $
                do { a <- m; facts <- getAllFacts
-                  ; my_trace "after sub-analysis facts are" (pprFacts facts) $
+                  ; -- my_trace "after sub-analysis facts are" (pprFacts facts) $
                     return a }
        ; facts <- getAllFacts
-       ; my_trace "in parent analysis facts are" (pprFacts facts) $
+       ; -- my_trace "in parent analysis facts are" (pprFacts facts) $
          return a }
-  where pprFacts env = nest 2 $ vcat $ map pprFact $ ufmToList env
+  where pprFacts env = nest 2 $ vcat $ map pprFact $ blockEnvToList env
         pprFact (id, a) = hang (ppr id <> colon) 4 (ppr a)
 
            info = ConstrInfo (ptrs, nptrs)
                              (fromIntegral (dataConTagZ con))
                              conName
-       return $ CmmInfo gc_target Nothing (CmmInfoTable prof cl_type info)
+       return $ CmmInfo gc_target Nothing (CmmInfoTable False prof cl_type info)
 
     ClosureInfo { closureName   = name,
                   closureLFInfo = lf_info,
                   closureSRT    = srt } ->
-       return $ CmmInfo gc_target Nothing (CmmInfoTable prof cl_type info)
+       return $ CmmInfo gc_target Nothing (CmmInfoTable False prof cl_type info)
        where
          info =
              case lf_info of
         ; let info = CmmInfo
                        gc_target
                        Nothing
-                       (CmmInfoTable
+                       (CmmInfoTable False
                         (ProfilingInfo zeroCLit zeroCLit)
                         rET_SMALL -- cmmToRawCmm may convert it to rET_BIG
                         (ContInfo frame srt_info))
 
 cgTopBinding :: DynFlags -> (StgBinding,[(Id,[Id])]) -> FCode ()
 cgTopBinding dflags (StgNonRec id rhs, _srts)
   = do { id' <- maybeExternaliseId dflags id
-       --; mapM_ (mkSRT [id']) srts
-       ; (id,info) <- cgTopRhs id' rhs
-       ; addBindC id info      -- Add the *un-externalised* Id to the envt,
-                               -- so we find it when we look up occurrences
+       ; info <- cgTopRhs id' rhs
+       ; addBindC (cg_id info) info -- Add the *un-externalised* Id to the envt,
+                                    -- so we find it when we look up occurrences
        }
 
 cgTopBinding dflags (StgRec pairs, _srts)
   = do { let (bndrs, rhss) = unzip pairs
        ; bndrs' <- mapFCs (maybeExternaliseId dflags) bndrs
        ; let pairs' = zip bndrs' rhss
-       --; mapM_ (mkSRT bndrs')  srts
        ; fixC (\ new_binds -> do 
                { addBindsC new_binds
                ; mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs' })
        ; return () }
 
---mkSRT :: [Id] -> (Id,[Id]) -> FCode ()
---mkSRT these (id,ids)
---  | null ids = nopC
---  | otherwise
---  = do       { ids <- mapFCs remap ids
---     ; id  <- remap id
---     ; emitRODataLits (mkSRTLabel (idName id) (idCafInfo id))
---                      (map (\id -> CmmLabel $ mkClosureLabel (idName id) (idCafInfo id)) ids)
---     }
---  where
---     -- Sigh, better map all the ids against the environment in 
---     -- case they've been externalised (see maybeExternaliseId below).
---    remap id = case filter (==id) these of
---             (id':_) -> returnFC id'
---             [] -> do { info <- getCgIdInfo id; return (cgIdInfoId info) }
-
 -- Urgh!  I tried moving the forkStatics call from the rhss of cgTopRhs
 -- to enclose the listFCs in cgTopBinding, but that tickled the
 -- statics "error" call in initC.  I DON'T UNDERSTAND WHY!
 
-cgTopRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
+cgTopRhs :: Id -> StgRhs -> FCode CgIdInfo
        -- The Id is passed along for setting up a binding...
        -- It's already been externalised if necessary
 
     forkStatics (cgTopRhsClosure bndr cc bi upd_flag srt args body)
 
 
-
 ---------------------------------------------------------------
 --     Module initialisation code
 ---------------------------------------------------------------
           -- In this way, Hpc enabled modules can interact seamlessly with
          -- not Hpc enabled moduled, provided Main is compiled with Hpc.
 
-        ; emitSimpleProc real_init_lbl $ withFreshLabel "ret_block" $ \retId -> catAGraphs
-               [ check_already_done retId
+        ; updfr_sz <- getUpdFrameOff
+        ; tail <- getCode (pushUpdateFrame imports
+                       (do updfr_sz' <- getUpdFrameOff
+                           emit $ mkReturn (ret_e updfr_sz') [] (pop_ret_loc updfr_sz')))
+        ; emitSimpleProc real_init_lbl $ (withFreshLabel "ret_block" $ \retId -> catAGraphs
+               [ check_already_done retId updfr_sz
                , init_prof
                , init_hpc
-               , catAGraphs $ map (registerImport way) all_imported_mods
-                , mkBranch retId ]
+                , tail])
            -- Make the "plain" procedure jump to the "real" init procedure
-       ; emitSimpleProc plain_init_lbl jump_to_init
+       ; emitSimpleProc plain_init_lbl (jump_to_init updfr_sz)
 
        -- When compiling the module in which the 'main' function lives,
        -- (that is, this_mod == main_mod)
 
 
        ; whenC (this_mod == main_mod)
-               (emitSimpleProc plain_main_init_lbl rec_descent_init)
+               (emitSimpleProc plain_main_init_lbl (rec_descent_init updfr_sz))
     }
   where
     plain_init_lbl = mkPlainModuleInitLabel this_mod
     real_init_lbl  = mkModuleInitLabel this_mod way
     plain_main_init_lbl = mkPlainModuleInitLabel rOOT_MAIN
 
-    jump_to_init = mkJump (mkLblExpr real_init_lbl) []
+    jump_to_init updfr_sz = mkJump (mkLblExpr real_init_lbl) [] updfr_sz
 
 
     -- Main refers to GHC.TopHandler.runIO, so make sure we call the
        | this_mod == main_mod = [gHC_TOP_HANDLER]
        | otherwise            = []
     all_imported_mods = imported_mods ++ extra_imported_mods
+    imports = map (\mod -> mkLblExpr (mkModuleInitLabel mod way))
+                  (filter (gHC_PRIM /=) all_imported_mods)
 
     mod_reg_val = CmmLoad (mkLblExpr moduleRegdLabel) bWord
-    check_already_done retId
+    check_already_done retId updfr_sz
      = mkCmmIfThenElse (cmmNeWord (CmmLit zeroCLit) mod_reg_val)
-                      (mkLabel retId Nothing <*> mkReturn []) mkNop
+                      (mkLabel retId emptyStackInfo
+                    <*> mkReturn (ret_e updfr_sz) [] (pop_ret_loc updfr_sz)) mkNop
        <*>     -- Set mod_reg to 1 to record that we've been here
            mkStore (mkLblExpr moduleRegdLabel) (CmmLit (mkIntCLit 1))
 
                     -- The return-code pops the work stack by 
-                    -- incrementing Sp, and then jumpd to the popped item
-    ret_code = mkAssign spReg (cmmRegOffW spReg 1)
-               <*> mkJump (CmmLoad (cmmRegOffW spReg (-1)) bWord) []
-
-    rec_descent_init = if opt_SccProfilingOn || isHpcUsed hpc_info
-                      then jump_to_init
-                      else ret_code
-
------------------------
-registerImport :: String -> Module -> CmmAGraph
-registerImport way mod
-  | mod == gHC_PRIM
-  = mkNop
-  | otherwise  -- Push the init procedure onto the work stack
-  = mkCmmCall init_lbl [] [] NoC_SRT
-  where
-    init_lbl = mkLblExpr $ mkModuleInitLabel mod way
+                    -- incrementing Sp, and then jumps to the popped item
+    ret_e updfr_sz = CmmLoad (CmmStackSlot (CallArea Old) updfr_sz) gcWord
+    ret_code updfr_sz = mkJump (ret_e updfr_sz) [] (pop_ret_loc updfr_sz)
+      -- mkAssign spReg (cmmRegOffW spReg 1) <*>
+      -- mkJump (CmmLoad (cmmRegOffW spReg (-1)) bWord) [] updfr_sz
 
+    pop_ret_loc updfr_sz = updfr_sz - widthInBytes (typeWidth bWord)
 
+    rec_descent_init updfr_sz =
+      if opt_SccProfilingOn || isHpcUsed hpc_info
+      then jump_to_init updfr_sz
+      else ret_code updfr_sz
 
 ---------------------------------------------------------------
 --     Generating static stuff for algebraic data types
            (dyn_cl_info, arg_things) = layOutDynConstr data_con arg_reps
 
            emit_info cl_info ticky_code
-               = do { code_blks <- getCode (mk_code ticky_code)
-                    ; emitClosureCodeAndInfoTable cl_info [] code_blks }
+               = emitClosureAndInfoTable cl_info [] $ mk_code ticky_code
 
            mk_code ticky_code
              =         -- NB: We don't set CC when entering data (WDP 94/06)
 
 module StgCmmBind ( 
        cgTopRhsClosure, 
        cgBind,
-       emitBlackHoleCode
+       emitBlackHoleCode,
+        pushUpdateFrame
   ) where
 
 #include "HsVersions.h"
 
+import StgCmmExpr
 import StgCmmMonad
 import StgCmmExpr
 import StgCmmEnv
 import StgSyn
 import CostCentre      
 import Id
+import Monad (foldM, liftM)
 import Name
 import Module
 import ListSetOps
                -> StgBinderInfo
                -> UpdateFlag
                -> SRT
-               -> [Id]         -- Args
+               -> [Id]                 -- Args
                -> StgExpr
-               -> FCode (Id, CgIdInfo)
+               -> FCode CgIdInfo
 
-cgTopRhsClosure id ccs binder_info upd_flag srt args body = do
+cgTopRhsClosure id ccs _ upd_flag srt args body = do
   {    -- LAY OUT THE OBJECT
     let name = idName id
   ; lf_info  <- mkClosureLFInfo id TopLevel [] upd_flag args
 
         -- BUILD THE OBJECT, AND GENERATE INFO TABLE (IF NECESSARY)
   ; emitDataLits closure_label closure_rep
-  ; forkClosureBody $ do
-       { node <- bindToReg id lf_info
-       ; closureCodeBody binder_info closure_info
-                         ccs srt_info node args body }
+  ; let fv_details :: [(NonVoid Id, VirtualHpOffset)]
+       (_, _, fv_details) = mkVirtHeapOffsets (isLFThunk lf_info) 
+                                              (addIdReps [])
+  -- Don't drop the non-void args until the closure info has been made
+  ; forkClosureBody (closureCodeBody True id closure_info ccs srt_info
+                                     (nonVoidIds args) (length args) body fv_details)
 
-  ; returnFC (id, cg_id_info) }
+  ; pprTrace "arity for" (ppr id <+> ppr (length args) <+> ppr args) $
+    returnFC cg_id_info }
 
 ------------------------------------------------------------------------
 --             Non-top-level bindings
 
 cgBind :: StgBinding -> FCode ()
 cgBind (StgNonRec name rhs)
-  = do { (name, info) <- cgRhs name rhs
-       ; addBindC name info }
+  = do { ((info, init), body) <- getCodeR $ cgRhs name rhs
+        ; addBindC (cg_id info) info
+        ; emit (init <*> body) }
 
 cgBind (StgRec pairs)
-  = do { new_binds <- fixC (\ new_binds -> 
-               do { addBindsC new_binds
-                  ; listFCs [ cgRhs b e | (b,e) <- pairs ] })
-       ; addBindsC new_binds }
+  = do { ((new_binds, inits), body) <- getCodeR $ fixC (\ new_binds_inits -> 
+               do { addBindsC $ fst new_binds_inits -- avoid premature deconstruction
+                  ; liftM unzip $ listFCs [ cgRhs b e | (b,e) <- pairs ] })
+       ; addBindsC new_binds
+       ; emit (catAGraphs inits <*> body) }
+
+{- Recursive let-bindings are tricky.
+   Consider the following pseudocode:
+     let x = \_ ->  ... y ...
+         y = \_ ->  ... z ...
+         z = \_ ->  ... x ...
+     in ...
+   For each binding, we need to allocate a closure, and each closure must
+   capture the address of the other closures.
+   We want to generate the following C-- code:
+     // Initialization Code
+     x = hp - 24; // heap address of x's closure
+     y = hp - 40; // heap address of x's closure
+     z = hp - 64; // heap address of x's closure
+     // allocate and initialize x
+     m[hp-8]   = ...
+     m[hp-16]  = y       // the closure for x captures y
+     m[hp-24] = x_info;
+     // allocate and initialize y
+     m[hp-32] = z;       // the closure for y captures z
+     m[hp-40] = y_info;
+     // allocate and initialize z
+     ...
+     
+   For each closure, we must generate not only the code to allocate and
+   initialize the closure itself, but also some Initialization Code that
+   sets a variable holding the closure pointer.
+   The complication here is that we don't know the heap offsets a priori,
+   which has two consequences:
+     1. we need a fixpoint
+     2. we can't trivially separate the Initialization Code from the
+        code that compiles the right-hand-sides
+
+   Note: We don't need this complication with let-no-escapes, because
+   in that case, the names are bound to labels in the environment,
+   and we don't need to emit any code to witness that binding.
+-}
 
 --------------------
-cgRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
+cgRhs :: Id -> StgRhs -> FCode (CgIdInfo, CmmAGraph)
    -- The Id is passed along so a binding can be set up
+   -- The returned values are the binding for the environment
+   -- and the Initialization Code that witnesses the binding
 
 cgRhs name (StgRhsCon maybe_cc con args)
-  = do { idinfo <- buildDynCon name maybe_cc con args
-       ; return (name, idinfo) }
+  = buildDynCon name maybe_cc con args
 
 cgRhs name (StgRhsClosure cc bi fvs upd_flag srt args body)
-  = mkRhsClosure name cc bi fvs upd_flag srt args body
+  = pprTrace "cgRhs closure" (ppr name <+> ppr args) $
+    mkRhsClosure name cc bi (nonVoidIds fvs) upd_flag srt args body
 
 ------------------------------------------------------------------------
 --             Non-constructor right hand sides
 ------------------------------------------------------------------------
 
 mkRhsClosure :: Id -> CostCentreStack -> StgBinderInfo
-            -> [Id]                    -- Free vars
+            -> [NonVoid Id]                    -- Free vars
             -> UpdateFlag -> SRT
-            -> [Id]                    -- Args
+            -> [Id]                            -- Args
             -> StgExpr
-            -> FCode (Id, CgIdInfo) 
+            -> FCode (CgIdInfo, CmmAGraph)
 
 {- mkRhsClosure looks for two special forms of the right-hand side:
        a) selector thunks
 
 ---------- Note [Selectors] ------------------
 mkRhsClosure   bndr cc bi
-               [the_fv]                -- Just one free var
+               [NonVoid the_fv]                -- Just one free var
                upd_flag                -- Updatable thunk
                _srt
                []                      -- A thunk
                                 (isUpdatable upd_flag)
     (_, params_w_offsets) = layOutDynConstr con (addIdReps params)
                        -- Just want the layout
-    maybe_offset         = assocMaybe params_w_offsets selectee
+    maybe_offset         = assocMaybe params_w_offsets (NonVoid selectee)
     Just the_offset      = maybe_offset
     offset_into_int       = the_offset - fixedHdrSize
 
                body@(StgApp fun_id args)
 
   | args `lengthIs` (arity-1)
-       && all isFollowableArg (map idCgRep fvs) 
+       && all isFollowableArg (map (idCgRep . stripNV) fvs) 
        && isUpdatable upd_flag
        && arity <= mAX_SPEC_AP_SIZE 
 
        arity   = length fvs
 
 ---------- Default case ------------------
-mkRhsClosure bndr cc bi fvs upd_flag srt args body
+mkRhsClosure bndr cc _ fvs upd_flag srt args body
   = do {       -- LAY OUT THE OBJECT
        -- If the binder is itself a free variable, then don't store
        -- it in the closure.  Instead, just bind it to Node on entry.
        -- NB we can be sure that Node will point to it, because we
-       -- havn't told mkClosureLFInfo about this; so if the binder
+       -- haven't told mkClosureLFInfo about this; so if the binder
        -- _was_ a free var of its RHS, mkClosureLFInfo thinks it *is*
        -- stored in the closure itself, so it will make sure that
        -- Node points to it...
        ; let
                is_elem      = isIn "cgRhsClosure"
-               bndr_is_a_fv = bndr `is_elem` fvs
-               reduced_fvs | bndr_is_a_fv = fvs `minusList` [bndr]
+               bndr_is_a_fv = (NonVoid bndr) `is_elem` fvs
+               reduced_fvs | bndr_is_a_fv = fvs `minusList` [NonVoid bndr]
                            | otherwise    = fvs
 
                
        ; c_srt <- getSRTInfo srt
        ; let   name  = idName bndr
                descr = closureDescription mod_name name
-               fv_details :: [(Id, VirtualHpOffset)]
+               fv_details :: [(NonVoid Id, VirtualHpOffset)]
                (tot_wds, ptr_wds, fv_details) 
                   = mkVirtHeapOffsets (isLFThunk lf_info) 
-                                      (addIdReps reduced_fvs)
+                                      (addIdReps (map stripNV reduced_fvs))
                closure_info = mkClosureInfo False      -- Not static
                                             bndr lf_info tot_wds ptr_wds
                                             c_srt descr
 
        -- BUILD ITS INFO TABLE AND CODE
-       ; forkClosureBody $ do
-               {   -- Bind the binder itself
-                   -- It does no harm to have it in the envt even if
-                   -- it's not a free variable; and we need a reg for it
-                 node <- bindToReg bndr lf_info
-
-                   -- Bind the free variables
-               ; mapCs (bind_fv node) fv_details
-       
-                   -- And compile the body
-               ; closureCodeBody bi closure_info cc c_srt node args body }
+       ; forkClosureBody $
+               -- forkClosureBody: (a) ensure that bindings in here are not seen elsewhere
+               --                  (b) ignore Sequel from context; use empty Sequel
+               -- And compile the body
+               closureCodeBody False bndr closure_info cc c_srt (nonVoidIds args)
+                                (length args) body fv_details
 
        -- BUILD THE OBJECT
        ; (use_cc, blame_cc) <- chooseDynCostCentres cc args body
         ; emit (mkComment $ mkFastString "calling allocDynClosure")
-       ; tmp <- allocDynClosure closure_info use_cc blame_cc 
-                                (mapFst StgVarArg fv_details)
+        ; let toVarArg (NonVoid a, off) = (NonVoid (StgVarArg a), off)
+       ; (tmp, init) <- allocDynClosure closure_info use_cc blame_cc 
+                                        (map toVarArg fv_details)
        
        -- RETURN
-       ; return (bndr, regIdInfo bndr lf_info tmp) }
-  where
-      -- A function closure pointer may be tagged, so we
-      -- must take it into account when accessing the free variables.
-     tag = tagForArity (length args)
+       ; return $ (regIdInfo bndr lf_info tmp, init) }
 
-     bind_fv node (id, off) 
-       = do { reg <- rebindToReg id
-            ; emit $ mkTaggedObjectLoad reg node off tag }
+-- Use with care; if used inappropriately, it could break invariants.
+stripNV :: NonVoid a -> a
+stripNV (NonVoid a) = a
 
 -------------------------
 cgStdThunk
        -> StgExpr
        -> LambdaFormInfo
        -> [StgArg]                     -- payload
-       -> FCode (Id, CgIdInfo)
+       -> FCode (CgIdInfo, CmmAGraph)
 
 cgStdThunk bndr cc _bndr_info body lf_info payload
   = do -- AHA!  A STANDARD-FORM THUNK
   ; (use_cc, blame_cc) <- chooseDynCostCentres cc [{- no args-}] body
 
        -- BUILD THE OBJECT
-  ; tmp <- allocDynClosure closure_info use_cc blame_cc payload_w_offsets
+  ; (tmp, init) <- allocDynClosure closure_info use_cc blame_cc payload_w_offsets
 
        -- RETURN
-  ; returnFC (bndr, regIdInfo bndr lf_info tmp) }
+  ; returnFC $ (regIdInfo bndr lf_info tmp, init) }
 
 mkClosureLFInfo :: Id          -- The binder
                -> TopLevelFlag -- True of top level
-               -> [Id]         -- Free vars
+               -> [NonVoid Id] -- Free vars
                -> UpdateFlag   -- Update flag
-               -> [Id]         -- Args
+               -> [Id]         -- Args
                -> FCode LambdaFormInfo
 mkClosureLFInfo bndr top fvs upd_flag args
-  | null args = return (mkLFThunk (idType bndr) top fvs upd_flag)
+  | null args = return (mkLFThunk (idType bndr) top (map stripNV fvs) upd_flag)
   | otherwise = do { arg_descr <- mkArgDescr (idName bndr) args
-                  ; return (mkLFReEntrant top fvs args arg_descr) }
+                  ; return (mkLFReEntrant top (map stripNV fvs) args arg_descr) }
 
 
 ------------------------------------------------------------------------
 --             The code for closures}
 ------------------------------------------------------------------------
 
-closureCodeBody :: StgBinderInfo   -- XXX: unused?
+closureCodeBody :: Bool            -- whether this is a top-level binding
+                -> Id              -- the closure's name
                -> ClosureInfo     -- Lots of information about this closure
                -> CostCentreStack -- Optional cost centre attached to closure
                -> C_SRT
-               -> LocalReg        -- The closure itself; first argument
-                                  -- The Id is in scope already, bound to this reg
-               -> [Id]
+               -> [NonVoid Id]    -- incoming args to the closure
+               -> Int             -- arity, including void args
                -> StgExpr
+               -> [(NonVoid Id, VirtualHpOffset)] -- the closure's free variables
                -> FCode ()
 
 {- There are two main cases for the code for closures.  
   argSatisfactionCheck (by calling fetchAndReschedule).  
   There info if Node points to closure is available. -- HWL -}
 
-closureCodeBody _binder_info cl_info cc srt node args body 
-  | null args  -- No args i.e. thunk
-  = do  { code <- getCode $ thunkCode cl_info cc srt node body
-       ; emitClosureCodeAndInfoTable cl_info [node] code }
+closureCodeBody top_lvl bndr cl_info cc srt args arity body fv_details
+  | length args == 0 -- No args i.e. thunk
+  = emitClosureProcAndInfoTable top_lvl bndr cl_info [] $
+      (\ (node, _) -> thunkCode cl_info fv_details cc srt node arity body)
 
-closureCodeBody _binder_info cl_info cc srt node args body 
+closureCodeBody top_lvl bndr cl_info cc srt args arity body fv_details
   = ASSERT( length args > 0 )
     do {       -- Allocate the global ticky counter,
                -- and establish the ticky-counter 
                -- label for this block
          let ticky_ctr_lbl = mkRednCountsLabel (closureName cl_info) $ clHasCafRefs cl_info
-       ; emitTickyCounter cl_info args
+       ; emitTickyCounter cl_info (map stripNV args)
        ; setTickyCtrLabel ticky_ctr_lbl $ do
 
---     -- XXX: no slow-entry code for now
---     -- Emit the slow-entry code
---     { reg_save_code <- mkSlowEntryCode cl_info reg_args
-
        -- Emit the main entry code
-       ; let node_points = nodeMustPointToIt (closureLFInfo cl_info)
-       ; arg_regs <- bindArgsToRegs args
-       ; blks <- forkProc $ getCode $ do
-               { enterCostCentre cl_info cc body
+        ; emitClosureProcAndInfoTable top_lvl bndr cl_info args $ \(node, arg_regs) -> do
+               -- Emit the slow-entry code (for entering a closure through a PAP)
+               { mkSlowEntryCode cl_info arg_regs
+
+               ; let lf_info = closureLFInfo cl_info
+                     node_points = nodeMustPointToIt lf_info
                ; tickyEnterFun cl_info
                ; whenC node_points (ldvEnterClosure cl_info)
                ; granYield arg_regs node_points
 
                        -- Main payload
-               ; entryHeapCheck node arg_regs srt $
-                 cgExpr body }
+               ; entryHeapCheck node arity arg_regs srt $ do
+               { enterCostCentre cl_info cc body
+                ; fv_bindings <- mapM bind_fv fv_details
+               ; load_fvs node lf_info fv_bindings -- Load free vars out of closure *after*
+               ; cgExpr body }}            -- heap check, to reduce live vars over check
 
-       ; emitClosureCodeAndInfoTable cl_info (node:arg_regs) blks
   }
 
-{-
+-- A function closure pointer may be tagged, so we
+-- must take it into account when accessing the free variables.
+bind_fv :: (NonVoid Id, VirtualHpOffset) -> FCode (LocalReg, WordOff)
+bind_fv (id, off) = do { reg <- rebindToReg id; return (reg, off) }
+
+load_fvs :: LocalReg -> LambdaFormInfo -> [(LocalReg, WordOff)] -> FCode ()
+load_fvs node lf_info = mapCs (\ (reg, off) ->
+      pprTrace "get tag for" (ppr reg <+> ppr tag) $ emit $ mkTaggedObjectLoad reg node off tag)
+  where tag = lfDynTag lf_info
+
 -----------------------------------------
 -- The "slow entry" code for a function.  This entry point takes its
 -- arguments on the stack.  It loads the arguments into registers
 -- normal entry point.  The function's closure is assumed to be in
 -- R1/node.
 -- 
--- The slow entry point is used in two places:
--- 
--- (a) unknown calls: eg. stg_PAP_entry 
---  (b) returning from a heap-check failure
+-- The slow entry point is used for unknown calls: eg. stg_PAP_entry 
 
-mkSlowEntryCode :: ClosureInfo -> [(Id,GlobalReg)] -> FCode CmmStmts
+mkSlowEntryCode :: ClosureInfo -> [LocalReg] -> FCode ()
 -- If this function doesn't have a specialised ArgDescr, we need
--- to generate the function's arg bitmap, slow-entry code, and
--- register-save code for the heap-check failure
--- Here, we emit the slow-entry code, and 
--- return the register-save assignments
-mkSlowEntryCode cl_info reg_args
+-- to generate the function's arg bitmap and slow-entry code.
+-- Here, we emit the slow-entry code.
+mkSlowEntryCode cl_info (_ : arg_regs) -- first arg should already be in `Node'
   | Just (_, ArgGen _) <- closureFunInfo cl_info
-  = do         { emitSimpleProc slow_lbl (emitStmts load_stmts)
-       ; return save_stmts }
-  | otherwise = return noStmts
+  = emitProcWithConvention Slow (CmmInfo Nothing Nothing CmmNonInfoTable) slow_lbl
+                           arg_regs jump
+  | otherwise = return ()
   where
-     name = closureName cl_info
-     slow_lbl = mkSlowEntryLabel name
-
-     load_stmts = mkStmts load_assts `plusStmts` mkStmts [stk_adj_pop, jump_to_entry]
-     save_stmts = oneStmt stk_adj_push `plusStmts`  mkStmts save_assts
-
-     reps_w_regs :: [(CgRep,GlobalReg)]
-     reps_w_regs = [(idCgRep id, reg) | (id,reg) <- reverse reg_args]
-     (final_stk_offset, stk_offsets)
-       = mapAccumL (\off (rep,_) -> (off + cgRepSizeW rep, off))
-                   0 reps_w_regs
-
-     load_assts = zipWithEqual "mk_load" mk_load reps_w_regs stk_offsets
-     mk_load (rep,reg) offset = CmmAssign (CmmGlobal reg) 
-                                         (CmmLoad (cmmRegOffW spReg offset)
-                                                  (argMachRep rep))
-
-     save_assts = zipWithEqual "mk_save" mk_save reps_w_regs stk_offsets
-     mk_save (rep,reg) offset = ASSERT( argMachRep rep == globalRegType reg )
-                               CmmStore (cmmRegOffW spReg offset) 
-                                        (CmmReg (CmmGlobal reg))
-
-     stk_adj_pop   = CmmAssign spReg (cmmRegOffW spReg final_stk_offset)
-     stk_adj_push  = CmmAssign spReg (cmmRegOffW spReg (- final_stk_offset))
-     jump_to_entry = CmmJump (mkLblExpr (enterLocalIdLabel name)) []
--}
+     caf_refs = clHasCafRefs cl_info
+     name     = closureName cl_info
+     slow_lbl = mkSlowEntryLabel  name caf_refs
+     fast_lbl = enterLocalIdLabel name caf_refs
+     jump = mkJump (mkLblExpr fast_lbl) (map (CmmReg . CmmLocal) arg_regs)
+                   initUpdFrameOff
+mkSlowEntryCode _ [] = panic "entering a closure with no arguments?"
 
 -----------------------------------------
-thunkCode :: ClosureInfo -> CostCentreStack -> C_SRT -> LocalReg -> StgExpr -> FCode ()
-thunkCode cl_info cc srt node body 
+thunkCode :: ClosureInfo -> [(NonVoid Id, VirtualHpOffset)] -> CostCentreStack ->
+             C_SRT -> LocalReg -> Int -> StgExpr -> FCode ()
+thunkCode cl_info fv_details cc srt node arity body 
   = do { let node_points = nodeMustPointToIt (closureLFInfo cl_info)
-
        ; tickyEnterThunk cl_info
        ; ldvEnterClosure cl_info  -- NB: Node always points when profiling
        ; granThunk node_points
 
         -- Heap overflow check
-       ; entryHeapCheck node [] srt $ do
+       ; entryHeapCheck node arity [] srt $ do
        {       -- Overwrite with black hole if necessary
                -- but *after* the heap-overflow check
          whenC (blackHoleOnEntry cl_info && node_points)
                (blackHoleIt cl_info)
 
                -- Push update frame
-       ; setupUpdate cl_info node
-
+       ; setupUpdate cl_info node $
                -- We only enter cc after setting up update so
                -- that cc of enclosing scope will be recorded
                -- in update frame CAF/DICT functions will be
                -- subsumed by this enclosing cc
-       ; enterCostCentre cl_info cc body
-
-       ; cgExpr body } }
+            do { enterCostCentre cl_info cc body
+               ; let lf_info = closureLFInfo cl_info
+               ; fv_bindings <- mapM bind_fv fv_details
+               ; load_fvs node lf_info fv_bindings
+              ; cgExpr body }}}
 
 
 ------------------------------------------------------------------------
 
     eager_blackholing = False 
 
-setupUpdate :: ClosureInfo -> LocalReg -> FCode ()
+setupUpdate :: ClosureInfo -> LocalReg -> FCode () -> FCode ()
        -- Nota Bene: this function does not change Node (even if it's a CAF),
        -- so that the cost centre in the original closure can still be
        -- extracted by a subsequent enterCostCentre
-setupUpdate closure_info node
+setupUpdate closure_info node body
   | closureReEntrant closure_info
-  = return ()
+  = body
 
   | not (isStaticClosure closure_info)
   = if closureUpdReqd closure_info
-    then do { tickyPushUpdateFrame; pushUpdateFrame node }
-    else tickyUpdateFrameOmitted
+    then do { tickyPushUpdateFrame;
+           ; pushUpdateFrame [CmmReg (CmmLocal node),
+                               mkLblExpr mkUpdInfoLabel] body }
+    else do { tickyUpdateFrameOmitted; body}
  
   | otherwise  -- A static closure
   = do         { tickyUpdateBhCaf closure_info
        ; if closureUpdReqd closure_info
          then do       -- Blackhole the (updatable) CAF:
                { upd_closure <- link_caf closure_info True
-               ; pushUpdateFrame upd_closure }
-         else tickyUpdateFrameOmitted
+               ; pushUpdateFrame [CmmReg (CmmLocal upd_closure),
+                                   mkLblExpr mkUpdInfoLabel] body }
+         else do {tickyUpdateFrameOmitted; body}
     }
 
-pushUpdateFrame :: LocalReg -> FCode ()
-pushUpdateFrame cl_reg
-  = emit (mkAddToContext (mkLblExpr mkUpdInfoLabel) 
-                        [CmmReg (CmmLocal cl_reg)])
+-- Push the update frame on the stack in the Entry area,
+-- leaving room for the return address that is already
+-- at the old end of the area.
+pushUpdateFrame :: [CmmExpr] -> FCode () -> FCode ()
+pushUpdateFrame es body
+  = do updfr  <- getUpdFrameOff
+       offset <- foldM push updfr es
+       withUpdFrameOff offset body
+     where push off e =
+             do emit (mkStore (CmmStackSlot (CallArea Old) base) e)
+                return base
+             where base = off + widthInBytes (cmmExprWidth e)
 
 -----------------------------------------------------------------------------
 -- Entering a CAF
   {    -- Alloc black hole specifying CC_HDR(Node) as the cost centre
   ; let        use_cc   = costCentreFrom (CmmReg nodeReg)
         blame_cc = use_cc
-  ; hp_rel <- allocDynClosure bh_cl_info use_cc blame_cc []
+  ; (hp_rel, init) <- allocDynClosure bh_cl_info use_cc blame_cc []
+  ; emit init
 
        -- Call the RTS function newCAF to add the CAF to the CafList
        -- so that the garbage collector can find them
 
 
 import StgSyn
 import SMRep
-import Cmm     ( ClosureTypeInfo(..) )
+import Cmm     ( ClosureTypeInfo(..), ConstrDescription )
 import CmmExpr
 
 import CLabel
 
 -------------
 mkLFReEntrant :: TopLevelFlag  -- True of top level
-             -> [Id]           -- Free vars
+             -> [Id]           -- Free vars
              -> [Id]           -- Args
              -> ArgDescr       -- Argument descriptor
              -> LambdaFormInfo
                   | otherwise           = 0
 
 lfDynTag :: LambdaFormInfo -> DynTag
-lfDynTag (LFCon con)               = tagForCon con
-lfDynTag (LFReEntrant _ arity _ _) = tagForArity arity
+-- Return the tag in the low order bits of a variable bound
+-- to this LambdaForm
+lfDynTag (LFCon con)               = pprTrace "tagForCon" (ppr con <+> ppr (tagForCon con)) $ tagForCon con
+lfDynTag (LFReEntrant _ arity _ _) = pprTrace "reentrant" (ppr arity) $ tagForArity arity
 lfDynTag _other                    = 0
 
 
   | n_args == 0    = ASSERT( arity /= 0 )
                     ReturnIt   -- No args at all
   | n_args < arity = SlowCall  -- Not enough args
-  | otherwise      = DirectEntry (enterIdLabel name caf) arity
+  | otherwise      = pprTrace "getCallMethod" (ppr name <+> ppr arity) $
+                     DirectEntry (enterIdLabel name caf) arity
 
 getCallMethod _name _ LFUnLifted n_args
   = ASSERT( n_args == 0 ) ReturnIt
        closureSMRep  :: !SMRep,          -- representation used by storage mgr
        closureSRT    :: !C_SRT,          -- What SRT applies to this closure
        closureType   :: !Type,           -- Type of closure (ToDo: remove)
-       closureDescr  :: !String          -- closure description (for profiling)
+       closureDescr  :: !String,         -- closure description (for profiling)
+        closureCafs   :: !CafInfo         -- whether the closure may have CAFs
     }
 
   -- Constructor closures don't have a unique info table label (they use
                  closureSMRep = sm_rep, 
                  closureSRT = srt_info,
                  closureType = idType id,
-                 closureDescr = descr }
+                 closureDescr = descr,
+                  closureCafs = idCafInfo id }
   where
     name   = idName id
     sm_rep = chooseSMRep is_static lf_info tot_wds ptr_wds
 
 cafBlackHoleClosureInfo :: ClosureInfo -> ClosureInfo
 cafBlackHoleClosureInfo (ClosureInfo { closureName = nm,
-                                      closureType = ty })
+                                      closureType = ty,
+                                      closureCafs = cafs })
   = ClosureInfo { closureName   = nm,
                  closureLFInfo = LFBlackHole mkCAFBlackHoleInfoTableLabel,
                  closureSMRep  = BlackHoleRep,
                  closureSRT    = NoC_SRT,
                  closureType   = ty,
-                 closureDescr  = "" }
+                 closureDescr  = "", 
+                 closureCafs   = cafs }
 cafBlackHoleClosureInfo _ = panic "cafBlackHoleClosureInfo"
 
 seCafBlackHoleClosureInfo :: ClosureInfo -> ClosureInfo
 seCafBlackHoleClosureInfo (ClosureInfo { closureName = nm,
-                                        closureType = ty })
+                                        closureType = ty,
+                                        closureCafs = cafs })
   = ClosureInfo { closureName   = nm,
                  closureLFInfo = LFBlackHole mkSECAFBlackHoleInfoTableLabel,
                  closureSMRep  = BlackHoleRep,
                  closureSRT    = NoC_SRT,
                  closureType   = ty,
-                 closureDescr  = ""  }
+                 closureDescr  = "",
+                 closureCafs   = cafs }
 seCafBlackHoleClosureInfo _ = panic "seCafBlackHoleClosureInfo"
 
 --------------------------------------
 --   Extracting ClosureTypeInfo
 --------------------------------------
 
-closureTypeInfo :: ClosureInfo -> ClosureTypeInfo
-closureTypeInfo cl_info
+-- JD: I've added the continuation arguments not for fun but because
+-- I don't want to pipe the monad in here (circular module dependencies),
+-- and I don't want to pull this code out of this module, which would
+-- require us to expose a bunch of abstract types.
+
+closureTypeInfo ::
+  ClosureInfo -> ((ConstrDescription -> ClosureTypeInfo) -> DataCon -> CLabel -> a) ->
+  (ClosureTypeInfo -> a) -> a
+closureTypeInfo cl_info k_with_con_name k_simple
    = case cl_info of
        ConInfo { closureCon = con } 
-               -> ConstrInfo (ptrs, nptrs)
-                             (fromIntegral (dataConTagZ con))
-                             con_name
+               -> k_with_con_name (ConstrInfo (ptrs, nptrs)
+                                     (fromIntegral (dataConTagZ con))) con info_lbl
                where
-                 con_name = panic "closureTypeInfo"
+                 --con_name = panic "closureTypeInfo"
                        -- Was: 
                        -- cstr <- mkByteStringCLit $ dataConIdentity con
                        -- con_name = makeRelativeRefTo info_lbl cstr
        ClosureInfo { closureName   = name,
                       closureLFInfo = LFReEntrant _ arity _ arg_descr,
                       closureSRT    = srt }
-               -> FunInfo (ptrs, nptrs)
-                          srt 
-                          (fromIntegral arity)
-                          arg_descr 
-                          (CmmLabel (mkSlowEntryLabel name (clHasCafRefs cl_info)))
+               -> k_simple $ FunInfo (ptrs, nptrs)
+                               srt 
+                               (fromIntegral arity)
+                               arg_descr 
+                               (CmmLabel (mkSlowEntryLabel name (clHasCafRefs cl_info)))
   
        ClosureInfo { closureLFInfo = LFThunk _ _ _ (SelectorThunk offset) _, 
                       closureSRT    = srt }
-               -> ThunkSelectorInfo (fromIntegral offset) srt
+               -> k_simple $ ThunkSelectorInfo (fromIntegral offset) srt
 
        ClosureInfo { closureLFInfo = LFThunk {}, 
                       closureSRT    = srt }
-               -> ThunkInfo (ptrs, nptrs) srt
+               -> k_simple $ ThunkInfo (ptrs, nptrs) srt
 
         _ -> panic "unexpected lambda form in mkCmmInfo"
   where
---    info_lbl = infoTableLabelFromCI cl_info
+    info_lbl = infoTableLabelFromCI cl_info
     ptrs     = fromIntegral $ closurePtrsSize cl_info
     size     = fromIntegral $ closureNonHdrSize cl_info
     nptrs    = size - ptrs
 --   SRTs/CAFs
 --------------------------------------
 
--- This is horrible, but we need to know whether a closure may have CAFs.
+-- We need to know whether a closure may have CAFs.
 clHasCafRefs :: ClosureInfo -> CafInfo
-clHasCafRefs (ClosureInfo {closureSRT = srt}) = 
-  case srt of NoC_SRT -> NoCafRefs
-              _       -> MayHaveCafRefs
+clHasCafRefs (ClosureInfo {closureCafs = cafs}) = cafs
 clHasCafRefs (ConInfo {}) = NoCafRefs
 
 
 import Cmm
 import CLabel
+import MkZipCfgCmm (CmmAGraph, mkNop)
 import SMRep
 import CostCentre
 import Constants
 cgTopRhsCon :: Id              -- Name of thing bound to this RHS
            -> DataCon          -- Id
            -> [StgArg]         -- Args
-           -> FCode (Id, CgIdInfo)
+           -> FCode CgIdInfo
 cgTopRhsCon id con args
   = do { 
 #if mingw32_TARGET_OS
                        = layOutStaticConstr con (addArgReps args)
 
            get_lit (arg, _offset) = do { CmmLit lit <- getArgAmode arg
-                                       ; return lit }
+                                       ; return lit }
 
        ; payload <- mapM get_lit nv_args_w_offsets
                -- NB1: nv_args_w_offsets is sorted into ptrs then non-ptrs
        ; emitDataLits closure_label closure_rep
 
                -- RETURN
-       ; return (id, litIdInfo id lf_info (CmmLabel closure_label)) }
+       ; return $ litIdInfo id lf_info (CmmLabel closure_label) }
 
 
 ---------------------------------------------------------------
                                  -- current CCS if currentOrSubsumedCCS
            -> DataCon            -- The data constructor
            -> [StgArg]           -- Its args
-           -> FCode CgIdInfo     -- Return details about how to find it
+           -> FCode (CgIdInfo, CmmAGraph)
+               -- Return details about how to find it and initialization code
 
 {- We used to pass a boolean indicating whether all the
 args were of size zero, so we could use a static
 
 buildDynCon binder _cc con []
   = return (litIdInfo binder (mkConLFInfo con)
-               (CmmLabel (mkClosureLabel (dataConName con) (idCafInfo binder))))
+               (CmmLabel (mkClosureLabel (dataConName con) (idCafInfo binder))),
+            mkNop)
 
 -------- buildDynCon: Charlike and Intlike constructors -----------
 {- The following three paragraphs about @Char@-like and @Int@-like
              offsetW = (val_int - mIN_INTLIKE) * (fixedHdrSize + 1)
                -- INTLIKE closures consist of a header and one word payload
              intlike_amode = cmmLabelOffW intlike_lbl offsetW
-       ; return (litIdInfo binder (mkConLFInfo con) intlike_amode) }
+       ; return (litIdInfo binder (mkConLFInfo con) intlike_amode, mkNop) }
 
 buildDynCon binder _cc con [arg]
   | maybeCharLikeCon con 
              offsetW = (val_int - mIN_CHARLIKE) * (fixedHdrSize + 1)
                -- CHARLIKE closures consist of a header and one word payload
              charlike_amode = cmmLabelOffW charlike_lbl offsetW
-       ; return (litIdInfo binder (mkConLFInfo con) charlike_amode) }
+       ; return (litIdInfo binder (mkConLFInfo con) charlike_amode, mkNop) }
 
 -------- buildDynCon: the general case -----------
 buildDynCon binder ccs con args
   = do { let (cl_info, args_w_offsets) = layOutDynConstr con (addArgReps args)
                -- No void args in args_w_offsets
-       ; tmp <- allocDynClosure cl_info use_cc blame_cc args_w_offsets
-       ; return (regIdInfo binder lf_info tmp) }
+       ; (tmp, init) <- allocDynClosure cl_info use_cc blame_cc args_w_offsets
+       ; return (regIdInfo binder lf_info tmp, init) }
   where
     lf_info = mkConLFInfo con
 
 
           -- The binding below forces the masking out of the tag bits
           -- when accessing the constructor field.
-    bind_arg :: (Id, VirtualHpOffset) -> FCode LocalReg
+    bind_arg :: (NonVoid Id, VirtualHpOffset) -> FCode LocalReg
     bind_arg (arg, offset) 
        = do { emit $ mkTaggedObjectLoad (idToReg arg) base offset tag
-            ; bindArgToReg arg }
+            ; pprTrace "bind_arg gets tag" (ppr arg <+> ppr tag) $
+               bindArgToReg arg }
 
 bindConArgs _other_con _base args
   = ASSERT( null args ) return []
 
        litIdInfo, lneIdInfo, regIdInfo,
        idInfoToAmode,
 
+        NonVoid(..), isVoidId, nonVoidIds,
+
        addBindC, addBindsC,
 
        bindArgsToRegs, bindToReg, rebindToReg,
 
 #include "HsVersions.h"
 
+import TyCon
 import StgCmmMonad
 import StgCmmUtils
 import StgCmmClosure
 import Id
 import VarEnv
 import Maybes
+import Monad
 import Name
 import StgSyn
 import Outputable
 
+-------------------------------------
+--     Non-void types
+-------------------------------------
+-- We frequently need the invariant that an Id or a an argument
+-- is of a non-void type. This type is a witness to the invariant.
+
+newtype NonVoid a = NonVoid a
+  deriving (Eq, Show)
+
+instance (Outputable a) => Outputable (NonVoid a) where
+  ppr (NonVoid a) = ppr a
+
+isVoidId :: Id -> Bool
+isVoidId = isVoidRep . idPrimRep
 
+nonVoidIds :: [Id] -> [NonVoid Id]
+nonVoidIds ids = [NonVoid id | id <- ids, not (isVoidRep (idPrimRep id))]
 
 -------------------------------------
 --     Manipulating CgIdInfo
     blk_id = mkBlockId (idUnique id)
 
 litIdInfo :: Id -> LambdaFormInfo -> CmmLit -> CgIdInfo
-litIdInfo id lf_info lit = mkCgIdInfo id lf_info (CmmLit lit)
+litIdInfo id lf_info lit = --mkCgIdInfo id lf_info (CmmLit lit)
+  mkCgIdInfo id lf_info (addDynTag (CmmLit lit) (lfDynTag lf_info))
 
 regIdInfo :: Id -> LambdaFormInfo -> LocalReg -> CgIdInfo
-regIdInfo id lf_info reg = mkCgIdInfo id lf_info (CmmReg (CmmLocal reg))
+regIdInfo id lf_info reg =
+  mkCgIdInfo id lf_info (addDynTag (CmmReg (CmmLocal reg)) (lfDynTag lf_info))
 
 idInfoToAmode :: CgIdInfo -> CmmExpr
 -- Returns a CmmExpr for the *tagged* pointer
-idInfoToAmode (CgIdInfo { cg_loc = CmmLoc e, cg_tag = tag })
-  = addDynTag e tag
+idInfoToAmode (CgIdInfo { cg_loc = CmmLoc e }) = e
 idInfoToAmode cg_info
   = pprPanic "idInfoToAmode" (ppr (cg_id cg_info))     -- LneLoc
 
        binds <- getBinds
        setBinds $ extendVarEnv binds name stuff_to_bind
 
-addBindsC :: [(Id, CgIdInfo)] -> FCode ()
+addBindsC :: [CgIdInfo] -> FCode ()
 addBindsC new_bindings = do
        binds <- getBinds
-       let new_binds = foldl (\ binds (name,info) -> extendVarEnv binds name info)
+       let new_binds = foldl (\ binds info -> extendVarEnv binds (cg_id info) info)
                              binds
                              new_bindings
        setBinds new_binds
 
 
 --------------------
-getArgAmode :: StgArg -> FCode CmmExpr
-getArgAmode (StgVarArg var)  = do { info  <- getCgIdInfo var; return (idInfoToAmode info) }
-getArgAmode (StgLitArg lit)  = return (CmmLit (mkSimpleLit lit))
-getArgAmode (StgTypeArg _)   = panic "getArgAmode: type arg"
+getArgAmode :: NonVoid StgArg -> FCode CmmExpr
+getArgAmode (NonVoid (StgVarArg var))  =
+  do { info  <- getCgIdInfo var; return (idInfoToAmode info) }
+getArgAmode (NonVoid (StgLitArg lit))  = liftM CmmLit $ cgLit lit
+getArgAmode (NonVoid (StgTypeArg _))   = panic "getArgAmode: type arg"
 
 getNonVoidArgAmodes :: [StgArg] -> FCode [CmmExpr]
 -- NB: Filters out void args, 
 getNonVoidArgAmodes [] = return []
 getNonVoidArgAmodes (arg:args)
   | isVoidRep (argPrimRep arg) = getNonVoidArgAmodes args
-  | otherwise = do { amode  <- getArgAmode  arg 
+  | otherwise = do { amode  <- getArgAmode (NonVoid arg)
                   ; amodes <- getNonVoidArgAmodes args
                   ; return ( amode : amodes ) }
 
 --     Interface functions for binding and re-binding names
 ------------------------------------------------------------------------
 
-bindToReg :: Id -> LambdaFormInfo -> FCode LocalReg
+bindToReg :: NonVoid Id -> LambdaFormInfo -> FCode LocalReg
 -- Bind an Id to a fresh LocalReg
-bindToReg id lf_info
-  = do { let reg = idToReg id
-       ; addBindC id (regIdInfo id lf_info reg)
+bindToReg nvid@(NonVoid id) lf_info
+  = do { let reg = idToReg nvid
+       ; addBindC id (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)))
        ; return reg }
 
-rebindToReg :: Id -> FCode LocalReg
+rebindToReg :: NonVoid Id -> FCode LocalReg
 -- Like bindToReg, but the Id is already in scope, so 
 -- get its LF info from the envt
-rebindToReg id 
+rebindToReg nvid@(NonVoid id)
   = do { info <- getCgIdInfo id
-       ; bindToReg id (cgIdInfoLF info) }
+       ; bindToReg nvid (cgIdInfoLF info) }
 
-bindArgToReg :: Id -> FCode LocalReg
-bindArgToReg id = bindToReg id (mkLFArgument id)
+bindArgToReg :: NonVoid Id -> FCode LocalReg
+bindArgToReg nvid@(NonVoid id) = bindToReg nvid (mkLFArgument id)
 
-bindArgsToRegs :: [Id] -> FCode [LocalReg]
+bindArgsToRegs :: [NonVoid Id] -> FCode [LocalReg]
 bindArgsToRegs args = mapM bindArgToReg args
 
-idToReg :: Id -> LocalReg
+idToReg :: NonVoid Id -> LocalReg
 -- Make a register from an Id, typically a function argument,
 -- free variable, or case binder
 --
 --
 -- By now the Ids should be uniquely named; else one would worry
 -- about accidental collision 
-idToReg id = LocalReg (idUnique id) 
-                     (primRepCmmType (idPrimRep id))
+idToReg (NonVoid id) = LocalReg (idUnique id) 
+                        (case idPrimRep id of VoidRep -> pprPanic "idToReg" (ppr id)
+                                              _ -> primRepCmmType (idPrimRep id))
 
 
 
 import CmmExpr
 import CoreSyn
 import DataCon
+import ForeignCall
 import Id
+import PrimOp
 import TyCon
 import CostCentre      ( CostCentreStack, currentCCS )
 import Maybes
 cgExpr (StgApp fun args)     = cgIdApp fun args
 cgExpr (StgOpApp op args ty) = cgOpApp op args ty
 cgExpr (StgConApp con args)  = cgConApp con args
-
 cgExpr (StgSCC cc expr)   = do { emitSetCCC cc; cgExpr expr }
 cgExpr (StgTick m n expr) = do { emit (mkTickBox m n); cgExpr expr }
-cgExpr (StgLit lit)       = emitReturn [CmmLit (mkSimpleLit lit)]
+cgExpr (StgLit lit)       = do cmm_lit <- cgLit lit
+                               emitReturn [CmmLit cmm_lit]
 
-cgExpr (StgLet binds expr)            = do { emit (mkComment $ mkFastString "calling cgBind"); cgBind binds; emit (mkComment $ mkFastString "calling cgExpr"); cgExpr expr }
+cgExpr (StgLet binds expr)            = do { cgBind binds; cgExpr expr }
 cgExpr (StgLetNoEscape _ _ binds expr) = do { cgLneBinds binds; cgExpr expr }
 
-cgExpr (StgCase expr _live_vars _save_vars bndr srt alt_type alts)
-  = cgCase expr bndr srt alt_type alts
+cgExpr (StgCase expr _live_vars _save_vars bndr srt alt_type alts) =
+  cgCase expr bndr srt alt_type alts
 
 cgExpr (StgLam {}) = panic "cgExpr: StgLam"
 
 ------------------------------------------------------------------------
 
 {- Generating code for a let-no-escape binding, aka join point is very
-very similar to whatwe do for a case expression.  The duality is
+very similar to what we do for a case expression.  The duality is
 between
        let-no-escape x = b
        in e
 cgLneBinds (StgNonRec bndr rhs)
   = do { local_cc <- saveCurrentCostCentre
                -- See Note [Saving the current cost centre]
-       ; (bndr,info) <- cgLetNoEscapeRhs local_cc bndr rhs 
-       ; addBindC bndr info }
+       ; info <- cgLetNoEscapeRhs local_cc bndr rhs 
+       ; addBindC (cg_id info) info }
 
 cgLneBinds (StgRec pairs)
   = do { local_cc <- saveCurrentCostCentre
 
        ; addBindsC new_bindings }
 
+
 -------------------------
-cgLetNoEscapeRhs
+cgLetNoEscapeRhs, cgLetNoEscapeRhsBody
     :: Maybe LocalReg  -- Saved cost centre
     -> Id
     -> StgRhs
-    -> FCode (Id, CgIdInfo)
-
-cgLetNoEscapeRhs local_cc bndr (StgRhsClosure cc _bi _ _upd srt args body)
-  = cgLetNoEscapeClosure bndr local_cc cc srt args body
-cgLetNoEscapeRhs local_cc bndr (StgRhsCon cc con args)
+    -> FCode CgIdInfo
+
+cgLetNoEscapeRhs local_cc bndr rhs =
+  do { (info, rhs_body) <- getCodeR $ cgLetNoEscapeRhsBody local_cc bndr rhs 
+     ; let (bid, _) = expectJust "cgLetNoEscapeRhs" $ maybeLetNoEscape info
+     ; emit (outOfLine $ mkLabel bid emptyStackInfo <*> rhs_body)
+     ; return info
+     }
+
+cgLetNoEscapeRhsBody local_cc bndr (StgRhsClosure cc _bi _ _upd srt args body)
+  = cgLetNoEscapeClosure bndr local_cc cc srt (nonVoidIds args) body
+cgLetNoEscapeRhsBody local_cc bndr (StgRhsCon cc con args)
   = cgLetNoEscapeClosure bndr local_cc cc NoSRT [] (StgConApp con args)
        -- For a constructor RHS we want to generate a single chunk of 
        -- code which can be jumped to from many places, which will 
        -> Maybe LocalReg       -- Slot for saved current cost centre
        -> CostCentreStack      -- XXX: *** NOT USED *** why not?
        -> SRT
-       -> [Id]                 -- Args (as in \ args -> body)
+       -> [NonVoid Id]         -- Args (as in \ args -> body)
        -> StgExpr              -- Body (as in above)
-       -> FCode (Id, CgIdInfo)
+       -> FCode CgIdInfo
 
 cgLetNoEscapeClosure bndr cc_slot _unused_cc srt args body
   = do  { arg_regs <- forkProc $ do    
                        -- Using altHeapCheck just reduces
                        -- instructions to save on stack
                ; return arg_regs }
-       ; return (bndr, lneIdInfo bndr arg_regs) }
+       ; return $ lneIdInfo bndr arg_regs}
 
 
 ------------------------------------------------------------------------
 
 -------------------------------------
 cgCase :: StgExpr -> Id -> SRT -> AltType -> [StgAlt] -> FCode ()
+-- cgCase (OpApp ) bndr srt AlgAlt [(DataAlt flase, a2]
+  -- | isBoolTy (idType bndr)
+  -- , isDeadBndr bndr
+  -- = 
+
 cgCase scrut bndr srt alt_type alts 
   = do { up_hp_usg <- getVirtHp        -- Upstream heap usage
        ; let ret_bndrs = chooseReturnBndrs bndr alt_type alts
        ; restoreCurrentCostCentre mb_cc
 
        ; bindArgsToRegs ret_bndrs
-       ; cgAlts gc_plan bndr alt_type alts }
+       ; cgAlts gc_plan (NonVoid bndr) alt_type alts }
 
 -----------------
 maybeSaveCostCentre :: Bool -> FCode (Maybe LocalReg)
   | otherwise    = return Nothing
 
 
-
 -----------------
 isSimpleScrut :: StgExpr -> AltType -> Bool
--- Simple scrutinee, does not allocate
-isSimpleScrut (StgOpApp _ _ _) _           = True
-isSimpleScrut (StgLit _)       _           = True
-isSimpleScrut (StgApp _ [])    (PrimAlt _) = True
+-- Simple scrutinee, does not block or allocate; hence safe to amalgamate
+-- heap usage from alternatives into the stuff before the case
+-- NB: if you get this wrong, and claim that the expression doesn't allocate
+--     when it does, you'll deeply mess up allocation
+isSimpleScrut (StgOpApp op _ _) _          = isSimpleOp op
+isSimpleScrut (StgLit _)       _           = True      -- case 1# of { 0# -> ..; ... }
+isSimpleScrut (StgApp _ [])    (PrimAlt _) = True      -- case x# of { 0# -> ..; ... }
 isSimpleScrut _                       _           = False
 
+isSimpleOp :: StgOp -> Bool
+-- True iff the op cannot block or allocate
+isSimpleOp (StgFCallOp (CCall (CCallSpec _ _ safe)) _) = not (playSafe safe)
+isSimpleOp (StgFCallOp (DNCall _) _)                   = False         -- Safe!
+isSimpleOp (StgPrimOp op)                                     = not (primOpOutOfLine op)
+
 -----------------
-chooseReturnBndrs :: Id -> AltType -> [StgAlt] -> [Id]
+chooseReturnBndrs :: Id -> AltType -> [StgAlt] -> [NonVoid Id]
 -- These are the binders of a case that are assigned
 -- by the evaluation of the scrutinee
 -- Only non-void ones come back
   = nonVoidIds ids     -- 'bndr' is not assigned!
 
 chooseReturnBndrs bndr (AlgAlt _) _alts
-  = [bndr]             -- Only 'bndr' is assigned
+  = nonVoidIds [bndr]  -- Only 'bndr' is assigned
 
 chooseReturnBndrs bndr PolyAlt _alts
-  = [bndr]             -- Only 'bndr' is assigned
+  = nonVoidIds [bndr]  -- Only 'bndr' is assigned
 
 chooseReturnBndrs _ _ _ = panic "chooseReturnBndrs"
        -- UbxTupALt has only one alternative
 
-nonVoidIds :: [Id] -> [Id]
-nonVoidIds ids = [id | id <- ids, not (isVoidRep (idPrimRep id))]
-
 -------------------------------------
-cgAlts :: GcPlan -> Id -> AltType -> [StgAlt] -> FCode ()
+cgAlts :: GcPlan -> NonVoid Id -> AltType -> [StgAlt] -> FCode ()
 -- At this point the result of the case are in the binders
 cgAlts gc_plan _bndr PolyAlt [(_, _, _, rhs)]
   = maybeAltHeapCheck gc_plan (cgExpr rhs)
                         | (DataAlt con, cmm) <- tagged_cmms ]
 
                     -- Is the constructor tag in the node reg?
-       ; if isSmallFamily fam_sz
+        ; if isSmallFamily fam_sz
          then let      -- Yes, bndr_reg has constr. tag in ls bits
                    tag_expr = cmmConstrTag1 (CmmReg bndr_reg)
                    branches' = [(tag+1,branch) | (tag,branch) <- branches]
        -- UbxTupAlt and PolyAlt have only one alternative
 
 -------------------
-cgAltRhss :: GcPlan -> Id -> [StgAlt] -> FCode [(AltCon, CmmAGraph)]
+cgAltRhss :: GcPlan -> NonVoid Id -> [StgAlt] -> FCode [(AltCon, CmmAGraph)]
 cgAltRhss gc_plan bndr alts
   = forkAlts (map cg_alt alts)
   where
     cg_alt (con, bndrs, _uses, rhs)
       = getCodeR                 $
        maybeAltHeapCheck gc_plan $
-       do { bindConArgs con base_reg bndrs
+       do { pprTrace "binding args for" (ppr bndr <+> ppr con) $ bindConArgs con base_reg bndrs
           ; cgExpr rhs
           ; return con }
 
 
 cgConApp :: DataCon -> [StgArg] -> FCode ()
 cgConApp con stg_args
+  | isUnboxedTupleCon con      -- Unboxed tuple: assign and return
+  = do { arg_exprs <- getNonVoidArgAmodes stg_args
+       ; tickyUnboxedTupleReturn (length arg_exprs)
+       ; emitReturn arg_exprs }
+
+  | otherwise  --  Boxed constructors; allocate and return
   = ASSERT( stg_args `lengthIs` dataConRepArity con )
-    do { idinfo <- buildDynCon (dataConWorkId con) currentCCS con stg_args
+    do { (idinfo, init) <- buildDynCon (dataConWorkId con) currentCCS con stg_args
                -- The first "con" says that the name bound to this closure is
                -- is "con", which is a bit of a fudge, but it only affects profiling
 
+        ; emit init
        ; emitReturn [idInfoToAmode idinfo] }
 
+
 cgIdApp :: Id -> [StgArg] -> FCode ()
+cgIdApp fun_id [] | isVoidId fun_id = emitReturn []
 cgIdApp fun_id args
   = do         { fun_info <- getCgIdInfo fun_id
-       ; case maybeLetNoEscape fun_info of
-               Just (blk_id, lne_regs) -> cgLneJump blk_id lne_regs args
-               Nothing -> cgTailCall fun_id fun_info args }
+        ; case maybeLetNoEscape fun_info of
+            Just (blk_id, lne_regs) -> cgLneJump blk_id lne_regs args
+            Nothing -> cgTailCall fun_id fun_info args }
 
 cgLneJump :: BlockId -> [LocalReg] -> [StgArg] -> FCode ()
 cgLneJump blk_id lne_regs args -- Join point; discard sequel
 cgTailCall fun_id fun_info args
   = case (getCallMethod fun_name (idCafInfo fun_id) lf_info (length args)) of
 
-           -- A value in WHNF, so we can just return it.  
+           -- A value in WHNF, so we can just return it.
        ReturnIt -> emitReturn [fun]    -- ToDo: does ReturnIt guarantee tagged?
     
        EnterIt -> ASSERT( null args )  -- Discarding arguments
-               do { [ret,call] <- forkAlts [
+               do { let fun' = CmmLoad fun (cmmExprType fun)
+                   ; [ret,call] <- forkAlts [
                        getCode $ emitReturn [fun],     -- Is tagged; no need to untag
-                       getCode $ emitCall (entryCode fun) [fun]]       -- Not tagged
+                       getCode $ do emit (mkAssign nodeReg fun)
+                                     emitCall Native (entryCode fun') []]  -- Not tagged
                   ; emit (mkCmmIfThenElse (cmmIsTagged fun) ret call) }
 
        SlowCall -> do      -- A slow function call via the RTS apply routines
                { tickySlowCall lf_info args
+                ; emit $ mkComment $ mkFastString "slowCall"
                ; slowCall fun args }
     
        -- A direct function call (possibly with some left-over arguments)
        DirectEntry lbl arity -> do
                { tickyDirectCall arity args
                ; if node_points then
-                    do call <- getCode $ directCall lbl arity args
-                       emit (mkAssign nodeReg fun <*> call)
+                    do emit $ mkComment $ mkFastString "directEntry"
+                       emit (mkAssign nodeReg fun)
+                       directCall lbl arity args
                     -- directCall lbl (arity+1) (StgVarArg fun_id : args))
                     -- >>= (emit . (mkComment (mkFastString "DirectEntry") <*>))
-                 else directCall lbl arity      args }
+                 else do emit $ mkComment $ mkFastString "directEntry else"
+                          directCall lbl arity args }
 
        JumpToIt {} -> panic "cgTailCall"       -- ???
 
   where
-    fun_name   = idName fun_id
-    fun         = idInfoToAmode fun_info
-    lf_info     = cgIdInfoLF fun_info
+    fun_name   = idName            fun_id
+    fun         = idInfoToAmode     fun_info
+    lf_info     = cgIdInfoLF        fun_info
     node_points = nodeMustPointToIt lf_info
 
 
 
 -----------------------------------------------------------------------------
 
 module StgCmmForeign (
-  cgForeignCall,
+  cgForeignCall, loadThreadState, saveThreadState,
   emitPrimCall, emitCCall,
   emitSaveThreadState, -- will be needed by the Cmm parser
   emitLoadThreadState, -- ditto
-  emitCloseNursery,
   emitOpenNursery,
  ) where
 
 import StgCmmUtils
 import StgCmmClosure
 
-import MkZipCfgCmm
+import BlockId
 import Cmm
 import CmmUtils
+import MkZipCfg
+import MkZipCfgCmm hiding (CmmAGraph)
 import Type
 import TysPrim
+import UniqSupply
 import CLabel
 import SMRep
 import ForeignCall
 import Constants
 import StaticFlags
+import FastString
 import Maybes
 import Outputable
+import ZipCfgCmmRep
 
 import Control.Monad
 
                   DynamicTarget    ->  case args of fn:rest -> (rest, fn)
              call_target = ForeignTarget cmm_target fc
        
-       ; srt <- getSRTInfo (panic "emitForeignCall")   -- SLPJ: Not sure what SRT 
-                                                       -- is right here
+       ; srt <- getSRTInfo NoSRT       -- SLPJ: Not sure what SRT 
+                                       -- is right here
+                                        -- JD: Does it matter in the new codegen?
        ; emitForeignCall safety results call_target call_args srt CmmMayReturn }
   where
        -- in the stdcall calling convention, the symbol needs @size appended
         -> CmmReturnInfo       -- This can say "never returns"
                                --   only RTS procedures do this
        -> FCode ()
-emitForeignCall safety results target args _srt _ret
-  | not (playSafe safety) = trace "emitForeignCall; ret is undone" $ do
+emitForeignCall safety results target args _srt ret
+  | not (playSafe safety) = do -- trace "emitForeignCall; ret is undone" $ do
     let (caller_save, caller_load) = callerSaveVolatileRegs
+    updfr_off <- getUpdFrameOff
     emit caller_save
-    emit (mkUnsafeCall target results args)
+    emit $ mkUnsafeCall target results args
     emit caller_load
 
-  | otherwise = panic "ToDo: emitForeignCall'"
-
-{-
   | otherwise = do
-    -- Both 'id' and 'new_base' are KindNonPtr because they're
-    -- RTS only objects and are not subject to garbage collection
-    id <- newTemp bWord
-    new_base <- newTemp (cmmRegType (CmmGlobal BaseReg))
+    updfr_off <- getUpdFrameOff
     temp_target <- load_target_into_temp target
-    let (caller_save, caller_load) = callerSaveVolatileRegs 
-    emitSaveThreadState
-    emit caller_save
-    -- The CmmUnsafe arguments are only correct because this part
-    -- of the code hasn't been moved into the CPS pass yet.
-    -- Once that happens, this function will just emit a (CmmSafe srt) call,
-    -- and the CPS will will be the one to convert that
-    -- to this sequence of three CmmUnsafe calls.
-    emit (mkCmmCall (CmmCallee suspendThread CCallConv)
-                       [ (id,AddrHint) ]
-                       [ (CmmReg (CmmGlobal BaseReg), AddrHint) ]
-                       CmmUnsafe
-                       ret)
-    emit (mkCmmCall temp_target results args CmmUnsafe ret)
-    emit (mkCmmCall (CmmCallee resumeThread CCallConv)
-                       [ (new_base, AddrHint) ]
-                       [ (CmmReg (CmmLocal id), AddrHint) ]
-                       CmmUnsafe
-                       ret )
-    -- Assign the result to BaseReg: we
-    -- might now have a different Capability!
-    emit (mkAssign (CmmGlobal BaseReg) (CmmReg (CmmLocal new_base)))
-    emit caller_load
-    emitLoadThreadState
-
-suspendThread = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("suspendThread")))
-resumeThread  = CmmLit (CmmLabel (mkRtsCodeLabel SLIT("resumeThread")))
--}
+    emit $ mkSafeCall temp_target results args updfr_off
 
 
 {-
   where arg_assign_temp (e,hint) = do
           tmp <- maybe_assign_temp e
           return (tmp,hint)
+-}
        
-load_target_into_temp (CmmCallee expr conv) = do 
+load_target_into_temp (ForeignTarget expr conv) = do 
   tmp <- maybe_assign_temp expr
-  return (CmmCallee tmp conv)
-load_target_into_temp other_target =
+  return (ForeignTarget tmp conv)
+load_target_into_temp other_target@(PrimTarget _) =
   return other_target
 
 maybe_assign_temp e
   | hasNoGlobalRegs e = return e
-  | otherwise          = do 
+  | otherwise         = do 
        -- don't use assignTemp, it uses its own notion of "trivial"
        -- expressions, which are wrong here.
         -- this is a NonPtr because it only duplicates an existing
        reg <- newTemp (cmmExprType e) --TODO FIXME NOW
        emit (mkAssign (CmmLocal reg) e)
        return (CmmReg (CmmLocal reg))
--}
 
 -- -----------------------------------------------------------------------------
 -- Save/restore the thread state in the TSO
 -- This stuff can't be done in suspendThread/resumeThread, because it
 -- refers to global registers which aren't available in the C world.
 
-emitSaveThreadState :: FCode ()
-emitSaveThreadState = do
+saveThreadState :: CmmAGraph
+saveThreadState =
   -- CurrentTSO->sp = Sp;
-  emit $ mkStore (cmmOffset stgCurrentTSO tso_SP) stgSp
-  emitCloseNursery
+  mkStore (cmmOffset stgCurrentTSO tso_SP) stgSp
+  <*> closeNursery
+  -- and save the current cost centre stack in the TSO when profiling:
+  <*> if opt_SccProfilingOn then
+       mkStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS
+      else mkNop
+
+emitSaveThreadState :: BlockId -> FCode ()
+emitSaveThreadState bid = do
+  -- CurrentTSO->sp = Sp;
+  emit $ mkStore (cmmOffset stgCurrentTSO tso_SP)
+                 (CmmStackSlot (CallArea (Young bid)) (widthInBytes (typeWidth gcWord)))
+  emit closeNursery
   -- and save the current cost centre stack in the TSO when profiling:
   when opt_SccProfilingOn $
        emit (mkStore (cmmOffset stgCurrentTSO tso_CCCS) curCCS)
 
    -- CurrentNursery->free = Hp+1;
-emitCloseNursery :: FCode ()
-emitCloseNursery = emit $ mkStore nursery_bdescr_free (cmmOffsetW stgHp 1)
+closeNursery :: CmmAGraph
+closeNursery = mkStore nursery_bdescr_free (cmmOffsetW stgHp 1)
 
-emitLoadThreadState :: FCode ()
-emitLoadThreadState = do
-  tso <- newTemp gcWord -- TODO FIXME NOW
-  emit $ catAGraphs [
+loadThreadState :: LocalReg -> CmmAGraph
+loadThreadState tso = do
+  -- tso <- newTemp gcWord -- TODO FIXME NOW
+  catAGraphs [
        -- tso = CurrentTSO;
        mkAssign (CmmLocal tso) stgCurrentTSO,
        -- Sp = tso->sp;
                              bWord),
        -- SpLim = tso->stack + RESERVED_STACK_WORDS;
        mkAssign spLim (cmmOffsetW (cmmOffset (CmmReg (CmmLocal tso)) tso_STACK)
-                                   rESERVED_STACK_WORDS)
-    ]
-  emitOpenNursery
-  -- and load the current cost centre stack from the TSO when profiling:
-  when opt_SccProfilingOn $
-       emit (mkStore curCCSAddr 
-               (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) ccsType))
-
-emitOpenNursery :: FCode ()
-emitOpenNursery = emit $ catAGraphs [
+                                   rESERVED_STACK_WORDS),
+        openNursery,
+        -- and load the current cost centre stack from the TSO when profiling:
+        if opt_SccProfilingOn then
+         mkStore curCCSAddr
+                  (CmmLoad (cmmOffset (CmmReg (CmmLocal tso)) tso_CCCS) ccsType)
+        else mkNop]
+emitLoadThreadState :: LocalReg -> FCode ()
+emitLoadThreadState tso = emit $ loadThreadState tso
+
+openNursery :: CmmAGraph
+openNursery = catAGraphs [
         -- Hp = CurrentNursery->free - 1;
        mkAssign hp (cmmOffsetW (CmmLoad nursery_bdescr_free bWord) (-1)),
 
                )
            )
    ]
-
+emitOpenNursery :: FCode ()
+emitOpenNursery = emit openNursery
 
 nursery_bdescr_free   = cmmOffset stgCurrentNursery oFFSET_bdescr_free
 nursery_bdescr_start  = cmmOffset stgCurrentNursery oFFSET_bdescr_start
 
 getFCallArgs :: [StgArg] -> FCode [(CmmExpr, ForeignHint)]
 -- (a) Drop void args
--- (b) Add foriegn-call shim code
+-- (b) Add foreign-call shim code
 -- It's (b) that makes this differ from getNonVoidArgAmodes
 
 getFCallArgs args
     get arg | isVoidRep arg_rep 
            = return Nothing
            | otherwise
-           = do { cmm <- getArgAmode arg
+           = do { cmm <- getArgAmode (NonVoid arg)
                 ; return (Just (add_shim arg_ty cmm, hint)) }
            where
              arg_ty  = stgArgType arg
 
 
 layOutDynConstr, layOutStaticConstr
        :: DataCon -> [(PrimRep, a)]
-       -> (ClosureInfo, [(a, VirtualHpOffset)])
+       -> (ClosureInfo, [(NonVoid a, VirtualHpOffset)])
 -- No Void arguments in result
 
 layOutDynConstr    = layOutConstr False
 layOutStaticConstr = layOutConstr True
 
 layOutConstr :: Bool -> DataCon -> [(PrimRep, a)]
-            -> (ClosureInfo, [(a, VirtualHpOffset)])
+            -> (ClosureInfo, [(NonVoid a, VirtualHpOffset)])
 layOutConstr is_static data_con args
    = (mkConInfo is_static data_con tot_wds ptr_wds,
       things_w_offsets)
        -> CmmExpr              -- Cost Centre to blame for this alloc
                                -- (usually the same; sometimes "OVERHEAD")
 
-       -> [(StgArg, VirtualHpOffset)]  -- Offsets from start of the object
-                                       -- ie Info ptr has offset zero.
-                                       -- No void args in here
-       -> FCode LocalReg
+       -> [(NonVoid StgArg, VirtualHpOffset)]  -- Offsets from start of the object
+                                               -- ie Info ptr has offset zero.
+                                               -- No void args in here
+       -> FCode (LocalReg, CmmAGraph)
 
 -- allocDynClosure allocates the thing in the heap, 
 -- and modifies the virtual Hp to account for this.
+-- The second return value is the graph that sets the value of the
+-- returned LocalReg, which should point to the closure after executing
+-- the graph.
 
 -- Note [Return a LocalReg]
 -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        -- Assign to a temporary and return
        -- Note [Return a LocalReg]
        ; hp_rel <- getHpRelOffset info_offset
-       ; assignTemp hp_rel }
+       ; getCodeR $ assignTemp hp_rel }
 
 emitSetDynHdr :: CmmExpr -> CmmExpr -> CmmExpr -> FCode ()
 emitSetDynHdr base info_ptr ccs 
 mkStaticClosure info_lbl ccs payload padding_wds static_link_field saved_info_field
   =  [CmmLabel info_lbl]
   ++ variable_header_words
-  ++ payload
+  ++ concatMap padLitToWord payload
   ++ padding_wds
   ++ static_link_field
   ++ saved_info_field
        ++ staticProfHdr ccs
        ++ staticTickyHdr
 
+-- JD: Simon had ellided this padding, but without it the C back end asserts failure.
+-- Maybe it's a bad assertion, and this padding is indeed unnecessary?
+padLitToWord :: CmmLit -> [CmmLit]
+padLitToWord lit = lit : padding pad_length
+  where width = typeWidth (cmmLitType lit)
+        pad_length = wORD_SIZE - widthInBytes width :: Int
+
+        padding n | n <= 0 = []
+                  | n `rem` 2 /= 0 = CmmInt 0 W8  : padding (n-1)
+                  | n `rem` 4 /= 0 = CmmInt 0 W16 : padding (n-2)
+                  | n `rem` 8 /= 0 = CmmInt 0 W32 : padding (n-4)
+                  | otherwise      = CmmInt 0 W64 : padding (n-8)
+
 -----------------------------------------------------------
 --             Heap overflow checking
 -----------------------------------------------------------
        Here, the info table needed by the call 
        to gc_1p should be the *same* as the
        one for the call to f; the C-- optimiser 
-       spots this sharing opportunity
+       spots this sharing opportunity)
 
    (b) No canned sequence for results of f
        Note second info table
 --------------------------------------------------------------
 -- A heap/stack check at a function or thunk entry point.
 
-entryHeapCheck :: LocalReg     -- Function
-              -> [LocalReg]    -- Args (empty for thunk)
+entryHeapCheck :: LocalReg     -- Function (closure environment)
+              -> Int           -- Arity -- not same as length args b/c of voids
+              -> [LocalReg]    -- Non-void args (empty for thunk)
               -> C_SRT
               -> FCode ()
               -> FCode ()
 
-entryHeapCheck fun args srt code
-  = heapCheck gc_call code     -- The 'fun' keeps relevant CAFs alive
+entryHeapCheck fun arity args srt code
+  = do updfr_sz <- getUpdFrameOff
+       heapCheck True (gc_call updfr_sz) code   -- The 'fun' keeps relevant CAFs alive
   where
-    gc_call 
-       | null args = mkJump (CmmReg (CmmGlobal GCEnter1)) [CmmReg (CmmLocal fun)]
-       | otherwise = case gc_lbl args of
-                       Just lbl -> mkJump (CmmLit (CmmLabel (mkRtsCodeLabel lbl)))
-                                          (map (CmmReg . CmmLocal) (fun:args))
-                       Nothing  -> mkCmmCall generic_gc [] [] srt
+    fun_expr = CmmReg (CmmLocal fun)
+    -- JD: ugh... we should only do the following for dynamic closures
+    args' = fun_expr : map (CmmReg . CmmLocal) args
+    gc_call updfr_sz
+       | arity == 0 = mkJumpGC (CmmReg (CmmGlobal GCEnter1)) args' updfr_sz
+       | otherwise  = case gc_lbl (fun : args) of
+                        Just lbl -> mkJumpGC (CmmLit (CmmLabel (mkRtsCodeLabel lbl)))
+                                             args' updfr_sz
+                        Nothing  -> mkCall generic_gc GC [] [] updfr_sz
 
     gc_lbl :: [LocalReg] -> Maybe LitString
-    gc_lbl [reg] 
+{-
+    gc_lbl [reg]
        | isGcPtrType ty  = Just (sLit "stg_gc_unpt_r1") -- "stg_gc_fun_1p"
        | isFloatType ty  = case width of
                              W32 -> Just (sLit "stg_gc_f1") -- "stg_gc_fun_f1"
        where
          ty = localRegType reg
          width = typeWidth ty
+-}
 
     gc_lbl regs = gc_lbl_ptrs (map (isGcPtrType . localRegType) regs)
 
 
 altHeapCheck :: [LocalReg] -> C_SRT -> FCode a -> FCode a
 altHeapCheck regs srt code
-  = heapCheck gc_call code
+  = do updfr_sz <- getUpdFrameOff
+       heapCheck False (gc_call updfr_sz) code
   where
-    gc_call
-       | null regs = mkCmmCall generic_gc [] [] srt
+    gc_call updfr_sz
+       | null regs = mkCall generic_gc GC [] [] updfr_sz
 
        | Just gc_lbl <- rts_label regs -- Canned call
-       = mkCmmCall (CmmLit (CmmLabel (mkRtsCodeLabel gc_lbl)))
-                   regs
-                   (map (CmmReg . CmmLocal) regs)
-                   srt
+       = mkCall    (CmmLit (CmmLabel (mkRtsCodeLabel gc_lbl))) GC
+                   regs (map (CmmReg . CmmLocal) regs) updfr_sz
        | otherwise             -- No canned call, and non-empty live vars
-       = mkCmmCall generic_gc [] [] srt
+       = mkCall generic_gc GC [] [] updfr_sz
 
+{-
     rts_label [reg] 
        | isGcPtrType ty  = Just (sLit "stg_gc_unpt_r1")
        | isFloatType ty  = case width of
                              _other -> Nothing
        | otherwise       = case width of
                              W32 -> Just (sLit "stg_gc_unbx_r1")
-                             W64 -> Just (sLit "stg_gc_unbx_l1")
+                             W64 -> Just (sLit "stg_gc_l1") -- "stg_gc_fun_unbx_l1"
                              _other -> Nothing -- Narrow cases
        where
          ty = localRegType reg
          width = typeWidth ty
+-}
 
     rts_label _ = Nothing
 
 
 generic_gc :: CmmExpr  -- The generic GC procedure; no params, no resuls
-generic_gc = CmmLit (CmmLabel (mkRtsCodeLabel (sLit "stg_gc_fun")))
+generic_gc = CmmLit (CmmLabel (mkRtsCodeLabel (sLit "stg_gc_noregs")))
+-- JD: TEMPORARY -- UNTIL THOSE FUNCTIONS EXIST...
+-- generic_gc = CmmLit (CmmLabel (mkRtsCodeLabel (sLit "stg_gc_fun")))
 
 -------------------------------
-heapCheck :: CmmAGraph -> FCode a -> FCode a
-heapCheck do_gc code
+heapCheck :: Bool -> CmmAGraph -> FCode a -> FCode a
+heapCheck checkStack do_gc code
   = getHeapUsage $ \ hpHw ->
-    do { emit (do_checks hpHw do_gc)
+    do { emit $ do_checks checkStack hpHw do_gc
                -- Emit heap checks, but be sure to do it lazily so 
                -- that the conditionals on hpHw don't cause a black hole
        ; tickyAllocHeap hpHw
        ; setRealHp hpHw
        ; code }
 
-do_checks :: WordOff   -- Heap headroom
-         -> CmmAGraph  -- What to do on failure
-         -> CmmAGraph
-do_checks 0 _ 
-  = mkNop
-do_checks alloc do_gc
-  = withFreshLabel "gc" $ \ blk_id ->
-    mkLabel blk_id Nothing
-    <*>        mkAssign hpReg bump_hp
-    <*> mkCmmIfThen hp_oflo 
-               (save_alloc
-            <*> do_gc
-            <*> mkBranch blk_id)
-               -- Bump heap pointer, and test for heap exhaustion
+do_checks :: Bool       -- Should we check the stack?
+          -> WordOff   -- Heap headroom
+          -> CmmAGraph -- What to do on failure
+          -> CmmAGraph
+do_checks checkStack alloc do_gc
+  = withFreshLabel "gc" $ \ loop_id ->
+    withFreshLabel "gc" $ \ gc_id   ->
+      mkLabel loop_id emptyStackInfo
+      <*> (let hpCheck = if alloc == 0 then mkNop
+                         else mkAssign hpReg bump_hp <*>
+                              mkCmmIfThen hp_oflo (save_alloc <*> mkBranch gc_id)
+           in if checkStack then
+                mkCmmIfThenElse sp_oflo (mkBranch gc_id) hpCheck
+              else hpCheck)
+      <*> mkComment (mkFastString "outOfLine should follow:")
+      <*> outOfLine (mkLabel gc_id emptyStackInfo
+                     <*> mkComment (mkFastString "outOfLine here")
+                     <*> do_gc
+                     <*> mkBranch loop_id)
+               -- Test for stack pointer exhaustion, then
+               -- bump heap pointer, and test for heap exhaustion
                -- Note that we don't move the heap pointer unless the 
                -- stack check succeeds.  Otherwise we might end up
                -- with slop at the end of the current block, which can 
     alloc_lit = CmmLit (mkIntCLit (alloc*wORD_SIZE))   -- Bytes
     bump_hp   = cmmOffsetExprB (CmmReg hpReg) alloc_lit
 
+       -- Sp overflow if (Sp - CmmHighStack < SpLim)
+    sp_oflo = CmmMachOp mo_wordULt 
+                 [CmmMachOp (MO_Sub (typeWidth (cmmRegType spReg)))
+                             [CmmReg spReg, CmmLit CmmHighStackMark],
+                   CmmReg spLimReg]
        -- Hp overflow if (Hp > HpLim)
        -- (Hp has been incremented by now)
        -- HpLim points to the LAST WORD of valid allocation space.
 
        mkArgDescr, 
        emitCall, emitReturn,
 
-       emitClosureCodeAndInfoTable,
+       emitClosureProcAndInfoTable,
+       emitClosureAndInfoTable,
 
        slowCall, directCall, 
 
 import Cmm
 import CLabel
 import StgSyn
+import DataCon
 import Id
 import Name
 import TyCon           ( PrimRep(..) )
 import Util
 import Data.List
 import Outputable
-import FastString      ( LitString, sLit )
+import FastString      ( mkFastString, LitString, sLit )
 
 ------------------------------------------------------------------------
 --             Call and return sequences
 --     p=x; q=y; 
 emitReturn results 
   = do  { adjustHpBackwards
-       ; sequel <- getSequel; 
+       ; sequel    <- getSequel;
+       ; updfr_off <- getUpdFrameOff
        ; case sequel of
-           Return _        -> emit (mkReturn results)
-           AssignTo regs _ -> emit (mkMultiAssign regs results)
+           Return _        -> emit (mkReturnSimple results updfr_off)
+           AssignTo regs _ -> emit (mkMultiAssign  regs results)
     }
 
-emitCall :: CmmExpr -> [CmmExpr] -> FCode ()
+emitCall :: Convention -> CmmExpr -> [CmmExpr] -> FCode ()
 -- (cgCall fun args) makes a call to the entry-code of 'fun', 
 -- passing 'args', and returning the results to the current sequel
-emitCall fun args
+emitCall conv fun args
   = do { adjustHpBackwards
-       ; sequel <- getSequel;
+       ; sequel <- getSequel
+       ; updfr_off <- getUpdFrameOff
+        ; emit $ mkComment $ mkFastString "emitcall"
        ; case sequel of
-           Return _              -> emit (mkJump fun args)
-           AssignTo res_regs srt -> emit (mkCmmCall fun res_regs args srt)
+           Return _              -> emit (mkForeignJump conv fun args updfr_off)
+           AssignTo res_regs srt -> emit (mkCall fun conv res_regs args updfr_off)
     }
 
 adjustHpBackwards :: FCode ()
 -- Both arity and args include void args
 directCall lbl arity stg_args 
   = do { cmm_args <- getNonVoidArgAmodes stg_args
-       ; direct_call lbl arity cmm_args (argsLReps stg_args) }
+       ; direct_call "directCall" lbl arity cmm_args (argsLReps stg_args) }
 
 slowCall :: CmmExpr -> [StgArg] -> FCode ()
 -- (slowCall fun args) applies fun to args, returning the results to Sequel
        ; slow_call fun cmm_args (argsLReps stg_args) }
 
 --------------
-direct_call :: CLabel -> Arity -> [CmmExpr] -> [LRep] -> FCode ()
--- NB1: (length args) maybe less than (length reps), because
+direct_call :: String -> CLabel -> Arity -> [CmmExpr] -> [LRep] -> FCode ()
+-- NB1: (length args) may be less than (length reps), because
 --     the args exclude the void ones
 -- NB2: 'arity' refers to the *reps* 
-direct_call lbl arity args reps
-  | null rest_args
-  = ASSERT( arity == length args) 
-    emitCall target args
+direct_call caller lbl arity args reps
+  | debugIsOn && arity > length reps   -- Too few args
+  =        -- Caller should ensure that there enough args!  
+    pprPanic "direct_call" (text caller <+> ppr arity <+> ppr lbl <+> ppr (length reps)
+                           <+> ppr args <+> ppr reps )
 
-  | otherwise
+  | null rest_reps     -- Precisely the right number of arguments
+  = emitCall Native target args
+
+  | otherwise          -- Over-saturated call
   = ASSERT( arity == length initial_reps )
     do { pap_id <- newTemp gcWord
        ; let srt = pprTrace "Urk! SRT for over-sat call" 
                             (ppr lbl) NoC_SRT
                -- XXX: what if rest_args contains static refs?
        ; withSequel (AssignTo [pap_id] srt)
-                    (emitCall target args)
+                    (emitCall Native target fast_args)
        ; slow_call (CmmReg (CmmLocal pap_id)) 
                    rest_args rest_reps }
   where
     target = CmmLit (CmmLabel lbl)
     (initial_reps, rest_reps) = splitAt arity reps
     arg_arity = count isNonV initial_reps
-    (_, rest_args) = splitAt arg_arity args
+    (fast_args, rest_args) = splitAt arg_arity args
 
 --------------
 slow_call :: CmmExpr -> [CmmExpr] -> [LRep] -> FCode ()
 slow_call fun args reps
-  = direct_call (mkRtsApFastLabel rts_fun) (arity+1) 
-               (fun : args) (P : reps)
+  = do call <- getCode $ direct_call "slow_call" (mkRtsApFastLabel rts_fun) arity args reps
+       emit $ mkComment $ mkFastString ("slow_call for " ++ showSDoc (ppr fun) ++
+                                        " with pat " ++ showSDoc (ptext rts_fun))
+       emit (mkAssign nodeReg fun <*> call)
   where
     (rts_fun, arity) = slowCallPattern reps
 
          | V   -- Void
          | F   -- Float
          | D   -- Double
+instance Outputable LRep where
+  ppr P = text "P"
+  ppr N = text "N"
+  ppr L = text "L"
+  ppr V = text "V"
+  ppr F = text "F"
+  ppr D = text "D"
 
 toLRep :: PrimRep -> LRep
 toLRep VoidRep          = V
   -> [(PrimRep,a)]     -- Things to make offsets for
   -> (WordOff,         -- _Total_ number of words allocated
       WordOff,         -- Number of words allocated for *pointers*
-      [(a, VirtualHpOffset)])
+      [(NonVoid a, VirtualHpOffset)])
 
 -- Things with their offsets from start of object in order of
 -- increasing offset; BUT THIS MAY BE DIFFERENT TO INPUT ORDER
 
     computeOffset wds_so_far (rep, thing)
       = (wds_so_far + lRepSizeW (toLRep rep), 
-        (thing, hdr_size + wds_so_far))
+        (NonVoid thing, hdr_size + wds_so_far))
 
 
 -------------------------------------------------------------------------
 -- Here we make an info table of type 'CmmInfo'.  The concrete
 -- representation as a list of 'CmmAddr' is handled later
 -- in the pipeline by 'cmmToRawCmm'.
-
-emitClosureCodeAndInfoTable :: ClosureInfo -> CmmFormals
-                           -> CmmAGraph -> FCode ()
-emitClosureCodeAndInfoTable cl_info args body
- = do  { info <- mkCmmInfo cl_info
-       ; emitProc info (infoLblToEntryLbl info_lbl) args body }
+-- When loading the free variables, a function closure pointer may be tagged,
+-- so we must take it into account.
+
+emitClosureProcAndInfoTable :: Bool                    -- top-level? 
+                            -> Id                      -- name of the closure
+                            -> ClosureInfo             -- lots of info abt the closure
+                            -> [NonVoid Id]            -- incoming arguments
+                            -> ((LocalReg, [LocalReg]) -> FCode ()) -- function body
+                            -> FCode ()
+emitClosureProcAndInfoTable top_lvl bndr cl_info args body
+ = do  { let lf_info = closureLFInfo cl_info
+       -- Bind the binder itself, but only if it's not a top-level
+        -- binding. We need non-top let-bindings to refer to the
+        -- top-level binding, which this binding would incorrectly shadow.
+        ; node <- if top_lvl then return $ idToReg (NonVoid bndr)
+                  else bindToReg (NonVoid bndr) lf_info
+        ; arg_regs <-
+            pprTrace "bindArgsToRegs" (ppr args) $
+            bindArgsToRegs args
+        ; emitClosureAndInfoTable cl_info (node : arg_regs) $ body (node, arg_regs)
+        }
+
+-- Data constructors need closures, but not with all the argument handling
+-- needed for functions. The shared part goes here.
+emitClosureAndInfoTable :: ClosureInfo -> [LocalReg] -> FCode () -> FCode ()
+emitClosureAndInfoTable cl_info args body
+  = do { info <- mkCmmInfo cl_info
+       ; blks <- getCode body
+       ; emitProc info (infoLblToEntryLbl info_lbl) args blks
+       }
   where
     info_lbl = infoTableLabelFromCI cl_info
 
 -- Not used for return points.  (The 'smRepClosureTypeInt' call would panic.)
 mkCmmInfo :: ClosureInfo -> FCode CmmInfo
 mkCmmInfo cl_info
-  = do { prof <- if opt_SccProfilingOn then
+  = do { info <- closureTypeInfo cl_info k_with_con_name return 
+        ; prof <- if opt_SccProfilingOn then
                     do fd_lit <- mkStringCLit (closureTypeDescr cl_info)
                       ad_lit <- mkStringCLit (closureValDescr  cl_info)
                       return $ ProfilingInfo fd_lit ad_lit
                   else return $ ProfilingInfo (mkIntCLit 0) (mkIntCLit 0)
-       ; return (CmmInfo gc_target Nothing (CmmInfoTable prof cl_type info)) }
+       ; return (CmmInfo gc_target Nothing
+                   (CmmInfoTable (isStaticClosure cl_info) prof cl_type info)) }
   where
-    info = closureTypeInfo cl_info
+    k_with_con_name con_info con info_lbl =
+      do cstr <- mkByteStringCLit $ dataConIdentity con
+         return $ con_info $ makeRelativeRefTo info_lbl cstr
     cl_type  = smRepClosureTypeInt (closureSMRep cl_info)
 
     -- The gc_target is to inform the CPS pass when it inserts a stack check.
 
        returnFC, fixC, nopC, whenC, 
        newUnique, newUniqSupply, 
 
-       emit, emitData, emitProc, emitSimpleProc,
+       emit, emitData, emitProc, emitProcWithConvention, emitSimpleProc,
 
        getCmm, cgStmtsToBlocks,
        getCodeR, getCode, getHeapUsage,
        setSRTLabel, getSRTLabel, 
        setTickyCtrLabel, getTickyCtrLabel,
 
+       withUpdFrameOff, getUpdFrameOff, initUpdFrameOff,
+
        HeapUsage(..), VirtualHpOffset, initHpUsage,
        getHpUsage,  setHpUsage, heapHWM,
        setVirtHp, getVirtHp, setRealHp,
 import StgCmmClosure
 import DynFlags
 import MkZipCfgCmm
+import ZipCfgCmmRep (UpdFrameOffset)
 import BlockId
 import Cmm
 import CLabel
 
 data CgInfoDownwards   -- information only passed *downwards* by the monad
   = MkCgInfoDown {
-       cgd_dflags  :: DynFlags,
-       cgd_mod     :: Module,          -- Module being compiled
-       cgd_statics :: CgBindings,      -- [Id -> info] : static environment
-       cgd_srt_lbl :: CLabel,          -- Label of the current top-level SRT
-       cgd_ticky   :: CLabel,          -- Current destination for ticky counts
-       cgd_sequel  :: Sequel           -- What to do at end of basic block
+       cgd_dflags     :: DynFlags,
+       cgd_mod        :: Module,         -- Module being compiled
+       cgd_statics    :: CgBindings,     -- [Id -> info] : static environment
+       cgd_srt_lbl    :: CLabel,         -- Label of the current top-level SRT
+       cgd_updfr_off  :: UpdFrameOffset, -- Size of current update frame
+       cgd_ticky      :: CLabel,         -- Current destination for ticky counts
+       cgd_sequel     :: Sequel          -- What to do at end of basic block
   }
 
 type CgBindings = IdEnv CgIdInfo
                        -- Can differ from the Id at occurrence sites by 
                        -- virtue of being externalised, for splittable C
        , cg_lf  :: LambdaFormInfo 
-       , cg_loc :: CgLoc
+       , cg_loc :: CgLoc                    -- CmmExpr for the *tagged* value
        , cg_rep :: PrimRep                  -- Cache for (idPrimRep id)
         , cg_tag :: {-# UNPACK #-} !DynTag   -- Cache for (lfDynTag cg_lf)
-         }
+        }
 
 data CgLoc
   = CmmLoc CmmExpr     -- A stable CmmExpr; that is, one not mentioning
        [LocalReg]      -- Put result(s) in these regs and fall through
                        --      NB: no void arguments here
        C_SRT           -- Here are the statics live in the continuation
-
+                       -- E.g.  case (case x# of 0# -> a; DEFAULT -> b) of {
+                       --          r -> <blah>
+                       -- When compiling the nested case, remember to put the
+                       -- result in r, and fall through  
 
 
 initCgInfoDown :: DynFlags -> Module -> CgInfoDownwards
 initCgInfoDown dflags mod
-  = MkCgInfoDown {     cgd_dflags  = dflags,
-                       cgd_mod     = mod,
-                       cgd_statics = emptyVarEnv,
-                       cgd_srt_lbl = error "initC: srt_lbl",
-                       cgd_ticky   = mkTopTickyCtrLabel,
-                       cgd_sequel  = initSequel }
+  = MkCgInfoDown {     cgd_dflags    = dflags,
+                       cgd_mod       = mod,
+                       cgd_statics   = emptyVarEnv,
+                       cgd_srt_lbl   = error "initC: srt_lbl",
+                       cgd_updfr_off = initUpdFrameOff,
+                       cgd_ticky     = mkTopTickyCtrLabel,
+                       cgd_sequel    = initSequel }
 
 initSequel :: Sequel
 initSequel = Return False
 
+initUpdFrameOff :: UpdFrameOffset
+initUpdFrameOff = widthInBytes wordWidth -- space for the RA
+
 
 --------------------------------------------------------
 --     The code generator state
                                -- the info-down part
 
      cgs_hp_usg  :: HeapUsage,
-     
+
      cgs_uniqs :: UniqSupply }
 
 data HeapUsage =
 
 initCgState :: UniqSupply -> CgState
 initCgState uniqs
-  = MkCgState { cgs_stmts = mkNop, cgs_tops = nilOL,
-               cgs_binds = emptyVarEnv, 
-               cgs_hp_usg = initHpUsage,
-               cgs_uniqs = uniqs }
+  = MkCgState { cgs_stmts      = mkNop, cgs_tops = nilOL,
+               cgs_binds      = emptyVarEnv, 
+               cgs_hp_usg     = initHpUsage,
+               cgs_uniqs      = uniqs }
 
 stateIncUsage :: CgState -> CgState -> CgState
 -- stateIncUsage@ e1 e2 incorporates in e1 
        withInfoDown code (info { cgd_srt_lbl = srt_lbl})
 
 -- ----------------------------------------------------------------------------
+-- Get/set the size of the update frame
+
+-- We keep track of the size of the update frame so that we
+-- can set the stack pointer to the proper address on return
+-- (or tail call) from the closure.
+-- There should be at most one update frame for each closure.
+-- Note: I'm including the size of the original return address
+-- in the size of the update frame -- hence the default case on `get'.
+
+withUpdFrameOff :: UpdFrameOffset -> FCode () -> FCode ()
+withUpdFrameOff size code
+  = do { info  <- getInfoDown
+       ; withInfoDown code (info {cgd_updfr_off = size }) }
+
+getUpdFrameOff :: FCode UpdFrameOffset
+getUpdFrameOff
+  = do { info  <- getInfoDown
+       ; return $ cgd_updfr_off info }
+
+-- ----------------------------------------------------------------------------
 -- Get/set the current ticky counter label
 
 getTickyCtrLabel :: FCode CLabel
   = do { info <- getInfoDown
        ; us   <- newUniqSupply
        ; state <- getState
-       ; let   body_info_down = info { cgd_sequel = initSequel }
+       ; let   body_info_down = info { cgd_sequel    = initSequel
+                                      , cgd_updfr_off = initUpdFrameOff }
                fork_state_in = (initCgState us) { cgs_binds = cgs_binds state }
                ((),fork_state_out)
                    = doFCode body_code body_info_down fork_state_in
   = do { info  <- getInfoDown
        ; us    <- newUniqSupply
        ; state <- getState
-       ; let   rhs_info_down = info { cgd_statics = cgs_binds state,
-                                      cgd_sequel  = initSequel }
+       ; let   rhs_info_down = info { cgd_statics = cgs_binds state
+                                    , cgd_sequel  = initSequel 
+                                    , cgd_updfr_off = initUpdFrameOff }
                (result, fork_state_out) = doFCode body_code rhs_info_down 
                                                   (initCgState us)
        ; setState (state `addCodeBlocksFrom` fork_state_out)
   = do { info_down <- getInfoDown
        ; us    <- newUniqSupply
        ; state <- getState
-       ; let   fork_state_in = (initCgState us) 
-                                       { cgs_binds = cgs_binds state }
-               (result, fork_state_out) = doFCode body_code info_down fork_state_in
+       ; let   info_down' = info_down { cgd_sequel = initSequel }
+                fork_state_in = (initCgState us) { cgs_binds = cgs_binds state }
+               (result, fork_state_out) = doFCode body_code info_down' fork_state_in
        ; setState $ state `addCodeBlocksFrom` fork_state_out
        ; return result }
 
   where
     data_block = CmmData sect lits
 
-emitProc :: CmmInfo -> CLabel -> CmmFormals -> CmmAGraph -> FCode ()
-emitProc info lbl args blocks
+emitProcWithConvention :: Convention -> CmmInfo -> CLabel -> CmmFormals ->
+                          CmmAGraph -> FCode ()
+emitProcWithConvention conv info lbl args blocks
   = do  { us <- newUniqSupply
-        ; let (offset, entry) = mkEntry (mkBlockId $ uniqFromSupply us) Native args
+        ; let (offset, entry) = mkEntry (mkBlockId $ uniqFromSupply us) conv args
               blks = initUs_ us $ lgraphOfAGraph offset $ entry <*> blocks
-        -- ; blks <- cgStmtsToBlocks blocks
         ; let proc_block = CmmProc info lbl args blks
         ; state <- getState
         ; setState $ state { cgs_tops = cgs_tops state `snocOL` proc_block } }
 
+emitProc :: CmmInfo -> CLabel -> CmmFormals -> CmmAGraph -> FCode ()
+emitProc = emitProcWithConvention Native
+
 emitSimpleProc :: CLabel -> CmmAGraph -> FCode ()
--- Emit a procedure whose body is the specified code; no info table
-emitSimpleProc lbl code
-  = emitProc (CmmInfo Nothing Nothing CmmNonInfoTable) lbl [] code
+emitSimpleProc lbl code = 
+  emitProc (CmmInfo Nothing Nothing CmmNonInfoTable) lbl [] code
 
 getCmm :: FCode () -> FCode CmmZ
 -- Get all the CmmTops (there should be no stmts)
 
 
 cgOpApp (StgPrimOp TagToEnumOp) [arg] res_ty 
   = ASSERT(isEnumerationTyCon tycon)
-    do { amode <- getArgAmode arg
+    do { args' <- getNonVoidArgAmodes [arg]
+        ; let amode = case args' of [amode] -> amode
+                                    _ -> panic "TagToEnumOp had void arg"
        ; emitReturn [tagToClosure tycon amode] }
    where
          -- If you're reading this code in the attempt to figure
 cgOpApp (StgPrimOp primop) args res_ty
   | primOpOutOfLine primop
   = do { cmm_args <- getNonVoidArgAmodes args
-       ; let fun = CmmLit (CmmLabel (mkRtsPrimOpLabel primop))
-       ; emitCall fun cmm_args }
+        ; let fun = CmmLit (CmmLabel (mkRtsPrimOpLabel primop))
+        ; pprTrace "cgOpApp" (ppr primop) $ emitCall PrimOp fun cmm_args }
 
   | ReturnsPrim VoidRep <- result_info
   = do cgPrimOp [] primop args 
 
        -- For REP_xxx constants, which are MachReps
 
 import StgCmmClosure
+import StgCmmEnv
 import StgCmmUtils
 import StgCmmMonad
 import SMRep
 -- Setting the cost centre in a new closure
 
 chooseDynCostCentres :: CostCentreStack
-                    -> [Id]            -- Args
+                    -> [Id]            -- Args
                     -> StgExpr         -- Body
                     -> FCode (CmmExpr, CmmExpr)
--- Called when alllcating a closure
+-- Called when allocating a closure
 -- Tells which cost centre to put in the object, and which
 -- to blame the cost of allocation on
 chooseDynCostCentres ccs args body = do
 
 import Cmm
 import CmmExpr
 import MkZipCfgCmm
+import ZipCfg hiding (last, unzip, zip)
 import CLabel
 import CmmUtils
 import PprCmm          ( {- instances -} )
    -> FCode ()
 emitRtsCall' res fun args _vols safe
   = --error "emitRtsCall'"
-    do { emit caller_save
-       ; emit call
+    do { updfr_off <- getUpdFrameOff
+       ; emit caller_save
+       ; emit $ call updfr_off
        ; emit caller_load }
   where
-    call = if safe then
-             mkCall fun_expr CCallConv res' args' undefined
-           else
-             mkUnsafeCall (ForeignTarget fun_expr
-                            (ForeignConvention CCallConv arg_hints res_hints)) res' args'
+    call updfr_off =
+      if safe then
+        mkCall fun_expr Native res' args' updfr_off
+      else
+        mkUnsafeCall (ForeignTarget fun_expr
+                         (ForeignConvention CCallConv arg_hints res_hints)) res' args'
     (args', arg_hints) = unzip args
     (res',  res_hints) = unzip res
     (caller_save, caller_load) = callerSaveVolatileRegs
     mk_switch tag_expr' (sortLe le branches) mb_deflt 
              lo_tag hi_tag via_C
          -- Sort the branches before calling mk_switch
-    <*> mkLabel join_lbl Nothing
+    <*> mkLabel join_lbl emptyStackInfo
 
   where
     (t1,_) `le` (t2,_) = t1 <= t2
   | Just deflt <- mb_deflt, (hi_tag - highest_branch) >= n_branches
   = mkCmmIfThenElse 
        (cmmUGtWord tag_expr (CmmLit (mkIntCLit highest_branch)))
+       (mkBranch deflt)
        (mk_switch tag_expr branches mb_deflt 
                        lo_tag highest_branch via_C)
-       (mkBranch deflt)
 
   | otherwise  -- Use an if-tree
   = mkCmmIfThenElse 
     label_code join_lbl deflt          $ \ deflt ->
     label_branches join_lbl branches   $ \ branches ->
     mk_lit_switch scrut' deflt (sortLe le branches)
+    <*> mkLabel join_lbl emptyStackInfo
   where
     le (t1,_) (t2,_) = t1 <= t2
 
              -> [(Literal,BlockId)]
              -> CmmAGraph
 mk_lit_switch scrut deflt [(lit,blk)] 
-  = mkCbranch
-       (CmmMachOp (MO_Ne rep) [scrut, CmmLit cmm_lit])
-       deflt blk
+  = mkCbranch (CmmMachOp ne [scrut, CmmLit cmm_lit]) deflt blk
   where
     cmm_lit = mkSimpleLit lit
-    rep     = typeWidth (cmmLitType cmm_lit)
+    cmm_ty  = cmmLitType cmm_lit
+    rep     = typeWidth cmm_ty
+    ne      = if isFloatType cmm_ty then MO_F_Ne rep else MO_Ne rep
 
 mk_lit_switch scrut deflt_blk_id branches
   = mkCmmIfThenElse cond
 --  [L: code; goto J] fun L
 label_code join_lbl code thing_inside
   = withFreshLabel "switch"    $ \lbl -> 
-    outOfLine (mkLabel lbl Nothing <*> code <*> mkBranch join_lbl)
+    outOfLine (mkLabel lbl emptyStackInfo <*> code <*> mkBranch join_lbl)
     <*> thing_inside lbl
  
 
   = do         { id <- newUnique
        ; top_srt <- getSRTLabel
         ; let srt_desc_lbl = mkLargeSRTLabel id
-       ; emitRODataLits srt_desc_lbl
-             ( cmmLabelOffW top_srt off
-              : mkWordCLit (fromIntegral len)
-              : map mkWordCLit bmp)
+        -- JD: We're not constructing and emitting SRTs in the back end,
+        -- which renders this code wrong (and it now names a now-non-existent label).
+       -- ; emitRODataLits srt_desc_lbl
+        --      ( cmmLabelOffW top_srt off
+       --        : mkWordCLit (fromIntegral len)
+       --        : map mkWordCLit bmp)
        ; return (C_SRT srt_desc_lbl 0 srt_escape) }
 
   | otherwise
 
         CLabel
         Cmm
         CmmBrokenBlock
+        CmmBuildInfoTables
         CmmCPS
         CmmCPSGen
         CmmCPSZ
         CmmProcPoint
         CmmProcPointZ
         CmmSpillReload
+        CmmStackLayout
         CmmTx
         CmmUtils
         CmmZipUtil
 
 import Cmm              ( Cmm )
 import PprCmm          ( pprCmms )
 import CmmParse                ( parseCmmFile )
+import CmmBuildInfoTables
 import CmmCPS
 import CmmCPSZ
 import CmmInfo
              <- {-# SCC "CoreToStg" #-}
                 myCoreToStg dflags this_mod prepd_binds        
 
-         ------------------  Try new code gen route ----------
-         cmms <- tryNewCodeGen hsc_env this_mod data_tycons
-                               dir_imps cost_centre_info
-                               stg_binds hpc_info
-
          ------------------  Code generation ------------------
          cmms <- if dopt Opt_TryNewCodeGen (hsc_dflags hsc_env)
-                 then pprTrace "cmms" (ppr cmms) $ return cmms
+                 then do cmms <- tryNewCodeGen hsc_env this_mod data_tycons
+                                 dir_imps cost_centre_info
+                                 stg_binds hpc_info
+                         pprTrace "cmms" (ppr cmms) $ return cmms
                  else {-# SCC "CodeGen" #-}
                        codeGen dflags this_mod data_tycons
                                dir_imps cost_centre_info
        ; prog <- return $ map (runTx $ runCmmOpts cmmCfgOptsZ) prog
                -- Control flow optimisation
 
-       ; prog <- mapM (protoCmmCPSZ hsc_env) prog
+        -- Note: Have to thread the module's SRT through all the procedures
+        -- because we greedily build it as we go.
+        ; us <- mkSplitUniqSupply 'S'
+        ; let topSRT = initUs_ us emptySRT
+       ; (topSRT, prog) <- foldM (protoCmmCPSZ hsc_env) (topSRT, []) prog
                -- The main CPS conversion
 
-       ; prog <- return $ map (runTx $ runCmmOpts cmmCfgOptsZ) prog
+       ; prog <- return $ map (runTx $ runCmmOpts cmmCfgOptsZ) (srtToData topSRT : prog)
                -- Control flow optimisation, again
 
-       ; dumpIfSet_dyn dflags Opt_D_dump_cmmz "New Cmm" 
-               (pprCmms prog)
+       ; dumpIfSet_dyn dflags Opt_D_dump_cmmz "New Cmm" (pprCmms prog)
 
        ; return $ map cmmOfZgraph prog }
 
        let cvtm = do g <- cmmToZgraph cmm
                      return $ cfopts g
        let zgraph = initUs_ us cvtm
-       cps_zgraph <- protoCmmCPSZ hsc_env zgraph
+       us <- mkSplitUniqSupply 'S'
+       let topSRT = initUs_ us emptySRT
+       (topSRT, [cps_zgraph]) <- protoCmmCPSZ hsc_env (topSRT, []) zgraph
        let chosen_graph = if dopt Opt_RunCPSZ dflags then cps_zgraph else zgraph
        dumpIfSet_dyn dflags Opt_D_dump_cmmz "C-- Zipper Graph" (ppr chosen_graph)
        showPass dflags "Convert from Z back to Cmm"
 
   , Flag "dppr-user-length"  (AnySuffix addOpt) Supported
   , Flag "dopt-fuel"         (AnySuffix addOpt) Supported
   , Flag "dno-debug-output"  (PassFlag addOpt) Supported
+  , Flag "dstub-dead-values" (PassFlag addOpt) Supported
       -- rest of the debugging flags are dynamic
 
         --------- Profiling --------------------------------------------------
 
        opt_EmitExternalCore,
        v_Ld_inputs,
        tablesNextToCode,
+        opt_StubDeadValues,
 
     -- For the parser
     addOpt, removeOpt, addWay, findBuildTag, v_opt_C_ready
 opt_HistorySize                        = lookup_def_int "-fhistory-size" 20
 opt_OmitBlackHoling :: Bool
 opt_OmitBlackHoling            = lookUp  (fsLit "-dno-black-holing")
+opt_StubDeadValues  :: Bool
+opt_StubDeadValues             = lookUp  (fsLit "-dstub-dead-values")
 
 -- Simplifier switches
 opt_SimplNoPreInlining :: Bool
 
 
 #include "../includes/MachRegs.h"
 
+import BlockId
 import Cmm
 import CgUtils          ( get_GlobalReg_addr )
 import CLabel           ( CLabel, mkMainCapabilityLabel )
                              = ImmConstantSum
                                (ImmConstantDiff (ImmCLbl l1) (ImmCLbl l2))
                                (ImmInt off)
+litToImm (CmmBlock id)       = ImmCLbl (infoTblLbl id)
 
 -- -----------------------------------------------------------------------------
 -- Addressing modes
 
 pprImm (ImmIndex l i) = pprCLabel_asm l <> char '+' <> int i
 pprImm (ImmLit s)     = s
 
-pprImm (ImmFloat _) = ptext (sLit "naughty float immediate")
+pprImm (ImmFloat _)  = ptext (sLit "naughty float immediate")
 pprImm (ImmDouble _) = ptext (sLit "naughty double immediate")
 
 pprImm (ImmConstantSum a b) = pprImm a <> char '+' <> pprImm b
 
                , Nothing )
        
 regAlloc (CmmProc (LiveInfo info _ _) lbl params (ListGraph []))
-       = return
-               ( CmmProc info lbl params (ListGraph [])
-               , Nothing )
+       = return ( CmmProc info lbl params (ListGraph [])
+                , Nothing )
        
 regAlloc (CmmProc static lbl params (ListGraph comps))
        | LiveInfo info (Just first_id) block_live      <- static
 initBlock :: BlockId -> RegM ()
 initBlock id
  = do  block_assig     <- getBlockAssigR
-       case lookupUFM block_assig id of
+       case lookupBlockEnv block_assig id of
                -- no prior info about this block: assume everything is
                -- free and the assignment is empty.
                Nothing
        regsOfLoc (InBoth r _) = [r]
        regsOfLoc (InMem _)    = []
   -- in
-  case lookupUFM block_assig dest of
+  case lookupBlockEnv block_assig dest of
        -- Nothing <=> this is the first time we jumped to this
        -- block.
        Nothing -> do
          freeregs <- getFreeRegsR
          let freeregs' = foldr releaseReg freeregs to_free 
-         setBlockAssigR (addToUFM block_assig dest 
+         setBlockAssigR (extendBlockEnv block_assig dest 
                                (freeregs',adjusted_assig))
          joinToTargets block_live new_blocks instr dests
 
 my_fromJust _ _ (Just x) = x
 my_fromJust s p Nothing = pprPanic ("fromJust: " ++ s) p
 
-lookItUp :: Uniquable b => String -> UniqFM a -> b -> a
-lookItUp str fm x = my_fromJust str (ppr (getUnique x)) (lookupUFM fm x)
+lookItUp :: String -> BlockMap a -> BlockId -> a
+lookItUp str fm x = my_fromJust str (ppr x) (lookupBlockEnv fm x)
 
 emptyRegMap :: UniqFM a
 emptyRegMap = emptyUFM
 
-type BlockMap a = UniqFM a
+type BlockMap a = BlockEnv a
 
-emptyBlockMap :: UniqFM a
-emptyBlockMap = emptyUFM
+emptyBlockMap :: BlockEnv a
+emptyBlockMap = emptyBlockEnv
 
 
 -- | A top level thing which carries liveness information.
 
        slurpBlock info rs (BasicBlock blockId instrs)  
                | LiveInfo _ _ blockLive        <- info
-               , Just rsLiveEntry              <- lookupUFM blockLive blockId
+               , Just rsLiveEntry              <- lookupBlockEnv blockLive blockId
                , (conflicts, moves)            <- slurpLIs rsLiveEntry rs instrs
                = (consBag rsLiveEntry conflicts, moves)
 
 
  where stripCmm (CmmData sec ds)       = CmmData sec ds
        stripCmm (CmmProc (LiveInfo info _ _) label params (ListGraph comps))
-               = CmmProc info label params (ListGraph $ concatMap stripComp comps)
+               = CmmProc info label params
+                          (ListGraph $ concatMap stripComp comps)
 
        stripComp  (BasicBlock _ blocks)        = map stripBlock blocks
        stripBlock (BasicBlock i instrs)        = BasicBlock i (map stripLI instrs)
        patchCmm (CmmProc info label params (ListGraph comps))
         | LiveInfo static id blockMap  <- info
         = let  patchRegSet set = mkUniqSet $ map patchF $ uniqSetToList set
-               blockMap'       = mapUFM patchRegSet blockMap
+               blockMap'       = mapBlockEnv patchRegSet blockMap
 
                info'           = LiveInfo static id blockMap'
           in   CmmProc info' label params $ ListGraph $ map patchComp comps
 
 regLiveness (CmmProc info lbl params (ListGraph []))
        = returnUs $ CmmProc
-                       (LiveInfo info Nothing emptyUFM)
+                       (LiveInfo info Nothing emptyBlockEnv)
                        lbl params (ListGraph [])
 
 regLiveness (CmmProc info lbl params (ListGraph blocks@(first : _)))
                         -> panic "RegLiveness.regLiveness: no blocks in scc list")
                 $ ann_sccs
 
-   in  returnUs $ CmmProc
-                       (LiveInfo info (Just first_id) block_live)
-                       lbl params (ListGraph liveBlocks)
+   in  returnUs $ CmmProc (LiveInfo info (Just first_id) block_live)
+                          lbl params (ListGraph liveBlocks)
 
 
 sccBlocks :: [NatBasicBlock] -> [SCC NatBasicBlock]
                 -- BlockMaps for equality.
            equalBlockMaps a b
                = a' == b'
-             where a' = map f $ ufmToList a
-                   b' = map f $ ufmToList b
+             where a' = map f $ blockEnvToList a
+                   b' = map f $ blockEnvToList b
                    f (key,elt) = (key, uniqSetToList elt)
 
 
  = let
        (regsLiveOnEntry, instrs1)
                = livenessBack emptyUniqSet blockmap [] (reverse instrs)
-       blockmap'       = addToUFM blockmap block_id regsLiveOnEntry
+       blockmap'       = extendBlockEnv blockmap block_id regsLiveOnEntry
 
        instrs2         = livenessForward regsLiveOnEntry instrs1
 
            not_a_branch = null targets
 
            targetLiveRegs target
-                  = case lookupUFM blockmap target of
+                  = case lookupBlockEnv blockmap target of
                                 Just ra -> ra
-                                Nothing -> emptyBlockMap
+                                Nothing -> emptyRegMap
 
             live_from_branch = unionManyUniqSets (map targetLiveRegs targets)
 
 
 import RegAllocInfo
 import MachInstrs
 import MachRegs
+import BlockId
 import Cmm
 
 import UniqFM
        --      the info table from the CmmProc
        countBlock info (BasicBlock blockId instrs)
                | LiveInfo _ _ blockLive        <- info
-               , Just rsLiveEntry              <- lookupUFM blockLive blockId
+               , Just rsLiveEntry              <- lookupBlockEnv blockLive blockId
                = countLIs rsLiveEntry instrs
 
                | otherwise