Fix long-standing bug in CPR analysis
[ghc-hetmet.git] / ghc / compiler / stranal / DmdAnal.lhs
index f23802e..c5cfb7b 100644 (file)
@@ -13,26 +13,38 @@ module DmdAnal ( dmdAnalPgm, dmdAnalTopRhs,
 
 #include "HsVersions.h"
 
-import CmdLineOpts     ( DynFlags, DynFlag(..), opt_MaxWorkerArgs )
+import DynFlags                ( DynFlags, DynFlag(..) )
+import StaticFlags     ( opt_MaxWorkerArgs )
 import NewDemand       -- All of it
 import CoreSyn
 import PprCore 
-import CoreUtils       ( exprIsValue, exprArity )
+import CoreUtils       ( exprIsHNF, exprIsTrivial, exprArity )
 import DataCon         ( dataConTyCon )
 import TyCon           ( isProductTyCon, isRecursiveTyCon )
-import Id              ( Id, idType, idDemandInfo, idInlinePragma,
-                         isDataConId, isGlobalId, idArity,
-                         idNewStrictness, idNewStrictness_maybe, setIdNewStrictness,
-                         idNewDemandInfo, setIdNewDemandInfo, idName, idStrictness, idCprInfo )
-import IdInfo          ( newDemand, newStrictnessFromOld )
+import Id              ( Id, idType, idInlinePragma,
+                         isDataConWorkId, isGlobalId, idArity,
+#ifdef OLD_STRICTNESS
+                         idDemandInfo,  idStrictness, idCprInfo, idName,
+#endif
+                         idNewStrictness, idNewStrictness_maybe,
+                         setIdNewStrictness, idNewDemandInfo,
+                         idNewDemandInfo_maybe,
+                         setIdNewDemandInfo
+                       )
+#ifdef OLD_STRICTNESS
+import IdInfo          ( newStrictnessFromOld, newDemand )
+#endif
 import Var             ( Var )
 import VarEnv
+import TysWiredIn      ( unboxedPairDataCon )
+import TysPrim         ( realWorldStatePrimTy )
 import UniqFM          ( plusUFM_C, addToUFM_Directly, lookupUFM_Directly,
                          keysUFM, minusUFM, ufmToList, filterUFM )
-import Type            ( isUnLiftedType )
+import Type            ( isUnLiftedType, coreEqType )
 import CoreLint                ( showPass, endPass )
 import Util            ( mapAndUnzip, mapAccumL, mapAccumR, lengthIs )
-import BasicTypes      ( Arity, TopLevelFlag(..), isTopLevel, isNeverActive )
+import BasicTypes      ( Arity, TopLevelFlag(..), isTopLevel, isNeverActive,
+                         RecFlag(..), isRec )
 import Maybes          ( orElse, expectJust )
 import Outputable
 \end{code}
@@ -44,10 +56,6 @@ To think about
 * Consider f x = x+1 `fatbar` error (show x)
   We'd like to unbox x, even if that means reboxing it in the error case.
 
-\begin{code}
-instance Outputable TopLevelFlag where
-  ppr flag = empty
-\end{code}
 
 %************************************************************************
 %*                                                                     *
@@ -60,12 +68,14 @@ dmdAnalPgm :: DynFlags -> [CoreBind] -> IO [CoreBind]
 dmdAnalPgm dflags binds
   = do {
        showPass dflags "Demand analysis" ;
-       let { binds_plus_dmds = do_prog binds ;
-             dmd_changes = get_changes binds_plus_dmds } ;
+       let { binds_plus_dmds = do_prog binds } ;
+
        endPass dflags "Demand analysis" 
                Opt_D_dump_stranal binds_plus_dmds ;
-#ifdef DEBUG
-       -- Only if DEBUG is on, because only then is the old strictness analyser run
+#ifdef OLD_STRICTNESS
+       -- Only if OLD_STRICTNESS is on, because only then is the old
+       -- strictness analyser run
+       let { dmd_changes = get_changes binds_plus_dmds } ;
        printDump (text "Changes in demands" $$ dmd_changes) ;
 #endif
        return binds_plus_dmds
@@ -79,10 +89,11 @@ dmdAnalTopBind :: SigEnv
               -> (SigEnv, CoreBind)
 dmdAnalTopBind sigs (NonRec id rhs)
   = let
-       (    _, _, (_,   rhs1)) = dmdAnalRhs TopLevel sigs (id, rhs)
-       (sigs2, _, (id2, rhs2)) = dmdAnalRhs TopLevel sigs (id, rhs1)
+       (    _, _, (_,   rhs1)) = dmdAnalRhs TopLevel NonRecursive sigs (id, rhs)
+       (sigs2, _, (id2, rhs2)) = dmdAnalRhs TopLevel NonRecursive sigs (id, rhs1)
                -- Do two passes to improve CPR information
-               -- See the comments with mkSigTy.ignore_cpr_info below
+               -- See comments with ignore_cpr_info in mk_sig_ty
+               -- and with extendSigsWithLam
     in
     (sigs2, NonRec id2 rhs2)    
 
@@ -90,6 +101,7 @@ dmdAnalTopBind sigs (Rec pairs)
   = let
        (sigs', _, pairs')  = dmdFix TopLevel sigs pairs
                -- We get two iterations automatically
+               -- c.f. the NonRec case above
     in
     (sigs', Rec pairs')
 \end{code}
@@ -100,11 +112,18 @@ dmdAnalTopRhs :: CoreExpr -> (StrictSig, CoreExpr)
 --     a) appropriate strictness info
 --     b) the unfolding (decorated with stricntess info)
 dmdAnalTopRhs rhs
-  = (sig, rhs')
+  = (sig, rhs2)
   where
-    arity         = exprArity rhs
-    (rhs_ty, rhs') = dmdAnal emptySigEnv (vanillaCall arity) rhs
+    call_dmd      = vanillaCall (exprArity rhs)
+    (_,      rhs1) = dmdAnal emptySigEnv call_dmd rhs
+    (rhs_ty, rhs2) = dmdAnal emptySigEnv call_dmd rhs1
     sig                   = mkTopSigTy rhs rhs_ty
+       -- Do two passes; see notes with extendSigsWithLam
+       -- Otherwise we get bogus CPR info for constructors like
+       --      newtype T a = MkT a
+       -- The constructor looks like (\x::T a -> x), modulo the coerce
+       -- extendSigsWithLam will optimistically give x a CPR tag the 
+       -- first time, which is wrong in the end.
 \end{code}
 
 %************************************************************************
@@ -180,7 +199,8 @@ dmdAnal sigs dmd (Lam var body)
 
   | Call body_dmd <- dmd       -- A call demand: good!
   = let        
-       (body_ty, body') = dmdAnal sigs body_dmd body
+       sigs'            = extendSigsWithLam sigs var
+       (body_ty, body') = dmdAnal sigs' body_dmd body
        (lam_ty, var')   = annotateLamIdBndr body_ty var
     in
     (lam_ty, Lam var' body')
@@ -192,7 +212,7 @@ dmdAnal sigs dmd (Lam var body)
     in
     (deferType lam_ty, Lam var' body')
 
-dmdAnal sigs dmd (Case scrut case_bndr [alt@(DataAlt dc,bndrs,rhs)])
+dmdAnal sigs dmd (Case scrut case_bndr ty [alt@(DataAlt dc,bndrs,rhs)])
   | let tycon = dataConTyCon dc,
     isProductTyCon tycon,
     not (isRecursiveTyCon tycon)
@@ -201,7 +221,7 @@ dmdAnal sigs dmd (Case scrut case_bndr [alt@(DataAlt dc,bndrs,rhs)])
        (alt_ty, alt')        = dmdAnalAlt sigs_alt dmd alt
        (alt_ty1, case_bndr') = annotateBndr alt_ty case_bndr
        (_, bndrs', _)        = alt'
-       case_bndr_sig         = StrictSig (mkDmdType emptyVarEnv [] RetCPR)
+       case_bndr_sig         = cprSig
                -- Inside the alternative, the case binder has the CPR property.
                -- Meaning that a case on it will successfully cancel.
                -- Example:
@@ -238,36 +258,36 @@ dmdAnal sigs dmd (Case scrut case_bndr [alt@(DataAlt dc,bndrs,rhs)])
 
        (scrut_ty, scrut') = dmdAnal sigs scrut_dmd scrut
     in
-    (alt_ty1 `bothType` scrut_ty, Case scrut' case_bndr' [alt'])
+    (alt_ty1 `bothType` scrut_ty, Case scrut' case_bndr' ty [alt'])
 
-dmdAnal sigs dmd (Case scrut case_bndr alts)
+dmdAnal sigs dmd (Case scrut case_bndr ty alts)
   = let
        (alt_tys, alts')        = mapAndUnzip (dmdAnalAlt sigs dmd) alts
        (scrut_ty, scrut')      = dmdAnal sigs evalDmd scrut
        (alt_ty, case_bndr')    = annotateBndr (foldr1 lubType alt_tys) case_bndr
     in
 --    pprTrace "dmdAnal:Case" (ppr alts $$ ppr alt_tys)
-    (alt_ty `bothType` scrut_ty, Case scrut' case_bndr' alts')
+    (alt_ty `bothType` scrut_ty, Case scrut' case_bndr' ty alts')
 
 dmdAnal sigs dmd (Let (NonRec id rhs) body) 
   = let
-       (sigs', lazy_fv, (id1, rhs')) = dmdAnalRhs NotTopLevel sigs (id, rhs)
+       (sigs', lazy_fv, (id1, rhs')) = dmdAnalRhs NotTopLevel NonRecursive sigs (id, rhs)
        (body_ty, body')              = dmdAnal sigs' dmd body
        (body_ty1, id2)               = annotateBndr body_ty id1
        body_ty2                      = addLazyFVs body_ty1 lazy_fv
     in
-#ifdef DEBUG
-       -- If the actual demand is better than the vanilla
-       -- demand, we might do better to re-analyse with the
-       -- stronger demand.
-    (let vanilla_dmd = vanillaCall (idArity id)
-        actual_dmd  = idNewDemandInfo id2
-     in
-     if actual_dmd `betterDemand` vanilla_dmd && actual_dmd /= vanilla_dmd then
-       pprTrace "dmdLet: better demand" (ppr id <+> vcat [text "vanilla" <+> ppr vanilla_dmd,
-                                                          text "actual" <+> ppr actual_dmd])
-     else \x -> x)
-#endif
+       -- If the actual demand is better than the vanilla call
+       -- demand, you might think that we might do better to re-analyse 
+       -- the RHS with the stronger demand.
+       -- But (a) That seldom happens, because it means that *every* path in 
+       --         the body of the let has to use that stronger demand
+       -- (b) It often happens temporarily in when fixpointing, because
+       --     the recursive function at first seems to place a massive demand.
+       --     But we don't want to go to extra work when the function will
+       --     probably iterate to something less demanding.  
+       -- In practice, all the times the actual demand on id2 is more than
+       -- the vanilla call demand seem to be due to (b).  So we don't
+       -- bother to re-analyse the RHS.
     (body_ty2, Let (NonRec id2 rhs') body')    
 
 dmdAnal sigs dmd (Let (Rec pairs) body) 
@@ -292,8 +312,30 @@ dmdAnalAlt sigs dmd (con,bndrs,rhs)
   = let 
        (rhs_ty, rhs')   = dmdAnal sigs dmd rhs
        (alt_ty, bndrs') = annotateBndrs rhs_ty bndrs
-    in
-    (alt_ty, (con, bndrs', rhs'))
+       final_alt_ty | io_hack_reqd = alt_ty `lubType` topDmdType
+                    | otherwise    = alt_ty
+
+       -- There's a hack here for I/O operations.  Consider
+       --      case foo x s of { (# s, r #) -> y }
+       -- Is this strict in 'y'.  Normally yes, but what if 'foo' is an I/O
+       -- operation that simply terminates the program (not in an erroneous way)?
+       -- In that case we should not evaluate y before the call to 'foo'.
+       -- Hackish solution: spot the IO-like situation and add a virtual branch,
+       -- as if we had
+       --      case foo x s of 
+       --         (# s, r #) -> y 
+       --         other      -> return ()
+       -- So the 'y' isn't necessarily going to be evaluated
+       --
+       -- A more complete example where this shows up is:
+       --      do { let len = <expensive> ;
+       --         ; when (...) (exitWith ExitSuccess)
+       --         ; print len }
+
+       io_hack_reqd = con == DataAlt unboxedPairDataCon &&
+                      idType (head bndrs) `coreEqType` realWorldStatePrimTy
+    in 
+    (final_alt_ty, (con, bndrs', rhs'))
 \end{code}
 
 %************************************************************************
@@ -313,26 +355,34 @@ dmdFix top_lvl sigs orig_pairs
   = loop 1 initial_sigs orig_pairs
   where
     bndrs        = map fst orig_pairs
-    initial_sigs = extendSigEnvList sigs [(id, (initial_sig id, top_lvl)) | id <- bndrs]
+    initial_sigs = extendSigEnvList sigs [(id, (initialSig id, top_lvl)) | id <- bndrs]
     
     loop :: Int
         -> SigEnv                      -- Already contains the current sigs
         -> [(Id,CoreExpr)]             
         -> (SigEnv, DmdEnv, [(Id,CoreExpr)])
     loop n sigs pairs
-      | all (same_sig sigs sigs') bndrs 
+      | found_fixpoint
       = (sigs', lazy_fv, pairs')
                -- Note: use pairs', not pairs.   pairs' is the result of 
                -- processing the RHSs with sigs (= sigs'), whereas pairs 
                -- is the result of processing the RHSs with the *previous* 
                -- iteration of sigs.
-      | n >= 10       = pprTrace "dmdFix loop" (ppr n <+> (vcat 
+
+      | n >= 10  = pprTrace "dmdFix loop" (ppr n <+> (vcat 
                                [ text "Sigs:" <+> ppr [(id,lookup sigs id, lookup sigs' id) | (id,_) <- pairs],
                                  text "env:" <+> ppr (ufmToList sigs),
                                  text "binds:" <+> pprCoreBinding (Rec pairs)]))
-                             (emptySigEnv, emptyDmdEnv, orig_pairs)    -- Safe output
+                             (emptySigEnv, lazy_fv, orig_pairs)        -- Safe output
+                       -- The lazy_fv part is really important!  orig_pairs has no strictness
+                       -- info, including nothing about free vars.  But if we have
+                       --      letrec f = ....y..... in ...f...
+                       -- where 'y' is free in f, we must record that y is mentioned, 
+                       -- otherwise y will get recorded as absent altogether
+
       | otherwise    = loop (n+1) sigs' pairs'
       where
+       found_fixpoint = all (same_sig sigs sigs') bndrs 
                -- Use the new signature to do the next pair
                -- The occurrence analyser has arranged them in a good order
                -- so this can significantly reduce the number of iterations needed
@@ -345,36 +395,38 @@ dmdFix top_lvl sigs orig_pairs
          ((sigs', lazy_fv'), pair')
          --     )
        where
-         (sigs', lazy_fv1, pair') = dmdAnalRhs top_lvl sigs (id,rhs)
+         (sigs', lazy_fv1, pair') = dmdAnalRhs top_lvl Recursive sigs (id,rhs)
          lazy_fv'                 = plusUFM_C both lazy_fv lazy_fv1   
          -- old_sig               = lookup sigs id
          -- new_sig               = lookup sigs' id
           
+    same_sig sigs sigs' var = lookup sigs var == lookup sigs' var
+    lookup sigs var = case lookupVarEnv sigs var of
+                       Just (sig,_) -> sig
+
        -- Get an initial strictness signature from the Id
        -- itself.  That way we make use of earlier iterations
        -- of the fixpoint algorithm.  (Cunning plan.)
        -- Note that the cunning plan extends to the DmdEnv too,
        -- since it is part of the strictness signature
-    initial_sig id = idNewStrictness_maybe id `orElse` botSig
+initialSig id = idNewStrictness_maybe id `orElse` botSig
 
-    same_sig sigs sigs' var = lookup sigs var == lookup sigs' var
-    lookup sigs var = case lookupVarEnv sigs var of
-                       Just (sig,_) -> sig
-
-dmdAnalRhs :: TopLevelFlag 
+dmdAnalRhs :: TopLevelFlag -> RecFlag
        -> SigEnv -> (Id, CoreExpr)
        -> (SigEnv,  DmdEnv, (Id, CoreExpr))
 -- Process the RHS of the binding, add the strictness signature
 -- to the Id, and augment the environment with the signature as well.
 
-dmdAnalRhs top_lvl sigs (id, rhs)
+dmdAnalRhs top_lvl rec_flag sigs (id, rhs)
  = (sigs', lazy_fv, (id', rhs'))
  where
   arity                     = idArity id   -- The idArity should be up to date
                                    -- The simplifier was run just beforehand
   (rhs_dmd_ty, rhs') = dmdAnal sigs (vanillaCall arity) rhs
-  (lazy_fv, sig_ty)  = WARN( arity /= dmdTypeDepth rhs_dmd_ty, ppr id )
-                      mkSigTy id rhs rhs_dmd_ty
+  (lazy_fv, sig_ty)  = WARN( arity /= dmdTypeDepth rhs_dmd_ty && not (exprIsTrivial rhs), ppr id )
+                               -- The RHS can be eta-reduced to just a variable, 
+                               -- in which case we should not complain. 
+                      mkSigTy top_lvl rec_flag id rhs rhs_dmd_ty
   id'               = id `setIdNewStrictness` sig_ty
   sigs'                     = extendSigEnv top_lvl sigs id sig_ty
 \end{code}
@@ -391,12 +443,93 @@ mkTopSigTy :: CoreExpr -> DmdType -> StrictSig
        -- NB: not used for never-inline things; hence False
 mkTopSigTy rhs dmd_ty = snd (mk_sig_ty False False rhs dmd_ty)
 
-mkSigTy :: Id -> CoreExpr -> DmdType -> (DmdEnv, StrictSig)
-mkSigTy id rhs dmd_ty = mk_sig_ty (isNeverActive (idInlinePragma id))
-                                 (isStrictDmd (idNewDemandInfo id))
-                                 rhs dmd_ty
+mkSigTy :: TopLevelFlag -> RecFlag -> Id -> CoreExpr -> DmdType -> (DmdEnv, StrictSig)
+mkSigTy top_lvl rec_flag id rhs dmd_ty 
+  = mk_sig_ty never_inline thunk_cpr_ok rhs dmd_ty
+  where
+    never_inline = isNeverActive (idInlinePragma id)
+    maybe_id_dmd = idNewDemandInfo_maybe id
+       -- Is Nothing the first time round
+
+    thunk_cpr_ok
+       | isTopLevel top_lvl       = False      -- Top level things don't get
+                                               -- their demandInfo set at all
+       | isRec rec_flag           = False      -- Ditto recursive things
+       | Just dmd <- maybe_id_dmd = isStrictDmd dmd
+       | otherwise                = True       -- Optimistic, first time round
+                                               -- See notes below
+\end{code}
 
-mk_sig_ty never_inline strictly_demanded rhs (DmdType fv dmds res) 
+The thunk_cpr_ok stuff [CPR-AND-STRICTNESS]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If the rhs is a thunk, we usually forget the CPR info, because
+it is presumably shared (else it would have been inlined, and 
+so we'd lose sharing if w/w'd it into a function.
+
+However, if the strictness analyser has figured out (in a previous 
+iteration) that it's strict, then we DON'T need to forget the CPR info.
+Instead we can retain the CPR info and do the thunk-splitting transform 
+(see WorkWrap.splitThunk).
+
+This made a big difference to PrelBase.modInt, which had something like
+       modInt = \ x -> let r = ... -> I# v in
+                       ...body strict in r...
+r's RHS isn't a value yet; but modInt returns r in various branches, so
+if r doesn't have the CPR property then neither does modInt
+Another case I found in practice (in Complex.magnitude), looks like this:
+               let k = if ... then I# a else I# b
+               in ... body strict in k ....
+(For this example, it doesn't matter whether k is returned as part of
+the overall result; but it does matter that k's RHS has the CPR property.)  
+Left to itself, the simplifier will make a join point thus:
+               let $j k = ...body strict in k...
+               if ... then $j (I# a) else $j (I# b)
+With thunk-splitting, we get instead
+               let $j x = let k = I#x in ...body strict in k...
+               in if ... then $j a else $j b
+This is much better; there's a good chance the I# won't get allocated.
+
+The difficulty with this is that we need the strictness type to
+look at the body... but we now need the body to calculate the demand
+on the variable, so we can decide whether its strictness type should
+have a CPR in it or not.  Simple solution: 
+       a) use strictness info from the previous iteration
+       b) make sure we do at least 2 iterations, by doing a second
+          round for top-level non-recs.  Top level recs will get at
+          least 2 iterations except for totally-bottom functions
+          which aren't very interesting anyway.
+
+NB: strictly_demanded is never true of a top-level Id, or of a recursive Id.
+
+The Nothing case in thunk_cpr_ok [CPR-AND-STRICTNESS]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Demand info now has a 'Nothing' state, just like strictness info.
+The analysis works from 'dangerous' towards a 'safe' state; so we 
+start with botSig for 'Nothing' strictness infos, and we start with
+"yes, it's demanded" for 'Nothing' in the demand info.  The
+fixpoint iteration will sort it all out.
+
+We can't start with 'not-demanded' because then consider
+       f x = let 
+                 t = ... I# x
+             in
+             if ... then t else I# y else f x'
+
+In the first iteration we'd have no demand info for x, so assume
+not-demanded; then we'd get TopRes for f's CPR info.  Next iteration
+we'd see that t was demanded, and so give it the CPR property, but by
+now f has TopRes, so it will stay TopRes.  Instead, with the Nothing
+setting the first time round, we say 'yes t is demanded' the first
+time.
+
+However, this does mean that for non-recursive bindings we must
+iterate twice to be sure of not getting over-optimistic CPR info,
+in the case where t turns out to be not-demanded.  This is handled
+by dmdAnalTopBind.
+
+
+\begin{code}
+mk_sig_ty never_inline thunk_cpr_ok rhs (DmdType fv dmds res) 
   | never_inline && not (isBotRes res)
        --                      HACK ALERT
        -- Don't strictness-analyse NOINLINE things.  Why not?  Because
@@ -467,41 +600,7 @@ mk_sig_ty never_inline strictly_demanded rhs (DmdType fv dmds res)
     res' = case res of
                RetCPR | ignore_cpr_info -> TopRes
                other                    -> res
-    ignore_cpr_info = is_thunk && not strictly_demanded
-    is_thunk       = not (exprIsValue rhs)
-       -- If the rhs is a thunk, we forget the CPR info, because
-       -- it is presumably shared (else it would have been inlined, and 
-       -- so we'd lose sharing if w/w'd it into a function.
-       --
-       -- Also, if the strictness analyser has figured out (in a previous iteration)
-       -- that it's strict, the let-to-case transformation will happen, so again 
-       -- it's good.
-       -- This made a big difference to PrelBase.modInt, which had something like
-       --      modInt = \ x -> let r = ... -> I# v in
-       --                      ...body strict in r...
-       -- r's RHS isn't a value yet; but modInt returns r in various branches, so
-       -- if r doesn't have the CPR property then neither does modInt
-       -- Another case I found in practice (in Complex.magnitude), looks like this:
-       --              let k = if ... then I# a else I# b
-       --              in ... body strict in k ....
-       -- (For this example, it doesn't matter whether k is returned as part of
-       -- the overall result.)  Left to itself, the simplifier will make a join
-       -- point thus:
-       --              let $j k = ...body strict in k...
-       --              if ... then $j (I# a) else $j (I# b)
-       -- 
-       --
-       -- The difficulty with this is that we need the strictness type to
-       -- look at the body... but we now need the body to calculate the demand
-       -- on the variable, so we can decide whether its strictness type should
-       -- have a CPR in it or not.  Simple solution: 
-       --      a) use strictness info from the previous iteration
-       --      b) make sure we do at least 2 iterations, by doing a second
-       --         round for top-level non-recs.  Top level recs will get at
-       --         least 2 iterations except for totally-bottom functions
-       --         which aren't very interesting anyway.
-       --
-       -- NB: strictly_demanded is never true of a top-level Id, or of a recursive Id.
+    ignore_cpr_info = not (exprIsHNF rhs || thunk_cpr_ok)
 \end{code}
 
 The unpack strategy determines whether we'll *really* unpack the argument,
@@ -657,6 +756,31 @@ extendSigEnv top_lvl env var sig = extendVarEnv env var (sig, top_lvl)
 
 extendSigEnvList = extendVarEnvList
 
+extendSigsWithLam :: SigEnv -> Id -> SigEnv
+-- Extend the SigEnv when we meet a lambda binder
+-- If the binder is marked demanded with a product demand, then give it a CPR 
+-- signature, because in the likely event that this is a lambda on a fn defn 
+-- [we only use this when the lambda is being consumed with a call demand],
+-- it'll be w/w'd and so it will be CPR-ish.  E.g.
+--     f = \x::(Int,Int).  if ...strict in x... then
+--                             x
+--                         else
+--                             (a,b)
+-- We want f to have the CPR property because x does, by the time f has been w/w'd
+--
+-- Also note that we only want to do this for something that
+-- definitely has product type, else we may get over-optimistic 
+-- CPR results (e.g. from \x -> x!).
+
+extendSigsWithLam sigs id
+  = case idNewDemandInfo_maybe id of
+       Nothing               -> extendVarEnv sigs id (cprSig, NotTopLevel)
+               -- Optimistic in the Nothing case;
+               -- See notes [CPR-AND-STRICTNESS]
+       Just (Eval (Prod ds)) -> extendVarEnv sigs id (cprSig, NotTopLevel)
+       other                 -> sigs
+
+
 dmdTransform :: SigEnv         -- The strictness environment
             -> Id              -- The function
             -> Demand          -- The demand on the function
@@ -667,7 +791,7 @@ dmdTransform :: SigEnv              -- The strictness environment
 dmdTransform sigs var dmd
 
 ------         DATA CONSTRUCTOR
-  | isDataConId var            -- Data constructor
+  | isDataConWorkId var                -- Data constructor
   = let 
        StrictSig dmd_ty    = idNewStrictness var       -- It must have a strictness sig
        DmdType _ _ con_res = dmd_ty
@@ -763,26 +887,15 @@ argDemand (Defer d) = lazyDmd
 argDemand (Eval ds) = Eval (mapDmds argDemand ds)
 argDemand (Box Bot) = evalDmd
 argDemand (Box d)   = box (argDemand d)
-argDemand Bot      = Abs       -- Don't pass args that are consumed by bottom/err
+argDemand Bot      = Abs       -- Don't pass args that are consumed (only) by bottom
 argDemand d        = d
 \end{code}
 
 \begin{code}
-betterStrictness :: StrictSig -> StrictSig -> Bool
-betterStrictness (StrictSig t1) (StrictSig t2) = betterDmdType t1 t2
-
-betterDmdType t1 t2 = (t1 `lubType` t2) == t2
-
-betterDemand :: Demand -> Demand -> Bool
--- If d1 `better` d2, and d2 `better` d2, then d1==d2
-betterDemand d1 d2 = (d1 `lub` d2) == d2
-\end{code}
-
-\begin{code}
 -------------------------
 -- Consider (if x then y else []) with demand V
 -- Then the first branch gives {y->V} and the second
--- *implicitly* has {y->A}.  So we must put {y->(V `lub` A)}
+--  *implicitly* has {y->A}.  So we must put {y->(V `lub` A)}
 -- in the result env.
 lubType (DmdType fv1 ds1 r1) (DmdType fv2 ds2 r2)
   = DmdType lub_fv2 (lub_ds ds1 ds2) (r1 `lubRes` r2)
@@ -886,7 +999,7 @@ lubs = zipWithDmds lub
 box (Call d)  = Call d -- The odd man out.  Why?
 box (Box d)   = Box d
 box (Defer _) = lazyDmd
-box Top      = lazyDmd -- Box Abs and Box Top
+box Top       = lazyDmd        -- Box Abs and Box Top
 box Abs       = lazyDmd        -- are the same <B,L>
 box d        = Box d   -- Bot, Eval
 
@@ -996,6 +1109,7 @@ boths = zipWithDmds both
 
 
 \begin{code}
+#ifdef OLD_STRICTNESS
 get_changes binds = vcat (map get_changes_bind binds)
 
 get_changes_bind (Rec pairs) = vcat (map get_changes_pr pairs)
@@ -1048,6 +1162,15 @@ get_changes_dmd id
     new_better = new `betterDemand` old 
     old_better = old `betterDemand` new
 
+betterStrictness :: StrictSig -> StrictSig -> Bool
+betterStrictness (StrictSig t1) (StrictSig t2) = betterDmdType t1 t2
+
+betterDmdType t1 t2 = (t1 `lubType` t2) == t2
+
+betterDemand :: Demand -> Demand -> Bool
+-- If d1 `better` d2, and d2 `better` d2, then d1==d2
+betterDemand d1 d2 = (d1 `lub` d2) == d2
+
 squashSig (StrictSig (DmdType fv ds res))
   = StrictSig (DmdType emptyDmdEnv (map squashDmd ds) res)
   where
@@ -1058,4 +1181,5 @@ squashDmd (Box d)    = Box (squashDmd d)
 squashDmd (Eval ds)  = Eval (mapDmds squashDmd ds)
 squashDmd (Defer ds) = Defer (mapDmds squashDmd ds)
 squashDmd d          = d
+#endif
 \end{code}