More modules that need LANGUAGE BangPatterns
[ghc-hetmet.git] / compiler / simplCore / SimplUtils.lhs
index 1c08d6b..1618525 100644 (file)
@@ -6,7 +6,7 @@
 \begin{code}
 module SimplUtils (
        -- Rebuilding
-       mkLam, mkCase, prepareAlts, 
+       mkLam, mkCase, prepareAlts, tryEtaExpand,
 
        -- Inlining,
        preInlineUnconditionally, postInlineUnconditionally, 
@@ -15,8 +15,9 @@ module SimplUtils (
 
        -- The continuation type
        SimplCont(..), DupFlag(..), ArgInfo(..),
+        isSimplified,
        contIsDupable, contResultType, contIsTrivial, contArgs, dropArgs, 
-       pushArgs, countValArgs, countArgs, addArgTo,
+       pushSimplifiedArgs, countValArgs, countArgs, addArgTo,
        mkBoringStop, mkRhsStop, mkLazyArgStop, contIsRhsOrArg,
        interestingCallContext, 
 
@@ -36,11 +37,11 @@ import qualified CoreSubst
 import PprCore
 import CoreFVs
 import CoreUtils
-import CoreArity       ( etaExpand, exprEtaExpandArity )
+import CoreArity
 import CoreUnfold
 import Name
 import Id
-import Var     ( isCoVar )
+import Var
 import Demand
 import SimplMonad
 import Type    hiding( substTy )
@@ -99,12 +100,12 @@ data SimplCont
        SimplCont
 
   | ApplyTo            -- C arg
-       DupFlag 
-       InExpr StaticEnv                -- The argument and its static env
+       DupFlag                 -- See Note [DupFlag invariants]
+       InExpr StaticEnv        -- The argument and its static env
        SimplCont
 
   | Select             -- case C of alts
-       DupFlag 
+       DupFlag                 -- See Note [DupFlag invariants]
        InId [InAlt] StaticEnv  -- The case binder, alts, and subst-env
        SimplCont
 
@@ -151,14 +152,31 @@ instance Outputable SimplCont where
                                       (nest 2 $ vcat [ppr (seTvSubst se), ppr alts]) $$ ppr cont 
   ppr (CoerceIt co cont)            = (ptext (sLit "CoerceIt") <+> ppr co) $$ ppr cont
 
-data DupFlag = OkToDup | NoDup
+data DupFlag = NoDup       -- Unsimplified, might be big
+             | Simplified  -- Simplified
+             | OkToDup     -- Simplified and small
+
+isSimplified :: DupFlag -> Bool
+isSimplified NoDup = False
+isSimplified _     = True      -- Invariant: the subst-env is empty
 
 instance Outputable DupFlag where
-  ppr OkToDup = ptext (sLit "ok")
-  ppr NoDup   = ptext (sLit "nodup")
+  ppr OkToDup    = ptext (sLit "ok")
+  ppr NoDup      = ptext (sLit "nodup")
+  ppr Simplified = ptext (sLit "simpl")
+\end{code}
 
+Note [DupFlag invariants]
+~~~~~~~~~~~~~~~~~~~~~~~~~
+In both (ApplyTo dup _ env k)
+   and  (Select dup _ _ env k)
+the following invariants hold
 
+  (a) if dup = OkToDup, then continuation k is also ok-to-dup
+  (b) if dup = OkToDup or Simplified, the subst-env is empty
+      (and and hence no need to re-simplify)
 
+\begin{code}
 -------------------
 mkBoringStop :: SimplCont
 mkBoringStop = Stop BoringCtxt
@@ -179,8 +197,8 @@ contIsRhsOrArg _               = False
 -------------------
 contIsDupable :: SimplCont -> Bool
 contIsDupable (Stop {})                  = True
-contIsDupable (ApplyTo  OkToDup _ _ _)   = True
-contIsDupable (Select   OkToDup _ _ _ _) = True
+contIsDupable (ApplyTo  OkToDup _ _ _)   = True        -- See Note [DupFlag invariants]
+contIsDupable (Select   OkToDup _ _ _ _) = True -- ...ditto...
 contIsDupable (CoerceIt _ cont)          = contIsDupable cont
 contIsDupable _                          = False
 
@@ -238,9 +256,10 @@ contArgs cont@(ApplyTo {})
 
 contArgs cont = (True, [], cont)
 
-pushArgs :: SimplEnv -> [CoreExpr] -> SimplCont -> SimplCont
-pushArgs _env []         cont = cont
-pushArgs env  (arg:args) cont = ApplyTo NoDup arg env (pushArgs env args cont)
+pushSimplifiedArgs :: SimplEnv -> [CoreExpr] -> SimplCont -> SimplCont
+pushSimplifiedArgs _env []         cont = cont
+pushSimplifiedArgs env  (arg:args) cont = ApplyTo Simplified arg env (pushSimplifiedArgs env args cont)
+                  -- The env has an empty SubstEnv
 
 dropArgs :: Int -> SimplCont -> SimplCont
 dropArgs 0 cont = cont
@@ -433,10 +452,9 @@ interestingArgContext rules call_cont
 \end{code}
 
 
-
 %************************************************************************
 %*                                                                     *
-\subsection{Decisions about inlining}
+                  Gentle mode                                                                  
 %*                                                                     *
 %************************************************************************
 
@@ -457,9 +475,33 @@ Gentle mode has a separate boolean flag to control
        a) inlining (sm_inline flag)
        b) rules    (sm_rules  flag)
 A key invariant about Gentle mode is that it is treated as the EARLIEST
-phase.  Something is inlined if the sm_inline flag is on AND the thing
-is inlinable in the earliest phase.  This is important. Example
+phase.  
+
+\begin{code}
+simplEnvForGHCi :: SimplEnv
+simplEnvForGHCi = mkSimplEnv allOffSwitchChecker $
+                  SimplGently { sm_rules = True, sm_inline = False }
+   -- Do not do any inlining, in case we expose some unboxed
+   -- tuple stuff that confuses the bytecode interpreter
+
+simplEnvForRules :: SimplEnv
+simplEnvForRules = mkSimplEnv allOffSwitchChecker $
+                   SimplGently { sm_rules = True, sm_inline = False }
+
+updModeForInlineRules :: Activation -> SimplifierMode -> SimplifierMode
+-- See Note [Simplifying inside InlineRules]
+updModeForInlineRules _inline_rule_act _current_mode
+  = SimplGently { sm_rules = True, sm_inline = True }
+\end{code}
+
+Note [Inlining in gentle mode]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Something is inlined if 
+   (i)   the sm_inline flag is on, AND
+   (ii)  the thing has an INLINE pragma, AND
+   (iii) the thing is inlinable in the earliest phase.  
 
+Example of why (iii) is important:
   {-# INLINE [~1] g #-}
   g = ...
   
@@ -475,9 +517,9 @@ On the other hand, it is bad not to do ANY inlining into an
 InlineRule, because then recursive knots in instance declarations
 don't get unravelled.
 
-However, *sometimes* SimplGently must do no call-site inlining at all.
-Before full laziness we must be careful not to inline wrappers,
-because doing so inhibits floating
+However, *sometimes* SimplGently must do no call-site inlining at all
+(hence sm_inline = False).  Before full laziness we must be careful
+not to inline wrappers, because doing so inhibits floating
     e.g. ...(case f x of ...)...
     ==> ...(case (case x of I# x# -> fw x#) of ...)...
     ==> ...(case x of I# x# -> case fw x# of ...)...
@@ -502,6 +544,12 @@ RULES are enabled when doing "gentle" simplification.  Two reasons:
     to work in Template Haskell when simplifying
     splices, so we get simpler code for literal strings
 
+But watch out: list fusion can prevent floating.  So use phase control
+to switch off those rules until after floating.
+
+Currently (Oct10) I think that sm_rules is always True, so we
+could remove it.
+
 Note [Simplifying inside InlineRules]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 We must take care with simplification inside InlineRules (which come from
@@ -521,57 +569,7 @@ one; see OccurAnal.addRuleUsage.
 Second, we do want *do* to some modest rules/inlining stuff in InlineRules,
 partly to eliminate senseless crap, and partly to break the recursive knots
 generated by instance declarations.  To keep things simple, we always set 
-the phase to 'gentle' when processing InlineRules.  OK, so suppose we have
-       {-# INLINE <act> f #-}
-       f = <rhs>
-meaning "inline f in phases p where activation <act>(p) holds". 
-Then what inlinings/rules can we apply to the copy of <rhs> captured in
-f's InlineRule?  Our model is that literally <rhs> is substituted for
-f when it is inlined.  So our conservative plan (implemented by 
-updModeForInlineRules) is this:
-
-  -------------------------------------------------------------
-  When simplifying the RHS of an InlineRule,
-  If the InlineRule becomes active in phase p, then
-    if the current phase is *earlier than* p, 
-       make no inlinings or rules active when simplifying the RHS
-    otherwise 
-       set the phase to p when simplifying the RHS
-  -------------------------------------------------------------
-
-That ensures that
-
-  a) Rules/inlinings that *cease* being active before p will 
-     not apply to the InlineRule rhs, consistent with it being
-     inlined in its *original* form in phase p.
-
-  b) Rules/inlinings that only become active *after* p will
-     not apply to the InlineRule rhs, again to be consistent with
-     inlining the *original* rhs in phase p.
-
-For example, 
-       {-# INLINE f #-}
-       f x = ...g...
-
-       {-# NOINLINE [1] g #-}
-       g y = ...
-
-       {-# RULE h g = ... #-}
-Here we must not inline g into f's RHS, even when we get to phase 0,
-because when f is later inlined into some other module we want the
-rule for h to fire.
-
-Similarly, consider
-       {-# INLINE f #-}
-       f x = ...g...
-
-       g y = ...
-and suppose that there are auto-generated specialisations and a strictness
-wrapper for g.  The specialisations get activation AlwaysActive, and the
-strictness wrapper get activation (ActiveAfter 0).  So the strictness
-wrepper fails the test and won't be inlined into f's InlineRule. That
-means f can inline, expose the specialised call to g, so the specialisation
-rules can fire.
+the phase to 'gentle' when processing InlineRules.  
 
 A note about wrappers
 ~~~~~~~~~~~~~~~~~~~~~
@@ -585,41 +583,155 @@ mark it 'demanded', so when the RHS is simplified, it'll get an ArgOf
 continuation. 
 
 \begin{code}
-simplEnvForGHCi :: SimplEnv
-simplEnvForGHCi = mkSimplEnv allOffSwitchChecker $
-                  SimplGently { sm_rules = False, sm_inline = False }
-   -- Do not do any inlining, in case we expose some unboxed
-   -- tuple stuff that confuses the bytecode interpreter
+activeUnfolding :: SimplEnv -> IdUnfoldingFun
+activeUnfolding env
+  = case getMode env of
+      SimplGently { sm_inline = False } -> active_unfolding_minimal
+      SimplGently { sm_inline = True  } -> active_unfolding_gentle
+      SimplPhase n _                    -> active_unfolding n
 
-simplEnvForRules :: SimplEnv
-simplEnvForRules = mkSimplEnv allOffSwitchChecker $
-                   SimplGently { sm_rules = True, sm_inline = False }
+activeUnfInRule :: SimplEnv -> IdUnfoldingFun
+-- When matching in RULE, we want to "look through" an unfolding
+-- (to see a constructor) if *rules* are on, even if *inlinings* 
+-- are not.  A notable example is DFuns, which really we want to 
+-- match in rules like (op dfun) in gentle mode. Another example
+-- is 'otherwise' which we want exprIsConApp_maybe to be able to
+-- see very early on
+activeUnfInRule env
+  = case getMode env of
+      SimplGently { sm_rules = False } -> active_unfolding_minimal
+      SimplGently { sm_rules = True  } -> active_unfolding_early
+      SimplPhase n _                   -> active_unfolding n
+  where
+    active_unfolding_early id
+      | isEarlyActive (idInlineActivation id) = idUnfolding id
+      | otherwise                             = idUnfolding id
 
-updModeForInlineRules :: Activation -> SimplifierMode -> SimplifierMode
--- See Note [Simplifying inside InlineRules]
---    Treat Gentle as phase "infinity"
---    If current_phase `earlier than` inline_rule_start_phase 
---      then no_op
---    else 
---    if current_phase `same phase` inline_rule_start_phase 
---      then current_phase   (keep gentle flags)
---      else inline_rule_start_phase
-updModeForInlineRules inline_rule_act current_mode
-  = case inline_rule_act of
-      NeverActive     -> no_op
-      AlwaysActive    -> mk_gentle current_mode
-      ActiveBefore {} -> mk_gentle current_mode
-      ActiveAfter n   -> mk_phase n current_mode
+active_unfolding_minimal :: IdUnfoldingFun
+-- Compuslory unfoldings only
+-- Ignore SimplGently, because we want to inline regardless;
+-- the Id has no top-level binding at all
+--
+-- NB: we used to have a second exception, for data con wrappers.
+-- On the grounds that we use gentle mode for rule LHSs, and 
+-- they match better when data con wrappers are inlined.
+-- But that only really applies to the trivial wrappers (like (:)),
+-- and they are now constructed as Compulsory unfoldings (in MkId)
+-- so they'll happen anyway.
+active_unfolding_minimal id
+  | isCompulsoryUnfolding unf = unf
+  | otherwise                 = NoUnfolding
+  where
+    unf = idUnfolding id
+
+active_unfolding_gentle :: IdUnfoldingFun
+-- Anything that is early-active
+-- See Note [Gentle mode]
+active_unfolding_gentle id
+  | isStableUnfolding unf
+  , isEarlyActive (idInlineActivation id) = unf
+       -- NB: wrappers are not early-active
+  | otherwise                             = NoUnfolding
   where
-    no_op = SimplGently { sm_rules = False, sm_inline = False }
+    unf = idUnfolding id
+      -- idUnfolding checks for loop-breakers
+      -- Things with an INLINE pragma may have 
+      -- an unfolding *and* be a loop breaker  
+      -- (maybe the knot is not yet untied)
 
-    mk_gentle (SimplGently {}) = current_mode
-    mk_gentle _                = SimplGently { sm_rules = True, sm_inline = True }
+active_unfolding :: CompilerPhase -> IdUnfoldingFun
+active_unfolding n id
+  | isActive n (idInlineActivation id) = idUnfolding id
+  | otherwise                          = NoUnfolding
 
-    mk_phase n (SimplPhase _ ss) = SimplPhase n ss
-    mk_phase n (SimplGently {})  = SimplPhase n ["gentle-rules"]
+activeRule :: DynFlags -> SimplEnv -> Maybe (Activation -> Bool)
+-- Nothing => No rules at all
+activeRule dflags env
+  | not (dopt Opt_EnableRewriteRules dflags)
+  = Nothing    -- Rewriting is off
+  | otherwise
+  = case getMode env of
+      SimplGently { sm_rules = rules_on } 
+        | rules_on  -> Just isEarlyActive      -- Note [RULEs enabled in SimplGently]
+        | otherwise -> Nothing
+      SimplPhase n _ -> Just (isActive n)
 \end{code}
 
+--------------------------------------------------------------
+                OLD NOTES, now wrong
+           Preserved just for now (Oct 10)
+--------------------------------------------------------------
+
+      OK, so suppose we have
+       {-# INLINE <act> f #-}
+       f = <rhs>
+      meaning "inline f in phases p where activation <act>(p) holds". 
+      Then what inlinings/rules can we apply to the copy of <rhs> captured in
+      f's InlineRule?  Our model is that literally <rhs> is substituted for
+      f when it is inlined.  So our conservative plan (implemented by 
+      updModeForInlineRules) is this:
+
+        -------------------------------------------------------------
+        When simplifying the RHS of an InlineRule,
+        If the InlineRule becomes active in phase p, then
+          if the current phase is *earlier than* p, 
+             make no inlinings or rules active when simplifying the RHS
+          otherwise 
+             set the phase to p when simplifying the RHS
+
+      --    Treat Gentle as phase "infinity"
+      --    If current_phase `earlier than` inline_rule_start_phase 
+      --      then no_op
+      --    else 
+      --    if current_phase `same phase` inline_rule_start_phase 
+      --      then current_phase   (keep gentle flags)
+      --      else inline_rule_start_phase
+        -------------------------------------------------------------
+
+      That ensures that
+
+        a) Rules/inlinings that *cease* being active before p will 
+           not apply to the InlineRule rhs, consistent with it being
+           inlined in its *original* form in phase p.
+
+        b) Rules/inlinings that only become active *after* p will
+           not apply to the InlineRule rhs, again to be consistent with
+           inlining the *original* rhs in phase p.
+
+      For example, 
+               {-# INLINE f #-}
+       f x = ...g...
+
+       {-# NOINLINE [1] g #-}
+       g y = ...
+
+       {-# RULE h g = ... #-}
+      Here we must not inline g into f's RHS, even when we get to phase 0,
+      because when f is later inlined into some other module we want the
+      rule for h to fire.
+
+      Similarly, consider
+               {-# INLINE f #-}
+       f x = ...g...
+
+       g y = ...
+      and suppose that there are auto-generated specialisations and a strictness
+      wrapper for g.  The specialisations get activation AlwaysActive, and the
+      strictness wrapper get activation (ActiveAfter 0).  So the strictness
+      wrepper fails the test and won't be inlined into f's InlineRule. That
+      means f can inline, expose the specialised call to g, so the specialisation
+      rules can fire.
+
+--------------------------------------------------------------
+                END OF OLD NOTES
+--------------------------------------------------------------
+
+
+%************************************************************************
+%*                                                                     *
+                  preInlineUnconditionally
+%*                                                                     *
+%************************************************************************
 
 preInlineUnconditionally
 ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -697,6 +809,27 @@ let-float if you inline windowToViewport
 However, as usual for Gentle mode, do not inline things that are
 inactive in the intial stages.  See Note [Gentle mode].
 
+Note [InlineRule and preInlineUnconditionally]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Surprisingly, do not pre-inline-unconditionally Ids with INLINE pragmas!
+Example
+
+   {-# INLINE f #-}
+   f :: Eq a => a -> a
+   f x = ...
+   
+   fInt :: Int -> Int
+   fInt = f Int dEqInt
+
+   ...fInt...fInt...fInt...
+
+Here f occurs just once, in the RHS of f1. But if we inline it there
+we'll lose the opportunity to inline at each of fInt's call sites.
+The INLINE pragma will only inline when the application is saturated
+for exactly this reason; and we don't want PreInlineUnconditionally
+to second-guess it.  A live example is Trac #3736.
+    c.f. Note [InlineRule and postInlineUnconditionally]
+
 Note [Top-level botomming Ids]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Don't inline top-level Ids that are bottoming, even if they are used just
@@ -707,6 +840,7 @@ Inlining them won't make the program run faster!
 preInlineUnconditionally :: SimplEnv -> TopLevelFlag -> InId -> InExpr -> Bool
 preInlineUnconditionally env top_lvl bndr rhs
   | not active                                      = False
+  | isStableUnfolding (idUnfolding bndr)     = False    -- Note [InlineRule and preInlineUnconditionally]
   | isTopLevel top_lvl && isBottomingId bndr = False   -- Note [Top-level bottoming Ids]
   | opt_SimplNoPreInlining                   = False
   | otherwise = case idOccInfo bndr of
@@ -770,6 +904,12 @@ preInlineUnconditionally env top_lvl bndr rhs
 
 \end{code}
 
+%************************************************************************
+%*                                                                     *
+                  postInlineUnconditionally
+%*                                                                     *
+%************************************************************************
+
 postInlineUnconditionally
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 @postInlineUnconditionally@ decides whether to unconditionally inline
@@ -879,69 +1019,6 @@ postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding
                        -- See Note [pre/postInlineUnconditionally in gentle mode]
                   SimplPhase n _ -> isActive n act
     act = idInlineActivation bndr
-
-activeUnfolding :: SimplEnv -> IdUnfoldingFun
-activeUnfolding env
-  = case getMode env of
-      SimplGently { sm_inline = False } -> active_unfolding_minimal
-      SimplGently { sm_inline = True  } -> active_unfolding_gentle
-      SimplPhase n _                    -> active_unfolding n
-
-activeUnfInRule :: SimplEnv -> IdUnfoldingFun
--- When matching in RULE, we want to "look through" an unfolding
--- if *rules* are on, even if *inlinings* are not.  A notable example
--- is DFuns, which really we want to match in rules like (op dfun)
--- in gentle mode.
-activeUnfInRule env
-  = case getMode env of
-      SimplGently { sm_rules = False } -> active_unfolding_minimal
-      SimplGently { sm_rules = True  } -> active_unfolding_gentle
-      SimplPhase n _                   -> active_unfolding n
-
-active_unfolding_minimal :: IdUnfoldingFun
--- Compuslory unfoldings only
--- Ignore SimplGently, because we want to inline regardless;
--- the Id has no top-level binding at all
---
--- NB: we used to have a second exception, for data con wrappers.
--- On the grounds that we use gentle mode for rule LHSs, and 
--- they match better when data con wrappers are inlined.
--- But that only really applies to the trivial wrappers (like (:)),
--- and they are now constructed as Compulsory unfoldings (in MkId)
--- so they'll happen anyway.
-active_unfolding_minimal id
-  | isCompulsoryUnfolding unf = unf
-  | otherwise                 = NoUnfolding
-  where
-    unf = realIdUnfolding id   -- Never a loop breaker
-
-active_unfolding_gentle :: IdUnfoldingFun
--- Anything that is early-active
--- See Note [Gentle mode]
-active_unfolding_gentle id
-  | isEarlyActive (idInlineActivation id) = idUnfolding id
-  | otherwise                             = NoUnfolding
-      -- idUnfolding checks for loop-breakers
-      -- Things with an INLINE pragma may have 
-      -- an unfolding *and* be a loop breaker  
-      -- (maybe the knot is not yet untied)
-
-active_unfolding :: CompilerPhase -> IdUnfoldingFun
-active_unfolding n id
-  | isActive n (idInlineActivation id) = idUnfolding id
-  | otherwise                          = NoUnfolding
-
-activeRule :: DynFlags -> SimplEnv -> Maybe (Activation -> Bool)
--- Nothing => No rules at all
-activeRule dflags env
-  | not (dopt Opt_EnableRewriteRules dflags)
-  = Nothing    -- Rewriting is off
-  | otherwise
-  = case getMode env of
-      SimplGently { sm_rules = rules_on } 
-        | rules_on  -> Just isEarlyActive      -- Note [RULEs enabled in SimplGently]
-        | otherwise -> Nothing
-      SimplPhase n _ -> Just (isActive n)
 \end{code}
 
 Note [Top level and postInlineUnconditionally]
@@ -971,6 +1048,8 @@ Then there's a danger we'll optimise to
 and now postInlineUnconditionally, losing the InlineRule on f.  Now f'
 won't inline because 'e' is too big.
 
+    c.f. Note [InlineRule and preInlineUnconditionally]
+
 
 %************************************************************************
 %*                                                                     *
@@ -986,7 +1065,7 @@ mkLam :: SimplEnv -> [OutBndr] -> OutExpr -> SimplM OutExpr
 
 mkLam _b [] body 
   = return body
-mkLam env bndrs body
+mkLam _env bndrs body
   = do { dflags <- getDOptsSmpl
        ; mkLam' dflags bndrs body }
   where
@@ -1000,24 +1079,22 @@ mkLam env bndrs body
        co_vars  = tyVarsOfType co
        bad bndr = isCoVar bndr && bndr `elemVarSet` co_vars      
 
+    mkLam' dflags bndrs body@(Lam {})
+      = mkLam' dflags (bndrs ++ bndrs1) body1
+      where
+        (bndrs1, body1) = collectBinders body
+
     mkLam' dflags bndrs body
-      | dopt Opt_DoEtaReduction dflags,
-        Just etad_lam <- tryEtaReduce bndrs body
+      | dopt Opt_DoEtaReduction dflags
+      , Just etad_lam <- tryEtaReduce bndrs body
       = do { tick (EtaReduction (head bndrs))
           ; return etad_lam }
 
-      | dopt Opt_DoLambdaEtaExpansion dflags,
-        not (inGentleMode env),              -- In gentle mode don't eta-expansion
-                                     -- because it can clutter up the code
-                                     -- with casts etc that may not be removed
-       not (all isTyVar bndrs) -- Don't eta expand type abstractions
-      = do { let body' = tryEtaExpansion dflags body
-          ; return (mkLams bndrs body') }
-   
       | otherwise 
       = return (mkLams bndrs body)
 \end{code}
 
+
 Note [Casts and lambdas]
 ~~~~~~~~~~~~~~~~~~~~~~~~
 Consider 
@@ -1050,159 +1127,64 @@ It does not make sense to transform
        /\g. e `cast` g  ==>  (/\g.e) `cast` (/\g.g)
 because the latter is not well-kinded.
 
---     c) floating lets out through big lambdas 
---             [only if all tyvar lambdas, and only if this lambda
---              is the RHS of a let]
-
-{-     Sept 01: I'm experimenting with getting the
-       full laziness pass to float out past big lambdsa
- | all isTyVar bndrs,  -- Only for big lambdas
-   contIsRhs cont      -- Only try the rhs type-lambda floating
-                       -- if this is indeed a right-hand side; otherwise
-                       -- we end up floating the thing out, only for float-in
-                       -- to float it right back in again!
- = do (floats, body') <- tryRhsTyLam env bndrs body
-      return (floats, mkLams bndrs body')
--}
-
-
 %************************************************************************
 %*                                                                     *
-               Eta reduction
+              Eta expansion                                                                     
 %*                                                                     *
 %************************************************************************
 
-Note [Eta reduction conditions]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We try for eta reduction here, but *only* if we get all the way to an
-trivial expression.  We don't want to remove extra lambdas unless we
-are going to avoid allocating this thing altogether.
-
-There are some particularly delicate points here:
-
-* Eta reduction is not valid in general:  
-       \x. bot  /=  bot
-  This matters, partly for old-fashioned correctness reasons but,
-  worse, getting it wrong can yield a seg fault. Consider
-       f = \x.f x
-       h y = case (case y of { True -> f `seq` True; False -> False }) of
-               True -> ...; False -> ...
-
-  If we (unsoundly) eta-reduce f to get f=f, the strictness analyser
-  says f=bottom, and replaces the (f `seq` True) with just
-  (f `cast` unsafe-co).  BUT, as thing stand, 'f' got arity 1, and it
-  *keeps* arity 1 (perhaps also wrongly).  So CorePrep eta-expands 
-  the definition again, so that it does not termninate after all.
-  Result: seg-fault because the boolean case actually gets a function value.
-  See Trac #1947.
-
-  So it's important to to the right thing.
-
-* Note [Arity care]: we need to be careful if we just look at f's
-  arity. Currently (Dec07), f's arity is visible in its own RHS (see
-  Note [Arity robustness] in SimplEnv) so we must *not* trust the
-  arity when checking that 'f' is a value.  Otherwise we will
-  eta-reduce
-      f = \x. f x
-  to
-      f = f
-  Which might change a terminiating program (think (f `seq` e)) to a 
-  non-terminating one.  So we check for being a loop breaker first.
-
-  However for GlobalIds we can look at the arity; and for primops we
-  must, since they have no unfolding.  
-
-* Regardless of whether 'f' is a value, we always want to 
-  reduce (/\a -> f a) to f
-  This came up in a RULE: foldr (build (/\a -> g a))
-  did not match          foldr (build (/\b -> ...something complex...))
-  The type checker can insert these eta-expanded versions,
-  with both type and dictionary lambdas; hence the slightly 
-  ad-hoc isDictId
-
-* Never *reduce* arity. For example
-      f = \xy. g x y
-  Then if h has arity 1 we don't want to eta-reduce because then
-  f's arity would decrease, and that is bad
-
-These delicacies are why we don't use exprIsTrivial and exprIsHNF here.
-Alas.
-
 \begin{code}
-tryEtaReduce :: [OutBndr] -> OutExpr -> Maybe OutExpr
-tryEtaReduce bndrs body 
-  = go (reverse bndrs) body
+tryEtaExpand :: SimplEnv -> OutId -> OutExpr -> SimplM (Arity, OutExpr)
+-- See Note [Eta-expanding at let bindings]
+tryEtaExpand env bndr rhs
+  = do { dflags <- getDOptsSmpl
+       ; (new_arity, new_rhs) <- try_expand dflags
+
+       ; WARN( new_arity < old_arity || new_arity < _dmd_arity, 
+               (ptext (sLit "Arity decrease:") <+> (ppr bndr <+> ppr old_arity
+               <+> ppr new_arity <+> ppr _dmd_arity) $$ ppr new_rhs) )
+                       -- Note [Arity decrease]
+         return (new_arity, new_rhs) }
   where
-    incoming_arity = count isId bndrs
-
-    go (b : bs) (App fun arg) | ok_arg b arg = go bs fun       -- Loop round
-    go []       fun           | ok_fun fun   = Just fun                -- Success!
-    go _        _                           = Nothing          -- Failure!
-
-       -- Note [Eta reduction conditions]
-    ok_fun (App fun (Type ty)) 
-       | not (any (`elemVarSet` tyVarsOfType ty) bndrs)
-       =  ok_fun fun
-    ok_fun (Var fun_id)
-       =  not (fun_id `elem` bndrs)
-       && (ok_fun_id fun_id || all ok_lam bndrs)
-    ok_fun _fun = False
-
-    ok_fun_id fun = fun_arity fun >= incoming_arity
-
-    fun_arity fun            -- See Note [Arity care]
-       | isLocalId fun && isLoopBreaker (idOccInfo fun) = 0
-       | otherwise = idArity fun             
-
-    ok_lam v = isTyVar v || isDictId v
-
-    ok_arg b arg = varToCoreExpr b `cheapEqExpr` arg
+    try_expand dflags
+      | dopt Opt_DoLambdaEtaExpansion dflags 
+      , not (exprIsTrivial rhs)
+      , not (inGentleMode env)  -- In gentle mode don't eta-expansion
+                               -- because it can clutter up the code
+                               -- with casts etc that may not be removed
+      , let new_arity = exprEtaExpandArity dflags rhs
+      , new_arity > old_arity
+      = do { tick (EtaExpansion bndr)
+           ; return (new_arity, etaExpand new_arity rhs) }
+      | otherwise
+      = return (exprArity rhs, rhs)
+
+    old_arity  = idArity bndr
+    _dmd_arity = length $ fst $ splitStrictSig $ idStrictness bndr
 \end{code}
 
+Note [Eta-expanding at let bindings]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We now eta expand at let-bindings, which is where the payoff 
+comes. 
 
-%************************************************************************
-%*                                                                     *
-               Eta expansion
-%*                                                                     *
-%************************************************************************
-
-
-We go for:
-   f = \x1..xn -> N  ==>   f = \x1..xn y1..ym -> N y1..ym
-                                (n >= 0)
-
-where (in both cases) 
-
-       * The xi can include type variables
-
-       * The yi are all value variables
-
-       * N is a NORMAL FORM (i.e. no redexes anywhere)
-         wanting a suitable number of extra args.
-
-The biggest reason for doing this is for cases like
-
-       f = \x -> case x of
-                   True  -> \y -> e1
-                   False -> \y -> e2
-
-Here we want to get the lambdas together.  A good exmaple is the nofib
-program fibheaps, which gets 25% more allocation if you don't do this
-eta-expansion.
+One useful consequence is this example:
+   genMap :: C a => ...
+   {-# INLINE genMap #-}
+   genMap f xs = ...
 
-We may have to sandwich some coerces between the lambdas
-to make the types work.   exprEtaExpandArity looks through coerces
-when computing arity; and etaExpand adds the coerces as necessary when
-actually computing the expansion.
+   myMap :: D a => ...
+   {-# INLINE myMap #-}
+   myMap = genMap
 
-\begin{code}
-tryEtaExpansion :: DynFlags -> OutExpr -> OutExpr
--- There is at least one runtime binder in the binders
-tryEtaExpansion dflags body
-  = etaExpand fun_arity body
-  where
-    fun_arity = exprEtaExpandArity dflags body
-\end{code}
+Notice that 'genMap' should only inline if applied to two arguments.
+In the InlineRule for myMap we'll have the unfolding 
+    (\d -> genMap Int (..d..))  
+We do not want to eta-expand to 
+    (\d f xs -> genMap Int (..d..) f xs) 
+because then 'genMap' will inline, and it really shouldn't: at least
+as far as the programmer is concerned, it's not applied to two
+arguments!
 
 
 %************************************************************************
@@ -1308,7 +1290,7 @@ abstractFloats main_tvs body_env body
        rhs' = CoreSubst.substExpr (text "abstract_floats2") subst rhs
        tvs_here | any isCoVar main_tvs = main_tvs      -- Note [Abstract over coercions]
                 | otherwise 
-                = varSetElems (main_tv_set `intersectVarSet` exprSomeFreeVars isTyVar rhs')
+                = varSetElems (main_tv_set `intersectVarSet` exprSomeFreeVars isTyCoVar rhs')
        
                -- Abstract only over the type variables free in the rhs
                -- wrt which the new binding is abstracted.  But the naive
@@ -1500,16 +1482,17 @@ prepareDefault case_bndr (Just (tycon, inst_tys)) imposs_cons (Just deflt_rhs)
                                --      case x of { DEFAULT -> e }
                                -- and we don't want to fill in a default for them!
   , Just all_cons <- tyConDataCons_maybe tycon
-  , not (null all_cons)                -- This is a tricky corner case.  If the data type has no constructors,
-                               -- which GHC allows, then the case expression will have at most a default
-                               -- alternative.  We don't want to eliminate that alternative, because the
-                               -- invariant is that there's always one alternative.  It's more convenient
-                               -- to leave     
-                               --      case x of { DEFAULT -> e }     
-                               -- as it is, rather than transform it to
-                               --      error "case cant match"
-                               -- which would be quite legitmate.  But it's a really obscure corner, and
-                               -- not worth wasting code on.
+  , not (null all_cons)        
+       -- This is a tricky corner case.  If the data type has no constructors,
+       -- which GHC allows, then the case expression will have at most a default
+       -- alternative.  We don't want to eliminate that alternative, because the
+       -- invariant is that there's always one alternative.  It's more convenient
+       -- to leave     
+       --      case x of { DEFAULT -> e }     
+       -- as it is, rather than transform it to
+       --      error "case cant match"
+       -- which would be quite legitmate.  But it's a really obscure corner, and
+       -- not worth wasting code on.
   , let imposs_data_cons = [con | DataAlt con <- imposs_cons]  -- We now know it's a data type 
        impossible con   = con `elem` imposs_data_cons || dataConCannotMatch inst_tys con
   = case filterOut impossible all_cons of
@@ -1525,9 +1508,12 @@ prepareDefault case_bndr (Just (tycon, inst_tys)) imposs_cons (Just deflt_rhs)
 
        _ -> return [(DEFAULT, [], deflt_rhs)]
 
-  | debugIsOn, isAlgTyCon tycon, not (isOpenTyCon tycon), null (tyConDataCons tycon)
+  | debugIsOn, isAlgTyCon tycon
+  , null (tyConDataCons tycon)
+  , not (isFamilyTyCon tycon || isAbstractTyCon tycon)
        -- Check for no data constructors
-        -- This can legitimately happen for type families, so don't report that
+        -- This can legitimately happen for abstract types and type families,
+        -- so don't report that
   = pprTrace "prepareDefault" (ppr case_bndr <+> ppr tycon)
         $ return [(DEFAULT, [], deflt_rhs)]