Magnus pushed to branch wip/mangoiv/ghc-9.12-bp at Glasgow Haskell Compiler / GHC
Commits:
-
8725aa42
by mangoiv at 2026-05-29T13:33:44+02:00
5 changed files:
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- + testsuite/tests/simplCore/should_compile/T27261.hs
- + testsuite/tests/simplCore/should_compile/T27261_aux.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
| ... | ... | @@ -24,7 +24,7 @@ import GHC.Core.Opt.Simplify.Env |
| 24 | 24 | import GHC.Core.Opt.Simplify.Inline
|
| 25 | 25 | import GHC.Core.Opt.Simplify.Utils
|
| 26 | 26 | import GHC.Core.Opt.OccurAnal ( occurAnalyseExpr, zapLambdaBndrs, scrutOkForBinderSwap, BinderSwapDecision (..) )
|
| 27 | -import GHC.Core.Make ( FloatBind, mkImpossibleExpr, castBottomExpr )
|
|
| 27 | +import GHC.Core.Make ( FloatBind, mkImpossibleExpr )
|
|
| 28 | 28 | import qualified GHC.Core.Make
|
| 29 | 29 | import GHC.Core.Coercion hiding ( substCo, substCoVar )
|
| 30 | 30 | import GHC.Core.Reduction
|
| ... | ... | @@ -2293,24 +2293,14 @@ rebuildCall :: SimplEnv -> ArgInfo -> SimplCont |
| 2293 | 2293 | |
| 2294 | 2294 | ---------- Bottoming applications --------------
|
| 2295 | 2295 | rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args, ai_dmds = [] }) cont
|
| 2296 | - -- When we run out of strictness args, it means
|
|
| 2297 | - -- that the call is definitely bottom; see GHC.Core.Opt.Simplify.Utils.mkArgInfo
|
|
| 2298 | - -- Then we want to discard the entire strict continuation. E.g.
|
|
| 2299 | - -- * case (error "hello") of { ... }
|
|
| 2300 | - -- * (error "Hello") arg
|
|
| 2301 | - -- * f (error "Hello") where f is strict
|
|
| 2302 | - -- etc
|
|
| 2303 | - -- Then, especially in the first of these cases, we'd like to discard
|
|
| 2304 | - -- the continuation, leaving just the bottoming expression. But the
|
|
| 2305 | - -- type might not be right, so we may have to add a coerce.
|
|
| 2306 | - | not (contIsTrivial cont) -- Only do this if there is a non-trivial
|
|
| 2307 | - -- continuation to discard, else we do it
|
|
| 2308 | - -- again and again!
|
|
| 2309 | - = seqType cont_ty `seq` -- See Note [Avoiding space leaks in OutType]
|
|
| 2310 | - return (emptyFloats env, castBottomExpr res cont_ty)
|
|
| 2311 | - where
|
|
| 2312 | - res = argInfoExpr fun rev_args
|
|
| 2313 | - cont_ty = contResultType cont
|
|
| 2296 | + -- When we run out of demands, it means that the call is definitely bottom.
|
|
| 2297 | + -- See (TC2) in Note [Trimming the continuation for bottoming functions]
|
|
| 2298 | + = rebuild env (argInfoExpr fun rev_args) (mkBottomCont env cont)
|
|
| 2299 | + -- NOTE(mangoiv): the env passed to mkBottomCont is only relevant for its static part
|
|
| 2300 | + -- and should not be looked at whatsoever, which is why it should be fine to pass it
|
|
| 2301 | + -- this way. The reason why we deviate from the original patch is that it was done
|
|
| 2302 | + -- after a significant refactor we cannot backport.
|
|
| 2303 | + -- The original patch should be included in `master` as 4a645683ee0bd4421a88cd6ec49b40c6046b041d
|
|
| 2314 | 2304 | |
| 2315 | 2305 | ---------- Try inlining, if ai_rewrite = TryInlining --------
|
| 2316 | 2306 | -- In the TryInlining case we try inlining immediately, before simplifying
|
| ... | ... | @@ -3813,6 +3803,41 @@ When we have |
| 3813 | 3803 | then we can just duplicate those alts because the A and C cases
|
| 3814 | 3804 | will disappear immediately. This is more direct than creating
|
| 3815 | 3805 | join points and inlining them away. See #4930.
|
| 3806 | + |
|
| 3807 | +Note [Trimming the continuation for bottoming functions]
|
|
| 3808 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 3809 | +Suppose
|
|
| 3810 | + f :: Int -> Int -> Int
|
|
| 3811 | + f x = error "urk"
|
|
| 3812 | + |
|
| 3813 | + foo = f 3 4
|
|
| 3814 | + |
|
| 3815 | +f's demand signature say "after one arg I return bottom". We can drop
|
|
| 3816 | +the remaining arguments, thus
|
|
| 3817 | + |
|
| 3818 | + foo = case f 3 of {}
|
|
| 3819 | + |
|
| 3820 | +This trimming can also be done with other continuations:
|
|
| 3821 | + * case (error "hello") of { ... }
|
|
| 3822 | + * f (error "Hello") where f is strict
|
|
| 3823 | + etc
|
|
| 3824 | + |
|
| 3825 | +We implement the trimming in three parts:
|
|
| 3826 | + |
|
| 3827 | +(TC1) In `mkArgInfo`, for a bottoming function, we make a list of `RemainingArgDmds`
|
|
| 3828 | + with a finite list of elements (in the example above, just one).
|
|
| 3829 | + |
|
| 3830 | + For comparison, note that, for non-bottoming functions, the `RemainingArgDmds`
|
|
| 3831 | + always finishes with an infinite list of `topDmd`.
|
|
| 3832 | + |
|
| 3833 | +(TC2) In `rebuildCall`, when we run out of `RemainingArgDmds` we discard the
|
|
| 3834 | + remaining continuation.
|
|
| 3835 | + |
|
| 3836 | + After discarding the continuation, the types might not match, in which case
|
|
| 3837 | + we leave behind a (case <hole> of {}) wrapper. See the call to `mkBottomCont`.
|
|
| 3838 | + |
|
| 3839 | +(TC3) In `mkDupableContWithDmds`, we similarly discard the continuation when
|
|
| 3840 | + we run out of `RemainingArgDmds`.
|
|
| 3816 | 3841 | -}
|
| 3817 | 3842 | |
| 3818 | 3843 | --------------------
|
| ... | ... | @@ -3931,7 +3956,7 @@ mkDupableContWithDmds env dmds |
| 3931 | 3956 | ; return (floats, ApplyToTy { sc_cont = cont'
|
| 3932 | 3957 | , sc_arg_ty = arg_ty, sc_hole_ty = hole_ty }) }
|
| 3933 | 3958 | |
| 3934 | -mkDupableContWithDmds env dmds
|
|
| 3959 | +mkDupableContWithDmds env (dmd : cont_dmds)
|
|
| 3935 | 3960 | (ApplyToVal { sc_arg = arg, sc_dup = dup, sc_env = se
|
| 3936 | 3961 | , sc_cont = cont, sc_hole_ty = hole_ty })
|
| 3937 | 3962 | = -- e.g. [...hole...] (...arg...)
|
| ... | ... | @@ -3939,8 +3964,7 @@ mkDupableContWithDmds env dmds |
| 3939 | 3964 | -- let a = ...arg...
|
| 3940 | 3965 | -- in [...hole...] a
|
| 3941 | 3966 | -- NB: sc_dup /= OkToDup; that is caught earlier by contIsDupable
|
| 3942 | - do { let (dmd:cont_dmds) = dmds -- Never fails
|
|
| 3943 | - ; (floats1, cont') <- mkDupableContWithDmds env cont_dmds cont
|
|
| 3967 | + do { (floats1, cont') <- mkDupableContWithDmds env cont_dmds cont
|
|
| 3944 | 3968 | ; let env' = env `setInScopeFromF` floats1
|
| 3945 | 3969 | ; (_, se', arg') <- simplLazyArg env' dup hole_ty Nothing se arg
|
| 3946 | 3970 | ; (let_floats2, arg'') <- makeTrivial env NotTopLevel dmd (fsLit "karg") arg'
|
| ... | ... | @@ -3954,6 +3978,12 @@ mkDupableContWithDmds env dmds |
| 3954 | 3978 | -- See Note [StaticEnv invariant] in GHC.Core.Opt.Simplify.Utils
|
| 3955 | 3979 | , sc_dup = OkToDup, sc_cont = cont'
|
| 3956 | 3980 | , sc_hole_ty = hole_ty }) }
|
| 3981 | +mkDupableContWithDmds env dmds cont
|
|
| 3982 | + -- No more demands => function is definitely bottom
|
|
| 3983 | + -- => simply trim the continuation
|
|
| 3984 | + -- c.f. the null-demands case in `rebuildCall`
|
|
| 3985 | + -- See (TC3) in Note [Trimming the continuation for bottoming functions]
|
|
| 3986 | + | [] <- dmds = return (emptyFloats env, mkBottomCont env cont)
|
|
| 3957 | 3987 | |
| 3958 | 3988 | mkDupableContWithDmds env _
|
| 3959 | 3989 | (Select { sc_bndr = case_bndr, sc_alts = alts, sc_env = se, sc_cont = cont })
|
| ... | ... | @@ -24,7 +24,7 @@ module GHC.Core.Opt.Simplify.Utils ( |
| 24 | 24 | SimplCont(..), DupFlag(..), FromWhat(..), StaticEnv,
|
| 25 | 25 | isSimplified, contIsStop,
|
| 26 | 26 | contIsDupable, contResultType, contHoleType, contHoleScaling,
|
| 27 | - contIsTrivial, contArgs, contIsRhs,
|
|
| 27 | + contIsTrivial, contArgs, contIsRhs, mkBottomCont,
|
|
| 28 | 28 | countArgs,
|
| 29 | 29 | mkBoringStop, mkRhsStop, mkLazyArgStop,
|
| 30 | 30 | interestingCallContext,
|
| ... | ... | @@ -87,6 +87,8 @@ import Control.Monad ( guard, when ) |
| 87 | 87 | import Data.List ( sortBy )
|
| 88 | 88 | import Data.Maybe
|
| 89 | 89 | import Data.Graph
|
| 90 | +import GHC.Core.TyCo.Compare (eqTypeIgnoringMultiplicity)
|
|
| 91 | +import GHC.Core.Make (mkWildValBinder)
|
|
| 90 | 92 | |
| 91 | 93 | {- *********************************************************************
|
| 92 | 94 | * *
|
| ... | ... | @@ -505,6 +507,20 @@ contIsTrivial (ApplyToTy { sc_cont = k }) = contIsTrivial |
| 505 | 507 | contIsTrivial (CastIt { sc_cont = k }) = contIsTrivial k
|
| 506 | 508 | contIsTrivial _ = False
|
| 507 | 509 | |
| 510 | +-------------------
|
|
| 511 | +contStop :: SimplCont -> SimplCont
|
|
| 512 | +-- ^ Get the 'Stop' at the tail of the continuation
|
|
| 513 | +--
|
|
| 514 | +-- Always returns a continuation of form @(Stop ...)@.
|
|
| 515 | +contStop stop@(Stop {}) = stop
|
|
| 516 | +contStop (CastIt { sc_cont = k }) = contStop k
|
|
| 517 | +contStop (StrictBind { sc_cont = k }) = contStop k
|
|
| 518 | +contStop (StrictArg { sc_cont = k }) = contStop k
|
|
| 519 | +contStop (Select { sc_cont = k }) = contStop k
|
|
| 520 | +contStop (ApplyToTy { sc_cont = k }) = contStop k
|
|
| 521 | +contStop (ApplyToVal { sc_cont = k }) = contStop k
|
|
| 522 | +contStop (TickIt _ k) = contStop k
|
|
| 523 | + |
|
| 508 | 524 | -------------------
|
| 509 | 525 | contResultType :: SimplCont -> OutType
|
| 510 | 526 | contResultType (Stop ty _ _) = ty
|
| ... | ... | @@ -623,6 +639,37 @@ contEvalContext k = case k of |
| 623 | 639 | -- Perhaps reconstruct the demand on the scrutinee by looking at field
|
| 624 | 640 | -- and case binder dmds, see addCaseBndrDmd. No priority right now.
|
| 625 | 641 | |
| 642 | +-------------------
|
|
| 643 | +mkBottomCont ::StaticEnv -> SimplCont -> SimplCont
|
|
| 644 | +-- ^ Given a continuation `cont`, return a `cont` /of the same type/,
|
|
| 645 | +-- looking like @(case \<hole\> of {})@.
|
|
| 646 | +--
|
|
| 647 | +-- This is used when we are going to fill in the @<hole>@ with bottom.
|
|
| 648 | +-- See (TC2,3) in Note [Trimming the continuation for bottoming functions]
|
|
| 649 | +--
|
|
| 650 | +-- Don't bother to trim, making a @case <hole> of {}@, if we have only
|
|
| 651 | +-- an essentially-trivial continuation; e.g. @(<hole> \@ty |> co)@.
|
|
| 652 | +mkBottomCont se cont = go cont
|
|
| 653 | + where
|
|
| 654 | + go k@(Stop {}) = k
|
|
| 655 | + go (TickIt t k') = TickIt t (go k')
|
|
| 656 | + go k@(CastIt { sc_cont = k' }) = k { sc_cont = go k' }
|
|
| 657 | + go k@(ApplyToTy { sc_cont = k' }) = k { sc_cont = go k' }
|
|
| 658 | + go k@(Select { sc_alts = [], sc_cont = Stop {} }) = k -- Optimisation only
|
|
| 659 | + go k | Stop res_ty _ _ <- stop_cont
|
|
| 660 | + , hole_ty `eqTypeIgnoringMultiplicity` res_ty
|
|
| 661 | + = stop_cont
|
|
| 662 | + | otherwise
|
|
| 663 | + = Select { sc_alts = []
|
|
| 664 | + , sc_bndr = mkWildValBinder OneTy hole_ty
|
|
| 665 | + , sc_dup = OkToDup
|
|
| 666 | + , sc_env = se
|
|
| 667 | + , sc_cont = stop_cont }
|
|
| 668 | + where
|
|
| 669 | + hole_ty = contHoleType k
|
|
| 670 | + stop_cont = contStop k
|
|
| 671 | + |
|
| 672 | + |
|
| 626 | 673 | -------------------
|
| 627 | 674 | mkArgInfo :: SimplEnv -> RuleEnv -> Id -> SimplCont -> ArgInfo
|
| 628 | 675 |
| 1 | +{-# OPTIONS_GHC -fno-full-laziness #-}
|
|
| 2 | + |
|
| 3 | +module T27261 (foo) where
|
|
| 4 | + |
|
| 5 | +import T27261_aux (myError)
|
|
| 6 | + |
|
| 7 | +foo :: [String] -> (() -> Int) -> Int
|
|
| 8 | +foo cs =
|
|
| 9 | + \ k -> ( case bar of
|
|
| 10 | + Just str -> let cs2 = case cs of { [] -> cs; _ -> "stack entry" : cs }
|
|
| 11 | + in myError cs2 str
|
|
| 12 | + Nothing -> \ c -> c () )
|
|
| 13 | + ( \ _ -> k () )
|
|
| 14 | + |
|
| 15 | +bar :: Maybe String
|
|
| 16 | +bar = Nothing
|
|
| 17 | +{-# NOINLINE bar #-} |
| 1 | +{-# LANGUAGE BangPatterns #-}
|
|
| 2 | + |
|
| 3 | +module T27261_aux (myError) where
|
|
| 4 | + |
|
| 5 | +myError :: [String] -> String -> a
|
|
| 6 | +myError !_ _ = undefined
|
|
| 7 | +{-# NOINLINE myError #-} |
| ... | ... | @@ -541,3 +541,4 @@ test('T25883d', [extra_files(['T25883d_import.hs'])], multimod_compile_filter, [ |
| 541 | 541 | test('T26681', normal, compile, ['-O'])
|
| 542 | 542 | test('T26903', [grep_errmsg(r'reverse')], compile, ['-O -dno-typeable-binds -ddump-simpl -dsuppress-uniques -dsuppress-all'])
|
| 543 | 543 | test('T26682', normal, multimod_compile, ['T26682', '-O -v0'])
|
| 544 | +test('T27261', [extra_files(['T27261_aux.hs'])], multimod_compile, ['T27261', '-v0 -O']) |