Do not call preInlineUnconditionally in simplNonRecX
[ghc-hetmet.git] / compiler / simplCore / Simplify.lhs
index 5ea0a91..4a71774 100644 (file)
@@ -13,16 +13,16 @@ import DynFlags     ( dopt, DynFlag(Opt_D_dump_inlinings),
                        )
 import SimplMonad
 import SimplEnv        
-import SimplUtils      ( mkCase, mkLam, prepareAlts,
+import SimplUtils      ( mkCase, mkLam,
                          SimplCont(..), DupFlag(..), LetRhsFlag(..), 
-                         mkRhsStop, mkBoringStop,  pushContArgs,
+                         mkRhsStop, mkBoringStop,  mkLazyArgStop, pushContArgs,
                          contResultType, countArgs, contIsDupable, contIsRhsOrArg,
                          getContArgs, interestingCallContext, interestingArg, isStrictType,
                          preInlineUnconditionally, postInlineUnconditionally, 
-                         inlineMode, activeInline, activeRule
+                         interestingArgContext, inlineMode, activeInline, activeRule
                        )
 import Id              ( Id, idType, idInfo, idArity, isDataConWorkId, 
-                         setIdUnfolding, isDeadBinder,
+                         idUnfolding, setIdUnfolding, isDeadBinder,
                          idNewDemandInfo, setIdInfo, 
                          setIdOccInfo, zapLamIdInfo, setOneShotLambda
                        )
@@ -34,15 +34,16 @@ import IdInfo               ( OccInfo(..), isLoopBreaker,
                          occInfo
                        )
 import NewDemand       ( isStrictDmd )
-import Unify           ( coreRefineTys )
-import DataCon         ( dataConTyCon, dataConRepStrictness, isVanillaDataCon )
-import TyCon           ( tyConArity )
+import Unify           ( coreRefineTys, dataConCanMatch )
+import DataCon         ( DataCon, dataConTyCon, dataConRepStrictness, isVanillaDataCon,
+                         dataConInstArgTys, dataConTyVars )
+import TyCon           ( tyConArity, isAlgTyCon, isNewTyCon, tyConDataCons_maybe )
 import CoreSyn
 import PprCore         ( pprParendExpr, pprCoreExpr )
 import CoreUnfold      ( mkUnfolding, callSiteInline )
 import CoreUtils       ( exprIsDupable, exprIsTrivial, needsCaseBinding,
                          exprIsConApp_maybe, mkPiTypes, findAlt, 
-                         exprType, exprIsHNF, 
+                         exprType, exprIsHNF, findDefault, mergeAlts,
                          exprOkForSpeculation, exprArity, 
                          mkCoerce, mkCoerce2, mkSCC, mkInlineMe, applyTypeToArg
                        )
@@ -50,19 +51,23 @@ import Rules                ( lookupRule )
 import BasicTypes      ( isMarkedStrict )
 import CostCentre      ( currentCCS )
 import Type            ( TvSubstEnv, isUnLiftedType, seqType, tyConAppArgs, funArgTy,
-                         splitFunTy_maybe, splitFunTy, coreEqType 
+                         splitFunTy_maybe, splitFunTy, coreEqType, splitTyConApp_maybe,
+                         isTyVarTy, mkTyVarTys
                        )
+import Var             ( tyVarKind, mkTyVar )
 import VarEnv          ( elemVarEnv, emptyVarEnv )
 import TysPrim         ( realWorldStatePrimTy )
 import PrelInfo                ( realWorldPrimId )
 import BasicTypes      ( TopLevelFlag(..), isTopLevel, 
                          RecFlag(..), isNonRec
                        )
+import Name            ( mkSysTvName )
 import StaticFlags     ( opt_PprStyle_Debug )
 import OrdList
+import List            ( nub )
 import Maybes          ( orElse )
 import Outputable
-import Util             ( notNull )
+import Util             ( notNull, filterOut )
 \end{code}
 
 
@@ -359,6 +364,7 @@ simplNonRecX env bndr new_rhs thing_inside
     let body' = wrapFloats floats body in 
     returnSmpl (emptyFloats env, Case new_rhs bndr' (exprType body') [(DEFAULT, [], body')])
 
+{- No, no, no!  Do not try preInlineUnconditionally 
   | preInlineUnconditionally env NotTopLevel bndr new_rhs
        -- This happens; for example, the case_bndr during case of
        -- known constructor:  case (a,b) of x { (p,q) -> ... }
@@ -369,6 +375,7 @@ simplNonRecX env bndr new_rhs thing_inside
        -- e.g.  case (f x, g y) of (a,b) -> ....
        -- If a,b occur once we can avoid constructing the let binding for them.
   = thing_inside (extendIdSubst env bndr (DoneEx new_rhs))
+-}
 
   | otherwise
   = simplBinder env bndr       `thenSmpl` \ (env, bndr') ->
@@ -864,9 +871,6 @@ simplNote env (SCC cc) e cont
   = simplExpr (setEnclosingCC env currentCCS) e        `thenSmpl` \ e' ->
     rebuild env (mkSCC cc e') cont
 
-simplNote env InlineCall e cont
-  = simplExprF env e (InlinePlease cont)
-
 -- See notes with SimplMonad.inlineMode
 simplNote env InlineMe e cont
   | contIsRhsOrArg cont                -- Totally boring continuation; see notes above
@@ -914,11 +918,12 @@ completeCall env var occ_info cont
   =     -- Simplify the arguments
     getDOptsSmpl                                       `thenSmpl` \ dflags ->
     let
-       chkr                           = getSwitchChecker env
-       (args, call_cont, inline_call) = getContArgs chkr var cont
-       fn_ty                          = idType var
+       chkr              = getSwitchChecker env
+       (args, call_cont) = getContArgs chkr var cont
+       fn_ty             = idType var
     in
-    simplifyArgs env fn_ty args (contResultType call_cont)     $ \ env args ->
+    simplifyArgs env fn_ty (interestingArgContext var call_cont) args 
+                (contResultType call_cont)     $ \ env args ->
 
        -- Next, look for rules or specialisations that match
        --
@@ -971,13 +976,11 @@ completeCall env var occ_info cont
        -- Next, look for an inlining
     let
        arg_infos = [ interestingArg arg | arg <- args, isValArg arg]
-
        interesting_cont = interestingCallContext (notNull args)
                                                  (notNull arg_infos)
                                                  call_cont
-
        active_inline = activeInline env var occ_info
-       maybe_inline  = callSiteInline dflags active_inline inline_call occ_info
+       maybe_inline  = callSiteInline dflags active_inline occ_info
                                       var arg_infos interesting_cont
     in
     case maybe_inline of {
@@ -1048,6 +1051,7 @@ makeThatCall env var fun args cont
 
 simplifyArgs :: SimplEnv 
             -> OutType                         -- Type of the function
+            -> Bool                            -- True if the fn has RULES
             -> [(InExpr, SimplEnv, Bool)]      -- Details of the arguments
             -> OutType                         -- Type of the continuation
             -> (SimplEnv -> [OutExpr] -> SimplM FloatsWithExpr)
@@ -1078,19 +1082,19 @@ simplifyArgs :: SimplEnv
 -- discard the entire application and replace it with (error "foo").  Getting
 -- all this at once is TOO HARD!
 
-simplifyArgs env fn_ty args cont_ty thing_inside
+simplifyArgs env fn_ty has_rules args cont_ty thing_inside
   = go env fn_ty args thing_inside
   where
     go env fn_ty []        thing_inside = thing_inside env []
-    go env fn_ty (arg:args) thing_inside = simplifyArg env fn_ty arg cont_ty           $ \ env arg' ->
+    go env fn_ty (arg:args) thing_inside = simplifyArg env fn_ty has_rules arg cont_ty $ \ env arg' ->
                                           go env (applyTypeToArg fn_ty arg') args      $ \ env args' ->
                                           thing_inside env (arg':args')
 
-simplifyArg env fn_ty (Type ty_arg, se, _) cont_ty thing_inside
+simplifyArg env fn_ty has_rules (Type ty_arg, se, _) cont_ty thing_inside
   = simplType (setInScope se env) ty_arg       `thenSmpl` \ new_ty_arg ->
     thing_inside env (Type new_ty_arg)
 
-simplifyArg env fn_ty (val_arg, arg_se, is_strict) cont_ty thing_inside 
+simplifyArg env fn_ty has_rules (val_arg, arg_se, is_strict) cont_ty thing_inside 
   | is_strict 
   = simplStrictArg AnArg env val_arg arg_se arg_ty cont_ty thing_inside
 
@@ -1100,8 +1104,8 @@ simplifyArg env fn_ty (val_arg, arg_se, is_strict) cont_ty thing_inside
                -- have to be very careful about bogus strictness through 
                -- floating a demanded let.
   = simplExprC (setInScope arg_se env) val_arg
-              (mkBoringStop arg_ty)            `thenSmpl` \ arg1 ->
-   thing_inside env arg1
+              (mkLazyArgStop arg_ty has_rules)         `thenSmpl` \ arg1 ->
+    thing_inside env arg1
   where
     arg_ty = funArgTy fn_ty
 
@@ -1250,7 +1254,6 @@ rebuild :: SimplEnv -> OutExpr -> SimplCont -> SimplM FloatsWithExpr
 rebuild env expr (Stop _ _ _)                = rebuildDone env expr
 rebuild env expr (ArgOf _ _ _ cont_fn)       = cont_fn env expr
 rebuild env expr (CoerceIt to_ty cont)       = rebuild env (mkCoerce to_ty expr) cont
-rebuild env expr (InlinePlease cont)         = rebuild env (Note InlineCall expr) cont
 rebuild env expr (Select _ bndr alts se cont) = rebuildCase (setInScope se env) expr bndr alts cont
 rebuild env expr (ApplyTo _ arg se cont)      = rebuildApp  (setInScope se env) expr arg cont
 
@@ -1292,13 +1295,10 @@ rebuildCase env scrut case_bndr alts cont
   = knownCon env (LitAlt lit) [] case_bndr alts cont
 
   | otherwise
-  =    -- Prepare the alternatives.
-    prepareAlts scrut case_bndr alts           `thenSmpl` \ (better_alts, handled_cons) -> 
-       
-       -- Prepare the continuation;
+  =    -- Prepare the continuation;
        -- The new subst_env is in place
-    prepareCaseCont env better_alts cont       `thenSmpl` \ (floats, (dup_cont, nondup_cont)) ->
-    addFloats env floats                       $ \ env ->      
+    prepareCaseCont env alts cont      `thenSmpl` \ (floats, (dup_cont, nondup_cont)) ->
+    addFloats env floats               $ \ env ->      
 
     let
        -- The case expression is annotated with the result type of the continuation
@@ -1316,8 +1316,7 @@ rebuildCase env scrut case_bndr alts cont
     simplCaseBinder env scrut case_bndr        `thenSmpl` \ (alt_env, case_bndr') ->
 
        -- Deal with the case alternatives
-    simplAlts alt_env handled_cons
-             case_bndr' better_alts dup_cont   `thenSmpl` \ alts' ->
+    simplAlts alt_env scrut case_bndr' alts dup_cont   `thenSmpl` \ alts' ->
 
        -- Put the case back together
     mkCase scrut case_bndr' res_ty' alts'      `thenSmpl` \ case_expr ->
@@ -1429,29 +1428,174 @@ simplCaseBinder env other_scrut case_bndr
 \end{code}
 
 
+simplAlts does two things:
+
+1.  Eliminate alternatives that cannot match, including the
+    DEFAULT alternative.
+
+2.  If the DEFAULT alternative can match only one possible constructor,
+    then make that constructor explicit.
+    e.g.
+       case e of x { DEFAULT -> rhs }
+     ===>
+       case e of x { (a,b) -> rhs }
+    where the type is a single constructor type.  This gives better code
+    when rhs also scrutinises x or e.
+
+Here "cannot match" includes knowledge from GADTs
+
+It's a good idea do do this stuff before simplifying the alternatives, to
+avoid simplifying alternatives we know can't happen, and to come up with
+the list of constructors that are handled, to put into the IdInfo of the
+case binder, for use when simplifying the alternatives.
+
+Eliminating the default alternative in (1) isn't so obvious, but it can
+happen:
+
+data Colour = Red | Green | Blue
+
+f x = case x of
+       Red -> ..
+       Green -> ..
+       DEFAULT -> h x
+
+h y = case y of
+       Blue -> ..
+       DEFAULT -> [ case y of ... ]
+
+If we inline h into f, the default case of the inlined h can't happen.
+If we don't notice this, we may end up filtering out *all* the cases
+of the inner case y, which give us nowhere to go!
+
 
 \begin{code}
 simplAlts :: SimplEnv 
-         -> [AltCon]                   -- Alternatives the scrutinee can't be
-                                       -- in the default case
+         -> OutExpr
          -> OutId                      -- Case binder
          -> [InAlt] -> SimplCont
          -> SimplM [OutAlt]            -- Includes the continuation
 
-simplAlts env handled_cons case_bndr' alts cont'
-  = do { mb_alts <- mapSmpl simpl_alt alts
-       ; return [alt' | Just (_, alt') <- mb_alts] }
-       -- Filter out the alternatives that are inaccessible
+simplAlts env scrut case_bndr' alts cont'
+  = do { mb_alts      <- mapSmpl (simplAlt env imposs_cons case_bndr' cont') alts_wo_default
+       ; default_alts <- simplDefault env case_bndr' imposs_deflt_cons cont' maybe_deflt
+       ; return (mergeAlts default_alts [alt' | Just (_, alt') <- mb_alts]) }
+       -- We need the mergeAlts in case the new default_alt 
+       -- has turned into a constructor alternative.
   where
-    simpl_alt alt = simplAlt env handled_cons case_bndr' alt cont'
+    (alts_wo_default, maybe_deflt) = findDefault alts
+    imposs_cons = case scrut of
+                   Var v -> otherCons (idUnfolding v)
+                   other -> []
+
+       -- "imposs_deflt_cons" are handled either by the context, 
+       -- OR by a branch in this case expression. (Don't include DEFAULT!!)
+    imposs_deflt_cons = nub (imposs_cons ++ [con | (con,_,_) <- alts_wo_default])
+
+simplDefault :: SimplEnv
+            -> OutId           -- Case binder; need just for its type. Note that as an
+                               --   OutId, it has maximum information; this is important.
+                               --   Test simpl013 is an example
+            -> [AltCon]        -- These cons can't happen when matching the default
+            -> SimplCont
+            -> Maybe InExpr
+            -> SimplM [OutAlt] -- One branch or none; we use a list because it's what 
+                               --   mergeAlts expects
+
+
+simplDefault env case_bndr' imposs_cons cont Nothing
+  = return []  -- No default branch
+simplDefault env case_bndr' imposs_cons cont (Just rhs)
+  |    -- This branch handles the case where we are 
+       -- scrutinisng an algebraic data type
+    Just (tycon, inst_tys) <- splitTyConApp_maybe (idType case_bndr'),
+    isAlgTyCon tycon,          -- It's a data type, tuple, or unboxed tuples.  
+    not (isNewTyCon tycon),    -- We can have a newtype, if we are just doing an eval:
+                               --      case x of { DEFAULT -> e }
+                               -- and we don't want to fill in a default for them!
+    Just all_cons <- tyConDataCons_maybe tycon,
+    not (null all_cons),       -- This is a tricky corner case.  If the data type has no constructors,
+                               -- which GHC allows, then the case expression will have at most a default
+                               -- alternative.  We don't want to eliminate that alternative, because the
+                               -- invariant is that there's always one alternative.  It's more convenient
+                               -- to leave     
+                               --      case x of { DEFAULT -> e }     
+                               -- as it is, rather than transform it to
+                               --      error "case cant match"
+                               -- which would be quite legitmate.  But it's a really obscure corner, and
+                               -- not worth wasting code on.
+
+    let imposs_data_cons = [con | DataAlt con <- imposs_cons]  -- We now know it's a data type 
+       poss_data_cons   = filterOut (`elem` imposs_data_cons) all_cons
+       gadt_imposs      | all isTyVarTy inst_tys = []
+                        | otherwise = filter (cant_match inst_tys) poss_data_cons
+       final_poss       = filterOut (`elem` gadt_imposs) poss_data_cons
+       
+  = case final_poss of
+       []    -> returnSmpl []  -- Eliminate the default alternative
+                               -- altogether if it can't match
+
+       [con] ->        -- It matches exactly one constructor, so fill it in
+                do { con_alt <- mkDataConAlt case_bndr' con inst_tys rhs
+                   ; Just (_, alt') <- simplAlt env [] case_bndr' cont con_alt
+                       -- The simplAlt must succeed with Just because we have
+                       -- already filtered out construtors that can't match
+                   ; return [alt'] }
 
-simplAlt :: SimplEnv -> [AltCon] -> OutId -> InAlt -> SimplCont
+       two_or_more -> simplify_default (map DataAlt gadt_imposs ++ imposs_cons)
+
+  | otherwise
+  = simplify_default imposs_cons
+  where
+    cant_match tys data_con = not (dataConCanMatch data_con tys)
+
+    simplify_default imposs_cons
+       = do { let env' = mk_rhs_env env case_bndr' (mkOtherCon imposs_cons)
+               -- Record the constructors that the case-binder *can't* be.
+            ; rhs' <- simplExprC env' rhs cont
+            ; return [(DEFAULT, [], rhs')] }
+
+mkDataConAlt :: Id -> DataCon -> [OutType] -> InExpr -> SimplM InAlt
+-- Make a data-constructor alternative to replace the DEFAULT case
+-- NB: there's something a bit bogus here, because we put OutTypes into an InAlt
+mkDataConAlt case_bndr con tys rhs
+  = do         { tick (FillInCaseDefault case_bndr)
+       ; args <- mk_args con tys
+       ; return (DataAlt con, args, rhs) }
+  where
+    mk_args con inst_tys
+      = do { (tv_bndrs, inst_tys') <- mk_tv_bndrs con inst_tys
+          ; let arg_tys = dataConInstArgTys con inst_tys'
+          ; arg_ids <- mapM (newId FSLIT("a")) arg_tys
+          ; returnSmpl (tv_bndrs ++ arg_ids) }
+
+    mk_tv_bndrs con inst_tys
+      | isVanillaDataCon con
+      = return ([], inst_tys)
+      | otherwise
+      = do { tv_uniqs <- getUniquesSmpl
+          ; let new_tvs    = zipWith mk tv_uniqs (dataConTyVars con)
+                mk uniq tv = mkTyVar (mkSysTvName uniq FSLIT("t")) (tyVarKind tv)
+          ; return (new_tvs, mkTyVarTys new_tvs) }
+
+simplAlt :: SimplEnv
+        -> [AltCon]    -- These constructors can't be present when
+                       -- matching this alternative
+        -> OutId       -- The case binder
+        -> SimplCont
+        -> InAlt
         -> SimplM (Maybe (TvSubstEnv, OutAlt))
+
 -- Simplify an alternative, returning the type refinement for the 
 -- alternative, if the alternative does any refinement at all
 -- Nothing => the alternative is inaccessible
 
-simplAlt env handled_cons case_bndr' (DEFAULT, bndrs, rhs) cont'
+simplAlt env imposs_cons case_bndr' cont' (con, bndrs, rhs)
+  | con `elem` imposs_cons     -- This case can't match
+  = return Nothing
+
+simplAlt env handled_cons case_bndr' cont' (DEFAULT, bndrs, rhs)
+       -- TURGID DUPLICATION, needed only for the simplAlt call
+       -- in mkDupableAlt.  Clean this up when moving to FC
   = ASSERT( null bndrs )
     simplExprC env' rhs cont'  `thenSmpl` \ rhs' ->
     returnSmpl (Just (emptyVarEnv, (DEFAULT, [], rhs')))
@@ -1459,14 +1603,14 @@ simplAlt env handled_cons case_bndr' (DEFAULT, bndrs, rhs) cont'
     env' = mk_rhs_env env case_bndr' (mkOtherCon handled_cons)
        -- Record the constructors that the case-binder *can't* be.
 
-simplAlt env handled_cons case_bndr' (LitAlt lit, bndrs, rhs) cont'
+simplAlt env handled_cons case_bndr' cont' (LitAlt lit, bndrs, rhs)
   = ASSERT( null bndrs )
     simplExprC env' rhs cont'  `thenSmpl` \ rhs' ->
     returnSmpl (Just (emptyVarEnv, (LitAlt lit, [], rhs')))
   where
     env' = mk_rhs_env env case_bndr' (mkUnfolding False (Lit lit))
 
-simplAlt env handled_cons case_bndr' (DataAlt con, vs, rhs) cont'
+simplAlt env handled_cons case_bndr' cont' (DataAlt con, vs, rhs)
   | isVanillaDataCon con
   =    -- Deal with the pattern-bound variables
        -- Mark the ones that are in ! positions in the data constructor
@@ -1640,7 +1784,8 @@ prepareCaseCont :: SimplEnv
                -> [InAlt] -> SimplCont
                -> SimplM (FloatsWith (SimplCont,SimplCont))    
                        -- Return a duplicatable continuation, a non-duplicable part 
-                       -- plus some extra bindings
+                       -- plus some extra bindings (that scope over the entire
+                       -- continunation)
 
        -- No need to make it duplicatable if there's only one alternative
 prepareCaseCont env [alt] cont = returnSmpl (emptyFloats env, (cont, mkBoringStop (contResultType cont)))
@@ -1659,10 +1804,6 @@ mkDupableCont env (CoerceIt ty cont)
   = mkDupableCont env cont             `thenSmpl` \ (floats, (dup_cont, nondup_cont)) ->
     returnSmpl (floats, (CoerceIt ty dup_cont, nondup_cont))
 
-mkDupableCont env (InlinePlease cont)
-  = mkDupableCont env cont             `thenSmpl` \ (floats, (dup_cont, nondup_cont)) ->
-    returnSmpl (floats, (InlinePlease dup_cont, nondup_cont))
-
 mkDupableCont env cont@(ArgOf _ arg_ty _ _)
   =  returnSmpl (emptyFloats env, (mkBoringStop arg_ty, cont))
        -- Do *not* duplicate an ArgOf continuation
@@ -1696,56 +1837,56 @@ mkDupableCont env (ApplyTo _ arg se cont)
        --      ==>
        --              let a = ...arg... 
        --              in [...hole...] a
-    simplExpr (setInScope se env) arg                  `thenSmpl` \ arg' ->
-
-    mkDupableCont env cont                             `thenSmpl` \ (floats, (dup_cont, nondup_cont)) ->
-    addFloats env floats                               $ \ env ->
-
-    if exprIsDupable arg' then
-       returnSmpl (emptyFloats env, (ApplyTo OkToDup arg' (zapSubstEnv se) dup_cont, nondup_cont))
-    else
-    newId FSLIT("a") (exprType arg')                   `thenSmpl` \ arg_id ->
-
-    tick (CaseOfCase arg_id)                           `thenSmpl_`
-       -- Want to tick here so that we go round again,
-       -- and maybe copy or inline the code.
-       -- Not strictly CaseOfCase, but never mind
-
-    returnSmpl (unitFloat env arg_id arg', 
-               (ApplyTo OkToDup (Var arg_id) (zapSubstEnv se) dup_cont,
-                nondup_cont))
-       -- But what if the arg should be case-bound? 
-       -- This has been this way for a long time, so I'll leave it,
-       -- but I can't convince myself that it's right.
+    do { (floats, (dup_cont, nondup_cont)) <- mkDupableCont env cont
+       ; addFloats env floats $ \ env -> do
+       { arg1 <- simplExpr (setInScope se env) arg
+       ; (floats2, arg2) <- mkDupableArg env arg1
+       ; return (floats2, (ApplyTo OkToDup arg2 (zapSubstEnv se) dup_cont, nondup_cont)) }}
 
 mkDupableCont env (Select _ case_bndr alts se cont)
   =    -- e.g.         (case [...hole...] of { pi -> ei })
        --      ===>
        --              let ji = \xij -> ei 
        --              in case [...hole...] of { pi -> ji xij }
-    tick (CaseOfCase case_bndr)                                        `thenSmpl_`
-    let
-       alt_env = setInScope se env
-    in
-    prepareCaseCont alt_env alts cont                          `thenSmpl` \ (floats1, (dup_cont, nondup_cont)) ->
-    addFloats alt_env floats1                                  $ \ alt_env ->
-
-    simplBinder alt_env case_bndr                              `thenSmpl` \ (alt_env, case_bndr') ->
-       -- NB: simplBinder does not zap deadness occ-info, so
-       -- a dead case_bndr' will still advertise its deadness
-       -- This is really important because in
-       --      case e of b { (# a,b #) -> ... }
-       -- b is always dead, and indeed we are not allowed to bind b to (# a,b #),
-       -- which might happen if e was an explicit unboxed pair and b wasn't marked dead.
-       -- In the new alts we build, we have the new case binder, so it must retain
-       -- its deadness.
-
-    mkDupableAlts alt_env case_bndr' alts dup_cont     `thenSmpl` \ (floats2, alts') ->
-    addFloats alt_env floats2                          $ \ alt_env ->
-    returnSmpl (emptyFloats alt_env, 
-               (Select OkToDup case_bndr' alts' (zapSubstEnv se) 
-                       (mkBoringStop (contResultType dup_cont)),
-                nondup_cont))
+    do { tick (CaseOfCase case_bndr)
+       ; let alt_env = setInScope se env
+       ; (floats1, (dup_cont, nondup_cont)) <- mkDupableCont alt_env cont
+               -- NB: call mkDupableCont here, *not* prepareCaseCont
+               -- We must make a duplicable continuation, whereas prepareCaseCont
+               -- doesn't when there is a single case branch
+       ; addFloats alt_env floats1     $ \ alt_env -> do
+
+       { (alt_env, case_bndr') <- simplBinder alt_env case_bndr
+               -- NB: simplBinder does not zap deadness occ-info, so
+               -- a dead case_bndr' will still advertise its deadness
+               -- This is really important because in
+               --      case e of b { (# a,b #) -> ... }
+               -- b is always dead, and indeed we are not allowed to bind b to (# a,b #),
+               -- which might happen if e was an explicit unboxed pair and b wasn't marked dead.
+               -- In the new alts we build, we have the new case binder, so it must retain
+               -- its deadness.
+
+       ; (floats2, alts') <- mkDupableAlts alt_env case_bndr' alts dup_cont
+       ; return (floats2, (Select OkToDup case_bndr' alts' (zapSubstEnv se) 
+                                  (mkBoringStop (contResultType dup_cont)),
+                           nondup_cont))
+       }}
+
+mkDupableArg :: SimplEnv -> OutExpr -> SimplM (FloatsWith OutExpr)
+-- Let-bind the thing if necessary
+mkDupableArg env arg
+  | exprIsDupable arg 
+  = return (emptyFloats env, arg)
+  | otherwise     
+  = do { arg_id <- newId FSLIT("a") (exprType arg)
+       ; tick (CaseOfCase arg_id)
+               -- Want to tick here so that we go round again,
+               -- and maybe copy or inline the code.
+               -- Not strictly CaseOfCase, but never mind
+       ; return (unitFloat env arg_id arg, Var arg_id) }
+       -- What if the arg should be case-bound? 
+       -- This has been this way for a long time, so I'll leave it,
+       -- but I can't convince myself that it's right.
 
 mkDupableAlts :: SimplEnv -> OutId -> [InAlt] -> SimplCont
              -> SimplM (FloatsWith [InAlt])
@@ -1765,7 +1906,7 @@ mkDupableAlts env case_bndr' alts dupable_cont
                          )}}
                                        
 mkDupableAlt env case_bndr' cont alt
-  = simplAlt env [] case_bndr' alt cont                `thenSmpl` \ mb_stuff ->
+  = simplAlt env [] case_bndr' cont alt                `thenSmpl` \ mb_stuff ->
     case mb_stuff of {
        Nothing -> returnSmpl (emptyFloats env, Nothing) ;