Simon Peyton Jones pushed to branch wip/26543 at Glasgow Haskell Compiler / GHC
Commits:
-
fa93d8c6
by Simon Peyton Jones at 2025-12-04T17:47:15+00:00
4 changed files:
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/TyCo/Rep.hs
Changes:
| ... | ... | @@ -11,7 +11,7 @@ module GHC.Core.Opt.Simplify.Env ( |
| 11 | 11 | SimplMode(..), updMode, smPlatform,
|
| 12 | 12 | |
| 13 | 13 | -- * Environments
|
| 14 | - SimplEnv(..), pprSimplEnv, -- Temp not abstract
|
|
| 14 | + SimplEnv(..), StaticEnv, pprSimplEnv, -- Temp not abstract
|
|
| 15 | 15 | SimplPhase(..), isActive,
|
| 16 | 16 | seArityOpts, seCaseCase, seCaseFolding, seCaseMerge, seCastSwizzle,
|
| 17 | 17 | seDoEtaReduction, seEtaExpand, seFloatEnable, seInline, seNames,
|
| ... | ... | @@ -28,13 +28,13 @@ module GHC.Core.Opt.Simplify.Env ( |
| 28 | 28 | SimplEnvIS, checkSimplEnvIS, pprBadSimplEnvIS,
|
| 29 | 29 | |
| 30 | 30 | -- * Substitution results
|
| 31 | - SimplSR(..), mkContEx, substId, lookupRecBndr,
|
|
| 31 | + SimplClo(..), mkContEx, substId, lookupRecBndr,
|
|
| 32 | 32 | |
| 33 | 33 | -- * Simplifying 'Id' binders
|
| 34 | 34 | simplNonRecBndr, simplNonRecJoinBndr, simplRecBndrs, simplRecJoinBndrs,
|
| 35 | 35 | simplBinder, simplBinders,
|
| 36 | 36 | substTy, substTyVar, getFullSubst, getTCvSubst,
|
| 37 | - substCo, substCoVar,
|
|
| 37 | + substCo, substCoVar, simplCloExpr, simplCloCoercion_maybe,
|
|
| 38 | 38 | |
| 39 | 39 | -- * Floats
|
| 40 | 40 | SimplFloats(..), emptyFloats, isEmptyFloats, mkRecFloats,
|
| ... | ... | @@ -60,8 +60,9 @@ import GHC.Core.Opt.Arity ( ArityOpts(..) ) |
| 60 | 60 | import GHC.Core.Opt.Simplify.Monad
|
| 61 | 61 | import GHC.Core.Rules.Config ( RuleOpts(..) )
|
| 62 | 62 | import GHC.Core
|
| 63 | +import GHC.Core.Ppr
|
|
| 63 | 64 | import GHC.Core.Utils
|
| 64 | -import GHC.Core.Subst( substExprSC )
|
|
| 65 | +import GHC.Core.Subst( substExpr )
|
|
| 65 | 66 | import GHC.Core.Unfold
|
| 66 | 67 | import GHC.Core.TyCo.Subst (emptyIdSubstEnv, mkSubst)
|
| 67 | 68 | import GHC.Core.Multiplicity( Scaled(..), mkMultMul )
|
| ... | ... | @@ -209,6 +210,8 @@ type SimplEnvIS = SimplEnv |
| 209 | 210 | -- Invariant: the substitution is empty
|
| 210 | 211 | -- We want this SimplEnv for its InScopeSet and flags
|
| 211 | 212 | |
| 213 | +type StaticEnv = SimplEnv -- Just the static part is relevant
|
|
| 214 | + |
|
| 212 | 215 | checkSimplEnvIS :: SimplEnvIS -> Bool
|
| 213 | 216 | -- Check the invariant for SimplEnvIS
|
| 214 | 217 | checkSimplEnvIS (SimplEnv { seIdSubst = id_env, seTvSubst = tv_env, seCvSubst = cv_env })
|
| ... | ... | @@ -459,41 +462,46 @@ pprSimplEnv env |
| 459 | 462 | ppr_one v | isId v = ppr v <+> ppr (idUnfolding v)
|
| 460 | 463 | | otherwise = ppr v
|
| 461 | 464 | |
| 462 | -type SimplIdSubst = IdEnv SimplSR -- IdId |--> OutExpr
|
|
| 465 | +type SimplIdSubst = IdEnv SimplClo -- IdId |--> OutExpr
|
|
| 463 | 466 | -- See Note [Extending the IdSubstEnv] in GHC.Core.Subst
|
| 464 | 467 | |
| 465 | --- | A substitution result.
|
|
| 466 | -data SimplSR
|
|
| 468 | +-- | A "closure" used in the Simplifier
|
|
| 469 | +-- Roughly: either an (InExpr, StaticEnv) pair for an
|
|
| 470 | +-- as-yet-unsimplified expression
|
|
| 471 | +-- or an OutExpr, for an already-simplified one
|
|
| 472 | + |
|
| 473 | +data SimplClo
|
|
| 467 | 474 | = DoneEx OutExpr JoinPointHood
|
| 468 | 475 | -- If x :-> DoneEx e ja is in the SimplIdSubst
|
| 469 | 476 | -- then replace occurrences of x by e
|
| 470 | 477 | -- and ja = Just a <=> x is a join-point of arity a
|
| 471 | 478 | -- See Note [Join arity in SimplIdSubst]
|
| 472 | 479 | |
| 473 | - |
|
| 474 | 480 | | DoneId OutId
|
| 475 | 481 | -- If x :-> DoneId v is in the SimplIdSubst
|
| 476 | 482 | -- then replace occurrences of x by v
|
| 477 | 483 | -- and v is a join-point of arity a
|
| 478 | 484 | -- <=> x is a join-point of arity a
|
| 479 | 485 | |
| 480 | - | ContEx TvSubstEnv -- A suspended substitution
|
|
| 481 | - CvSubstEnv
|
|
| 482 | - SimplIdSubst
|
|
| 486 | + | ContEx StaticEnv
|
|
| 483 | 487 | InExpr
|
| 484 | - -- If x :-> ContEx tv cv id e is in the SimplISubst
|
|
| 485 | - -- then replace occurrences of x by (subst (tv,cv,id) e)
|
|
| 488 | + MOutCoercion -- An /optimised/ OutCoercion
|
|
| 489 | + -- If x :-> ContEx subst e co is in the SimplISubst
|
|
| 490 | + -- then replace occurrences of x by ((substExpr subst e) |> co)
|
|
| 486 | 491 | |
| 487 | -instance Outputable SimplSR where
|
|
| 492 | +instance Outputable SimplClo where
|
|
| 488 | 493 | ppr (DoneId v) = text "DoneId" <+> ppr v
|
| 489 | - ppr (DoneEx e mj) = text "DoneEx" <> pp_mj <+> ppr e
|
|
| 494 | + ppr (DoneEx e mj) = text "DoneEx" <> pp_mj<> braces (ppr e)
|
|
| 490 | 495 | where
|
| 491 | 496 | pp_mj = case mj of
|
| 492 | 497 | NotJoinPoint -> empty
|
| 493 | 498 | JoinPoint n -> parens (int n)
|
| 494 | 499 | |
| 495 | - ppr (ContEx _tv _cv _id e) = vcat [text "ContEx" <+> ppr e {-,
|
|
| 496 | - ppr (filter_env tv), ppr (filter_env id) -}]
|
|
| 500 | + ppr (ContEx _se e mco)
|
|
| 501 | + = text "ContEx" <> vcat [ pprParendExpr e
|
|
| 502 | + , case mco of
|
|
| 503 | + MRefl -> empty
|
|
| 504 | + MCo co -> text "|>" <+> pprOptCo co ]
|
|
| 497 | 505 | -- where
|
| 498 | 506 | -- fvs = exprFreeVars e
|
| 499 | 507 | -- filter_env env = filterVarEnv_Directly keep env
|
| ... | ... | @@ -627,7 +635,7 @@ reSimplifying :: SimplEnv -> Bool |
| 627 | 635 | reSimplifying (SimplEnv { seInlineDepth = n }) = n>0
|
| 628 | 636 | |
| 629 | 637 | ---------------------
|
| 630 | -extendIdSubst :: SimplEnv -> Id -> SimplSR -> SimplEnv
|
|
| 638 | +extendIdSubst :: SimplEnv -> Id -> SimplClo -> SimplEnv
|
|
| 631 | 639 | extendIdSubst env@(SimplEnv {seIdSubst = subst}) var res
|
| 632 | 640 | = assertPpr (isId var && not (isCoVar var)) (ppr var) $
|
| 633 | 641 | env { seIdSubst = extendVarEnv subst var res }
|
| ... | ... | @@ -725,8 +733,8 @@ zapSubstEnv env@(SimplEnv { seInlineDepth = n }) |
| 725 | 733 | setSubstEnv :: SimplEnv -> TvSubstEnv -> CvSubstEnv -> SimplIdSubst -> SimplEnv
|
| 726 | 734 | setSubstEnv env tvs cvs ids = env { seTvSubst = tvs, seCvSubst = cvs, seIdSubst = ids }
|
| 727 | 735 | |
| 728 | -mkContEx :: SimplEnv -> InExpr -> SimplSR
|
|
| 729 | -mkContEx (SimplEnv { seTvSubst = tvs, seCvSubst = cvs, seIdSubst = ids }) e = ContEx tvs cvs ids e
|
|
| 736 | +mkContEx :: SimplEnv -> InExpr -> SimplClo
|
|
| 737 | +mkContEx env e = ContEx env e MRefl
|
|
| 730 | 738 | |
| 731 | 739 | {-
|
| 732 | 740 | ************************************************************************
|
| ... | ... | @@ -1011,7 +1019,7 @@ So we want to look up the inner X.g_34 in the substitution, where we'll |
| 1011 | 1019 | find that it has been substituted by b. (Or conceivably cloned.)
|
| 1012 | 1020 | -}
|
| 1013 | 1021 | |
| 1014 | -substId :: SimplEnv -> InId -> SimplSR
|
|
| 1022 | +substId :: SimplEnv -> InId -> SimplClo
|
|
| 1015 | 1023 | -- Returns DoneEx only on a non-Var expression
|
| 1016 | 1024 | substId (SimplEnv { seInScope = in_scope, seIdSubst = ids }) v
|
| 1017 | 1025 | = case lookupVarEnv ids v of -- Note [Global Ids in the substitution]
|
| ... | ... | @@ -1343,17 +1351,29 @@ getTCvSubst (SimplEnv { seInScope = in_scope, seTvSubst = tv_env, seCvSubst = cv |
| 1343 | 1351 | |
| 1344 | 1352 | getFullSubst :: InScopeSet -> SimplEnv -> Subst
|
| 1345 | 1353 | getFullSubst in_scope (SimplEnv { seIdSubst = id_env, seTvSubst = tv_env, seCvSubst = cv_env })
|
| 1346 | - = mk_full_subst in_scope tv_env cv_env id_env
|
|
| 1347 | - |
|
| 1348 | -mk_full_subst :: InScopeSet -> TvSubstEnv -> CvSubstEnv -> SimplIdSubst -> Subst
|
|
| 1349 | -mk_full_subst in_scope tv_env cv_env id_env
|
|
| 1350 | - = mkSubst in_scope (mapVarEnv to_expr id_env) tv_env cv_env
|
|
| 1351 | - where
|
|
| 1352 | - to_expr :: SimplSR -> CoreExpr
|
|
| 1353 | - -- A tiresome impedence-matcher
|
|
| 1354 | - to_expr (DoneEx e _) = e
|
|
| 1355 | - to_expr (DoneId v) = Var v
|
|
| 1356 | - to_expr (ContEx tvs cvs ids e) = GHC.Core.Subst.substExprSC (mk_full_subst in_scope tvs cvs ids) e
|
|
| 1354 | + = mkSubst in_scope (mapVarEnv (simplCloExpr in_scope) id_env) tv_env cv_env
|
|
| 1355 | + |
|
| 1356 | +simplCloExpr :: InScopeSet -> SimplClo -> OutExpr
|
|
| 1357 | +simplCloExpr _ (DoneEx e _) = e
|
|
| 1358 | +simplCloExpr _ (DoneId v) = Var v
|
|
| 1359 | +simplCloExpr in_scope (ContEx se e mco) = mkCastMCo e' mco
|
|
| 1360 | + where
|
|
| 1361 | + e' = GHC.Core.Subst.substExpr (getFullSubst in_scope se) e
|
|
| 1362 | + -- Make sure we apply the static environment `sc_env` as a substitution
|
|
| 1363 | + -- to get an OutExpr. See (BF1) in Note [tryRules: plan (BEFORE)]
|
|
| 1364 | + -- in GHC.Core.Opt.Simplify.Iteration
|
|
| 1365 | + -- NB: we use substExpr, not substExprSC: we want to get the benefit of
|
|
| 1366 | + -- knowing what is evaluated etc, via the in-scope set
|
|
| 1367 | + |
|
| 1368 | +simplCloCoercion_maybe :: SimplClo -> Maybe OutCoercion
|
|
| 1369 | +-- If the closure is just a coercion, give it to me
|
|
| 1370 | +simplCloCoercion_maybe clo
|
|
| 1371 | + = case clo of
|
|
| 1372 | + DoneEx (Coercion co) _ -> Just co
|
|
| 1373 | + ContEx se (Coercion co) MRefl -> Just (substCo se co)
|
|
| 1374 | + -- Do we ever cast a coercion??
|
|
| 1375 | + DoneId {} -> Nothing -- Coercion variables never occur naked
|
|
| 1376 | + _ -> Nothing
|
|
| 1357 | 1377 | |
| 1358 | 1378 | substTy :: HasDebugCallStack => SimplEnv -> Type -> Type
|
| 1359 | 1379 | substTy env ty = Type.substTy (getTCvSubst env) ty
|
| ... | ... | @@ -278,8 +278,8 @@ simplRecOrTopPair :: SimplEnv |
| 278 | 278 | -> SimplM (SimplFloats, SimplEnv)
|
| 279 | 279 | |
| 280 | 280 | simplRecOrTopPair env bind_cxt old_bndr new_bndr rhs
|
| 281 | - | Just env' <- preInlineUnconditionally env (bindContextLevel bind_cxt)
|
|
| 282 | - old_bndr rhs env
|
|
| 281 | + | Just env' <- preInlineLetUnconditionally env (bindContextLevel bind_cxt)
|
|
| 282 | + old_bndr rhs env
|
|
| 283 | 283 | = {-#SCC "simplRecOrTopPair-pre-inline-uncond" #-}
|
| 284 | 284 | simplTrace "SimplBindr:inline-uncond1" (ppr old_bndr) $
|
| 285 | 285 | do { tick (PreInlineUnconditionally old_bndr)
|
| ... | ... | @@ -1211,7 +1211,7 @@ simplExprF1 env (App fun arg) cont |
| 1211 | 1211 | -- observed the quadratic behavior, so this extra entanglement
|
| 1212 | 1212 | -- seems not worthwhile.
|
| 1213 | 1213 | simplExprF env fun $
|
| 1214 | - ApplyToVal { sc_arg = arg, sc_env = env
|
|
| 1214 | + ApplyToVal { sc_arg = mkContEx env arg
|
|
| 1215 | 1215 | , sc_hole_ty = substTy env (exprType fun)
|
| 1216 | 1216 | , sc_dup = NoDup, sc_cont = cont }
|
| 1217 | 1217 | |
| ... | ... | @@ -1249,7 +1249,7 @@ simplExprF1 env (Let (NonRec bndr rhs) body) cont |
| 1249 | 1249 | do { ty' <- simplType env ty
|
| 1250 | 1250 | ; simplExprF (extendTvSubst env bndr ty') body cont }
|
| 1251 | 1251 | |
| 1252 | - | Just env' <- preInlineUnconditionally env NotTopLevel bndr rhs env
|
|
| 1252 | + | Just env' <- preInlineLetUnconditionally env NotTopLevel bndr rhs env
|
|
| 1253 | 1253 | -- Because of the let-can-float invariant, it's ok to
|
| 1254 | 1254 | -- inline freely, or to drop the binding if it is dead.
|
| 1255 | 1255 | = do { simplTrace "SimplBindr:inline-uncond2" (ppr bndr) $
|
| ... | ... | @@ -1266,7 +1266,7 @@ simplExprF1 env (Let (NonRec bndr rhs) body) cont |
| 1266 | 1266 | |
| 1267 | 1267 | | otherwise
|
| 1268 | 1268 | = {-#SCC "simplNonRecE" #-}
|
| 1269 | - simplNonRecE env FromLet bndr (rhs, env) body cont
|
|
| 1269 | + simplNonRecE env FromLet bndr (mkContEx env rhs) body cont
|
|
| 1270 | 1270 | |
| 1271 | 1271 | {- Note [Avoiding space leaks in OutType]
|
| 1272 | 1272 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1549,10 +1549,9 @@ rebuild_go env expr cont |
| 1549 | 1549 | ApplyToTy { sc_arg_ty = ty, sc_cont = cont}
|
| 1550 | 1550 | -> rebuild_go env (App expr (Type ty)) cont
|
| 1551 | 1551 | |
| 1552 | - ApplyToVal { sc_arg = arg, sc_env = se, sc_dup = dup_flag
|
|
| 1553 | - , sc_cont = cont, sc_hole_ty = fun_ty }
|
|
| 1552 | + ApplyToVal { sc_arg = arg_clo, sc_cont = cont, sc_hole_ty = fun_ty }
|
|
| 1554 | 1553 | -- See Note [Avoid redundant simplification]
|
| 1555 | - -> do { (_, _, arg') <- simplLazyArg env dup_flag fun_ty Nothing se arg
|
|
| 1554 | + -> do { arg' <- simplClo env fun_ty Nothing arg_clo
|
|
| 1556 | 1555 | ; rebuild_go env (App expr arg') cont }
|
| 1557 | 1556 | |
| 1558 | 1557 | completeBindX :: SimplEnv
|
| ... | ... | @@ -1709,7 +1708,7 @@ simplCast env body co0 cont0 |
| 1709 | 1708 | -- where co :: (s1->s2) ~ (t1->t2)
|
| 1710 | 1709 | -- co1 :: t1 ~ s1
|
| 1711 | 1710 | -- co2 :: s2 ~ t2
|
| 1712 | - addCoerce co co_is_opt cont@(ApplyToVal { sc_arg = arg, sc_env = arg_se
|
|
| 1711 | + addCoerce co co_is_opt cont@(ApplyToVal { sc_arg = arg_clo
|
|
| 1713 | 1712 | , sc_dup = dup, sc_cont = tail
|
| 1714 | 1713 | , sc_hole_ty = fun_ty })
|
| 1715 | 1714 | | not co_is_opt -- pushCoValArg duplicates the coercion, so optimise first
|
| ... | ... | @@ -1724,15 +1723,13 @@ simplCast env body co0 cont0 |
| 1724 | 1723 | -- See Note [Avoiding simplifying repeatedly]
|
| 1725 | 1724 | |
| 1726 | 1725 | MCo co1 ->
|
| 1727 | - do { (dup', arg_se', arg') <- simplLazyArg env dup fun_ty Nothing arg_se arg
|
|
| 1728 | - -- When we build the ApplyTo we can't mix the OutCoercion
|
|
| 1729 | - -- 'co' with the InExpr 'arg', so we simplify
|
|
| 1730 | - -- to make it all consistent. It's a bit messy.
|
|
| 1731 | - -- But it isn't a common case.
|
|
| 1732 | - -- Example of use: #995
|
|
| 1733 | - ; return (ApplyToVal { sc_arg = mkCast arg' co1
|
|
| 1734 | - , sc_env = arg_se'
|
|
| 1735 | - , sc_dup = dup'
|
|
| 1726 | + do { let arg_clo' = case arg_clo of
|
|
| 1727 | + DoneId v -> DoneEx (Cast (Var v) co1) NotJoinPoint
|
|
| 1728 | + DoneEx e _jp -> DoneEx (Cast e co1) NotJoinPoint
|
|
| 1729 | + ContEx se e mco -> ContEx se e (mkTransMCoL mco co1)
|
|
| 1730 | + |
|
| 1731 | + ; return (ApplyToVal { sc_arg = arg_clo'
|
|
| 1732 | + , sc_dup = dup
|
|
| 1736 | 1733 | , sc_cont = tail'
|
| 1737 | 1734 | , sc_hole_ty = coercionLKind co }) } } }
|
| 1738 | 1735 | |
| ... | ... | @@ -1742,28 +1739,25 @@ simplCast env body co0 cont0 |
| 1742 | 1739 | -- See Note [Optimising reflexivity]
|
| 1743 | 1740 | | otherwise = return (CastIt { sc_co = co, sc_opt = co_is_opt, sc_cont = cont })
|
| 1744 | 1741 | |
| 1745 | -simplLazyArg :: SimplEnvIS -- ^ Used only for its InScopeSet
|
|
| 1746 | - -> DupFlag
|
|
| 1747 | - -> OutType -- ^ Type of the function applied to this arg
|
|
| 1748 | - -> Maybe ArgInfo -- ^ Just <=> This arg `ai` occurs in an app
|
|
| 1749 | - -- `f a1 ... an` where we have ArgInfo on
|
|
| 1750 | - -- how `f` uses `ai`, affecting the Stop
|
|
| 1751 | - -- continuation passed to 'simplExprC'
|
|
| 1752 | - -> StaticEnv -> CoreExpr -- ^ Expression with its static envt
|
|
| 1753 | - -> SimplM (DupFlag, StaticEnv, OutExpr)
|
|
| 1754 | -simplLazyArg env dup_flag fun_ty mb_arg_info arg_env arg
|
|
| 1755 | - | isSimplified dup_flag
|
|
| 1756 | - = return (dup_flag, arg_env, arg)
|
|
| 1757 | - | otherwise
|
|
| 1758 | - = do { let arg_env' = arg_env `setInScopeFromE` env
|
|
| 1759 | - ; let arg_ty = funArgTy fun_ty
|
|
| 1760 | - ; let stop = case mb_arg_info of
|
|
| 1761 | - Nothing -> mkBoringStop arg_ty
|
|
| 1762 | - Just ai -> mkLazyArgStop arg_ty ai
|
|
| 1763 | - ; arg' <- simplExprC arg_env' arg stop
|
|
| 1764 | - ; return (Simplified, zapSubstEnv arg_env', arg') }
|
|
| 1765 | - -- Return a StaticEnv that includes the in-scope set from 'env',
|
|
| 1766 | - -- because arg' may well mention those variables (#20639)
|
|
| 1742 | +simplClo :: SimplEnvIS -- ^ Used only for its InScopeSet
|
|
| 1743 | + -> OutType -- ^ Type of the function applied to this arg
|
|
| 1744 | + -> Maybe ArgInfo -- ^ Just <=> This arg `ai` occurs in an app
|
|
| 1745 | + -- `f a1 ... an` where we have ArgInfo on
|
|
| 1746 | + -- how `f` uses `ai`, affecting the Stop
|
|
| 1747 | + -- continuation passed to 'simplExprC'
|
|
| 1748 | + -> SimplClo
|
|
| 1749 | + -> SimplM OutExpr
|
|
| 1750 | +simplClo env fun_ty mb_arg_info (ContEx arg_se arg mco)
|
|
| 1751 | + = simplExprC arg_env arg stop
|
|
| 1752 | + where
|
|
| 1753 | + arg_env = arg_se `setInScopeFromE` env
|
|
| 1754 | + arg_ty = funArgTy fun_ty
|
|
| 1755 | + stop = case mb_arg_info of
|
|
| 1756 | + Nothing -> mkBoringStop arg_ty
|
|
| 1757 | + Just ai -> mkLazyArgStop arg_ty ai
|
|
| 1758 | + |
|
| 1759 | +simplClo _ _ _ (DoneEx e _) = return e
|
|
| 1760 | +simplClo _ _ _ (DoneId v) = return (Var v)
|
|
| 1767 | 1761 | |
| 1768 | 1762 | {-
|
| 1769 | 1763 | ************************************************************************
|
| ... | ... | @@ -1797,16 +1791,15 @@ simpl_lam env bndr body (ApplyToTy { sc_arg_ty = arg_ty, sc_cont = cont }) |
| 1797 | 1791 | ; simplLam (extendTvSubst env bndr arg_ty) body cont }
|
| 1798 | 1792 | |
| 1799 | 1793 | -- Coercion beta-reduction
|
| 1800 | -simpl_lam env bndr body (ApplyToVal { sc_arg = Coercion arg_co, sc_env = arg_se
|
|
| 1801 | - , sc_cont = cont })
|
|
| 1794 | +simpl_lam env bndr body (ApplyToVal { sc_arg = arg_clo, sc_cont = cont })
|
|
| 1795 | + | Just out_co <- simplCloCoercion_maybe arg_clo
|
|
| 1802 | 1796 | = assertPpr (isCoVar bndr) (ppr bndr) $
|
| 1803 | 1797 | do { tick (BetaReduction bndr)
|
| 1804 | - ; let arg_co' = substCo (arg_se `setInScopeFromE` env) arg_co
|
|
| 1805 | - ; simplLam (extendCvSubst env bndr arg_co') body cont }
|
|
| 1798 | + ; simplLam (extendCvSubst env bndr out_co) body cont }
|
|
| 1806 | 1799 | |
| 1807 | 1800 | -- Value beta-reduction
|
| 1808 | 1801 | -- This works for /coercion/ lambdas too
|
| 1809 | -simpl_lam env bndr body (ApplyToVal { sc_arg = arg, sc_env = arg_se
|
|
| 1802 | +simpl_lam env bndr body (ApplyToVal { sc_arg = arg_clo
|
|
| 1810 | 1803 | , sc_cont = cont, sc_dup = dup
|
| 1811 | 1804 | , sc_hole_ty = fun_ty})
|
| 1812 | 1805 | = do { tick (BetaReduction bndr)
|
| ... | ... | @@ -1823,24 +1816,13 @@ simpl_lam env bndr body (ApplyToVal { sc_arg = arg, sc_env = arg_se |
| 1823 | 1816 | -- It's wrong to err in either direction
|
| 1824 | 1817 | -- But fun_ty is an OutType, so is fully substituted
|
| 1825 | 1818 | |
| 1826 | - ; if | Just env' <- preInlineUnconditionally env NotTopLevel bndr arg arg_se
|
|
| 1827 | - , not (needsCaseBindingL arg_levity arg)
|
|
| 1828 | - -- Ok to test arg::InExpr in needsCaseBinding because
|
|
| 1829 | - -- exprOkForSpeculation is stable under simplification
|
|
| 1830 | - , not ( isSimplified dup && -- See (SR2) in Note [Avoiding simplifying repeatedly]
|
|
| 1831 | - not (exprIsTrivial arg) &&
|
|
| 1832 | - not (isDeadOcc (idOccInfo bndr)) )
|
|
| 1819 | + ; if | Just env' <- preInlineBetaUnconditionally env arg_levity bndr arg_clo
|
|
| 1833 | 1820 | -> do { simplTrace "SimplBindr:inline-uncond3" (ppr bndr) $
|
| 1834 | 1821 | tick (PreInlineUnconditionally bndr)
|
| 1835 | 1822 | ; simplLam env' body cont }
|
| 1836 | 1823 | |
| 1837 | - | isSimplified dup -- Don't re-simplify if we've simplified it once
|
|
| 1838 | - -- Including don't preInlineUnconditionally
|
|
| 1839 | - -- See Note [Avoiding simplifying repeatedly]
|
|
| 1840 | - -> completeBindX env from_what bndr arg body cont
|
|
| 1841 | - |
|
| 1842 | 1824 | | otherwise
|
| 1843 | - -> simplNonRecE env from_what bndr (arg, arg_se) body cont }
|
|
| 1825 | + -> simplNonRecE env from_what bndr arg_clo body cont }
|
|
| 1844 | 1826 | |
| 1845 | 1827 | -- Discard a non-counting tick on a lambda. This may change the
|
| 1846 | 1828 | -- cost attribution slightly (moving the allocation of the
|
| ... | ... | @@ -1876,8 +1858,7 @@ simplNonRecE :: HasDebugCallStack |
| 1876 | 1858 | -> FromWhat
|
| 1877 | 1859 | -> InId -- The binder, always an Id
|
| 1878 | 1860 | -- Never a join point
|
| 1879 | - -- The static env for its unfolding (if any) is the first parameter
|
|
| 1880 | - -> (InExpr, SimplEnv) -- Rhs of binding (or arg of lambda)
|
|
| 1861 | + -> SimplClo -- Rhs of binding (or arg of lambda)
|
|
| 1881 | 1862 | -> InExpr -- Body of the let/lambda
|
| 1882 | 1863 | -> SimplCont
|
| 1883 | 1864 | -> SimplM (SimplFloats, OutExpr)
|
| ... | ... | @@ -1896,7 +1877,14 @@ simplNonRecE :: HasDebugCallStack |
| 1896 | 1877 | -- from_what=FromLet => the RHS satisfies the let-can-float invariant
|
| 1897 | 1878 | -- Otherwise it may or may not satisfy it.
|
| 1898 | 1879 | |
| 1899 | -simplNonRecE env from_what bndr (rhs, rhs_se) body cont
|
|
| 1880 | +simplNonRecE env from_what bndr (DoneEx rhs jp) body cont
|
|
| 1881 | + = assertPpr (jp == NotJoinPoint) (ppr bndr) $
|
|
| 1882 | + completeBindX env from_what bndr rhs body cont
|
|
| 1883 | + |
|
| 1884 | +simplNonRecE env from_what bndr (DoneId v) body cont
|
|
| 1885 | + = completeBindX env from_what bndr (Var v) body cont
|
|
| 1886 | + |
|
| 1887 | +simplNonRecE env from_what bndr (ContEx rhs_se rhs mco) body cont
|
|
| 1900 | 1888 | | assert (isId bndr && not (isJoinId bndr) ) $
|
| 1901 | 1889 | is_strict_bind
|
| 1902 | 1890 | = -- Evaluate RHS strictly
|
| ... | ... | @@ -2237,10 +2225,10 @@ simplInVar env var |
| 2237 | 2225 | | isCoVar var = return $! Coercion $! (substCoVar env var)
|
| 2238 | 2226 | | otherwise
|
| 2239 | 2227 | = case substId env var of
|
| 2240 | - ContEx tvs cvs ids e -> let env' = setSubstEnv env tvs cvs ids
|
|
| 2241 | - in simplExpr env' e
|
|
| 2242 | - DoneId var1 -> return (Var var1)
|
|
| 2243 | - DoneEx e _ -> return e
|
|
| 2228 | + ContEx se e mco -> do { e' <- simplExpr (se `setInScopeFromE` env) e
|
|
| 2229 | + ; return (mkCastMCo e' mco) }
|
|
| 2230 | + DoneId var1 -> return (Var var1)
|
|
| 2231 | + DoneEx e _ -> return e
|
|
| 2244 | 2232 | |
| 2245 | 2233 | simplInId :: SimplEnv -> InId -> SimplCont -> SimplM (SimplFloats, OutExpr)
|
| 2246 | 2234 | simplInId env var cont
|
| ... | ... | @@ -2249,19 +2237,16 @@ simplInId env var cont |
| 2249 | 2237 | = rebuild zapped_env (Var var) cont
|
| 2250 | 2238 | | otherwise
|
| 2251 | 2239 | = case substId env var of
|
| 2252 | - ContEx tvs cvs ids e -> simplExprF env' e cont
|
|
| 2253 | - -- Don't trimJoinCont; haven't already simplified e,
|
|
| 2240 | + ContEx se e mco -> do { e' <- simplExprF (se `setInScopeFromE` env) e cont
|
|
| 2241 | + ; return (mkCastMCo e' mco) }
|
|
| 2242 | + -- Don't trimJoinCont; we haven't already simplified e,
|
|
| 2254 | 2243 | -- so the cont is not embodied in e
|
| 2255 | - where
|
|
| 2256 | - env' = setSubstEnv env tvs cvs ids
|
|
| 2257 | 2244 | |
| 2258 | - DoneId out_id -> simplOutId zapped_env out_id cont'
|
|
| 2259 | - where
|
|
| 2260 | - cont' = trimJoinCont out_id (idJoinPointHood out_id) cont
|
|
| 2245 | + DoneId out_id -> simplOutId zapped_env out_id $
|
|
| 2246 | + trimJoinCont out_id (idJoinPointHood out_id) cont
|
|
| 2261 | 2247 | |
| 2262 | - DoneEx e mb_join -> simplExprF zapped_env e cont'
|
|
| 2263 | - where
|
|
| 2264 | - cont' = trimJoinCont var mb_join cont
|
|
| 2248 | + DoneEx e mb_join -> simplExprF zapped_env e $
|
|
| 2249 | + trimJoinCont var mb_join cont
|
|
| 2265 | 2250 | where
|
| 2266 | 2251 | zapped_env = zapSubstEnv env -- See Note [zapSubstEnv]
|
| 2267 | 2252 | |
| ... | ... | @@ -2277,8 +2262,8 @@ simplOutId env fun cont |
| 2277 | 2262 | | fun `hasKey` runRWKey
|
| 2278 | 2263 | , ApplyToTy { sc_cont = cont1 } <- cont
|
| 2279 | 2264 | , ApplyToTy { sc_cont = cont2, sc_arg_ty = hole_ty } <- cont1
|
| 2280 | - , ApplyToVal { sc_cont = cont3, sc_arg = arg
|
|
| 2281 | - , sc_env = arg_se, sc_hole_ty = fun_ty } <- cont2
|
|
| 2265 | + , ApplyToVal { sc_cont = cont3, sc_arg = arg_clo
|
|
| 2266 | + , sc_hole_ty = fun_ty } <- cont2
|
|
| 2282 | 2267 | -- Do this even if (contIsStop cont), or if seCaseCase is off.
|
| 2283 | 2268 | -- See Note [No eta-expansion in runRW#]
|
| 2284 | 2269 | = do { let arg_env = arg_se `setInScopeFromE` env
|
| ... | ... | @@ -2306,8 +2291,8 @@ simplOutId env fun cont |
| 2306 | 2291 | _ -> do { s' <- newId (fsLit "s") ManyTy realWorldStatePrimTy
|
| 2307 | 2292 | ; let (m,_,_) = splitFunTy fun_ty
|
| 2308 | 2293 | env' = arg_env `addNewInScopeIds` [s']
|
| 2309 | - cont' = ApplyToVal { sc_dup = Simplified, sc_arg = Var s'
|
|
| 2310 | - , sc_env = env', sc_cont = inner_cont
|
|
| 2294 | + cont' = ApplyToVal { sc_dup = Dupable, sc_arg = DoneId s'
|
|
| 2295 | + , sc_cont = inner_cont
|
|
| 2311 | 2296 | , sc_hole_ty = mkVisFunTy m realWorldStatePrimTy new_runrw_res_ty }
|
| 2312 | 2297 | -- cont' applies to s', then K
|
| 2313 | 2298 | ; body' <- simplExprC env' arg cont'
|
| ... | ... | @@ -2386,32 +2371,36 @@ rebuildCall env info (ApplyToTy { sc_arg_ty = arg_ty, sc_hole_ty = hole_ty, sc_c |
| 2386 | 2371 | |
| 2387 | 2372 | ---------- Simplify value arguments --------------------
|
| 2388 | 2373 | rebuildCall env fun_info
|
| 2389 | - (ApplyToVal { sc_arg = arg, sc_env = arg_se
|
|
| 2374 | + (ApplyToVal { sc_arg = arg_clo
|
|
| 2390 | 2375 | , sc_dup = dup_flag, sc_hole_ty = fun_ty
|
| 2391 | 2376 | , sc_cont = cont })
|
| 2392 | - -- Argument is already simplified
|
|
| 2393 | - | isSimplified dup_flag -- See Note [Avoid redundant simplification]
|
|
| 2394 | - = rebuildCall env (addValArgTo fun_info arg fun_ty) cont
|
|
| 2395 | - |
|
| 2396 | - -- Strict arguments
|
|
| 2397 | - | isStrictArgInfo fun_info
|
|
| 2398 | - , seCaseCase env -- Only when case-of-case is on. See GHC.Driver.Config.Core.Opt.Simplify
|
|
| 2399 | - -- Note [Case-of-case and full laziness]
|
|
| 2400 | - = -- pprTrace "Strict Arg" (ppr arg $$ ppr (seIdSubst env) $$ ppr (seInScope env)) $
|
|
| 2401 | - simplExprF (arg_se `setInScopeFromE` env) arg
|
|
| 2402 | - (StrictArg { sc_fun = fun_info, sc_fun_ty = fun_ty
|
|
| 2403 | - , sc_dup = Simplified
|
|
| 2404 | - , sc_cont = cont })
|
|
| 2377 | + = case arg_clo of -- See Note [Avoid redundant simplification]
|
|
| 2378 | + DoneId v -> rebuildCall env (addValArgTo fun_info (Var v) fun_ty) cont
|
|
| 2379 | + DoneEx arg _ -> rebuildCall env (addValArgTo fun_info arg fun_ty) cont
|
|
| 2380 | + ContEx arg_se in_arg mco
|
|
| 2381 | + -- Strict arguments
|
|
| 2382 | + | isStrictArgInfo fun_info
|
|
| 2383 | + , seCaseCase env -- Only when case-of-case is on. See GHC.Driver.Config.Core.Opt.Simplify
|
|
| 2384 | + -- Note [Case-of-case and full laziness]
|
|
| 2385 | + -> simplExprF (arg_se `setInScopeFromE` env) in_arg
|
|
| 2386 | + (add_cast mco $
|
|
| 2387 | + StrictArg { sc_fun = fun_info, sc_fun_ty = fun_ty
|
|
| 2388 | + , sc_dup = NoDup, sc_cont = cont })
|
|
| 2405 | 2389 | -- Note [Shadowing in the Simplifier]
|
| 2406 | 2390 | |
| 2407 | - -- Lazy arguments
|
|
| 2408 | - | otherwise
|
|
| 2391 | + -- Lazy arguments
|
|
| 2392 | + | otherwise
|
|
| 2409 | 2393 | -- DO NOT float anything outside, hence simplExprC
|
| 2410 | 2394 | -- There is no benefit (unlike in a let-binding), and we'd
|
| 2411 | 2395 | -- have to be very careful about bogus strictness through
|
| 2412 | 2396 | -- floating a demanded let.
|
| 2413 | - = do { (_, _, arg') <- simplLazyArg env dup_flag fun_ty (Just fun_info) arg_se arg
|
|
| 2414 | - ; rebuildCall env (addValArgTo fun_info arg' fun_ty) cont }
|
|
| 2397 | + -> do { arg' <- simplClo env fun_ty (Just fun_info) arg_clo
|
|
| 2398 | + ; rebuildCall env (addValArgTo fun_info arg' fun_ty) cont }
|
|
| 2399 | + |
|
| 2400 | + where
|
|
| 2401 | + add_cast MRefl cont = cont
|
|
| 2402 | + add_cast (MCo co) cont = CastIt { sc_co = co, sc_opt = True, sc_cont = cont }
|
|
| 2403 | + |
|
| 2415 | 2404 | |
| 2416 | 2405 | ---------- No further useful info, revert to generic rebuild ------------
|
| 2417 | 2406 | rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args, ai_rules = rules }) cont
|
| ... | ... | @@ -2436,7 +2425,7 @@ tryInlining env logger var cont |
| 2436 | 2425 | = return Nothing
|
| 2437 | 2426 | |
| 2438 | 2427 | where
|
| 2439 | - (lone_variable, arg_infos, call_cont) = contArgs cont
|
|
| 2428 | + (lone_variable, arg_infos, call_cont) = contArgs env cont
|
|
| 2440 | 2429 | interesting_cont = interestingCallContext env call_cont
|
| 2441 | 2430 | |
| 2442 | 2431 | log_inlining doc
|
| ... | ... | @@ -2644,7 +2633,7 @@ tryRules env rules fn args |
| 2644 | 2633 | --, text "Rule activation:" <+> ppr (ruleActivation rule)
|
| 2645 | 2634 | , text "Full arity:" <+> ppr (ruleArity rule)
|
| 2646 | 2635 | , text "Before:" <+> hang (ppr fn) 2 (sep (map ppr args))
|
| 2647 | - , text "After: " <+> pprCoreExpr rule_rhs ]
|
|
| 2636 | + , text "After: " <+> mkApps (pprCoreExpr rule_rhs) (drop (ruleArity rule) args) ]
|
|
| 2648 | 2637 | |
| 2649 | 2638 | | logHasDumpFlag logger Opt_D_dump_rule_firings
|
| 2650 | 2639 | = log_rule Opt_D_dump_rule_firings "Rule fired:" $
|
| ... | ... | @@ -2713,8 +2702,8 @@ trySeqRules in_env scrut rhs cont |
| 2713 | 2702 | , ValArg { as_arg = no_cast_scrut
|
| 2714 | 2703 | , as_dmd = seqDmd
|
| 2715 | 2704 | , as_hole_ty = res3_ty } ]
|
| 2716 | - rule_cont = ApplyToVal { sc_dup = NoDup, sc_arg = rhs
|
|
| 2717 | - , sc_env = in_env, sc_cont = cont
|
|
| 2705 | + rule_cont = ApplyToVal { sc_dup = NoDup, sc_arg = mkContEx in_env rhs
|
|
| 2706 | + , sc_cont = cont
|
|
| 2718 | 2707 | , sc_hole_ty = res4_ty }
|
| 2719 | 2708 | |
| 2720 | 2709 | -- Lazily evaluated, so we don't do most of this
|
| ... | ... | @@ -3941,7 +3930,7 @@ mkDupableContWithDmds env dmds |
| 3941 | 3930 | , sc_arg_ty = arg_ty, sc_hole_ty = hole_ty }) }
|
| 3942 | 3931 | |
| 3943 | 3932 | mkDupableContWithDmds env dmds
|
| 3944 | - (ApplyToVal { sc_arg = arg, sc_dup = dup, sc_env = se
|
|
| 3933 | + (ApplyToVal { sc_arg = arg_clo, sc_dup = dup
|
|
| 3945 | 3934 | , sc_cont = cont, sc_hole_ty = hole_ty })
|
| 3946 | 3935 | = -- e.g. [...hole...] (...arg...)
|
| 3947 | 3936 | -- ==>
|
| ... | ... | @@ -3951,16 +3940,11 @@ mkDupableContWithDmds env dmds |
| 3951 | 3940 | do { let dmd:|cont_dmds = expectNonEmpty dmds
|
| 3952 | 3941 | ; (floats1, cont') <- mkDupableContWithDmds env cont_dmds cont
|
| 3953 | 3942 | ; let env' = env `setInScopeFromF` floats1
|
| 3954 | - ; (_, se', arg') <- simplLazyArg env' dup hole_ty Nothing se arg
|
|
| 3943 | + ; arg' <- simplClo env' hole_ty Nothing arg_clo
|
|
| 3955 | 3944 | ; (let_floats2, arg'') <- makeTrivial env NotTopLevel dmd (fsLit "karg") arg'
|
| 3956 | 3945 | ; let all_floats = floats1 `addLetFloats` let_floats2
|
| 3957 | 3946 | ; return ( all_floats
|
| 3958 | - , ApplyToVal { sc_arg = arg''
|
|
| 3959 | - , sc_env = se' `setInScopeFromF` all_floats
|
|
| 3960 | - -- Ensure that sc_env includes the free vars of
|
|
| 3961 | - -- arg'' in its in-scope set, even if makeTrivial
|
|
| 3962 | - -- has turned arg'' into a fresh variable
|
|
| 3963 | - -- See Note [StaticEnv invariant] in GHC.Core.Opt.Simplify.Utils
|
|
| 3947 | + , ApplyToVal { sc_arg = DoneEx arg'' NotJoinPoint
|
|
| 3964 | 3948 | , sc_dup = OkToDup, sc_cont = cont'
|
| 3965 | 3949 | , sc_hole_ty = hole_ty }) }
|
| 3966 | 3950 |
| ... | ... | @@ -12,7 +12,9 @@ module GHC.Core.Opt.Simplify.Utils ( |
| 12 | 12 | tryEtaExpandRhs, wantEtaExpansion,
|
| 13 | 13 | |
| 14 | 14 | -- Inlining,
|
| 15 | - preInlineUnconditionally, postInlineUnconditionally,
|
|
| 15 | + preInlineLetUnconditionally,
|
|
| 16 | + preInlineBetaUnconditionally,
|
|
| 17 | + postInlineUnconditionally,
|
|
| 16 | 18 | activeRule,
|
| 17 | 19 | getUnfoldingInRuleMatch,
|
| 18 | 20 | updModeForStableUnfoldings, updModeForRuleLHS, updModeForRuleRHS,
|
| ... | ... | @@ -173,8 +175,7 @@ data SimplCont |
| 173 | 175 | { sc_dup :: DupFlag -- See Note [DupFlag invariants]
|
| 174 | 176 | , sc_hole_ty :: OutType -- Type of the function, presumably (forall a. blah)
|
| 175 | 177 | -- See Note [The hole type in ApplyToTy]
|
| 176 | - , sc_arg :: InExpr -- The argument,
|
|
| 177 | - , sc_env :: StaticEnv -- see Note [StaticEnv invariant]
|
|
| 178 | + , sc_arg :: SimplClo -- The argument
|
|
| 178 | 179 | , sc_cont :: SimplCont }
|
| 179 | 180 | |
| 180 | 181 | | ApplyToTy -- (ApplyToTy ty K)[e] = K[ e ty ]
|
| ... | ... | @@ -216,23 +217,17 @@ data SimplCont |
| 216 | 217 | CoreTickish -- Tick tickish <hole>
|
| 217 | 218 | SimplCont
|
| 218 | 219 | |
| 219 | -type StaticEnv = SimplEnv -- Just the static part is relevant
|
|
| 220 | 220 | |
| 221 | 221 | data FromWhat = FromLet | FromBeta Levity
|
| 222 | 222 | |
| 223 | 223 | -- See Note [DupFlag invariants]
|
| 224 | 224 | data DupFlag = NoDup -- Unsimplified, might be big
|
| 225 | - | Simplified -- Simplified
|
|
| 226 | 225 | | OkToDup -- Simplified and small
|
| 227 | 226 | |
| 228 | 227 | isSimplified :: DupFlag -> Bool
|
| 229 | 228 | isSimplified NoDup = False
|
| 230 | 229 | isSimplified _ = True -- Invariant: the subst-env is empty
|
| 231 | 230 | |
| 232 | -perhapsSubstTy :: DupFlag -> StaticEnv -> Type -> Type
|
|
| 233 | -perhapsSubstTy dup env ty
|
|
| 234 | - | isSimplified dup = ty
|
|
| 235 | - | otherwise = substTy env ty
|
|
| 236 | 231 | |
| 237 | 232 | {- Note [StaticEnv invariant]
|
| 238 | 233 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -255,21 +250,16 @@ the expression, and that (rightly) gives ASSERT failures if the InScopeSet |
| 255 | 250 | isn't big enough.
|
| 256 | 251 | |
| 257 | 252 | Note [DupFlag invariants]
|
| 258 | -~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 253 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 259 | 254 | In both ApplyToVal { se_dup = dup, se_env = env, se_cont = k}
|
| 260 | 255 | and Select { se_dup = dup, se_env = env, se_cont = k}
|
| 261 | -the following invariants hold
|
|
| 262 | - |
|
| 263 | - (a) if dup = OkToDup, then continuation k is also ok-to-dup
|
|
| 264 | - (b) if dup = OkToDup or Simplified, the subst-env is empty,
|
|
| 265 | - or at least is always ignored; the payload is
|
|
| 266 | - already an OutThing
|
|
| 256 | +the following invariant holds
|
|
| 257 | + if dup = OkToDup, then continuation k is also ok-to-dup
|
|
| 267 | 258 | -}
|
| 268 | 259 | |
| 269 | 260 | instance Outputable DupFlag where
|
| 270 | 261 | ppr OkToDup = text "ok"
|
| 271 | 262 | ppr NoDup = text "nodup"
|
| 272 | - ppr Simplified = text "simpl"
|
|
| 273 | 263 | |
| 274 | 264 | instance Outputable SimplCont where
|
| 275 | 265 | ppr (Stop ty interesting eval_sd)
|
| ... | ... | @@ -284,7 +274,7 @@ instance Outputable SimplCont where |
| 284 | 274 | = (text "ApplyToTy" <+> pprParendType ty) $$ ppr cont
|
| 285 | 275 | ppr (ApplyToVal { sc_arg = arg, sc_dup = dup, sc_cont = cont, sc_hole_ty = hole_ty })
|
| 286 | 276 | = (hang (text "ApplyToVal" <+> ppr dup <+> text "hole-ty:" <+> pprParendType hole_ty)
|
| 287 | - 2 (pprParendExpr arg))
|
|
| 277 | + 2 (ppr arg))
|
|
| 288 | 278 | $$ ppr cont
|
| 289 | 279 | ppr (StrictBind { sc_bndr = b, sc_cont = cont })
|
| 290 | 280 | = (text "StrictBind" <+> ppr b) $$ ppr cont
|
| ... | ... | @@ -392,9 +382,8 @@ pushSimplifiedArgs env args cont = foldr (pushSimplifiedArg env) cont args |
| 392 | 382 | pushSimplifiedArg :: SimplEnv -> ArgSpec -> SimplCont -> SimplCont
|
| 393 | 383 | pushSimplifiedArg _env (TyArg { as_arg_ty = arg_ty, as_hole_ty = hole_ty }) cont
|
| 394 | 384 | = ApplyToTy { sc_arg_ty = arg_ty, sc_hole_ty = hole_ty, sc_cont = cont }
|
| 395 | -pushSimplifiedArg env (ValArg { as_arg = arg, as_hole_ty = hole_ty }) cont
|
|
| 396 | - = ApplyToVal { sc_arg = arg, sc_env = env, sc_dup = Simplified
|
|
| 397 | - -- The SubstEnv will be ignored since sc_dup=Simplified
|
|
| 385 | +pushSimplifiedArg _env (ValArg { as_arg = arg, as_hole_ty = hole_ty }) cont
|
|
| 386 | + = ApplyToVal { sc_arg = DoneEx arg NotJoinPoint, sc_dup = NoDup
|
|
| 398 | 387 | , sc_hole_ty = hole_ty, sc_cont = cont }
|
| 399 | 388 | |
| 400 | 389 | argSpecArg :: ArgSpec -> OutExpr
|
| ... | ... | @@ -475,14 +464,17 @@ contHoleType :: SimplCont -> OutType |
| 475 | 464 | contHoleType (Stop ty _ _) = ty
|
| 476 | 465 | contHoleType (TickIt _ k) = contHoleType k
|
| 477 | 466 | contHoleType (CastIt { sc_co = co }) = coercionLKind co
|
| 478 | -contHoleType (StrictBind { sc_bndr = b, sc_dup = dup, sc_env = se })
|
|
| 479 | - = perhapsSubstTy dup se (idType b)
|
|
| 480 | 467 | contHoleType (StrictArg { sc_fun_ty = ty }) = funArgTy ty
|
| 481 | 468 | contHoleType (ApplyToTy { sc_hole_ty = ty }) = ty -- See Note [The hole type in ApplyToTy]
|
| 482 | 469 | contHoleType (ApplyToVal { sc_hole_ty = ty }) = ty -- See Note [The hole type in ApplyToTy]
|
| 483 | -contHoleType (Select { sc_dup = d, sc_bndr = b, sc_env = se })
|
|
| 484 | - = perhapsSubstTy d se (idType b)
|
|
| 470 | +contHoleType (StrictBind { sc_bndr = b, sc_dup = d, sc_env = se }) = perhapsSubstIdTy d se b
|
|
| 471 | +contHoleType (Select { sc_bndr = b, sc_dup = d, sc_env = se }) = perhapsSubstIdTy d se b
|
|
| 485 | 472 | |
| 473 | +perhapsSubstIdTy :: DupFlag -> StaticEnv -> Id -> Type
|
|
| 474 | +perhapsSubstIdTy dup_flag env bndr
|
|
| 475 | + = case dup_flag of
|
|
| 476 | + OkToDup -> idType bndr -- The Id is an OutId
|
|
| 477 | + NoDup -> substTy env (idType bndr) -- The Id is an InId
|
|
| 486 | 478 | |
| 487 | 479 | -- Computes the multiplicity scaling factor at the hole. That is, in (case [] of
|
| 488 | 480 | -- x ::(p) _ { … }) (respectively for arguments of functions), the scaling
|
| ... | ... | @@ -525,11 +517,11 @@ countValArgs (CastIt { sc_cont = cont }) = countValArgs cont |
| 525 | 517 | countValArgs _ = 0
|
| 526 | 518 | |
| 527 | 519 | -------------------
|
| 528 | -contArgs :: SimplCont -> (Bool, [ArgSummary], SimplCont)
|
|
| 520 | +contArgs :: SimplEnv -> SimplCont -> (Bool, [ArgSummary], SimplCont)
|
|
| 529 | 521 | -- Summarises value args, discards type args and coercions
|
| 530 | 522 | -- The returned continuation of the call is only used to
|
| 531 | 523 | -- answer questions like "are you interesting?"
|
| 532 | -contArgs cont
|
|
| 524 | +contArgs env cont
|
|
| 533 | 525 | | lone cont = (True, [], cont)
|
| 534 | 526 | | otherwise = go [] cont
|
| 535 | 527 | where
|
| ... | ... | @@ -538,34 +530,22 @@ contArgs cont |
| 538 | 530 | lone (CastIt {}) = False -- stops it being "lone"
|
| 539 | 531 | lone _ = True
|
| 540 | 532 | |
| 541 | - go args (ApplyToVal { sc_arg = arg, sc_env = se, sc_cont = k })
|
|
| 542 | - = go (is_interesting arg se : args) k
|
|
| 533 | + go args (ApplyToVal { sc_arg = arg_clo, sc_cont = k })
|
|
| 534 | + = go (interestingArg env arg_clo : args) k
|
|
| 543 | 535 | go args (ApplyToTy { sc_cont = k }) = go args k
|
| 544 | 536 | go args (CastIt { sc_cont = k }) = go args k
|
| 545 | 537 | go args k = (False, reverse args, k)
|
| 546 | 538 | |
| 547 | - is_interesting arg se = interestingArg se arg
|
|
| 548 | - -- Do *not* use short-cutting substitution here
|
|
| 549 | - -- because we want to get as much IdInfo as possible
|
|
| 550 | - |
|
| 551 | 539 | contOutArgs :: SimplEnv -> SimplCont -> [OutExpr]
|
| 552 | 540 | -- Get the leading arguments from the `SimplCont`, as /OutExprs/
|
| 553 | 541 | contOutArgs env cont
|
| 554 | 542 | = go cont
|
| 555 | 543 | where
|
| 556 | - in_scope = seInScope env
|
|
| 557 | - |
|
| 558 | 544 | go (ApplyToTy { sc_arg_ty = ty, sc_cont = cont })
|
| 559 | 545 | = Type ty : go cont
|
| 560 | 546 | |
| 561 | - go (ApplyToVal { sc_dup = dup, sc_arg = arg, sc_env = env, sc_cont = cont })
|
|
| 562 | - | isSimplified dup = arg : go cont
|
|
| 563 | - | otherwise = GHC.Core.Subst.substExpr (getFullSubst in_scope env) arg : go cont
|
|
| 564 | - -- Make sure we apply the static environment `sc_env` as a substitution
|
|
| 565 | - -- to get an OutExpr. See (BF1) in Note [tryRules: plan (BEFORE)]
|
|
| 566 | - -- in GHC.Core.Opt.Simplify.Iteration
|
|
| 567 | - -- NB: we use substExpr, not substExprSC: we want to get the benefit of
|
|
| 568 | - -- knowing what is evaluated etc, via the in-scope set
|
|
| 547 | + go (ApplyToVal { sc_arg = arg_clo, sc_cont = cont })
|
|
| 548 | + = simplCloExpr (seInScope env) arg_clo : go cont
|
|
| 569 | 549 | |
| 570 | 550 | -- No more arguments
|
| 571 | 551 | go _ = []
|
| ... | ... | @@ -993,16 +973,18 @@ rule for (*) (df d) can fire. To do this |
| 993 | 973 | b) we say that a con-like argument (eg (df d)) is interesting
|
| 994 | 974 | -}
|
| 995 | 975 | |
| 996 | -interestingArg :: SimplEnv -> CoreExpr -> ArgSummary
|
|
| 976 | +interestingArg :: SimplEnv -> SimplClo -> ArgSummary
|
|
| 997 | 977 | -- See Note [Interesting arguments]
|
| 998 | -interestingArg env e = go env 0 e
|
|
| 978 | +-- Do *not* use short-cutting substitution here
|
|
| 979 | +-- because we want to get as much IdInfo as possible
|
|
| 980 | +interestingArg env e = go_clo env 0 e
|
|
| 999 | 981 | where
|
| 982 | + go_clo _env n (DoneId v) = go_var n v
|
|
| 983 | + go_clo env n (DoneEx e _) = go (zapSubstEnv env) n e
|
|
| 984 | + go_clo env n (ContEx se e _co) = go (se `setInScopeFromE` env) n e
|
|
| 985 | + |
|
| 1000 | 986 | -- n is # value args to which the expression is applied
|
| 1001 | - go env n (Var v)
|
|
| 1002 | - = case substId env v of
|
|
| 1003 | - DoneId v' -> go_var n v'
|
|
| 1004 | - DoneEx e _ -> go (zapSubstEnv env) n e
|
|
| 1005 | - ContEx tvs cvs ids e -> go (setSubstEnv env tvs cvs ids) n e
|
|
| 987 | + go env n (Var v) = go_clo env n (substId env v)
|
|
| 1006 | 988 | |
| 1007 | 989 | go _ _ (Lit l)
|
| 1008 | 990 | | isLitRubbish l = TrivArg -- Leads to unproductive inlining in WWRec, #20035
|
| ... | ... | @@ -1490,7 +1472,38 @@ is a term (not a coercion) so we can't necessarily inline the latter in |
| 1490 | 1472 | the former.
|
| 1491 | 1473 | -}
|
| 1492 | 1474 | |
| 1493 | -preInlineUnconditionally
|
|
| 1475 | + |
|
| 1476 | +preInlineBetaUnconditionally
|
|
| 1477 | + :: SimplEnv -> Levity -> InId -> SimplClo
|
|
| 1478 | + -> Maybe SimplEnv -- Returned env has extended substitution
|
|
| 1479 | +preInlineBetaUnconditionally env levity bndr clo
|
|
| 1480 | + | not pre_inline_unconditionally = Nothing
|
|
| 1481 | + | isCoVar bndr = Nothing -- Note [Do not inline CoVars unconditionally]
|
|
| 1482 | + | not (one_occ (idOccInfo bndr)) = Nothing
|
|
| 1483 | + | needs_case_binding levity = Nothing
|
|
| 1484 | + | otherwise = Just $! extendIdSubst env bndr clo
|
|
| 1485 | + where
|
|
| 1486 | + pre_inline_unconditionally = sePreInline env
|
|
| 1487 | + |
|
| 1488 | + one_occ OneOcc{ occ_n_br = 1, occ_in_lam = NotInsideLam }
|
|
| 1489 | + = True
|
|
| 1490 | + one_occ OneOcc{ occ_n_br = 1, occ_in_lam = IsInsideLam, occ_int_cxt = IsInteresting }
|
|
| 1491 | + = case clo of
|
|
| 1492 | + ContEx _ rhs _ -> canInlineInLam rhs
|
|
| 1493 | + DoneId {} -> True
|
|
| 1494 | + DoneEx rhs _ -> exprIsTrivial rhs
|
|
| 1495 | + one_occ IAmDead = True -- Happens in ((\x.1) v)
|
|
| 1496 | + one_occ _ = False
|
|
| 1497 | + |
|
| 1498 | + -- NB: exprOkForSpeculation is stable under substitution
|
|
| 1499 | + -- so we can apply it to an InExpr in the ContEx case
|
|
| 1500 | + needs_case_binding Lifted = False
|
|
| 1501 | + needs_case_binding Unlifted = case clo of
|
|
| 1502 | + DoneId {} -> False
|
|
| 1503 | + DoneEx e _ -> exprOkForSpeculation e
|
|
| 1504 | + ContEx _ e _ -> exprOkForSpeculation e
|
|
| 1505 | + |
|
| 1506 | +preInlineLetUnconditionally
|
|
| 1494 | 1507 | :: SimplEnv -> TopLevelFlag -> InId
|
| 1495 | 1508 | -> InExpr -> StaticEnv -- These two go together
|
| 1496 | 1509 | -> Maybe SimplEnv -- Returned env has extended substitution
|
| ... | ... | @@ -1498,7 +1511,7 @@ preInlineUnconditionally |
| 1498 | 1511 | -- See Note [Core let-can-float invariant] in GHC.Core
|
| 1499 | 1512 | -- Reason: we don't want to inline single uses, or discard dead bindings,
|
| 1500 | 1513 | -- for unlifted, side-effect-ful bindings
|
| 1501 | -preInlineUnconditionally env top_lvl bndr rhs rhs_env
|
|
| 1514 | +preInlineLetUnconditionally env top_lvl bndr rhs rhs_env
|
|
| 1502 | 1515 | | not pre_inline_unconditionally = Nothing
|
| 1503 | 1516 | | not active = Nothing
|
| 1504 | 1517 | | isTopLevel top_lvl && isDeadEndId bndr = Nothing -- Note [Top-level bottoming Ids]
|
| ... | ... | @@ -1516,13 +1529,12 @@ preInlineUnconditionally env top_lvl bndr rhs rhs_env |
| 1516 | 1529 | unf = idUnfolding bndr
|
| 1517 | 1530 | extend_subst_with inl_rhs = extendIdSubst env bndr $! (mkContEx rhs_env inl_rhs)
|
| 1518 | 1531 | |
| 1532 | + one_occ OneOcc{ occ_n_br = 1, occ_in_lam = NotInsideLam }
|
|
| 1533 | + = isNotTopLevel top_lvl || early_phase
|
|
| 1534 | + one_occ OneOcc{ occ_n_br = 1, occ_in_lam = IsInsideLam, occ_int_cxt = IsInteresting }
|
|
| 1535 | + = canInlineInLam rhs
|
|
| 1519 | 1536 | one_occ IAmDead = True -- Happens in ((\x.1) v)
|
| 1520 | - one_occ OneOcc{ occ_n_br = 1
|
|
| 1521 | - , occ_in_lam = NotInsideLam } = isNotTopLevel top_lvl || early_phase
|
|
| 1522 | - one_occ OneOcc{ occ_n_br = 1
|
|
| 1523 | - , occ_in_lam = IsInsideLam
|
|
| 1524 | - , occ_int_cxt = IsInteresting } = canInlineInLam rhs
|
|
| 1525 | - one_occ _ = False
|
|
| 1537 | + one_occ _ = False
|
|
| 1526 | 1538 | |
| 1527 | 1539 | pre_inline_unconditionally = sePreInline env
|
| 1528 | 1540 | active = isActive (sePhase env)
|
| ... | ... | @@ -1530,38 +1542,6 @@ preInlineUnconditionally env top_lvl bndr rhs rhs_env |
| 1530 | 1542 | -- See Note [pre/postInlineUnconditionally in gentle mode]
|
| 1531 | 1543 | inline_prag = idInlinePragma bndr
|
| 1532 | 1544 | |
| 1533 | --- Be very careful before inlining inside a lambda, because (a) we must not
|
|
| 1534 | --- invalidate occurrence information, and (b) we want to avoid pushing a
|
|
| 1535 | --- single allocation (here) into multiple allocations (inside lambda).
|
|
| 1536 | --- Inlining a *function* with a single *saturated* call would be ok, mind you.
|
|
| 1537 | --- || (if is_cheap && not (canInlineInLam rhs) then pprTrace "preinline" (ppr bndr <+> ppr rhs) ok else ok)
|
|
| 1538 | --- where
|
|
| 1539 | --- is_cheap = exprIsCheap rhs
|
|
| 1540 | --- ok = is_cheap && int_cxt
|
|
| 1541 | - |
|
| 1542 | - -- int_cxt The context isn't totally boring
|
|
| 1543 | - -- E.g. let f = \ab.BIG in \y. map f xs
|
|
| 1544 | - -- Don't want to substitute for f, because then we allocate
|
|
| 1545 | - -- its closure every time the \y is called
|
|
| 1546 | - -- But: let f = \ab.BIG in \y. map (f y) xs
|
|
| 1547 | - -- Now we do want to substitute for f, even though it's not
|
|
| 1548 | - -- saturated, because we're going to allocate a closure for
|
|
| 1549 | - -- (f y) every time round the loop anyhow.
|
|
| 1550 | - |
|
| 1551 | - -- canInlineInLam => free vars of rhs are (Once in_lam) or Many,
|
|
| 1552 | - -- so substituting rhs inside a lambda doesn't change the occ info.
|
|
| 1553 | - -- Sadly, not quite the same as exprIsHNF.
|
|
| 1554 | - canInlineInLam (Lit _) = True
|
|
| 1555 | - canInlineInLam (Cast e _) = canInlineInLam e
|
|
| 1556 | - canInlineInLam (Lam b e) = isRuntimeVar b || canInlineInLam e
|
|
| 1557 | - canInlineInLam (Tick t e) = not (tickishIsCode t) && canInlineInLam e
|
|
| 1558 | - canInlineInLam (Var v) = case idOccInfo v of
|
|
| 1559 | - OneOcc { occ_in_lam = IsInsideLam } -> True
|
|
| 1560 | - ManyOccs {} -> True
|
|
| 1561 | - _ -> False
|
|
| 1562 | - canInlineInLam _ = False
|
|
| 1563 | - -- not ticks. Counting ticks cannot be duplicated, and non-counting
|
|
| 1564 | - -- ticks around a Lam will disappear anyway.
|
|
| 1565 | 1545 | |
| 1566 | 1546 | early_phase =
|
| 1567 | 1547 | case sePhase env of
|
| ... | ... | @@ -1593,6 +1573,39 @@ preInlineUnconditionally env top_lvl bndr rhs rhs_env |
| 1593 | 1573 | -- (Nor can we check for `exprIsExpandable rhs`, because that needs to look
|
| 1594 | 1574 | -- at the non-existent unfolding for the `I# 2#` which is also floated out.)
|
| 1595 | 1575 | |
| 1576 | +canInlineInLam :: CoreExpr -> Bool
|
|
| 1577 | +-- Be very careful before inlining inside a lambda, because (a) we must not
|
|
| 1578 | +-- invalidate occurrence information, and (b) we want to avoid pushing a
|
|
| 1579 | +-- single allocation (here) into multiple allocations (inside lambda).
|
|
| 1580 | +-- Inlining a *function* with a single *saturated* call would be ok, mind you.
|
|
| 1581 | +-- || (if is_cheap && not (canInlineInLam rhs) then pprTrace "preinline" (ppr bndr <+> ppr rhs) ok else ok)
|
|
| 1582 | +-- where
|
|
| 1583 | +-- is_cheap = exprIsCheap rhs
|
|
| 1584 | +-- ok = is_cheap && int_cxt
|
|
| 1585 | + -- int_cxt The context isn't totally boring
|
|
| 1586 | + -- E.g. let f = \ab.BIG in \y. map f xs
|
|
| 1587 | + -- Don't want to substitute for f, because then we allocate
|
|
| 1588 | + -- its closure every time the \y is called
|
|
| 1589 | + -- But: let f = \ab.BIG in \y. map (f y) xs
|
|
| 1590 | + -- Now we do want to substitute for f, even though it's not
|
|
| 1591 | + -- saturated, because we're going to allocate a closure for
|
|
| 1592 | + -- (f y) every time round the loop anyhow.
|
|
| 1593 | + |
|
| 1594 | + -- canInlineInLam => free vars of rhs are (Once in_lam) or Many,
|
|
| 1595 | + -- so substituting rhs inside a lambda doesn't change the occ info.
|
|
| 1596 | + -- Sadly, not quite the same as exprIsHNF.
|
|
| 1597 | +canInlineInLam (Lit _) = True
|
|
| 1598 | +canInlineInLam (Cast e _) = canInlineInLam e
|
|
| 1599 | +canInlineInLam (Lam b e) = isRuntimeVar b || canInlineInLam e
|
|
| 1600 | +canInlineInLam (Tick t e) = not (tickishIsCode t) && canInlineInLam e
|
|
| 1601 | +canInlineInLam (Var v) = case idOccInfo v of
|
|
| 1602 | + OneOcc { occ_in_lam = IsInsideLam } -> True
|
|
| 1603 | + ManyOccs {} -> True
|
|
| 1604 | + _ -> False
|
|
| 1605 | +canInlineInLam _ = False
|
|
| 1606 | + -- not ticks. Counting ticks cannot be duplicated, and non-counting
|
|
| 1607 | + -- ticks around a Lam will disappear anyway.
|
|
| 1608 | + |
|
| 1596 | 1609 | {-
|
| 1597 | 1610 | ************************************************************************
|
| 1598 | 1611 | * *
|
| ... | ... | @@ -1022,7 +1022,7 @@ instance NFData CoSel where |
| 1022 | 1022 | |
| 1023 | 1023 | instance Outputable MCoercion where
|
| 1024 | 1024 | ppr MRefl = text "MRefl"
|
| 1025 | - ppr (MCo co) = text "MCo" <+> ppr co
|
|
| 1025 | + ppr (MCo co) = text "MCo" <> braces (ppr co)
|
|
| 1026 | 1026 | |
| 1027 | 1027 | {- Note [Refl invariant]
|
| 1028 | 1028 | ~~~~~~~~~~~~~~~~~~~~~~~~
|