X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2FsimplCore%2FSimplify.lhs;h=17a6bcc4e2ed1bfa141e22ce0972db069a8cb432;hb=33406b8c7668247e52cb6260297640b9df4e9e1b;hp=5ea0a91007d35fe3319a558a6af4c5bf8f45f967;hpb=0065d5ab628975892cea1ec7303f968c3338cbe1;p=ghc-hetmet.git diff --git a/compiler/simplCore/Simplify.lhs b/compiler/simplCore/Simplify.lhs index 5ea0a91..17a6bcc 100644 --- a/compiler/simplCore/Simplify.lhs +++ b/compiler/simplCore/Simplify.lhs @@ -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,7 +364,10 @@ simplNonRecX env bndr new_rhs thing_inside let body' = wrapFloats floats body in returnSmpl (emptyFloats env, Case new_rhs bndr' (exprType body') [(DEFAULT, [], body')]) - | preInlineUnconditionally env NotTopLevel bndr new_rhs +{- No, no, no! Do not try preInlineUnconditionally + 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 @@ -368,7 +376,9 @@ 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') -> @@ -701,7 +711,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 ) @@ -761,25 +771,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 @@ -829,7 +846,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 @@ -846,10 +863,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 @@ -864,9 +883,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 +930,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 +988,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 { @@ -990,7 +1005,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! @@ -998,43 +1013,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} %************************************************************************ %* * @@ -1048,7 +1027,8 @@ makeThatCall env var fun args cont simplifyArgs :: SimplEnv -> OutType -- Type of the function - -> [(InExpr, SimplEnv, Bool)] -- Details of the arguments + -> Bool -- True if the fn has RULES + -> [(InExpr, Maybe SimplEnv, Bool)] -- Details of the arguments -> OutType -- Type of the continuation -> (SimplEnv -> [OutExpr] -> SimplM FloatsWithExpr) -> SimplM FloatsWithExpr @@ -1078,19 +1058,22 @@ 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 (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 (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 @@ -1100,8 +1083,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,13 +1233,16 @@ 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 +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} @@ -1292,13 +1278,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 +1299,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 +1411,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 +1586,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 +1767,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 +1787,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 @@ -1691,61 +1815,61 @@ 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 - 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 <- simplArg env arg mb_se + ; (floats2, arg2) <- mkDupableArg env arg1 + ; return (floats2, (ApplyTo OkToDup arg2 Nothing 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 +1889,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) ;