activeInline, activeRule, inlineMode,
-- The continuation type
- SimplCont(..), DupFlag(..), LetRhsFlag(..),
+ SimplCont(..), DupFlag(..), ArgInfo(..),
contIsDupable, contResultType, contIsTrivial, contArgs, dropArgs,
countValArgs, countArgs, splitInlineCont,
mkBoringStop, mkLazyArgStop, mkRhsStop, contIsRhsOrArg,
import VarSet
import BasicTypes
import Util
+import MonadUtils
import Outputable
+
import List( nub )
\end{code}
data SimplCont
= Stop -- An empty context, or hole, []
OutType -- Type of the result
- LetRhsFlag
- Bool -- True <=> There is something interesting about
+ CallCtxt -- True <=> There is something interesting about
-- the context, and hence the inliner
-- should be a bit keener (see interestingCallContext)
-- Specifically:
| StrictArg -- e C
OutExpr OutType -- e and its type
- (Bool,[Bool]) -- Whether the function at the head of e has rules,
- SimplCont -- plus strictness flags for further args
-
-data LetRhsFlag = AnArg -- It's just an argument not a let RHS
- | AnRhs -- It's the RHS of a let (so please float lets out of big lambdas)
-
-instance Outputable LetRhsFlag where
- ppr AnArg = ptext SLIT("arg")
- ppr AnRhs = ptext SLIT("rhs")
+ CallCtxt -- Whether *this* argument position is interesting
+ ArgInfo -- Whether the function at the head of e has rules, etc
+ SimplCont -- plus strictness flags for *further* args
+
+data ArgInfo
+ = ArgInfo {
+ ai_rules :: Bool, -- Function has rules (recursively)
+ -- => be keener to inline in all args
+ ai_strs :: [Bool], -- Strictness of arguments
+ -- Usually infinite, but if it is finite it guarantees
+ -- that the function diverges after being given
+ -- that number of args
+ ai_discs :: [Int] -- Discounts for arguments; non-zero => be keener to inline
+ -- Always infinite
+ }
instance Outputable SimplCont where
- ppr (Stop ty is_rhs _) = ptext SLIT("Stop") <> brackets (ppr is_rhs) <+> ppr ty
+ ppr (Stop ty _) = ptext SLIT("Stop") <+> ppr ty
ppr (ApplyTo dup arg se cont) = ((ptext SLIT("ApplyTo") <+> ppr dup <+> pprParendExpr arg)
{- $$ nest 2 (pprSimplEnv se) -}) $$ ppr cont
ppr (StrictBind b _ _ _ cont) = (ptext SLIT("StrictBind") <+> ppr b) $$ ppr cont
- ppr (StrictArg f _ _ cont) = (ptext SLIT("StrictArg") <+> ppr f) $$ ppr cont
+ ppr (StrictArg f _ _ _ cont) = (ptext SLIT("StrictArg") <+> ppr f) $$ ppr cont
ppr (Select dup bndr alts se cont) = (ptext SLIT("Select") <+> ppr dup <+> ppr bndr) $$
(nest 4 (ppr alts)) $$ ppr cont
ppr (CoerceIt co cont) = (ptext SLIT("CoerceIt") <+> ppr co) $$ ppr cont
-------------------
mkBoringStop :: OutType -> SimplCont
-mkBoringStop ty = Stop ty AnArg False
+mkBoringStop ty = Stop ty BoringCtxt
-mkLazyArgStop :: OutType -> Bool -> SimplCont
-mkLazyArgStop ty has_rules = Stop ty AnArg has_rules
+mkLazyArgStop :: OutType -> CallCtxt -> SimplCont
+mkLazyArgStop ty cci = Stop ty cci
mkRhsStop :: OutType -> SimplCont
-mkRhsStop ty = Stop ty AnRhs False
+mkRhsStop ty = Stop ty BoringCtxt
-------------------
contIsRhsOrArg (Stop {}) = True
-------------------
contResultType :: SimplCont -> OutType
-contResultType (Stop to_ty _ _) = to_ty
-contResultType (StrictArg _ _ _ cont) = contResultType cont
+contResultType (Stop to_ty _) = to_ty
+contResultType (StrictArg _ _ _ _ cont) = contResultType cont
contResultType (StrictBind _ _ _ _ cont) = contResultType cont
contResultType (ApplyTo _ _ _ cont) = contResultType cont
contResultType (CoerceIt _ cont) = contResultType cont
splitInlineCont (ApplyTo dup (Type ty) se c)
| Just (c1, c2) <- splitInlineCont c = Just (ApplyTo dup (Type ty) se c1, c2)
-splitInlineCont cont@(Stop ty _ _) = Just (mkBoringStop ty, cont)
+splitInlineCont cont@(Stop ty _) = Just (mkBoringStop ty, cont)
splitInlineCont cont@(StrictBind bndr _ _ se _) = Just (mkBoringStop (substTy se (idType bndr)), cont)
-splitInlineCont cont@(StrictArg _ fun_ty _ _) = Just (mkBoringStop (funArgTy fun_ty), cont)
+splitInlineCont cont@(StrictArg _ fun_ty _ _ _) = Just (mkBoringStop (funArgTy fun_ty), cont)
splitInlineCont other = Nothing
-- NB: the calculation of the type for mkBoringStop is an annoying
-- duplication of the same calucation in mkDupableCont
\begin{code}
-interestingCallContext :: SimplCont -> CallContInfo
+interestingCallContext :: SimplCont -> CallCtxt
interestingCallContext cont
= interesting cont
where
+ interestingCtxt = ArgCtxt False 2 -- Give *some* incentive!
+
interesting (Select _ bndr _ _ _)
- | isDeadBinder bndr = CaseCont
- | otherwise = InterestingCont
+ | isDeadBinder bndr = CaseCtxt
+ | otherwise = interestingCtxt
- interesting (ApplyTo {}) = InterestingCont
- -- Can happen if we have (coerce t (f x)) y
- -- Perhaps True is a bit over-keen, but I've
- -- seen (coerce f) x, where f has an INLINE prag,
- -- So we have to give some motivation for inlining it
- interesting (StrictArg {}) = InterestingCont
- interesting (StrictBind {}) = InterestingCont
- interesting (Stop ty _ yes) = if yes then InterestingCont else BoringCont
- interesting (CoerceIt _ cont) = interesting cont
+ interesting (ApplyTo {}) = interestingCtxt
+ -- Can happen if we have (coerce t (f x)) y
+ -- Perhaps interestingCtxt is a bit over-keen, but I've
+ -- seen (coerce f) x, where f has an INLINE prag,
+ -- So we have to give some motivation for inlining it
+
+ interesting (StrictArg _ _ cci _ _) = cci
+ interesting (StrictBind {}) = BoringCtxt
+ interesting (Stop ty cci) = cci
+ interesting (CoerceIt _ cont) = interesting cont
-- If this call is the arg of a strict function, the context
-- is a bit interesting. If we inline here, we may get useful
-- evaluation information to avoid repeated evals: e.g.
mkArgInfo :: Id
-> Int -- Number of value args
-> SimplCont -- Context of the cal
- -> (Bool, [Bool]) -- Arg info
--- The arg info consists of
--- * A Bool indicating if the function has rules (recursively)
--- * A [Bool] indicating strictness for each arg
--- The [Bool] is usually infinite, but if it is finite it
--- guarantees that the function diverges after being given
--- that number of args
+ -> ArgInfo
mkArgInfo fun n_val_args call_cont
- = (interestingArgContext fun call_cont, fun_stricts)
+ = ArgInfo { ai_rules = interestingArgContext fun call_cont
+ , ai_strs = arg_stricts
+ , ai_discs = arg_discounts }
where
- vanilla_stricts, fun_stricts :: [Bool]
+ vanilla_discounts, arg_discounts :: [Int]
+ vanilla_discounts = repeat 0
+ arg_discounts = case idUnfolding fun of
+ CoreUnfolding _ _ _ _ (UnfoldIfGoodArgs _ discounts _ _)
+ -> discounts ++ vanilla_discounts
+ other -> vanilla_discounts
+
+ vanilla_stricts, arg_stricts :: [Bool]
vanilla_stricts = repeat False
- fun_stricts
+ arg_stricts
= case splitStrictSig (idNewStrictness fun) of
(demands, result_info)
| not (demands `lengthExceeds` n_val_args)
interestingArgContext fn call_cont
= idHasRules fn || go call_cont
where
- go (Select {}) = False
- go (ApplyTo {}) = False
- go (StrictArg {}) = True
- go (StrictBind {}) = False -- ??
- go (CoerceIt _ c) = go c
- go (Stop _ _ interesting) = interesting
+ go (Select {}) = False
+ go (ApplyTo {}) = False
+ go (StrictArg _ _ cci _ _) = interesting cci
+ go (StrictBind {}) = False -- ??
+ go (CoerceIt _ c) = go c
+ go (Stop _ cci) = interesting cci
+
+ interesting (ArgCtxt rules _) = rules
+ interesting other = False
\end{code}
; return (mkLams bndrs body') }
| otherwise
- = returnSmpl (mkLams bndrs body)
+ = return (mkLams bndrs body)
\end{code}
Note [Casts and lambdas]
-- if this is indeed a right-hand side; otherwise
-- we end up floating the thing out, only for float-in
-- to float it right back in again!
- = tryRhsTyLam env bndrs body `thenSmpl` \ (floats, body') ->
- returnSmpl (floats, mkLams bndrs body')
+ = do (floats, body') <- tryRhsTyLam env bndrs body
+ return (floats, mkLams bndrs body')
-}
\begin{code}
tryEtaExpansion :: DynFlags -> OutExpr -> SimplM OutExpr
-- There is at least one runtime binder in the binders
-tryEtaExpansion dflags body
- = getUniquesSmpl `thenSmpl` \ us ->
- returnSmpl (etaExpand fun_arity us body (exprType body))
+tryEtaExpansion dflags body = do
+ us <- getUniquesM
+ return (etaExpand fun_arity us body (exprType body))
where
fun_arity = exprEtaExpandArity dflags body
\end{code}
abstractFloats :: [OutTyVar] -> SimplEnv -> OutExpr -> SimplM ([OutBind], OutExpr)
abstractFloats main_tvs body_env body
= ASSERT( notNull body_floats )
- do { (subst, float_binds) <- mapAccumLSmpl abstract empty_subst body_floats
+ do { (subst, float_binds) <- mapAccumLM abstract empty_subst body_floats
; return (float_binds, CoreSubst.substExpr subst body) }
where
main_tv_set = mkVarSet main_tvs
-- gives rise to problems. SLPJ June 98
abstract subst (Rec prs)
- = do { (poly_ids, poly_apps) <- mapAndUnzipSmpl (mk_poly tvs_here) ids
+ = do { (poly_ids, poly_apps) <- mapAndUnzipM (mk_poly tvs_here) ids
; let subst' = CoreSubst.extendSubstList subst (ids `zip` poly_apps)
poly_rhss = [mkLams tvs_here (CoreSubst.substExpr subst' rhs) | rhs <- rhss]
; return (subst', Rec (poly_ids `zip` poly_rhss)) }
tvs_here = main_tvs
mk_poly tvs_here var
- = do { uniq <- getUniqueSmpl
+ = do { uniq <- getUniqueM
; let poly_name = setNameUnique (idName var) uniq -- Keep same name
poly_ty = mkForAllTys tvs_here (idType var) -- But new type of course
poly_id = mkLocalId poly_name poly_ty
[con] -> -- It matches exactly one constructor, so fill it in
do { tick (FillInCaseDefault case_bndr)
- ; us <- getUniquesSmpl
+ ; us <- getUniquesM
; let (ex_tvs, co_tvs, arg_ids) =
dataConRepInstPat us con inst_tys
; return [(DataAlt con, ex_tvs ++ co_tvs ++ arg_ids, deflt_rhs)] }
mkCase scrut case_bndr ty alts -- Identity case
| all identity_alt alts
- = tick (CaseIdentity case_bndr) `thenSmpl_`
- returnSmpl (re_cast scrut)
+ = do tick (CaseIdentity case_bndr)
+ return (re_cast scrut)
where
identity_alt (con, args, rhs) = check_eq con args (de_cast rhs)
--------------------------------------------------
-- Catch-all
--------------------------------------------------
-mkCase scrut bndr ty alts = returnSmpl (Case scrut bndr ty alts)
+mkCase scrut bndr ty alts = return (Case scrut bndr ty alts)
\end{code}