For a non-recursive let, make sure we extend the value environment
[ghc-hetmet.git] / compiler / specialise / SpecConstr.lhs
index db06d55..a2ef2a1 100644 (file)
@@ -4,8 +4,17 @@
 \section[SpecConstr]{Specialise over constructors}
 
 \begin{code}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
 module SpecConstr(
-       specConstrProgram       
+       specConstrProgram
+#ifdef GHCI
+        , SpecConstrAnnotation(..)
+#endif
     ) where
 
 #include "HsVersions.h"
@@ -14,32 +23,45 @@ import CoreSyn
 import CoreSubst
 import CoreUtils
 import CoreUnfold      ( couldBeSmallEnoughToInline )
-import CoreLint                ( showPass, endPass )
 import CoreFVs                 ( exprsFreeVars )
-import CoreTidy                ( tidyRules )
-import PprCore         ( pprRules )
+import CoreMonad
+import HscTypes         ( ModGuts(..) )
 import WwLib           ( mkWorkerArgs )
-import DataCon         ( dataConRepArity, dataConUnivTyVars )
-import Type            ( Type, tyConAppArgs )
-import Coercion                ( coercionKind )
-import Id              ( Id, idName, idType, isDataConWorkId_maybe, 
-                         mkUserLocal, mkSysLocal, idUnfolding, isLocalId )
-import Var             ( Var )
+import DataCon
+import Coercion        
+import Rules
+import Type            hiding( substTy )
+import Id
+import MkCore          ( mkImpossibleExpr )
+import Var
 import VarEnv
 import VarSet
 import Name
-import Rules           ( addIdSpecialisations, mkLocalRule, rulesOfBinds )
-import OccName         ( mkSpecOcc )
-import ErrUtils                ( dumpIfSet_dyn )
-import DynFlags                ( DynFlags(..), DynFlag(..) )
-import BasicTypes      ( Activation(..) )
-import Maybes          ( orElse, catMaybes )
+import BasicTypes
+import DynFlags                ( DynFlags(..) )
+import StaticFlags     ( opt_PprStyle_Debug )
+import Maybes          ( orElse, catMaybes, isJust, isNothing )
+import Demand
+import DmdAnal         ( both )
+import Serialized       ( deserializeWithData )
 import Util
-import List            ( nubBy, partition )
 import UniqSupply
 import Outputable
 import FastString
 import UniqFM
+import MonadUtils
+import Control.Monad   ( zipWithM )
+import Data.List
+
+
+-- See Note [SpecConstrAnnotation]
+#ifndef GHCI
+type SpecConstrAnnotation = ()
+#else
+import Literal          ( literalType )
+import TyCon            ( TyCon )
+import GHC.Exts( SpecConstrAnnotation(..) )
+#endif
 \end{code}
 
 -----------------------------------------------------
@@ -336,6 +358,85 @@ The recursive call ends up looking like
 So we want to spot the construtor application inside the cast.
 That's why we have the Cast case in argToPat
 
+Note [Local recursive groups]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+For a *local* recursive group, we can see all the calls to the
+function, so we seed the specialisation loop from the calls in the
+body, not from the calls in the RHS.  Consider:
+
+  bar m n = foo n (n,n) (n,n) (n,n) (n,n)
+   where
+     foo n p q r s
+       | n == 0    = m
+       | n > 3000  = case p of { (p1,p2) -> foo (n-1) (p2,p1) q r s }
+       | n > 2000  = case q of { (q1,q2) -> foo (n-1) p (q2,q1) r s }
+       | n > 1000  = case r of { (r1,r2) -> foo (n-1) p q (r2,r1) s }
+       | otherwise = case s of { (s1,s2) -> foo (n-1) p q r (s2,s1) }
+
+If we start with the RHSs of 'foo', we get lots and lots of specialisations,
+most of which are not needed.  But if we start with the (single) call
+in the rhs of 'bar' we get exactly one fully-specialised copy, and all
+the recursive calls go to this fully-specialised copy. Indeed, the original
+function is later collected as dead code.  This is very important in 
+specialising the loops arising from stream fusion, for example in NDP where
+we were getting literally hundreds of (mostly unused) specialisations of
+a local function.
+
+Note [Do not specialise diverging functions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Specialising a function that just diverges is a waste of code.
+Furthermore, it broke GHC (simpl014) thus:
+   {-# STR Sb #-}
+   f = \x. case x of (a,b) -> f x
+If we specialise f we get
+   f = \x. case x of (a,b) -> fspec a b
+But fspec doesn't have decent strictnes info.  As it happened,
+(f x) :: IO t, so the state hack applied and we eta expanded fspec,
+and hence f.  But now f's strictness is less than its arity, which
+breaks an invariant.
+
+Note [SpecConstrAnnotation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+SpecConstrAnnotation is defined in GHC.Exts, and is only guaranteed to
+be available in stage 2 (well, until the bootstrap compiler can be
+guaranteed to have it)
+
+So we define it to be () in stage1 (ie when GHCI is undefined), and
+'#ifdef' out the code that uses it.
+
+See also Note [Forcing specialisation]
+
+Note [Forcing specialisation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+With stream fusion and in other similar cases, we want to fully specialise
+some (but not necessarily all!) loops regardless of their size and the
+number of specialisations. We allow a library to specify this by annotating
+a type with ForceSpecConstr and then adding a parameter of that type to the
+loop. Here is a (simplified) example from the vector library:
+
+  data SPEC = SPEC | SPEC2
+  {-# ANN type SPEC ForceSpecConstr #-}
+
+  foldl :: (a -> b -> a) -> a -> Stream b -> a
+  {-# INLINE foldl #-}
+  foldl f z (Stream step s _) = foldl_loop SPEC z s
+    where
+      foldl_loop SPEC z s = case step s of
+                              Yield x s' -> foldl_loop SPEC (f z x) s'
+                              Skip       -> foldl_loop SPEC z s'
+                              Done       -> z
+
+SpecConstr will spot the SPEC parameter and always fully specialise
+foldl_loop. Note that we can't just annotate foldl_loop since it isn't a
+top-level function but even if we could, inlining etc. could easily drop the
+annotation. We also have to prevent the SPEC argument from being removed by
+w/w which is why SPEC is a sum type. This is all quite ugly; we ought to come
+up with a better design.
+
+ForceSpecConstr arguments are spotted in scExpr' and scTopBinds which then set
+force_spec to True when calling specLoop. This flag makes specLoop and
+specialise ignore specConstrCount and specConstrThreshold when deciding
+whether to specialise a function.
 
 -----------------------------------------------------
                Stuff not yet handled
@@ -412,8 +513,6 @@ But perhaps the first one isn't good.  After all, we know that tpl_B2 is
 a T (I# x) really, because T is strict and Int has one constructor.  (We can't
 unbox the strict fields, becuase T is polymorphic!)
 
-
-
 %************************************************************************
 %*                                                                     *
 \subsection{Top level wrapper stuff}
@@ -421,24 +520,19 @@ unbox the strict fields, becuase T is polymorphic!)
 %************************************************************************
 
 \begin{code}
-specConstrProgram :: DynFlags -> UniqSupply -> [CoreBind] -> IO [CoreBind]
-specConstrProgram dflags us binds
+specConstrProgram :: ModGuts -> CoreM ModGuts
+specConstrProgram guts
   = do
-       showPass dflags "SpecConstr"
-
-       let (binds', _) = initUs us (go (initScEnv dflags) binds)
-
-       endPass dflags "SpecConstr" Opt_D_dump_spec binds'
-
-       dumpIfSet_dyn dflags Opt_D_dump_rules "Top-level specialisations"
-                 (pprRules (tidyRules emptyTidyEnv (rulesOfBinds binds')))
-
-       return binds'
+      dflags <- getDynFlags
+      us     <- getUniqueSupplyM
+      annos  <- getFirstAnnotations deserializeWithData guts
+      let binds' = fst $ initUs us (go (initScEnv dflags annos) (mg_binds guts))
+      return (guts { mg_binds = binds' })
   where
-    go env []          = returnUs []
-    go env (bind:binds) = scBind env bind      `thenUs` \ (env', _, bind') ->
-                         go env' binds         `thenUs` \ binds' ->
-                         returnUs (bind' : binds')
+    go _   []          = return []
+    go env (bind:binds) = do (env', bind') <- scTopBind env bind
+                             binds' <- go env' binds
+                             return (bind' : binds')
 \end{code}
 
 
@@ -449,23 +543,30 @@ specConstrProgram dflags us binds
 %************************************************************************
 
 \begin{code}
-data ScEnv = SCE { sc_size :: Int,     -- Size threshold
+data ScEnv = SCE { sc_size  :: Maybe Int,      -- Size threshold
+                  sc_count :: Maybe Int,       -- Max # of specialisations for any one fn
+                                               -- See Note [Avoiding exponential blowup]
 
-                  sc_subst :: Subst,   -- Current substitution
+                  sc_subst :: Subst,           -- Current substitution
+                                               -- Maps InIds to OutExprs
 
                   sc_how_bound :: HowBoundEnv,
                        -- Binds interesting non-top-level variables
                        -- Domain is OutVars (*after* applying the substitution)
 
-                  sc_cons  :: ConstrEnv
+                  sc_vals  :: ValueEnv,
                        -- Domain is OutIds (*after* applying the substitution)
+                       -- Used even for top-level bindings (but not imported ones)
+
+                   sc_annotations :: UniqFM SpecConstrAnnotation
             }
 
 ---------------------
 -- As we go, we apply a substitution (sc_subst) to the current term
-type InExpr = CoreExpr         -- *Before* applying the subst
+type InExpr = CoreExpr         -- _Before_ applying the subst
+type InVar  = Var
 
-type OutExpr = CoreExpr                -- *After* applying the subst
+type OutExpr = CoreExpr                -- _After_ applying the subst
 type OutId   = Id
 type OutVar  = Var
 
@@ -473,21 +574,24 @@ type OutVar  = Var
 type HowBoundEnv = VarEnv HowBound     -- Domain is OutVars
 
 ---------------------
-type ConstrEnv = IdEnv ConValue                -- Domain is OutIds
-data ConValue  = CV AltCon [CoreArg]
-       -- Variables known to be bound to a constructor
-       -- in a particular case alternative
-
+type ValueEnv = IdEnv Value            -- Domain is OutIds
+data Value    = ConVal AltCon [CoreArg]        -- _Saturated_ constructors
+                                       --   The AltCon is never DEFAULT
+             | LambdaVal               -- Inlinable lambdas or PAPs
 
-instance Outputable ConValue where
-   ppr (CV con args) = ppr con <+> interpp'SP args
+instance Outputable Value where
+   ppr (ConVal con args) = ppr con <+> interpp'SP args
+   ppr LambdaVal        = ptext (sLit "<Lambda>")
 
 ---------------------
-initScEnv dflags
-  = SCE { sc_size = specThreshold dflags,
+initScEnv :: DynFlags -> UniqFM SpecConstrAnnotation -> ScEnv
+initScEnv dflags anns
+  = SCE { sc_size = specConstrThreshold dflags,
+         sc_count = specConstrCount dflags,
          sc_subst = emptySubst, 
          sc_how_bound = emptyVarEnv, 
-         sc_cons = emptyVarEnv }
+         sc_vals = emptyVarEnv,
+          sc_annotations = anns }
 
 data HowBound = RecFun -- These are the recursive functions for which 
                        -- we seek interesting call patterns
@@ -503,7 +607,7 @@ lookupHowBound :: ScEnv -> Id -> Maybe HowBound
 lookupHowBound env id = lookupVarEnv (sc_how_bound env) id
 
 scSubstId :: ScEnv -> Id -> CoreExpr
-scSubstId env v = lookupIdSubst (sc_subst env) v
+scSubstId env v = lookupIdSubst (text "scSubstId") (sc_subst env) v
 
 scSubstTy :: ScEnv -> Type -> Type
 scSubstTy env ty = substTy (sc_subst env) ty
@@ -515,9 +619,12 @@ extendScInScope :: ScEnv -> [Var] -> ScEnv
        -- Bring the quantified variables into scope
 extendScInScope env qvars = env { sc_subst = extendInScopeList (sc_subst env) qvars }
 
-extendScSubst :: ScEnv -> [(Var,CoreArg)] -> ScEnv
        -- Extend the substitution
-extendScSubst env prs = env { sc_subst = extendSubstList (sc_subst env) prs }
+extendScSubst :: ScEnv -> Var -> OutExpr -> ScEnv
+extendScSubst env var expr = env { sc_subst = extendSubst (sc_subst env) var expr }
+
+extendScSubstList :: ScEnv -> [(Var,OutExpr)] -> ScEnv
+extendScSubstList env prs = env { sc_subst = extendSubstList (sc_subst env) prs }
 
 extendHowBound :: ScEnv -> [Var] -> HowBound -> ScEnv
 extendHowBound env bndrs how_bound
@@ -549,31 +656,117 @@ extendBndr  env bndr  = (env { sc_subst = subst' }, bndr')
                      where
                        (subst', bndr') = substBndr (sc_subst env) bndr
 
-extendConEnv :: ScEnv -> Id -> Maybe ConValue -> ScEnv
-extendConEnv env id Nothing   = env
-extendConEnv env id (Just cv) = env { sc_cons = extendVarEnv (sc_cons env) id cv }
+extendValEnv :: ScEnv -> Id -> Maybe Value -> ScEnv
+extendValEnv env _  Nothing   = env
+extendValEnv env id (Just cv) = env { sc_vals = extendVarEnv (sc_vals env) id cv }
 
-extendCaseBndrs :: ScEnv -> CoreExpr -> Id -> AltCon -> [Var] -> ScEnv
+extendCaseBndrs :: ScEnv -> Id -> AltCon -> [Var] -> (ScEnv, [Var])
 -- When we encounter
 --     case scrut of b
 --         C x y -> ...
--- we want to bind b, and perhaps scrut too, to (C x y)
--- NB: Extends only the sc_cons part of the envt
-extendCaseBndrs env scrut case_bndr con alt_bndrs
-  = case scrut of
-       Var v -> extendConEnv env1 v cval
-       other -> env1
+-- we want to bind b, to (C x y)
+-- NB1: Extends only the sc_vals part of the envt
+-- NB2: Kill the dead-ness info on the pattern binders x,y, since
+--      they are potentially made alive by the [b -> C x y] binding
+extendCaseBndrs env case_bndr con alt_bndrs
+  | isDeadBinder case_bndr
+  = (env, alt_bndrs)
+  | otherwise
+  = (env1, map zap alt_bndrs)
+       -- NB: We used to bind v too, if scrut = (Var v); but
+        --     the simplifer has already done this so it seems
+        --     redundant to do so here
+       -- case scrut of
+       --      Var v  -> extendValEnv env1 v cval
+       --      _other -> env1
  where
-   env1 = extendConEnv env case_bndr cval
+   zap v | isTyCoVar v = v             -- See NB2 above
+         | otherwise = zapIdOccInfo v
+   env1 = extendValEnv env case_bndr cval
    cval = case con of
                DEFAULT    -> Nothing
-               LitAlt lit -> Just (CV con [])
-               DataAlt dc -> Just (CV con vanilla_args)
+               LitAlt {}  -> Just (ConVal con [])
+               DataAlt {} -> Just (ConVal con vanilla_args)
                      where
                        vanilla_args = map Type (tyConAppArgs (idType case_bndr)) ++
                                       varsToCoreExprs alt_bndrs
+
+
+decreaseSpecCount :: ScEnv -> Int -> ScEnv
+-- See Note [Avoiding exponential blowup]
+decreaseSpecCount env n_specs 
+  = env { sc_count = case sc_count env of
+                       Nothing -> Nothing
+                       Just n  -> Just (n `div` (n_specs + 1)) }
+       -- The "+1" takes account of the original function; 
+       -- See Note [Avoiding exponential blowup]
+
+---------------------------------------------------
+-- See Note [SpecConstrAnnotation]
+ignoreType    :: ScEnv -> Type   -> Bool
+ignoreAltCon  :: ScEnv -> AltCon -> Bool
+forceSpecBndr :: ScEnv -> Var    -> Bool
+#ifndef GHCI
+ignoreType    _ _ = False
+ignoreAltCon  _ _ = False
+forceSpecBndr _ _ = False
+
+#else /* GHCI */
+
+ignoreAltCon env (DataAlt dc) = ignoreTyCon env (dataConTyCon dc)
+ignoreAltCon env (LitAlt lit) = ignoreType env (literalType lit)
+ignoreAltCon _   DEFAULT      = panic "ignoreAltCon"  -- DEFAULT cannot be in a ConVal
+
+ignoreType env ty
+  = case splitTyConApp_maybe ty of
+      Just (tycon, _) -> ignoreTyCon env tycon
+      _               -> False
+
+ignoreTyCon :: ScEnv -> TyCon -> Bool
+ignoreTyCon env tycon
+  = lookupUFM (sc_annotations env) tycon == Just NoSpecConstr
+
+forceSpecBndr env var = forceSpecFunTy env . snd . splitForAllTys . varType $ var
+
+forceSpecFunTy :: ScEnv -> Type -> Bool
+forceSpecFunTy env = any (forceSpecArgTy env) . fst . splitFunTys
+
+forceSpecArgTy :: ScEnv -> Type -> Bool
+forceSpecArgTy env ty
+  | Just ty' <- coreView ty = forceSpecArgTy env ty'
+
+forceSpecArgTy env ty
+  | Just (tycon, tys) <- splitTyConApp_maybe ty
+  , tycon /= funTyCon
+      = lookupUFM (sc_annotations env) tycon == Just ForceSpecConstr
+        || any (forceSpecArgTy env) tys
+
+forceSpecArgTy _ _ = False
+#endif /* GHCI */
 \end{code}
 
+Note [Avoiding exponential blowup]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The sc_count field of the ScEnv says how many times we are prepared to
+duplicate a single function.  But we must take care with recursive
+specialiations.  Consider
+
+       let $j1 = let $j2 = let $j3 = ...
+                            in 
+                            ...$j3...
+                  in 
+                  ...$j2...
+        in 
+        ...$j1...
+
+If we specialise $j1 then in each specialisation (as well as the original)
+we can specialise $j2, and similarly $j3.  Even if we make just *one*
+specialisation of each, becuase we also have the original we'll get 2^n
+copies of $j3, which is not good.
+
+So when recursively specialising we divide the sc_count by the number of
+copies we are making at this level, including the original.
+
 
 %************************************************************************
 %*                                                                     *
@@ -584,38 +777,40 @@ extendCaseBndrs env scrut case_bndr con alt_bndrs
 \begin{code}
 data ScUsage
    = SCU {
-       calls :: CallEnv,               -- Calls
+       scu_calls :: CallEnv,           -- Calls
                                        -- The functions are a subset of the 
                                        --      RecFuns in the ScEnv
 
-       occs :: !(IdEnv ArgOcc)         -- Information on argument occurrences
-     }                                 -- The variables are a subset of the 
-                                       --      RecArg in the ScEnv
+       scu_occs :: !(IdEnv ArgOcc)     -- Information on argument occurrences
+     }                                 -- The domain is OutIds
 
 type CallEnv = IdEnv [Call]
-type Call = (ConstrEnv, [CoreArg])
+type Call = (ValueEnv, [CoreArg])
        -- The arguments of the call, together with the
        -- env giving the constructor bindings at the call site
 
-nullUsage = SCU { calls = emptyVarEnv, occs = emptyVarEnv }
+nullUsage :: ScUsage
+nullUsage = SCU { scu_calls = emptyVarEnv, scu_occs = emptyVarEnv }
 
 combineCalls :: CallEnv -> CallEnv -> CallEnv
 combineCalls = plusVarEnv_C (++)
 
-combineUsage u1 u2 = SCU { calls = combineCalls (calls u1) (calls u2),
-                          occs  = plusVarEnv_C combineOcc (occs u1) (occs u2) }
+combineUsage :: ScUsage -> ScUsage -> ScUsage
+combineUsage u1 u2 = SCU { scu_calls = combineCalls (scu_calls u1) (scu_calls u2),
+                          scu_occs  = plusVarEnv_C combineOcc (scu_occs u1) (scu_occs u2) }
 
+combineUsages :: [ScUsage] -> ScUsage
 combineUsages [] = nullUsage
 combineUsages us = foldr1 combineUsage us
 
-lookupOcc :: ScUsage -> Var -> (ScUsage, ArgOcc)
-lookupOcc (SCU { calls = sc_calls, occs = sc_occs }) bndr
-  = (SCU {calls = sc_calls, occs = delVarEnv sc_occs bndr},
+lookupOcc :: ScUsage -> OutVar -> (ScUsage, ArgOcc)
+lookupOcc (SCU { scu_calls = sc_calls, scu_occs = sc_occs }) bndr
+  = (SCU {scu_calls = sc_calls, scu_occs = delVarEnv sc_occs bndr},
      lookupVarEnv sc_occs bndr `orElse` NoOcc)
 
-lookupOccs :: ScUsage -> [Var] -> (ScUsage, [ArgOcc])
-lookupOccs (SCU { calls = sc_calls, occs = sc_occs }) bndrs
-  = (SCU {calls = sc_calls, occs = delVarEnvList sc_occs bndrs},
+lookupOccs :: ScUsage -> [OutVar] -> (ScUsage, [ArgOcc])
+lookupOccs (SCU { scu_calls = sc_calls, scu_occs = sc_occs }) bndrs
+  = (SCU {scu_calls = sc_calls, scu_occs = delVarEnvList sc_occs bndrs},
      [lookupVarEnv sc_occs b `orElse` NoOcc | b <- bndrs])
 
 data ArgOcc = NoOcc    -- Doesn't occur at all; or a type argument
@@ -644,35 +839,36 @@ A pattern binds b, x::a, y::b, z::b->a, but not 'a'!
 -}
 
 instance Outputable ArgOcc where
-  ppr (ScrutOcc xs) = ptext SLIT("scrut-occ") <> ppr xs
-  ppr UnkOcc       = ptext SLIT("unk-occ")
-  ppr BothOcc      = ptext SLIT("both-occ")
-  ppr NoOcc                = ptext SLIT("no-occ")
+  ppr (ScrutOcc xs) = ptext (sLit "scrut-occ") <> ppr xs
+  ppr UnkOcc       = ptext (sLit "unk-occ")
+  ppr BothOcc      = ptext (sLit "both-occ")
+  ppr NoOcc                = ptext (sLit "no-occ")
 
 -- Experimentally, this vesion of combineOcc makes ScrutOcc "win", so
 -- that if the thing is scrutinised anywhere then we get to see that
 -- in the overall result, even if it's also used in a boxed way
 -- This might be too agressive; see Note [Reboxing] Alternative 3
+combineOcc :: ArgOcc -> ArgOcc -> ArgOcc
 combineOcc NoOcc        occ           = occ
 combineOcc occ                  NoOcc         = occ
 combineOcc (ScrutOcc xs) (ScrutOcc ys) = ScrutOcc (plusUFM_C combineOccs xs ys)
-combineOcc occ           (ScrutOcc ys) = ScrutOcc ys
-combineOcc (ScrutOcc xs) occ          = ScrutOcc xs
+combineOcc _occ          (ScrutOcc ys) = ScrutOcc ys
+combineOcc (ScrutOcc xs) _occ         = ScrutOcc xs
 combineOcc UnkOcc        UnkOcc        = UnkOcc
 combineOcc _       _                  = BothOcc
 
 combineOccs :: [ArgOcc] -> [ArgOcc] -> [ArgOcc]
 combineOccs xs ys = zipWithEqual "combineOccs" combineOcc xs ys
 
-setScrutOcc :: ScEnv -> ScUsage -> CoreExpr -> ArgOcc -> ScUsage
--- *Overwrite* the occurrence info for the scrutinee, if the scrutinee 
+setScrutOcc :: ScEnv -> ScUsage -> OutExpr -> ArgOcc -> ScUsage
+-- _Overwrite_ the occurrence info for the scrutinee, if the scrutinee
 -- is a variable, and an interesting variable
 setScrutOcc env usg (Cast e _) occ = setScrutOcc env usg e occ
 setScrutOcc env usg (Note _ e) occ = setScrutOcc env usg e occ
 setScrutOcc env usg (Var v)    occ
-  | Just RecArg <- lookupHowBound env v = usg { occs = extendVarEnv (occs usg) v occ }
+  | Just RecArg <- lookupHowBound env v = usg { scu_occs = extendVarEnv (scu_occs usg) v occ }
   | otherwise                          = usg
-setScrutOcc env usg other occ  -- Catch-all
+setScrutOcc _env usg _other _occ       -- Catch-all
   = usg        
 
 conArgOccs :: ArgOcc -> AltCon -> [ArgOcc]
@@ -681,9 +877,9 @@ conArgOccs :: ArgOcc -> AltCon -> [ArgOcc]
 
 conArgOccs (ScrutOcc fm) (DataAlt dc) 
   | Just pat_arg_occs <- lookupUFM fm dc
-  = [UnkOcc | tv <- dataConUnivTyVars dc] ++ pat_arg_occs
+  = [UnkOcc | _ <- dataConUnivTyVars dc] ++ pat_arg_occs
 
-conArgOccs other con = repeat UnkOcc
+conArgOccs _other _con = repeat UnkOcc
 \end{code}
 
 %************************************************************************
@@ -696,7 +892,7 @@ The main recursive function gathers up usage information, and
 creates specialised versions of functions.
 
 \begin{code}
-scExpr :: ScEnv -> CoreExpr -> UniqSM (ScUsage, CoreExpr)
+scExpr, scExpr' :: ScEnv -> CoreExpr -> UniqSM (ScUsage, CoreExpr)
        -- The unique supply is needed when we invent
        -- a new name for the specialised function and its args
 
@@ -704,40 +900,41 @@ scExpr env e = scExpr' env e
 
 
 scExpr' env (Var v)     = case scSubstId env v of
-                           Var v' -> returnUs (varUsage env v UnkOcc, Var v')
+                           Var v' -> return (varUsage env v' UnkOcc, Var v')
                            e'     -> scExpr (zapScSubst env) e'
 
-scExpr' env e@(Type t)  = returnUs (nullUsage, Type (scSubstTy env t))
-scExpr' env e@(Lit l)   = returnUs (nullUsage, e)
-scExpr' env (Note n e)  = do { (usg,e') <- scExpr env e
-                           ; return (usg, Note n e') }
-scExpr' env (Cast e co) = do { (usg, e') <- scExpr env e
-                           ; return (usg, Cast e' (scSubstTy env co)) }
-scExpr' env (Lam b e)   = do { let (env', b') = extendBndr env b
-                           ; (usg, e') <- scExpr env' e
-                           ; return (usg, Lam b' e') }
+scExpr' env (Type t)    = return (nullUsage, Type (scSubstTy env t))
+scExpr' _   e@(Lit {})  = return (nullUsage, e)
+scExpr' env (Note n e)  = do (usg,e') <- scExpr env e
+                             return (usg, Note n e')
+scExpr' env (Cast e co) = do (usg, e') <- scExpr env e
+                             return (usg, Cast e' (scSubstTy env co))
+scExpr' env e@(App _ _) = scApp env (collectArgs e)
+scExpr' env (Lam b e)   = do let (env', b') = extendBndr env b
+                             (usg, e') <- scExpr env' e
+                             return (usg, Lam b' e')
 
 scExpr' env (Case scrut b ty alts) 
   = do { (scrut_usg, scrut') <- scExpr env scrut
-       ; case isConApp (sc_cons env) scrut' of
-               Nothing   -> sc_vanilla scrut_usg scrut'
-               Just cval -> sc_con_app cval scrut'
+       ; case isValue (sc_vals env) scrut' of
+               Just (ConVal con args) -> sc_con_app con args scrut'
+               _other                 -> sc_vanilla scrut_usg scrut'
        }
   where
-    sc_con_app cval@(CV con args) scrut'       -- Known constructor; simplify
+    sc_con_app con args scrut'         -- Known constructor; simplify
        = do { let (_, bs, rhs) = findAlt con alts
-                  alt_env' = extendScSubst env ((b,scrut') : bs `zip` trimConArgs con args)
+                                 `orElse` (DEFAULT, [], mkImpossibleExpr (coreAltsType alts))
+                  alt_env'  = extendScSubstList env ((b,scrut') : bs `zip` trimConArgs con args)
             ; scExpr alt_env' rhs }
-
                                
     sc_vanilla scrut_usg scrut'        -- Normal case
      = do { let (alt_env,b') = extendBndrWith RecArg env b
                        -- Record RecArg for the components
 
          ; (alt_usgs, alt_occs, alts')
-               <- mapAndUnzip3Us (sc_alt alt_env scrut' b') alts
+               <- mapAndUnzip3M (sc_alt alt_env scrut' b') alts
 
-         ; let (alt_usg, b_occ) = lookupOcc (combineUsages alt_usgs) b
+         ; let (alt_usg, b_occ) = lookupOcc (combineUsages alt_usgs) b'
                scrut_occ        = foldr combineOcc b_occ alt_occs
                scrut_usg'       = setScrutOcc env scrut_usg scrut' scrut_occ
                -- The combined usage of the scrutinee is given
@@ -747,120 +944,163 @@ scExpr' env (Case scrut b ty alts)
          ; return (alt_usg `combineUsage` scrut_usg',
                    Case scrut' b' (scSubstTy env ty) alts') }
 
-    sc_alt env scrut' b' (con,bs,rhs)
-      = do { let (env1, bs') = extendBndrsWith RecArg env bs
-                env2        = extendCaseBndrs env1 scrut' b' con bs'
+    sc_alt env _scrut' b' (con,bs,rhs)
+      = do { let (env1, bs1)  = extendBndrsWith RecArg env bs
+                (env2, bs2) = extendCaseBndrs env1 b' con bs1
           ; (usg,rhs') <- scExpr env2 rhs
-          ; let (usg', arg_occs) = lookupOccs usg bs
+          ; let (usg', arg_occs) = lookupOccs usg bs2
                 scrut_occ = case con of
                                DataAlt dc -> ScrutOcc (unitUFM dc arg_occs)
-                               other      -> ScrutOcc emptyUFM
-          ; return (usg', scrut_occ, (con,bs',rhs')) }
+                               _          -> ScrutOcc emptyUFM
+          ; return (usg', scrut_occ, (con, bs2, rhs')) }
 
 scExpr' env (Let (NonRec bndr rhs) body)
+  | isTyCoVar bndr     -- Type-lets may be created by doBeta
+  = scExpr' (extendScSubst env bndr rhs) body
+
+  | otherwise  
   = do { let (body_env, bndr') = extendBndr env bndr
-       ; (rhs_usg, rhs_info@(_, args', rhs_body', _)) <- scRecRhs env (bndr',rhs)
-
-       ; if null args' || isEmptyVarEnv (calls rhs_usg) then do
-           do  {       -- Vanilla case
-                 let rhs' = mkLams args' rhs_body'
-                     body_env2 = extendConEnv body_env bndr' (isConApp (sc_cons env) rhs')
-                       -- Record if the RHS is a constructor
-               ; (body_usg, body') <- scExpr body_env2 body
-               ; return (body_usg `combineUsage` rhs_usg, Let (NonRec bndr' rhs') body') }
-         else 
-           do  {       -- Join-point case
-                 let body_env2 = extendHowBound body_env [bndr'] RecFun
-                       -- If the RHS of this 'let' contains calls
-                       -- to recursive functions that we're trying
-                       -- to specialise, then treat this let too
-                       -- as one to specialise
-               ; (body_usg, body') <- scExpr body_env2 body
-
-               ; (spec_usg, _, specs) <- specialise env (calls body_usg) ([], rhs_info)
-
-               ; return (body_usg { calls = calls body_usg `delVarEnv` bndr' } 
-                         `combineUsage` rhs_usg `combineUsage` spec_usg,
-                         mkLets [NonRec b r | (b,r) <- addRules rhs_info specs] body')
-       }       }
+       ; (rhs_usg, rhs_info) <- scRecRhs env (bndr',rhs)
+
+       ; let body_env2 = extendHowBound body_env [bndr'] RecFun
+                                  -- Note [Local let bindings]
+             RI _ rhs' _ _ _ = rhs_info
+              body_env3 = extendValEnv body_env2 bndr' (isValue (sc_vals env) rhs')
+
+       ; (body_usg, body') <- scExpr body_env3 body
+
+          -- NB: We don't use the ForceSpecConstr mechanism (see
+          -- Note [Forcing specialisation]) for non-recursive bindings
+          -- at the moment. I'm not sure if this is the right thing to do.
+       ; let force_spec = False
+       ; (spec_usg, specs) <- specialise env force_spec 
+                                          (scu_calls body_usg) 
+                                         rhs_info
+                                          (SI [] 0 (Just rhs_usg))
+
+       ; return (body_usg { scu_calls = scu_calls body_usg `delVarEnv` bndr' } 
+                   `combineUsage` spec_usg,
+                 mkLets [NonRec b r | (b,r) <- specInfoBinds rhs_info specs] body')
+       }
+
 
+-- A *local* recursive group: see Note [Local recursive groups]
 scExpr' env (Let (Rec prs) body)
-  = do { (env', bind_usg, bind') <- scBind env (Rec prs)
-       ; (body_usg, body') <- scExpr env' body
-       ; return (bind_usg `combineUsage` body_usg, Let bind' body') }
-
-scExpr' env e@(App _ _) 
-  = do { let (fn, args) = collectArgs e
-       ; (fn_usg, fn') <- scExpr env fn
-       -- Process the function too.   It's almost always a variable,
-       -- but not always.  In particular, if this pass follows float-in,
-       -- which it may, we can get 
-       --      (let f = ...f... in f) arg1 arg2
-       -- Also the substitution may replace a variable by a non-variable
-
-       ; let fn_usg' = setScrutOcc env fn_usg fn' (ScrutOcc emptyUFM)
-       -- We use setScrutOcc to record the fact that the function is called
-       -- Perhaps we should check that it has at least one value arg, 
-       -- but currently we don't bother
-
-       ; (arg_usgs, args') <- mapAndUnzipUs (scExpr env) args
-       ; let call_usg = case fn' of
-                          Var f | Just RecFun <- lookupHowBound env f
-                                , not (null args)      -- Not a proper call!
-                                -> SCU { calls = unitVarEnv f [(sc_cons env, args')], 
-                                         occs  = emptyVarEnv }
-                          other -> nullUsage
-       ; return (combineUsages arg_usgs `combineUsage` fn_usg' 
-                                        `combineUsage` call_usg,
-                 mkApps fn' args') }
+  = do { let (bndrs,rhss) = unzip prs
+             (rhs_env1,bndrs') = extendRecBndrs env bndrs
+             rhs_env2 = extendHowBound rhs_env1 bndrs' RecFun
+              force_spec = any (forceSpecBndr env) bndrs'
+                -- Note [Forcing specialisation]
+
+       ; (rhs_usgs, rhs_infos) <- mapAndUnzipM (scRecRhs rhs_env2) (bndrs' `zip` rhss)
+       ; (body_usg, body')     <- scExpr rhs_env2 body
+
+       -- NB: start specLoop from body_usg
+       ; (spec_usg, specs) <- specLoop rhs_env2 force_spec
+                                        (scu_calls body_usg) rhs_infos nullUsage
+                                       [SI [] 0 (Just usg) | usg <- rhs_usgs]
+               -- Do not unconditionally use rhs_usgs. 
+               -- Instead use them only if we find an unspecialised call
+               -- See Note [Local recursive groups]
+
+       ; let all_usg = spec_usg `combineUsage` body_usg
+             bind'   = Rec (concat (zipWith specInfoBinds rhs_infos specs))
+
+       ; return (all_usg { scu_calls = scu_calls all_usg `delVarEnvList` bndrs' },
+                 Let bind' body') }
+\end{code}
+
+Note [Local let bindings]
+~~~~~~~~~~~~~~~~~~~~~~~~~
+It is not uncommon to find this
+
+   let $j = \x. <blah> in ...$j True...$j True...
+
+Here $j is an arbitrary let-bound function, but it often comes up for
+join points.  We might like to specialise $j for its call patterns.
+Notice the difference from a letrec, where we look for call patterns
+in the *RHS* of the function.  Here we look for call patterns in the
+*body* of the let.
+
+At one point I predicated this on the RHS mentioning the outer
+recursive function, but that's not essential and might even be
+harmful.  I'm not sure.
 
 
+\begin{code}
+scApp :: ScEnv -> (InExpr, [InExpr]) -> UniqSM (ScUsage, CoreExpr)
+
+scApp env (Var fn, args)       -- Function is a variable
+  = ASSERT( not (null args) )
+    do { args_w_usgs <- mapM (scExpr env) args
+       ; let (arg_usgs, args') = unzip args_w_usgs
+             arg_usg = combineUsages arg_usgs
+       ; case scSubstId env fn of
+           fn'@(Lam {}) -> scExpr (zapScSubst env) (doBeta fn' args')
+                       -- Do beta-reduction and try again
+
+           Var fn' -> return (arg_usg `combineUsage` fn_usg, mkApps (Var fn') args')
+               where
+                 fn_usg = case lookupHowBound env fn' of
+                               Just RecFun -> SCU { scu_calls = unitVarEnv fn' [(sc_vals env, args')], 
+                                                    scu_occs  = emptyVarEnv }
+                               Just RecArg -> SCU { scu_calls = emptyVarEnv,
+                                                    scu_occs  = unitVarEnv fn' (ScrutOcc emptyUFM) }
+                               Nothing     -> nullUsage
+
+
+           other_fn' -> return (arg_usg, mkApps other_fn' args') }
+               -- NB: doing this ignores any usage info from the substituted
+               --     function, but I don't think that matters.  If it does
+               --     we can fix it.
+  where
+    doBeta :: OutExpr -> [OutExpr] -> OutExpr
+    -- ToDo: adjust for System IF
+    doBeta (Lam bndr body) (arg : args) = Let (NonRec bndr arg) (doBeta body args)
+    doBeta fn             args         = mkApps fn args
+
+-- The function is almost always a variable, but not always.  
+-- In particular, if this pass follows float-in,
+-- which it may, we can get 
+--     (let f = ...f... in f) arg1 arg2
+scApp env (other_fn, args)
+  = do         { (fn_usg,   fn')   <- scExpr env other_fn
+       ; (arg_usgs, args') <- mapAndUnzipM (scExpr env) args
+       ; return (combineUsages arg_usgs `combineUsage` fn_usg, mkApps fn' args') }
+
 ----------------------
-scBind :: ScEnv -> CoreBind -> UniqSM (ScEnv, ScUsage, CoreBind)
-scBind env (Rec prs)
-  | not (all (couldBeSmallEnoughToInline (sc_size env)) rhss)
+scTopBind :: ScEnv -> CoreBind -> UniqSM (ScEnv, CoreBind)
+scTopBind env (Rec prs)
+  | Just threshold <- sc_size env
+  , not force_spec
+  , not (all (couldBeSmallEnoughToInline threshold) rhss)
                -- No specialisation
   = do { let (rhs_env,bndrs') = extendRecBndrs env bndrs
-       ; (rhs_usgs, rhss') <- mapAndUnzipUs (scExpr rhs_env) rhss
-       ; return (rhs_env, combineUsages rhs_usgs, Rec (bndrs' `zip` rhss')) }
+       ; (_, rhss') <- mapAndUnzipM (scExpr rhs_env) rhss
+       ; return (rhs_env, Rec (bndrs' `zip` rhss')) }
   | otherwise  -- Do specialisation
   = do { let (rhs_env1,bndrs') = extendRecBndrs env bndrs
              rhs_env2 = extendHowBound rhs_env1 bndrs' RecFun
 
-       ; (rhs_usgs, rhs_infos) <- mapAndUnzipUs (scRecRhs rhs_env2) (bndrs' `zip` rhss)
+       ; (rhs_usgs, rhs_infos) <- mapAndUnzipM (scRecRhs rhs_env2) (bndrs' `zip` rhss)
        ; let rhs_usg = combineUsages rhs_usgs
 
-       ; (spec_usg, specs) <- spec_loop rhs_env2 (calls rhs_usg)
-                                        (repeat [] `zip` rhs_infos)
-
-       ; let all_usg = rhs_usg `combineUsage` spec_usg
+       ; (_, specs) <- specLoop rhs_env2 force_spec
+                                 (scu_calls rhs_usg) rhs_infos nullUsage
+                                [SI [] 0 Nothing | _ <- bndrs]
 
        ; return (rhs_env1,  -- For the body of the letrec, delete the RecFun business
-                 all_usg { calls = calls rhs_usg `delVarEnvList` bndrs' },
-                 Rec (concat (zipWith addRules rhs_infos specs))) }
+                 Rec (concat (zipWith specInfoBinds rhs_infos specs))) }
   where
     (bndrs,rhss) = unzip prs
+    force_spec = any (forceSpecBndr env) bndrs
+      -- Note [Forcing specialisation]
 
-    spec_loop :: ScEnv
-             -> CallEnv
-             -> [([CallPat], RhsInfo)]                 -- One per binder
-             -> UniqSM (ScUsage, [[SpecInfo]])         -- One list per binder
-    spec_loop env all_calls rhs_stuff
-       = do { (spec_usg_s, new_pats_s, specs) <- mapAndUnzip3Us (specialise env all_calls) rhs_stuff
-            ; let spec_usg = combineUsages spec_usg_s
-            ; if all null new_pats_s then
-               return (spec_usg, specs) else do
-            { (spec_usg1, specs1) <- spec_loop env (calls spec_usg) 
-                                               (zipWith add_pats new_pats_s rhs_stuff)
-            ; return (spec_usg `combineUsage` spec_usg1, zipWith (++) specs specs1) } }
-
-    add_pats :: [CallPat] -> ([CallPat], RhsInfo) -> ([CallPat], RhsInfo)
-    add_pats new_pats (done_pats, rhs_info) = (done_pats ++ new_pats, rhs_info)
-
-scBind env (NonRec bndr rhs)
-  = do { (usg, rhs') <- scExpr env rhs
-       ; let (env', bndr') = extendBndr env bndr
-       ; return (env', usg, NonRec bndr' rhs') }
+scTopBind env (NonRec bndr rhs)
+  = do { (_, rhs') <- scExpr env rhs
+       ; let (env1, bndr') = extendBndr env bndr
+             env2 = extendValEnv env1 bndr' (isValue (sc_vals env) rhs')
+       ; return (env2, NonRec bndr' rhs') }
 
 ----------------------
 scRecRhs :: ScEnv -> (OutId, InExpr) -> UniqSM (ScUsage, RhsInfo)
@@ -869,25 +1109,26 @@ scRecRhs env (bndr,rhs)
              (body_env, arg_bndrs') = extendBndrsWith RecArg env arg_bndrs
        ; (body_usg, body') <- scExpr body_env body
        ; let (rhs_usg, arg_occs) = lookupOccs body_usg arg_bndrs'
-       ; return (rhs_usg, (bndr, arg_bndrs', body', arg_occs)) }
-
+       ; return (rhs_usg, RI bndr (mkLams arg_bndrs' body')
+                                   arg_bndrs body arg_occs) }
                -- The arg_occs says how the visible,
                -- lambda-bound binders of the RHS are used
                -- (including the TyVar binders)
                -- Two pats are the same if they match both ways
 
 ----------------------
-addRules :: RhsInfo -> [SpecInfo] -> [(Id,CoreExpr)]
-addRules (fn, args, body, _) specs
-  = [(id,rhs) | (_,id,rhs) <- specs] ++ 
-    [(fn `addIdSpecialisations` rules, mkLams args body)]
+specInfoBinds :: RhsInfo -> SpecInfo -> [(Id,CoreExpr)]
+specInfoBinds (RI fn new_rhs _ _ _) (SI specs _ _)
+  = [(id,rhs) | OS _ _ id rhs <- specs] ++ 
+    [(fn `addIdSpecialisations` rules, new_rhs)]
   where
-    rules = [r | (r,_,_) <- specs]
+    rules = [r | OS _ r _ _ <- specs]
 
 ----------------------
+varUsage :: ScEnv -> OutVar -> ArgOcc -> ScUsage
 varUsage env v use 
-  | Just RecArg <- lookupHowBound env v = SCU { calls = emptyVarEnv, 
-                                               occs = unitVarEnv v use }
+  | Just RecArg <- lookupHowBound env v = SCU { scu_calls = emptyVarEnv 
+                                             , scu_occs = unitVarEnv v use }
   | otherwise                          = nullUsage
 \end{code}
 
@@ -899,49 +1140,114 @@ varUsage env v use
 %************************************************************************
 
 \begin{code}
-type RhsInfo = (OutId, [OutVar], OutExpr, [ArgOcc])
-       -- Info about the *original* RHS of a binding we are specialising
-       -- Original binding f = \xs.body
-       -- Plus info about usage of arguments
+data RhsInfo = RI OutId                -- The binder
+                  OutExpr              -- The new RHS
+                 [InVar] InExpr        -- The *original* RHS (\xs.body)
+                                       --   Note [Specialise original body]
+                  [ArgOcc]             -- Info on how the xs occur in body
 
-type SpecInfo = (CoreRule, OutId, OutExpr)
-       -- One specialisation: Rule plus definition
+data SpecInfo = SI [OneSpec]           -- The specialisations we have generated
+
+                  Int                  -- Length of specs; used for numbering them
 
+                  (Maybe ScUsage)      -- Nothing => we have generated specialisations
+                                       --            from calls in the *original* RHS
+                                       -- Just cs => we haven't, and this is the usage
+                                       --            of the original RHS
+                                       -- See Note [Local recursive groups]
+
+       -- One specialisation: Rule plus definition
+data OneSpec  = OS CallPat             -- Call pattern that generated this specialisation
+                  CoreRule             -- Rule connecting original id with the specialisation
+                  OutId OutExpr        -- Spec id + its rhs
+
+
+specLoop :: ScEnv
+         -> Bool                                -- force specialisation?
+                                                -- Note [Forcing specialisation]
+        -> CallEnv
+        -> [RhsInfo]
+        -> ScUsage -> [SpecInfo]               -- One per binder; acccumulating parameter
+        -> UniqSM (ScUsage, [SpecInfo])        -- ...ditto...
+specLoop env force_spec all_calls rhs_infos usg_so_far specs_so_far
+  = do { specs_w_usg <- zipWithM (specialise env force_spec all_calls) rhs_infos specs_so_far
+       ; let (new_usg_s, all_specs) = unzip specs_w_usg
+             new_usg   = combineUsages new_usg_s
+             new_calls = scu_calls new_usg
+             all_usg   = usg_so_far `combineUsage` new_usg
+       ; if isEmptyVarEnv new_calls then
+               return (all_usg, all_specs) 
+         else 
+               specLoop env force_spec new_calls rhs_infos all_usg all_specs }
 
 specialise 
    :: ScEnv
+   -> Bool                              -- force specialisation?
+                                        --   Note [Forcing specialisation]
    -> CallEnv                          -- Info on calls
-   -> ([CallPat], RhsInfo)             -- Original RHS plus patterns dealt with
-   -> UniqSM (ScUsage, [CallPat], [SpecInfo])  -- Specialised calls
+   -> RhsInfo
+   -> SpecInfo                         -- Original RHS plus patterns dealt with
+   -> UniqSM (ScUsage, SpecInfo)       -- New specialised versions and their usage
 
 -- Note: the rhs here is the optimised version of the original rhs
 -- So when we make a specialised copy of the RHS, we're starting
 -- from an RHS whose nested functions have been optimised already.
 
-specialise env bind_calls (done_pats, (fn, arg_bndrs, body, arg_occs))
-  | notNull arg_bndrs, -- Only specialise functions
-    Just all_calls <- lookupVarEnv bind_calls fn
-  = do { pats <- callsToPats env done_pats arg_occs all_calls
---     ; pprTrace "specialise" (vcat [ppr fn <+> ppr arg_occs,
---                                     text "calls" <+> ppr all_calls,
---                                     text "good pats" <+> ppr pats])  $
+specialise env force_spec bind_calls (RI fn _ arg_bndrs body arg_occs) 
+                         spec_info@(SI specs spec_count mb_unspec)
+  | not (isBottomingId fn)      -- Note [Do not specialise diverging functions]
+  , not (isNeverActive (idInlineActivation fn))        -- See Note [Transfer activation]
+  , notNull arg_bndrs          -- Only specialise functions
+  , Just all_calls <- lookupVarEnv bind_calls fn
+  = do { (boring_call, pats) <- callsToPats env specs arg_occs all_calls
+--     ; pprTrace "specialise" (vcat [ ppr fn <+> text "with" <+> int (length pats) <+> text "good patterns"
+--                                      , text "arg_occs" <+> ppr arg_occs
+--                                   , text "calls" <+> ppr all_calls
+--                                   , text "good pats" <+> ppr pats])  $
 --       return ()
 
-       ; (spec_usgs, specs) <- mapAndUnzipUs (spec_one env fn arg_bndrs body)
-                                             (pats `zip` [length done_pats..])
-
-       ; return (combineUsages spec_usgs, pats, specs) }
+               -- Bale out if too many specialisations
+       ; let n_pats      = length pats
+              spec_count' = n_pats + spec_count
+       ; case sc_count env of
+           Just max | not force_spec && spec_count' > max
+               -> pprTrace "SpecConstr" msg $  
+                   return (nullUsage, spec_info)
+               where
+                  msg = vcat [ sep [ ptext (sLit "Function") <+> quotes (ppr fn)
+                                   , nest 2 (ptext (sLit "has") <+> 
+                                              speakNOf spec_count' (ptext (sLit "call pattern")) <> comma <+>
+                                              ptext (sLit "but the limit is") <+> int max) ]
+                             , ptext (sLit "Use -fspec-constr-count=n to set the bound")
+                             , extra ]
+                  extra | not opt_PprStyle_Debug = ptext (sLit "Use -dppr-debug to see specialisations")
+                        | otherwise = ptext (sLit "Specialisations:") <+> ppr (pats ++ [p | OS p _ _ _ <- specs])
+
+           _normal_case -> do {
+
+          let spec_env = decreaseSpecCount env n_pats
+       ; (spec_usgs, new_specs) <- mapAndUnzipM (spec_one spec_env fn arg_bndrs body)
+                                                (pats `zip` [spec_count..])
+               -- See Note [Specialise original body]
+
+       ; let spec_usg = combineUsages spec_usgs
+             (new_usg, mb_unspec')
+                 = case mb_unspec of
+                     Just rhs_usg | boring_call -> (spec_usg `combineUsage` rhs_usg, Nothing)
+                     _                          -> (spec_usg,                      mb_unspec)
+           
+       ; return (new_usg, SI (new_specs ++ specs) spec_count' mb_unspec') } }
   | otherwise
-  = return (nullUsage, [], [])         -- The boring case
+  = return (nullUsage, spec_info)              -- The boring case
 
 
 ---------------------
 spec_one :: ScEnv
         -> OutId       -- Function
-        -> [Var]       -- Lambda-binders of RHS; should match patterns
-        -> CoreExpr    -- Body of the original function
-        -> (([Var], [CoreArg]), Int)
-        -> UniqSM (ScUsage, SpecInfo)  -- Rule and binding
+        -> [InVar]     -- Lambda-binders of RHS; should match patterns
+        -> InExpr      -- Body of the original function
+        -> (CallPat, Int)
+        -> UniqSM (ScUsage, OneSpec)   -- Rule and binding
 
 -- spec_one creates a specialised copy of the function, together
 -- with a rule for using it.  I'm very proud of how short this
@@ -965,45 +1271,110 @@ spec_one :: ScEnv
            f (b,c) ((:) (a,(b,c)) (x,v) hw) = f_spec b c v hw
 -}
 
-spec_one env fn arg_bndrs body ((qvars, pats), rule_number)
-  = do {       -- Specialise the body
-         let spec_env = extendScSubst (extendScInScope env qvars)
-                                      (arg_bndrs `zip` pats)
+spec_one env fn arg_bndrs body (call_pat@(qvars, pats), rule_number)
+  = do { spec_uniq <- getUniqueUs
+        ; let spec_env = extendScSubstList (extendScInScope env qvars)
+                                          (arg_bndrs `zip` pats)
+             fn_name    = idName fn
+             fn_loc     = nameSrcSpan fn_name
+             spec_occ   = mkSpecOcc (nameOccName fn_name)
+             rule_name  = mkFastString ("SC:" ++ showSDoc (ppr fn <> int rule_number))
+             spec_name  = mkInternalName spec_uniq spec_occ fn_loc
+--     ; pprTrace "{spec_one" (ppr (sc_count env) <+> ppr fn <+> ppr pats <+> text "-->" <+> ppr spec_name) $ 
+--       return ()
+
+       -- Specialise the body
        ; (spec_usg, spec_body) <- scExpr spec_env body
 
---     ; pprTrace "spec_one" (ppr fn <+> vcat [text "pats" <+> ppr pats,
---                     text "calls" <+> (ppr (calls spec_usg))])
---       (return ())
+--     ; pprTrace "done spec_one}" (ppr fn) $ 
+--       return ()
 
                -- And build the results
-       ; spec_uniq <- getUniqueUs
-       ; let (spec_lam_args, spec_call_args) = mkWorkerArgs qvars body_ty
+       ; let spec_id = mkLocalId spec_name (mkPiTypes spec_lam_args body_ty) 
+                            `setIdStrictness` spec_str         -- See Note [Transfer strictness]
+                            `setIdArity` count isId spec_lam_args
+             spec_str   = calcSpecStrictness fn spec_lam_args pats
+             (spec_lam_args, spec_call_args) = mkWorkerArgs qvars body_ty
                -- Usual w/w hack to avoid generating 
                -- a spec_rhs of unlifted type and no args
-       
-             fn_name   = idName fn
-             fn_loc    = nameSrcSpan fn_name
-             spec_occ  = mkSpecOcc (nameOccName fn_name)
-             rule_name = mkFastString ("SC:" ++ showSDoc (ppr fn <> int rule_number))
-             spec_rhs  = mkLams spec_lam_args spec_body
-             spec_id   = mkUserLocal spec_occ spec_uniq (mkPiTypes spec_lam_args body_ty) fn_loc
-             body_ty   = exprType spec_body
-             rule_rhs  = mkVarApps (Var spec_id) spec_call_args
-             rule      = mkLocalRule rule_name specConstrActivation fn_name qvars pats rule_rhs
-       ; return (spec_usg, (rule, spec_id, spec_rhs)) }
-
--- In which phase should the specialise-constructor rules be active?
--- Originally I made them always-active, but Manuel found that
--- this defeated some clever user-written rules.  So Plan B
--- is to make them active only in Phase 0; after all, currently,
--- the specConstr transformation is only run after the simplifier
--- has reached Phase 0.  In general one would want it to be 
--- flag-controllable, but for now I'm leaving it baked in
---                                     [SLPJ Oct 01]
-specConstrActivation :: Activation
-specConstrActivation = ActiveAfter 0   -- Baked in; see comments above
+
+              spec_rhs   = mkLams spec_lam_args spec_body
+             body_ty    = exprType spec_body
+             rule_rhs   = mkVarApps (Var spec_id) spec_call_args
+              inline_act = idInlineActivation fn
+             rule       = mkRule True {- Auto -} True {- Local -}
+                                  rule_name inline_act fn_name qvars pats rule_rhs
+                          -- See Note [Transfer activation]
+       ; return (spec_usg, OS call_pat rule spec_id spec_rhs) }
+
+calcSpecStrictness :: Id                    -- The original function
+                   -> [Var] -> [CoreExpr]    -- Call pattern
+                  -> StrictSig              -- Strictness of specialised thing
+-- See Note [Transfer strictness]
+calcSpecStrictness fn qvars pats
+  = StrictSig (mkTopDmdType spec_dmds TopRes)
+  where
+    spec_dmds = [ lookupVarEnv dmd_env qv `orElse` lazyDmd | qv <- qvars, isId qv ]
+    StrictSig (DmdType _ dmds _) = idStrictness fn
+
+    dmd_env = go emptyVarEnv dmds pats
+
+    go env ds (Type {} : pats) = go env ds pats
+    go env (d:ds) (pat : pats) = go (go_one env d pat) ds pats
+    go env _      _            = env
+
+    go_one env d   (Var v) = extendVarEnv_C both env v d
+    go_one env (Box d)   e = go_one env d e
+    go_one env (Eval (Prod ds)) e 
+          | (Var _, args) <- collectArgs e = go env ds args
+    go_one env _         _ = env
+
 \end{code}
 
+Note [Specialise original body]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The RhsInfo for a binding keeps the *original* body of the binding.  We
+must specialise that, *not* the result of applying specExpr to the RHS
+(which is also kept in RhsInfo). Otherwise we end up specialising a
+specialised RHS, and that can lead directly to exponential behaviour.
+
+Note [Transfer activation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+  This note is for SpecConstr, but exactly the same thing
+  happens in the overloading specialiser; see
+  Note [Auto-specialisation and RULES] in Specialise.
+
+In which phase should the specialise-constructor rules be active?
+Originally I made them always-active, but Manuel found that this
+defeated some clever user-written rules.  Then I made them active only
+in Phase 0; after all, currently, the specConstr transformation is
+only run after the simplifier has reached Phase 0, but that meant
+that specialisations didn't fire inside wrappers; see test
+simplCore/should_compile/spec-inline.
+
+So now I just use the inline-activation of the parent Id, as the
+activation for the specialiation RULE, just like the main specialiser;
+
+This in turn means there is no point in specialising NOINLINE things,
+so we test for that.
+
+Note [Transfer strictness]
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+We must transfer strictness information from the original function to
+the specialised one.  Suppose, for example
+
+  f has strictness     SS
+        and a RULE     f (a:as) b = f_spec a as b
+
+Now we want f_spec to have strictess  LLS, otherwise we'll use call-by-need
+when calling f_spec instead of call-by-value.  And that can result in 
+unbounded worsening in space (cf the classic foldl vs foldl')
+
+See Trac #3437 for a good example.
+
+The function calcSpecStrictness performs the calculation.
+
+
 %************************************************************************
 %*                                                                     *
 \subsection{Argument analysis}
@@ -1018,17 +1389,20 @@ they are constructor applications.
 type CallPat = ([Var], [CoreExpr])     -- Quantified variables and arguments
 
 
-callsToPats :: ScEnv -> [CallPat] -> [ArgOcc] -> [Call] -> UniqSM [CallPat]
+callsToPats :: ScEnv -> [OneSpec] -> [ArgOcc] -> [Call] -> UniqSM (Bool, [CallPat])
        -- Result has no duplicate patterns, 
        -- nor ones mentioned in done_pats
-callsToPats env done_pats bndr_occs calls
+       -- Bool indicates that there was at least one boring pattern
+callsToPats env done_specs bndr_occs calls
   = do { mb_pats <- mapM (callToPats env bndr_occs) calls
 
        ; let good_pats :: [([Var], [CoreArg])]
              good_pats = catMaybes mb_pats
+             done_pats = [p | OS p _ _ _ <- done_specs] 
              is_done p = any (samePat p) done_pats
 
-       ; return (filterOut is_done (nubBy samePat good_pats)) }
+       ; return (any isNothing mb_pats, 
+                 filterOut is_done (nubBy samePat good_pats)) }
 
 callToPats :: ScEnv -> [ArgOcc] -> Call -> UniqSM (Maybe CallPat)
        -- The [Var] is the variables to quantify over in the rule
@@ -1040,21 +1414,21 @@ callToPats env bndr_occs (con_env, args)
   = return Nothing
   | otherwise
   = do { let in_scope = substInScope (sc_subst env)
-       ; prs <- argsToPats in_scope con_env (args `zip` bndr_occs)
-       ; let (good_pats, pats) = unzip prs
+       ; prs <- argsToPats env in_scope con_env (args `zip` bndr_occs)
+       ; let (interesting_s, pats) = unzip prs
              pat_fvs = varSetElems (exprsFreeVars pats)
              qvars   = filterOut (`elemInScopeSet` in_scope) pat_fvs
                -- Quantify over variables that are not in sccpe
                -- at the call site
                -- See Note [Shadowing] at the top
                
-             (tvs, ids) = partition isTyVar qvars
+             (tvs, ids) = partition isTyCoVar qvars
              qvars'     = tvs ++ ids
                -- Put the type variables first; the type of a term
                -- variable may mention a type variable
 
        ; -- pprTrace "callToPats"  (ppr args $$ ppr prs $$ ppr bndr_occs) $
-         if or good_pats 
+         if or interesting_s
          then return (Just (qvars', pats))
          else return Nothing }
 
@@ -1064,8 +1438,9 @@ callToPats env bndr_occs (con_env, args)
     -- placeholder variables.  For example:
     --    C a (D (f x) (g y))  ==>  C p1 (D p2 p3)
 
-argToPat :: InScopeSet                 -- What's in scope at the fn defn site
-        -> ConstrEnv                   -- ConstrEnv at the call site
+argToPat :: ScEnv
+         -> InScopeSet                 -- What's in scope at the fn defn site
+        -> ValueEnv                    -- ValueEnv at the call site
         -> CoreArg                     -- A call arg (or component thereof)
         -> ArgOcc
         -> UniqSM (Bool, CoreArg)
@@ -1079,11 +1454,11 @@ argToPat :: InScopeSet                  -- What's in scope at the fn defn site
 --             lvl7         --> (True, lvl7)      if lvl7 is bound 
 --                                                somewhere further out
 
-argToPat in_scope con_env arg@(Type ty) arg_occ
+argToPat _env _in_scope _val_env arg@(Type {}) _arg_occ
   = return (False, arg)
 
-argToPat in_scope con_env (Note n arg) arg_occ
-  = argToPat in_scope con_env arg arg_occ
+argToPat env in_scope val_env (Note _ arg) arg_occ
+  = argToPat env in_scope val_env arg arg_occ
        -- Note [Notes in call patterns]
        -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        -- Ignore Notes.  In particular, we want to ignore any InlineMe notes
@@ -1091,23 +1466,39 @@ argToPat in_scope con_env (Note n arg) arg_occ
        -- ride roughshod over them all for now.
        --- See Note [Notes in RULE matching] in Rules
 
-argToPat in_scope con_env (Let _ arg) arg_occ
-  = argToPat in_scope con_env arg arg_occ
+argToPat env in_scope val_env (Let _ arg) arg_occ
+  = argToPat env in_scope val_env arg arg_occ
+       -- See Note [Matching lets] in Rule.lhs
        -- Look through let expressions
-       -- e.g.         f (let v = rhs in \y -> ...v...)
-       -- Here we can specialise for f (\y -> ...)
+       -- e.g.         f (let v = rhs in (v,w))
+       -- Here we can specialise for f (v,w)
        -- because the rule-matcher will look through the let.
 
-argToPat in_scope con_env (Cast arg co) arg_occ
-  = do { (interesting, arg') <- argToPat in_scope con_env arg arg_occ
-       ; if interesting then 
-               return (interesting, Cast arg' co)
-         else 
-               wildCardPat (snd (coercionKind co)) }
+{- Disabled; see Note [Matching cases] in Rule.lhs
+argToPat env in_scope val_env (Case scrut _ _ [(_, _, rhs)]) arg_occ
+  | exprOkForSpeculation scrut -- See Note [Matching cases] in Rule.hhs
+  = argToPat env in_scope val_env rhs arg_occ
+-}
+
+argToPat env in_scope val_env (Cast arg co) arg_occ
+  | not (ignoreType env ty2)
+  = do { (interesting, arg') <- argToPat env in_scope val_env arg arg_occ
+       ; if not interesting then 
+               wildCardPat ty2
+         else do
+       { -- Make a wild-card pattern for the coercion
+         uniq <- getUniqueUs
+       ; let co_name = mkSysTvName uniq (fsLit "sg")
+             co_var = mkCoVar co_name (mkCoKind ty1 ty2)
+       ; return (interesting, Cast arg' (mkTyVarTy co_var)) } }
+  where
+    (ty1, ty2) = coercionKind co
+
+    
 
 {-     Disabling lambda specialisation for now
        It's fragile, and the spec_loop can be infinite
-argToPat in_scope con_env arg arg_occ
+argToPat in_scope val_env arg arg_occ
   | is_value_lam arg
   = return (True, arg)
   where
@@ -1119,15 +1510,16 @@ argToPat in_scope con_env arg arg_occ
 
   -- Check for a constructor application
   -- NB: this *precedes* the Var case, so that we catch nullary constrs
-argToPat in_scope con_env arg arg_occ
-  | Just (CV dc args) <- isConApp con_env arg
+argToPat env in_scope val_env arg arg_occ
+  | Just (ConVal dc args) <- isValue val_env arg
+  , not (ignoreAltCon env dc)
   , case arg_occ of
        ScrutOcc _ -> True              -- Used only by case scrutinee
        BothOcc    -> case arg of       -- Used elsewhere
                        App {} -> True  --     see Note [Reboxing]
-                       other  -> False
-       other      -> False     -- No point; the arg is not decomposed
-  = do { args' <- argsToPats in_scope con_env (args `zip` conArgOccs arg_occ dc)
+                       _other -> False
+       _other     -> False     -- No point; the arg is not decomposed
+  = do { args' <- argsToPats env in_scope val_env (args `zip` conArgOccs arg_occ dc)
        ; return (True, mk_con_app dc (map snd args')) }
 
   -- Check if the argument is a variable that 
@@ -1135,74 +1527,101 @@ argToPat in_scope con_env arg arg_occ
   -- It's worth specialising on this if
   --   (a) it's used in an interesting way in the body
   --   (b) we know what its value is
-argToPat in_scope con_env (Var v) arg_occ
-  | not (isLocalId v) || v `elemInScopeSet` in_scope,
-    case arg_occ of { UnkOcc -> False; other -> True },        -- (a)
-    isValueUnfolding (idUnfolding v)                   -- (b)
+argToPat env in_scope val_env (Var v) arg_occ
+  | case arg_occ of { UnkOcc -> False; _other -> True },       -- (a)
+    is_value,                                                  -- (b)
+    not (ignoreType env (varType v))
   = return (True, Var v)
+  where
+    is_value 
+       | isLocalId v = v `elemInScopeSet` in_scope 
+                       && isJust (lookupVarEnv val_env v)
+               -- Local variables have values in val_env
+       | otherwise   = isValueUnfolding (idUnfolding v)
+               -- Imports have unfoldings
 
 --     I'm really not sure what this comment means
 --     And by not wild-carding we tend to get forall'd 
 --     variables that are in soope, which in turn can
 --     expose the weakness in let-matching
 --     See Note [Matching lets] in Rules
+
   -- Check for a variable bound inside the function. 
   -- Don't make a wild-card, because we may usefully share
   --   e.g.  f a = let x = ... in f (x,x)
   -- NB: this case follows the lambda and con-app cases!!
-argToPat in_scope con_env (Var v) arg_occ
-  = return (False, Var v)
+-- argToPat _in_scope _val_env (Var v) _arg_occ
+--   = return (False, Var v)
+       -- SLPJ : disabling this to avoid proliferation of versions
+       -- also works badly when thinking about seeding the loop
+       -- from the body of the let
+       --       f x y = letrec g z = ... in g (x,y)
+       -- We don't want to specialise for that *particular* x,y
 
   -- The default case: make a wild-card
-argToPat in_scope con_env arg arg_occ
+argToPat _env _in_scope _val_env arg _arg_occ
   = wildCardPat (exprType arg)
 
 wildCardPat :: Type -> UniqSM (Bool, CoreArg)
 wildCardPat ty = do { uniq <- getUniqueUs
-                   ; let id = mkSysLocal FSLIT("sc") uniq ty
+                   ; let id = mkSysLocal (fsLit "sc") uniq ty
                    ; return (False, Var id) }
 
-argsToPats :: InScopeSet -> ConstrEnv
+argsToPats :: ScEnv -> InScopeSet -> ValueEnv
           -> [(CoreArg, ArgOcc)]
           -> UniqSM [(Bool, CoreArg)]
-argsToPats in_scope con_env args
-  = mapUs do_one args
+argsToPats env in_scope val_env args
+  = mapM do_one args
   where
-    do_one (arg,occ) = argToPat in_scope con_env arg occ
+    do_one (arg,occ) = argToPat env in_scope val_env arg occ
 \end{code}
 
 
 \begin{code}
-isConApp :: ConstrEnv -> CoreExpr -> Maybe ConValue
-isConApp env (Lit lit)
-  = Just (CV (LitAlt lit) [])
-
-isConApp env expr      -- Maybe it's a constructor application
-  | (Var fun, args) <- collectArgs expr,
-    Just con <- isDataConWorkId_maybe fun,
-    args `lengthAtLeast` dataConRepArity con
-       -- Might be > because the arity excludes type args
-  = Just (CV (DataAlt con) args)
-
-isConApp env (Var v)
+isValue :: ValueEnv -> CoreExpr -> Maybe Value
+isValue _env (Lit lit)
+  = Just (ConVal (LitAlt lit) [])
+
+isValue env (Var v)
   | Just stuff <- lookupVarEnv env v
   = Just stuff -- You might think we could look in the idUnfolding here
                -- but that doesn't take account of which branch of a 
                -- case we are in, which is the whole point
 
   | not (isLocalId v) && isCheapUnfolding unf
-  = isConApp env (unfoldingTemplate unf)
+  = isValue env (unfoldingTemplate unf)
   where
     unf = idUnfolding v
        -- However we do want to consult the unfolding 
        -- as well, for let-bound constructors!
 
-isConApp env expr = Nothing
+isValue env (Lam b e)
+  | isTyCoVar b = case isValue env e of
+                 Just _  -> Just LambdaVal
+                 Nothing -> Nothing
+  | otherwise = Just LambdaVal
+
+isValue _env expr      -- Maybe it's a constructor application
+  | (Var fun, args) <- collectArgs expr
+  = case isDataConWorkId_maybe fun of
+
+       Just con | args `lengthAtLeast` dataConRepArity con 
+               -- Check saturated; might be > because the 
+               --                  arity excludes type args
+               -> Just (ConVal (DataAlt con) args)
+
+       _other | valArgCount args < idArity fun
+               -- Under-applied function
+              -> Just LambdaVal        -- Partial application
+
+       _other -> Nothing
+
+isValue _env _expr = Nothing
 
 mk_con_app :: AltCon -> [CoreArg] -> CoreExpr
 mk_con_app (LitAlt lit)  []   = Lit lit
 mk_con_app (DataAlt con) args = mkConApp con args
-mk_con_app other args = panic "SpecConstr.mk_con_app"
+mk_con_app _other _args = panic "SpecConstr.mk_con_app"
 
 samePat :: CallPat -> CallPat -> Bool
 samePat (vs1, as1) (vs2, as2)
@@ -1216,7 +1635,7 @@ samePat (vs1, as1) (vs2, as2)
     same (Lit l1)    (Lit l2)    = l1==l2
     same (App f1 a1) (App f2 a2) = same f1 f2 && same a1 a2
 
-    same (Type t1) (Type t2) = True    -- Note [Ignore type differences]
+    same (Type {}) (Type {}) = True    -- Note [Ignore type differences]
     same (Note _ e1) e2        = same e1 e2    -- Ignore casts and notes
     same (Cast e1 _) e2        = same e1 e2
     same e1 (Note _ e2) = same e1 e2
@@ -1224,12 +1643,10 @@ samePat (vs1, as1) (vs2, as2)
 
     same e1 e2 = WARN( bad e1 || bad e2, ppr e1 $$ ppr e2) 
                 False  -- Let, lambda, case should not occur
-#ifdef DEBUG
     bad (Case {}) = True
     bad (Let {})  = True
     bad (Lam {})  = True
-    bad other    = False
-#endif
+    bad _other   = False
 \end{code}
 
 Note [Ignore type differences]