)
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
)
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
)
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}
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
-- 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') ->
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 )
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
| 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
-- 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
= 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
= -- 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
--
-- 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 {
text "Cont: " <+> ppr call_cont])
else
id) $
- makeThatCall env var unfolding args call_cont
+ simplExprF env unfolding (pushContArgs args call_cont)
;
Nothing -> -- No inlining!
-- 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}
%************************************************************************
%* *
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
-- 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
-- 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
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}
= 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
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 ->
\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')))
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
-> [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)))
= 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
-- 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])
)}}
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) ;