)
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}
(args, call_cont, inline_call) = 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
var arg_infos interesting_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)
-- 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
-- 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
= 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'] }
+
+ two_or_more -> simplify_default (map DataAlt gadt_imposs ++ imposs_cons)
-simplAlt :: SimplEnv -> [AltCon] -> OutId -> InAlt -> SimplCont
+ | 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)))
-- ==>
-- 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])
)}}
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) ;