remove empty dir
[ghc-hetmet.git] / ghc / compiler / stranal / DmdAnal.lhs
index aa26c74..c5cfb7b 100644 (file)
@@ -7,33 +7,46 @@
                        -----------------
 
 \begin{code}
-module DmdAnal ( dmdAnalPgm ) where
+module DmdAnal ( dmdAnalPgm, dmdAnalTopRhs, 
+                both {- needed by WwLib -}
+   ) where
 
 #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 CoreUtils       ( exprIsValue, exprArity )
+import PprCore 
+import CoreUtils       ( exprIsHNF, exprIsTrivial, exprArity )
 import DataCon         ( dataConTyCon )
 import TyCon           ( isProductTyCon, isRecursiveTyCon )
-import Id              ( Id, idType, idInfo, idArity, idCprInfo, idDemandInfo,
-                         modifyIdInfo, isDataConId, isImplicitId, isGlobalId,
-                         idNewStrictness, idNewStrictness_maybe, getNewStrictness, setIdNewStrictness,
-                         idNewDemandInfo, setIdNewDemandInfo, newStrictnessFromOld )
-import IdInfo          ( newDemand )
+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 ErrUtils                ( dumpIfSet_dyn )
-import Util            ( mapAndUnzip, mapAccumL, mapAccumR, zipWithEqual )
-import BasicTypes      ( Arity, TopLevelFlag(..), isTopLevel )
+import Util            ( mapAndUnzip, mapAccumL, mapAccumR, lengthIs )
+import BasicTypes      ( Arity, TopLevelFlag(..), isTopLevel, isNeverActive,
+                         RecFlag(..), isRec )
 import Maybes          ( orElse, expectJust )
 import Outputable
-import FastTypes
 \end{code}
 
 To think about
@@ -43,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}
 
 %************************************************************************
 %*                                                                     *
@@ -59,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
@@ -77,21 +88,43 @@ dmdAnalTopBind :: SigEnv
               -> CoreBind 
               -> (SigEnv, CoreBind)
 dmdAnalTopBind sigs (NonRec id rhs)
-  | isImplicitId id            -- Don't touch the info on constructors, selectors etc
-  = (sigs, NonRec id rhs)      -- It's pre-computed in MkId.lhs
-  | otherwise
   = let
-       (sigs', _, (id', rhs')) = downRhs TopLevel sigs (id, rhs)
+       (    _, _, (_,   rhs1)) = dmdAnalRhs TopLevel NonRecursive sigs (id, rhs)
+       (sigs2, _, (id2, rhs2)) = dmdAnalRhs TopLevel NonRecursive sigs (id, rhs1)
+               -- Do two passes to improve CPR information
+               -- See comments with ignore_cpr_info in mk_sig_ty
+               -- and with extendSigsWithLam
     in
-    (sigs', NonRec id' rhs')    
+    (sigs2, NonRec id2 rhs2)    
 
 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}
 
+\begin{code}
+dmdAnalTopRhs :: CoreExpr -> (StrictSig, CoreExpr)
+-- Analyse the RHS and return
+--     a) appropriate strictness info
+--     b) the unfolding (decorated with stricntess info)
+dmdAnalTopRhs rhs
+  = (sig, rhs2)
+  where
+    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}
 
 %************************************************************************
 %*                                                                     *
@@ -104,10 +137,12 @@ dmdAnal :: SigEnv -> Demand -> CoreExpr -> (DmdType, CoreExpr)
 
 dmdAnal sigs Abs  e = (topDmdType, e)
 
-dmdAnal sigs Lazy e = let 
-                       (res_ty, e') = dmdAnal sigs Eval e
-                     in
-                     (deferType res_ty, e')
+dmdAnal sigs dmd e 
+  | not (isStrictDmd dmd)
+  = let 
+       (res_ty, e') = dmdAnal sigs evalDmd e
+    in
+    (deferType res_ty, e')
        -- It's important not to analyse e with a lazy demand because
        -- a) When we encounter   case s of (a,b) -> 
        --      we demand s with U(d1d2)... but if the overall demand is lazy
@@ -118,6 +153,9 @@ dmdAnal sigs Lazy e = let
        --    We still want to mark x as demanded, because it will be when we
        --    enter the let.  If we analyse f's arg with a Lazy demand, we'll
        --    just mark x as Lazy
+       -- c) The application rule wouldn't be right either
+       --    Evaluating (f x) in a L demand does *not* cause
+       --    evaluation of f in a C(L) demand!
 
 
 dmdAnal sigs dmd (Lit lit)
@@ -131,18 +169,20 @@ dmdAnal sigs dmd (Note n e)
   where
     (dmd_ty, e') = dmdAnal sigs dmd' e 
     dmd' = case n of
-            Coerce _ _ -> Eval   -- This coerce usually arises from a recursive
-            other      -> dmd    -- newtype, and we don't want to look inside them
-                                 -- for exactly the same reason that we don't look
-                                 -- inside recursive products -- we might not reach
-                                 -- a fixpoint.  So revert to a vanilla Eval demand
+            Coerce _ _ -> evalDmd  -- This coerce usually arises from a recursive
+            other      -> dmd      -- newtype, and we don't want to look inside them
+                                   -- for exactly the same reason that we don't look
+                                   -- inside recursive products -- we might not reach
+                                   -- a fixpoint.  So revert to a vanilla Eval demand
 
 dmdAnal sigs dmd (App fun (Type ty))
   = (fun_ty, App fun' (Type ty))
   where
     (fun_ty, fun') = dmdAnal sigs dmd fun
 
-dmdAnal sigs dmd (App fun arg) -- Non-type arguments
+-- Lots of the other code is there to make this
+-- beautiful, compositional, application rule :-)
+dmdAnal sigs dmd e@(App fun arg)       -- Non-type arguments
   = let                                -- [Type arg handled above]
        (fun_ty, fun')    = dmdAnal sigs (Call dmd) fun
        (arg_ty, arg')    = dmdAnal sigs arg_dmd arg
@@ -159,61 +199,95 @@ 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')
 
   | otherwise  -- Not enough demand on the lambda; but do the body
   = let                -- anyway to annotate it and gather free var info
-       (body_ty, body') = dmdAnal sigs Eval body
+       (body_ty, body') = dmdAnal sigs evalDmd body
        (lam_ty, var')   = annotateLamIdBndr body_ty var
     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)
   = let
-       bndr_ids                 = filter isId bndrs
-       (alt_ty, alt')           = dmdAnalAlt sigs dmd alt
-       (alt_ty1, case_bndr')    = annotateBndr alt_ty case_bndr
-       (_, bndrs', _)           = alt'
-
-       -- Figure out whether the case binder is used, and use
-       -- that to set the keepity of the demand.  This is utterly essential.
+       sigs_alt              = extendSigEnv NotTopLevel sigs case_bndr case_bndr_sig
+       (alt_ty, alt')        = dmdAnalAlt sigs_alt dmd alt
+       (alt_ty1, case_bndr') = annotateBndr alt_ty case_bndr
+       (_, bndrs', _)        = alt'
+       case_bndr_sig         = cprSig
+               -- Inside the alternative, the case binder has the CPR property.
+               -- Meaning that a case on it will successfully cancel.
+               -- Example:
+               --      f True  x = case x of y { I# x' -> if x' ==# 3 then y else I# 8 }
+               --      f False x = I# 3
+               --      
+               -- We want f to have the CPR property:
+               --      f b x = case fw b x of { r -> I# r }
+               --      fw True  x = case x of y { I# x' -> if x' ==# 3 then x' else 8 }
+               --      fw False x = 3
+
+       -- Figure out whether the demand on the case binder is used, and use
+       -- that to set the scrut_dmd.  This is utterly essential.
        -- Consider     f x = case x of y { (a,b) -> k y a }
        -- If we just take scrut_demand = U(L,A), then we won't pass x to the
        -- worker, so the worker will rebuild 
        --      x = (a, absent-error)
        -- and that'll crash.
-       dead_case_bndr           = isAbsentDmd (idNewDemandInfo case_bndr')
-       keepity | dead_case_bndr = Drop
-               | otherwise      = Keep         
-
-        scrut_dmd               = Seq keepity Now [idNewDemandInfo b | b <- bndrs', isId b]
-       (scrut_ty, scrut')       = dmdAnal sigs scrut_dmd scrut
+       -- So at one stage I had:
+       --      dead_case_bndr           = isAbsentDmd (idNewDemandInfo case_bndr')
+       --      keepity | dead_case_bndr = Drop
+       --              | otherwise      = Keep         
+       --
+       -- But then consider
+       --      case x of y { (a,b) -> h y + a }
+       -- where h : U(LL) -> T
+       -- The above code would compute a Keep for x, since y is not Abs, which is silly
+       -- The insight is, of course, that a demand on y is a demand on the
+       -- scrutinee, so we need to `both` it with the scrut demand
+
+        scrut_dmd         = Eval (Prod [idNewDemandInfo b | b <- bndrs', isId b])
+                                  `both`
+                            idNewDemandInfo case_bndr'
+
+       (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 Eval scrut
+       (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')) = downRhs 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
---    pprTrace "dmdLet" (ppr id <+> ppr (sig,rhs_env))
+       -- 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) 
@@ -238,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}
 
 %************************************************************************
@@ -255,29 +351,38 @@ dmdFix :: TopLevelFlag
        -> (SigEnv, DmdEnv,
           [(Id,CoreExpr)])     -- Binders annotated with stricness info
 
-dmdFix top_lvl sigs pairs
-  = loop 1 initial_sigs pairs
+dmdFix top_lvl sigs orig_pairs
+  = loop 1 initial_sigs orig_pairs
   where
-    bndrs        = map fst pairs
-    initial_sigs = extendSigEnvList sigs [(id, (initial_sig id, top_lvl)) | id <- bndrs]
+    bndrs        = map fst orig_pairs
+    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 = (sigs', lazy_fv, pairs')
+      | 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 >= 5             = pprTrace "dmdFix" (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:" <+> ppr pairs]))
-                             (loop (n+1) sigs' pairs')
-      | otherwise          = {- pprTrace "dmdFixLoop" (ppr id_sigs) -} (loop (n+1) sigs' pairs')
+                                 text "binds:" <+> pprCoreBinding (Rec pairs)]))
+                             (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
@@ -290,36 +395,40 @@ dmdFix top_lvl sigs pairs
          ((sigs', lazy_fv'), pair')
          --     )
        where
-         (sigs', lazy_fv1, pair') = downRhs 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
+         -- 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
-
-    same_sig sigs sigs' var = lookup sigs var == lookup sigs' var
-    lookup sigs var = case lookupVarEnv sigs var of
-                       Just (sig,_) -> sig
+initialSig id = idNewStrictness_maybe id `orElse` botSig
 
-downRhs :: 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.
 
-downRhs top_lvl sigs (id, rhs)
+dmdAnalRhs top_lvl rec_flag sigs (id, rhs)
  = (sigs', lazy_fv, (id', rhs'))
  where
-  arity                    = exprArity rhs   -- The idArity may not be up to date
-  (rhs_ty, rhs')    = dmdAnal sigs (vanillaCall arity) rhs
-  (lazy_fv, sig_ty) = mkSigTy id arity rhs rhs_ty
-  id'              = id `setIdNewStrictness` sig_ty
-  sigs'                    = extendSigEnv top_lvl sigs id sig_ty
+  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 && 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}
 
 %************************************************************************
@@ -329,12 +438,129 @@ downRhs top_lvl sigs (id, rhs)
 %************************************************************************
 
 \begin{code}
-mkSigTy :: Id -> Arity -> CoreExpr -> DmdType -> (DmdEnv, StrictSig)
--- Take a DmdType and turn it into a StrictSig
-mkSigTy id arity rhs (DmdType fv dmds res) 
-  = (lazy_fv, mkStrictSig id arity dmd_ty)
+mkTopSigTy :: CoreExpr -> DmdType -> StrictSig
+       -- Take a DmdType and turn it into a StrictSig
+       -- NB: not used for never-inline things; hence False
+mkTopSigTy rhs dmd_ty = snd (mk_sig_ty False False 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}
+
+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
+       -- the NOINLINE says "don't expose any of the inner workings at the call 
+       -- site" and the strictness is certainly an inner working.
+       --
+       -- More concretely, the demand analyser discovers the following strictness
+       -- for unsafePerformIO:  C(U(AV))
+       -- But then consider
+       --      unsafePerformIO (\s -> let r = f x in 
+       --                             case writeIORef v r s of (# s1, _ #) ->
+       --                             (# s1, r #)
+       -- The strictness analyser will find that the binding for r is strict,
+       -- (becuase of uPIO's strictness sig), and so it'll evaluate it before 
+       -- doing the writeIORef.  This actually makes tests/lib/should_run/memo002
+       -- get a deadlock!  
+       --
+       -- Solution: don't expose the strictness of unsafePerformIO.
+       --
+       -- But we do want to expose the strictness of error functions, 
+       -- which are also often marked NOINLINE
+       --      {-# NOINLINE foo #-}
+       --      foo x = error ("wubble buggle" ++ x)
+       -- So (hack, hack) we only drop the strictness for non-bottom things
+       -- This is all very unsatisfactory.
+  = (deferEnv fv, topSig)
+
+  | otherwise
+  = (lazy_fv, mkStrictSig dmd_ty)
   where
-    dmd_ty = DmdType strict_fv lazified_dmds res'
+    dmd_ty = DmdType strict_fv final_dmds res'
 
     lazy_fv   = filterUFM (not . isStrictDmd) fv
     strict_fv = filterUFM isStrictDmd         fv
@@ -368,28 +594,13 @@ mkSigTy id arity rhs (DmdType fv dmds res)
        -- DmdType, because that makes fixpointing very slow --- the 
        -- DmdType gets full of lazy demands that are slow to converge.
 
-    lazified_dmds = map lazify dmds
-       -- Get rid of defers in the arguments
-    final_dmds = setUnpackStrategy lazified_dmds
+    final_dmds = setUnpackStrategy dmds
        -- Set the unpacking strategy
        
-    res' = case (dmds, res) of
-               ([], RetCPR) | not (exprIsValue rhs) -> TopRes
-               other                                -> res
-       -- 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.
-       --
-       --      DONE IN OLD CPR ANALYSER, BUT NOT YET HERE
-       -- Also, if the strictness analyser has figured out that it's strict,
-       -- the let-to-case transformation will happen, so again it's good.
-       -- (CPR analysis runs before the simplifier has had a chance to do
-       --  the let-to-case transform.)
-       -- 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
+    res' = case res of
+               RetCPR | ignore_cpr_info -> TopRes
+               other                    -> res
+    ignore_cpr_info = not (exprIsHNF rhs || thunk_cpr_ok)
 \end{code}
 
 The unpack strategy determines whether we'll *really* unpack the argument,
@@ -405,15 +616,13 @@ setUnpackStrategy ds
        -> [Demand]
        -> (Int, [Demand])      -- Args remaining after subcomponents of [Demand] are unpacked
 
-    go n (Seq keep _ cs : ds) 
-       | n' >= 0    = Seq keep Now cs' `cons` go n'' ds
-        | otherwise  = Eval `cons` go n ds
+    go n (Eval (Prod cs) : ds) 
+       | n' >= 0   = Eval (Prod cs') `cons` go n'' ds
+        | otherwise = Box (Eval (Prod cs)) `cons` go n ds
        where
          (n'',cs') = go n' cs
-         n' = n + box - non_abs_args
-         box = case keep of
-                  Keep -> 0
-                  Drop -> 1    -- Add one to the budget if we drop the top-level arg
+         n' = n + 1 - non_abs_args
+               -- Add one to the budget 'cos we drop the top-level arg
          non_abs_args = nonAbsentArgs cs
                -- Delete # of non-absent args to which we'll now be committed
                                
@@ -438,12 +647,10 @@ nonAbsentArgs (d   : ds) = 1 + nonAbsentArgs ds
 \begin{code}
 splitDmdTy :: DmdType -> (Demand, DmdType)
 -- Split off one function argument
+-- We already have a suitable demand on all
+-- free vars, so no need to add more!
 splitDmdTy (DmdType fv (dmd:dmds) res_ty) = (dmd, DmdType fv dmds res_ty)
-splitDmdTy ty@(DmdType fv [] TopRes)         = (topDmd, ty)
-splitDmdTy ty@(DmdType fv [] BotRes)         = (Abs,    ty)
-       -- We already have a suitable demand on all
-       -- free vars, so no need to add more!
-splitDmdTy (DmdType fv [] RetCPR)        = panic "splitDmdTy"
+splitDmdTy ty@(DmdType fv [] res_ty)      = (resTypeArgDmd res_ty, ty)
 \end{code}
 
 \begin{code}
@@ -454,7 +661,35 @@ addVarDmd top_lvl dmd_ty@(DmdType fv ds res) var dmd
   | otherwise         = DmdType (extendVarEnv fv var dmd) ds res
 
 addLazyFVs (DmdType fv ds res) lazy_fvs
-  = DmdType (plusUFM_C both fv lazy_fvs) ds res
+  = DmdType both_fv1 ds res
+  where
+    both_fv = (plusUFM_C both fv lazy_fvs)
+    both_fv1 = modifyEnv (isBotRes res) (`both` Bot) lazy_fvs fv both_fv
+       -- This modifyEnv is vital.  Consider
+       --      let f = \x -> (x,y)
+       --      in  error (f 3)
+       -- Here, y is treated as a lazy-fv of f, but we must `both` that L
+       -- demand with the bottom coming up from 'error'
+       -- 
+       -- I got a loop in the fixpointer without this, due to an interaction
+       -- with the lazy_fv filtering in mkSigTy.  Roughly, it was
+       --      letrec f n x 
+       --          = letrec g y = x `fatbar` 
+       --                         letrec h z = z + ...g...
+       --                         in h (f (n-1) x)
+       --      in ...
+       -- In the initial iteration for f, f=Bot
+       -- Suppose h is found to be strict in z, but the occurrence of g in its RHS
+       -- is lazy.  Now consider the fixpoint iteration for g, esp the demands it
+       -- places on its free variables.  Suppose it places none.  Then the
+       --      x `fatbar` ...call to h...
+       -- will give a x->V demand for x.  That turns into a L demand for x,
+       -- which floats out of the defn for h.  Without the modifyEnv, that
+       -- L demand doesn't get both'd with the Bot coming up from the inner
+       -- call to f.  So we just get an L demand for x for g.
+       --
+       -- A better way to say this is that the lazy-fv filtering should give the
+       -- same answer as putting the lazy fv demands in the function's type.
 
 annotateBndr :: DmdType -> Var -> (DmdType, Var)
 -- The returned env has the var deleted
@@ -472,16 +707,31 @@ annotateLamIdBndr dmd_ty@(DmdType fv ds res) id
 -- For lambdas we add the demand to the argument demands
 -- Only called for Ids
   = ASSERT( isId id )
-    (DmdType fv' (dmd:ds) res, setIdNewDemandInfo id dmd)
+    (DmdType fv' (hacked_dmd:ds) res, setIdNewDemandInfo id hacked_dmd)
   where
     (fv', dmd) = removeFV fv id res
-
-removeFV fv var res = (fv', dmd)
+    hacked_dmd = argDemand dmd
+       -- This call to argDemand is vital, because otherwise we label
+       -- a lambda binder with demand 'B'.  But in terms of calling
+       -- conventions that's Abs, because we don't pass it.  But
+       -- when we do a w/w split we get
+       --      fw x = (\x y:B -> ...) x (error "oops")
+       -- And then the simplifier things the 'B' is a strict demand
+       -- and evaluates the (error "oops").  Sigh
+
+removeFV fv id res = (fv', zapUnlifted id dmd)
                where
-                 fv' = fv `delVarEnv` var
-                 dmd = lookupVarEnv fv var `orElse` deflt
+                 fv' = fv `delVarEnv` id
+                 dmd = lookupVarEnv fv id `orElse` deflt
                  deflt | isBotRes res = Bot
                        | otherwise    = Abs
+
+-- For unlifted-type variables, we are only 
+-- interested in Bot/Abs/Box Abs
+zapUnlifted is Bot = Bot
+zapUnlifted id Abs = Abs
+zapUnlifted id dmd | isUnLiftedType (idType id) = lazyDmd
+                  | otherwise                  = dmd
 \end{code}
 
 %************************************************************************
@@ -506,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
@@ -516,19 +791,40 @@ dmdTransform :: SigEnv            -- The strictness environment
 dmdTransform sigs var dmd
 
 ------         DATA CONSTRUCTOR
-  | isDataConId var,           -- Data constructor
-    Seq k Now ds <- res_dmd,   -- and the demand looks inside its fields
-    let StrictSig dmd_ty = idNewStrictness var -- It must have a strictness sig
-  = if dmdTypeDepth dmd_ty == length ds then   -- Saturated, so unleash the demand
-       -- ds can be empty, when we are just seq'ing the thing
-       mkDmdType emptyDmdEnv ds (dmdTypeRes dmd_ty)
-               -- Need to extract whether it's a product, hence dmdTypeRes
+  | isDataConWorkId var                -- Data constructor
+  = let 
+       StrictSig dmd_ty    = idNewStrictness var       -- It must have a strictness sig
+       DmdType _ _ con_res = dmd_ty
+       arity               = idArity var
+    in
+    if arity == call_depth then                -- Saturated, so unleash the demand
+       let 
+               -- Important!  If we Keep the constructor application, then
+               -- we need the demands the constructor places (always lazy)
+               -- If not, we don't need to.  For example:
+               --      f p@(x,y) = (p,y)       -- S(AL)
+               --      g a b     = f (a,b)
+               -- It's vital that we don't calculate Absent for a!
+          dmd_ds = case res_dmd of
+                       Box (Eval ds) -> mapDmds box ds
+                       Eval ds       -> ds
+                       other         -> Poly Top
+
+               -- ds can be empty, when we are just seq'ing the thing
+               -- If so we must make up a suitable bunch of demands
+          arg_ds = case dmd_ds of
+                     Poly d  -> replicate arity d
+                     Prod ds -> ASSERT( ds `lengthIs` arity ) ds
+
+       in
+       mkDmdType emptyDmdEnv arg_ds con_res
+               -- Must remember whether it's a product, hence con_res, not TopRes
     else
        topDmdType
 
 ------         IMPORTED FUNCTION
   | isGlobalId var,            -- Imported function
-    let StrictSig dmd_ty = getNewStrictness var
+    let StrictSig dmd_ty = idNewStrictness var
   = if dmdTypeDepth dmd_ty <= call_depth then  -- Saturated, so unleash the demand
        dmd_ty
     else
@@ -568,185 +864,61 @@ splitCallDmd (Call d) = case splitCallDmd d of
 splitCallDmd d       = (0, d)
 
 vanillaCall :: Arity -> Demand
-vanillaCall 0 = Eval
+vanillaCall 0 = evalDmd
 vanillaCall n = Call (vanillaCall (n-1))
 
 deferType :: DmdType -> DmdType
-deferType (DmdType fv _ _) = DmdType (mapVarEnv defer fv) [] TopRes
+deferType (DmdType fv _ _) = DmdType (deferEnv fv) [] TopRes
        -- Notice that we throw away info about both arguments and results
        -- For example,   f = let ... in \x -> x
        -- We don't want to get a stricness type V->T for f.
+       -- Peter??
 
-defer :: Demand -> Demand
--- c.f. `lub` Abs
-defer Abs         = Abs
-defer (Seq k _ ds) = Seq k Defer ds
-defer other       = Lazy
+deferEnv :: DmdEnv -> DmdEnv
+deferEnv fv = mapVarEnv defer fv
 
-lazify :: Demand -> Demand
--- The 'Defer' demands are just Lazy at function boundaries
-lazify (Seq k Defer ds) = Lazy
-lazify (Seq k Now   ds) = Seq k Now (map lazify ds)
-lazify Bot             = Abs   -- Don't pass args that are consumed by bottom
-lazify 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
-
-squashDmdEnv (StrictSig (DmdType fv ds res)) = StrictSig (DmdType emptyDmdEnv ds res)
+----------------
+argDemand :: Demand -> Demand
+-- The 'Defer' demands are just Lazy at function boundaries
+-- Ugly!  Ask John how to improve it.
+argDemand Top      = lazyDmd
+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 (only) by bottom
+argDemand d        = d
 \end{code}
 
-
-%************************************************************************
-%*                                                                     *
-\subsection{LUB and BOTH}
-%*                                                                     *
-%************************************************************************
-
 \begin{code}
-lub :: Demand -> Demand -> Demand
-
-lub Bot  d = d
-
-lub Lazy d = Lazy
-
-lub Err Bot = Err 
-lub Err d   = d 
-
-lub Abs Bot         = Abs
-lub Abs Err         = Abs
-lub Abs Abs         = Abs    
-lub Abs (Seq k _ ds) = Seq k Defer ds  -- Very important ('radicals' example)
-lub Abs d           = Lazy
-
-lub Eval Abs             = Lazy
-lub Eval Lazy            = Lazy
-lub Eval (Seq k Now   ds) = Eval       -- Was (incorrectly): Seq Keep Now ds
-lub Eval (Seq k Defer ds) = Lazy
-lub Eval d               = Eval
-
-lub (Call d1) (Call d2) = Call (lub d1 d2)
-
-lub (Seq k1 l1 ds1) (Seq k2 l2 ds2) = Seq (k1 `vee` k2) (l1 `or_defer` l2) (lubs ds1 ds2)
-
--- The last clauses deal with the remaining cases for Call and Seq
-lub d1@(Call _) d2@(Seq _ _ _) = pprPanic "lub" (ppr d1 $$ ppr d2)
-lub d1 d2                     = lub d2 d1
-
--- A Seq can have an empty list of demands, in the polymorphic case.
-lubs [] ds2 = ds2
-lubs ds1 [] = ds1
-lubs ds1 ds2 = ASSERT( length ds1 == length ds2 ) zipWith lub ds1 ds2
-
-or_defer Now Now = Now
-or_defer _   _   = Defer
-
 -------------------------
 -- 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 (zipWith lub ds1 ds2) (r1 `lubRes` r2)
+  = DmdType lub_fv2 (lub_ds ds1 ds2) (r1 `lubRes` r2)
   where
     lub_fv  = plusUFM_C lub fv1 fv2
-    lub_fv1 = modifyEnv (not (isBotRes r1)) (Abs `lub`) fv2 fv1 lub_fv
-    lub_fv2 = modifyEnv (not (isBotRes r2)) (Abs `lub`) fv1 fv2 lub_fv1
+    lub_fv1 = modifyEnv (not (isBotRes r1)) absLub fv2 fv1 lub_fv
+    lub_fv2 = modifyEnv (not (isBotRes r2)) absLub fv1 fv2 lub_fv1
        -- lub is the identity for Bot
 
--------------------------
-lubRes BotRes r      = r
-lubRes r      BotRes = r
-lubRes RetCPR RetCPR = RetCPR
-lubRes r1     r2     = TopRes
-
------------------------------------
-vee :: Keepity -> Keepity -> Keepity
-vee Drop Drop = Drop
-vee k1   k2   = Keep
-
------------------------------------
-both :: Demand -> Demand -> Demand
-
--- The normal one
--- both Bot d = Bot
-
--- The experimental one
--- The idea is that (error x) places on x
---     both demand Bot (like on all free vars)
---     and demand Eval (for the arg to error)
--- and we want the result to be Eval.
-both Bot Bot = Bot
-both Bot Abs = Bot
-both Bot d   = d
-
-both Abs d   = d
-
-both Err Bot = Err
-both Err Abs = Err
-both Err d   = d
-
-both Lazy Bot         = Lazy
-both Lazy Abs         = Lazy
-both Lazy Err         = Lazy 
-both Lazy (Seq k l ds) = Seq Keep l ds
-both Lazy d           = d
-  -- Notice that the Seq case ensures that we have the
-  -- boxed value.  The equation originally said
-  --   both (Seq k Now ds) = Seq Keep Now ds
-  -- but it's important that the Keep is switched on even
-  -- for a deferred demand.  Otherwise a (Seq Drop Now [])
-  -- might both'd with the result, and then we won't pass
-  -- the boxed value.  Here's an example:
-  --   (x-1) `seq` (x+1, x)
-  -- From the (x+1, x) we get (U*(V) `both` L), which must give S*(V)
-  -- From (x-1) we get U(V). Combining, we must get S(V).
-  -- If we got U*(V) from the pair, we'd end up with U(V), and that
-  -- can be a disaster if a component of the data structure is absent.
-  -- [Disaster = enter an absent argument.]
-
-both Eval (Seq k l ds) = Seq Keep Now ds
-both Eval (Call d)     = Call d
-both Eval d           = Eval
-
-both (Seq k1 Defer ds1) (Seq k2 Defer ds2) = Seq (k1 `vee` k2) Defer (boths ds1  ds2)
-both (Seq k1 l1 ds1)    (Seq k2 l2 ds2)    = Seq (k1 `vee` k2) Now   (boths ds1' ds2')
-                                          where
-                                            ds1' = case l1 of { Now -> ds1; Defer -> map defer ds1 }
-                                            ds2' = case l2 of { Now -> ds2; Defer -> map defer ds2 }
-
-both (Call d1) (Call d2) = Call (d1 `both` d2)
-
--- The last clauses deal with the remaining cases for Call and Seq
-both d1@(Call _) d2@(Seq _ _ _) = pprPanic "both" (ppr d1 $$ ppr d2)
-both d1 d2                     = both d2 d1
-
------------------------------------
--- A Seq can have an empty list of demands, in the polymorphic case.
-boths [] ds2  = ds2
-boths ds1 []  = ds1
-boths ds1 ds2 = ASSERT( length ds1 == length ds2 ) zipWith both ds1 ds2
-
------------------------------------
-bothRes :: DmdResult -> DmdResult -> DmdResult
--- Left-biased for CPR info
-bothRes BotRes _ = BotRes
-bothRes _ BotRes = BotRes
-bothRes r1 _     = r1
+       -- Extend the shorter argument list to match the longer
+    lub_ds (d1:ds1) (d2:ds2) = lub d1 d2 : lub_ds ds1 ds2
+    lub_ds []      []       = []
+    lub_ds ds1     []       = map (`lub` resTypeArgDmd r2) ds1
+    lub_ds []      ds2      = map (resTypeArgDmd r1 `lub`) ds2
 
 -----------------------------------
 -- (t1 `bothType` t2) takes the argument/result info from t1,
 -- using t2 just for its free-var info
+-- NB: Don't forget about r2!  It might be BotRes, which is
+--     a bottom demand on all the in-scope variables.
+-- Peter: can this be done more neatly?
 bothType (DmdType fv1 ds1 r1) (DmdType fv2 ds2 r2)
-  = DmdType both_fv2 ds1 r1
+  = DmdType both_fv2 ds1 (r1 `bothRes` r2)
   where
     both_fv  = plusUFM_C both fv1 fv2
     both_fv1 = modifyEnv (isBotRes r1) (`both` Bot) fv2 fv1 both_fv
@@ -754,6 +926,19 @@ bothType (DmdType fv1 ds1 r1) (DmdType fv2 ds2 r2)
        -- both is the identity for Abs
 \end{code}
 
+
+\begin{code}
+lubRes BotRes r      = r
+lubRes r      BotRes = r
+lubRes RetCPR RetCPR = RetCPR
+lubRes r1     r2     = TopRes
+
+-- If either diverges, the whole thing does
+-- Otherwise take CPR info from the first
+bothRes r1 BotRes = BotRes
+bothRes r1 r2     = r1
+\end{code}
+
 \begin{code}
 modifyEnv :: Bool                      -- No-op if False
          -> (Demand -> Demand)         -- The zapper
@@ -774,20 +959,164 @@ modifyEnv need_to_modify zapper env1 env2 env
 
 %************************************************************************
 %*                                                                     *
+\subsection{LUB and BOTH}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+lub :: Demand -> Demand -> Demand
+
+lub Bot        d2 = d2
+lub Abs        d2 = absLub d2
+lub Top        d2 = Top
+lub (Defer ds1) d2 = defer (Eval ds1 `lub` d2)
+
+lub (Call d1)   (Call d2)    = Call (d1 `lub` d2)
+lub d1@(Call _) (Box d2)     = d1 `lub` d2     -- Just strip the box
+lub d1@(Call _) d2@(Eval _)  = d2              -- Presumably seq or vanilla eval
+lub d1@(Call _) d2          = d2 `lub` d1      -- Bot, Abs, Top
+
+-- For the Eval case, we use these approximation rules
+-- Box Bot      <= Eval (Box Bot ...)
+-- Box Top      <= Defer (Box Bot ...)
+-- Box (Eval ds) <= Eval (map Box ds)
+lub (Eval ds1)  (Eval ds2)       = Eval (ds1 `lubs` ds2)
+lub (Eval ds1)  (Box Bot)        = Eval (mapDmds (`lub` Box Bot) ds1)
+lub (Eval ds1)  (Box (Eval ds2)) = Eval (ds1 `lubs` mapDmds box ds2)
+lub (Eval ds1)  (Box Abs)        = deferEval (mapDmds (`lub` Box Bot) ds1)
+lub d1@(Eval _) d2               = d2 `lub` d1 -- Bot,Abs,Top,Call,Defer
+
+lub (Box d1)   (Box d2) = box (d1 `lub` d2)
+lub d1@(Box _)  d2     = d2 `lub` d1
+
+lubs = zipWithDmds lub
+
+---------------------
+-- box is the smart constructor for Box
+-- It computes <B,bot> & d
+-- INVARIANT: (Box d) => d = Bot, Abs, Eval
+-- Seems to be no point in allowing (Box (Call d))
+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 Abs       = lazyDmd        -- are the same <B,L>
+box d        = Box d   -- Bot, Eval
+
+---------------
+defer :: Demand -> Demand
+
+-- defer is the smart constructor for Defer
+-- The idea is that (Defer ds) = <U(ds), L>
+--
+-- It specifies what happens at a lazy function argument
+-- or a lambda; the L* operator
+-- Set the strictness part to L, but leave
+-- the boxity side unaffected
+-- It also ensures that Defer (Eval [LLLL]) = L
+
+defer Bot       = Abs
+defer Abs       = Abs
+defer Top       = Top
+defer (Call _)  = lazyDmd      -- Approximation here?
+defer (Box _)   = lazyDmd
+defer (Defer ds) = Defer ds
+defer (Eval ds)  = deferEval ds
+
+-- deferEval ds = defer (Eval ds)
+deferEval ds | allTop ds = Top
+            | otherwise  = Defer ds
+
+---------------------
+absLub :: Demand -> Demand
+-- Computes (Abs `lub` d)
+-- For the Bot case consider
+--     f x y = if ... then x else error x
+--   Then for y we get Abs `lub` Bot, and we really
+--   want Abs overall
+absLub Bot       = Abs
+absLub Abs       = Abs
+absLub Top       = Top
+absLub (Call _)   = Top
+absLub (Box _)    = Top
+absLub (Eval ds)  = Defer (absLubs ds) -- Or (Defer ds)?
+absLub (Defer ds) = Defer (absLubs ds) -- Or (Defer ds)?
+
+absLubs = mapDmds absLub
+
+---------------
+both :: Demand -> Demand -> Demand
+
+both Abs d2 = d2
+
+both Bot Bot      = Bot
+both Bot Abs      = Bot 
+both Bot (Eval ds) = Eval (mapDmds (`both` Bot) ds)
+       -- Consider
+       --      f x = error x
+       -- From 'error' itself we get demand Bot on x
+       -- From the arg demand on x we get 
+       --      x :-> evalDmd = Box (Eval (Poly Abs))
+       -- So we get  Bot `both` Box (Eval (Poly Abs))
+       --          = Seq Keep (Poly Bot)
+       --
+       -- Consider also
+       --      f x = if ... then error (fst x) else fst x
+       -- Then we get (Eval (Box Bot, Bot) `lub` Eval (SA))
+       --      = Eval (SA)
+       -- which is what we want.
+both Bot d = errDmd
+
+both Top Bot        = errDmd
+both Top Abs        = Top
+both Top Top        = Top
+both Top (Box d)    = Box d
+both Top (Call d)   = Call d
+both Top (Eval ds)  = Eval (mapDmds (`both` Top) ds)
+both Top (Defer ds)    -- = defer (Top `both` Eval ds)
+                       -- = defer (Eval (mapDmds (`both` Top) ds))
+                    = deferEval (mapDmds (`both` Top) ds)
+
+
+both (Box d1)  (Box d2)    = box (d1 `both` d2)
+both (Box d1)  d2@(Call _) = box (d1 `both` d2)
+both (Box d1)  d2@(Eval _) = box (d1 `both` d2)
+both (Box d1)  (Defer d2)  = Box d1
+both d1@(Box _) d2         = d2 `both` d1
+
+both (Call d1)          (Call d2)   = Call (d1 `both` d2)
+both (Call d1)          (Eval ds2)  = Call d1  -- Could do better for (Poly Bot)?
+both (Call d1)          (Defer ds2) = Call d1  -- Ditto
+both d1@(Call _) d2         = d1 `both` d1
+
+both (Eval ds1)    (Eval  ds2) = Eval (ds1 `boths` ds2)
+both (Eval ds1)    (Defer ds2) = Eval (ds1 `boths` mapDmds defer ds2)
+both d1@(Eval ds1) d2         = d2 `both` d1
+
+both (Defer ds1) (Defer ds2) = deferEval (ds1 `boths` ds2)
+both d1@(Defer ds1) d2      = d2 `both` d1
+boths = zipWithDmds both
+\end{code}
+
+
+
+%************************************************************************
+%*                                                                     *
 \subsection{Miscellaneous
 %*                                                                     *
 %************************************************************************
 
 
 \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)
 get_changes_bind (NonRec id rhs) = get_changes_pr (id,rhs)
 
 get_changes_pr (id,rhs) 
-  | isImplicitId id = empty  -- We don't look inside these
-  | otherwise      = get_changes_var id $$ get_changes_expr rhs
+  = get_changes_var id $$ get_changes_expr rhs
 
 get_changes_var var
   | isId var  = get_changes_str var $$ get_changes_dmd var
@@ -812,8 +1141,9 @@ get_changes_str id
   where
     message word = text word <+> text "strictness for" <+> ppr id <+> info
     info = (text "Old" <+> ppr old) $$ (text "New" <+> ppr new)
-    new = squashDmdEnv (idNewStrictness id)    -- Don't report diffs in the env
-    old = newStrictnessFromOld id
+    new = squashSig (idNewStrictness id)       -- Don't report spurious diffs that the old
+                                               -- strictness analyser can't track
+    old = newStrictnessFromOld (idName id) (idArity id) (idStrictness id) (idCprInfo id)
     old_better = old `betterStrictness` new
     new_better = new `betterStrictness` old
 
@@ -826,8 +1156,30 @@ get_changes_dmd id
   where
     message word = text word <+> text "demand for" <+> ppr id <+> info
     info = (text "Old" <+> ppr old) $$ (text "New" <+> ppr new)
-    new = lazify (idNewDemandInfo id)  -- Lazify to avoid spurious improvements
+    new = squashDmd (argDemand (idNewDemandInfo id))   -- To avoid spurious improvements
+                                                       -- A bit of a hack
     old = newDemand (idDemandInfo 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
+       -- squash just gets rid of call demands
+       -- which the old analyser doesn't track
+squashDmd (Call d)   = evalDmd
+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}