[project @ 2002-09-27 08:20:43 by simonpj]
[ghc-hetmet.git] / ghc / compiler / stgSyn / CoreToStg.lhs
index 07054ff..258260d 100644 (file)
@@ -19,25 +19,25 @@ import Type
 import TyCon           ( isAlgTyCon )
 import Literal
 import Id
 import TyCon           ( isAlgTyCon )
 import Literal
 import Id
-import Var             ( Var, globalIdDetails )
+import Var             ( Var, globalIdDetails, varType )
+#ifdef ILX
+import MkId            ( unsafeCoerceId )
+#endif
 import IdInfo
 import DataCon
 import CostCentre      ( noCCS )
 import VarSet
 import VarEnv
 import DataCon         ( dataConWrapId )
 import IdInfo
 import DataCon
 import CostCentre      ( noCCS )
 import VarSet
 import VarEnv
 import DataCon         ( dataConWrapId )
-import IdInfo          ( OccInfo(..) )
-import TysPrim         ( foreignObjPrimTyCon )
 import Maybes          ( maybeToBool )
 import Maybes          ( maybeToBool )
-import Name            ( getOccName, isExternallyVisibleName, isDllName )
+import Name            ( getOccName, isExternalName, isDllName )
 import OccName         ( occNameUserString )
 import OccName         ( occNameUserString )
-import BasicTypes       ( TopLevelFlag(..), isNotTopLevel )
-import CmdLineOpts     ( DynFlags, opt_KeepStgTypes )
+import BasicTypes       ( Arity )
+import CmdLineOpts     ( DynFlags, opt_RuntimeTypes )
 import FastTypes       hiding ( fastOr )
 import FastTypes       hiding ( fastOr )
+import Util             ( listLengthCmp, mapAndUnzip )
 import Outputable
 
 import Outputable
 
-import List            ( partition )
-
 infixr 9 `thenLne`
 \end{code}
 
 infixr 9 `thenLne`
 \end{code}
 
@@ -117,6 +117,25 @@ The later SRT pass takes these lists of Ids and uses them to construct
 the actual nested SRTs, and replaces the lists of Ids with (offset,length)
 pairs.
 
 the actual nested SRTs, and replaces the lists of Ids with (offset,length)
 pairs.
 
+
+Interaction of let-no-escape with SRTs   [Sept 01]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+
+       let-no-escape x = ...caf1...caf2...
+       in
+       ...x...x...x...
+
+where caf1,caf2 are CAFs.  Since x doesn't have a closure, we 
+build SRTs just as if x's defn was inlined at each call site, and
+that means that x's CAF refs get duplicated in the overall SRT.
+
+This is unlike ordinary lets, in which the CAF refs are not duplicated.
+
+We could fix this loss of (static) sharing by making a sort of pseudo-closure
+for x, solely to put in the SRTs lower down.
+
+
 %************************************************************************
 %*                                                                     *
 \subsection[binds-StgVarInfo]{Setting variable info: top-level, binds, RHSs}
 %************************************************************************
 %*                                                                     *
 \subsection[binds-StgVarInfo]{Setting variable info: top-level, binds, RHSs}
@@ -127,7 +146,7 @@ pairs.
 coreToStg :: DynFlags -> [CoreBind] -> IO [StgBinding]
 coreToStg dflags pgm
   = return pgm'
 coreToStg :: DynFlags -> [CoreBind] -> IO [StgBinding]
 coreToStg dflags pgm
   = return pgm'
-  where (env', fvs, pgm') = coreTopBindsToStg emptyVarEnv pgm
+  where (_, _, pgm') = coreTopBindsToStg emptyVarEnv pgm
 
 coreExprToStg :: CoreExpr -> StgExpr
 coreExprToStg expr 
 
 coreExprToStg :: CoreExpr -> StgExpr
 coreExprToStg expr 
@@ -141,7 +160,7 @@ coreTopBindsToStg
 
 coreTopBindsToStg env [] = (env, emptyFVInfo, [])
 coreTopBindsToStg env (b:bs)
 
 coreTopBindsToStg env [] = (env, emptyFVInfo, [])
 coreTopBindsToStg env (b:bs)
-  = (env2, fvs1, b':bs')
+  = (env2, fvs2, b':bs')
   where
        -- env accumulates down the list of binds, fvs accumulates upwards
        (env1, fvs2, b' ) = coreTopBindToStg env fvs1 b
   where
        -- env accumulates down the list of binds, fvs accumulates upwards
        (env1, fvs2, b' ) = coreTopBindToStg env fvs1 b
@@ -156,23 +175,20 @@ coreTopBindToStg
 
 coreTopBindToStg env body_fvs (NonRec id rhs)
   = let 
 
 coreTopBindToStg env body_fvs (NonRec id rhs)
   = let 
-       caf_info = hasCafRefs env rhs
-
-       env' = extendVarEnv env id (LetBound how_bound emptyVarSet)
+       (caf_info, upd) = hasCafRefs env rhs
+       env'      = extendVarEnv env id how_bound
+       how_bound = LetBound (TopLet caf_info) (manifestArity rhs)
 
 
-       how_bound | mayHaveCafRefs caf_info = TopLevelHasCafs
-                 | otherwise               = TopLevelNoCafs
-
-        (stg_rhs, fvs', cafs) = 
+        (stg_rhs, fvs', lv_info) = 
            initLne env (
            initLne env (
-              coreToStgRhs body_fvs TopLevel (id,rhs) 
-                       `thenLne` \ (stg_rhs, fvs', _) ->
-             freeVarsToLiveVars fvs' `thenLne` \ (_, cafs) ->
-             returnLne (stg_rhs, fvs', cafs)
+              coreToTopStgRhs body_fvs ((id,rhs), upd) `thenLne` \ (stg_rhs, fvs') ->
+             freeVarsToLiveVars fvs'                   `thenLne` \ lv_info ->
+             returnLne (stg_rhs, fvs', lv_info)
            )
        
            )
        
-       bind = StgNonRec (SRTEntries cafs) id stg_rhs
+       bind = StgNonRec (mkSRT lv_info) id stg_rhs
     in
     in
+    ASSERT2(manifestArity rhs == stgRhsArity stg_rhs, ppr id)
     ASSERT2(consistent caf_info bind, ppr id)
 --    WARN(not (consistent caf_info bind), ppr id <+> ppr cafs <+> ppCafInfo caf_info)
     (env', fvs' `unionFVInfo` body_fvs, bind)
     ASSERT2(consistent caf_info bind, ppr id)
 --    WARN(not (consistent caf_info bind), ppr id <+> ppr cafs <+> ppCafInfo caf_info)
     (env', fvs' `unionFVInfo` body_fvs, bind)
@@ -181,30 +197,34 @@ coreTopBindToStg env body_fvs (Rec pairs)
   = let 
        (binders, rhss) = unzip pairs
 
   = let 
        (binders, rhss) = unzip pairs
 
-       -- to calculate caf_info, we initially map all the binders to
-       -- TopLevelNoCafs.
-       env1 = extendVarEnvList env 
-               [ (b, LetBound TopLevelNoCafs emptyVarSet) | b <- binders ]
-
-       caf_info = hasCafRefss env1{-NB: not env'-} rhss
-
-       env' = extendVarEnvList env 
-               [ (b, LetBound how_bound emptyVarSet) | b <- binders ]
+       -- To calculate caf_info, we initially map 
+       -- all the binders to NoCafRefs
+       extra_env = [ (b, LetBound (TopLet NoCafRefs) (manifestArity rhs)) 
+                   | (b,rhs) <- pairs ]
+       env1      = extendVarEnvList env extra_env
+       (caf_infos, upd_flags) = mapAndUnzip (hasCafRefs env1) rhss
+               -- NB: use env1 not env'
+       
+       -- If any has a CAF ref, they all do
+       caf_info | any mayHaveCafRefs caf_infos = MayHaveCafRefs
+                | otherwise                    = NoCafRefs
 
 
-       how_bound | mayHaveCafRefs caf_info = TopLevelHasCafs
-                 | otherwise               = TopLevelNoCafs
+       extra_env' = [ (b, LetBound (TopLet caf_info) arity)
+                    | (b, LetBound _                 arity) <- extra_env ]
+       env' = extendVarEnvList env extra_env'
 
 
-        (stg_rhss, fvs', cafs)
+        (stg_rhss, fvs', lv_info)
          = initLne env' (
          = initLne env' (
-              mapAndUnzip3Lne (coreToStgRhs body_fvs TopLevel) pairs
-                       `thenLne` \ (stg_rhss, fvss', _) ->
+              mapAndUnzipLne (coreToTopStgRhs body_fvs) 
+                              (pairs `zip` upd_flags)  `thenLne` \ (stg_rhss, fvss') ->
               let fvs' = unionFVInfos fvss' in
               let fvs' = unionFVInfos fvss' in
-              freeVarsToLiveVars fvs'  `thenLne` \ (_, cafs) ->
-              returnLne (stg_rhss, fvs', cafs)
+              freeVarsToLiveVars fvs'                  `thenLne` \ lv_info ->
+              returnLne (stg_rhss, fvs', lv_info)
            )
 
            )
 
-       bind = StgRec (SRTEntries cafs) (zip binders stg_rhss)
+       bind = StgRec (mkSRT lv_info) (zip binders stg_rhss)
     in
     in
+    ASSERT2(and [manifestArity rhs == stgRhsArity stg_rhs | (rhs,stg_rhs) <- rhss `zip` stg_rhss], ppr binders)
     ASSERT2(consistent caf_info bind, ppr binders)
 --    WARN(not (consistent caf_info bind), ppr binders <+> ppr cafs <+> ppCafInfo caf_info)
     (env', fvs' `unionFVInfo` body_fvs, bind)
     ASSERT2(consistent caf_info bind, ppr binders)
 --    WARN(not (consistent caf_info bind), ppr binders <+> ppr cafs <+> ppCafInfo caf_info)
     (env', fvs' `unionFVInfo` body_fvs, bind)
@@ -214,85 +234,35 @@ consistent caf_info bind = mayHaveCafRefs caf_info == stgBindHasCafRefs bind
 \end{code}
 
 \begin{code}
 \end{code}
 
 \begin{code}
-coreToStgRhs
+coreToTopStgRhs
        :: FreeVarsInfo         -- Free var info for the scope of the binding
        :: FreeVarsInfo         -- Free var info for the scope of the binding
-       -> TopLevelFlag
-       -> (Id,CoreExpr)
-       -> LneM (StgRhs, FreeVarsInfo, EscVarsSet)
+       -> ((Id,CoreExpr), UpdateFlag)
+       -> LneM (StgRhs, FreeVarsInfo)
 
 
-coreToStgRhs scope_fv_info top (binder, rhs)
-  = coreToStgExpr rhs  `thenLne` \ (new_rhs, rhs_fvs, rhs_escs) ->
-    returnLne (mkStgRhs top rhs_fvs binder_info new_rhs, 
-              rhs_fvs, rhs_escs)
+coreToTopStgRhs scope_fv_info ((bndr, rhs), upd)
+  = coreToStgExpr rhs          `thenLne` \ (new_rhs, rhs_fvs, _) ->
+    returnLne (mkTopStgRhs upd rhs_fvs bndr_info new_rhs, rhs_fvs)
   where
   where
-    binder_info = lookupFVInfo scope_fv_info binder
-
-bogus_rhs = StgRhsClosure noCCS noBinderInfo [] ReEntrant [] bogus_expr
-bogus_expr = (StgLit (MachInt 1))
+    bndr_info = lookupFVInfo scope_fv_info bndr
 
 
-mkStgRhs :: TopLevelFlag -> FreeVarsInfo -> StgBinderInfo
-        -> StgExpr -> StgRhs
+mkTopStgRhs :: UpdateFlag -> FreeVarsInfo -> StgBinderInfo
+           -> StgExpr -> StgRhs
 
 
-mkStgRhs top rhs_fvs binder_info (StgLam _ bndrs body)
+mkTopStgRhs upd rhs_fvs binder_info (StgLam _ bndrs body)
   = StgRhsClosure noCCS binder_info
                  (getFVs rhs_fvs)               
                  ReEntrant
                  bndrs body
        
   = StgRhsClosure noCCS binder_info
                  (getFVs rhs_fvs)               
                  ReEntrant
                  bndrs body
        
-mkStgRhs top rhs_fvs binder_info (StgConApp con args)
-  | isNotTopLevel top || not (isDllConApp con args)
+mkTopStgRhs ReEntrant rhs_fvs binder_info (StgConApp con args)
+       -- StgConApps can be Updatable: see isCrossDllConApp below
   = StgRhsCon noCCS con args
 
   = StgRhsCon noCCS con args
 
-mkStgRhs top rhs_fvs binder_info rhs
+mkTopStgRhs upd_flag rhs_fvs binder_info rhs
   = StgRhsClosure noCCS binder_info
                  (getFVs rhs_fvs)               
   = StgRhsClosure noCCS binder_info
                  (getFVs rhs_fvs)               
-                 (updatable [] rhs)
+                 upd_flag
                  [] rhs
                  [] rhs
-  where
-    updatable args body | null args && isPAP body  = ReEntrant
-                       | otherwise                = Updatable
-{- ToDo:
-          upd = if isOnceDem dem
-                   then (if isNotTop toplev 
-                           then SingleEntry    -- HA!  Paydirt for "dem"
-                           else 
-#ifdef DEBUG
-                     trace "WARNING: SE CAFs unsupported, forcing UPD instead" $
-#endif
-                     Updatable)
-               else Updatable
-        -- For now we forbid SingleEntry CAFs; they tickle the
-        -- ASSERT in rts/Storage.c line 215 at newCAF() re mut_link,
-        -- and I don't understand why.  There's only one SE_CAF (well,
-        -- only one that tickled a great gaping bug in an earlier attempt
-        -- at ClosureInfo.getEntryConvention) in the whole of nofib, 
-        -- specifically Main.lvl6 in spectral/cryptarithm2.
-        -- So no great loss.  KSW 2000-07.
--}
-\end{code}
-
-Detect thunks which will reduce immediately to PAPs, and make them
-non-updatable.  This has several advantages:
-
-        - the non-updatable thunk behaves exactly like the PAP,
-
-       - the thunk is more efficient to enter, because it is
-         specialised to the task.
-
-        - we save one update frame, one stg_update_PAP, one update
-         and lots of PAP_enters.
-
-       - in the case where the thunk is top-level, we save building
-         a black hole and futhermore the thunk isn't considered to
-         be a CAF any more, so it doesn't appear in any SRTs.
-
-We do it here, because the arity information is accurate, and we need
-to do it before the SRT pass to save the SRT entries associated with
-any top-level PAPs.
-
-\begin{code}
-isPAP (StgApp f args) = idArity f > length args
-isPAP _              = False
 \end{code}
 
 
 \end{code}
 
 
@@ -328,15 +298,15 @@ coreToStgExpr expr@(App _ _)
     (f, args) = myCollectArgs expr
 
 coreToStgExpr expr@(Lam _ _)
     (f, args) = myCollectArgs expr
 
 coreToStgExpr expr@(Lam _ _)
-  = let (args, body) = myCollectBinders expr 
+  = let
+       (args, body) = myCollectBinders expr 
        args'        = filterStgBinders args
     in
     extendVarEnvLne [ (a, LambdaBound) | a <- args' ] $
     coreToStgExpr body  `thenLne` \ (body, body_fvs, body_escs) ->
     let
        args'        = filterStgBinders args
     in
     extendVarEnvLne [ (a, LambdaBound) | a <- args' ] $
     coreToStgExpr body  `thenLne` \ (body, body_fvs, body_escs) ->
     let
-       set_of_args     = mkVarSet args'
        fvs             = args' `minusFVBinders` body_fvs
        fvs             = args' `minusFVBinders` body_fvs
-       escs            = body_escs `minusVarSet`    set_of_args
+       escs            = body_escs `delVarSetList` args'
        result_expr | null args' = body
                    | otherwise  = StgLam (exprType expr) args' body
     in
        result_expr | null args' = body
                    | otherwise  = StgLam (exprType expr) args' body
     in
@@ -346,112 +316,80 @@ coreToStgExpr (Note (SCC cc) expr)
   = coreToStgExpr expr         `thenLne` ( \ (expr2, fvs, escs) ->
     returnLne (StgSCC cc expr2, fvs, escs) )
 
   = coreToStgExpr expr         `thenLne` ( \ (expr2, fvs, escs) ->
     returnLne (StgSCC cc expr2, fvs, escs) )
 
+#ifdef ILX
+-- For ILX, convert (__coerce__ to_ty from_ty e) 
+--         into    (coerce to_ty from_ty e)
+-- where coerce is real function
+coreToStgExpr (Note (Coerce to_ty from_ty) expr)
+  = coreToStgExpr (mkApps (Var unsafeCoerceId) 
+                         [Type from_ty, Type to_ty, expr])
+#endif
+
 coreToStgExpr (Note other_note expr)
   = coreToStgExpr expr
 
 coreToStgExpr (Note other_note expr)
   = coreToStgExpr expr
 
-
 -- Cases require a little more real work.
 
 coreToStgExpr (Case scrut bndr alts)
 -- Cases require a little more real work.
 
 coreToStgExpr (Case scrut bndr alts)
-  = extendVarEnvLne [(bndr, CaseBound)]        $
-    vars_alts (findDefault alts)   `thenLne` \ (alts2, alts_fvs, alts_escs) ->
-    freeVarsToLiveVars  alts_fvs   `thenLne` \ (alts_lvs, alts_caf_refs) ->
+  = extendVarEnvLne [(bndr, LambdaBound)]      (
+        mapAndUnzip3Lne vars_alt alts  `thenLne` \ (alts2, fvs_s, escs_s) ->
+        returnLne ( mkStgAlts (idType bndr) alts2,
+                    unionFVInfos fvs_s,
+                    unionVarSets escs_s )
+    )                                  `thenLne` \ (alts2, alts_fvs, alts_escs) ->
     let
     let
-       -- determine whether the default binder is dead or not
+       -- Determine whether the default binder is dead or not
        -- This helps the code generator to avoid generating an assignment
        -- for the case binder (is extremely rare cases) ToDo: remove.
        -- This helps the code generator to avoid generating an assignment
        -- for the case binder (is extremely rare cases) ToDo: remove.
-       bndr'= if (bndr `elementOfFVInfo` alts_fvs) 
-                 then bndr
-                 else bndr `setIdOccInfo` IAmDead
+       bndr' | bndr `elementOfFVInfo` alts_fvs = bndr
+             | otherwise                       = bndr `setIdOccInfo` IAmDead
 
        -- Don't consider the default binder as being 'live in alts',
        -- since this is from the point of view of the case expr, where
        -- the default binder is not free.
 
        -- Don't consider the default binder as being 'live in alts',
        -- since this is from the point of view of the case expr, where
        -- the default binder is not free.
-       live_in_alts = (alts_lvs `minusVarSet` unitVarSet bndr)
+       alts_fvs_wo_bndr  = bndr `minusFVBinder` alts_fvs
+       alts_escs_wo_bndr = alts_escs `delVarSet` bndr
     in
     in
-       -- we tell the scrutinee that everything live in the alts
-       -- is live in it, too.
-    setVarsLiveInCont (live_in_alts,alts_caf_refs) (
+
+    freeVarsToLiveVars alts_fvs_wo_bndr                `thenLne` \ alts_lv_info ->
+
+       -- We tell the scrutinee that everything 
+       -- live in the alts is live in it, too.
+    setVarsLiveInCont alts_lv_info (
        coreToStgExpr scrut       `thenLne` \ (scrut2, scrut_fvs, scrut_escs) ->
        coreToStgExpr scrut       `thenLne` \ (scrut2, scrut_fvs, scrut_escs) ->
-        freeVarsToLiveVars scrut_fvs `thenLne` \ (scrut_lvs, _) ->
-       returnLne (scrut2, scrut_fvs, scrut_escs, scrut_lvs)
+        freeVarsToLiveVars scrut_fvs `thenLne` \ scrut_lv_info ->
+       returnLne (scrut2, scrut_fvs, scrut_escs, scrut_lv_info)
       )    
       )    
-               `thenLne` \ (scrut2, scrut_fvs, scrut_escs, scrut_lvs) ->
+               `thenLne` \ (scrut2, scrut_fvs, scrut_escs, scrut_lv_info) ->
 
 
-    let srt = SRTEntries alts_caf_refs
-    in
     returnLne (
     returnLne (
-      StgCase scrut2 scrut_lvs live_in_alts bndr' srt alts2,
-      bndr `minusFVBinder` (scrut_fvs `unionFVInfo` alts_fvs),
-      (alts_escs `minusVarSet` unitVarSet bndr) `unionVarSet` getFVSet scrut_fvs
+      StgCase scrut2 (getLiveVars scrut_lv_info)
+                    (getLiveVars alts_lv_info)
+                    bndr'
+                    (mkSRT alts_lv_info)
+                    alts2,
+      scrut_fvs `unionFVInfo` alts_fvs_wo_bndr,
+      alts_escs_wo_bndr `unionVarSet` getFVSet scrut_fvs
                -- You might think we should have scrut_escs, not 
                -- (getFVSet scrut_fvs), but actually we can't call, and 
                -- then return from, a let-no-escape thing.
       )
   where
                -- You might think we should have scrut_escs, not 
                -- (getFVSet scrut_fvs), but actually we can't call, and 
                -- then return from, a let-no-escape thing.
       )
   where
-    scrut_ty   = idType bndr
-    prim_case  = isUnLiftedType scrut_ty && not (isUnboxedTupleType scrut_ty)
-
-    vars_alts (alts,deflt)
-       | prim_case
-        = mapAndUnzip3Lne vars_prim_alt alts
-                       `thenLne` \ (alts2,  alts_fvs_list,  alts_escs_list) ->
-         let
-             alts_fvs  = unionFVInfos alts_fvs_list
-             alts_escs = unionVarSets alts_escs_list
-         in
-         vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
-         returnLne (
-             mkStgPrimAlts scrut_ty alts2 deflt2,
-             alts_fvs  `unionFVInfo`   deflt_fvs,
-             alts_escs `unionVarSet` deflt_escs
-         )
-
-       | otherwise
-        = mapAndUnzip3Lne vars_alg_alt alts
-                       `thenLne` \ (alts2,  alts_fvs_list,  alts_escs_list) ->
-         let
-             alts_fvs  = unionFVInfos alts_fvs_list
-             alts_escs = unionVarSets alts_escs_list
-         in
-         vars_deflt deflt `thenLne` \ (deflt2, deflt_fvs, deflt_escs) ->
-         returnLne (
-             mkStgAlgAlts scrut_ty alts2 deflt2,
-             alts_fvs  `unionFVInfo`   deflt_fvs,
-             alts_escs `unionVarSet` deflt_escs
-         )
-
-      where
-       vars_prim_alt (LitAlt lit, _, rhs)
-         = coreToStgExpr rhs   `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
-           returnLne ((lit, rhs2), rhs_fvs, rhs_escs)
-
-       vars_alg_alt (DataAlt con, binders, rhs)
-         = let
-               -- remove type variables
-               binders' = filterStgBinders binders
-           in  
-           extendVarEnvLne [(b, CaseBound) | b <- binders']    $
-           coreToStgExpr rhs   `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
-           let
-               good_use_mask = [ b `elementOfFVInfo` rhs_fvs | b <- binders' ]
-               -- records whether each param is used in the RHS
-           in
-           returnLne (
-               (con, binders', good_use_mask, rhs2),
-               binders' `minusFVBinders` rhs_fvs,
-               rhs_escs `minusVarSet`   mkVarSet binders'
-                       -- ToDo: remove the minusVarSet;
-                       -- since escs won't include any of these binders
-           )
-       vars_alg_alt other = pprPanic "vars_alg_alt" (ppr other)
-
-       vars_deflt Nothing
-          = returnLne (StgNoDefault, emptyFVInfo, emptyVarSet)
-     
-       vars_deflt (Just rhs)
-          = coreToStgExpr rhs  `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
-            returnLne (StgBindDefault rhs2, rhs_fvs, rhs_escs)
+    vars_alt (con, binders, rhs)
+      = let            -- Remove type variables
+           binders' = filterStgBinders binders
+        in     
+        extendVarEnvLne [(b, LambdaBound) | b <- binders']     $
+        coreToStgExpr rhs      `thenLne` \ (rhs2, rhs_fvs, rhs_escs) ->
+        let
+               -- Records whether each param is used in the RHS
+           good_use_mask = [ b `elementOfFVInfo` rhs_fvs | b <- binders' ]
+        in
+        returnLne ( (con, binders', good_use_mask, rhs2),
+                   binders' `minusFVBinders` rhs_fvs,
+                   rhs_escs `delVarSetList` binders' )
+               -- ToDo: remove the delVarSet;
+               -- since escs won't include any of these binders
 \end{code}
 
 Lets not only take quite a bit of work, but this is where we convert
 \end{code}
 
 Lets not only take quite a bit of work, but this is where we convert
@@ -467,36 +405,29 @@ coreToStgExpr (Let bind body)
     returnLne (new_let, fvs, escs)
 \end{code}
 
     returnLne (new_let, fvs, escs)
 \end{code}
 
-If we've got a case containing a _ccall_GC_ primop, we need to
-ensure that the arguments are kept live for the duration of the
-call. This only an issue
-
 \begin{code}
 \begin{code}
-isForeignObjArg :: Id -> Bool
-isForeignObjArg x = isId x && isForeignObjPrimTy (idType x)
+mkStgAlts scrut_ty orig_alts
+ | is_prim_case = StgPrimAlts (tyConAppTyCon scrut_ty) prim_alts deflt
+ | otherwise    = StgAlgAlts  maybe_tycon             alg_alts  deflt
+  where
+    is_prim_case = isUnLiftedType scrut_ty && not (isUnboxedTupleType scrut_ty)
 
 
-isForeignObjPrimTy ty
-   = case splitTyConApp_maybe ty of
-       Just (tycon, _) -> tycon == foreignObjPrimTyCon
-       Nothing         -> False
-\end{code}
+    prim_alts    = [(lit, rhs)                    | (LitAlt lit, _, _, rhs)        <- other_alts]
+    alg_alts    = [(con, bndrs, use, rhs) | (DataAlt con, bndrs, use, rhs) <- other_alts]
 
 
-\begin{code}
-mkStgAlgAlts ty alts deflt
- =  case alts of
-               -- Get the tycon from the data con
-       (dc, _, _, _) : _rest
-           -> StgAlgAlts (Just (dataConTyCon dc)) alts deflt
-
-               -- Otherwise just do your best
-       [] -> case splitTyConApp_maybe (repType ty) of
-               Just (tc,_) | isAlgTyCon tc 
-                       -> StgAlgAlts (Just tc) alts deflt
-               other
-                       -> StgAlgAlts Nothing alts deflt
-
-mkStgPrimAlts ty alts deflt 
-  = StgPrimAlts (tyConAppTyCon ty) alts deflt
+    (other_alts, deflt) 
+       = case orig_alts of     -- DEFAULT is always first if it's there at all
+           (DEFAULT, _, _, rhs) : other_alts -> (other_alts, StgBindDefault rhs)
+           other                             -> (orig_alts,  StgNoDefault)
+
+    maybe_tycon = case alg_alts of 
+                       -- Get the tycon from the data con
+                       (dc, _, _, _) : _rest -> Just (dataConTyCon dc)
+
+                       -- Otherwise just do your best
+                       [] -> case splitTyConApp_maybe (repType scrut_ty) of
+                               Just (tc,_) | isAlgTyCon tc -> Just tc
+                               _other                      -> Nothing
 \end{code}
 
 
 \end{code}
 
 
@@ -519,9 +450,16 @@ coreToStgApp maybe_thunk_body f args
     lookupVarLne f             `thenLne` \ how_bound ->
 
     let
     lookupVarLne f             `thenLne` \ how_bound ->
 
     let
-       n_args           = length args
+       n_val_args       = valArgCount args
        not_letrec_bound = not (isLetBound how_bound)
        not_letrec_bound = not (isLetBound how_bound)
-       fun_fvs          = singletonFVInfo f how_bound fun_occ
+       fun_fvs          
+          = let fvs = singletonFVInfo f how_bound fun_occ in
+            -- e.g. (f :: a -> int) (x :: a) 
+            -- Here the free variables are "f", "x" AND the type variable "a"
+            -- coreToStgArgs will deal with the arguments recursively
+            if opt_RuntimeTypes then
+             fvs `unionFVInfo` tyvarFVInfo (tyVarsOfType (varType f))
+           else fvs
 
        -- Mostly, the arity info of a function is in the fn's IdInfo
        -- But new bindings introduced by CoreSat may not have no
 
        -- Mostly, the arity info of a function is in the fn's IdInfo
        -- But new bindings introduced by CoreSat may not have no
@@ -529,18 +467,18 @@ coreToStgApp maybe_thunk_body f args
        --      let f = \ab -> e in f
        -- No point in having correct arity info for f!
        -- Hence the hasArity stuff below.
        --      let f = \ab -> e in f
        -- No point in having correct arity info for f!
        -- Hence the hasArity stuff below.
-       f_arity_info     = idArityInfo f
-       f_arity          = arityLowerBound f_arity_info         -- Zero if no info
+       -- NB: f_arity is only consulted for LetBound things
+       f_arity   = stgArity f how_bound
+       saturated = f_arity <= n_val_args
 
        fun_occ 
 
        fun_occ 
-        | not_letrec_bound                 = noBinderInfo      -- Uninteresting variable
-        | f_arity > 0 && f_arity <= n_args = stgSatOcc         -- Saturated or over-saturated function call
-        | otherwise                        = stgUnsatOcc       -- Unsaturated function or thunk
+        | not_letrec_bound         = noBinderInfo      -- Uninteresting variable
+        | f_arity > 0 && saturated = stgSatOcc -- Saturated or over-saturated function call
+        | otherwise                = stgUnsatOcc       -- Unsaturated function or thunk
 
        fun_escs
 
        fun_escs
-        | not_letrec_bound  = emptyVarSet      -- Only letrec-bound escapees are interesting
-        | hasArity f_arity_info &&
-          f_arity == n_args = emptyVarSet      -- A function *or thunk* with an exactly
+        | not_letrec_bound      = emptyVarSet  -- Only letrec-bound escapees are interesting
+        | f_arity == n_val_args = emptyVarSet  -- A function *or thunk* with an exactly
                                                -- saturated call doesn't escape
                                                -- (let-no-escape applies to 'thunks' too)
 
                                                -- saturated call doesn't escape
                                                -- (let-no-escape applies to 'thunks' too)
 
@@ -557,10 +495,14 @@ coreToStgApp maybe_thunk_body f args
        --         continuation, but it does no harm to just union the
        --         two regardless.
 
        --         continuation, but it does no harm to just union the
        --         two regardless.
 
+       res_ty = exprType (mkApps (Var f) args)
        app = case globalIdDetails f of
        app = case globalIdDetails f of
-               DataConId dc -> StgConApp dc args'
-               PrimOpId op  -> StgPrimApp op args' (exprType (mkApps (Var f) args))
-               _other       -> StgApp f args'
+               DataConId dc | saturated -> StgConApp dc args'
+               PrimOpId op              -> ASSERT( saturated )
+                                           StgOpApp (StgPrimOp op) args' res_ty
+               FCallId call             -> ASSERT( saturated )
+                                           StgOpApp (StgFCallOp call (idUnique f)) args' res_ty
+               _other                   -> StgApp f args'
 
     in
     returnLne (
 
     in
     returnLne (
@@ -584,7 +526,7 @@ coreToStgArgs []
 
 coreToStgArgs (Type ty : args) -- Type argument
   = coreToStgArgs args `thenLne` \ (args', fvs) ->
 
 coreToStgArgs (Type ty : args) -- Type argument
   = coreToStgArgs args `thenLne` \ (args', fvs) ->
-    if opt_KeepStgTypes then
+    if opt_RuntimeTypes then
        returnLne (StgTypeArg ty : args', fvs `unionFVInfo` tyvarFVInfo (tyVarsOfType ty))
     else
     returnLne (args', fvs)
        returnLne (StgTypeArg ty : args', fvs `unionFVInfo` tyvarFVInfo (tyVarsOfType ty))
     else
     returnLne (args', fvs)
@@ -625,20 +567,20 @@ coreToStgLet let_no_escape bind body
        getVarsLiveInCont               `thenLne` \ live_in_cont ->
        setVarsLiveInCont (if let_no_escape 
                                then live_in_cont 
        getVarsLiveInCont               `thenLne` \ live_in_cont ->
        setVarsLiveInCont (if let_no_escape 
                                then live_in_cont 
-                               else (emptyVarSet,emptyVarSet))
+                               else emptyLiveInfo)
                          (vars_bind rec_body_fvs bind)
                          (vars_bind rec_body_fvs bind)
-                 `thenLne` \ (bind2, bind_fvs, bind_escs, bind_lvs, env_ext) ->
+           `thenLne` \ ( bind2, bind_fvs, bind_escs, bind_lv_info, env_ext) ->
 
        -- Do the body
        extendVarEnvLne env_ext (
          coreToStgExpr body          `thenLne` \(body2, body_fvs, body_escs) ->
 
        -- Do the body
        extendVarEnvLne env_ext (
          coreToStgExpr body          `thenLne` \(body2, body_fvs, body_escs) ->
-         freeVarsToLiveVars body_fvs `thenLne` \(body_lvs, _) ->
+         freeVarsToLiveVars body_fvs `thenLne` \ body_lv_info ->
 
 
-         returnLne (bind2, bind_fvs, bind_escs, bind_lvs,
-                    body2, body_fvs, body_escs, body_lvs)
+         returnLne (bind2, bind_fvs, bind_escs, getLiveVars bind_lv_info,
+                    body2, body_fvs, body_escs, getLiveVars body_lv_info)
        )
 
        )
 
-    ) `thenLne` (\ (bind2, bind_fvs, bind_escs, bind_lvs,
+    ) `thenLne` (\ (bind2, bind_fvs, bind_escs, bind_lvs, 
                    body2, body_fvs, body_escs, body_lvs) ->
 
 
                    body2, body_fvs, body_escs, body_lvs) ->
 
 
@@ -651,7 +593,7 @@ coreToStgLet let_no_escape bind body
          = binders `minusFVBinders` (bind_fvs `unionFVInfo` body_fvs)
 
        live_in_whole_let
          = binders `minusFVBinders` (bind_fvs `unionFVInfo` body_fvs)
 
        live_in_whole_let
-         = bind_lvs `unionVarSet` (body_lvs `minusVarSet` set_of_binders)
+         = bind_lvs `unionVarSet` (body_lvs `delVarSetList` binders)
 
        real_bind_escs = if let_no_escape then
                            bind_escs
 
        real_bind_escs = if let_no_escape then
                            bind_escs
@@ -659,7 +601,7 @@ coreToStgLet let_no_escape bind body
                            getFVSet bind_fvs
                            -- Everything escapes which is free in the bindings
 
                            getFVSet bind_fvs
                            -- Everything escapes which is free in the bindings
 
-       let_escs = (real_bind_escs `unionVarSet` body_escs) `minusVarSet` set_of_binders
+       let_escs = (real_bind_escs `unionVarSet` body_escs) `delVarSetList` binders
 
        all_escs = bind_escs `unionVarSet` body_escs    -- Still includes binders of
                                                        -- this let(rec)
 
        all_escs = bind_escs `unionVarSet` body_escs    -- Still includes binders of
                                                        -- this let(rec)
@@ -688,59 +630,56 @@ coreToStgLet let_no_escape bind body
     ))
   where
     set_of_binders = mkVarSet binders
     ))
   where
     set_of_binders = mkVarSet binders
-    binders       = case bind of
-                       NonRec binder rhs -> [binder]
-                       Rec pairs         -> map fst pairs
+    binders       = bindersOf bind
 
 
-    mk_binding bind_lvs binder
-       = (binder,  LetBound  NotTopLevelBound  -- Not top level
-                       live_vars
-          )
+    mk_binding bind_lv_info binder rhs
+       = (binder, LetBound (NestedLet live_vars) (manifestArity rhs))
        where
        where
-          live_vars = if let_no_escape then
-                           extendVarSet bind_lvs binder
-                      else
-                           unitVarSet binder
+          live_vars | let_no_escape = addLiveVar bind_lv_info binder
+                    | otherwise     = unitLiveVar binder
+               -- c.f. the invariant on NestedLet
 
     vars_bind :: FreeVarsInfo          -- Free var info for body of binding
              -> CoreBind
              -> LneM (StgBinding,
                       FreeVarsInfo, 
                       EscVarsSet,        -- free vars; escapee vars
 
     vars_bind :: FreeVarsInfo          -- Free var info for body of binding
              -> CoreBind
              -> LneM (StgBinding,
                       FreeVarsInfo, 
                       EscVarsSet,        -- free vars; escapee vars
-                      StgLiveVars,       -- vars live in binding
+                      LiveInfo,          -- Vars and CAFs live in binding
                       [(Id, HowBound)])  -- extension to environment
                                         
 
     vars_bind body_fvs (NonRec binder rhs)
                       [(Id, HowBound)])  -- extension to environment
                                         
 
     vars_bind body_fvs (NonRec binder rhs)
-      = coreToStgRhs body_fvs NotTopLevel (binder,rhs)
+      = coreToStgRhs body_fvs (binder,rhs)
                                `thenLne` \ (rhs2, bind_fvs, escs) ->
 
                                `thenLne` \ (rhs2, bind_fvs, escs) ->
 
-       freeVarsToLiveVars bind_fvs `thenLne` \ (bind_lvs, bind_cafs) ->
+       freeVarsToLiveVars bind_fvs `thenLne` \ bind_lv_info ->
        let
        let
-           env_ext_item@(binder', _) = mk_binding bind_lvs binder
+           env_ext_item = mk_binding bind_lv_info binder rhs
        in
        in
-       returnLne (StgNonRec (SRTEntries bind_cafs) binder' rhs2, 
-                       bind_fvs, escs, bind_lvs, [env_ext_item])
+       returnLne (StgNonRec (mkSRT bind_lv_info) binder rhs2, 
+                  bind_fvs, escs, bind_lv_info, [env_ext_item])
 
 
     vars_bind body_fvs (Rec pairs)
 
 
     vars_bind body_fvs (Rec pairs)
-      = fixLne (\ ~(_, rec_rhs_fvs, _, bind_lvs, _) ->
+      = fixLne (\ ~(_, rec_rhs_fvs, _, bind_lv_info, _) ->
           let
                rec_scope_fvs = unionFVInfo body_fvs rec_rhs_fvs
                binders = map fst pairs
           let
                rec_scope_fvs = unionFVInfo body_fvs rec_rhs_fvs
                binders = map fst pairs
-               env_ext = map (mk_binding bind_lvs) binders
+               env_ext = [ mk_binding bind_lv_info b rhs 
+                         | (b,rhs) <- pairs ]
           in
           extendVarEnvLne env_ext (
           in
           extendVarEnvLne env_ext (
-             mapAndUnzip3Lne (coreToStgRhs rec_scope_fvs NotTopLevel) pairs 
+             mapAndUnzip3Lne (coreToStgRhs rec_scope_fvs) pairs 
                                        `thenLne` \ (rhss2, fvss, escss) ->
              let
                        bind_fvs = unionFVInfos fvss
                        escs     = unionVarSets escss
              in
              freeVarsToLiveVars (binders `minusFVBinders` bind_fvs)
                                        `thenLne` \ (rhss2, fvss, escss) ->
              let
                        bind_fvs = unionFVInfos fvss
                        escs     = unionVarSets escss
              in
              freeVarsToLiveVars (binders `minusFVBinders` bind_fvs)
-                                       `thenLne` \ (bind_lvs, bind_cafs) ->
-             returnLne (StgRec (SRTEntries bind_cafs) (binders `zip` rhss2), 
-                               bind_fvs, escs, bind_lvs, env_ext)
+                                       `thenLne` \ bind_lv_info ->
+
+             returnLne (StgRec (mkSRT bind_lv_info) (binders `zip` rhss2), 
+                        bind_fvs, escs, bind_lv_info, env_ext)
           )
        )
 
           )
        )
 
@@ -750,6 +689,84 @@ is_join_var :: Id -> Bool
 is_join_var j = occNameUserString (getOccName j) == "$j"
 \end{code}
 
 is_join_var j = occNameUserString (getOccName j) == "$j"
 \end{code}
 
+\begin{code}
+coreToStgRhs :: FreeVarsInfo           -- Free var info for the scope of the binding
+            -> (Id,CoreExpr)
+            -> LneM (StgRhs, FreeVarsInfo, EscVarsSet)
+
+coreToStgRhs scope_fv_info (bndr, rhs)
+  = coreToStgExpr rhs          `thenLne` \ (new_rhs, rhs_fvs, rhs_escs) ->
+    getEnvLne                  `thenLne` \ env ->    
+    returnLne (mkStgRhs env rhs_fvs bndr_info new_rhs,
+              rhs_fvs, rhs_escs)
+  where
+    bndr_info = lookupFVInfo scope_fv_info bndr
+
+mkStgRhs :: IdEnv HowBound -> FreeVarsInfo -> StgBinderInfo -> StgExpr -> StgRhs
+
+mkStgRhs env rhs_fvs binder_info (StgConApp con args)
+  = StgRhsCon noCCS con args
+
+mkStgRhs env rhs_fvs binder_info (StgLam _ bndrs body)
+  = StgRhsClosure noCCS binder_info
+                 (getFVs rhs_fvs)               
+                 ReEntrant
+                 bndrs body
+       
+mkStgRhs env rhs_fvs binder_info rhs
+  = StgRhsClosure noCCS binder_info
+                 (getFVs rhs_fvs)               
+                 upd_flag [] rhs
+  where
+    upd_flag | isPAP env rhs  = ReEntrant
+            | otherwise      = Updatable
+{- ToDo:
+          upd = if isOnceDem dem
+                   then (if isNotTop toplev 
+                           then SingleEntry    -- HA!  Paydirt for "dem"
+                           else 
+#ifdef DEBUG
+                     trace "WARNING: SE CAFs unsupported, forcing UPD instead" $
+#endif
+                     Updatable)
+               else Updatable
+        -- For now we forbid SingleEntry CAFs; they tickle the
+        -- ASSERT in rts/Storage.c line 215 at newCAF() re mut_link,
+        -- and I don't understand why.  There's only one SE_CAF (well,
+        -- only one that tickled a great gaping bug in an earlier attempt
+        -- at ClosureInfo.getEntryConvention) in the whole of nofib, 
+        -- specifically Main.lvl6 in spectral/cryptarithm2.
+        -- So no great loss.  KSW 2000-07.
+-}
+\end{code}
+
+Detect thunks which will reduce immediately to PAPs, and make them
+non-updatable.  This has several advantages:
+
+        - the non-updatable thunk behaves exactly like the PAP,
+
+       - the thunk is more efficient to enter, because it is
+         specialised to the task.
+
+        - we save one update frame, one stg_update_PAP, one update
+         and lots of PAP_enters.
+
+       - in the case where the thunk is top-level, we save building
+         a black hole and futhermore the thunk isn't considered to
+         be a CAF any more, so it doesn't appear in any SRTs.
+
+We do it here, because the arity information is accurate, and we need
+to do it before the SRT pass to save the SRT entries associated with
+any top-level PAPs.
+
+\begin{code}
+isPAP env (StgApp f args) = listLengthCmp args arity == LT -- idArity f > length args
+                         where
+                           arity = stgArity f (lookupBinding env f)
+isPAP env _              = False
+\end{code}
+
+
 %************************************************************************
 %*                                                                     *
 \subsection[LNE-monad]{A little monad for this let-no-escaping pass}
 %************************************************************************
 %*                                                                     *
 \subsection[LNE-monad]{A little monad for this let-no-escaping pass}
@@ -761,37 +778,85 @@ help.  All the stuff here is only passed *down*.
 
 \begin{code}
 type LneM a =  IdEnv HowBound
 
 \begin{code}
 type LneM a =  IdEnv HowBound
-           -> (StgLiveVars,    -- vars live in continuation
-               IdSet)          -- cafs live in continuation
+           -> LiveInfo         -- Vars and CAFs live in continuation
            -> a
 
            -> a
 
+type LiveInfo = (StgLiveVars,  -- Dynamic live variables; 
+                               -- i.e. ones with a nested (non-top-level) binding
+                CafSet)        -- Static live variables;
+                               -- i.e. top-level variables that are CAFs or refer to them
+
+type EscVarsSet = IdSet
+type CafSet     = IdSet
+
 data HowBound
 data HowBound
-  = ImportBound
-  | CaseBound
-  | LambdaBound
-  | LetBound
-       TopLevelCafInfo
-       StgLiveVars     -- Live vars... see notes below
+  = ImportBound                -- Used only as a response to lookupBinding; never
+                       -- exists in the range of the (IdEnv HowBound)
+
+  | LetBound           -- A let(rec) in this module
+       LetInfo         -- Whether top level or nested
+       Arity           -- Its arity (local Ids don't have arity info at this point)
+
+  | LambdaBound                -- Used for both lambda and case
+
+data LetInfo = NestedLet LiveInfo      -- For nested things, what is live if this thing is live?
+                                       -- Invariant: the binder itself is always a member of
+                                       --            the dynamic set of its own LiveInfo
+
+            | TopLet CafInfo           -- For top level things, is it a CAF, or can it refer to one?
 
 isLetBound (LetBound _ _) = True
 isLetBound other         = False
 
 isLetBound (LetBound _ _) = True
 isLetBound other         = False
+
+topLevelBound ImportBound            = True
+topLevelBound (LetBound (TopLet _) _) = True
+topLevelBound other                  = False
 \end{code}
 
 \end{code}
 
-For a let(rec)-bound variable, x, we record StgLiveVars, the set of
-variables that are live if x is live.  For "normal" variables that is
-just x alone.  If x is a let-no-escaped variable then x is represented
-by a code pointer and a stack pointer (well, one for each stack).  So
-all of the variables needed in the execution of x are live if x is,
-and are therefore recorded in the LetBound constructor; x itself
-*is* included.
+For a let(rec)-bound variable, x, we record LiveInfo, the set of
+variables that are live if x is live.  This LiveInfo comprises
+       (a) dynamic live variables (ones with a non-top-level binding)
+       (b) static live variabes (CAFs or things that refer to CAFs)
+
+For "normal" variables (a) is just x alone.  If x is a let-no-escaped
+variable then x is represented by a code pointer and a stack pointer
+(well, one for each stack).  So all of the variables needed in the
+execution of x are live if x is, and are therefore recorded in the
+LetBound constructor; x itself *is* included.
 
 
-The set of live variables is guaranteed ot have no further let-no-escaped
+The set of dynamic live variables is guaranteed ot have no further let-no-escaped
 variables in it.
 
 variables in it.
 
+\begin{code}
+emptyLiveInfo :: LiveInfo
+emptyLiveInfo = (emptyVarSet,emptyVarSet)
+
+unitLiveVar :: Id -> LiveInfo
+unitLiveVar lv = (unitVarSet lv, emptyVarSet)
+
+unitLiveCaf :: Id -> LiveInfo
+unitLiveCaf caf = (emptyVarSet, unitVarSet caf)
+
+addLiveVar :: LiveInfo -> Id -> LiveInfo
+addLiveVar (lvs, cafs) id = (lvs `extendVarSet` id, cafs)
+
+unionLiveInfo :: LiveInfo -> LiveInfo -> LiveInfo
+unionLiveInfo (lv1,caf1) (lv2,caf2) = (lv1 `unionVarSet` lv2, caf1 `unionVarSet` caf2)
+
+mkSRT :: LiveInfo -> SRT
+mkSRT (_, cafs) = SRTEntries cafs
+
+getLiveVars :: LiveInfo -> StgLiveVars
+getLiveVars (lvs, _) = lvs
+\end{code}
+
+
 The std monad functions:
 \begin{code}
 initLne :: IdEnv HowBound -> LneM a -> a
 The std monad functions:
 \begin{code}
 initLne :: IdEnv HowBound -> LneM a -> a
-initLne env m = m env (emptyVarSet,emptyVarSet)
+initLne env m = m env emptyLiveInfo
+
+
 
 {-# INLINE thenLne #-}
 {-# INLINE returnLne #-}
 
 {-# INLINE thenLne #-}
 {-# INLINE returnLne #-}
@@ -836,10 +901,10 @@ fixLne expr env lvs_cont
 Functions specific to this monad:
 
 \begin{code}
 Functions specific to this monad:
 
 \begin{code}
-getVarsLiveInCont :: LneM (StgLiveVars, IdSet)
+getVarsLiveInCont :: LneM LiveInfo
 getVarsLiveInCont env lvs_cont = lvs_cont
 
 getVarsLiveInCont env lvs_cont = lvs_cont
 
-setVarsLiveInCont :: (StgLiveVars,IdSet) -> LneM a -> LneM a
+setVarsLiveInCont :: LiveInfo -> LneM a -> LneM a
 setVarsLiveInCont new_lvs_cont expr env lvs_cont
   = expr env new_lvs_cont
 
 setVarsLiveInCont new_lvs_cont expr env lvs_cont
   = expr env new_lvs_cont
 
@@ -848,44 +913,40 @@ extendVarEnvLne ids_w_howbound expr env lvs_cont
   = expr (extendVarEnvList env ids_w_howbound) lvs_cont
 
 lookupVarLne :: Id -> LneM HowBound
   = expr (extendVarEnvList env ids_w_howbound) lvs_cont
 
 lookupVarLne :: Id -> LneM HowBound
-lookupVarLne v env lvs_cont
-  = returnLne (
-      case (lookupVarEnv env v) of
-       Just xx -> xx
-       Nothing -> ImportBound
-    ) env lvs_cont
+lookupVarLne v env lvs_cont = returnLne (lookupBinding env v) env lvs_cont
+
+getEnvLne :: LneM (IdEnv HowBound)
+getEnvLne env lvs_cont = returnLne env env lvs_cont
+
+lookupBinding :: IdEnv HowBound -> Id -> HowBound
+lookupBinding env v = case lookupVarEnv env v of
+                       Just xx -> xx
+                       Nothing -> ASSERT2( isGlobalId v, ppr v ) ImportBound
+
 
 -- The result of lookupLiveVarsForSet, a set of live variables, is
 -- only ever tacked onto a decorated expression. It is never used as
 -- the basis of a control decision, which might give a black hole.
 
 
 -- The result of lookupLiveVarsForSet, a set of live variables, is
 -- only ever tacked onto a decorated expression. It is never used as
 -- the basis of a control decision, which might give a black hole.
 
-freeVarsToLiveVars :: FreeVarsInfo -> LneM (StgLiveVars, IdSet)
+freeVarsToLiveVars :: FreeVarsInfo -> LneM LiveInfo
 freeVarsToLiveVars fvs env live_in_cont
 freeVarsToLiveVars fvs env live_in_cont
-  = returnLne (lvs `unionVarSet` lvs_cont,
-              mkVarSet cafs `unionVarSet` cafs_cont)
-        env live_in_cont
+  = returnLne live_info env live_in_cont
   where
   where
-    (lvs_cont, cafs_cont) = live_in_cont -- not a strict pattern match!
-    (local, global) = partition isLocalId (allFVs fvs)
-
-    cafs = filter is_caf_one global
-    lvs  = unionVarSets (map do_one local)
-
-    do_one v
-      = if isLocalId v then
-           case (lookupVarEnv env v) of
-             Just (LetBound _ lvs) -> extendVarSet lvs v
-             Just _                -> unitVarSet v
-             Nothing -> pprPanic "lookupLiveVarsForSet/do_one:" (ppr v)
-       else
-           emptyVarSet
-
-    is_caf_one v
-        = case lookupVarEnv env v of
-               Just (LetBound TopLevelHasCafs lvs) ->
-                   ASSERT( isEmptyVarSet lvs ) True
-               Just (LetBound _ _) -> False
-               _otherwise          -> mayHaveCafRefs (idCafInfo v)
+    live_info    = foldr unionLiveInfo live_in_cont lvs_from_fvs
+    lvs_from_fvs = map do_one (allFreeIds fvs)
+
+    do_one (v, how_bound)
+      = case how_bound of
+         ImportBound                     -> unitLiveCaf v      -- Only CAF imports are 
+                                                               -- recorded in fvs
+         LetBound (TopLet caf_info) _ 
+               | mayHaveCafRefs caf_info -> unitLiveCaf v
+               | otherwise               -> emptyLiveInfo
+
+         LetBound (NestedLet lvs) _      -> lvs        -- lvs already contains v
+                                                       -- (see the invariant on NestedLet)
+
+         _lambda_or_case_binding         -> unitLiveVar v      -- Bound by lambda or case
 \end{code}
 
 %************************************************************************
 \end{code}
 
 %************************************************************************
@@ -895,7 +956,21 @@ freeVarsToLiveVars fvs env live_in_cont
 %************************************************************************
 
 \begin{code}
 %************************************************************************
 
 \begin{code}
-type FreeVarsInfo = VarEnv (Var, TopLevelCafInfo, StgBinderInfo)
+type FreeVarsInfo = VarEnv (Var, HowBound, StgBinderInfo)
+       -- The Var is so we can gather up the free variables
+       -- as a set.
+       --
+       -- The HowBound info just saves repeated lookups;
+       -- we look up just once when we encounter the occurrence.
+       -- INVARIANT: Any ImportBound Ids are HaveCafRef Ids
+       --            Imported Ids without CAF refs are simply
+       --            not put in the FreeVarsInfo for an expression.
+       --            See singletonFVInfo and freeVarsToLiveVars
+       --
+       -- StgBinderInfo records how it occurs; notably, we
+       -- are interested in whether it only occurs in saturated 
+       -- applications, because then we don't need to build a
+       -- curried version.
        -- If f is mapped to noBinderInfo, that means
        -- that f *is* mentioned (else it wouldn't be in the
        -- IdEnv at all), but perhaps in an unsaturated applications.
        -- If f is mapped to noBinderInfo, that means
        -- that f *is* mentioned (else it wouldn't be in the
        -- IdEnv at all), but perhaps in an unsaturated applications.
@@ -906,14 +981,6 @@ type FreeVarsInfo = VarEnv (Var, TopLevelCafInfo, StgBinderInfo)
        --
        -- For ILX we track free var info for type variables too;
        -- hence VarEnv not IdEnv
        --
        -- For ILX we track free var info for type variables too;
        -- hence VarEnv not IdEnv
-
-data TopLevelCafInfo
-  = NotTopLevelBound
-  | TopLevelNoCafs
-  | TopLevelHasCafs
-  deriving Eq
-
-type EscVarsSet = IdSet
 \end{code}
 
 \begin{code}
 \end{code}
 
 \begin{code}
@@ -921,18 +988,17 @@ emptyFVInfo :: FreeVarsInfo
 emptyFVInfo = emptyVarEnv
 
 singletonFVInfo :: Id -> HowBound -> StgBinderInfo -> FreeVarsInfo
 emptyFVInfo = emptyVarEnv
 
 singletonFVInfo :: Id -> HowBound -> StgBinderInfo -> FreeVarsInfo
+-- Don't record non-CAF imports at all, to keep free-var sets small
 singletonFVInfo id ImportBound info
 singletonFVInfo id ImportBound info
-   | mayHaveCafRefs (idCafInfo id) = unitVarEnv id (id, TopLevelHasCafs, info)
+   | mayHaveCafRefs (idCafInfo id) = unitVarEnv id (id, ImportBound, info)
    | otherwise                            = emptyVarEnv
    | otherwise                            = emptyVarEnv
-singletonFVInfo id (LetBound top_level _) info 
-   = unitVarEnv id (id, top_level, info)
-singletonFVInfo id other info
-   = unitVarEnv id (id, NotTopLevelBound, info)
+singletonFVInfo id how_bound info  = unitVarEnv id (id, how_bound, info)
 
 tyvarFVInfo :: TyVarSet -> FreeVarsInfo
 tyvarFVInfo tvs = foldVarSet add emptyFVInfo tvs
         where
 
 tyvarFVInfo :: TyVarSet -> FreeVarsInfo
 tyvarFVInfo tvs = foldVarSet add emptyFVInfo tvs
         where
-         add tv fvs = extendVarEnv fvs tv (tv, NotTopLevelBound, noBinderInfo)
+         add tv fvs = extendVarEnv fvs tv (tv, LambdaBound, noBinderInfo)
+               -- Type variables must be lambda-bound
 
 unionFVInfo :: FreeVarsInfo -> FreeVarsInfo -> FreeVarsInfo
 unionFVInfo fv1 fv2 = plusVarEnv_C plusFVInfo fv1 fv2
 
 unionFVInfo :: FreeVarsInfo -> FreeVarsInfo -> FreeVarsInfo
 unionFVInfo fv1 fv2 = plusVarEnv_C plusFVInfo fv1 fv2
@@ -944,7 +1010,7 @@ minusFVBinders :: [Id] -> FreeVarsInfo -> FreeVarsInfo
 minusFVBinders vs fv = foldr minusFVBinder fv vs
 
 minusFVBinder :: Id -> FreeVarsInfo -> FreeVarsInfo
 minusFVBinders vs fv = foldr minusFVBinder fv vs
 
 minusFVBinder :: Id -> FreeVarsInfo -> FreeVarsInfo
-minusFVBinder v fv | isId v && opt_KeepStgTypes
+minusFVBinder v fv | isId v && opt_RuntimeTypes
                   = (fv `delVarEnv` v) `unionFVInfo` 
                     tyvarFVInfo (tyVarsOfType (idType v))
                   | otherwise = fv `delVarEnv` v
                   = (fv `delVarEnv` v) `unionFVInfo` 
                     tyvarFVInfo (tyVarsOfType (idType v))
                   | otherwise = fv `delVarEnv` v
@@ -958,30 +1024,45 @@ lookupFVInfo :: FreeVarsInfo -> Id -> StgBinderInfo
 -- Find how the given Id is used.
 -- Externally visible things may be used any old how
 lookupFVInfo fvs id 
 -- Find how the given Id is used.
 -- Externally visible things may be used any old how
 lookupFVInfo fvs id 
-  | isExternallyVisibleName (idName id) = noBinderInfo
+  | isExternalName (idName id) = noBinderInfo
   | otherwise = case lookupVarEnv fvs id of
                        Nothing         -> noBinderInfo
                        Just (_,_,info) -> info
 
   | otherwise = case lookupVarEnv fvs id of
                        Nothing         -> noBinderInfo
                        Just (_,_,info) -> info
 
-allFVs :: FreeVarsInfo -> [Id] -- Non-top-level things only
-allFVs fvs = [id | (id,_,_) <- rngVarEnv fvs]
+allFreeIds :: FreeVarsInfo -> [(Id,HowBound)]  -- Both top level and non-top-level Ids
+allFreeIds fvs = [(id,how_bound) | (id,how_bound,_) <- rngVarEnv fvs, isId id]
 
 
-getFVs :: FreeVarsInfo -> [Id] -- Non-top-level things only
-getFVs fvs = [id | (id,NotTopLevelBound,_) <- rngVarEnv fvs]
+-- Non-top-level things only, both type variables and ids
+-- (type variables only if opt_RuntimeTypes)
+getFVs :: FreeVarsInfo -> [Var]        
+getFVs fvs = [id | (id, how_bound, _) <- rngVarEnv fvs, 
+                   not (topLevelBound how_bound) ]
 
 
-getFVSet :: FreeVarsInfo -> IdSet
+getFVSet :: FreeVarsInfo -> VarSet
 getFVSet fvs = mkVarSet (getFVs fvs)
 
 getFVSet fvs = mkVarSet (getFVs fvs)
 
-plusFVInfo (id1,top1,info1) (id2,top2,info2)
-  = ASSERT (id1 == id2 && top1 == top2)
-    (id1, top1, combineStgBinderInfo info1 info2)
+plusFVInfo (id1,hb1,info1) (id2,hb2,info2)
+  = ASSERT (id1 == id2 && hb1 `check_eq_how_bound` hb2)
+    (id1, hb1, combineStgBinderInfo info1 info2)
+
+#ifdef DEBUG
+-- The HowBound info for a variable in the FVInfo should be consistent
+check_eq_how_bound ImportBound               ImportBound        = True
+check_eq_how_bound LambdaBound               LambdaBound        = True
+check_eq_how_bound (LetBound li1 ar1) (LetBound li2 ar2) = ar1 == ar2 && check_eq_li li1 li2
+check_eq_how_bound hb1               hb2                = False
+
+check_eq_li (NestedLet _) (NestedLet _) = True
+check_eq_li (TopLet _)    (TopLet _)    = True
+check_eq_li li1          li2           = False
+#endif
 \end{code}
 
 Misc.
 \begin{code}
 filterStgBinders :: [Var] -> [Var]
 filterStgBinders bndrs
 \end{code}
 
 Misc.
 \begin{code}
 filterStgBinders :: [Var] -> [Var]
 filterStgBinders bndrs
-  | opt_KeepStgTypes = bndrs
+  | opt_RuntimeTypes = bndrs
   | otherwise       = filter isId bndrs
 \end{code}
 
   | otherwise       = filter isId bndrs
 \end{code}
 
@@ -1031,40 +1112,34 @@ it as a CAF.  In these cases however, we would need to use an additional
 CAF list to keep track of non-collectable CAFs.  
 
 \begin{code}
 CAF list to keep track of non-collectable CAFs.  
 
 \begin{code}
-hasCafRefs  :: IdEnv HowBound -> CoreExpr -> CafInfo
--- Only called for the RHS of top-level lets
-hasCafRefss :: IdEnv HowBound -> [CoreExpr] -> CafInfo
-       -- predicate returns True for a given Id if we look at this Id when
-       -- calculating the result.  Used to *avoid* looking at the CafInfo
-       -- field for an Id that is part of the current recursive group.
-
+hasCafRefs  :: IdEnv HowBound -> CoreExpr -> (CafInfo, UpdateFlag)
 hasCafRefs p expr 
 hasCafRefs p expr 
-  | isCAF expr || isFastTrue (cafRefs p expr) =  MayHaveCafRefs
-  | otherwise = NoCafRefs
-
-       -- used for recursive groups.  The whole group is set to
-       -- "MayHaveCafRefs" if at least one of the group is a CAF or
-       -- refers to any CAFs.
-hasCafRefss p exprs
-  | any isCAF exprs || isFastTrue (cafRefss p exprs) = MayHaveCafRefs
-  | otherwise = NoCafRefs
+  | is_caf || mentions_cafs = (MayHaveCafRefs, upd_flag)
+  | otherwise              = (NoCafRefs,      ReEntrant)
+  where
+    mentions_cafs = isFastTrue (cafRefs p expr)
+    is_caf = not (rhsIsNonUpd p expr)
+    upd_flag | is_caf    = Updatable
+            | otherwise = ReEntrant
 
 
--- cafRefs compiles to beautiful code :)
+-- The environment that cafRefs uses has top-level bindings *only*.
+-- We don't bother to add local bindings as cafRefs traverses the expression
+-- because they will all be for LocalIds (all nested things are LocalIds)
+-- However, we must look in the env first, because some top level things
+-- might be local Ids
 
 cafRefs p (Var id)
 
 cafRefs p (Var id)
-  | isLocalId id = fastBool False
-  | otherwise = 
-      case lookupVarEnv p id of
-       Just (LetBound TopLevelHasCafs _) -> fastBool True
-        Just (LetBound _ _) -> fastBool False
-       Nothing -> fastBool (cgMayHaveCafRefs (idCgInfo id)) --  imported Ids
+  = case lookupVarEnv p id of
+       Just (LetBound (TopLet caf_info) _) -> fastBool (mayHaveCafRefs caf_info)
+        Nothing | isGlobalId id                    -> fastBool (mayHaveCafRefs (idCafInfo id)) -- Imported
+               | otherwise                 -> fastBool False                           -- Nested binder
+       _other                              -> error ("cafRefs " ++ showSDoc (ppr id))  -- No nested things in env
 
 cafRefs p (Lit l)           = fastBool False
 cafRefs p (App f a)         = fastOr (cafRefs p f) (cafRefs p) a
 cafRefs p (Lam x e)         = cafRefs p e
 cafRefs p (Let b e)         = fastOr (cafRefss p (rhssOfBind b)) (cafRefs p) e
 
 cafRefs p (Lit l)           = fastBool False
 cafRefs p (App f a)         = fastOr (cafRefs p f) (cafRefs p) a
 cafRefs p (Lam x e)         = cafRefs p e
 cafRefs p (Let b e)         = fastOr (cafRefss p (rhssOfBind b)) (cafRefs p) e
-cafRefs p (Case e bndr alts) = fastOr (cafRefs p e)    
-                               (cafRefss p) (rhssOfAlts alts)
+cafRefs p (Case e bndr alts) = fastOr (cafRefs p e) (cafRefss p) (rhssOfAlts alts)
 cafRefs p (Note n e)        = cafRefs p e
 cafRefs p (Type t)          = fastBool False
 
 cafRefs p (Note n e)        = cafRefs p e
 cafRefs p (Type t)          = fastBool False
 
@@ -1074,13 +1149,8 @@ cafRefss p (e:es) = fastOr (cafRefs p e) (cafRefss p) es
 -- hack for lazy-or over FastBool.
 fastOr a f x = fastBool (isFastTrue a || isFastTrue (f x))
 
 -- hack for lazy-or over FastBool.
 fastOr a f x = fastBool (isFastTrue a || isFastTrue (f x))
 
-isCAF :: CoreExpr -> Bool
--- Only called for the RHS of top-level lets
-isCAF e = not (rhsIsNonUpd e)
-  {- ToDo: check type for onceness, i.e. non-updatable thunks? -}
 
 
-
-rhsIsNonUpd :: CoreExpr -> Bool
+rhsIsNonUpd :: IdEnv HowBound -> CoreExpr -> Bool
   -- True => Value-lambda, constructor, PAP
   -- This is a bit like CoreUtils.exprIsValue, with the following differences:
   --   a) scc "foo" (\x -> ...) is updatable (so we catch the right SCC)
   -- True => Value-lambda, constructor, PAP
   -- This is a bit like CoreUtils.exprIsValue, with the following differences:
   --   a) scc "foo" (\x -> ...) is updatable (so we catch the right SCC)
@@ -1090,13 +1160,18 @@ rhsIsNonUpd :: CoreExpr -> Bool
   -- 
   --    c) don't look through unfolding of f in (f x).  I'm suspicious of this one
 
   -- 
   --    c) don't look through unfolding of f in (f x).  I'm suspicious of this one
 
-rhsIsNonUpd (Lam b e)          = isId b || rhsIsNonUpd e
-rhsIsNonUpd (Note (SCC _) e)   = False
-rhsIsNonUpd (Note _ e)         = rhsIsNonUpd e
-rhsIsNonUpd other_expr
+-- This function has to line up with what the update flag
+-- for the StgRhs gets set to in mkStgRhs (above)
+--
+-- When opt_RuntimeTypes is on, we keep type lambdas and treat
+-- them as making the RHS re-entrant (non-updatable).
+rhsIsNonUpd p (Lam b e)          = isRuntimeVar b || rhsIsNonUpd p e
+rhsIsNonUpd p (Note (SCC _) e)   = False
+rhsIsNonUpd p (Note _ e)         = rhsIsNonUpd p e
+rhsIsNonUpd p other_expr
   = go other_expr 0 []
   where
   = go other_expr 0 []
   where
-    go (Var f) n_args args = idAppIsNonUpd f n_args args
+    go (Var f) n_args args = idAppIsNonUpd p f n_args args
        
     go (App f a) n_args args
        | isTypeArg a = go f n_args args
        
     go (App f a) n_args args
        | isTypeArg a = go f n_args args
@@ -1107,13 +1182,18 @@ rhsIsNonUpd other_expr
 
     go other n_args args = False
 
 
     go other n_args args = False
 
-idAppIsNonUpd :: Id -> Int -> [CoreExpr] -> Bool
-idAppIsNonUpd id n_val_args args
-  | Just con <- isDataConId_maybe id = not (isDynConApp con args)
-  | otherwise                       = n_val_args < idArity id
+idAppIsNonUpd :: IdEnv HowBound -> Id -> Int -> [CoreExpr] -> Bool
+idAppIsNonUpd p id n_val_args args
+  | Just con <- isDataConId_maybe id = not (isCrossDllConApp con args)
+  | otherwise                       = n_val_args < stgArity id (lookupBinding p id)
+
+stgArity :: Id -> HowBound -> Arity
+stgArity f (LetBound _ arity) = arity
+stgArity f ImportBound       = idArity f
+stgArity f LambdaBound        = 0
 
 
-isDynConApp :: DataCon -> [CoreExpr] -> Bool
-isDynConApp con args = isDllName (dataConName con) || any isDynArg args
+isCrossDllConApp :: DataCon -> [CoreExpr] -> Bool
+isCrossDllConApp con args = isDllName (dataConName con) || any isCrossDllArg args
 -- Top-level constructor applications can usually be allocated 
 -- statically, but they can't if 
 --     a) the constructor, or any of the arguments, come from another DLL
 -- Top-level constructor applications can usually be allocated 
 -- statically, but they can't if 
 --     a) the constructor, or any of the arguments, come from another DLL
@@ -1121,13 +1201,15 @@ isDynConApp con args = isDllName (dataConName con) || any isDynArg args
 -- (because we can't refer to static labels in other DLLs).
 -- If this happens we simply make the RHS into an updatable thunk, 
 -- and 'exectute' it rather than allocating it statically.
 -- (because we can't refer to static labels in other DLLs).
 -- If this happens we simply make the RHS into an updatable thunk, 
 -- and 'exectute' it rather than allocating it statically.
--- All this should match the decision in (see CoreToStg.coreToStgRhs)
+-- All this should match the decision in (see CoreToStg.mkStgRhs)
 
 
 
 
-isDynArg :: CoreExpr -> Bool
-isDynArg (Var v)    = isDllName (idName v)
-isDynArg (Note _ e) = isDynArg e
-isDynArg (Lit lit)  = isLitLitLit lit
-isDynArg (App e _)  = isDynArg e       -- must be a type app
-isDynArg (Lam _ e)  = isDynArg e       -- must be a type lam
+isCrossDllArg :: CoreExpr -> Bool
+-- True if somewhere in the expression there's a cross-DLL reference
+isCrossDllArg (Type _)    = False
+isCrossDllArg (Var v)     = isDllName (idName v)
+isCrossDllArg (Note _ e)  = isCrossDllArg e
+isCrossDllArg (Lit lit)   = isLitLitLit lit
+isCrossDllArg (App e1 e2) = isCrossDllArg e1 || isCrossDllArg e2       -- must be a type app
+isCrossDllArg (Lam v e)   = isCrossDllArg e    -- must be a type lam
 \end{code}
 \end{code}