[project @ 1999-06-24 12:27:11 by simonmar]
[ghc-hetmet.git] / ghc / compiler / stgSyn / CoreToStg.lhs
index fb9529f..1a31975 100644 (file)
@@ -21,7 +21,7 @@ import CoreUtils      ( coreExprType )
 import SimplUtils      ( findDefault )
 import CostCentre      ( noCCS )
 import Id              ( Id, mkSysLocal, idType, getIdStrictness, idUnique, isExportedId,
-                         externallyVisibleId, setIdUnique, idName, getIdDemandInfo
+                         externallyVisibleId, setIdUnique, idName, getIdDemandInfo, setIdType
                        )
 import Var             ( Var, varType, modifyIdInfo )
 import IdInfo          ( setDemandInfo, StrictnessInfo(..) )
@@ -38,7 +38,9 @@ import Type           ( isUnLiftedType, isUnboxedTupleType, Type, splitFunTy_maybe,
 import TysPrim         ( intPrimTy )
 import UniqSupply      -- all of it, really
 import Util            ( lengthExceeds )
-import BasicTypes      ( TopLevelFlag(..) )
+import BasicTypes      ( TopLevelFlag(..), isNotTopLevel )
+import CmdLineOpts     ( opt_D_verbose_stg2stg )
+import UniqSet         ( emptyUniqSet )
 import Maybes
 import Outputable
 \end{code}
@@ -109,8 +111,20 @@ A binder to be floated out becomes an @StgFloatBind@.
 type StgEnv = IdEnv Id
 
 data StgFloatBind = NoBindF
-                 | NonRecF Id StgExpr RhsDemand
                  | 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
@@ -145,12 +159,17 @@ No free/live variable information is pinned on in this pass; it's added
 later.  For this pass
 we use @bOGUS_LVs@ and @bOGUS_FVs@ as placeholders.
 
+When printing out the Stg we need non-bottom values in these
+locations.
+
 \begin{code}
 bOGUS_LVs :: StgLiveVars
-bOGUS_LVs = panic "bOGUS_LVs" -- emptyUniqSet (used when pprTracing)
+bOGUS_LVs | opt_D_verbose_stg2stg = emptyUniqSet
+         | otherwise =panic "bOGUS_LVs"
 
 bOGUS_FVs :: [Id]
-bOGUS_FVs = panic "bOGUS_FVs" -- [] (ditto)
+bOGUS_FVs | opt_D_verbose_stg2stg = [] 
+         | otherwise = panic "bOGUS_FVs"
 \end{code}
 
 \begin{code}
@@ -167,16 +186,22 @@ topCoreBindsToStg us core_binds
     coreBindsToStg env (b:bs)
       = coreBindToStg  TopLevel env b  `thenUs` \ (bind_spec, new_env) ->
        coreBindsToStg new_env bs       `thenUs` \ new_bs ->
-       let
-          res_bs = case bind_spec of
-                       NonRecF bndr rhs dem -> ASSERT2( not (isStrictDem dem) && not (isUnLiftedType (idType bndr)),
-                                                        ppr b )
-                                                               -- No top-level cases!
-                                                    StgNonRec bndr (exprToRhs dem rhs) : new_bs
-                       RecF prs             -> StgRec prs : new_bs
-                       NoBindF              -> pprTrace "topCoreBindsToStg" (ppr b) new_bs
-       in
-       returnUs res_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 TopLevel 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}
 
 
@@ -190,9 +215,9 @@ topCoreBindsToStg us core_binds
 coreBindToStg :: TopLevelFlag -> StgEnv -> CoreBind -> UniqSM (StgFloatBind, StgEnv)
 
 coreBindToStg top_lev env (NonRec binder rhs)
-  = coreExprToStg env rhs dem                  `thenUs` \ stg_rhs ->
-    case stg_rhs of
-       StgApp var [] | not (isExportedId binder)
+  = 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
@@ -201,7 +226,7 @@ coreBindToStg top_lev env (NonRec binder rhs)
                -- 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, new_env)
+                returnUs (NonRecF new_binder stg_rhs dem floats, new_env)
   where
     dem = bdrDem binder
 
@@ -211,7 +236,12 @@ coreBindToStg top_lev env (Rec pairs)
     returnUs (RecF (binders' `zip` stg_rhss), env')
   where
     binders = map fst pairs
-    do_rhs env (bndr,rhs) = coreRhsToStg env rhs (bdrDem bndr)
+    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 top_lev stg_expr')
+                         where
+                           dem = bdrDem bndr
 \end{code}
 
 
@@ -222,19 +252,16 @@ coreBindToStg top_lev env (Rec pairs)
 %************************************************************************
 
 \begin{code}
-coreRhsToStg :: StgEnv -> CoreExpr -> RhsDemand -> UniqSM StgRhs
-coreRhsToStg env rhs dem
-  = coreExprToStg env rhs dem  `thenUs` \ stg_expr ->
-    returnUs (exprToRhs dem stg_expr)
-
-exprToRhs :: RhsDemand -> StgExpr -> StgRhs
-exprToRhs dem (StgLet (StgNonRec var1 rhs) (StgApp 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.
+exprToRhs :: RhsDemand -> TopLevelFlag -> 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:
@@ -266,9 +293,10 @@ exprToRhs dem (StgLet (StgNonRec var1 rhs) (StgApp var2 []))
   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
+exprToRhs dem toplev (StgCon (DataCon con) args _)
+  | isNotTopLevel toplev ||
+    (not is_dynamic  &&
+     all  (not.is_lit_lit) args)  = StgRhsCon noCCS con args
  where
   is_dynamic = isDynCon con || any (isDynArg) args
 
@@ -278,7 +306,7 @@ exprToRhs dem (StgCon (DataCon con) args _)
        Literal l -> isLitLitLit l
        _         -> False
 
-exprToRhs dem expr
+exprToRhs dem _ expr
        = StgRhsClosure noCCS           -- No cost centre (ToDo?)
                        stgArgOcc       -- safe
                        noSRT           -- figure out later
@@ -329,25 +357,12 @@ coreArgToStg :: StgEnv -> (CoreArg,RhsDemand) -> UniqSM ([StgFloatBind], StgArg)
 -- This is where we arrange that a non-trivial argument is let-bound
 
 coreArgToStg env (arg,dem)
-  | isStrictDem dem || isUnLiftedType arg_ty
-       -- Strict, so float all the binds out
-  = coreExprToStgFloat env arg dem  `thenUs` \ (binds, arg') ->
+  = coreExprToStgFloat env arg dem             `thenUs` \ (floats, arg') ->
     case arg' of
-           StgCon con [] _ | isWHNFCon con -> returnUs (binds, StgConArg con)
-           StgApp v []                     -> returnUs (binds, StgVarArg v)
-           other                           -> newStgVar arg_ty `thenUs` \ v ->
-                                              returnUs (binds ++ [NonRecF v arg' dem], StgVarArg v)
-  | otherwise
-       -- Lazy
-  = coreExprToStgFloat env arg dem  `thenUs` \ (binds, arg') ->
-    case (binds, arg') of
-       ([], StgCon con [] _) | isWHNFCon con -> returnUs ([], StgConArg con)
-       ([], StgApp v [])                     -> returnUs ([], StgVarArg v)
-
-       -- A non-trivial argument: we must let-bind it
-       -- We don't do the case part here... we leave that to mkStgLets
-       (_, other) ->    newStgVar arg_ty       `thenUs` \ v ->
-                        returnUs ([NonRecF v (mkStgBinds binds arg') dem], StgVarArg v)
+       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
     arg_ty = coreExprType arg
 \end{code}
@@ -362,8 +377,9 @@ coreArgToStg env (arg,dem)
 \begin{code}
 coreExprToStg :: StgEnv -> CoreExpr -> RhsDemand -> UniqSM StgExpr
 coreExprToStg env expr dem
-  = coreExprToStgFloat env expr dem  `thenUs` \ (binds,stg_expr) ->
-    returnUs (mkStgBinds binds stg_expr)
+  = coreExprToStgFloat env expr dem    `thenUs` \ (binds,stg_expr) ->
+    mkStgBinds binds stg_expr          `thenUs` \ stg_expr' ->
+    deStgLam stg_expr'
 \end{code}
 
 %************************************************************************
@@ -380,6 +396,8 @@ coreExprToStgFloat :: StgEnv -> CoreExpr
 -- 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}
 
 Simple cases first
@@ -394,7 +412,7 @@ coreExprToStgFloat env (Let bind body) dem
     returnUs (new_bind:floats, stg_body)
 \end{code}
 
-Covert core @scc@ expression directly to STG @scc@ expression.
+Convert core @scc@ expression directly to STG @scc@ expression.
 
 \begin{code}
 coreExprToStgFloat env (Note (SCC cc) expr) dem
@@ -420,51 +438,31 @@ coreExprToStgFloat env expr@(Type _) dem
 \begin{code}
 coreExprToStgFloat env expr@(Lam _ _) dem
   = let
+       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 NotTopLevel env id_binders     `thenUs` \ (env', binders') ->
-    coreExprToStg env' body body_dem           `thenUs` \ stg_body ->
-
     if null id_binders then    -- It was all type/usage binders; tossed
-       returnUs ([], stg_body)
+       coreExprToStgFloat env body dem
     else
-    case stg_body of
-
-      -- if the body reduced to a lambda too...
-      (StgLet (StgNonRec var (StgRhsClosure cc bi srt fvs uf args body))
-             (StgApp var' []))
-       | var == var' ->
-       returnUs ([],
-                               -- ToDo: make this a float, but we need
-                               -- a lambda form for that!  Sigh
-                 StgLet (StgNonRec var (StgRhsClosure noCCS
-                                 stgArgOcc
-                                 noSRT
-                                 bOGUS_FVs
-                                 ReEntrant
-                                 (binders' ++ args)
-                                 body))
-                 (StgApp var []))
-                                   
-      other ->
+       -- 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)
 
-       -- We must let-bind the lambda
-       newStgVar (coreExprType expr)   `thenUs` \ var ->
-       returnUs ([],
-                       -- Ditto
-                 StgLet (StgNonRec var (StgRhsClosure noCCS
-                                 stgArgOcc
-                                 noSRT
-                                 bOGUS_FVs
-                                 ReEntrant     -- binders is non-empty
-                                 binders'
-                                 stg_body))
-                 (StgApp var []))
+      other ->
+               -- Body didn't reduce to a lambda, so return one
+         returnUs ([], StgLam expr_ty binders' stg_body')
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsubsection[coreToStg-applications]{Applications}
@@ -474,26 +472,32 @@ coreExprToStgFloat env expr@(Lam _ _) dem
 \begin{code}
 coreExprToStgFloat env expr@(App _ _) dem
   = let
-        (fun,rads,_,_) = collect_args expr
-        ads            = reverse rads
+        (fun,rads,_,ss)       = collect_args expr
+        ads                   = reverse rads
+       final_ads | null ss   = ads
+                 | otherwise = zap ads -- Too few args to satisfy strictness info
+                                       -- so we have to ignore all the strictness info
+                                       -- e.g. + (error "urk")
+                                       -- Here, we can't evaluate the arg strictly,
+                                       -- because this partial application might be seq'd
     in
-    coreArgsToStg env ads              `thenUs` \ (binds, stg_args) ->
+    coreArgsToStg env final_ads                `thenUs` \ (arg_floats, stg_args) ->
 
        -- Now deal with the function
     case (fun, stg_args) of
       (Var fun_id, _) ->       -- A function Id, so do an StgApp; it's ok if
                                -- there are no arguments.
-                           returnUs (binds, 
+                           returnUs (arg_floats, 
                                      StgApp (stgLookup env fun_id) stg_args)
 
       (non_var_fun, []) ->     -- No value args, so recurse into the function
-                           ASSERT( null binds )
+                           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 onceDem   `thenUs` \ stg_fun ->
-               returnUs (NonRecF fun_id stg_fun onceDem : binds,
+               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
@@ -515,12 +519,11 @@ coreExprToStgFloat env expr@(App _ _) dem
     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)
+       = (the_fun, (arg, mkDemTy ss1 arg_ty) : ads, res_ty, ss_rest)
        where
+         (ss1, ss_rest)             = case ss of 
+                                        (ss1:ss_rest) -> (ss1, ss_rest)
+                                        []            -> (wwLazy, [])
          (the_fun, ads, fun_ty, ss) = collect_args fun
           (arg_ty, res_ty)           = expectJust "coreExprToStgFloat:collect_args" $
                                        splitFunTy_maybe fun_ty
@@ -574,7 +577,7 @@ coreExprToStgFloat env expr@(Con con args) dem
        dems' = zipWith mkDem stricts onces
         args' = filter isValArg args
     in
-    coreArgsToStg env (zip args' dems')                  `thenUs` \ (binds, stg_atoms) ->
+    coreArgsToStg env (zip args' dems')                  `thenUs` \ (arg_floats, stg_atoms) ->
 
        -- YUK YUK: must unique if present
     (case con of
@@ -583,7 +586,7 @@ coreExprToStgFloat env expr@(Con con args) dem
        _                                -> returnUs con
     )                                                     `thenUs` \ con' ->
 
-    returnUs (binds, StgCon con' stg_atoms (coreExprType expr))
+    returnUs (arg_floats, StgCon con' stg_atoms (coreExprType expr))
 \end{code}
 
 
@@ -593,6 +596,72 @@ coreExprToStgFloat env expr@(Con con args) dem
 %*                                                                     *
 %************************************************************************
 
+First, two special cases.  We mangle cases involving 
+               par# and seq#
+inthe scrutinee.
+
+Up to this point, seq# will appear like this:
+
+         case seq# e of
+               0# -> seqError#
+               _  -> <stuff>
+
+This code comes from an unfolding for 'seq' in Prelude.hs.
+The 0# branch is purely to bamboozle the strictness analyser.
+For example, if <stuff> is strict in x, and there was no seqError#
+branch, the strictness analyser would conclude that the whole expression
+was strict in x, and perhaps evaluate x first -- but that would be a DISASTER.
+
+Now that the evaluation order is safe, we translate this into
+
+         case e of
+               _ -> ...
+
+This used to be done in the post-simplification phase, but we need
+unfoldings involving seq# to appear unmangled in the interface file,
+hence we do this mangling here.
+
+Similarly, par# has an unfolding in PrelConc.lhs that makes it show
+up like this:
+
+       case par# e of
+         0# -> rhs
+         _  -> parError#
+
+
+    ==>
+       case par# e of
+         _ -> rhs
+
+fork# isn't handled like this - it's an explicit IO operation now.
+The reason is that fork# returns a ThreadId#, which gets in the
+way of the above scheme.  And anyway, IO is the only guaranteed
+way to enforce ordering  --SDM.
+
+
+\begin{code}
+coreExprToStgFloat env 
+       (Case scrut@(Con (PrimOp SeqOp) [Type ty, e]) bndr alts) dem
+  = coreExprToStgFloat env (Case e new_bndr [(DEFAULT,[],default_rhs)]) dem
+  where 
+    new_bndr                   = setIdType bndr ty
+    (other_alts, maybe_default) = findDefault alts
+    Just default_rhs           = maybe_default
+
+coreExprToStgFloat env 
+       (Case scrut@(Con (PrimOp ParOp) args) bndr alts) dem
+  | maybeToBool maybe_default
+  = coreExprToStgFloat env scrut (bdrDem bndr) `thenUs` \ (binds, scrut') ->
+    newEvaldLocalId env bndr                   `thenUs` \ (env', bndr') ->
+    coreExprToStg env' default_rhs dem                 `thenUs` \ default_rhs' ->
+    returnUs (binds, mkStgCase scrut' bndr' (StgPrimAlts (idType bndr) [] (StgBindDefault default_rhs')))
+  where
+    (other_alts, maybe_default) = findDefault alts
+    Just default_rhs           = maybe_default
+\end{code}
+
+Now for normal case expressions...
+
 \begin{code}
 coreExprToStgFloat env (Case scrut bndr alts) dem
   = coreExprToStgFloat env scrut (bdrDem bndr) `thenUs` \ (binds, scrut') ->
@@ -700,41 +769,101 @@ newLocalIds top_lev env (b:bs)
 
 
 \begin{code}
-mkStgBinds :: [StgFloatBind] -> StgExpr -> StgExpr
-mkStgBinds binds body = foldr mkStgBind body binds
+-- 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'
 
-mkStgBind NoBindF    body = body
-mkStgBind (RecF prs) body = StgLet (StgRec prs) 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) 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 body)
-       other       ->  mk_stg_let bndr rhs dem body
+                      (mk_stg_let bndr rhs dem floats body)
+       other       ->  mk_stg_let bndr rhs dem floats body
 
-mk_stg_let bndr rhs dem body
+mk_stg_let bndr rhs dem floats body
 #endif
-  | isUnLiftedType bndr_ty                             -- Use a case/PrimAlts
+  | isUnLiftedType bndr_ty                     -- Use a case/PrimAlts
   = ASSERT( not (isUnboxedTupleType bndr_ty) )
+    mkStgBinds floats $
     mkStgCase rhs bndr (StgPrimAlts bndr_ty [] (StgBindDefault body))
 
-  | isStrictDem dem && not_whnf                                -- Use an case/AlgAlts
-  = mkStgCase rhs bndr (StgAlgAlts bndr_ty [] (StgBindDefault body))
-
-  | otherwise
-  = ASSERT( not (isUnLiftedType bndr_ty) )
-    StgLet (StgNonRec bndr expr_rhs) body
+  | is_whnf
+  = if is_strict then
+       -- Strict let with WHNF rhs
+       mkStgBinds floats $
+       StgLet (StgNonRec bndr (exprToRhs dem NotTopLevel 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 NotTopLevel 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 NotTopLevel new_rhs)) body)
+       
   where
-    bndr_ty = idType bndr
-    expr_rhs = exprToRhs dem rhs
-    not_whnf = case expr_rhs of
-               StgRhsClosure _ _ _ _ _ args _ -> null args
-               StgRhsCon _ _ _                -> False
-
-mkStgCase (StgLet bind expr) bndr alts
-  = StgLet bind (mkStgCase expr bndr alts)
+    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 [] = ([], [])
+
+
 mkStgCase scrut bndr alts
-  = StgCase scrut bOGUS_LVs bOGUS_LVs bndr noSRT 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}