[project @ 1997-09-04 20:01:34 by sof]
[ghc-hetmet.git] / ghc / compiler / simplCore / Simplify.lhs
index 46cd242..242bd4b 100644 (file)
@@ -1,5 +1,5 @@
 %
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1996
 %
 \section[Simplify]{The main module of the simplifier}
 
@@ -8,36 +8,52 @@
 
 module Simplify ( simplTopBinds, simplExpr, simplBind ) where
 
-import Pretty          -- these are for debugging only
-import Outputable
+IMPORT_1_3(List(partition))
+
+IMP_Ubiq(){-uitous-}
+#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ <= 201
+IMPORT_DELOOPER(SmplLoop)              -- paranoia checking
+#endif
 
-import SimplMonad
-import SimplEnv
-import TaggedCore
-import PlainCore
-
-import AbsPrel         ( getPrimOpResultInfo, PrimOpResultInfo(..),
-                         primOpOkForSpeculation, PrimOp(..), PrimKind,
-                         realWorldStateTy
-                         IF_ATTACK_PRAGMAS(COMMA realWorldTy)
-                         IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
-                         IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
-                       )
-import AbsUniType      ( getUniDataTyCon_maybe, mkTyVarTy, applyTy,
-                         splitTyArgs, splitTypeWithDictsAsArgs,
-                         maybeUnpackFunTy, isPrimType
-                       )
-import BasicLit                ( isNoRepLit, BasicLit(..) )
 import BinderInfo
 import CmdLineOpts     ( SimplifierSwitch(..) )
 import ConFold         ( completePrim )
-import Id
-import IdInfo
-import Maybes          ( Maybe(..), catMaybes, maybeToBool )
-import SimplCase
-import SimplUtils
+import CoreUnfold      ( Unfolding, SimpleUnfolding, mkFormSummary, exprIsTrivial, whnfOrBottom, FormSummary(..) )
+import CostCentre      ( isSccCountCostCentre, cmpCostCentre, costsAreSubsumed, useCurrentCostCentre )
+import CoreSyn
+import CoreUtils       ( coreExprType, nonErrorRHSs, maybeErrorApp,
+                         unTagBinders, squashableDictishCcExpr
+                       )
+import Id              ( idType, idMustBeINLINEd, idWantsToBeINLINEd, idMustNotBeINLINEd, 
+                         addIdArity, getIdArity,
+                         getIdDemandInfo, addIdDemandInfo,
+                         GenId{-instance NamedThing-}
+                       )
+import Name            ( isExported )
+import IdInfo          ( willBeDemanded, noDemandInfo, DemandInfo, ArityInfo(..),
+                         atLeastArity, unknownArity )
+import Literal         ( isNoRepLit )
+import Maybes          ( maybeToBool )
+import PprType         ( GenType{-instance Outputable-}, GenTyVar{- instance Outputable -} )
+#if __GLASGOW_HASKELL__ <= 30
+import PprCore         ( GenCoreArg, GenCoreExpr )
+#endif
+import TyVar           ( GenTyVar {- instance Eq -} )
+import Pretty          --( ($$) )
+import PrimOp          ( primOpOkForSpeculation, PrimOp(..) )
+import SimplCase       ( simplCase, bindLargeRhs )
+import SimplEnv
+import SimplMonad
 import SimplVar                ( completeVar )
-import Util
+import Unique          ( Unique )
+import SimplUtils
+import Type            ( mkTyVarTy, mkTyVarTys, mkAppTy, applyTy, mkFunTys, maybeAppDataTyCon,
+                         splitFunTy, splitFunTyExpandingDicts, getFunTy_maybe, eqTy
+                       )
+import TysWiredIn      ( realWorldStateTy )
+import Outputable      ( PprStyle(..), Outputable(..) )
+import Util            ( SYN_IE(Eager), appEager, returnEager, runEager, mapEager,
+                         isSingleton, zipEqual, zipWithEqual, mapAndUnzip, panic, pprPanic, assertPanic, pprTrace )
 \end{code}
 
 The controlling flags, and what they do
@@ -48,7 +64,7 @@ passes:
 -fsimplify             = run the simplifier
 -ffloat-inwards                = runs the float lets inwards pass
 -ffloat                        = runs the full laziness pass
-                          (ToDo: rename to -ffull-laziness)
+                         (ToDo: rename to -ffull-laziness)
 -fupdate-analysis      = runs update analyser
 -fstrictness           = runs strictness analyser
 -fsaturate-apps                = saturates applications (eta expansion)
@@ -56,20 +72,20 @@ passes:
 options:
 -------
 -ffloat-past-lambda    = OK to do full laziness.
-                          (ToDo: remove, as the full laziness pass is
-                                 useless without this flag, therefore
-                                 it is unnecessary. Just -ffull-laziness
-                                 should be kept.)
+                         (ToDo: remove, as the full laziness pass is
+                                useless without this flag, therefore
+                                it is unnecessary. Just -ffull-laziness
+                                should be kept.)
 
 -ffloat-lets-ok                = OK to float lets out of lets if the enclosing
-                          let is strict or if the floating will expose
-                          a WHNF [simplifier].
+                         let is strict or if the floating will expose
+                         a WHNF [simplifier].
 
--ffloat-primops-ok     = OK to float out of lets cases whose scrutinee 
-                          is a primop that cannot fail [simplifier].
+-ffloat-primops-ok     = OK to float out of lets cases whose scrutinee
+                         is a primop that cannot fail [simplifier].
 
 -fcode-duplication-ok  = allows the previous option to work on cases with
-                          multiple branches [simplifier].
+                         multiple branches [simplifier].
 
 -flet-to-case          = does let-to-case transformation [simplifier].
 
@@ -102,9 +118,9 @@ binding altogether.
 
 2.  Conditional.  In all other situations, the simplifer simplifies
 the RHS anyway, and keeps the new binding.  It also binds the new
-(cloned) variable to a ``suitable'' UnfoldingDetails in the UnfoldEnv.
+(cloned) variable to a ``suitable'' Unfolding in the UnfoldEnv.
 
-Here, ``suitable'' might mean NoUnfoldingDetails (if the occurrence
+Here, ``suitable'' might mean NoUnfolding (if the occurrence
 info is ManyOcc and the RHS is not a manifest HNF, or UnfoldAlways (if
 the variable has an INLINE pragma on it).  The idea is that anything
 in the UnfoldEnv is safe to use, but also has an enclosing binding if
@@ -113,7 +129,7 @@ you decide not to use it.
 Head normal forms
 ~~~~~~~~~~~~~~~~~
 We *never* put a non-HNF unfolding in the UnfoldEnv except in the
-INLINE-pragma case.  
+INLINE-pragma case.
 
 At one time I thought it would be OK to put non-HNF unfoldings in for
 variables which occur only once [if they got inlined at that
@@ -124,12 +140,12 @@ would occur].   But consider:
            f = \y -> ...y...y...y...
        in f x
 @
-Now, it seems that @x@ appears only once, but even so it is NOT safe to put @x@
-in the UnfoldEnv, because @f@ will be inlined, and will duplicate the references to
-@x@.  
+Now, it seems that @x@ appears only once, but even so it is NOT safe
+to put @x@ in the UnfoldEnv, because @f@ will be inlined, and will
+duplicate the references to @x@.
 
-Becuase of this, the "unconditional-inline" mechanism above is the only way
-in which non-HNFs can get inlined.
+Because of this, the "unconditional-inline" mechanism above is the
+only way in which non-HNFs can get inlined.
 
 INLINE pragmas
 ~~~~~~~~~~~~~~
@@ -151,7 +167,7 @@ because then we'd duplicate BIG when we inline'd y.  (Exception:
 things in the UnfoldEnv with UnfoldAlways flags, which originated in
 other INLINE pragmas.)
 
-So, we clean out the UnfoldEnv of all GeneralForm inlinings before
+So, we clean out the UnfoldEnv of all SimpleUnfolding inlinings before
 going into such an RHS.
 
 What about imports?  They don't really matter much because we only
@@ -173,65 +189,51 @@ mutually-recursive worker/wrapper split.
 At the top level things are a little different.
 
   * No cloning (not allowed for exported Ids, unnecessary for the others)
-
-  * No floating.   Case floating is obviously out.  Let floating is
-       theoretically OK, but dangerous because of space leaks.
-       The long-distance let-floater lifts these lets.
+  * Floating is done a bit differently (no case floating; check for leaks; handle letrec)
 
 \begin{code}
 simplTopBinds :: SimplEnv -> [InBinding] -> SmplM [OutBinding]
 
-simplTopBinds env [] = returnSmpl []
-
 -- Dead code is now discarded by the occurrence analyser,
 
-simplTopBinds env (CoNonRec binder@(in_id, occ_info) rhs : binds)
-  | inlineUnconditionally ok_to_dup_code occ_info
-  = --pprTrace "simplTopBinds (inline):" (ppr PprDebug in_id) (
-    let
-       new_env = extendIdEnvWithInlining env env binder rhs
-    in
-    simplTopBinds new_env binds
-    --)
-  where
-    ok_to_dup_code = switchIsSet env SimplOkToDupCode
-
-simplTopBinds env (CoNonRec binder@(in_id,occ_info) rhs : binds)
-  =    -- No cloning necessary at top level
-       -- Process the binding
-    simplRhsExpr env binder rhs                `thenSmpl` \ rhs' ->
-    let
-       new_env = case rhs' of
-        CoVar var                        -> extendIdEnvWithAtom env binder (CoVarAtom var)
-         CoLit lit | not (isNoRepLit lit) -> extendIdEnvWithAtom env binder (CoLitAtom lit)
-         other                           -> extendUnfoldEnvGivenRhs env binder in_id rhs'
-    in
-    --pprTrace "simplTopBinds (nonrec):" (ppCat [ppr PprDebug in_id, ppr PprDebug rhs']) (
-
-       -- Process the other bindings
-    simplTopBinds new_env binds        `thenSmpl` \ binds' ->
-
-       -- Glue together and return ...
-       -- We leave it to susequent occurrence analysis to throw away 
-       -- an unused atom binding. This localises the decision about
-       -- discarding top-level bindings.
-    returnSmpl (CoNonRec in_id rhs' : binds')
-    --)
-
-simplTopBinds env (CoRec pairs : binds)
-  = simplRecursiveGroup env triples    `thenSmpl` \ (bind', new_env) ->
-
-    --pprTrace "simplTopBinds (rec):" (ppCat [ppr PprDebug bind']) (
-
-       -- Process the other bindings
-    simplTopBinds new_env binds                `thenSmpl` \ binds' ->
-
-       -- Glue together and return
-    returnSmpl (bind' : binds')
-    --)
+simplTopBinds env binds
+  = mapSmpl (floatBind env True) binds `thenSmpl` \ binds_s ->
+    simpl_top_binds env (concat binds_s)
   where
-    triples = [(id, (binder, rhs)) | (binder@(id,_), rhs) <- pairs]
-               -- No cloning necessary at top level
+    simpl_top_binds env [] = returnSmpl []
+
+    simpl_top_binds env (NonRec binder@(in_id,occ_info) rhs : binds)
+      =                --- No cloning necessary at top level
+        simplRhsExpr env binder rhs in_id                              `thenSmpl` \ (rhs',arity) ->
+        completeNonRec env binder (in_id `withArity` arity) rhs'       `thenSmpl` \ (new_env, binds1') ->
+        simpl_top_binds new_env binds                                  `thenSmpl` \ binds2' ->
+        returnSmpl (binds1' ++ binds2')
+
+    simpl_top_binds env (Rec pairs : binds)
+      =                -- No cloning necessary at top level, but we nevertheless
+               -- add the Ids to the environment.  This makes sure that
+               -- info carried on the Id (such as arity info) gets propagated
+               -- to occurrences.
+               --
+               -- This may seem optional, but I found an occasion when it Really matters.
+               -- Consider     foo{n} = ...foo...
+               --              baz* = foo
+               --
+               -- where baz* is exported and foo isn't.  Then when we do "indirection-shorting"
+               -- in tidyCore, we need the {no-inline} pragma from foo to attached to the final
+               -- thing:       baz*{n} = ...baz...
+               --
+               -- Sure we could have made the indirection-shorting a bit cleverer, but
+               -- propagating pragma info is a Good Idea anyway.
+       let
+           env1 = extendIdEnvWithClones env binders ids
+       in
+        simplRecursiveGroup env1 ids pairs     `thenSmpl` \ (bind', new_env) ->
+        simpl_top_binds new_env binds          `thenSmpl` \ binds' ->
+        returnSmpl (Rec bind' : binds')
+      where
+       binders = map fst pairs
+        ids     = map fst binders
 \end{code}
 
 %************************************************************************
@@ -240,11 +242,12 @@ simplTopBinds env (CoRec pairs : binds)
 %*                                                                     *
 %************************************************************************
 
-       
-\begin{code} 
+
+\begin{code}
 simplExpr :: SimplEnv
          -> InExpr -> [OutArg]
-         -> SmplM OutExpr 
+         -> OutType            -- Type of (e args); i.e. type of overall result
+         -> SmplM OutExpr
 \end{code}
 
 The expression returned has the same meaning as the input expression
@@ -253,268 +256,223 @@ applied to the specified arguments.
 
 Variables
 ~~~~~~~~~
-Check if there's a macro-expansion, and if so rattle on.  Otherwise
-do the more sophisticated stuff.
+Check if there's a macro-expansion, and if so rattle on.  Otherwise do
+the more sophisticated stuff.
 
 \begin{code}
-simplExpr env (CoVar v) args
-  = --pprTrace "simplExpr:Var:" (ppr PprDebug v) (
-    case lookupId env v of
-      Nothing -> let
-                       new_v = simplTyInId env v
-                in
-                completeVar env new_v args
-
-      Just info ->
-       case info of
-         ItsAnAtom (CoLitAtom lit)     -- A boring old literal
-                       -- Paranoia check for args empty
-           ->  case args of
-                 []    -> returnSmpl (CoLit lit)
-                 other -> panic "simplExpr:coVar"
-
-         ItsAnAtom (CoVarAtom var)     -- More interesting!  An id!
-                                       -- No need to substitute the type env here,
-                                       -- because we already have!
-           -> completeVar env var args 
-               
-         InlineIt id_env ty_env in_expr        -- A macro-expansion
-           -> simplExpr (replaceInEnvs env (ty_env, id_env)) in_expr args
-    --)
+simplExpr env (Var v) args result_ty
+  = case (runEager $ lookupId env v) of
+      LitArg lit               -- A boring old literal
+       -> ASSERT( null args )
+          returnSmpl (Lit lit)
+
+      VarArg var       -- More interesting!  An id!
+       -> completeVar env var args result_ty
+                               -- Either Id is in the local envt, or it's a global.
+                               -- In either case we don't need to apply the type
+                               -- environment to it.
 \end{code}
 
 Literals
-~~~~~~~~~
+~~~~~~~~
 
 \begin{code}
-simplExpr env (CoLit l) [] = returnSmpl (CoLit l)
-simplExpr env (CoLit l) _  = panic "simplExpr:CoLit with argument"
+simplExpr env (Lit l) [] result_ty = returnSmpl (Lit l)
+#ifdef DEBUG
+simplExpr env (Lit l) _  _ = panic "simplExpr:Lit with argument"
+#endif
 \end{code}
 
-Primitive applications are simple.  
+Primitive applications are simple.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-NB: CoPrim expects an empty argument list! (Because it should be
+NB: Prim expects an empty argument list! (Because it should be
 saturated and not higher-order. ADR)
 
-\begin{code} 
-simplExpr env (CoPrim op tys prim_args) args
+\begin{code}
+simplExpr env (Prim op prim_args) args result_ty
   = ASSERT (null args)
-    let
-       tys'       = [simplTy   env ty       | ty       <- tys]
-       prim_args' = [simplAtom env prim_arg | prim_arg <- prim_args]
-       op'        = simpl_op op
-    in
-    completePrim env op' tys' prim_args'
+    mapEager (simplArg env) prim_args  `appEager` \ prim_args' ->
+    simpl_op op                                `appEager` \ op' ->
+    completePrim env op' prim_args'
   where
     -- PrimOps just need any types in them renamed.
 
-    simpl_op (CCallOp label is_asm may_gc arg_tys result_ty) 
-      = let
-           arg_tys'    = map (simplTy env) arg_tys
-           result_ty'  = simplTy env result_ty
-       in
-       CCallOp label is_asm may_gc arg_tys' result_ty'
+    simpl_op (CCallOp label is_asm may_gc arg_tys result_ty)
+      = mapEager (simplTy env) arg_tys `appEager` \ arg_tys' ->
+       simplTy env result_ty           `appEager` \ result_ty' ->
+       returnEager (CCallOp label is_asm may_gc arg_tys' result_ty')
 
-    simpl_op other_op = other_op
+    simpl_op other_op = returnEager other_op
 \end{code}
 
-Constructor applications 
-~~~~~~~~~~~~~~~~~~~~~~~~ 
+Constructor applications
+~~~~~~~~~~~~~~~~~~~~~~~~
 Nothing to try here.  We only reuse constructors when they appear as the
 rhs of a let binding (see completeLetBinding).
 
 \begin{code}
-simplExpr env (CoCon con tys con_args) args
+simplExpr env (Con con con_args) args result_ty
   = ASSERT( null args )
-    returnSmpl (CoCon con tys' con_args')
-  where
-    con_args' = [simplAtom env con_arg | con_arg <- con_args]
-    tys'      = [simplTy   env ty      | ty <- tys]
+    mapEager (simplArg env) con_args   `appEager` \ con_args' ->
+    returnSmpl (Con con con_args')
 \end{code}
 
 
-Applications are easy too: 
-~~~~~~~~~~~~~~~~~~~~~~~~~~ 
+Applications are easy too:
+~~~~~~~~~~~~~~~~~~~~~~~~~~
 Just stuff 'em in the arg stack
 
-\begin{code} 
-simplExpr env (CoApp fun arg) args
-  = simplExpr env fun (ValArg (simplAtom env arg) : args)
-
-simplExpr env (CoTyApp fun ty) args
-  = simplExpr env fun (TypeArg (simplTy env ty) : args)
+\begin{code}
+simplExpr env (App fun arg) args result_ty
+  = simplArg env arg   `appEager` \ arg' ->
+    simplExpr env fun (arg' : args) result_ty
 \end{code}
 
 Type lambdas
 ~~~~~~~~~~~~
 
-We only eta-reduce a type lambda if all type arguments in the body can
-be eta-reduced. This requires us to collect up all tyvar parameters so
-we can pass them all to @mkCoTyLamTryingEta@.
+First the case when it's applied to an argument.
 
-\begin{code} 
-simplExpr env (CoTyLam tyvar body) (TypeArg ty : args)
+\begin{code}
+simplExpr env (Lam (TyBinder tyvar) body) (TyArg ty : args) result_ty
   = -- ASSERT(not (isPrimType ty))
+    tick TyBetaReduction       `thenSmpl_`
+    simplExpr (extendTyEnv env tyvar ty) body args result_ty
+\end{code}
+
+\begin{code}
+simplExpr env tylam@(Lam (TyBinder tyvar) body) [] result_ty
+  = cloneTyVarSmpl tyvar               `thenSmpl` \ tyvar' ->
     let
-       new_env = extendTyEnv env tyvar ty
+       new_ty  = mkTyVarTy tyvar'
+       new_env = extendTyEnv env tyvar new_ty
+       new_result_ty = applyTy result_ty new_ty
     in
-    tick TyBetaReduction       `thenSmpl_`
-    simplExpr new_env body args
+    simplExpr new_env body [] new_result_ty            `thenSmpl` \ body' ->
+    returnSmpl (Lam (TyBinder tyvar') body')
 
-simplExpr env tylam@(CoTyLam tyvar body) []
-  = do_tylambdas env [] tylam 
-  where
-    do_tylambdas env tyvars' (CoTyLam tyvar body)
-      =          -- Clone the type variable
-       cloneTyVarSmpl tyvar            `thenSmpl` \ tyvar' ->
-       let
-           new_env = extendTyEnv env tyvar (mkTyVarTy tyvar')
-       in
-       do_tylambdas new_env (tyvar':tyvars') body
-
-    do_tylambdas env tyvars' body
-      =        simplExpr env body []           `thenSmpl` \ body' ->
-       returnSmpl (
-          (if switchIsSet env SimplDoEtaReduction
-          then mkCoTyLamTryingEta
-          else mkCoTyLam) (reverse tyvars')  body'
-       )
-
-simplExpr env (CoTyLam tyvar body) (ValArg _ : _)
-  = panic "simplExpr:CoTyLam ValArg" 
+#ifdef DEBUG
+simplExpr env (Lam (TyBinder _) _) (_ : _) result_ty
+  = panic "simplExpr:TyLam with non-TyArg"
+#endif
 \end{code}
 
 
 Ordinary lambdas
 ~~~~~~~~~~~~~~~~
 
-\begin{code}
-simplExpr env (CoLam binders body) args
-  | null leftover_binders
-  =    -- The lambda is saturated (or over-saturated)
-    tick BetaReduction `thenSmpl_`
-    simplExpr env_for_enough_args body leftover_args
+There's a complication with lambdas that aren't saturated.
+Suppose we have:
 
-  | otherwise
-  =    -- Too few args to saturate the lambda
-    ASSERT( null leftover_args )
-
-    (if not (null args) -- ah, we must've gotten rid of some...
-     then tick BetaReduction
-     else returnSmpl (panic "BetaReduction")
-    ) `thenSmpl_`
+       (\x. \y. ...x...)
 
-    simplLam env_for_too_few_args leftover_binders body 
-            0 {- Guaranteed applied to at least 0 args! -}
+If we did nothing, x is used inside the \y, so would be marked
+as dangerous to dup.  But in the common case where the abstraction
+is applied to two arguments this is over-pessimistic.
+So instead we don't take account of the \y when dealing with x's usage;
+instead, the simplifier is careful when partially applying lambdas.
 
+\begin{code}
+simplExpr env expr@(Lam (ValBinder binder) body) orig_args result_ty
+  = go 0 env expr orig_args
   where
-    (binder_args_pairs, leftover_binders, leftover_args) = collect_val_args binders args
-
-    env_for_enough_args  = extendIdEnvWithAtomList env binder_args_pairs
-
-    env_for_too_few_args = extendIdEnvWithAtomList env zapped_binder_args_pairs
-
-       -- Since there aren't enough args the binders we are cancelling with
-       -- the args supplied are, in effect, ocurring inside a lambda.
-       -- So we modify their occurrence info to reflect this fact.
-       -- Example:     (\ x y z -> e) p q
-       --          ==> (\z -> e[p/x, q/y])
-       --      but we should behave as if x and y are marked "inside lambda".
-       -- The occurrence analyser does not mark them so itself because then we
-       -- do badly on the very common case of saturated lambdas applications:
-       --              (\ x y z -> e) p q r
-       --          ==> e[p/x, q/y, r/z]
-       --
-    zapped_binder_args_pairs = [ ((id, markDangerousToDup occ_info), arg) 
-                              | ((id, occ_info), arg) <- binder_args_pairs ]
-
-    collect_val_args :: [InBinder]     -- Binders
-                    -> [OutArg]        -- Arguments
-                    -> ([(InBinder,OutAtom)],  -- Binder,arg pairs
-                         [InBinder],           -- Leftover binders
-                         [OutArg])             -- Leftover args
-       
-       -- collect_val_args strips off the leading ValArgs from
-       -- the current arg list, returning them along with the
-       -- depleted list
-    collect_val_args []      args = ([], [], args)
-    collect_val_args binders []   = ([], binders, [])
-    collect_val_args (binder:binders) (ValArg val_arg : args)
-       = ((binder,val_arg):rest_pairs, leftover_binders, leftover_args)
-       where
-         (rest_pairs, leftover_binders, leftover_args) = collect_val_args binders args
-
-    collect_val_args (binder:binders) (other_val_arg : args) = panic "collect_val_args"
-               -- TypeArg should never meet a CoLam
+    go n env (Lam (ValBinder binder) body) (val_arg : args)
+      | isValArg val_arg               -- The lambda has an argument
+      = tick BetaReduction     `thenSmpl_`
+        go (n+1) (extendIdEnvWithAtom env binder val_arg) body args
+
+    go n env expr@(Lam (ValBinder binder) body) args
+       -- The lambda is un-saturated, so we must zap the occurrence info
+       -- on the arguments we've already beta-reduced into the body of the lambda
+      = ASSERT( null args )    -- Value lambda must match value argument!
+        let
+           new_env = markDangerousOccs env (take n orig_args)
+        in
+        simplValLam new_env expr 0 {- Guaranteed applied to at least 0 args! -} result_ty 
+                               `thenSmpl` \ (expr', arity) ->
+       returnSmpl expr'
+
+    go n env non_val_lam_expr args             -- The lambda had enough arguments
+      = simplExpr env non_val_lam_expr args result_ty
 \end{code}
 
 
-Let expressions 
+Let expressions
 ~~~~~~~~~~~~~~~
 
-\begin{code}   
-simplExpr env (CoLet bind body) args
-  | not (switchIsSet env SimplNoLetFromApp)            -- The common case
-  = simplBind env bind (\env -> simplExpr env body args) 
-                      (computeResultType env body args)
-
-  | otherwise          -- No float from application
-  = simplBind env bind (\env -> simplExpr env body []) 
-                      (computeResultType env body [])  `thenSmpl` \ let_expr' ->
-    returnSmpl (applyToArgs let_expr' args)
+\begin{code}
+simplExpr env (Let bind body) args result_ty
+  = simplBind env bind (\env -> simplExpr env body args result_ty) result_ty
 \end{code}
 
-Case expressions 
+Case expressions
 ~~~~~~~~~~~~~~~~
 
 \begin{code}
-simplExpr env expr@(CoCase scrut alts) args
-  = simplCase env scrut alts (\env rhs -> simplExpr env rhs args)
-                            (computeResultType env expr args)
+simplExpr env expr@(Case scrut alts) args result_ty
+  = simplCase env scrut alts (\env rhs -> simplExpr env rhs args result_ty) result_ty
 \end{code}
 
 
-Set-cost-centre 
+Coercions
+~~~~~~~~~
+\begin{code}
+simplExpr env (Coerce coercion ty body) args result_ty
+  = simplCoerce env coercion ty body args result_ty
+\end{code}
+
+
+Set-cost-centre
 ~~~~~~~~~~~~~~~
 
-A special case we do:
-\begin{verbatim}
-       scc "foo" (\x -> e)  ===>   \x -> scc "foo" e
-\end{verbatim}
-Simon thinks it's OK, at least for lexical scoping; and it makes
-interfaces change less (arities).
+1) Eliminating nested sccs ...
+We must be careful to maintain the scc counts ...
 
 \begin{code}
-simplExpr env (CoSCC cc (CoLam binders body)) args
-  = simplExpr env (CoLam binders (CoSCC cc body)) args
-
-simplExpr env (CoSCC cc (CoTyLam tyvar body)) args
-  = simplExpr env (CoTyLam tyvar (CoSCC cc body)) args
+simplExpr env (SCC cc1 (SCC cc2 expr)) args result_ty
+  | not (isSccCountCostCentre cc2) && case cmpCostCentre cc1 cc2 of { EQ_ -> True; _ -> False }
+       -- eliminate inner scc if no call counts and same cc as outer
+  = simplExpr env (SCC cc1 expr) args result_ty
+
+  | not (isSccCountCostCentre cc2) && not (isSccCountCostCentre cc1)
+       -- eliminate outer scc if no call counts associated with either ccs
+  = simplExpr env (SCC cc2 expr) args result_ty
 \end{code}
 
-Some other slightly turgid SCC tidying-up cases:
+2) Moving sccs inside lambdas ...
+  
 \begin{code}
-simplExpr env (CoSCC cc1 expr@(CoSCC _ _)) args
-  = simplExpr env expr args
-    -- the outer _scc_ serves no purpose 
+simplExpr env (SCC cc (Lam binder@(ValBinder _) body)) args result_ty
+  | not (isSccCountCostCentre cc)
+       -- move scc inside lambda only if no call counts
+  = simplExpr env (Lam binder (SCC cc body)) args result_ty
+
+simplExpr env (SCC cc (Lam binder body)) args result_ty
+       -- always ok to move scc inside type/usage lambda
+  = simplExpr env (Lam binder (SCC cc body)) args result_ty
+\end{code}
 
-simplExpr env (CoSCC cc expr) args
+3) Eliminating dict sccs ...
+
+\begin{code}
+simplExpr env (SCC cc expr) args result_ty
   | squashableDictishCcExpr cc expr
-  = simplExpr env expr args
-    -- the DICT-ish CC is no longer serving any purpose
+       -- eliminate dict cc if trivial dict expression
+  = simplExpr env expr args result_ty
 \end{code}
 
-NB: for other set-cost-centre we move arguments inside the body.
-ToDo: check with Patrick that this is ok.
+4) Moving arguments inside the body of an scc ...
+This moves the cost of doing the application inside the scc
+(which may include the cost of extracting methods etc)
 
 \begin{code}
-simplExpr env (CoSCC cost_centre body) args
+simplExpr env (SCC cost_centre body) args result_ty
   = let
-       new_env = setEnclosingCC env (EnclosingCC cost_centre)
+       new_env = setEnclosingCC env cost_centre
     in
-    simplExpr new_env body args                `thenSmpl` \ body' ->
-    returnSmpl (CoSCC cost_centre body') 
+    simplExpr new_env body args result_ty              `thenSmpl` \ body' ->
+    returnSmpl (SCC cost_centre body')
 \end{code}
 
 %************************************************************************
@@ -536,69 +494,108 @@ it transforms the rhs to
 This is a Very Good Thing!
 
 \begin{code}
-simplRhsExpr 
+simplRhsExpr
        :: SimplEnv
        -> InBinder
        -> InExpr
-       -> SmplM OutExpr 
+       -> OutId                -- The new binder (used only for its type)
+       -> SmplM (OutExpr, ArityInfo)
+\end{code}
 
-simplRhsExpr env binder@(id,occ_info) rhs 
-  | dont_eta_expand rhs
-  = simplExpr rhs_env rhs []
+First a special case for variable right-hand sides
+       v = w
+It's OK to simplify the RHS, but it's often a waste of time.  Often
+these v = w things persist because v is exported, and w is used 
+elsewhere.  So if we're not careful we'll eta expand the rhs, only
+to eta reduce it in competeNonRec.
+
+If we leave the binding unchanged, we will certainly replace v by w at 
+every occurrence of v, which is good enough.  
+
+In fact, it's *better* to replace v by w than to inline w in v's rhs,
+even if this is the only occurrence of w.  Why? Because w might have
+IdInfo (like strictness) that v doesn't.
+Furthermore, there might be other uses of w; if so, inlining w in 
+v's rhs will duplicate w's rhs, whereas replacing v by w doesn't.
+
+HOWEVER, we have to be careful if w is something that *must* be
+inlined.  In particular, its binding may have been dropped.  Here's
+an example that actually happened:
+       let x = let y = e in y
+     in f x
+The "let y" was floated out, and then (since y occurs once in a
+definitely inlinable position) the binding was dropped, leaving
+       {y=e} let x = y in f x
+But now using the reasoning of this little section, 
+y wasn't inlined, because it was a let x=y form.
 
-  | otherwise  -- Have a go at eta expansion
+\begin{code}
+simplRhsExpr env binder@(id,occ_info) (Var v) new_id
+ | maybeToBool maybe_stop_at_var
+ = returnSmpl (Var the_var, getIdArity the_var)
+ where
+   maybe_stop_at_var 
+     = case (runEager $ lookupId env v) of
+        VarArg v' | not (must_unfold v') -> Just v'
+        other                            -> Nothing
+
+   Just the_var = maybe_stop_at_var
+
+   must_unfold v' =  idMustBeINLINEd v'
+                 || case lookupOutIdEnv env v' of
+                       Just (_, _, InUnfolding _ _) -> True
+                       other                        -> False
+\end{code}
+
+\begin{code}
+simplRhsExpr env binder@(id,occ_info) rhs new_id
+  | maybeToBool (maybeAppDataTyCon rhs_ty)
+       -- Deal with the data type case, in which case the elaborate
+       -- eta-expansion nonsense is really quite a waste of time.
+  = simplExpr rhs_env rhs [] rhs_ty            `thenSmpl` \ rhs' ->
+    returnSmpl (rhs', ArityExactly 0)
+
+  | otherwise  -- OK, use the big hammer
   =    -- Deal with the big lambda part
+    ASSERT( null uvars )       -- For now
+
     mapSmpl cloneTyVarSmpl tyvars                      `thenSmpl` \ tyvars' ->
     let
-       lam_env  = extendTyEnvList rhs_env (tyvars `zip` (map mkTyVarTy tyvars'))
+       new_tys  = mkTyVarTys tyvars'
+       body_ty  = foldl applyTy rhs_ty new_tys
+       lam_env  = extendTyEnvList rhs_env (zipEqual "simplRhsExpr" tyvars new_tys)
     in
        -- Deal with the little lambda part
-       -- Note that we call simplLam even if there are no binders, in case
-       -- it can do arity expansion.
-    simplLam lam_env binders body min_no_of_args       `thenSmpl` \ lambda' ->
+       -- Note that we call simplLam even if there are no binders,
+       -- in case it can do arity expansion.
+    simplValLam lam_env body (getBinderInfoArity occ_info) body_ty     `thenSmpl` \ (lambda', arity) ->
 
-       -- Put it back together
-    returnSmpl (
-       (if switchIsSet env SimplDoEtaReduction
-       then mkCoTyLamTryingEta
-       else mkCoTyLam) tyvars' lambda'
-    )
+       -- Put on the big lambdas, trying to float out any bindings caught inside
+    mkRhsTyLam tyvars' lambda'                                 `thenSmpl` \ rhs' ->
+
+    returnSmpl (rhs', arity)
   where
-       -- Note from ANDY:
-       -- If you say {-# INLINE #-} then you get what's coming to you;
-       -- you are saying inline the rhs, please.
-       -- we might want a {-# INLINE UNSIMPLIFIED #-} option.
-    rhs_env | simplIdWantsToBeINLINEd id env = filterUnfoldEnvForInlines env
-           | otherwise                      = env
-       
-    (tyvars, binders, body) = digForLambdas rhs
-
-    min_no_of_args | not (null binders)                        &&      -- It's not a thunk
-                    switchIsSet env SimplDoArityExpand         -- Arity expansion on
-                  = getBinderInfoArity occ_info - length binders
-
-                  | otherwise  -- Not a thunk
-                  = 0          -- Play safe!
-
-       -- dont_eta_expand prevents eta expansion in silly situations.
-       -- For example, consider the defn
-       --      x = y
-       -- It would be silly to eta expand the "y", because it would just
-       -- get eta-reduced back to y.  Furthermore, if this was a top level defn,
-       -- and x was exported, then the defn won't be eliminated, so this
-       -- silly expand/reduce cycle will happen every time, which makes the
-       -- simplifier loop!. 
-       -- The solution is to not even try eta expansion unless the rhs looks
-       -- non-trivial.  
-    dont_eta_expand (CoLit _)     = True
-    dont_eta_expand (CoVar _)     = True
-    dont_eta_expand (CoTyApp f _) = dont_eta_expand f
-    dont_eta_expand (CoTyLam _ b) = dont_eta_expand b
-    dont_eta_expand (CoCon _ _ _) = True
-    dont_eta_expand _            = False
+    rhs_ty  = idType new_id
+    rhs_env | idWantsToBeINLINEd id    -- Don't ever inline in a INLINE thing's rhs
+           = switchOffInlining env1    -- See comments with switchOffInlining
+           | otherwise 
+            = env1
+
+       -- The top level "enclosing CC" is "SUBSUMED".  But the enclosing CC
+       -- for the rhs of top level defs is "OST_CENTRE".  Consider
+       --      f = \x -> e
+       --      g = \y -> let v = f y in scc "x" (v ...)
+       -- Here we want to inline "f", since its CC is SUBSUMED, but we don't
+       -- want to inline "v" since its CC is dynamically determined.
+
+    current_cc = getEnclosingCC env
+    env1 | costsAreSubsumed current_cc = setEnclosingCC env useCurrentCostCentre
+        | otherwise                   = env
+
+    (uvars, tyvars, body) = collectUsageAndTyBinders rhs
 \end{code}
 
-               
+
 %************************************************************************
 %*                                                                     *
 \subsection{Simplify a lambda abstraction}
@@ -609,69 +606,133 @@ Simplify (\binders -> body) trying eta expansion and reduction, given that
 the abstraction will always be applied to at least min_no_of_args.
 
 \begin{code}
-simplLam env binders body min_no_of_args
+simplValLam env expr min_no_of_args expr_ty
   | not (switchIsSet env SimplDoLambdaEtaExpansion) || -- Bale out if eta expansion off
+
+    exprIsTrivial expr                                     ||  -- or it's a trivial RHS
+       -- No eta expansion for trivial RHSs
+       -- It's rather a Bad Thing to expand
+       --      g = f alpha beta
+       -- to
+       --      g = \a b c -> f alpha beta a b c
+       --
+       -- The original RHS is "trivial" (exprIsTrivial), because it generates
+       -- no code (renames f to g).  But the new RHS isn't.
+
     null potential_extra_binder_tys                ||  -- or ain't a function
-    no_of_extra_binders == 0                           -- or no extra binders needed
+    no_of_extra_binders <= 0                           -- or no extra binders needed
   = cloneIds env binders               `thenSmpl` \ binders' ->
     let
        new_env = extendIdEnvWithClones env binders binders'
     in
-    simplExpr new_env body []          `thenSmpl` \ body' ->
-    returnSmpl (
-      (if switchIsSet new_env SimplDoEtaReduction
-       then mkCoLamTryingEta
-       else mkCoLam) binders' body'
-    )
+    simplExpr new_env body [] body_ty          `thenSmpl` \ body' ->
+    returnSmpl (mkValLam binders' body', final_arity)
 
   | otherwise                          -- Eta expansion possible
-  = tick EtaExpansion                  `thenSmpl_`
+  = -- A SSERT( no_of_extra_binders <= length potential_extra_binder_tys )
+    (if not ( no_of_extra_binders <= length potential_extra_binder_tys ) then
+       pprTrace "simplValLam" (vcat [ppr PprDebug expr, 
+                                         ppr PprDebug expr_ty,
+                                         ppr PprDebug binders,
+                                         int no_of_extra_binders,
+                                         ppr PprDebug potential_extra_binder_tys])
+    else \x -> x) $
+
+    tick EtaExpansion                  `thenSmpl_`
     cloneIds env binders               `thenSmpl` \ binders' ->
     let
        new_env = extendIdEnvWithClones env binders binders'
     in
     newIds extra_binder_tys                                            `thenSmpl` \ extra_binders' ->
-    simplExpr new_env body (map (ValArg.CoVarAtom) extra_binders')     `thenSmpl` \ body' ->
+    simplExpr new_env body (map VarArg extra_binders') etad_body_ty    `thenSmpl` \ body' ->
     returnSmpl (
-      (if switchIsSet new_env SimplDoEtaReduction
-       then mkCoLamTryingEta
-       else mkCoLam) (binders' ++ extra_binders') body'
+      mkValLam (binders' ++ extra_binders') body',
+      final_arity
     )
 
   where
-    (potential_extra_binder_tys, res_ty) 
-       = splitTyArgs (simplTy env (typeOfCoreExpr (unTagBinders body)))
-       -- Note: it's possible that simplLam will be applied to something
+    (binders,body)            = collectValBinders expr
+    no_of_binders             = length binders
+    (arg_tys, res_ty)         = splitFunTyExpandingDicts expr_ty
+    potential_extra_binder_tys = (if not (no_of_binders <= length arg_tys) then
+                                       pprTrace "simplValLam" (vcat [ppr PprDebug expr, 
+                                                                         ppr PprDebug expr_ty,
+                                                                         ppr PprDebug binders])
+                                 else \x->x) $
+                                drop no_of_binders arg_tys
+    body_ty                   = mkFunTys potential_extra_binder_tys res_ty
+
+       -- Note: it's possible that simplValLam will be applied to something
        -- with a forall type.  Eg when being applied to the rhs of
        --              let x = wurble
        -- where wurble has a forall-type, but no big lambdas at the top.
        -- We could be clever an insert new big lambdas, but we don't bother.
 
-    extra_binder_tys = take no_of_extra_binders potential_extra_binder_tys
+    etad_body_ty       = mkFunTys (drop no_of_extra_binders potential_extra_binder_tys) res_ty
+    extra_binder_tys    = take no_of_extra_binders potential_extra_binder_tys
+    final_arity                = atLeastArity (no_of_binders + no_of_extra_binders)
 
     no_of_extra_binders =      -- First, use the info about how many args it's
-                               -- always applied to in its scope
-                          min_no_of_args
+                               -- always applied to in its scope; but ignore this
+                               -- info for thunks. To see why we ignore it for thunks,
+                               -- consider     let f = lookup env key in (f 1, f 2)
+                               -- We'd better not eta expand f just because it is 
+                               -- always applied!
+                          (min_no_of_args - no_of_binders)
 
                                -- Next, try seeing if there's a lambda hidden inside
-                               -- something cheap
+                               -- something cheap.
+                               -- etaExpandCount can reuturn a huge number (like 10000!) if
+                               -- it finds that the body is a call to "error"; hence
+                               -- the use of "min" here.
                           `max`
-                          etaExpandCount body
+                          (etaExpandCount body `min` length potential_extra_binder_tys)
 
                                -- Finally, see if it's a state transformer, in which
                                -- case we eta-expand on principle! This can waste work,
                                -- but usually doesn't
                           `max`
                           case potential_extra_binder_tys of
-                               [ty] | ty == realWorldStateTy -> 1
-                               other                         -> 0
+                               [ty] | ty `eqTy` realWorldStateTy -> 1
+                               other                             -> 0
+\end{code}
+
+
+
+%************************************************************************
+%*                                                                     *
+\subsection[Simplify-coerce]{Coerce expressions}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+-- (coerce (case s of p -> r)) args ==> case s of p -> (coerce r) args
+simplCoerce env coercion ty expr@(Case scrut alts) args result_ty
+  = simplCase env scrut alts (\env rhs -> simplCoerce env coercion ty rhs args result_ty) result_ty
+
+-- (coerce (let defns in b)) args  ==> let defns' in (coerce b) args
+simplCoerce env coercion ty (Let bind body) args result_ty
+  = simplBind env bind (\env -> simplCoerce env coercion ty body args result_ty) result_ty
+
+-- Default case
+simplCoerce env coercion ty expr args result_ty
+  = simplTy env ty                     `appEager` \ ty' ->
+    simplTy env expr_ty                        `appEager` \ expr_ty' ->
+    simplExpr env expr [] expr_ty'     `thenSmpl` \ expr' ->
+    returnSmpl (mkGenApp (mkCoerce coercion ty' expr') args)
+  where
+    expr_ty = coreExprType (unTagBinders expr) -- Rather like simplCase other_scrut
 
+       -- Try cancellation; we do this "on the way up" because
+       -- I think that's where it'll bite best
+    mkCoerce (CoerceOut con1) ty1 (Coerce (CoerceIn  con2) ty2 body) | con1 == con2 = body
+    mkCoerce coercion ty  body = Coerce coercion ty body
 \end{code}
 
 
 %************************************************************************
 %*                                                                     *
-\subsection[Simplify-let]{Let-expressions}
+\subsection[Simplify-bind]{Binding groups}
 %*                                                                     *
 %************************************************************************
 
@@ -679,10 +740,37 @@ simplLam env binders body min_no_of_args
 simplBind :: SimplEnv
          -> InBinding
          -> (SimplEnv -> SmplM OutExpr)
-         -> OutUniType
+         -> OutType
          -> SmplM OutExpr
+
+simplBind env (NonRec binder rhs) body_c body_ty = simplNonRec env binder rhs body_c body_ty
+simplBind env (Rec pairs)         body_c body_ty = simplRec    env pairs      body_c body_ty
 \end{code}
 
+
+%************************************************************************
+%*                                                                     *
+\subsection[Simplify-let]{Let-expressions}
+%*                                                                     *
+%************************************************************************
+
+Float switches
+~~~~~~~~~~~~~~
+The booleans controlling floating have to be set with a little care.
+Here's one performance bug I found:
+
+       let x = let y = let z = case a# +# 1 of {b# -> E1}
+                       in E2
+               in E3
+       in E4
+
+Now, if E2, E3 aren't HNFs we won't float the y-binding or the z-binding.
+Before case_floating_ok included float_exposes_hnf, the case expression was floated
+*one level per simplifier iteration* outwards.  So it made th s
+
+
+Floating case from let
+~~~~~~~~~~~~~~~~~~~~~~
 When floating cases out of lets, remember this:
 
        let x* = case e of alts
@@ -710,11 +798,11 @@ becomes:
 
 ==>
       let join_body x' = foldr c n x'
-        in case y of
-        p1 -> let x* = build e1
-                in join_body x*
-        p2 -> let x* = build e2
-                in join_body x*
+       in case y of
+       p1 -> let x* = build e1
+               in join_body x*
+       p2 -> let x* = build e2
+               in join_body x*
 
 note that join_body is a let-no-escape.
 In this particular example join_body will later be inlined,
@@ -722,346 +810,189 @@ achieving the same effect.
 ToDo: check this is OK with andy
 
 
+Let to case: two points
+~~~~~~~~~~~
 
-\begin{code}
--- Dead code is now discarded by the occurrence analyser,
-
-simplBind env (CoNonRec binder@(id,occ_info) rhs) body_c body_ty
-  |  inlineUnconditionally ok_to_dup occ_info
-  = body_c (extendIdEnvWithInlining env env binder rhs)
-
--- Try let-to-case
--- It's important to try let-to-case before floating. Consider
---
---     let a*::Int = case v of {p1->e1; p2->e2}
---     in b
---
--- (The * means that a is sure to be demanded.)
--- If we do case-floating first we get this:
---
---     let k = \a* -> b
---     in case v of 
---             p1-> let a*=e1 in k a
---             p2-> let a*=e2 in k a
---
--- Now watch what happens if we do let-to-case first:
---
---     case (case v of {p1->e1; p2->e2}) of
---       Int a# -> let a*=I# a# in b
--- ===>
---     let k = \a# -> let a*=I# a# in b
---     in case v of
---             p1 -> case e1 of I# a# -> k a#
---             p1 -> case e1 of I# a# -> k a#
---
--- The latter is clearly better.  (Remember the reboxing let-decl
--- for a is likely to go away, because after all b is strict in a.)
-
-  | will_be_demanded && 
-    try_let_to_case &&
-    type_ok_for_let_to_case rhs_ty &&
-    not (manifestlyWHNF rhs)
-       -- note: no "manifestlyBottom rhs" in there... (comment below)
-    = tick Let2Case                            `thenSmpl_`
-      mkIdentityAlts rhs_ty                    `thenSmpl` \ id_alts ->
-      simplCase env rhs id_alts (\env rhs -> done_float env rhs body_c) body_ty
-       {-
-       We do not do let to case for WHNFs, e.g.
-
-         let x = a:b in ...
-         =/=>
-         case a:b of x in ...
-
-         as this is less efficient.
-         but we don't mind doing let-to-case for "bottom", as that
-         will
-         allow us to remove more dead code, if anything:
-         let x = error in ...
-         ===>
-         case error  of x -> ...
-         ===>
-         error
-
-         Notice that let to case occurs only if x is used strictly in
-         its body (obviously).
-       -}
-
-  | (will_be_demanded && not no_float) ||
-    always_float_let_from_let || 
-    floatExposesHNF float_lets float_primops ok_to_dup rhs
-  = try_float env rhs body_c
-
-  | otherwise
-  = done_float env rhs body_c
-
-  where
-    will_be_demanded = willBeDemanded (getIdDemandInfo id)
-    rhs_ty          = getIdUniType id
-
-    float_lets               = switchIsSet env SimplFloatLetsExposingWHNF
-    float_primops            = switchIsSet env SimplOkToFloatPrimOps
-    ok_to_dup                = switchIsSet env SimplOkToDupCode
-    always_float_let_from_let = switchIsSet env SimplAlwaysFloatLetsFromLets
-    try_let_to_case           = switchIsSet env SimplLetToCase
-    no_float                 = switchIsSet env SimplNoLetFromStrictLet
-
-    -------------------------------------------
-    done_float env rhs body_c
-       = simplRhsExpr env binder rhs   `thenSmpl` \ rhs' ->
-         completeLet env binder rhs rhs' body_c body_ty
-
-    ---------------------------------------
-    try_float env (CoLet bind rhs) body_c
-      = tick LetFloatFromLet                    `thenSmpl_`
-        simplBind env (fix_up_demandedness will_be_demanded bind) 
-                     (\env -> try_float env rhs body_c) body_ty
-
-    try_float env (CoCase scrut alts) body_c
-      | will_be_demanded || (float_primops && is_cheap_prim_app scrut)
-      = tick CaseFloatFromLet                          `thenSmpl_`
+Point 1.  We defer let-to-case for all data types except single-constructor
+ones.  Suppose we change
 
-       -- First, bind large let-body if necessary
-       if no_need_to_bind_large_body then
-           simplCase env scrut alts (\env rhs -> try_float env rhs body_c) body_ty
-       else            
-           bindLargeRhs env [binder] body_ty body_c    `thenSmpl` \ (extra_binding, new_body) ->
-           let
-               body_c' = \env -> simplExpr env new_body []
-           in
-           simplCase env scrut alts 
-                     (\env rhs -> try_float env rhs body_c')
-                     body_ty                           `thenSmpl` \ case_expr ->
+       let x* = e in b
+to
+       case e of x -> b
 
-           returnSmpl (CoLet extra_binding case_expr)
-      where
-       no_need_to_bind_large_body
-         = ok_to_dup || isSingleton (nonErrorRHSs alts)
+It can be the case that we find that b ultimately contains ...(case x of ..)....
+and this is the only occurrence of x.  Then if we've done let-to-case
+we can't inline x, which is a real pain.  On the other hand, we lose no
+transformations by not doing this transformation, because the relevant
+case-of-X transformations are also implemented by simpl_bind.
 
-    try_float env other_rhs body_c = done_float env other_rhs body_c
-\end{code}
+If x is a single-constructor type, then we go ahead anyway, giving
 
-Letrec expressions 
-~~~~~~~~~~~~~~~~~~
+       case e of (y,z) -> let x = (y,z) in b
 
-Simplify each RHS, float any let(recs) from the RHSs (if let-floating is
-on and it'll expose a HNF), and bang the whole resulting mess together
-into a huge letrec.
+because now we can squash case-on-x wherever they occur in b.
 
-1. Any "macros" should be expanded.  The main application of this
-macro-expansion is:
+We do let-to-case on multi-constructor types in the tidy-up phase
+(tidyCoreExpr) mainly so that the code generator doesn't need to
+spot the demand-flag.
 
-       letrec
-               f = ....g...
-               g = ....f...
-       in 
-       ....f...
 
-Here we would like the single call to g to be inlined.
+Point 2.  It's important to try let-to-case before doing the
+strict-let-of-case transformation, which happens in the next equation
+for simpl_bind.
 
-We can spot this easily, because g will be tagged as having just one
-occurrence.  The "inlineUnconditionally" predicate is just what we want.
+       let a*::Int = case v of {p1->e1; p2->e2}
+       in b
 
-A worry: could this lead to non-termination?  For example:
+(The * means that a is sure to be demanded.)
+If we do case-floating first we get this:
 
-       letrec
-               f = ...g...
-               g = ...f...
-               h = ...h...
-       in
-       ..h..
+       let k = \a* -> b
+       in case v of
+               p1-> let a*=e1 in k a
+               p2-> let a*=e2 in k a
 
-Here, f and g call each other (just once) and neither is used elsewhere.
-But it's OK:
+Now watch what happens if we do let-to-case first:
 
-* the occurrence analyser will drop any (sub)-group that isn't used at
-  all.
+       case (case v of {p1->e1; p2->e2}) of
+         Int a# -> let a*=I# a# in b
+===>
+       let k = \a# -> let a*=I# a# in b
+       in case v of
+               p1 -> case e1 of I# a# -> k a#
+               p1 -> case e2 of I# a# -> k a#
 
-* If the group is used outside itself (ie in the "in" part), then there
-  can't be a cyle.
+The latter is clearly better.  (Remember the reboxing let-decl for a
+is likely to go away, because after all b is strict in a.)
 
-** IMPORTANT: check that NewOccAnal has the property that a group of
-   bindings like the above has f&g dropped.! ***
+We do not do let to case for WHNFs, e.g.
 
+         let x = a:b in ...
+         =/=>
+         case a:b of x in ...
 
-2. We'd also like to pull out any top-level let(rec)s from the
-rhs of the defns:
-
-       letrec
-               f = let h = ... in \x -> ....h...f...h...
-       in
-       ...f...
-====>
-       letrec
-               h = ...
-               f = \x -> ....h...f...h...
-       in
-       ...f...
-
-But floating cases is less easy?  (Don't for now; ToDo?)
-
-
-3.  We'd like to arrange that the RHSs "know" about members of the
-group that are bound to constructors.  For example:
-
-    let rec
-       d.Eq      = (==,/=)
-       f a b c d = case d.Eq of (h,_) -> let x = (a,b); y = (c,d) in not (h x y)
-       /= a b    = unpack tuple a, unpack tuple b, call f
-    in d.Eq
-
-here, by knowing about d.Eq in f's rhs, one could get rid of 
-the case (and break out the recursion completely).
-[This occurred with more aggressive inlining threshold (4), 
-nofib/spectral/knights]
+as this is less efficient.  but we don't mind doing let-to-case for
+"bottom", as that will allow us to remove more dead code, if anything:
 
-How to do it?  
-       1: we simplify constructor rhss first.
-       2: we record the "known constructors" in the environment
-       3: we simplify the other rhss, with the knowledge about the constructors
+         let x = error in ...
+         ===>
+         case error  of x -> ...
+         ===>
+         error
 
+Notice that let to case occurs only if x is used strictly in its body
+(obviously).
 
 
 \begin{code}
-simplBind env (CoRec pairs) body_c body_ty
-  =    -- Do floating, if necessary
-    (if float_lets || always_float_let_from_let
-     then 
-       mapSmpl float pairs     `thenSmpl` \ floated_pairs_s ->
-       returnSmpl (concat floated_pairs_s)
-     else
-       returnSmpl pairs
-    )                                  `thenSmpl` \ floated_pairs ->
-    let
-       binders = map fst floated_pairs
-    in
-    cloneIds env binders               `thenSmpl` \ ids' ->
-    let
-       env_w_clones = extendIdEnvWithClones env binders ids'
-       triples      = ids' `zip` floated_pairs
-    in
-
-    simplRecursiveGroup env_w_clones triples   `thenSmpl` \ (binding, new_env) ->
-
-    body_c new_env                             `thenSmpl` \ body' ->
+-- Dead code is now discarded by the occurrence analyser,
 
-    returnSmpl (CoLet binding body')
+simplNonRec env binder@(id,occ_info) rhs body_c body_ty
+  | inlineUnconditionally ok_to_dup occ_info
+  =    -- The binder is used in definitely-inline way in the body
+       -- So add it to the environment, drop the binding, and continue
+    body_c (extendEnvGivenInlining env id occ_info rhs)
 
+  | idWantsToBeINLINEd id
+  = complete_bind env rhs      -- Don't mess about with floating or let-to-case on
+                               -- INLINE things
+  | otherwise
+  = simpl_bind env rhs
   where
-    ------------ Floating stuff -------------------
-
-    float_lets               = switchIsSet env SimplFloatLetsExposingWHNF
-    always_float_let_from_let = switchIsSet env SimplAlwaysFloatLetsFromLets
-
-    float (binder,rhs)
-      = let
-           pairs_s = float_pair (binder,rhs)
-       in
-       case pairs_s of
-         [_] -> returnSmpl pairs_s
-         more_than_one
-           -> tickN LetFloatFromLet (length pairs_s - 1) `thenSmpl_`
-               -- It's important to increment the tick counts if we
-               -- do any floating.  A situation where this turns out
-               -- to be important is this:
-               -- Float in produces:
-               --      letrec  x = let y = Ey in Ex
-               --      in B
-               -- Now floating gives this:
-               --      letrec x = Ex
-               --             y = Ey
-               --      in B
-               --- We now want to iterate once more in case Ey doesn't
-               -- mention x, in which case the y binding can be pulled
-               -- out as an enclosing let(rec), which in turn gives
-               -- the strictness analyser more chance.
-               returnSmpl pairs_s
-
-    float_pairs pairs = concat (map float_pair pairs)
-
-    float_pair (binder, rhs)
-       | always_float_let_from_let ||
-         floatExposesHNF True False False rhs
-        = (binder,rhs') : pairs'
-
-       | otherwise
-       = [(binder,rhs)]
-       where 
-         (pairs', rhs') = do_float rhs
-
-       -- Float just pulls out any top-level let(rec) bindings
-    do_float :: InExpr -> ([(InBinder,InExpr)], InExpr)
-    do_float (CoLet (CoRec pairs) body)     = (float_pairs pairs    ++ pairs', body')
-                                           where
-                                             (pairs', body') = do_float body
-    do_float (CoLet (CoNonRec id rhs) body) = (float_pair (id,rhs) ++ pairs', body')
-                                           where
-                                             (pairs', body') = do_float body
-    do_float other                         = ([], other)
-
-simplRecursiveGroup env triples
-  =    -- Toss out all the dead pairs?  No, there shouldn't be any!
-       -- Dead code is discarded by the occurrence analyser
-    let
-           -- Separate the live triples into "inline"able and
-           -- "ordinary" We're paranoid about duplication!
-       (inline_triples, ordinary_triples)
-         = partition is_inline_triple triples
-
-       is_inline_triple (_, ((_,occ_info),_))
-         = inlineUnconditionally False {-not ok_to_dup-} occ_info
-
-           -- Now add in the inline_pairs info (using "env_w_clones"),
-           -- so that we will save away suitably-clone-laden envs
-           -- inside the InlineIts...).
-
-           -- NOTE ALSO that we tie a knot here, because the
-           -- saved-away envs must also include these very inlinings
-           -- (they aren't stored anywhere else, and a late one might
-           -- be used in an early one).
+    -- Try let-to-case; see notes below about let-to-case
+    simpl_bind env rhs | try_let_to_case &&
+                        will_be_demanded &&
+                        (rhs_is_bot ||
+                         not rhs_is_whnf &&
+                         singleConstructorType rhs_ty
+                               -- Only do let-to-case for single constructor types. 
+                               -- For other types we defer doing it until the tidy-up phase at
+                               -- the end of simplification.
+                        )
+      = tick Let2Case                          `thenSmpl_`
+        simplCase env rhs (AlgAlts [] (BindDefault binder (Var id)))
+                         (\env rhs -> complete_bind env rhs) body_ty
+               -- OLD COMMENT:  [now the new RHS is only "x" so there's less worry]
+               -- NB: it's tidier to call complete_bind not simpl_bind, else
+               -- we nearly end up in a loop.  Consider:
+               --      let x = rhs in b
+               -- ==>  case rhs of (p,q) -> let x=(p,q) in b
+               -- This effectively what the above simplCase call does.
+               -- Now, the inner let is a let-to-case target again!  Actually, since
+               -- the RHS is in WHNF it won't happen, but it's a close thing!
+
+    -- Try let-from-let
+    simpl_bind env (Let bind rhs) | let_floating_ok
+      = tick LetFloatFromLet                    `thenSmpl_`
+       simplBind env (fix_up_demandedness will_be_demanded bind)
+                     (\env -> simpl_bind env rhs) body_ty
 
-       env_w_inlinings = foldl add_inline env inline_triples
+    -- Try case-from-let; this deals with a strict let of error too
+    simpl_bind env (Case scrut alts) | case_floating_ok scrut
+      = tick CaseFloatFromLet                          `thenSmpl_`
 
-       add_inline env (id', (binder,rhs))
-         = extendIdEnvWithInlining env env_w_inlinings binder rhs
+       -- First, bind large let-body if necessary
+       if ok_to_dup || isSingleton (nonErrorRHSs alts)
+       then
+           simplCase env scrut alts (\env rhs -> simpl_bind env rhs) body_ty
+       else
+           bindLargeRhs env [binder] body_ty body_c    `thenSmpl` \ (extra_binding, new_body) ->
+           let
+               body_c' = \env -> simplExpr env new_body [] body_ty
+               case_c  = \env rhs -> simplNonRec env binder rhs body_c' body_ty
+           in
+           simplCase env scrut alts case_c body_ty     `thenSmpl` \ case_expr ->
+           returnSmpl (Let extra_binding case_expr)
+
+    -- None of the above; simplify rhs and tidy up
+    simpl_bind env rhs = complete_bind env rhs
+    complete_bind env rhs
+      = cloneId env binder                     `thenSmpl` \ new_id ->
+       simplRhsExpr env binder rhs new_id      `thenSmpl` \ (rhs',arity) ->
+       completeNonRec env binder 
+               (new_id `withArity` arity) rhs' `thenSmpl` \ (new_env, binds) ->
+        body_c new_env                         `thenSmpl` \ body' ->
+        returnSmpl (mkCoLetsAny binds body')
+
+
+       -- All this stuff is computed at the start of the simpl_bind loop
+    float_lets               = switchIsSet env SimplFloatLetsExposingWHNF
+    float_primops            = switchIsSet env SimplOkToFloatPrimOps
+    ok_to_dup                = switchIsSet env SimplOkToDupCode
+    always_float_let_from_let = switchIsSet env SimplAlwaysFloatLetsFromLets
+    try_let_to_case           = switchIsSet env SimplLetToCase
+    no_float                 = switchIsSet env SimplNoLetFromStrictLet
 
-           -- Separate the remaining bindings into the ones which
-           -- need to be dealt with first (the "early" ones)
-           -- and the others (the "late" ones)
-       (early_triples, late_triples)
-         = partition is_early_triple ordinary_triples
+    demand_info             = getIdDemandInfo id
+    will_be_demanded = willBeDemanded demand_info
+    rhs_ty          = idType id
 
-       is_early_triple (_, (_, CoCon _ _ _)) = True
-       is_early_triple (i, _               ) = idWantsToBeINLINEd i
-    in
-       -- Process the early bindings first
-    mapSmpl (do_one_binding env_w_inlinings) early_triples     `thenSmpl` \ early_triples' ->
+    form       = mkFormSummary rhs
+    rhs_is_bot  = case form of
+                       BottomForm -> True
+                       other      -> False
+    rhs_is_whnf = case form of
+                       VarForm -> True
+                       ValueForm -> True
+                       other -> False
 
-       -- Now further extend the environment to record our knowledge
-       -- about the form of the binders bound in the constructor bindings
-    let
-        env_w_early_info = foldr add_early_info env_w_inlinings early_triples'
-        add_early_info (binder, (id', rhs')) env = extendUnfoldEnvGivenRhs env binder id' rhs'
-    in
-       -- Now process the non-constructor bindings
-    mapSmpl (do_one_binding env_w_early_info) late_triples     `thenSmpl` \ late_triples' ->
+    float_exposes_hnf = floatExposesHNF float_lets float_primops ok_to_dup rhs
 
-       -- Phew! We're done
-    let
-       binding = CoRec (map snd early_triples' ++ map snd late_triples')
-    in
-    returnSmpl (binding, env_w_early_info)
-  where
+    let_floating_ok  = (will_be_demanded && not no_float) ||
+                      always_float_let_from_let ||
+                      float_exposes_hnf
 
-    do_one_binding env (id', (binder,rhs)) 
-      = simplRhsExpr env binder rhs `thenSmpl` \ rhs' ->
-       returnSmpl (binder, (id', rhs'))
+    case_floating_ok scrut = (will_be_demanded && not no_float) || 
+                            (float_exposes_hnf && is_cheap_prim_app scrut && float_primops)
+       -- See note below 
 \end{code}
 
 
-@completeLet@ looks at the simplified post-floating RHS of the
+@completeNonRec@ looks at the simplified post-floating RHS of the
 let-expression, and decides what to do.  There's one interesting
 aspect to this, namely constructor reuse.  Consider
-@      
+@
        f = \x -> case x of
                    (y:ys) -> y:ys
                    []     -> ...
@@ -1076,7 +1007,7 @@ const.Int.max.wrk{-s2516-} =
          a.s3299 :: Int
          _N_ {-# U(P) #-}
          a.s3299 = I#! upk.s3297#
-       } in 
+       } in
          case (const.Int._tagCmp.wrk{-s2513-} upk.s3297# upk.s3298#) of {
            _LT -> I#! upk.s3298#
            _EQ -> a.s3299
@@ -1091,83 +1022,262 @@ only do the reverse (turn a constructor application back into a
 variable) when we find a let-expression:
 @
        let x = C a1 .. an
-       in 
-       ... (let y = C a1 .. an in ...) ... 
+       in
+       ... (let y = C a1 .. an in ...) ...
 @
 where it is always good to ditch the binding for y, and replace y by
 x.  That's just what completeLetBinding does.
 
+
 \begin{code}
-completeLet
-       :: SimplEnv
-       -> InBinder
-       -> InExpr               -- Original RHS
-       -> OutExpr              -- The simplified RHS
-       -> (SimplEnv -> SmplM OutExpr)          -- Body handler
-       -> OutUniType           -- Type of body
-       -> SmplM OutExpr
+{- FAILED CODE
+   The trouble is that we keep transforming
+               let x = coerce e
+                   y = coerce x
+               in ...
+   to
+               let x' = coerce e
+                   y' = coerce x'
+               in ...
+   and counting a couple of ticks for this non-transformation
+
+       -- We want to ensure that all let-bound Coerces have 
+       -- atomic bodies, so they can freely be inlined.
+completeNonRec env binder new_id (Coerce coercion ty rhs)
+  | not (is_atomic rhs)
+  = newId (coreExprType rhs)                           `thenSmpl` \ inner_id ->
+    completeNonRec env 
+                  (inner_id, dangerousArgOcc) inner_id rhs `thenSmpl` \ (env1, binds1) ->
+       -- Dangerous occ because, like constructor args,
+       -- it can be duplicated easily
+    let
+       atomic_rhs = case runEager $ lookupId env1 inner_id of
+                       LitArg l -> Lit l
+                       VarArg v -> Var v
+    in
+    completeNonRec env1 binder new_id
+                  (Coerce coercion ty atomic_rhs)      `thenSmpl` \ (env2, binds2) ->
+
+    returnSmpl (env2, binds1 ++ binds2)
+-}
+
+
+       -- Right hand sides that are constructors
+       --      let v = C args
+       --      in
+       --- ...(let w = C same-args in ...)...
+       -- Then use v instead of w.      This may save
+       -- re-constructing an existing constructor.
+completeNonRec env binder new_id rhs@(Con con con_args)
+  | switchIsSet env SimplReuseCon && 
+    maybeToBool maybe_existing_con &&
+    not (isExported new_id)            -- Don't bother for exported things
+                                       -- because we won't be able to drop
+                                       -- its binding.
+  = tick ConReused             `thenSmpl_`
+    returnSmpl (extendIdEnvWithAtom env binder (VarArg it), [NonRec new_id rhs])
+  where
+    maybe_existing_con = lookForConstructor env con con_args
+    Just it           = maybe_existing_con
+
+
+       -- Default case
+       -- Check for atomic right-hand sides.
+       -- We used to have a "tick AtomicRhs" in here, but it causes more trouble
+       -- than it's worth.  For a top-level binding a = b, where a is exported,
+       -- we can't drop the binding, so we get repeated AtomicRhs ticks
+completeNonRec env binder@(id,occ_info) new_id new_rhs
+ | is_atomic eta'd_rhs                 -- If rhs (after eta reduction) is atomic
+ = returnSmpl (atomic_env , [NonRec new_id eta'd_rhs])
+
+ | otherwise                   -- Non atomic rhs (don't eta after all)
+ = returnSmpl (non_atomic_env , [NonRec new_id new_rhs])
+ where
+   atomic_env = extendIdEnvWithAtom env binder the_arg
+
+   non_atomic_env = extendEnvGivenBinding (extendIdEnvWithClone env binder new_id)
+                                         occ_info new_id new_rhs
+
+   eta'd_rhs = etaCoreExpr new_rhs
+   the_arg   = case eta'd_rhs of
+                 Var v -> VarArg v
+                 Lit l -> LitArg l
+\end{code}
 
-completeLet env binder@(id,binder_info) old_rhs new_rhs body_c body_ty
+%************************************************************************
+%*                                                                     *
+\subsection[Simplify-letrec]{Letrec-expressions}
+%*                                                                     *
+%************************************************************************
 
-  -- See if RHS is an atom, or a reusable constructor
-  | maybeToBool maybe_atomic_rhs
-  = let
-       new_env = extendIdEnvWithAtom env binder rhs_atom
+Letrec expressions
+~~~~~~~~~~~~~~~~~~
+Here's the game plan
+
+1. Float any let(rec)s out of the RHSs
+2. Clone all the Ids and extend the envt with these clones
+3. Simplify one binding at a time, adding each binding to the
+   environment once it's done.
+
+This relies on the occurrence analyser to
+       a) break all cycles with an Id marked MustNotBeInlined
+       b) sort the decls into topological order
+The former prevents infinite inlinings, and the latter means
+that we get maximum benefit from working top to bottom.
+
+
+\begin{code}
+simplRec env pairs body_c body_ty
+  =    -- Do floating, if necessary
+    floatBind env False (Rec pairs)    `thenSmpl` \ [Rec pairs'] ->
+    let
+       binders = map fst pairs'
+    in
+    cloneIds env binders                       `thenSmpl` \ ids' ->
+    let
+       env_w_clones = extendIdEnvWithClones env binders ids'
     in
-    tick atom_tick_type                        `thenSmpl_`
-    body_c new_env
+    simplRecursiveGroup env_w_clones ids' pairs'       `thenSmpl` \ (pairs', new_env) ->
 
-  -- Maybe the rhs is an application of error, and sure to be demanded
-  | will_be_demanded && 
-    maybeToBool maybe_error_app
-  = tick CaseOfError                   `thenSmpl_`
-    returnSmpl retyped_error_app
+    body_c new_env                             `thenSmpl` \ body' ->
+
+    returnSmpl (Let (Rec pairs') body')
+\end{code}
+
+\begin{code}
+-- The env passed to simplRecursiveGroup already has 
+-- bindings that clone the variables of the group.
+simplRecursiveGroup env new_ids []
+  = returnSmpl ([], env)
+
+simplRecursiveGroup env (new_id : new_ids) ((binder@(_, occ_info), rhs) : pairs)
+  | inlineUnconditionally ok_to_dup occ_info
+  =    -- Single occurrence, so drop binding and extend env with the inlining
+    let
+       new_env = extendEnvGivenInlining env new_id occ_info rhs
+    in
+    simplRecursiveGroup new_env new_ids pairs
 
-  -- The general case
   | otherwise
-  = cloneId env binder                 `thenSmpl` \ id' ->
+  = simplRhsExpr env binder rhs new_id         `thenSmpl` \ (new_rhs, arity) ->
     let
-       env1    = extendIdEnvWithClone env binder id'
-       new_env = _scc_ "euegR2" (extendUnfoldEnvGivenRhs env1 binder id' new_rhs)
+       new_id' = new_id `withArity` arity
+    
+       -- ToDo: this next bit could usefully share code with completeNonRec
+
+        new_env 
+         | idMustNotBeINLINEd new_id           -- Occurrence analyser says "don't inline"
+         = env
+
+         | is_atomic eta'd_rhs                 -- If rhs (after eta reduction) is atomic
+         = extendIdEnvWithAtom env binder the_arg
+
+         | otherwise                           -- Non-atomic
+         = extendEnvGivenBinding env occ_info new_id new_rhs
+                                               -- Don't eta if it doesn't eliminate the binding
+
+        eta'd_rhs = etaCoreExpr new_rhs
+        the_arg   = case eta'd_rhs of
+                         Var v -> VarArg v
+                         Lit l -> LitArg l
     in
-    body_c new_env                     `thenSmpl` \ body' ->
-    returnSmpl (CoLet (CoNonRec id' new_rhs) body')
+    simplRecursiveGroup new_env new_ids pairs  `thenSmpl` \ (new_pairs, final_env) ->
+    returnSmpl ((new_id', new_rhs) : new_pairs, final_env)   
+  where
+    ok_to_dup = switchIsSet env SimplOkToDupCode
+\end{code}
+
+
+
+\begin{code}
+floatBind :: SimplEnv
+         -> Bool                               -- True <=> Top level
+         -> InBinding
+         -> SmplM [InBinding]
+
+floatBind env top_level bind
+  | not float_lets ||
+    n_extras == 0
+  = returnSmpl [bind]
+
+  | otherwise      
+  = tickN LetFloatFromLet n_extras             `thenSmpl_` 
+               -- It's important to increment the tick counts if we
+               -- do any floating.  A situation where this turns out
+               -- to be important is this:
+               -- Float in produces:
+               --      letrec  x = let y = Ey in Ex
+               --      in B
+               -- Now floating gives this:
+               --      letrec x = Ex
+               --             y = Ey
+               --      in B
+               --- We now want to iterate once more in case Ey doesn't
+               -- mention x, in which case the y binding can be pulled
+               -- out as an enclosing let(rec), which in turn gives
+               -- the strictness analyser more chance.
+    returnSmpl binds'
 
   where
-    will_be_demanded = willBeDemanded (getIdDemandInfo id)
-    try_to_reuse_constr   = switchIsSet env SimplReuseCon
-
-    Just (rhs_atom, atom_tick_type) = maybe_atomic_rhs
-
-    maybe_atomic_rhs :: Maybe (OutAtom, TickType)
-       -- If the RHS is atomic, we return Just (atom, tick type)
-       -- otherwise Nothing
-
-    maybe_atomic_rhs
-      = case new_rhs of
-         CoVar var -> Just (CoVarAtom var, AtomicRhs)
-
-         CoLit lit | not (isNoRepLit lit) 
-           -> Just (CoLitAtom lit, AtomicRhs)
-
-         CoCon con tys con_args
-           | try_to_reuse_constr 
-                  -- Look out for
-                  --   let v = C args
-                  --   in 
-                  --- ...(let w = C same-args in ...)...
-                  -- Then use v instead of w.   This may save
-                  -- re-constructing an existing constructor.
-            -> case lookForConstructor env con tys con_args of
-                 Nothing  -> Nothing
-                 Just var -> Just (CoVarAtom var, ConReused)
-
-         other -> Nothing
-
-    maybe_error_app        = maybeErrorApp new_rhs (Just body_ty)
-    Just retyped_error_app = maybe_error_app
+    (binds', _, n_extras) = fltBind bind       
+
+    float_lets               = switchIsSet env SimplFloatLetsExposingWHNF
+    always_float_let_from_let = switchIsSet env SimplAlwaysFloatLetsFromLets
+
+       -- fltBind guarantees not to return leaky floats
+       -- and all the binders of the floats have had their demand-info zapped
+    fltBind (NonRec bndr rhs)
+      = (binds ++ [NonRec (un_demandify bndr) rhs'], 
+        leakFree bndr rhs', 
+        length binds)
+      where
+        (binds, rhs') = fltRhs rhs
+    
+    fltBind (Rec pairs)
+      = ([Rec (extras
+              ++
+              binders `zip` rhss')],
+         and (zipWith leakFree binders rhss'),
+        length extras
+        )
+    
+      where
+        (binders, rhss)  = unzip pairs
+        (binds_s, rhss') = mapAndUnzip fltRhs rhss
+       extras           = concat (map get_pairs (concat binds_s))
+
+        get_pairs (NonRec bndr rhs) = [(bndr,rhs)]
+        get_pairs (Rec pairs)       = pairs
+    
+       -- fltRhs has same invariant as fltBind
+    fltRhs rhs
+      |  (always_float_let_from_let ||
+          floatExposesHNF True False False rhs)
+      = fltExpr rhs
+    
+      | otherwise
+      = ([], rhs)
+    
+    
+       -- fltExpr has same invariant as fltBind
+    fltExpr (Let bind body)
+      | not top_level || binds_wont_leak
+            -- fltExpr guarantees not to return leaky floats
+      = (binds' ++ body_binds, body')
+      where
+        (body_binds, body')         = fltExpr body
+        (binds', binds_wont_leak, _) = fltBind bind
+    
+    fltExpr expr = ([], expr)
+
+-- Crude but effective
+leakFree (id,_) rhs = case getIdArity id of
+                       ArityAtLeast n | n > 0 -> True
+                       ArityExactly n | n > 0 -> True
+                       other                  -> whnfOrBottom rhs
 \end{code}
 
+
 %************************************************************************
 %*                                                                     *
 \subsection[Simplify-atoms]{Simplifying atoms}
@@ -1175,23 +1285,14 @@ completeLet env binder@(id,binder_info) old_rhs new_rhs body_c body_ty
 %************************************************************************
 
 \begin{code}
-simplAtom :: SimplEnv -> InAtom -> OutAtom
-
-simplAtom env (CoLitAtom lit) = CoLitAtom lit
-
-simplAtom env (CoVarAtom id)
-  | isLocallyDefined id
-  = case lookupId env id of
-       Just (ItsAnAtom atom) -> atom
-       Just (InlineIt _ _ _) -> pprPanic "simplAtom InLineIt:" (ppAbove (ppr PprDebug id) (pprSimplEnv env))
-       Nothing               -> CoVarAtom id   -- Must be an uncloned thing
+simplArg :: SimplEnv -> InArg -> Eager ans OutArg
 
-  | otherwise
-  =    -- Not locally defined, so no change
-    CoVarAtom id
+simplArg env (LitArg lit) = returnEager (LitArg lit)
+simplArg env (TyArg  ty)  = simplTy env ty     `appEager` \ ty' -> 
+                           returnEager (TyArg ty')
+simplArg env (VarArg id)  = lookupId env id
 \end{code}
 
-
 %************************************************************************
 %*                                                                     *
 \subsection[Simplify-quickies]{Some local help functions}
@@ -1202,29 +1303,41 @@ simplAtom env (CoVarAtom id)
 \begin{code}
 -- fix_up_demandedness switches off the willBeDemanded Info field
 -- for bindings floated out of a non-demanded let
-fix_up_demandedness True {- Will be demanded -} bind 
+fix_up_demandedness True {- Will be demanded -} bind
    = bind      -- Simple; no change to demand info needed
-fix_up_demandedness False {- May not be demanded -} (CoNonRec binder rhs)
-   = CoNonRec (un_demandify binder) rhs
-fix_up_demandedness False {- May not be demanded -} (CoRec pairs)
-   = CoRec [(un_demandify binder, rhs) | (binder,rhs) <- pairs]
+fix_up_demandedness False {- May not be demanded -} (NonRec binder rhs)
+   = NonRec (un_demandify binder) rhs
+fix_up_demandedness False {- May not be demanded -} (Rec pairs)
+   = Rec [(un_demandify binder, rhs) | (binder,rhs) <- pairs]
 
-un_demandify (id, occ_info) = (id `addIdDemandInfo` noInfo, occ_info)
+un_demandify (id, occ_info) = (id `addIdDemandInfo` noDemandInfo, occ_info)
 
-is_cheap_prim_app (CoPrim op tys args) = primOpOkForSpeculation op
-is_cheap_prim_app other                       = False
+is_cheap_prim_app (Prim op _) = primOpOkForSpeculation op
+is_cheap_prim_app other              = False
 
-computeResultType :: SimplEnv -> InExpr -> [OutArg] -> OutUniType
-computeResultType env expr args
-  = do expr_ty' args
-  where
-    expr_ty  = typeOfCoreExpr (unTagBinders expr)
-    expr_ty' = simplTy env expr_ty
-
-    do ty [] = ty
-    do ty (TypeArg ty_arg : args) = do (applyTy ty ty_arg) args
-    do ty (ValArg a       : args) = case maybeUnpackFunTy ty of
-                                     Just (_, res_ty) -> do res_ty args
-                                     Nothing          -> panic "computeResultType"
+computeResultType :: SimplEnv -> InType -> [OutArg] -> OutType
+computeResultType env expr_ty orig_args
+  = simplTy env expr_ty                `appEager` \ expr_ty' ->
+    let
+       go ty [] = ty
+       go ty (TyArg ty_arg : args) = go (mkAppTy ty ty_arg) args
+       go ty (a:args) | isValArg a = case (getFunTy_maybe ty) of
+                                       Just (_, res_ty) -> go res_ty args
+                                       Nothing          -> 
+                                           pprPanic "computeResultType" (vcat [
+                                                                       ppr PprDebug (a:args),
+                                                                       ppr PprDebug orig_args,
+                                                                       ppr PprDebug expr_ty',
+                                                                       ppr PprDebug ty])
+    in
+    go expr_ty' orig_args
+
+
+var `withArity` UnknownArity = var
+var `withArity` arity       = var `addIdArity` arity
+
+is_atomic (Var v) = True
+is_atomic (Lit l) = not (isNoRepLit l)
+is_atomic other   = False
 \end{code}