Simon Peyton Jones pushed to branch wip/T26615 at Glasgow Haskell Compiler / GHC
Commits:
-
a47e6e22
by Simon Peyton Jones at 2026-01-11T23:22:44+00:00
5 changed files:
- compiler/GHC/Core/Opt/SpecConstr.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Opt/WorkWrap.hs
- compiler/GHC/Core/Rules.hs
- testsuite/tests/simplCore/should_compile/spec-inline.stderr
Changes:
| ... | ... | @@ -1864,7 +1864,7 @@ specialise env bind_calls (RI { ri_fn = fn, ri_lam_bndrs = arg_bndrs |
| 1864 | 1864 | return (nullUsage, spec_info, [])
|
| 1865 | 1865 | |
| 1866 | 1866 | | not (isNeverActive (idInlineActivation fn))
|
| 1867 | - -- See Note [Transfer activation]
|
|
| 1867 | + -- See (SCRA1) in Note [SpecConstr: rule activation]
|
|
| 1868 | 1868 | -- Don't specialise OPAQUE things, see Note [OPAQUE pragma].
|
| 1869 | 1869 | -- Since OPAQUE things are always never-active (see
|
| 1870 | 1870 | -- GHC.Parser.PostProcess.mkOpaquePragma) this guard never fires for
|
| ... | ... | @@ -2075,7 +2075,7 @@ mkSeqs seqees res_ty rhs = |
| 2075 | 2075 | = rhs
|
| 2076 | 2076 | |
| 2077 | 2077 | specConstrRuleActivation :: InlinePragmaInfo -> ActivationGhc
|
| 2078 | --- See Note [SpecConstr rule activation]
|
|
| 2078 | +-- See Note [SpecConstr: rule activation]
|
|
| 2079 | 2079 | specConstrRuleActivation fn_prag
|
| 2080 | 2080 | = activeAfter $ nextPhase $ beginPhase $ inlinePragmaActivation fn_prag
|
| 2081 | 2081 | |
| ... | ... | @@ -2129,7 +2129,7 @@ The void argument must follow the foralls, lest the forall be |
| 2129 | 2129 | ill-kinded. See Note [Worker/wrapper needs to add void arg last] in
|
| 2130 | 2130 | GHC.Core.Opt.WorkWrap.Utils.
|
| 2131 | 2131 | |
| 2132 | -Note [SpecConstr rule activation]
|
|
| 2132 | +Note [SpecConstr: rule activation]
|
|
| 2133 | 2133 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 2134 | 2134 | When should the RULE generated by SpecConstr be activated?
|
| 2135 | 2135 | See the function `specConstrRuleActivation`.
|
| ... | ... | @@ -2163,15 +2163,13 @@ Goal 1: "SC:1" won't fire in f's unfolding; |
| 2163 | 2163 | see Note [What is active in the RHS of a RULE or unfolding?]
|
| 2164 | 2164 | |
| 2165 | 2165 | Goal 2: "SPEC:f" has the same activation as `f`;
|
| 2166 | - see Note [Auto-specialisation and RULES]). So "SPEC:f" will fire
|
|
| 2166 | + see Note [Specialise: rule activation]. So "SPEC:f" will fire
|
|
| 2167 | 2167 | before "SC:1"
|
| 2168 | 2168 | |
| 2169 | -Other points:
|
|
| 2170 | - |
|
| 2171 | -* c.f. Note [Auto-specialisation and RULES] in GHC.Core.Opt.Specialise.
|
|
| 2172 | -* his in turn means there is no point in specialising NOINLINE things,
|
|
| 2173 | -so we test for that.
|
|
| 2169 | +Wrinkles
|
|
| 2174 | 2170 | |
| 2171 | +(SCRA1) If `f` is NOINLINE we arguably don't want a specialisation at all.
|
|
| 2172 | + See (SRA1) in GHC.Core.Opt.Specialise. At least that's the choice for now.
|
|
| 2175 | 2173 | |
| 2176 | 2174 | Note [generaliseDictPats]
|
| 2177 | 2175 | ~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1588,7 +1588,7 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs |
| 1588 | 1588 | | notNull calls_for_me -- And there are some calls to specialise
|
| 1589 | 1589 | && not (isNeverActive (idInlineActivation fn))
|
| 1590 | 1590 | -- Don't specialise NOINLINE things
|
| 1591 | - -- See Note [Auto-specialisation and RULES]
|
|
| 1591 | + -- See (SRA1) in Note [Specialise: rule activation]
|
|
| 1592 | 1592 | --
|
| 1593 | 1593 | -- Don't specialise OPAQUE things, see Note [OPAQUE pragma].
|
| 1594 | 1594 | -- Since OPAQUE things are always never-active (see
|
| ... | ... | @@ -1619,7 +1619,7 @@ specCalls spec_imp env existing_rules calls_for_me fn rhs |
| 1619 | 1619 | fn_unf = realIdUnfolding fn -- Ignore loop-breaker-ness here
|
| 1620 | 1620 | fn_prag = idInlinePragma fn
|
| 1621 | 1621 | rule_act = inlinePragmaActivation fn_prag
|
| 1622 | - -- rule_act: see Note [Auto-specialisation and RULES]
|
|
| 1622 | + -- rule_act: see Note [Specialise: rule activation]
|
|
| 1623 | 1623 | is_active :: ActivationGhc -> Bool
|
| 1624 | 1624 | is_active = isActive (SimplPhaseRange (beginPhase rule_act) (endPhase rule_act))
|
| 1625 | 1625 | -- is_active: rule_act is the activation we are going to put in the new
|
| ... | ... | @@ -2361,8 +2361,8 @@ argument pattern. Wrinkles |
| 2361 | 2361 | (SC3) Annoyingly, we /also/ eliminate duplicates in `filterCalls`.
|
| 2362 | 2362 | See (MP3) in Note [Specialising polymorphic dictionaries]
|
| 2363 | 2363 | |
| 2364 | -Note [Auto-specialisation and RULES]
|
|
| 2365 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 2364 | +Note [Specialise: rule activation]
|
|
| 2365 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 2366 | 2366 | Consider:
|
| 2367 | 2367 | g :: Num a => a -> a
|
| 2368 | 2368 | g = ...
|
| ... | ... | @@ -2383,15 +2383,22 @@ also add |
| 2383 | 2383 | RULE f g_spec = 0
|
| 2384 | 2384 | |
| 2385 | 2385 | But that's a bit complicated. For now we lean on the programmer:
|
| 2386 | - * Set the activation of the RULE is the same as the activation of the Id,
|
|
| 2386 | + |
|
| 2387 | + * Make the activation of the RULE be the same as the activation of the Id,
|
|
| 2387 | 2388 | i.e. (idInlineActivation g)
|
| 2388 | 2389 | |
| 2389 | 2390 | So if `g` says {-# NOINLINE[2] g #-}, then the auto-spec rule will also not be
|
| 2390 | 2391 | active until phase 2. And that's what programmers should jolly well do anyway,
|
| 2391 | 2392 | even aside from specialisation, to ensure that `g` doesn't inline too early.
|
| 2392 | 2393 | |
| 2393 | -This in turn means that the RULE would never fire for a NOINLINE
|
|
| 2394 | -thing so not much point in generating a specialisation at all.
|
|
| 2394 | +Wrinkles
|
|
| 2395 | + |
|
| 2396 | +(SRA1) This in turn means that the RULE would never fire for a NOINLINE thing
|
|
| 2397 | + so not much point in generating a specialisation at all. This is a
|
|
| 2398 | + bit moot: it's not unreasonable to have a (NOINLINE) specialisation for a
|
|
| 2399 | + NOINLINE function. But currently we don't. And hence we don't create
|
|
| 2400 | + a specialisation for an OPAQUE function either (see Note [OPAQUE pragma]
|
|
| 2401 | + in Language.Haskell.Syntax.Binds.InlinePragma.
|
|
| 2395 | 2402 | |
| 2396 | 2403 | Note [Specialisation shape]
|
| 2397 | 2404 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -499,7 +499,7 @@ When should the wrapper inlining be active? |
| 499 | 499 | {-# SPECIALISE foo :: (Int,Int) -> Bool -> Int #-}
|
| 500 | 500 | {-# NOINLINE [n] foo #-}
|
| 501 | 501 | then specialisation will generate a SPEC rule active from Phase n.
|
| 502 | - See Note [Auto-specialisation and RULES] in GHC.Core.Opt.Specialise
|
|
| 502 | + See Note [Specialise: rule activation] in GHC.Core.Opt.Specialise
|
|
| 503 | 503 | This SPEC specialisation rule will compete with inlining, but we don't
|
| 504 | 504 | mind that, because if inlining succeeds, it should be better.
|
| 505 | 505 |
| ... | ... | @@ -231,7 +231,7 @@ mkSpecRule dflags this_mod is_auto inl_act herald fn bndrs args rhs |
| 231 | 231 | where
|
| 232 | 232 | rule = mkRule this_mod is_auto is_local
|
| 233 | 233 | rule_name
|
| 234 | - inl_act -- Note [Auto-specialisation and RULES]
|
|
| 234 | + inl_act -- Note [Specialise: rule activation]
|
|
| 235 | 235 | (idName fn)
|
| 236 | 236 | bndrs args rhs
|
| 237 | 237 |
| ... | ... | @@ -17,7 +17,7 @@ Roman.foo3 |
| 17 | 17 | |
| 18 | 18 | Rec {
|
| 19 | 19 | -- RHS size: {terms: 40, types: 5, coercions: 0, joins: 0/0}
|
| 20 | -Roman.foo_$s$wgo [Occ=LoopBreaker]
|
|
| 20 | +Roman.foo_$s$wgo [InlPrag=[2], Occ=LoopBreaker]
|
|
| 21 | 21 | :: GHC.Internal.Prim.Int#
|
| 22 | 22 | -> GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int#
|
| 23 | 23 | [GblId, Arity=2, Str=<A><L>, Unf=OtherCon []]
|
| ... | ... | @@ -141,7 +141,7 @@ foo |
| 141 | 141 | |
| 142 | 142 | |
| 143 | 143 | ------ Local rules for imported ids --------
|
| 144 | -"SC:$wgo0" [2]
|
|
| 144 | +"SC:$wgo0" [1]
|
|
| 145 | 145 | forall (sc :: GHC.Internal.Prim.Int#)
|
| 146 | 146 | (sc1 :: GHC.Internal.Prim.Int#).
|
| 147 | 147 | Roman.$wgo (GHC.Internal.Maybe.Just
|