Simon Peyton Jones pushed to branch wip/T26989 at Glasgow Haskell Compiler / GHC
Commits:
-
9bbd56e8
by Simon Peyton Jones at 2026-04-27T23:54:56+01:00
4 changed files:
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
Changes:
| ... | ... | @@ -426,7 +426,8 @@ decomposeFunCo :: HasDebugCallStack |
| 426 | 426 | |
| 427 | 427 | decomposeFunCo (FunCo { fco_mult = w, fco_arg = co1, fco_res = co2 })
|
| 428 | 428 | = (w, co1, co2)
|
| 429 | - -- Short-circuits the calls to mkSelCo
|
|
| 429 | + -- Fast path that short-circuits the calls to mkSelCo,
|
|
| 430 | + -- even though they would give the exact same answers
|
|
| 430 | 431 | |
| 431 | 432 | decomposeFunCo co
|
| 432 | 433 | = assertPpr all_ok (ppr co) $
|
| ... | ... | @@ -2691,10 +2691,11 @@ same fix. |
| 2691 | 2691 | |
| 2692 | 2692 | -- | `tryEtaReduce [x,y,z] e sd` returns `Just e'` if `\x y z -> e` is evaluated
|
| 2693 | 2693 | -- according to `sd` and can soundly and gainfully be eta-reduced to `e'`.
|
| 2694 | --- See Note [Eta reduction soundness]
|
|
| 2695 | --- and Note [Eta reduction makes sense] when that is the case.
|
|
| 2696 | 2694 | tryEtaReduce :: UnVarSet -> [Var] -> CoreExpr -> SubDemand -> Maybe CoreExpr
|
| 2697 | 2695 | -- Return an expression equal to (\bndrs. body)
|
| 2696 | +-- See Note [Eta reduction soundness]
|
|
| 2697 | +-- and Note [Eta reduction makes sense] when that is the case.
|
|
| 2698 | +-- and Note [Eta reduction based on evaluation context] for the `eval_sd` arg
|
|
| 2698 | 2699 | tryEtaReduce rec_ids bndrs body eval_sd
|
| 2699 | 2700 | = go (reverse bndrs) body (mkRepReflCo (exprType body))
|
| 2700 | 2701 | where
|
| ... | ... | @@ -1729,10 +1729,15 @@ optOutCoercion env co already_optimised |
| 1729 | 1729 | opts = seOptCoercionOpts env
|
| 1730 | 1730 | |
| 1731 | 1731 | addCastMCo :: MOutCoercion -> SimplCont -> SimplCont
|
| 1732 | --- Simpler version of `pushCast` when optionally want to add a cast to the top
|
|
| 1732 | +-- Simpler, non-monadic version of pushCastMCo when we are certain that
|
|
| 1733 | +-- the cast should be at the top; i.e. cont is Stop or StrictArg
|
|
| 1733 | 1734 | addCastMCo MRefl cont = cont
|
| 1734 | 1735 | addCastMCo (MCo co) cont = CastIt { sc_co = co, sc_opt = False, sc_cont = cont }
|
| 1735 | 1736 | |
| 1737 | +pushCastMCo :: SimplEnv -> MOutCoercion -> SimplCont -> SimplM SimplCont
|
|
| 1738 | +pushCastMCo _env MRefl cont = return cont
|
|
| 1739 | +pushCastMCo env (MCo co) cont = pushCast env co cont
|
|
| 1740 | + |
|
| 1736 | 1741 | pushCast :: SimplEnv -> OutCoercion -> SimplCont -> SimplM SimplCont
|
| 1737 | 1742 | pushCast env co cont
|
| 1738 | 1743 | = go co True cont
|
| ... | ... | @@ -1753,7 +1758,7 @@ pushCast env co cont |
| 1753 | 1758 | -- NB! As the cast goes past, the
|
| 1754 | 1759 | -- type of the hole changes (#16312)
|
| 1755 | 1760 | |
| 1756 | - -- (f |> co) e ===> (f (e |> co1)) |> co2
|
|
| 1761 | + -- (f |> co) arg ===> (f (arg |> co1)) |> co2
|
|
| 1757 | 1762 | -- where co :: (s1->s2) ~ (t1->t2)
|
| 1758 | 1763 | -- co1 :: t1 ~ s1
|
| 1759 | 1764 | -- co2 :: s2 ~ t2
|
| ... | ... | @@ -1763,12 +1768,14 @@ pushCast env co cont |
| 1763 | 1768 | = -- pushCoValArg duplicates the coercion, so optimise first
|
| 1764 | 1769 | go (optOutCoercion (zapSubstEnv env) co co_is_opt) True cont
|
| 1765 | 1770 | |
| 1771 | +-- ToDo: return coercionLKind. And similarly pushCoTyArg
|
|
| 1772 | + |
|
| 1766 | 1773 | | Just (m_co1, m_co2) <- pushCoValArg co
|
| 1767 | 1774 | = {-#SCC "addCoerce-pushCoValArg" #-}
|
| 1768 | 1775 | do { tail' <- go_mco m_co2 co_is_opt tail
|
| 1769 | 1776 | ; return (ApplyToVal { sc_arg = arg
|
| 1770 | 1777 | , sc_env = arg_se
|
| 1771 | - , sc_cast = m_co1 `mkTransMCo` arg_mco
|
|
| 1778 | + , sc_cast = arg_mco `mkTransMCo` m_co1
|
|
| 1772 | 1779 | , sc_cont = tail'
|
| 1773 | 1780 | , sc_hole_ty = coercionLKind co }) }
|
| 1774 | 1781 | |
| ... | ... | @@ -1778,6 +1785,7 @@ pushCast env co cont |
| 1778 | 1785 | -- See Note [Optimising reflexivity]
|
| 1779 | 1786 | | otherwise = return (CastIt { sc_co = co, sc_opt = co_is_opt, sc_cont = cont })
|
| 1780 | 1787 | |
| 1788 | +-- ToDo: pushCast Refl (ApplylToVal arg1 (ApplyToVal arg2 ...)) will do lots of unnecessary work.
|
|
| 1781 | 1789 | |
| 1782 | 1790 | -- If the first parameter is MRefl, then simplifying revealed a
|
| 1783 | 1791 | -- reflexive coercion. Omit.
|
| ... | ... | @@ -2295,7 +2303,8 @@ simplInId env var cont |
| 2295 | 2303 | | otherwise
|
| 2296 | 2304 | = case substId env var of
|
| 2297 | 2305 | ContEx se e mco
|
| 2298 | - -> simplExprF (se `setInScopeFromE` env) e (addCastMCo mco cont)
|
|
| 2306 | + -> do { cont' <- pushCastMCo env mco cont
|
|
| 2307 | + ; simplExprF (se `setInScopeFromE` env) e cont' }
|
|
| 2299 | 2308 | -- Don't trimJoinCont; haven't already simplified e,
|
| 2300 | 2309 | -- so the cont is not embodied in e
|
| 2301 | 2310 | |
| ... | ... | @@ -2393,10 +2402,12 @@ simplOutId env fun cont |
| 2393 | 2402 | _ -> do { s' <- newId (fsLit "s") ManyTy realWorldStatePrimTy
|
| 2394 | 2403 | ; let (m,_,_) = splitFunTy fun_ty
|
| 2395 | 2404 | env' = arg_env `addNewInScopeIds` [s']
|
| 2396 | - cont' = addCastMCo arg_mco $
|
|
| 2397 | - ApplyToVal { sc_arg = Var s', sc_cast = MRefl
|
|
| 2398 | - , sc_env = Simplified OkDup, sc_cont = inner_cont
|
|
| 2399 | - , sc_hole_ty = mkVisFunTy m realWorldStatePrimTy new_runrw_res_ty }
|
|
| 2405 | + hole_ty = mkVisFunTy m realWorldStatePrimTy new_runrw_res_ty
|
|
| 2406 | + ; cont' <- pushCastMCo env' arg_mco $
|
|
| 2407 | + ApplyToVal { sc_arg = Var s', sc_cast = MRefl
|
|
| 2408 | + , sc_env = Simplified OkDup
|
|
| 2409 | + , sc_cont = inner_cont
|
|
| 2410 | + , sc_hole_ty = hole_ty }
|
|
| 2400 | 2411 | -- cont' applies to s', then K
|
| 2401 | 2412 | ; body' <- simplExprC env' arg cont'
|
| 2402 | 2413 | ; return (Lam s' body') }
|
| ... | ... | @@ -620,26 +620,33 @@ dropContArgs n cont = pprPanic "dropContArgs" (ppr n $$ ppr cont) |
| 620 | 620 | -- For example, when simplifying the argument `e` in `f e` and `f` has the
|
| 621 | 621 | -- demand signature `<MP(S,A)>`, this function will give you back `P(S,A)` when
|
| 622 | 622 | -- simplifying `e`.
|
| 623 | ---
|
|
| 624 | --- PRECONDITION: Don't call with 'ApplyToVal'. We haven't thoroughly thought
|
|
| 625 | --- about what to do then and no call sites so far seem to care.
|
|
| 626 | -contEvalContext :: SimplCont -> SubDemand
|
|
| 627 | -contEvalContext k = case k of
|
|
| 628 | - Stop _ _ sd -> sd
|
|
| 629 | - TickIt _ k -> contEvalContext k
|
|
| 630 | - CastIt { sc_cont = k } -> contEvalContext k
|
|
| 631 | - ApplyToTy{ sc_cont = k } -> contEvalContext k
|
|
| 632 | - -- ApplyToVal{sc_cont=k} -> mkCalledOnceDmd $ contEvalContext k
|
|
| 623 | +contEvalContext :: [Var] -> SimplCont -> SubDemand
|
|
| 624 | +contEvalContext bndrs cont = go cont
|
|
| 625 | + where
|
|
| 626 | + go (Stop _ _ sd) = sd
|
|
| 627 | + go (TickIt _ k) = go k
|
|
| 628 | + go (CastIt { sc_cont = k }) = go k
|
|
| 629 | + go (ApplyToTy{ sc_cont = k }) = go k
|
|
| 630 | + |
|
| 631 | + -- The ApplyToVal case can actually happen, if we have
|
|
| 632 | + -- (CastIt co (ApplyToVal ..))
|
|
| 633 | + -- Possible code:
|
|
| 634 | + -- go (ApplyToVal{sc_cont=k}) = mkCalledOnceDmd $ contEvalContext k
|
|
| 633 | 635 | -- Not 100% sure that's correct, . Here's an example:
|
| 634 | 636 | -- f (e x) and f :: <SC(S,C(1,L))>
|
| 635 | 637 | -- then what is the evaluation context of 'e' when we simplify it? E.g.,
|
| 636 | 638 | -- simpl e (ApplyToVal x $ Stop "C(S,C(1,L))")
|
| 637 | 639 | -- then it *should* be "C(1,C(S,C(1,L))", so perhaps correct after all.
|
| 638 | - -- But for now we just panic:
|
|
| 639 | - ApplyToVal{} -> pprPanic "contEvalContext" (ppr k)
|
|
| 640 | - StrictArg{sc_fun=fun_info} -> subDemandIfEvaluated (Partial.head (ai_dmds fun_info))
|
|
| 641 | - StrictBind{sc_bndr=bndr} -> subDemandIfEvaluated (idDemandInfo bndr)
|
|
| 642 | - Select{} -> topSubDmd
|
|
| 640 | + -- But for now we just return topDmd.
|
|
| 641 | + go (ApplyToVal{ sc_arg = arg }) = warnPprTrace True "contEvalContext"
|
|
| 642 | + (vcat [ text "arg:" <+> ppr arg
|
|
| 643 | + , text "bndrs:" <+> ppr bndrs
|
|
| 644 | + , text "cont:" <+> ppr cont ])
|
|
| 645 | + topSubDmd
|
|
| 646 | + |
|
| 647 | + go (StrictArg{sc_fun=fun_info}) = subDemandIfEvaluated (Partial.head (ai_dmds fun_info))
|
|
| 648 | + go (StrictBind{sc_bndr=bndr}) = subDemandIfEvaluated (idDemandInfo bndr)
|
|
| 649 | + go (Select{}) = topSubDmd
|
|
| 643 | 650 | -- Perhaps reconstruct the demand on the scrutinee by looking at field
|
| 644 | 651 | -- and case binder dmds, see addCaseBndrDmd. No priority right now.
|
| 645 | 652 | |
| ... | ... | @@ -1957,9 +1964,7 @@ rebuildLam env bndrs@(bndr:_) body cont |
| 1957 | 1964 | mb_rhs = contIsRhs cont
|
| 1958 | 1965 | |
| 1959 | 1966 | -- See Note [Eta reduction based on evaluation context]
|
| 1960 | - eval_sd = contEvalContext cont
|
|
| 1961 | - -- NB: cont is never ApplyToVal, because beta-reduction would
|
|
| 1962 | - -- have happened. So contEvalContext can panic on ApplyToVal.
|
|
| 1967 | + eval_sd = contEvalContext bndrs cont
|
|
| 1963 | 1968 | |
| 1964 | 1969 | try_eta :: [OutBndr] -> OutExpr -> SimplM OutExpr
|
| 1965 | 1970 | try_eta bndrs body
|