[project @ 1999-05-21 12:52:28 by simonmar]
[ghc-hetmet.git] / ghc / compiler / stgSyn / CoreToStg.lhs
index de10ed9..64e7e48 100644 (file)
@@ -1,5 +1,5 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
 %
 %************************************************************************
 %*                                                                     *
@@ -18,35 +18,67 @@ import CoreSyn              -- input
 import StgSyn          -- output
 
 import CoreUtils       ( coreExprType )
-import CostCentre      ( noCostCentre )
-import MkId            ( mkSysLocal ) 
-import Id              ( externallyVisibleId, mkIdWithNewUniq,
-                         nullIdEnv, addOneToIdEnv, lookupIdEnv,
-                         IdEnv, Id
+import SimplUtils      ( findDefault )
+import CostCentre      ( noCCS )
+import Id              ( Id, mkSysLocal, idType, getIdStrictness, idUnique, isExportedId,
+                         externallyVisibleId, setIdUnique, idName, getIdDemandInfo
                        )
-import SrcLoc          ( noSrcLoc )
-import Type            ( splitAlgTyConApp, Type )
-import UniqSupply      ( UniqSupply, UniqSM, 
-                         returnUs, thenUs, initUs,
-                         mapUs, getUnique
-                       )
-import PrimOp          ( PrimOp(..) )
-                       
-import Outputable      ( panic )
-
-isLeakFreeType x y = False -- safe option; ToDo
+import Var             ( Var, varType, modifyIdInfo )
+import IdInfo          ( setDemandInfo, StrictnessInfo(..) )
+import UsageSPUtils     ( primOpUsgTys )
+import DataCon         ( DataCon, dataConName, dataConId )
+import Demand          ( Demand, isStrict, wwStrict, wwLazy )
+import Name            ( Name, nameModule, isLocallyDefinedName )
+import Module          ( isDynamicModule )
+import Const           ( Con(..), Literal(..), isLitLitLit, conStrictness, isWHNFCon )
+import VarEnv
+import PrimOp          ( PrimOp(..), primOpUsg, primOpSig )
+import Type            ( isUnLiftedType, isUnboxedTupleType, Type, splitFunTy_maybe,
+                          UsageAnn(..), tyUsg, applyTy, mkUsgTy )
+import TysPrim         ( intPrimTy )
+import UniqSupply      -- all of it, really
+import Util            ( lengthExceeds )
+import BasicTypes      ( TopLevelFlag(..) )
+import Maybes
+import Outputable
 \end{code}
 
 
+       *************************************************
        ***************  OVERVIEW   *********************
+       *************************************************
 
 
-The business of this pass is to convert Core to Stg.  On the way:
+The business of this pass is to convert Core to Stg.  On the way it
+does some important transformations:
 
-* We discard type lambdas and applications. In so doing we discard
-  "trivial" bindings such as
+1.  We discard type lambdas and applications. In so doing we discard
+    "trivial" bindings such as
        x = y t1 t2
-  where t1, t2 are types
+    where t1, t2 are types
+
+2.  We get the program into "A-normal form".  In particular:
+
+       f E        ==>  let x = E in f x
+               OR ==>  case E of x -> f x
+
+    where E is a non-trivial expression.
+    Which transformation is used depends on whether f is strict or not.
+    [Previously the transformation to case used to be done by the
+     simplifier, but it's better done here.  It does mean that f needs
+     to have its strictness info correct!.]
+
+    Similarly, convert any unboxed let's into cases.
+    [I'm experimenting with leaving 'ok-for-speculation' rhss in let-form
+     right up to this point.]
+
+3.  We clone all local binders.  The code generator uses the uniques to
+    name chunks of code for thunks, so it's important that the names used
+    are globally unique, not simply not-in-scope, which is all that 
+    the simplifier ensures.
+
+
+NOTE THAT:
 
 * We don't pin on correct arities any more, because they can be mucked up
   by the lambda lifter.  In particular, the lambda lifter can take a local
@@ -66,18 +98,59 @@ The business of this pass is to convert Core to Stg.  On the way:
 %*                                                                     *
 %************************************************************************
 
-Because we're going to come across ``boring'' bindings like
-\tr{let x = /\ tyvars -> y in ...}, we want to keep a small
-environment, so we can just replace all occurrences of \tr{x}
-with \tr{y}.
-
-March 98: We also use this environment to give all locally bound
+March 98: We keep a small environment to give all locally bound
 Names new unique ids, since the code generator assumes that binders
 are unique across a module. (Simplifier doesn't maintain this
 invariant any longer.)
 
+A binder to be floated out becomes an @StgFloatBind@.
+
+\begin{code}
+type StgEnv = IdEnv Id
+
+data StgFloatBind = NoBindF
+                 | RecF [(Id, StgRhs)]
+                 | NonRecF 
+                       Id
+                       StgExpr         -- *Can* be a StgLam
+                       RhsDemand
+                       [StgFloatBind]
+
+-- The interesting one is the NonRecF
+--     NonRecF x rhs demand binds
+-- means
+--     x = let binds in rhs
+-- (or possibly case etc if x demand is strict)
+-- The binds are kept separate so they can be floated futher
+-- if appropriate
+\end{code}
+
+A @RhsDemand@ gives the demand on an RHS: strict (@isStrictDem@) and
+thus case-bound, or if let-bound, at most once (@isOnceDem@) or
+otherwise.
+
 \begin{code}
-type StgEnv = IdEnv StgArg
+data RhsDemand  = RhsDemand { isStrictDem :: Bool,  -- True => used at least once
+                              isOnceDem   :: Bool   -- True => used at most once
+                            }
+
+mkDem :: Demand -> Bool -> RhsDemand
+mkDem strict once = RhsDemand (isStrict strict) once
+
+mkDemTy :: Demand -> Type -> RhsDemand
+mkDemTy strict ty = RhsDemand (isStrict strict) (isOnceTy ty)
+
+isOnceTy :: Type -> Bool
+isOnceTy ty = case tyUsg ty of
+                    UsOnce -> True
+                    UsMany -> False
+
+bdrDem :: Id -> RhsDemand
+bdrDem id = mkDem (getIdDemandInfo id) (isOnceTy (idType id))
+
+safeDem, onceDem :: RhsDemand
+safeDem = RhsDemand False False  -- always safe to use this
+onceDem = RhsDemand False True   -- used at most once
 \end{code}
 
 No free/live variable information is pinned on in this pass; it's added
@@ -94,21 +167,36 @@ bOGUS_FVs = panic "bOGUS_FVs" -- [] (ditto)
 
 \begin{code}
 topCoreBindsToStg :: UniqSupply        -- name supply
-                 -> [CoreBinding]      -- input
+                 -> [CoreBind] -- input
                  -> [StgBinding]       -- output
 
 topCoreBindsToStg us core_binds
-  = initUs us (coreBindsToStg nullIdEnv core_binds)
+  = initUs_ us (coreBindsToStg emptyVarEnv core_binds)
   where
-    coreBindsToStg :: StgEnv -> [CoreBinding] -> UniqSM [StgBinding]
+    coreBindsToStg :: StgEnv -> [CoreBind] -> UniqSM [StgBinding]
 
     coreBindsToStg env [] = returnUs []
     coreBindsToStg env (b:bs)
-      = coreBindToStg  env b           `thenUs` \ (new_b, new_env) ->
+      = coreBindToStg  TopLevel env b  `thenUs` \ (bind_spec, new_env) ->
        coreBindsToStg new_env bs       `thenUs` \ new_bs ->
-       returnUs (new_b ++ new_bs)
+       case bind_spec of
+         NonRecF bndr rhs dem floats 
+               -> ASSERT2( not (isStrictDem dem) && 
+                           not (isUnLiftedType (idType bndr)),
+                           ppr b )             -- No top-level cases!
+
+                  mkStgBinds floats rhs        `thenUs` \ new_rhs ->
+                  returnUs (StgNonRec bndr (exprToRhs dem new_rhs) : new_bs)
+                                       -- Keep all the floats inside...
+                                       -- Some might be cases etc
+                                       -- We might want to revisit this decision
+
+         RecF prs -> returnUs (StgRec prs : new_bs)
+         NoBindF  -> pprTrace "topCoreBindsToStg" (ppr b) $
+                     returnUs new_bs
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[coreToStg-binds]{Converting bindings}
@@ -116,55 +204,36 @@ topCoreBindsToStg us core_binds
 %************************************************************************
 
 \begin{code}
-coreBindToStg :: StgEnv
-             -> CoreBinding
-             -> UniqSM ([StgBinding],  -- Empty or singleton
-                        StgEnv)        -- Floats
+coreBindToStg :: TopLevelFlag -> StgEnv -> CoreBind -> UniqSM (StgFloatBind, StgEnv)
+
+coreBindToStg top_lev env (NonRec binder rhs)
+  = coreExprToStgFloat env rhs dem                     `thenUs` \ (floats, stg_rhs) ->
+    case (floats, stg_rhs) of
+       ([], StgApp var []) | not (isExportedId binder)
+                    -> returnUs (NoBindF, extendVarEnv env binder var)
+               -- A trivial binding let x = y in ...
+               -- can arise if postSimplExpr floats a NoRep literal out
+               -- so it seems sensible to deal with it well.
+               -- But we don't want to discard exported things.  They can
+               -- occur; e.g. an exported user binding f = g
+
+       other -> newLocalId top_lev env binder          `thenUs` \ (new_env, new_binder) ->
+                returnUs (NonRecF new_binder stg_rhs dem floats, new_env)
+  where
+    dem = bdrDem binder
 
-coreBindToStg env (NonRec binder rhs)
-  = coreRhsToStg env rhs       `thenUs` \ stg_rhs ->
-    let
-       -- Binds to return if RHS is trivial
-       triv_binds | externallyVisibleId binder = [StgNonRec binder stg_rhs]    -- Retain it
-                  | otherwise                  = []                            -- Discard it
-    in
-    case stg_rhs of
-      StgRhsClosure cc bi fvs upd [] (StgApp atom [] lvs) ->
-               -- Trivial RHS, so augment envt, and ditch the binding
-               returnUs (triv_binds, new_env)
-          where
-               new_env = addOneToIdEnv env binder atom
-
-      StgRhsCon cc con_id [] ->
-               -- Trivial RHS, so augment envt, and ditch the binding
-               returnUs (triv_binds, new_env)
-          where
-               new_env = addOneToIdEnv env binder (StgConArg con_id)
-
-      other ->    -- Non-trivial RHS
-           mkUniqueBinder env binder   `thenUs` \ (new_env, new_binder) ->
-           returnUs ([StgNonRec new_binder stg_rhs], new_env)
-    where
-     mkUniqueBinder env binder
-       | externallyVisibleId binder = returnUs (env, binder)
-       | otherwise = 
-           -- local binder, give it a new unique Id.
-           newUniqueLocalId binder   `thenUs` \ binder' ->
-           let
-             new_env = addOneToIdEnv env binder (StgVarArg binder')
-           in
-          returnUs (new_env, binder')
-
-
-coreBindToStg env (Rec pairs)
-  = -- NB: *** WE DO NOT CHECK FOR TRIV_BINDS in REC BIND ****
-    -- (possibly ToDo)
-    let
-       (binders, rhss) = unzip pairs
-    in
-    newLocalIds env True{-maybe externally visible-} binders   `thenUs` \ (binders', env') ->
-    mapUs (coreRhsToStg env') rhss                             `thenUs` \ stg_rhss ->
-    returnUs ([StgRec (binders' `zip` stg_rhss)], env')
+coreBindToStg top_lev env (Rec pairs)
+  = newLocalIds top_lev env binders    `thenUs` \ (env', binders') ->
+    mapUs (do_rhs env') pairs          `thenUs` \ stg_rhss ->
+    returnUs (RecF (binders' `zip` stg_rhss), env')
+  where
+    binders = map fst pairs
+    do_rhs env (bndr,rhs) = coreExprToStgFloat env rhs dem     `thenUs` \ (floats, stg_expr) ->
+                           mkStgBinds floats stg_expr          `thenUs` \ stg_expr' ->
+                               -- NB: stg_expr' might still be a StgLam (and we want that)
+                           returnUs (exprToRhs dem stg_expr')
+                         where
+                           dem = bdrDem bndr
 \end{code}
 
 
@@ -175,29 +244,84 @@ coreBindToStg env (Rec pairs)
 %************************************************************************
 
 \begin{code}
-coreRhsToStg :: StgEnv -> CoreExpr -> UniqSM StgRhs
-
-coreRhsToStg env core_rhs
-  = coreExprToStg env core_rhs         `thenUs` \ stg_expr ->
-
-    let stg_rhs = case stg_expr of
-                   StgLet (StgNonRec var1 rhs) (StgApp (StgVarArg var2) [] _)
-                       | var1 == var2 -> rhs
-                       -- This curious stuff is to unravel what a lambda turns into
-                       -- We have to do it this way, rather than spot a lambda in the
-                       -- incoming rhs.  Why?  Because trivial bindings might conceal
-                       -- what the rhs is actually like.
-
-                   StgCon con args _ -> StgRhsCon noCostCentre con args
-
-                   other -> StgRhsClosure noCostCentre -- No cost centre (ToDo?)
-                                          stgArgOcc    -- safe
-                                          bOGUS_FVs
-                                          Updatable    -- Be pessimistic
-                                          []
-                                          stg_expr
-    in
-    returnUs stg_rhs
+exprToRhs :: RhsDemand -> StgExpr -> StgRhs
+exprToRhs dem (StgLam _ bndrs body)
+  = ASSERT( not (null bndrs) )
+    StgRhsClosure noCCS
+                 stgArgOcc
+                 noSRT
+                 bOGUS_FVs
+                 ReEntrant     -- binders is non-empty
+                 bndrs
+                 body
+
+{-
+  We reject the following candidates for 'static constructor'dom:
+  
+    - any dcon that takes a lit-lit as an arg.
+    - [Win32 DLLs only]: any dcon that is (or takes as arg)
+      that's living in a DLL.
+
+  These constraints are necessary to ensure that the code
+  generated in the end for the static constructors, which
+  live in the data segment, remain valid - i.e., it has to
+  be constant. For obvious reasons, that's hard to guarantee
+  with lit-lits. The second case of a constructor referring
+  to static closures hiding out in some DLL is an artifact
+  of the way Win32 DLLs handle global DLL variables. A (data)
+  symbol exported from a DLL  has to be accessed through a
+  level of indirection at the site of use, so whereas
+
+     extern StgClosure y_closure;
+     extern StgClosure z_closure;
+     x = { ..., &y_closure, &z_closure };
+
+  is legal when the symbols are in scope at link-time, it is
+  not when y_closure is in a DLL. So, any potential static
+  closures that refers to stuff that's residing in a DLL
+  will be put in an (updateable) thunk instead.
+
+  An alternative strategy is to support the generation of
+  constructors (ala C++ static class constructors) which will
+  then be run at load time to fix up static closures.
+-}
+exprToRhs dem (StgCon (DataCon con) args _)
+  | not is_dynamic  &&
+    all  (not.is_lit_lit) args  = StgRhsCon noCCS con args
+ where
+  is_dynamic = isDynCon con || any (isDynArg) args
+
+  is_lit_lit (StgVarArg _) = False
+  is_lit_lit (StgConArg x) =
+     case x of
+       Literal l -> isLitLitLit l
+       _         -> False
+
+exprToRhs dem expr
+       = StgRhsClosure noCCS           -- No cost centre (ToDo?)
+                       stgArgOcc       -- safe
+                       noSRT           -- figure out later
+                       bOGUS_FVs
+                       (if isOnceDem dem then SingleEntry else Updatable)
+                               -- HA!  Paydirt for "dem"
+                       []
+                       expr
+
+isDynCon :: DataCon -> Bool
+isDynCon con = isDynName (dataConName con)
+
+isDynArg :: StgArg -> Bool
+isDynArg (StgVarArg v)   = isDynName (idName v)
+isDynArg (StgConArg con) =
+  case con of
+    DataCon dc -> isDynCon dc
+    Literal l  -> isLitLitLit l
+    _          -> False
+
+isDynName :: Name -> Bool
+isDynName nm = 
+      not (isLocallyDefinedName nm) && 
+      isDynamicModule (nameModule nm)
 \end{code}
 
 
@@ -208,16 +332,30 @@ coreRhsToStg env core_rhs
 %************************************************************************
 
 \begin{code}
-coreArgsToStg :: StgEnv -> [CoreArg] -> ([Type], [StgArg])
-
-coreArgsToStg env [] = ([], [])
-coreArgsToStg env (a:as)
-  = case a of
-       TyArg    t -> (t:trest, vrest)
-       VarArg   v -> (trest,   stgLookup env v : vrest)
-       LitArg   l -> (trest,   StgLitArg l     : vrest)
+coreArgsToStg :: StgEnv -> [(CoreArg,RhsDemand)] -> UniqSM ([StgFloatBind], [StgArg])
+-- Arguments are all value arguments (tyargs already removed), paired with their demand
+
+coreArgsToStg env []
+  = returnUs ([], [])
+
+coreArgsToStg env (ad:ads)
+  = coreArgToStg env ad                `thenUs` \ (bs1, a') ->
+    coreArgsToStg env ads       `thenUs` \ (bs2, as') ->
+    returnUs (bs1 ++ bs2, a' : as')
+
+
+coreArgToStg :: StgEnv -> (CoreArg,RhsDemand) -> UniqSM ([StgFloatBind], StgArg)
+-- This is where we arrange that a non-trivial argument is let-bound
+
+coreArgToStg env (arg,dem)
+  = coreExprToStgFloat env arg dem             `thenUs` \ (floats, arg') ->
+    case arg' of
+       StgCon con [] _ -> returnUs (floats, StgConArg con)
+       StgApp v []     -> returnUs (floats, StgVarArg v)
+       other           -> newStgVar arg_ty     `thenUs` \ v ->
+                          returnUs ([NonRecF v arg' dem floats], StgVarArg v)
   where
-    (trest,vrest) = coreArgsToStg env as
+    arg_ty = coreExprType arg
 \end{code}
 
 
@@ -228,34 +366,60 @@ coreArgsToStg env (a:as)
 %************************************************************************
 
 \begin{code}
-coreExprToStg :: StgEnv -> CoreExpr -> UniqSM StgExpr
+coreExprToStg :: StgEnv -> CoreExpr -> RhsDemand -> UniqSM StgExpr
+coreExprToStg env expr dem
+  = coreExprToStgFloat env expr dem    `thenUs` \ (binds,stg_expr) ->
+    mkStgBinds binds stg_expr          `thenUs` \ stg_expr' ->
+    deStgLam stg_expr'
+\end{code}
 
-coreExprToStg env (Lit lit)
-  = returnUs (StgApp (StgLitArg lit) [] bOGUS_LVs)
+%************************************************************************
+%*                                                                     *
+\subsubsection[coreToStg-let(rec)]{Let and letrec expressions}
+%*                                                                     *
+%************************************************************************
 
-coreExprToStg env (Var var)
-  = returnUs (mk_app (stgLookup env var) [])
+\begin{code}
+coreExprToStgFloat :: StgEnv -> CoreExpr 
+                  -> RhsDemand
+                  -> UniqSM ([StgFloatBind], StgExpr)
+-- Transform an expression to STG. The demand on the expression is
+-- given by RhsDemand, and is solely used ot figure out the usage
+-- of constructor args: if the constructor is used once, then so are
+-- its arguments.  The strictness info in RhsDemand isn't used.
+
+-- The StgExpr returned *can* be an StgLam
+\end{code}
 
-coreExprToStg env (Con con args)
-  = let
-       (types, stg_atoms) = coreArgsToStg env args
-    in
-    returnUs (StgCon con stg_atoms bOGUS_LVs)
+Simple cases first
 
-coreExprToStg env (Prim op args)
-  = mkPrimOpUnique op `thenUs` \ op' ->
-    let
-       (types, stg_atoms) = coreArgsToStg env args
-    in
-    returnUs (StgPrim op' stg_atoms bOGUS_LVs)
-   where
-    mkPrimOpUnique (CCallOp (Right _) a b c d e) =
-       getUnique `thenUs` \ u ->
-       returnUs (CCallOp (Right u) a b c d e)
-    mkPrimOpUnique op = returnUs op
+\begin{code}
+coreExprToStgFloat env (Var var) dem
+  = returnUs ([], StgApp (stgLookup env var) [])
 
+coreExprToStgFloat env (Let bind body) dem
+  = coreBindToStg NotTopLevel env bind `thenUs` \ (new_bind, new_env) ->
+    coreExprToStgFloat new_env body dem        `thenUs` \ (floats, stg_body) ->
+    returnUs (new_bind:floats, stg_body)
+\end{code}
+
+Covert core @scc@ expression directly to STG @scc@ expression.
+
+\begin{code}
+coreExprToStgFloat env (Note (SCC cc) expr) dem
+  = coreExprToStg env expr dem  `thenUs` \ stg_expr ->
+    returnUs ([], StgSCC cc stg_expr)
+
+coreExprToStgFloat env (Note other_note expr) dem
+  = coreExprToStgFloat env expr dem
+\end{code}
+
+\begin{code}
+coreExprToStgFloat env expr@(Type _) dem
+  = pprPanic "coreExprToStgFloat: tyarg unexpected:" $ ppr expr
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsubsection[coreToStg-lambdas]{Lambda abstractions}
@@ -263,28 +427,33 @@ coreExprToStg env (Prim op args)
 %************************************************************************
 
 \begin{code}
-coreExprToStg env expr@(Lam _ _)
+coreExprToStgFloat env expr@(Lam _ _) dem
   = let
-       (_, binders, body) = collectBinders expr
+       expr_ty         = coreExprType expr
+       (binders, body) = collectBinders expr
+       id_binders      = filter isId binders
+        body_dem        = trace "coreExprToStg: approximating body_dem in Lam"
+                          safeDem
     in
-    newLocalIds env False{-all local-} binders  `thenUs` \ (binders', env') ->
-    coreExprToStg env' body                     `thenUs` \ stg_body ->
-
-    if null binders then -- it was all type/usage binders; tossed
-       returnUs stg_body
+    if null id_binders then    -- It was all type/usage binders; tossed
+       coreExprToStgFloat env body dem
     else
-       newStgVar (coreExprType expr)   `thenUs` \ var ->
-       returnUs
-         (StgLet (StgNonRec var
-                                 (StgRhsClosure noCostCentre
-                                 stgArgOcc
-                                 bOGUS_FVs
-                                 ReEntrant     -- binders is non-empty
-                                 binders'
-                                 stg_body))
-          (StgApp (StgVarArg var) [] bOGUS_LVs))
+       -- At least some value binders
+    newLocalIds NotTopLevel env id_binders     `thenUs` \ (env', binders') ->
+    coreExprToStgFloat env' body body_dem      `thenUs` \ (floats, stg_body) ->
+    mkStgBinds floats stg_body                 `thenUs` \ stg_body' ->
+
+    case stg_body' of
+      StgLam ty lam_bndrs lam_body ->
+               -- If the body reduced to a lambda too, join them up
+         returnUs ([], StgLam expr_ty (binders' ++ lam_bndrs) lam_body)
+
+      other ->
+               -- Body didn't reduce to a lambda, so return one
+         returnUs ([], StgLam expr_ty binders' stg_body')
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsubsection[coreToStg-applications]{Applications}
@@ -292,152 +461,167 @@ coreExprToStg env expr@(Lam _ _)
 %************************************************************************
 
 \begin{code}
-coreExprToStg env expr@(App _ _)
+coreExprToStgFloat env expr@(App _ _) dem
   = let
-       (fun,args)    = collect_args expr []
-       (_, stg_args) = coreArgsToStg env args
+        (fun,rads,_,_) = collect_args expr
+        ads            = reverse rads
     in
+    coreArgsToStg env ads              `thenUs` \ (arg_floats, stg_args) ->
+
        -- Now deal with the function
-    case (fun, args) of
+    case (fun, stg_args) of
       (Var fun_id, _) ->       -- A function Id, so do an StgApp; it's ok if
                                -- there are no arguments.
-                           returnUs (mk_app (stgLookup env fun_id) stg_args)
+                           returnUs (arg_floats, 
+                                     StgApp (stgLookup env fun_id) stg_args)
 
       (non_var_fun, []) ->     -- No value args, so recurse into the function
-                           coreExprToStg env non_var_fun
+                           ASSERT( null arg_floats )
+                           coreExprToStgFloat env non_var_fun dem
 
       other -> -- A non-variable applied to things; better let-bind it.
-               newStgVar (coreExprType fun)    `thenUs` \ fun_id ->
-               coreExprToStg env fun           `thenUs` \ (stg_fun) ->
-               let
-                  fun_rhs = StgRhsClosure noCostCentre -- No cost centre (ToDo?)
-                                          stgArgOcc
-                                          bOGUS_FVs
-                                          SingleEntry  -- Only entered once
-                                          []
-                                          stg_fun
-               in
-               returnUs (StgLet (StgNonRec fun_id fun_rhs)
-                                (StgApp (StgVarArg fun_id) stg_args bOGUS_LVs))
+               newStgVar (coreExprType fun)            `thenUs` \ fun_id ->
+                coreExprToStgFloat env fun onceDem     `thenUs` \ (fun_floats, stg_fun) ->
+               returnUs (NonRecF fun_id stg_fun onceDem fun_floats : arg_floats,
+                         StgApp fun_id stg_args)
+
   where
-       -- Collect arguments, discarding type/usage applications
-    collect_args (App e   (TyArg _))      args = collect_args e   args
-    collect_args (App fun arg)            args = collect_args fun (arg:args)
-    collect_args (Note (Coerce _ _) expr) args = collect_args expr args
-    collect_args (Note InlineCall   expr) args = collect_args expr args
-    collect_args fun                      args = (fun, args)
+       -- Collect arguments and demands (*in reverse order*)
+       -- collect_args e = (f, args_w_demands, ty, stricts)
+       --  => e = f tys args,  (i.e. args are just the value args)
+       --     e :: ty
+       --     stricts is the leftover demands of e on its further args
+       -- If stricts runs out, we zap all the demands in args_w_demands
+       -- because partial applications are lazy
+
+    collect_args :: CoreExpr -> (CoreExpr, [(CoreExpr,RhsDemand)], Type, [Demand])
+
+    collect_args (Note (Coerce ty _) e) = let (the_fun,ads,_,ss) = collect_args e
+                                          in  (the_fun,ads,ty,ss)
+    collect_args (Note InlineCall    e) = collect_args e
+    collect_args (Note (TermUsg _)   e) = collect_args e
+
+    collect_args (App fun (Type tyarg)) = let (the_fun,ads,fun_ty,ss) = collect_args fun
+                                          in  (the_fun,ads,applyTy fun_ty tyarg,ss)
+    collect_args (App fun arg) 
+       = case ss of
+           []            ->    -- Strictness info has run out
+                            (the_fun, (arg, mkDemTy wwLazy arg_ty) : zap ads, res_ty, repeat wwLazy)
+           (ss1:ss_rest) ->    -- Enough strictness info
+                            (the_fun, (arg, mkDemTy ss1 arg_ty)    : ads,     res_ty, ss_rest)
+       where
+         (the_fun, ads, fun_ty, ss) = collect_args fun
+          (arg_ty, res_ty)           = expectJust "coreExprToStgFloat:collect_args" $
+                                       splitFunTy_maybe fun_ty
+
+    collect_args (Var v)
+       = (Var v, [], idType v, stricts)
+       where
+         stricts = case getIdStrictness v of
+                       StrictnessInfo demands _ -> demands
+                       other                    -> repeat wwLazy
+
+    collect_args fun = (fun, [], coreExprType fun, repeat wwLazy)
+
+    -- "zap" nukes the strictness info for a partial application 
+    zap ads = [(arg, RhsDemand False once) | (arg, RhsDemand _ once) <- ads]
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsubsection[coreToStg-cases]{Case expressions}
+\subsubsection[coreToStg-con]{Constructors and primops}
 %*                                                                     *
 %************************************************************************
 
+For data constructors, the demand on an argument is the demand on the
+constructor as a whole (see module UsageSPInf).  For primops, the
+demand is derived from the type of the primop.
 
-******* TO DO TO DO: fix what follows
-
-Special case for
-
-       case (op x1 ... xn) of
-         y -> e
-
-where the type of the case scrutinee is a multi-constuctor algebraic type.
-Then we simply compile code for
-
-       let y = op x1 ... xn
-       in
-       e
-
-In this case:
-
-       case (op x1 ... xn) of
-          C a b -> ...
-          y     -> e
-
-where the type of the case scrutinee is a multi-constuctor algebraic type.
-we just bomb out at the moment. It never happens in practice.
-
-**** END OF TO DO TO DO
+If usage inference is off, we simply make all bindings updatable for
+speed.
 
 \begin{code}
-coreExprToStg env (Case scrut@(Prim op args) (AlgAlts alts (BindDefault binder rhs)))
-  = if not (null alts) then
-       panic "cgCase: case on PrimOp with default *and* alts\n"
-       -- For now, die if alts are non-empty
-    else
-       coreExprToStg env (Let (NonRec binder scrut) rhs)
-
-coreExprToStg env (Case discrim alts)
-  = coreExprToStg env discrim          `thenUs` \ stg_discrim ->
-    alts_to_stg discrim alts           `thenUs` \ stg_alts ->
-    getUnique                          `thenUs` \ uniq ->
-    returnUs (
-       StgCase stg_discrim
-               bOGUS_LVs
-               bOGUS_LVs
-               uniq
-               stg_alts
-    )
-  where
-    discrim_ty             = coreExprType discrim
-    (_, discrim_ty_args, _) = splitAlgTyConApp discrim_ty
-
-    alts_to_stg discrim (AlgAlts alts deflt)
-      = default_to_stg discrim deflt           `thenUs` \ stg_deflt ->
-       mapUs boxed_alt_to_stg alts             `thenUs` \ stg_alts  ->
-       returnUs (StgAlgAlts discrim_ty stg_alts stg_deflt)
-      where
-       boxed_alt_to_stg (con, bs, rhs)
-         = coreExprToStg env rhs    `thenUs` \ stg_rhs ->
-           returnUs (con, bs, [ True | b <- bs ]{-bogus use mask-}, stg_rhs)
-
-    alts_to_stg discrim (PrimAlts alts deflt)
-      = default_to_stg discrim deflt           `thenUs` \ stg_deflt ->
-       mapUs unboxed_alt_to_stg alts           `thenUs` \ stg_alts  ->
-       returnUs (StgPrimAlts discrim_ty stg_alts stg_deflt)
-      where
-       unboxed_alt_to_stg (lit, rhs)
-         = coreExprToStg env rhs    `thenUs` \ stg_rhs ->
-           returnUs (lit, stg_rhs)
-
-    default_to_stg discrim NoDefault
-      = returnUs StgNoDefault
-
-    default_to_stg discrim (BindDefault binder rhs)
-      = coreExprToStg env rhs    `thenUs` \ stg_rhs ->
-       returnUs (StgBindDefault binder True{-used? no it is lying-} stg_rhs)
-\end{code}
+coreExprToStgFloat env expr@(Con con args) dem
+  = let 
+        (stricts,_) = conStrictness con
+        onces = case con of
+                    DEFAULT   -> panic "coreExprToStgFloat: DEFAULT"
+                
+                    Literal _ -> ASSERT( null args' {-'cpp-} ) []
+                
+                    DataCon c -> repeat (isOnceDem dem)
+                                       -- HA!  This is the sole reason we propagate
+                                       -- dem all the way down 
+                
+                    PrimOp  p -> let tyargs      = map (\ (Type ty) -> ty) $
+                                                       takeWhile isTypeArg args
+                                     (arg_tys,_) = primOpUsgTys p tyargs
+                                 in  ASSERT( length arg_tys == length args' {-'cpp-} )
+                                     -- primops always fully applied, so == not >=
+                                     map isOnceTy arg_tys
+
+       dems' = zipWith mkDem stricts onces
+        args' = filter isValArg args
+    in
+    coreArgsToStg env (zip args' dems')                  `thenUs` \ (arg_floats, stg_atoms) ->
 
-%************************************************************************
-%*                                                                     *
-\subsubsection[coreToStg-let(rec)]{Let and letrec expressions}
-%*                                                                     *
-%************************************************************************
+       -- YUK YUK: must unique if present
+    (case con of
+       PrimOp (CCallOp (Right _) a b c) -> getUniqueUs   `thenUs` \ u ->
+                                           returnUs (PrimOp (CCallOp (Right u) a b c))
+       _                                -> returnUs con
+    )                                                     `thenUs` \ con' ->
 
-\begin{code}
-coreExprToStg env (Let bind body)
-  = coreBindToStg env     bind   `thenUs` \ (stg_binds, new_env) ->
-    coreExprToStg new_env body   `thenUs` \ stg_body ->
-    returnUs (mkStgLets stg_binds stg_body)
+    returnUs (arg_floats, StgCon con' stg_atoms (coreExprType expr))
 \end{code}
 
 
 %************************************************************************
 %*                                                                     *
-\subsubsection[coreToStg-scc]{SCC expressions}
+\subsubsection[coreToStg-cases]{Case expressions}
 %*                                                                     *
 %************************************************************************
 
-Covert core @scc@ expression directly to STG @scc@ expression.
 \begin{code}
-coreExprToStg env (Note (SCC cc) expr)
-  = coreExprToStg env expr   `thenUs` \ stg_expr ->
-    returnUs (StgSCC (coreExprType expr) cc stg_expr)
-\end{code}
+coreExprToStgFloat env (Case scrut bndr alts) dem
+  = coreExprToStgFloat env scrut (bdrDem bndr) `thenUs` \ (binds, scrut') ->
+    newEvaldLocalId env bndr                   `thenUs` \ (env', bndr') ->
+    alts_to_stg env' (findDefault alts)                `thenUs` \ alts' ->
+    returnUs (binds, mkStgCase scrut' bndr' alts')
+  where
+    scrut_ty  = idType bndr
+    prim_case = isUnLiftedType scrut_ty && not (isUnboxedTupleType scrut_ty)
+
+    alts_to_stg env (alts, deflt)
+      | prim_case
+      = default_to_stg env deflt               `thenUs` \ deflt' ->
+       mapUs (prim_alt_to_stg env) alts        `thenUs` \ alts' ->
+       returnUs (StgPrimAlts scrut_ty alts' deflt')
+
+      | otherwise
+      = default_to_stg env deflt               `thenUs` \ deflt' ->
+       mapUs (alg_alt_to_stg env) alts         `thenUs` \ alts' ->
+       returnUs (StgAlgAlts scrut_ty alts' deflt')
+
+    alg_alt_to_stg env (DataCon con, bs, rhs)
+         = coreExprToStg env rhs dem   `thenUs` \ stg_rhs ->
+           returnUs (con, filter isId bs, [ True | b <- bs ]{-bogus use mask-}, stg_rhs)
+               -- NB the filter isId.  Some of the binders may be
+               -- existential type variables, which STG doesn't care about
+
+    prim_alt_to_stg env (Literal lit, args, rhs)
+         = ASSERT( null args )
+           coreExprToStg env rhs dem   `thenUs` \ stg_rhs ->
+           returnUs (lit, stg_rhs)
 
-\begin{code}
-coreExprToStg env (Note other_note expr) = coreExprToStg env expr
+    default_to_stg env Nothing
+      = returnUs StgNoDefault
+
+    default_to_stg env (Just rhs)
+      = coreExprToStg env rhs dem   `thenUs` \ stg_rhs ->
+       returnUs (StgBindDefault stg_rhs)
+               -- The binder is used for prim cases and not otherwise
+               -- (hack for old code gen)
 \end{code}
 
 
@@ -451,52 +635,155 @@ There's not anything interesting we can ASSERT about \tr{var} if it
 isn't in the StgEnv. (WDP 94/06)
 
 \begin{code}
-stgLookup :: StgEnv -> Id -> StgArg
-stgLookup env var = case (lookupIdEnv env var) of
-                     Nothing   -> StgVarArg var
-                     Just atom -> atom
+stgLookup :: StgEnv -> Id -> Id
+stgLookup env var = case (lookupVarEnv env var) of
+                     Nothing  -> var
+                     Just var -> var
 \end{code}
 
 Invent a fresh @Id@:
 \begin{code}
 newStgVar :: Type -> UniqSM Id
 newStgVar ty
- = getUnique                   `thenUs` \ uniq ->
-   returnUs (mkSysLocal SLIT("stg") uniq ty noSrcLoc)
+ = getUniqueUs                 `thenUs` \ uniq ->
+   returnUs (mkSysLocal SLIT("stg") uniq ty)
 \end{code}
 
 \begin{code}
-newUniqueLocalId :: Id -> UniqSM Id
-newUniqueLocalId i =
-   getUnique                   `thenUs` \ uniq ->
-   returnUs (mkIdWithNewUniq i uniq)
-
-newLocalIds :: StgEnv -> Bool -> [Id] -> UniqSM ([Id], StgEnv)
-newLocalIds env maybe_visible [] = returnUs ([], env)
-newLocalIds env maybe_visible (i:is)
- | maybe_visible && externallyVisibleId i = 
-     newLocalIds env maybe_visible is `thenUs` \ (is', env') ->
-     returnUs (i:is', env')
- | otherwise             =
-     newUniqueLocalId i `thenUs` \ i' ->
-     let
-      new_env = addOneToIdEnv env i (StgVarArg i')
-     in
-     newLocalIds new_env maybe_visible is `thenUs` \ (is', env') ->
-     returnUs (i':is', env')
+-- we overload the demandInfo field of an Id to indicate whether the Id is definitely
+-- evaluated or not (i.e. whether it is a case binder).  This can be used to eliminate
+-- some redundant cases (c.f. dataToTag# above).
+
+newEvaldLocalId env id
+  = getUniqueUs                        `thenUs` \ uniq ->
+    let
+      id'     = modifyIdInfo (`setDemandInfo` wwStrict) (setIdUnique id uniq)
+      new_env = extendVarEnv env id id'
+    in
+    returnUs (new_env, id')
+
+
+newLocalId TopLevel env id
+  = returnUs (env, id)
+  -- Don't clone top-level binders.  MkIface relies on their
+  -- uniques staying the same, so it can snaffle IdInfo off the
+  -- STG ids to put in interface files.        
+
+newLocalId NotTopLevel env id
+  =    -- Local binder, give it a new unique Id.
+    getUniqueUs                        `thenUs` \ uniq ->
+    let
+      id'     = setIdUnique id uniq
+      new_env = extendVarEnv env id id'
+    in
+    returnUs (new_env, id')
+
+newLocalIds :: TopLevelFlag -> StgEnv -> [Id] -> UniqSM (StgEnv, [Id])
+newLocalIds top_lev env []
+  = returnUs (env, [])
+newLocalIds top_lev env (b:bs)
+  = newLocalId top_lev env b   `thenUs` \ (env', b') ->
+    newLocalIds top_lev env' bs        `thenUs` \ (env'', bs') ->
+    returnUs (env'', b':bs')
 \end{code}
 
 
 \begin{code}
-mkStgLets ::   [StgBinding]
-           -> StgExpr  -- body of let
-           -> StgExpr
+-- Stg doesn't have a lambda *expression*, 
+deStgLam (StgLam ty bndrs body) = mkStgLamExpr ty bndrs body
+deStgLam expr                  = returnUs expr
+
+mkStgLamExpr ty bndrs body
+  = ASSERT( not (null bndrs) )
+    newStgVar ty               `thenUs` \ fn ->
+    returnUs (StgLet (StgNonRec fn lam_closure) (StgApp fn []))
+  where
+    lam_closure = StgRhsClosure noCCS
+                               stgArgOcc
+                               noSRT
+                               bOGUS_FVs
+                               ReEntrant       -- binders is non-empty
+                               bndrs
+                               body
+
+mkStgBinds :: [StgFloatBind] 
+          -> StgExpr           -- *Can* be a StgLam 
+          -> UniqSM StgExpr    -- *Can* be a StgLam 
+
+mkStgBinds []     body = returnUs body
+mkStgBinds (b:bs) body 
+  = deStgLam body              `thenUs` \ body' ->
+    go (b:bs) body'
+  where
+    go []     body = returnUs body
+    go (b:bs) body = go bs body        `thenUs` \ body' ->
+                    mkStgBind  b body'
+
+-- The 'body' arg of mkStgBind can't be a StgLam
+mkStgBind NoBindF    body = returnUs body
+mkStgBind (RecF prs) body = returnUs (StgLet (StgRec prs) body)
+
+mkStgBind (NonRecF bndr rhs dem floats) body
+#ifdef DEBUG
+       -- We shouldn't get let or case of the form v=w
+  = case rhs of
+       StgApp v [] -> pprTrace "mkStgLet" (ppr bndr <+> ppr v)
+                      (mk_stg_let bndr rhs dem floats body)
+       other       ->  mk_stg_let bndr rhs dem floats body
+
+mk_stg_let bndr rhs dem floats body
+#endif
+  | isUnLiftedType bndr_ty                     -- Use a case/PrimAlts
+  = ASSERT( not (isUnboxedTupleType bndr_ty) )
+    mkStgBinds floats $
+    mkStgCase rhs bndr (StgPrimAlts bndr_ty [] (StgBindDefault body))
+
+  | is_whnf
+  = if is_strict then
+       -- Strict let with WHNF rhs
+       mkStgBinds floats $
+       StgLet (StgNonRec bndr (exprToRhs dem rhs)) body
+    else
+       -- Lazy let with WHNF rhs; float until we find a strict binding
+       let
+           (floats_out, floats_in) = splitFloats floats
+       in
+       mkStgBinds floats_in rhs        `thenUs` \ new_rhs ->
+       mkStgBinds floats_out $
+       StgLet (StgNonRec bndr (exprToRhs dem new_rhs)) body
+
+  | otherwise  -- Not WHNF
+  = if is_strict then
+       -- Strict let with non-WHNF rhs
+       mkStgBinds floats $
+       mkStgCase rhs bndr (StgAlgAlts bndr_ty [] (StgBindDefault body))
+    else
+       -- Lazy let with non-WHNF rhs, so keep the floats in the RHS
+       mkStgBinds floats rhs           `thenUs` \ new_rhs ->
+       returnUs (StgLet (StgNonRec bndr (exprToRhs dem new_rhs)) body)
+       
+  where
+    bndr_ty   = idType bndr
+    is_strict = isStrictDem dem
+    is_whnf   = case rhs of
+                 StgCon _ _ _ -> True
+                 StgLam _ _ _ -> True
+                 other        -> False
+
+-- Split at the first strict binding
+splitFloats fs@(NonRecF _ _ dem _ : _) 
+  | isStrictDem dem = ([], fs)
+
+splitFloats (f : fs) = case splitFloats fs of
+                            (fs_out, fs_in) -> (f : fs_out, fs_in)
+
+splitFloats [] = ([], [])
 
-mkStgLets binds body = foldr StgLet body binds
 
--- mk_app spots an StgCon in a function position, 
--- and turns it into an StgCon. See notes with
--- getArgAmode in CgBindery.
-mk_app (StgConArg con) args = StgCon con       args bOGUS_LVs
-mk_app other_fun       args = StgApp other_fun args bOGUS_LVs
+mkStgCase scrut bndr alts
+  = ASSERT( case scrut of { StgLam _ _ _ -> False; other -> True } )
+       -- We should never find 
+       --      case (\x->e) of { ... }
+       -- The simplifier eliminates such things
+    StgCase scrut bOGUS_LVs bOGUS_LVs bndr noSRT alts
 \end{code}