X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2FsimplCore%2FSimplUtils.lhs;h=56b07c480481a5b3f15d47cd52b577da3eafe843;hb=a263737bbf44050a7b5ecbe267ddf85d410b73e5;hp=4ddcfb87767ea43af29380424e2b7b89bd5c8818;hpb=cebea7e7549da2beb83b0baa59909a70dae2a7ad;p=ghc-hetmet.git diff --git a/compiler/simplCore/SimplUtils.lhs b/compiler/simplCore/SimplUtils.lhs index 4ddcfb8..56b07c4 100644 --- a/compiler/simplCore/SimplUtils.lhs +++ b/compiler/simplCore/SimplUtils.lhs @@ -4,27 +4,20 @@ \section[SimplUtils]{The simplifier utilities} \begin{code} -{-# OPTIONS -w #-} --- The above warning supression flag is a temporary kludge. --- While working on this module you are encouraged to remove it and fix --- any warnings in the module. See --- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings --- for details - module SimplUtils ( -- Rebuilding mkLam, mkCase, prepareAlts, bindCaseBndr, -- Inlining, preInlineUnconditionally, postInlineUnconditionally, - activeInline, activeRule, inlineMode, + activeInline, activeRule, -- The continuation type SimplCont(..), DupFlag(..), ArgInfo(..), contIsDupable, contResultType, contIsTrivial, contArgs, dropArgs, - countValArgs, countArgs, splitInlineCont, + countValArgs, countArgs, mkBoringStop, mkLazyArgStop, contIsRhsOrArg, - interestingCallContext, interestingArgContext, + interestingCallContext, interestingArg, mkArgInfo, @@ -41,9 +34,8 @@ import qualified CoreSubst import PprCore import CoreFVs import CoreUtils -import Literal +import CoreArity ( etaExpand, exprEtaExpandArity ) import CoreUnfold -import MkId import Name import Id import Var ( isCoVar ) @@ -52,7 +44,6 @@ import SimplMonad import Type hiding( substTy ) import Coercion ( coercionKind ) import TyCon -import DataCon import Unify ( dataConCannotMatch ) import VarSet import BasicTypes @@ -61,7 +52,7 @@ import MonadUtils import Outputable import FastString -import List( nub ) +import Data.List \end{code} @@ -122,7 +113,7 @@ data SimplCont SimplCont | StrictArg -- e C - OutExpr -- e + OutExpr -- e; *always* of form (Var v `App1` e1 .. `App` en) 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 @@ -141,11 +132,11 @@ data ArgInfo instance Outputable SimplCont where ppr (Stop interesting) = ptext (sLit "Stop") <> brackets (ppr interesting) - ppr (ApplyTo dup arg se cont) = ((ptext (sLit "ApplyTo") <+> ppr dup <+> pprParendExpr arg) + ppr (ApplyTo dup arg _ 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 (Select dup bndr alts se cont) = (ptext (sLit "Select") <+> ppr dup <+> ppr bndr) $$ + ppr (Select dup bndr alts _ 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 @@ -165,25 +156,26 @@ mkLazyArgStop :: CallCtxt -> SimplCont mkLazyArgStop cci = Stop cci ------------------- -contIsRhsOrArg (Stop {}) = True -contIsRhsOrArg (StrictBind {}) = True -contIsRhsOrArg (StrictArg {}) = True -contIsRhsOrArg other = False +contIsRhsOrArg :: SimplCont -> Bool +contIsRhsOrArg (Stop {}) = True +contIsRhsOrArg (StrictBind {}) = True +contIsRhsOrArg (StrictArg {}) = True +contIsRhsOrArg _ = False ------------------- contIsDupable :: SimplCont -> Bool -contIsDupable (Stop {}) = True +contIsDupable (Stop {}) = True contIsDupable (ApplyTo OkToDup _ _ _) = True contIsDupable (Select OkToDup _ _ _ _) = True contIsDupable (CoerceIt _ cont) = contIsDupable cont -contIsDupable other = False +contIsDupable _ = False ------------------- contIsTrivial :: SimplCont -> Bool -contIsTrivial (Stop {}) = True +contIsTrivial (Stop {}) = True contIsTrivial (ApplyTo _ (Type _) _ cont) = contIsTrivial cont -contIsTrivial (CoerceIt _ cont) = contIsTrivial cont -contIsTrivial other = False +contIsTrivial (CoerceIt _ cont) = contIsTrivial cont +contIsTrivial _ = False ------------------- contResultType :: SimplEnv -> OutType -> SimplCont -> OutType @@ -192,25 +184,25 @@ contResultType env ty cont where subst_ty se ty = substTy (se `setInScope` env) ty - go (Stop {}) ty = ty - go (CoerceIt co cont) ty = go cont (snd (coercionKind co)) - go (StrictBind _ bs body se cont) ty = go cont (subst_ty se (exprType (mkLams bs body))) - go (StrictArg fn _ _ cont) ty = go cont (funResultTy (exprType fn)) - go (Select _ _ alts se cont) ty = go cont (subst_ty se (coreAltsType alts)) + go (Stop {}) ty = ty + go (CoerceIt co cont) _ = go cont (snd (coercionKind co)) + go (StrictBind _ bs body se cont) _ = go cont (subst_ty se (exprType (mkLams bs body))) + go (StrictArg fn _ _ cont) _ = go cont (funResultTy (exprType fn)) + go (Select _ _ alts se cont) _ = go cont (subst_ty se (coreAltsType alts)) go (ApplyTo _ arg se cont) ty = go cont (apply_to_arg ty arg se) apply_to_arg ty (Type ty_arg) se = applyTy ty (subst_ty se ty_arg) - apply_to_arg ty other se = funResultTy ty + apply_to_arg ty _ _ = funResultTy ty ------------------- countValArgs :: SimplCont -> Int -countValArgs (ApplyTo _ (Type ty) se cont) = countValArgs cont -countValArgs (ApplyTo _ val_arg se cont) = 1 + countValArgs cont -countValArgs other = 0 +countValArgs (ApplyTo _ (Type _) _ cont) = countValArgs cont +countValArgs (ApplyTo _ _ _ cont) = 1 + countValArgs cont +countValArgs _ = 0 countArgs :: SimplCont -> Int -countArgs (ApplyTo _ arg se cont) = 1 + countArgs cont -countArgs other = 0 +countArgs (ApplyTo _ _ _ cont) = 1 + countArgs cont +countArgs _ = 0 contArgs :: SimplCont -> ([OutExpr], SimplCont) -- Uses substitution to turn each arg into an OutExpr @@ -223,63 +215,11 @@ dropArgs :: Int -> SimplCont -> SimplCont dropArgs 0 cont = cont dropArgs n (ApplyTo _ _ _ cont) = dropArgs (n-1) cont dropArgs n other = pprPanic "dropArgs" (ppr n <+> ppr other) - --------------------- -splitInlineCont :: SimplCont -> Maybe (SimplCont, SimplCont) --- Returns Nothing if the continuation should dissolve an InlineMe Note --- Return Just (c1,c2) otherwise, --- where c1 is the continuation to put inside the InlineMe --- and c2 outside - --- Example: (__inline_me__ (/\a. e)) ty --- Here we want to do the beta-redex without dissolving the InlineMe --- See test simpl017 (and Trac #1627) for a good example of why this is important - -splitInlineCont (ApplyTo dup (Type ty) se c) - | Just (c1, c2) <- splitInlineCont c = Just (ApplyTo dup (Type ty) se c1, c2) -splitInlineCont cont@(Stop {}) = Just (mkBoringStop, cont) -splitInlineCont cont@(StrictBind {}) = Just (mkBoringStop, cont) -splitInlineCont cont@(StrictArg {}) = Just (mkBoringStop, cont) -splitInlineCont other = Nothing -\end{code} - - -\begin{code} -interestingArg :: OutExpr -> Bool - -- An argument is interesting if it has *some* structure - -- We are here trying to avoid unfolding a function that - -- is applied only to variables that have no unfolding - -- (i.e. they are probably lambda bound): f x y z - -- There is little point in inlining f here. -interestingArg (Var v) = hasSomeUnfolding (idUnfolding v) - -- Was: isValueUnfolding (idUnfolding v') - -- But that seems over-pessimistic - || isDataConWorkId v - -- This accounts for an argument like - -- () or [], which is definitely interesting -interestingArg (Type _) = False -interestingArg (App fn (Type _)) = interestingArg fn -interestingArg (Note _ a) = interestingArg a - --- Idea (from Sam B); I'm not sure if it's a good idea, so commented out for now --- interestingArg expr | isUnLiftedType (exprType expr) --- -- Unlifted args are only ever interesting if we know what they are --- = case expr of --- Lit lit -> True --- _ -> False - -interestingArg other = True - -- Consider let x = 3 in f x - -- The substitution will contain (x -> ContEx 3), and we want to - -- to say that x is an interesting argument. - -- But consider also (\x. f x y) y - -- The substitution will contain (x -> ContEx y), and we want to say - -- that x is not interesting (assuming y has no unfolding) \end{code} -Comment about interestingCallContext -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Note [Interesting call context] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We want to avoid inlining an expression where there can't possibly be any gain, such as in an argument position. Hence, if the continuation is interesting (eg. a case scrutinee, application etc.) then we @@ -314,20 +254,21 @@ default case. \begin{code} interestingCallContext :: SimplCont -> CallCtxt +-- See Note [Interesting call context] interestingCallContext cont = interesting cont where - interestingCtxt = ArgCtxt False 2 -- Give *some* incentive! - interesting (Select _ bndr _ _ _) - | isDeadBinder bndr = CaseCtxt - | otherwise = interestingCtxt + | isDeadBinder bndr = CaseCtxt + | otherwise = ArgCtxt False 2 -- If the binder is used, this + -- is like a strict let - 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 (ApplyTo _ arg _ cont) + | isTypeArg arg = interesting cont + | otherwise = ValAppCtxt -- Can happen if we have (f Int |> co) y + -- If f has an INLINE prag we need to give it some + -- motivation to inline. See Note [Cast then apply] + -- in CoreUnfold interesting (StrictArg _ cci _ _) = cci interesting (StrictBind {}) = BoringCtxt @@ -351,26 +292,27 @@ interestingCallContext cont ------------------- mkArgInfo :: Id + -> [CoreRule] -- Rules for function -> Int -- Number of value args - -> SimplCont -- Context of the cal + -> SimplCont -- Context of the call -> ArgInfo -mkArgInfo fun n_val_args call_cont +mkArgInfo fun rules n_val_args call_cont | n_val_args < idArity fun -- Note [Unsaturated functions] = ArgInfo { ai_rules = False , ai_strs = vanilla_stricts , ai_discs = vanilla_discounts } | otherwise - = ArgInfo { ai_rules = interestingArgContext fun call_cont + = ArgInfo { ai_rules = interestingArgContext rules call_cont , ai_strs = add_type_str (idType fun) arg_stricts , ai_discs = arg_discounts } where vanilla_discounts, arg_discounts :: [Int] vanilla_discounts = repeat 0 arg_discounts = case idUnfolding fun of - CoreUnfolding _ _ _ _ (UnfoldIfGoodArgs _ discounts _ _) + CoreUnfolding {uf_guidance = UnfoldIfGoodArgs {ug_args = discounts}} -> discounts ++ vanilla_discounts - other -> vanilla_discounts + _ -> vanilla_discounts vanilla_stricts, arg_stricts :: [Bool] vanilla_stricts = repeat False @@ -402,14 +344,14 @@ mkArgInfo fun n_val_args call_cont -- add_type_str is done repeatedly (for each call); might be better -- once-for-all in the function -- But beware primops/datacons with no strictness - add_type_str fun_ty [] = [] + add_type_str _ [] = [] add_type_str fun_ty strs -- Look through foralls - | Just (tv, fun_ty') <- splitForAllTy_maybe fun_ty -- Includes coercions + | Just (_, fun_ty') <- splitForAllTy_maybe fun_ty -- Includes coercions = add_type_str fun_ty' strs add_type_str fun_ty (str:strs) -- Add strict-type info | Just (arg_ty, fun_ty') <- splitFunTy_maybe fun_ty = (str || isStrictType arg_ty) : add_type_str fun_ty' strs - add_type_str fun_ty strs + add_type_str _ strs = strs {- Note [Unsaturated functions] @@ -422,7 +364,7 @@ it'll just be floated out again. Even if f has lots of discounts on its first argument -- it must be saturated for these to kick in -} -interestingArgContext :: Id -> SimplCont -> Bool +interestingArgContext :: [CoreRule] -> SimplCont -> Bool -- If the argument has form (f x y), where x,y are boring, -- and f is marked INLINE, then we don't want to inline f. -- But if the context of the argument is @@ -433,16 +375,18 @@ interestingArgContext :: Id -> SimplCont -> Bool -- where h has rules, then we do want to inline f; hence the -- call_cont argument to interestingArgContext -- --- The interesting_arg_ctxt flag makes this happen; if it's +-- The ai-rules flag makes this happen; if it's -- set, the inliner gets just enough keener to inline f -- regardless of how boring f's arguments are, if it's marked INLINE -- -- The alternative would be to *always* inline an INLINE function, -- regardless of how boring its context is; but that seems overkill -- For example, it'd mean that wrapper functions were always inlined -interestingArgContext fn call_cont - = idHasRules fn || go call_cont +interestingArgContext rules call_cont + = notNull rules || enclosing_fn_has_rules where + enclosing_fn_has_rules = go call_cont + go (Select {}) = False go (ApplyTo {}) = False go (StrictArg _ cci _ _) = interesting cci @@ -451,7 +395,7 @@ interestingArgContext fn call_cont go (Stop cci) = interesting cci interesting (ArgCtxt rules _) = rules - interesting other = False + interesting _ = False \end{code} @@ -466,7 +410,7 @@ Inlining is controlled partly by the SimplifierMode switch. This has two settings: SimplGently (a) Simplifying before specialiser/full laziness - (b) Simplifiying inside INLINE pragma + (b) Simplifiying inside InlineRules (c) Simplifying the LHS of a rule (d) Simplifying a GHCi expression or Template Haskell splice @@ -487,17 +431,11 @@ running it, we don't want to use -O2. Indeed, we don't want to inline anything, because the byte-code interpreter might get confused about unboxed tuples and suchlike. -INLINE pragmas -~~~~~~~~~~~~~~ -SimplGently is also used as the mode to simplify inside an InlineMe note. - -\begin{code} -inlineMode :: SimplifierMode -inlineMode = SimplGently -\end{code} - -It really is important to switch off inlinings inside such -expressions. Consider the following example +Note [Simplifying gently inside InlineRules] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +We don't do much simplification inside InlineRules (which come from +INLINE pragmas). It really is important to switch off inlinings +inside such expressions. Consider the following example let f = \pq -> BIG in @@ -506,16 +444,14 @@ expressions. Consider the following example in ...g...g...g...g...g... Now, if that's the ONLY occurrence of f, it will be inlined inside g, -and thence copied multiple times when g is inlined. - +and thence copied multiple times when g is inlined. -This function may be inlinined in other modules, so we -don't want to remove (by inlining) calls to functions that have -specialisations, or that may have transformation rules in an importing -scope. +This function may be inlinined in other modules, so we don't want to +remove (by inlining) calls to functions that have specialisations, or +that may have transformation rules in an importing scope. E.g. {-# INLINE f #-} - f x = ...g... + f x = ...g... and suppose that g is strict *and* has specialisations. If we inline g's wrapper, we deny f the chance of getting the specialised version @@ -533,15 +469,14 @@ continuation. That's why the keep_inline predicate returns True for ArgOf continuations. It shouldn't do any harm not to dissolve the inline-me note under these circumstances. -Note that the result is that we do very little simplification -inside an InlineMe. +Although we do very little simplification inside an InlineRule, +the RHS is simplified as normal. For example: all xs = foldr (&&) True xs any p = all . map p {-# INLINE any #-} -Problem: any won't get deforested, and so if it's exported and the -importer doesn't use the inlining, (eg passes it as an arg) then we -won't get deforestation at all. We havn't solved this problem yet! +The RHS of 'any' will get optimised and deforested; but the InlineRule +will still mention the original RHS. preInlineUnconditionally @@ -616,13 +551,13 @@ preInlineUnconditionally env top_lvl bndr rhs | otherwise = case idOccInfo bndr of IAmDead -> True -- Happens in ((\x.1) v) OneOcc in_lam True int_cxt -> try_once in_lam int_cxt - other -> False + _ -> False where phase = getMode env active = case phase of - SimplGently -> isAlwaysActive prag - SimplPhase n _ -> isActive n prag - prag = idInlinePragma bndr + SimplGently -> isEarlyActive act + SimplPhase n _ -> isActive n act + act = idInlineActivation bndr try_once in_lam int_cxt -- There's one textual occurrence | not in_lam = isNotTopLevel top_lvl || early_phase @@ -649,14 +584,14 @@ preInlineUnconditionally env top_lvl bndr rhs -- canInlineInLam => free vars of rhs are (Once in_lam) or Many, -- so substituting rhs inside a lambda doesn't change the occ info. -- Sadly, not quite the same as exprIsHNF. - canInlineInLam (Lit l) = True + canInlineInLam (Lit _) = True canInlineInLam (Lam b e) = isRuntimeVar b || canInlineInLam e canInlineInLam (Note _ e) = canInlineInLam e canInlineInLam _ = False early_phase = case phase of SimplPhase 0 _ -> False - other -> True + _ -> True -- If we don't have this early_phase test, consider -- x = length [1,2,3] -- The full laziness pass carefully floats all the cons cells to @@ -705,7 +640,7 @@ story for now. \begin{code} postInlineUnconditionally :: SimplEnv -> TopLevelFlag - -> InId -- The binder (an OutId would be fine too) + -> OutId -- The binder (an InId would be fine too) -> OccInfo -- From the InId -> OutExpr -> Unfolding @@ -715,6 +650,7 @@ postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding | isLoopBreaker occ_info = False -- If it's a loop-breaker of any kind, don't inline -- because it might be referred to "earlier" | isExportedId bndr = False + | isInlineRule unfolding = False -- Note [InlineRule and postInlineUnconditionally] | exprIsTrivial rhs = True | otherwise = case occ_info of @@ -729,7 +665,7 @@ postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding -- True -> case x of ... -- False -> case x of ... -- I'm not sure how important this is in practice - OneOcc in_lam one_br int_cxt -- OneOcc => no code-duplication issue + OneOcc in_lam _one_br int_cxt -- OneOcc => no code-duplication issue -> smallEnoughToInline unfolding -- Small enough to dup -- ToDo: consider discount on smallEnoughToInline if int_cxt is true -- @@ -760,25 +696,25 @@ postInlineUnconditionally env top_lvl bndr occ_info rhs unfolding -- Here x isn't mentioned in the RHS, so we don't want to -- create the (dead) let-binding let x = (a,b) in ... - other -> False + _ -> False -- Here's an example that we don't handle well: -- let f = if b then Left (\x.BIG) else Right (\y.BIG) -- in \y. ....case f of {...} .... -- Here f is used just once, and duplicating the case work is fine (exprIsCheap). -- But --- * We can't preInlineUnconditionally because that woud invalidate --- the occ info for b. --- * We can't postInlineUnconditionally because the RHS is big, and --- that risks exponential behaviour --- * We can't call-site inline, because the rhs is big +-- - We can't preInlineUnconditionally because that woud invalidate +-- the occ info for b. +-- - We can't postInlineUnconditionally because the RHS is big, and +-- that risks exponential behaviour +-- - We can't call-site inline, because the rhs is big -- Alas! where active = case getMode env of - SimplGently -> isAlwaysActive prag - SimplPhase n _ -> isActive n prag - prag = idInlinePragma bndr + SimplGently -> isAlwaysActive act + SimplPhase n _ -> isActive n act + act = idInlineActivation bndr activeInline :: SimplEnv -> OutId -> Bool activeInline env id @@ -799,14 +735,14 @@ activeInline env id -- and they are now constructed as Compulsory unfoldings (in MkId) -- so they'll happen anyway. - SimplPhase n _ -> isActive n prag + SimplPhase n _ -> isActive n act where - prag = idInlinePragma id + act = idInlineActivation id activeRule :: DynFlags -> SimplEnv -> Maybe (Activation -> Bool) -- Nothing => No rules at all activeRule dflags env - | not (dopt Opt_RewriteRules dflags) + | not (dopt Opt_EnableRewriteRules dflags) = Nothing -- Rewriting is off | otherwise = case getMode env of @@ -819,6 +755,23 @@ activeRule dflags env SimplPhase n _ -> Just (isActive n) \end{code} +Note [InlineRule and postInlineUnconditionally] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Do not do postInlineUnconditionally if the Id has an InlineRule, otherwise +we lose the unfolding. Example + + -- f has InlineRule with rhs (e |> co) + -- where 'e' is big + f = e |> co + +Then there's a danger we'll optimise to + + f' = e + f = f' |> co + +and now postInlineUnconditionally, losing the InlineRule on f. Now f' +won't inline because 'e' is too big. + %************************************************************************ %* * @@ -827,14 +780,14 @@ activeRule dflags env %************************************************************************ \begin{code} -mkLam :: [OutBndr] -> OutExpr -> SimplM OutExpr +mkLam :: SimplEnv -> [OutBndr] -> OutExpr -> SimplM OutExpr -- mkLam tries three things -- a) eta reduction, if that gives a trivial expression -- b) eta expansion [only if there are some value lambdas] -mkLam [] body +mkLam _b [] body = return body -mkLam bndrs body +mkLam env bndrs body = do { dflags <- getDOptsSmpl ; mkLam' dflags bndrs body } where @@ -855,8 +808,10 @@ mkLam bndrs body ; return etad_lam } | dopt Opt_DoLambdaEtaExpansion dflags, - any isRuntimeVar bndrs - = do { body' <- tryEtaExpansion dflags body + not (inGentleMode env), -- In gentle mode don't eta-expansion + any isRuntimeVar bndrs -- because it can clutter up the code + -- with casts etc that may not be removed + = do { let body' = tryEtaExpansion dflags body ; return (mkLams bndrs body') } | otherwise @@ -943,10 +898,16 @@ There are some particularly delicate points here: So it's important to to the right thing. -* We need to be careful if we just look at f's arity. Currently (Dec07), - f's arity is visible in its own RHS (see Note [Arity robustness] in - SimplEnv) so we must *not* trust the arity when checking that 'f' is - a value. Instead, look at the unfolding. +* Note [Arity care]: we need to be careful if we just look at f's + arity. Currently (Dec07), f's arity is visible in its own RHS (see + Note [Arity robustness] in SimplEnv) so we must *not* trust the + arity when checking that 'f' is a value. Otherwise we will + eta-reduce + f = \x. f x + to + f = f + Which might change a terminiating program (think (f `seq` e)) to a + non-terminating one. So we check for being a loop breaker first. However for GlobalIds we can look at the arity; and for primops we must, since they have no unfolding. @@ -959,6 +920,11 @@ There are some particularly delicate points here: with both type and dictionary lambdas; hence the slightly ad-hoc isDictId +* Never *reduce* arity. For example + f = \xy. g x y + Then if h has arity 1 we don't want to eta-reduce because then + f's arity would decrease, and that is bad + These delicacies are why we don't use exprIsTrivial and exprIsHNF here. Alas. @@ -967,6 +933,8 @@ tryEtaReduce :: [OutBndr] -> OutExpr -> Maybe OutExpr tryEtaReduce bndrs body = go (reverse bndrs) body where + incoming_arity = count isId bndrs + go (b : bs) (App fun arg) | ok_arg b arg = go bs fun -- Loop round go [] fun | ok_fun fun = Just fun -- Success! go _ _ = Nothing -- Failure! @@ -980,10 +948,11 @@ tryEtaReduce bndrs body && (ok_fun_id fun_id || all ok_lam bndrs) ok_fun _fun = False - ok_fun_id fun - | isLocalId fun = isEvaldUnfolding (idUnfolding fun) - | isDataConWorkId fun = True - | isGlobalId fun = idArity fun > 0 + ok_fun_id fun = fun_arity fun >= incoming_arity + + fun_arity fun -- See Note [Arity care] + | isLocalId fun && isLoopBreaker (idOccInfo fun) = 0 + | otherwise = idArity fun ok_lam v = isTyVar v || isDictId v @@ -1027,11 +996,10 @@ when computing arity; and etaExpand adds the coerces as necessary when actually computing the expansion. \begin{code} -tryEtaExpansion :: DynFlags -> OutExpr -> SimplM OutExpr +tryEtaExpansion :: DynFlags -> OutExpr -> OutExpr -- There is at least one runtime binder in the binders -tryEtaExpansion dflags body = do - us <- getUniquesM - return (etaExpand fun_arity us body (exprType body)) +tryEtaExpansion dflags body + = etaExpand fun_arity body where fun_arity = exprEtaExpandArity dflags body \end{code} @@ -1184,7 +1152,7 @@ abstractFloats main_tvs body_env body = 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 = transferPolyIdInfo var $ -- Note [transferPolyIdInfo] in Id.lhs + poly_id = transferPolyIdInfo var tvs_here $ -- Note [transferPolyIdInfo] in Id.lhs mkLocalId poly_name poly_ty ; return (poly_id, mkTyApps (Var poly_id) (mkTyVarTys tvs_here)) } -- In the olden days, it was crucial to copy the occInfo of the original var, @@ -1327,12 +1295,12 @@ prepareAlts env scrut case_bndr' alts imposs_cons = case scrut of Var v -> otherCons (idUnfolding v) - other -> [] + _ -> [] impossible_alt :: CoreAlt -> Bool impossible_alt (con, _, _) | con `elem` imposs_cons = True impossible_alt (DataAlt con, _, _) = dataConCannotMatch inst_tys con - impossible_alt alt = False + impossible_alt _ = False -------------------------------------------------- @@ -1340,7 +1308,7 @@ prepareAlts env scrut case_bndr' alts -------------------------------------------------- combineIdenticalAlts :: OutId -> [InAlt] -> SimplM [InAlt] -combineIdenticalAlts case_bndr alts@((con1,bndrs1,rhs1) : con_alts) +combineIdenticalAlts case_bndr ((_con1,bndrs1,rhs1) : con_alts) | all isDeadBinder bndrs1, -- Remember the default length filtered_alts < length con_alts -- alternative comes first -- Also Note [Dead binders] @@ -1348,9 +1316,9 @@ combineIdenticalAlts case_bndr alts@((con1,bndrs1,rhs1) : con_alts) ; return ((DEFAULT, [], rhs1) : filtered_alts) } where filtered_alts = filter keep con_alts - keep (con,bndrs,rhs) = not (all isDeadBinder bndrs && rhs `cheapEqExpr` rhs1) + keep (_con,bndrs,rhs) = not (all isDeadBinder bndrs && rhs `cheapEqExpr` rhs1) -combineIdenticalAlts case_bndr alts = return alts +combineIdenticalAlts _ alts = return alts ------------------------------------------------------------------------- -- Prepare the default alternative @@ -1368,7 +1336,7 @@ prepareDefault :: DynFlags -- And becuase case-merging can cause many to show up ------- Merge nested cases ---------- -prepareDefault dflags env outer_bndr bndr_ty imposs_cons (Just deflt_rhs) +prepareDefault dflags env outer_bndr _bndr_ty imposs_cons (Just deflt_rhs) | dopt Opt_CaseMerge dflags , Case (Var inner_scrut_var) inner_bndr _ inner_alts <- deflt_rhs , DoneId inner_scrut_var' <- substId env inner_scrut_var @@ -1400,7 +1368,7 @@ prepareDefault dflags env outer_bndr bndr_ty imposs_cons (Just deflt_rhs) --------- Fill in known constructor ----------- -prepareDefault dflags env case_bndr (Just (tycon, inst_tys)) imposs_cons (Just deflt_rhs) +prepareDefault _ _ case_bndr (Just (tycon, inst_tys)) imposs_cons (Just deflt_rhs) | -- This branch handles the case where we are -- scrutinisng an algebraic data type isAlgTyCon tycon -- It's a data type, tuple, or unboxed tuples. @@ -1431,13 +1399,18 @@ prepareDefault dflags env case_bndr (Just (tycon, inst_tys)) imposs_cons (Just d dataConRepInstPat us con inst_tys ; return [(DataAlt con, ex_tvs ++ co_tvs ++ arg_ids, deflt_rhs)] } - two_or_more -> return [(DEFAULT, [], deflt_rhs)] + _ -> return [(DEFAULT, [], deflt_rhs)] + + | debugIsOn, isAlgTyCon tycon, not (isOpenTyCon tycon), null (tyConDataCons tycon) + -- This can legitimately happen for type families, so don't report that + = pprTrace "prepareDefault" (ppr case_bndr <+> ppr tycon) + $ return [(DEFAULT, [], deflt_rhs)] --------- Catch-all cases ----------- -prepareDefault dflags env case_bndr bndr_ty imposs_cons (Just deflt_rhs) +prepareDefault _dflags _env _case_bndr _bndr_ty _imposs_cons (Just deflt_rhs) = return [(DEFAULT, [], deflt_rhs)] -prepareDefault dflags env case_bndr bndr_ty imposs_cons Nothing +prepareDefault _dflags _env _case_bndr _bndr_ty _imposs_cons Nothing = return [] -- No default branch \end{code} @@ -1477,7 +1450,7 @@ mkCase scrut case_bndr alts -- Identity case check_eq (LitAlt lit') _ (Lit lit) = lit == lit' check_eq (DataAlt con) args rhs = rhs `cheapEqExpr` mkConApp con (arg_tys ++ varsToCoreExprs args) || rhs `cheapEqExpr` Var case_bndr - check_eq con args rhs = False + check_eq _ _ _ = False arg_tys = map Type (tyConAppArgs (idType case_bndr)) @@ -1495,7 +1468,7 @@ mkCase scrut case_bndr alts -- Identity case re_cast scrut = case head alts of (_,_,Cast _ co) -> Cast scrut co - other -> scrut + _ -> scrut @@ -1511,7 +1484,8 @@ its dead, because it often is, and occasionally these mkCase transformations cascade rather nicely. \begin{code} +bindCaseBndr :: Id -> CoreExpr -> CoreExpr -> CoreExpr bindCaseBndr bndr rhs body | isDeadBinder bndr = body - | otherwise = bindNonRec bndr rhs body + | otherwise = bindNonRec bndr rhs body \end{code}