X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2FsimplCore%2FSimplify.lhs;h=12505b76b06925f46841a1781ca78cc0a2c52320;hb=905941e45d80c193703fa65498c4e0b8d9dd9899;hp=d8f9506b23c0c42fb20ca431ad52ea333fce8f85;hpb=f2dcf256399e9a2de6343c625630b51f8abf4863;p=ghc-hetmet.git diff --git a/compiler/simplCore/Simplify.lhs b/compiler/simplCore/Simplify.lhs index d8f9506..12505b7 100644 --- a/compiler/simplCore/Simplify.lhs +++ b/compiler/simplCore/Simplify.lhs @@ -320,13 +320,7 @@ simplNonRecBind' env bndr rhs rhs_se cont_ty thing_inside let (env2,bndr2) = addLetIdInfo env1 bndr bndr1 in - if needsCaseBinding bndr_ty rhs1 - then - thing_inside env2 `thenSmpl` \ (floats, body) -> - returnSmpl (emptyFloats env2, Case rhs1 bndr2 (exprType body) - [(DEFAULT, [], wrapFloats floats body)]) - else - completeNonRecX env2 True {- strict -} bndr bndr2 rhs1 thing_inside + completeNonRecX env2 True {- strict -} bndr bndr2 rhs1 thing_inside | otherwise -- Normal, lazy case = -- Don't use simplBinder because that doesn't keep @@ -351,7 +345,21 @@ simplNonRecX :: SimplEnv -> SimplM FloatsWithExpr simplNonRecX env bndr new_rhs thing_inside - | needsCaseBinding (idType bndr) new_rhs + = do { (env, bndr') <- simplBinder env bndr + ; completeNonRecX env False {- Non-strict; pessimistic -} + bndr bndr' new_rhs thing_inside } + + +completeNonRecX :: SimplEnv + -> Bool -- Strict binding + -> InId -- Old binder + -> OutId -- New binder + -> OutExpr -- Simplified RHS + -> (SimplEnv -> SimplM FloatsWithExpr) + -> SimplM FloatsWithExpr + +completeNonRecX env is_strict old_bndr new_bndr new_rhs thing_inside + | needsCaseBinding (idType new_bndr) new_rhs -- Make this test *before* the preInlineUnconditionally -- Consider case I# (quotInt# x y) of -- I# v -> let w = J# v in ... @@ -359,12 +367,24 @@ simplNonRecX env bndr new_rhs thing_inside -- extra thunk: -- let w = J# (quotInt# x y) in ... -- because quotInt# can fail. - = simplBinder env bndr `thenSmpl` \ (env, bndr') -> - thing_inside env `thenSmpl` \ (floats, body) -> - let body' = wrapFloats floats body in - returnSmpl (emptyFloats env, Case new_rhs bndr' (exprType body') [(DEFAULT, [], body')]) + = do { (floats, body) <- thing_inside env + ; let body' = wrapFloats floats body + ; return (emptyFloats env, Case new_rhs new_bndr (exprType body) + [(DEFAULT, [], body')]) } - | preInlineUnconditionally env NotTopLevel bndr new_rhs + | otherwise + = -- Make the arguments atomic if necessary, + -- adding suitable bindings + -- pprTrace "completeNonRecX" (ppr new_bndr <+> ppr new_rhs) $ + mkAtomicArgsE env is_strict new_rhs $ \ env new_rhs -> + completeLazyBind env NotTopLevel + old_bndr new_bndr new_rhs `thenSmpl` \ (floats, env) -> + addFloats env floats thing_inside + +{- No, no, no! Do not try preInlineUnconditionally in completeNonRecX + Doing so risks exponential behaviour, because new_rhs has been simplified once already + In the cases described by the folowing commment, postInlineUnconditionally will + catch many of the relevant cases. -- This happens; for example, the case_bndr during case of -- known constructor: case (a,b) of x { (p,q) -> ... } -- Here x isn't mentioned in the RHS, so we don't want to @@ -373,24 +393,11 @@ simplNonRecX env bndr new_rhs thing_inside -- Similarly, single occurrences can be inlined vigourously -- e.g. case (f x, g y) of (a,b) -> .... -- If a,b occur once we can avoid constructing the let binding for them. + | preInlineUnconditionally env NotTopLevel bndr new_rhs = thing_inside (extendIdSubst env bndr (DoneEx new_rhs)) - | otherwise - = simplBinder env bndr `thenSmpl` \ (env, bndr') -> - completeNonRecX env False {- Non-strict; pessimistic -} - bndr bndr' new_rhs thing_inside - -completeNonRecX env is_strict old_bndr new_bndr new_rhs thing_inside - = mkAtomicArgs is_strict - True {- OK to float unlifted -} - new_rhs `thenSmpl` \ (aux_binds, rhs2) -> - - -- Make the arguments atomic if necessary, - -- adding suitable bindings - addAtomicBindsE env (fromOL aux_binds) $ \ env -> - completeLazyBind env NotTopLevel - old_bndr new_bndr rhs2 `thenSmpl` \ (floats, env) -> - addFloats env floats thing_inside + -- NB: completeLazyBind uses postInlineUnconditionally; no need to do that here +-} \end{code} @@ -530,8 +537,8 @@ simplLazyBind env top_lvl is_rec bndr bndr1 rhs rhs_se -- we only float if (a) arg' is a WHNF, or (b) it's going to top level -- and so there can't be any 'will be demanded' bindings in the floats. -- Hence the warning - ASSERT2( is_top_level || not (any demanded_float (floatBinds floats)), - ppr (filter demanded_float (floatBinds floats)) ) + WARN( not (is_top_level || not (any demanded_float (floatBinds floats))), + ppr (filter demanded_float (floatBinds floats)) ) tick LetFloatFromLet `thenSmpl_` ( addFloats env1 floats $ \ env2 -> @@ -589,6 +596,7 @@ completeLazyBind env top_lvl old_bndr new_bndr new_rhs | postInlineUnconditionally env top_lvl new_bndr occ_info new_rhs unfolding = -- Drop the binding tick (PostInlineUnconditionally old_bndr) `thenSmpl_` + -- pprTrace "Inline unconditionally" (ppr old_bndr <+> ppr new_bndr <+> ppr new_rhs) $ returnSmpl (emptyFloats env, extendIdSubst env old_bndr (DoneEx new_rhs)) -- Use the substitution to make quite, quite sure that the substitution -- will happen, since we are going to discard the binding @@ -627,6 +635,7 @@ completeLazyBind env top_lvl old_bndr new_bndr new_rhs -- These seqs forces the Id, and hence its IdInfo, -- and hence any inner substitutions final_id `seq` + -- pprTrace "Binding" (ppr final_id <+> ppr unfolding) $ returnSmpl (unitFloat env final_id new_rhs, env) where @@ -706,7 +715,7 @@ simplExprF env (Var v) cont = simplVar env v cont simplExprF env (Lit lit) cont = rebuild env (Lit lit) cont simplExprF env expr@(Lam _ _) cont = simplLam env expr cont simplExprF env (Note note expr) cont = simplNote env note expr cont -simplExprF env (App fun arg) cont = simplExprF env fun (ApplyTo NoDup arg env cont) +simplExprF env (App fun arg) cont = simplExprF env fun (ApplyTo NoDup arg (Just env) cont) simplExprF env (Type ty) cont = ASSERT( contIsRhsOrArg cont ) @@ -766,25 +775,32 @@ simplLam env fun cont cont_ty = contResultType cont -- Type-beta reduction - go env (Lam bndr body) (ApplyTo _ (Type ty_arg) arg_se body_cont) + go env (Lam bndr body) (ApplyTo _ (Type ty_arg) mb_arg_se body_cont) = ASSERT( isTyVar bndr ) - tick (BetaReduction bndr) `thenSmpl_` - simplType (setInScope arg_se env) ty_arg `thenSmpl` \ ty_arg' -> - go (extendTvSubst env bndr ty_arg') body body_cont + do { tick (BetaReduction bndr) + ; ty_arg' <- case mb_arg_se of + Just arg_se -> simplType (setInScope arg_se env) ty_arg + Nothing -> return ty_arg + ; go (extendTvSubst env bndr ty_arg') body body_cont } -- Ordinary beta reduction - go env (Lam bndr body) cont@(ApplyTo _ arg arg_se body_cont) - = tick (BetaReduction bndr) `thenSmpl_` - simplNonRecBind env (zap_it bndr) arg arg_se cont_ty $ \ env -> - go env body body_cont + go env (Lam bndr body) cont@(ApplyTo _ arg (Just arg_se) body_cont) + = do { tick (BetaReduction bndr) + ; simplNonRecBind env (zap_it bndr) arg arg_se cont_ty $ \ env -> + go env body body_cont } + + go env (Lam bndr body) cont@(ApplyTo _ arg Nothing body_cont) + = do { tick (BetaReduction bndr) + ; simplNonRecX env (zap_it bndr) arg $ \ env -> + go env body body_cont } -- Not enough args, so there are real lambdas left to put in the result go env lam@(Lam _ _) cont - = simplLamBndrs env bndrs `thenSmpl` \ (env, bndrs') -> - simplExpr env body `thenSmpl` \ body' -> - mkLam env bndrs' body' cont `thenSmpl` \ (floats, new_lam) -> - addFloats env floats $ \ env -> - rebuild env new_lam cont + = do { (env, bndrs') <- simplLamBndrs env bndrs + ; body' <- simplExpr env body + ; (floats, new_lam) <- mkLam env bndrs' body' cont + ; addFloats env floats $ \ env -> + rebuild env new_lam cont } where (bndrs,body) = collectBinders lam @@ -834,7 +850,7 @@ simplNote env (Coerce to from) body cont | otherwise = CoerceIt t1 cont -- They don't cancel, but -- the inner one is redundant - addCoerce t1t2 s1s2 (ApplyTo dup arg arg_se cont) + addCoerce t1t2 s1s2 (ApplyTo dup arg mb_arg_se cont) | not (isTypeArg arg), -- This whole case only works for value args -- Could upgrade to have equiv thing for type apps too Just (s1, s2) <- splitFunTy_maybe s1s2 @@ -851,10 +867,12 @@ simplNote env (Coerce to from) body cont -- But it isn't a common case. = let (t1,t2) = splitFunTy t1t2 - new_arg = mkCoerce2 s1 t1 (substExpr arg_env arg) - arg_env = setInScope arg_se env + new_arg = mkCoerce2 s1 t1 arg' + arg' = case mb_arg_se of + Nothing -> arg + Just arg_se -> substExpr (setInScope arg_se env) arg in - ApplyTo dup new_arg (zapSubstEnv env) (addCoerce t2 s2 cont) + ApplyTo dup new_arg Nothing (addCoerce t2 s2 cont) addCoerce to' _ cont = CoerceIt to' cont in @@ -991,7 +1009,7 @@ completeCall env var occ_info cont text "Cont: " <+> ppr call_cont]) else id) $ - makeThatCall env var unfolding args call_cont + simplExprF env unfolding (pushContArgs args call_cont) ; Nothing -> -- No inlining! @@ -999,43 +1017,7 @@ completeCall env var occ_info cont -- Done rebuild env (mkApps (Var var) args) call_cont }} - -makeThatCall :: SimplEnv - -> Id - -> InExpr -- Inlined function rhs - -> [OutExpr] -- Arguments, already simplified - -> SimplCont -- After the call - -> SimplM FloatsWithExpr --- Similar to simplLam, but this time --- the arguments are already simplified -makeThatCall orig_env var fun@(Lam _ _) args cont - = go orig_env fun args - where - zap_it = mkLamBndrZapper fun (length args) - - -- Type-beta reduction - go env (Lam bndr body) (Type ty_arg : args) - = ASSERT( isTyVar bndr ) - tick (BetaReduction bndr) `thenSmpl_` - go (extendTvSubst env bndr ty_arg) body args - - -- Ordinary beta reduction - go env (Lam bndr body) (arg : args) - = tick (BetaReduction bndr) `thenSmpl_` - simplNonRecX env (zap_it bndr) arg $ \ env -> - go env body args - - -- Not enough args, so there are real lambdas left to put in the result - go env fun args - = simplExprF env fun (pushContArgs orig_env args cont) - -- NB: orig_env; the correct environment to capture with - -- the arguments.... env has been augmented with substitutions - -- from the beta reductions. - -makeThatCall env var fun args cont - = simplExprF env fun (pushContArgs env args cont) -\end{code} - +\end{code} %************************************************************************ %* * @@ -1050,7 +1032,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 + -> [(InExpr, Maybe SimplEnv, Bool)] -- Details of the arguments -> OutType -- Type of the continuation -> (SimplEnv -> [OutExpr] -> SimplM FloatsWithExpr) -> SimplM FloatsWithExpr @@ -1088,11 +1070,14 @@ simplifyArgs env fn_ty has_rules args cont_ty thing_inside go env (applyTypeToArg fn_ty arg') args $ \ env args' -> thing_inside env (arg':args') -simplifyArg env fn_ty has_rules (Type ty_arg, se, _) cont_ty thing_inside +simplifyArg env fn_ty has_rules (arg, Nothing, _) cont_ty thing_inside + = thing_inside env arg -- Already simplified + +simplifyArg env fn_ty has_rules (Type ty_arg, Just 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 has_rules (val_arg, arg_se, is_strict) cont_ty thing_inside +simplifyArg env fn_ty has_rules (val_arg, Just arg_se, is_strict) cont_ty thing_inside | is_strict = simplStrictArg AnArg env val_arg arg_se arg_ty cont_ty thing_inside @@ -1172,6 +1157,38 @@ a *strict* let, then it would be a good thing to do. Hence the context information. \begin{code} +mkAtomicArgsE :: SimplEnv + -> Bool -- A strict binding + -> OutExpr -- The rhs + -> (SimplEnv -> OutExpr -> SimplM FloatsWithExpr) + -> SimplM FloatsWithExpr + +mkAtomicArgsE env is_strict rhs thing_inside + | (Var fun, args) <- collectArgs rhs, -- It's an application + isDataConWorkId fun || valArgCount args < idArity fun -- And it's a constructor or PAP + = go env (Var fun) args + + | otherwise = thing_inside env rhs + + where + go env fun [] = thing_inside env fun + + go env fun (arg : args) + | exprIsTrivial arg -- Easy case + || no_float_arg -- Can't make it atomic + = go env (App fun arg) args + + | otherwise + = do { arg_id <- newId FSLIT("a") arg_ty + ; completeNonRecX env False {- pessimistic -} arg_id arg_id arg $ \env -> + go env (App fun (Var arg_id)) args } + where + arg_ty = exprType arg + no_float_arg = not is_strict && (isUnLiftedType arg_ty) && not (exprOkForSpeculation arg) + + +-- Old code: consider rewriting to be more like mkAtomicArgsE + mkAtomicArgs :: Bool -- A strict binding -> Bool -- OK to float unlifted args -> OutExpr @@ -1218,25 +1235,6 @@ addAtomicBinds :: SimplEnv -> [(OutId,OutExpr)] addAtomicBinds env [] thing_inside = thing_inside env addAtomicBinds env ((v,r):bs) thing_inside = addAuxiliaryBind env (NonRec v r) $ \ env -> addAtomicBinds env bs thing_inside - -addAtomicBindsE :: SimplEnv -> [(OutId,OutExpr)] - -> (SimplEnv -> SimplM FloatsWithExpr) - -> SimplM FloatsWithExpr --- Same again, but this time we're in an expression context, --- and may need to do some case bindings - -addAtomicBindsE env [] thing_inside - = thing_inside env -addAtomicBindsE env ((v,r):bs) thing_inside - | needsCaseBinding (idType v) r - = addAtomicBindsE (addNewInScopeIds env [v]) bs thing_inside `thenSmpl` \ (floats, expr) -> - WARN( exprIsTrivial expr, ppr v <+> pprCoreExpr expr ) - (let body = wrapFloats floats expr in - returnSmpl (emptyFloats env, Case r v (exprType body) [(DEFAULT,[],body)])) - - | otherwise - = addAuxiliaryBind env (NonRec v r) $ \ env -> - addAtomicBindsE env bs thing_inside \end{code} @@ -1253,11 +1251,15 @@ 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 (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 +rebuild env expr (ApplyTo _ arg mb_se cont) = rebuildApp env expr arg mb_se cont + +rebuildApp env fun arg mb_se cont + = do { arg' <- simplArg env arg mb_se + ; rebuild env (App fun arg') cont } -rebuildApp env fun arg cont - = simplExpr env arg `thenSmpl` \ arg' -> - rebuild env (App fun arg') cont +simplArg :: SimplEnv -> CoreExpr -> Maybe SimplEnv -> SimplM CoreExpr +simplArg env arg Nothing = return arg -- The arg is already simplified +simplArg env arg (Just arg_env) = simplExpr (setInScope arg_env env) arg rebuildDone env expr = returnSmpl (emptyFloats env, expr) \end{code} @@ -1286,11 +1288,11 @@ rebuildCase env scrut case_bndr alts cont | Just (con,args) <- exprIsConApp_maybe scrut -- Works when the scrutinee is a variable with a known unfolding -- as well as when it's an explicit constructor application - = knownCon env (DataAlt con) args case_bndr alts cont + = knownCon env scrut (DataAlt con) args case_bndr alts cont | Lit lit <- scrut -- No need for same treatment as constructors -- because literals are inlined more vigorously - = knownCon env (LitAlt lit) [] case_bndr alts cont + = knownCon env scrut (LitAlt lit) [] case_bndr alts cont | otherwise = -- Prepare the continuation; @@ -1412,17 +1414,18 @@ simplCaseBinder env (Var v) case_bndr -- Failed try [see Note 2 above] -- not (isEvaldUnfolding (idUnfolding v)) - = simplBinder env (zap case_bndr) `thenSmpl` \ (env, case_bndr') -> + = simplBinder env (zapOccInfo case_bndr) `thenSmpl` \ (env, case_bndr') -> returnSmpl (modifyInScope env v case_bndr', case_bndr') -- We could extend the substitution instead, but it would be -- a hack because then the substitution wouldn't be idempotent -- any more (v is an OutId). And this does just as well. - where - zap b = b `setIdOccInfo` NoOccInfo simplCaseBinder env other_scrut case_bndr = simplBinder env case_bndr `thenSmpl` \ (env, case_bndr') -> returnSmpl (env, case_bndr') + +zapOccInfo :: InId -> InId +zapOccInfo b = b `setIdOccInfo` NoOccInfo \end{code} @@ -1692,8 +1695,9 @@ simplAlt env handled_cons case_bndr' cont' (DataAlt con, vs, rhs) -- If the case binder is alive, then we add the unfolding -- case_bndr = C vs -- to the envt; so vs are now very much alive + -- Note [Aug06] I can't see why this actually matters zap_occ_info | isDeadBinder case_bndr' = \id -> id - | otherwise = \id -> id `setIdOccInfo` NoOccInfo + | otherwise = zapOccInfo mk_rhs_env env case_bndr' case_bndr_unf = modifyInScope env case_bndr' (case_bndr' `setIdUnfolding` case_bndr_unf) @@ -1720,54 +1724,68 @@ and then All this should happen in one sweep. \begin{code} -knownCon :: SimplEnv -> AltCon -> [OutExpr] +knownCon :: SimplEnv -> OutExpr -> AltCon -> [OutExpr] -> InId -> [InAlt] -> SimplCont -> SimplM FloatsWithExpr -knownCon env con args bndr alts cont - = tick (KnownBranch bndr) `thenSmpl_` +knownCon env scrut con args bndr alts cont + = tick (KnownBranch bndr) `thenSmpl_` case findAlt con alts of (DEFAULT, bs, rhs) -> ASSERT( null bs ) simplNonRecX env bndr scrut $ \ env -> - -- This might give rise to a binding with non-atomic args - -- like x = Node (f x) (g x) - -- but no harm will be done + -- This might give rise to a binding with non-atomic args + -- like x = Node (f x) (g x) + -- but simplNonRecX will atomic-ify it simplExprF env rhs cont - where - scrut = case con of - LitAlt lit -> Lit lit - DataAlt dc -> mkConApp dc args (LitAlt lit, bs, rhs) -> ASSERT( null bs ) - simplNonRecX env bndr (Lit lit) $ \ env -> + simplNonRecX env bndr scrut $ \ env -> simplExprF env rhs cont (DataAlt dc, bs, rhs) -> ASSERT( n_drop_tys + length bs == length args ) - bind_args env bs (drop n_drop_tys args) $ \ env -> + bind_args env dead_bndr bs (drop n_drop_tys args) $ \ env -> let - con_app = mkConApp dc (take n_drop_tys args ++ con_args) + -- It's useful to bind bndr to scrut, rather than to a fresh + -- binding x = Con arg1 .. argn + -- because very often the scrut is a variable, so we avoid + -- creating, and then subsequently eliminating, a let-binding + -- BUT, if scrut is a not a variable, we must be careful + -- about duplicating the arg redexes; in that case, make + -- a new con-app from the args + bndr_rhs = case scrut of + Var v -> scrut + other -> con_app + con_app = mkConApp dc (take n_drop_tys args ++ con_args) con_args = [substExpr env (varToCoreExpr b) | b <- bs] -- args are aready OutExprs, but bs are InIds in - simplNonRecX env bndr con_app $ \ env -> + simplNonRecX env bndr bndr_rhs $ \ env -> simplExprF env rhs cont where + dead_bndr = isDeadBinder bndr n_drop_tys | isVanillaDataCon dc = tyConArity (dataConTyCon dc) | otherwise = 0 -- Vanilla data constructors lack type arguments in the pattern -- Ugh! -bind_args env [] _ thing_inside = thing_inside env +bind_args env dead_bndr [] _ thing_inside = thing_inside env -bind_args env (b:bs) (Type ty : args) thing_inside +bind_args env dead_bndr (b:bs) (Type ty : args) thing_inside = ASSERT( isTyVar b ) - bind_args (extendTvSubst env b ty) bs args thing_inside + bind_args (extendTvSubst env b ty) dead_bndr bs args thing_inside -bind_args env (b:bs) (arg : args) thing_inside +bind_args env dead_bndr (b:bs) (arg : args) thing_inside = ASSERT( isId b ) - simplNonRecX env b arg $ \ env -> - bind_args env bs args thing_inside + let + b' = if dead_bndr then b else zapOccInfo b + -- Note that the binder might be "dead", because it doesn't occur + -- in the RHS; and simplNonRecX may therefore discard it via postInlineUnconditionally + -- Nevertheless we must keep it if the case-binder is alive, because it may + -- be used in teh con_app + in + simplNonRecX env b' arg $ \ env -> + bind_args env dead_bndr bs args thing_inside \end{code} @@ -1830,16 +1848,85 @@ mkDupableCont env cont@(ArgOf _ arg_ty _ _) -- let $j = \a -> ...strict-fn... -- in $j [...hole...] -mkDupableCont env (ApplyTo _ arg se cont) +mkDupableCont env (ApplyTo _ arg mb_se cont) = -- e.g. [...hole...] (...arg...) -- ==> -- let a = ...arg... -- in [...hole...] a do { (floats, (dup_cont, nondup_cont)) <- mkDupableCont env cont ; addFloats env floats $ \ env -> do - { arg1 <- simplExpr (setInScope se env) arg + { arg1 <- simplArg env arg mb_se ; (floats2, arg2) <- mkDupableArg env arg1 - ; return (floats2, (ApplyTo OkToDup arg2 (zapSubstEnv se) dup_cont, nondup_cont)) }} + ; return (floats2, (ApplyTo OkToDup arg2 Nothing dup_cont, nondup_cont)) }} + +mkDupableCont env cont@(Select _ case_bndr [(_,bs,rhs)] se case_cont) +-- | not (exprIsDupable rhs && contIsDupable case_cont) -- See notes below +-- | not (isDeadBinder case_bndr) + | all isDeadBinder bs + = returnSmpl (emptyFloats env, (mkBoringStop scrut_ty, cont)) + where + scrut_ty = substTy se (idType case_bndr) + +{- Note [Single-alternative cases] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This case is just like the ArgOf case. Here's an example: + data T a = MkT !a + ...(MkT (abs x))... +Then we get + case (case x of I# x' -> + case x' <# 0# of + True -> I# (negate# x') + False -> I# x') of y { + DEFAULT -> MkT y +Because the (case x) has only one alternative, we'll transform to + case x of I# x' -> + case (case x' <# 0# of + True -> I# (negate# x') + False -> I# x') of y { + DEFAULT -> MkT y +But now we do *NOT* want to make a join point etc, giving + case x of I# x' -> + let $j = \y -> MkT y + in case x' <# 0# of + True -> $j (I# (negate# x')) + False -> $j (I# x') +In this case the $j will inline again, but suppose there was a big +strict computation enclosing the orginal call to MkT. Then, it won't +"see" the MkT any more, because it's big and won't get duplicated. +And, what is worse, nothing was gained by the case-of-case transform. + +When should use this case of mkDupableCont? +However, matching on *any* single-alternative case is a *disaster*; + e.g. case (case ....) of (a,b) -> (# a,b #) + We must push the outer case into the inner one! +Other choices: + + * Match [(DEFAULT,_,_)], but in the common case of Int, + the alternative-filling-in code turned the outer case into + case (...) of y { I# _ -> MkT y } + + * Match on single alternative plus (not (isDeadBinder case_bndr)) + Rationale: pushing the case inwards won't eliminate the construction. + But there's a risk of + case (...) of y { (a,b) -> let z=(a,b) in ... } + Now y looks dead, but it'll come alive again. Still, this + seems like the best option at the moment. + + * Match on single alternative plus (all (isDeadBinder bndrs)) + Rationale: this is essentially seq. + + * Match when the rhs is *not* duplicable, and hence would lead to a + join point. This catches the disaster-case above. We can test + the *un-simplified* rhs, which is fine. It might get bigger or + smaller after simplification; if it gets smaller, this case might + fire next time round. NB also that we must test contIsDupable + case_cont *btoo, because case_cont might be big! + + HOWEVER: I found that this version doesn't work well, because + we can get let x = case (...) of { small } in ...case x... + When x is inlined into its full context, we find that it was a bad + idea to have pushed the outer case inside the (...) case. +-} mkDupableCont env (Select _ case_bndr alts se cont) = -- e.g. (case [...hole...] of { pi -> ei })