X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FsimplCore%2FSimplUtils.lhs;h=827f5f4730a40ca551fb230fc59880786a9ee93d;hb=e195ea859d2d4227c478a3b5e1e9ac20b086b0c7;hp=83384cfcfea136476f38e5adc911b76d4775c1cb;hpb=abbc5a0be1df84a33015470319062ed7a3aa3153;p=ghc-hetmet.git diff --git a/ghc/compiler/simplCore/SimplUtils.lhs b/ghc/compiler/simplCore/SimplUtils.lhs index 83384cf..827f5f47 100644 --- a/ghc/compiler/simplCore/SimplUtils.lhs +++ b/ghc/compiler/simplCore/SimplUtils.lhs @@ -5,22 +5,26 @@ \begin{code} module SimplUtils ( - simplBinder, simplBinders, simplRecBndrs, - simplLetBndr, simplLamBndrs, - newId, mkLam, prepareAlts, mkCase, + mkLam, prepareAlts, mkCase, + + -- Inlining, + preInlineUnconditionally, postInlineUnconditionally, activeInline, activeRule, + inlineMode, -- The continuation type SimplCont(..), DupFlag(..), LetRhsFlag(..), contIsDupable, contResultType, countValArgs, countArgs, pushContArgs, - mkBoringStop, mkStop, contIsRhs, contIsRhsOrArg, + mkBoringStop, mkRhsStop, contIsRhs, contIsRhsOrArg, getContArgs, interestingCallContext, interestingArg, isStrictType ) where #include "HsVersions.h" -import CmdLineOpts ( SimplifierSwitch(..), opt_UF_UpdateInPlace, +import SimplEnv +import CmdLineOpts ( SimplifierSwitch(..), SimplifierMode(..), opt_UF_UpdateInPlace, + opt_SimplNoPreInlining, opt_RulesOff, DynFlag(..), dopt ) import CoreSyn import CoreFVs ( exprFreeVars ) @@ -28,23 +32,24 @@ import CoreUtils ( cheapEqExpr, exprType, exprIsTrivial, etaExpand, exprEtaExpandArity, bindNonRec, mkCoerce2, findDefault, exprOkForSpeculation, exprIsValue ) -import qualified Subst ( simplBndrs, simplBndr, simplLetId, simplLamBndr ) -import Id ( Id, idType, idInfo, isDataConWorkId, - mkSysLocal, isDeadBinder, idNewDemandInfo, - idUnfolding, idNewStrictness +import Id ( idType, isDataConWorkId, idOccInfo, + mkSysLocal, isDeadBinder, idNewDemandInfo, isExportedId, + idUnfolding, idNewStrictness, idInlinePragma, ) import NewDemand ( isStrictDmd, isBotRes, splitStrictSig ) import SimplMonad -import Type ( Type, seqType, splitFunTys, dropForAlls, isStrictType, +import Type ( Type, splitFunTys, dropForAlls, isStrictType, splitTyConApp_maybe, tyConAppArgs, mkTyVarTys ) import TcType ( isDictTy ) -import OccName ( EncodedFS ) +import Name ( mkSysTvName ) import TyCon ( tyConDataCons_maybe, isAlgTyCon, isNewTyCon ) -import DataCon ( dataConRepArity, dataConExistentialTyVars, dataConArgTys ) -import Var ( mkSysTyVar, tyVarKind ) +import DataCon ( dataConRepArity, dataConTyVars, dataConArgTys, isVanillaDataCon ) +import Var ( tyVarKind, mkTyVar ) import VarSet -import Util ( lengthExceeds, mapAccumL ) +import BasicTypes ( TopLevelFlag(..), isTopLevel, OccInfo(..), isLoopBreaker, isOneOcc, + Activation, isAlwaysActive, isActive ) +import Util ( lengthExceeds ) import Outputable \end{code} @@ -114,11 +119,9 @@ instance Outputable DupFlag where ------------------- -mkBoringStop :: OutType -> SimplCont +mkBoringStop, mkRhsStop :: OutType -> SimplCont mkBoringStop ty = Stop ty AnArg (canUpdateInPlace ty) - -mkStop :: OutType -> LetRhsFlag -> SimplCont -mkStop ty is_rhs = Stop ty is_rhs (canUpdateInPlace ty) +mkRhsStop ty = Stop ty AnRhs (canUpdateInPlace ty) contIsRhs :: SimplCont -> Bool contIsRhs (Stop _ AnRhs _) = True @@ -135,8 +138,8 @@ contIsDupable (Stop _ _ _) = True contIsDupable (ApplyTo OkToDup _ _ _) = True contIsDupable (Select OkToDup _ _ _ _) = True contIsDupable (CoerceIt _ cont) = contIsDupable cont -contIsDupable (InlinePlease cont) = contIsDupable cont -contIsDupable other = False +contIsDupable (InlinePlease cont) = contIsDupable cont +contIsDupable other = False ------------------- discardableCont :: SimplCont -> Bool @@ -371,9 +374,9 @@ interestingCallContext :: Bool -- False <=> no args at all interestingCallContext some_args some_val_args cont = interesting cont where - interesting (InlinePlease _) = True - interesting (Select _ _ _ _ _) = some_args - interesting (ApplyTo _ _ _ _) = True -- Can happen if we have (coerce t (f x)) y + interesting (InlinePlease _) = True + interesting (Select _ _ _ _ _) = some_args + interesting (ApplyTo _ _ _ _) = True -- 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 motivaiton for inlining it @@ -422,66 +425,272 @@ canUpdateInPlace ty %************************************************************************ %* * -\section{Dealing with a single binder} +\subsection{Decisions about inlining} %* * %************************************************************************ -These functions are in the monad only so that they can be made strict via seq. +Inlining is controlled partly by the SimplifierMode switch. This has two +settings: + + SimplGently (a) Simplifying before specialiser/full laziness + (b) Simplifiying inside INLINE pragma + (c) Simplifying the LHS of a rule + (d) Simplifying a GHCi expression or Template + Haskell splice + + SimplPhase n Used at all other times + +The key thing about SimplGently is that it does no call-site inlining. +Before full laziness we must be careful not to inline wrappers, +because doing so inhibits floating + e.g. ...(case f x of ...)... + ==> ...(case (case x of I# x# -> fw x#) of ...)... + ==> ...(case x of I# x# -> case fw x# of ...)... +and now the redex (f x) isn't floatable any more. + +The no-inling thing is also important for Template Haskell. You might be +compiling in one-shot mode with -O2; but when TH compiles a splice before +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} -simplBinders :: SimplEnv -> [InBinder] -> SimplM (SimplEnv, [OutBinder]) -simplBinders env bndrs - = let - (subst', bndrs') = Subst.simplBndrs (getSubst env) bndrs - in - seqBndrs bndrs' `seq` - returnSmpl (setSubst env subst', bndrs') +inlineMode :: SimplifierMode +inlineMode = SimplGently +\end{code} -simplBinder :: SimplEnv -> InBinder -> SimplM (SimplEnv, OutBinder) -simplBinder env bndr - = let - (subst', bndr') = Subst.simplBndr (getSubst env) bndr - in - seqBndr bndr' `seq` - returnSmpl (setSubst env subst', bndr') +It really is important to switch off inlinings inside such +expressions. Consider the following example + + let f = \pq -> BIG + in + let g = \y -> f y y + {-# INLINE g #-} + 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. + + +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... + +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 +of g when f is inlined at some call site (perhaps in some other +module). + +It's also important not to inline a worker back into a wrapper. +A wrapper looks like + wraper = inline_me (\x -> ...worker... ) +Normally, the inline_me prevents the worker getting inlined into +the wrapper (initially, the worker's only call site!). But, +if the wrapper is sure to be called, the strictness analyser will +mark it 'demanded', so when the RHS is simplified, it'll get an ArgOf +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. + + 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! + + +preInlineUnconditionally +~~~~~~~~~~~~~~~~~~~~~~~~ +@preInlineUnconditionally@ examines a bndr to see if it is used just +once in a completely safe way, so that it is safe to discard the +binding inline its RHS at the (unique) usage site, REGARDLESS of how +big the RHS might be. If this is the case we don't simplify the RHS +first, but just inline it un-simplified. + +This is much better than first simplifying a perhaps-huge RHS and then +inlining and re-simplifying it. Indeed, it can be at least quadratically +better. Consider + + x1 = e1 + x2 = e2[x1] + x3 = e3[x2] + ...etc... + xN = eN[xN-1] +We may end up simplifying e1 N times, e2 N-1 times, e3 N-3 times etc. -simplLetBndr :: SimplEnv -> InBinder -> SimplM (SimplEnv, OutBinder) -simplLetBndr env id - = let - (subst', id') = Subst.simplLetId (getSubst env) id - in - seqBndr id' `seq` - returnSmpl (setSubst env subst', id') +NB: we don't even look at the RHS to see if it's trivial +We might have + x = y +where x is used many times, but this is the unique occurrence of y. +We should NOT inline x at all its uses, because then we'd do the same +for y -- aargh! So we must base this pre-rhs-simplification decision +solely on x's occurrences, not on its rhs. -simplLamBndrs, simplRecBndrs - :: SimplEnv -> [InBinder] -> SimplM (SimplEnv, [OutBinder]) -simplRecBndrs = simplBndrs Subst.simplLetId -simplLamBndrs = simplBndrs Subst.simplLamBndr +Evne RHSs labelled InlineMe aren't caught here, because there might be +no benefit from inlining at the call site. -simplBndrs simpl_bndr env bndrs - = let - (subst', bndrs') = mapAccumL simpl_bndr (getSubst env) bndrs - in - seqBndrs bndrs' `seq` - returnSmpl (setSubst env subst', bndrs') +[Sept 01] Don't unconditionally inline a top-level thing, because that +can simply make a static thing into something built dynamically. E.g. + x = (a,b) + main = \s -> h x -seqBndrs [] = () -seqBndrs (b:bs) = seqBndr b `seq` seqBndrs bs +[Remember that we treat \s as a one-shot lambda.] No point in +inlining x unless there is something interesting about the call site. -seqBndr b | isTyVar b = b `seq` () - | otherwise = seqType (idType b) `seq` - idInfo b `seq` - () -\end{code} +But watch out: if you aren't careful, some useful foldr/build fusion +can be lost (most notably in spectral/hartel/parstof) because the +foldr didn't see the build. Doing the dynamic allocation isn't a big +deal, in fact, but losing the fusion can be. But the right thing here +seems to be to do a callSiteInline based on the fact that there is +something interesting about the call site (it's strict). Hmm. That +seems a bit fragile. +Conclusion: inline top level things gaily until Phase 0 (the last +phase), at which point don't. \begin{code} -newId :: EncodedFS -> Type -> SimplM Id -newId fs ty = getUniqueSmpl `thenSmpl` \ uniq -> - returnSmpl (mkSysLocal fs uniq ty) +preInlineUnconditionally :: SimplEnv -> TopLevelFlag -> InId -> Bool +preInlineUnconditionally env top_lvl bndr + | isTopLevel top_lvl, SimplPhase 0 <- phase = False +-- If we don't have this test, consider +-- x = length [1,2,3] +-- The full laziness pass carefully floats all the cons cells to +-- top level, and preInlineUnconditionally floats them all back in. +-- Result is (a) static allocation replaced by dynamic allocation +-- (b) many simplifier iterations because this tickles +-- a related problem; only one inlining per pass +-- +-- On the other hand, I have seen cases where top-level fusion is +-- lost if we don't inline top level thing (e.g. string constants) +-- Hence the test for phase zero (which is the phase for all the final +-- simplifications). Until phase zero we take no special notice of +-- top level things, but then we become more leery about inlining +-- them. + + | not active = False + | opt_SimplNoPreInlining = False + | otherwise = case idOccInfo bndr of + IAmDead -> True -- Happens in ((\x.1) v) + OneOcc in_lam once -> not in_lam && once + -- Not inside a lambda, one occurrence ==> safe! + other -> False + where + phase = getMode env + active = case phase of + SimplGently -> isAlwaysActive prag + SimplPhase n -> isActive n prag + prag = idInlinePragma bndr \end{code} +postInlineUnconditionally +~~~~~~~~~~~~~~~~~~~~~~~~~ +@postInlineUnconditionally@ decides whether to unconditionally inline +a thing based on the form of its RHS; in particular if it has a +trivial RHS. If so, we can inline and discard the binding altogether. + +NB: a loop breaker has must_keep_binding = True and non-loop-breakers +only have *forward* references Hence, it's safe to discard the binding + +NOTE: This isn't our last opportunity to inline. We're at the binding +site right now, and we'll get another opportunity when we get to the +ocurrence(s) + +Note that we do this unconditional inlining only for trival RHSs. +Don't inline even WHNFs inside lambdas; doing so may simply increase +allocation when the function is called. This isn't the last chance; see +NOTE above. + +NB: Even inline pragmas (e.g. IMustBeINLINEd) are ignored here Why? +Because we don't even want to inline them into the RHS of constructor +arguments. See NOTE above + +NB: At one time even NOINLINE was ignored here: if the rhs is trivial +it's best to inline it anyway. We often get a=E; b=a from desugaring, +with both a and b marked NOINLINE. But that seems incompatible with +our new view that inlining is like a RULE, so I'm sticking to the 'active' +story for now. + +\begin{code} +postInlineUnconditionally :: SimplEnv -> OutId -> OccInfo -> OutExpr -> Bool +postInlineUnconditionally env bndr occ_info rhs + = exprIsTrivial rhs + && active + && not (isLoopBreaker occ_info) + && not (isExportedId bndr) + -- We used to have (isOneOcc occ_info) instead of + -- not (isLoopBreaker occ_info) && not (isExportedId bndr) + -- That was because a rather fragile use of rules got confused + -- if you inlined even a binding f=g e.g. We used to have + -- map = mapList + -- But now a more precise use of phases has eliminated this problem, + -- so the is_active test will do the job. I think. + -- + -- OLD COMMENT: (delete soon) + -- Indeed, you might suppose that + -- there is nothing wrong with substituting for a trivial RHS, even + -- if it occurs many times. But consider + -- x = y + -- h = _inline_me_ (...x...) + -- Here we do *not* want to have x inlined, even though the RHS is + -- trivial, becuase the contract for an INLINE pragma is "no inlining". + -- This is important in the rules for the Prelude + where + active = case getMode env of + SimplGently -> isAlwaysActive prag + SimplPhase n -> isActive n prag + prag = idInlinePragma bndr + +activeInline :: SimplEnv -> OutId -> OccInfo -> Bool +activeInline env id occ + = case getMode env of + SimplGently -> isOneOcc occ && isAlwaysActive prag + -- No inlining at all when doing gentle stuff, + -- except for local things that occur once + -- The reason is that too little clean-up happens if you + -- don't inline use-once things. Also a bit of inlining is *good* for + -- full laziness; it can expose constant sub-expressions. + -- Example in spectral/mandel/Mandel.hs, where the mandelset + -- function gets a useful let-float if you inline windowToViewport + + -- NB: we used to have a second exception, for data con wrappers. + -- On the grounds that we use gentle mode for rule LHSs, and + -- they match better when data con wrappers are inlined. + -- But that only really applies to the trivial wrappers (like (:)), + -- and they are now constructed as Compulsory unfoldings (in MkId) + -- so they'll happen anyway. + + SimplPhase n -> isActive n prag + where + prag = idInlinePragma id + +activeRule :: SimplEnv -> Maybe (Activation -> Bool) +-- Nothing => No rules at all +activeRule env + | opt_RulesOff = Nothing + | otherwise + = case getMode env of + SimplGently -> Just isAlwaysActive + -- Used to be Nothing (no rules in gentle mode) + -- Main motivation for changing is that I wanted + -- lift String ===> ... + -- to work in Template Haskell when simplifying + -- splices, so we get simpler code for literal strings + SimplPhase n -> Just (isActive n) +\end{code} + %************************************************************************ %* * @@ -835,8 +1044,8 @@ of the inner case y, which give us nowhere to go! \begin{code} prepareAlts :: OutExpr -- Scrutinee -> InId -- Case binder - -> [InAlt] - -> SimplM ([InAlt], -- Better alternatives + -> [InAlt] -- Increasing order + -> SimplM ([InAlt], -- Better alternatives, still incresaing order [AltCon]) -- These cases are handled prepareAlts scrut case_bndr alts @@ -862,7 +1071,9 @@ prepareAlts scrut case_bndr alts -- is only one constructor left prepareDefault case_bndr handled_cons maybe_deflt `thenSmpl` \ deflt_alt -> - returnSmpl (deflt_alt ++ better_alts, handled_cons) + returnSmpl (mergeAlts better_alts deflt_alt, handled_cons) + -- We need the mergeAlts in case the new default_alt + -- has turned into a constructor alternative. prepareDefault case_bndr handled_cons (Just rhs) | Just (tycon, inst_tys) <- splitTyConApp_maybe (idType case_bndr), @@ -902,16 +1113,22 @@ prepareDefault case_bndr handled_cons Nothing = returnSmpl [] mk_args missing_con inst_tys - = getUniquesSmpl `thenSmpl` \ tv_uniqs -> - getUniquesSmpl `thenSmpl` \ id_uniqs -> - let - ex_tyvars = dataConExistentialTyVars missing_con - ex_tyvars' = zipWith mk tv_uniqs ex_tyvars - mk uniq tv = mkSysTyVar uniq (tyVarKind tv) - arg_tys = dataConArgTys missing_con (inst_tys ++ mkTyVarTys ex_tyvars') - arg_ids = zipWith (mkSysLocal FSLIT("a")) id_uniqs arg_tys - in - returnSmpl (ex_tyvars' ++ arg_ids) + = mk_tv_bndrs missing_con inst_tys `thenSmpl` \ (tv_bndrs, inst_tys') -> + getUniquesSmpl `thenSmpl` \ id_uniqs -> + let arg_tys = dataConArgTys missing_con inst_tys' + arg_ids = zipWith (mkSysLocal FSLIT("a")) id_uniqs arg_tys + in + returnSmpl (tv_bndrs ++ arg_ids) + +mk_tv_bndrs missing_con inst_tys + | isVanillaDataCon missing_con + = returnSmpl ([], inst_tys) + | otherwise + = getUniquesSmpl `thenSmpl` \ tv_uniqs -> + let new_tvs = zipWith mk tv_uniqs (dataConTyVars missing_con) + mk uniq tv = mkTyVar (mkSysTvName uniq FSLIT("t")) (tyVarKind tv) + in + returnSmpl (new_tvs, mkTyVarTys new_tvs) \end{code} @@ -924,11 +1141,14 @@ mk_args missing_con inst_tys mkCase puts a case expression back together, trying various transformations first. \begin{code} -mkCase :: OutExpr -> OutId -> [OutAlt] -> SimplM OutExpr - -mkCase scrut case_bndr alts - = mkAlts scrut case_bndr alts `thenSmpl` \ better_alts -> - mkCase1 scrut case_bndr better_alts +mkCase :: OutExpr -> OutId -> OutType + -> [OutAlt] -- Increasing order + -> SimplM OutExpr + +mkCase scrut case_bndr ty alts + = getDOptsSmpl `thenSmpl` \dflags -> + mkAlts dflags scrut case_bndr alts `thenSmpl` \ better_alts -> + mkCase1 scrut case_bndr ty better_alts \end{code} @@ -993,7 +1213,7 @@ and similarly in cascade for all the join points! -------------------------------------------------- -- 1. Merge identical branches -------------------------------------------------- -mkAlts scrut case_bndr alts@((con1,bndrs1,rhs1) : con_alts) +mkAlts dflags scrut case_bndr alts@((con1,bndrs1,rhs1) : con_alts) | all isDeadBinder bndrs1, -- Remember the default length filtered_alts < length con_alts -- alternative comes first = tick (AltMerge case_bndr) `thenSmpl_` @@ -1008,55 +1228,53 @@ mkAlts scrut case_bndr alts@((con1,bndrs1,rhs1) : con_alts) -- 2. Merge nested cases -------------------------------------------------- -mkAlts scrut outer_bndr outer_alts - = getDOptsSmpl `thenSmpl` \dflags -> - mkAlts' dflags scrut outer_bndr outer_alts - where - mkAlts' dflags scrut outer_bndr outer_alts - | dopt Opt_CaseMerge dflags, - (outer_alts_without_deflt, maybe_outer_deflt) <- findDefault outer_alts, - Just (Case (Var scrut_var) inner_bndr inner_alts) <- maybe_outer_deflt, - scruting_same_var scrut_var - - = let -- Eliminate any inner alts which are shadowed by the outer ones - outer_cons = [con | (con,_,_) <- outer_alts_without_deflt] - - munged_inner_alts = [ (con, args, munge_rhs rhs) - | (con, args, rhs) <- inner_alts, - not (con `elem` outer_cons) -- Eliminate shadowed inner alts - ] - munge_rhs rhs = bindCaseBndr inner_bndr (Var outer_bndr) rhs - - (inner_con_alts, maybe_inner_default) = findDefault munged_inner_alts - - new_alts = add_default maybe_inner_default - (outer_alts_without_deflt ++ inner_con_alts) +mkAlts dflags scrut outer_bndr outer_alts + | dopt Opt_CaseMerge dflags, + (outer_alts_without_deflt, maybe_outer_deflt) <- findDefault outer_alts, + Just (Case (Var scrut_var) inner_bndr _ inner_alts) <- maybe_outer_deflt, + scruting_same_var scrut_var + = let + munged_inner_alts = [(con, args, munge_rhs rhs) | (con, args, rhs) <- inner_alts] + munge_rhs rhs = bindCaseBndr inner_bndr (Var outer_bndr) rhs + + new_alts = mergeAlts outer_alts_without_deflt munged_inner_alts + -- The merge keeps the inner DEFAULT at the front, if there is one + -- and eliminates any inner_alts that are shadowed by the outer_alts in tick (CaseMerge outer_bndr) `thenSmpl_` returnSmpl new_alts - -- Warning: don't call mkAlts recursively! - -- Firstly, there's no point, because inner alts have already had - -- mkCase applied to them, so they won't have a case in their default - -- Secondly, if you do, you get an infinite loop, because the bindCaseBndr - -- in munge_rhs may put a case into the DEFAULT branch! - where - -- We are scrutinising the same variable if it's - -- the outer case-binder, or if the outer case scrutinises a variable - -- (and it's the same). Testing both allows us not to replace the - -- outer scrut-var with the outer case-binder (Simplify.simplCaseBinder). - scruting_same_var = case scrut of + -- Warning: don't call mkAlts recursively! + -- Firstly, there's no point, because inner alts have already had + -- mkCase applied to them, so they won't have a case in their default + -- Secondly, if you do, you get an infinite loop, because the bindCaseBndr + -- in munge_rhs may put a case into the DEFAULT branch! + where + -- We are scrutinising the same variable if it's + -- the outer case-binder, or if the outer case scrutinises a variable + -- (and it's the same). Testing both allows us not to replace the + -- outer scrut-var with the outer case-binder (Simplify.simplCaseBinder). + scruting_same_var = case scrut of Var outer_scrut -> \ v -> v == outer_bndr || v == outer_scrut other -> \ v -> v == outer_bndr - add_default (Just rhs) alts = (DEFAULT,[],rhs) : alts - add_default Nothing alts = alts - - --------------------------------------------------- +------------------------------------------------ -- Catch-all --------------------------------------------------- - - mkAlts' dflags scrut case_bndr other_alts = returnSmpl other_alts +------------------------------------------------ + +mkAlts dflags scrut case_bndr other_alts = returnSmpl other_alts + + +--------------------------------- +mergeAlts :: [OutAlt] -> [OutAlt] -> [OutAlt] +-- Merge preserving order; alternatives in the first arg +-- shadow ones in the second +mergeAlts [] as2 = as2 +mergeAlts as1 [] = as1 +mergeAlts (a1:as1) (a2:as2) + = case a1 `cmpAlt` a2 of + LT -> a1 : mergeAlts as1 (a2:as2) + EQ -> a1 : mergeAlts as1 as2 -- Discard a2 + GT -> a2 : mergeAlts (a1:as1) as2 \end{code} @@ -1198,7 +1416,7 @@ I don't really know how to improve this situation. -------------------------------------------------- #ifdef DEBUG -mkCase1 scrut case_bndr [] +mkCase1 scrut case_bndr ty [] = pprTrace "mkCase1: null alts" (ppr case_bndr <+> ppr scrut) $ returnSmpl scrut #endif @@ -1207,7 +1425,7 @@ mkCase1 scrut case_bndr [] -- 1. Eliminate the case altogether if poss -------------------------------------------------- -mkCase1 scrut case_bndr [(con,bndrs,rhs)] +mkCase1 scrut case_bndr ty [(con,bndrs,rhs)] -- See if we can get rid of the case altogether -- See the extensive notes on case-elimination above -- mkCase made sure that if all the alternatives are equal, @@ -1249,7 +1467,7 @@ mkCase1 scrut case_bndr [(con,bndrs,rhs)] -- 2. Identity case -------------------------------------------------- -mkCase1 scrut case_bndr alts -- Identity case +mkCase1 scrut case_bndr ty alts -- Identity case | all identity_alt alts = tick (CaseIdentity case_bndr) `thenSmpl_` returnSmpl (re_note scrut) @@ -1279,7 +1497,7 @@ mkCase1 scrut case_bndr alts -- Identity case -------------------------------------------------- -- Catch-all -------------------------------------------------- -mkCase1 scrut bndr alts = returnSmpl (Case scrut bndr alts) +mkCase1 scrut bndr ty alts = returnSmpl (Case scrut bndr ty alts) \end{code}