import SimplEnv
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,
idUnfolding, setIdUnfolding, isDeadBinder,
= 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 {
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
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
-> [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 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])