Simon Peyton Jones pushed to branch wip/T27737 at Glasgow Haskell Compiler / GHC
Commits:
-
a9fdc56f
by Simon Peyton Jones at 2026-10-09T17:40:35+01:00
6 changed files:
- compiler/GHC/Core.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- testsuite/tests/dmdanal/should_compile/T20510.stderr
- testsuite/tests/show-bytecode/show-bytecode-hpc.stdout
Changes:
| ... | ... | @@ -1720,10 +1720,19 @@ isEmptyFloatBinds = isNilOL |
| 1720 | 1720 | |
| 1721 | 1721 | data FloatBind
|
| 1722 | 1722 | = FloatLet CoreBind
|
| 1723 | + -- let(rec) x = e
|
|
| 1724 | + -- Invariant: satisfies the let-can-float invariant
|
|
| 1725 | + |
|
| 1723 | 1726 | | FloatCase CoreExpr CoreBndr AltCon [CoreBndr]
|
| 1724 | 1727 | -- case e of y { C ys -> ... }
|
| 1725 | 1728 | -- See Note [Floating single-alternative cases] in GHC.Core.Opt.SetLevels
|
| 1729 | + |
|
| 1726 | 1730 | | FloatTick CoreTickish
|
| 1731 | + -- tick<t> ...
|
|
| 1732 | + -- Invariant: the tick is always soft-scoped (tickishHasSoftScope holds)
|
|
| 1733 | + -- Why? We are floating these FloatBinds outwards, bringing more code under
|
|
| 1734 | + -- the bindigns; that is only OK for soft-scoped ticks.
|
|
| 1735 | + -- See Note [Scoping ticks and counting ticks] in GHC.Types.Tickish
|
|
| 1727 | 1736 | |
| 1728 | 1737 | floatsBinders :: FloatBinds -> [Var]
|
| 1729 | 1738 | floatsBinders fs = foldr ((++) . floatBinders) [] fs
|
| ... | ... | @@ -38,7 +38,7 @@ module GHC.Core.Opt.Simplify.Env ( |
| 38 | 38 | |
| 39 | 39 | -- * Floats
|
| 40 | 40 | SimplFloats(..), emptyFloats, isEmptyFloats, mkRecFloats,
|
| 41 | - mkFloatBind, addLetFloats, addJoinFloats, addFloats,
|
|
| 41 | + mkFloatBind, addLetFloats, addJoinFloats, addFloats, addFloatBindsF,
|
|
| 42 | 42 | extendFloats, wrapFloats,
|
| 43 | 43 | isEmptyJoinFloats, isEmptyLetFloats,
|
| 44 | 44 | doFloatFromRhs, getTopFloatBinds,
|
| ... | ... | @@ -79,6 +79,7 @@ import GHC.Types.Var.Set |
| 79 | 79 | import GHC.Types.Id as Id
|
| 80 | 80 | import GHC.Types.InlinePragma ( ActivationGhc, CompilerPhase, isActiveInPhase )
|
| 81 | 81 | import GHC.Types.Basic
|
| 82 | +import GHC.Types.Tickish ( CoreTickish, tickishCounts, tickishHasSoftScope )
|
|
| 82 | 83 | import GHC.Types.Unique.FM ( pprUniqFM )
|
| 83 | 84 | |
| 84 | 85 | import GHC.Data.OrdList
|
| ... | ... | @@ -745,45 +746,56 @@ setSubstEnv env tvs cvs ids = env { seTvSubst = tvs, seCvSubst = cvs, seIdSubst |
| 745 | 746 | |
| 746 | 747 | Note [LetFloats]
|
| 747 | 748 | ~~~~~~~~~~~~~~~~
|
| 748 | -The LetFloats is a bunch of bindings, classified by a FloatFlag.
|
|
| 749 | +The LetFloats is a bunch of FloatBinds, collectively classified by a FloatFlag.
|
|
| 749 | 750 | |
| 750 | -The `FloatFlag` contains summary information about the bindings, see the data
|
|
| 751 | -type declaration of `FloatFlag`
|
|
| 751 | +The `FloatFlag` contains summary information about the bindings: see the data
|
|
| 752 | +type declaration of `FloatFlag`. A FloatBind can take one of three forms:
|
|
| 753 | +FloatLet, FloatCase, and FloatTick. We discuss the FloatFlag for each form.
|
|
| 752 | 754 | |
| 755 | +Note [FloatFlag for FloatLet] -- see `getFF_Let`
|
|
| 756 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 753 | 757 | Examples
|
| 754 | 758 | |
| 755 | - NonRec x (y:ys) FltLifted
|
|
| 756 | - Rec [(x,rhs)] FltLifted
|
|
| 757 | - |
|
| 758 | - NonRec x* (p:q) FltOKSpec -- RHS is WHNF. Question: why not FltLifted?
|
|
| 759 | - NonRec x# (y +# 3) FltOkSpec -- Unboxed, but ok-for-spec'n
|
|
| 760 | - |
|
| 761 | - NonRec x* (f y) FltCareful -- Strict binding; might fail or diverge
|
|
| 762 | - NonRec x# (a /# b) FltCareful -- Might fail; does not satisfy let-can-float invariant
|
|
| 763 | - NonRec x# (f y) FltCareful -- Might diverge; does not satisfy let-can-float invariant
|
|
| 764 | - |
|
| 765 | -A binding that does not satisfy the let-can-float invariant (the last two
|
|
| 766 | -examples above) is represented by a FloatCase, not a FloatLet:
|
|
| 767 | - FloatCase (a /# b) x# DEFAULT []
|
|
| 768 | -That is done once and for all by `unitLetFloat`, so a FloatLet in a LetFloats
|
|
| 769 | -is always a valid let-binding, and `wrapFloats` does not need to check.
|
|
| 770 | -Such bindings can arise from `makeTrivial`, because an argument need not
|
|
| 771 | -satisfy the let-can-float invariant. They also arise because
|
|
| 772 | -exprOkForSpeculation is conservative: e.g. it says False for (# s, x #)
|
|
| 773 | -where x is lifted, because it checks the arguments against the
|
|
| 774 | -(representation-polymorphic) type of the unboxed-tuple worker.
|
|
| 775 | - |
|
| 776 | -However, a FloatLet can still be FltCareful: the first FltCareful example
|
|
| 777 | -above, NonRec x* (f y), where x* is lifted but has a strict demand
|
|
| 778 | -(isStrUsedDmd). That is a perfectly valid (lazy) let-binding, but its demand
|
|
| 779 | -info is valid only where it is. If we floated it out of the RHS of a lazy
|
|
| 780 | -binding
|
|
| 781 | - let v = let x* = f y in x*+1 in body
|
|
| 782 | - ==> let x* = f y; v = x*+1 in body
|
|
| 783 | -then x's demand info would be a lie, and CorePrep, which case-binds a let
|
|
| 784 | -whose binder has a strict demand, would evaluate (f y) eagerly. Hence
|
|
| 785 | -FltCareful, which doFloatFromRhs allows to float only out of a strict binding.
|
|
| 786 | - |
|
| 759 | + NonRec x (y:ys) FltLifted
|
|
| 760 | + Rec [(x,rhs)] FltLifted
|
|
| 761 | + |
|
| 762 | + NonRec x* (p:q) FltOKSpec -- RHS is WHNF. Question: why not FltLifted?
|
|
| 763 | + NonRec x# (y +# 3) FltOkSpec -- Unboxed, but ok-for-spec'n
|
|
| 764 | + |
|
| 765 | + NonRec x* (f y) FltCareful -- Strict binding; might fail or diverge
|
|
| 766 | + NonRec x# (a /# b) FltCareful -- Might fail; does not satisfy let-can-float invariant
|
|
| 767 | + NonRec x# (f y) FltCareful -- Might diverge; does not satisfy let-can-float invariant
|
|
| 768 | + |
|
| 769 | + NonRec s "foo"# FltLifted -- Literal string can go to top level
|
|
| 770 | + |
|
| 771 | +* (FFL1) Note that a FloatLet can still be FltCareful: the first FltCareful example
|
|
| 772 | + above, NonRec x* (f y), where x* is lifted but has a strict demand
|
|
| 773 | + (isStrUsedDmd). That is a perfectly valid (lazy) let-binding, but its demand
|
|
| 774 | + info is valid only where it is. If we floated it out of the RHS of a lazy
|
|
| 775 | + binding
|
|
| 776 | + let v = let x* = f y in x*+1 in body
|
|
| 777 | + ==> let x* = f y; v = x*+1 in body
|
|
| 778 | + then x's demand info would be a lie, and CorePrep, which case-binds a let
|
|
| 779 | + whose binder has a strict demand, would evaluate (f y) eagerly. Hence
|
|
| 780 | + FltCareful, which doFloatFromRhs allows to float only out of a strict binding.
|
|
| 781 | + |
|
| 782 | +* (FFL2) A literal-string binding is marked FltLifted (a bit of a mis-nomer
|
|
| 783 | + because it's not a lifted type) because it can go to top level.
|
|
| 784 | + See Note [Core top-level string literals] in GHC.Core.
|
|
| 785 | + |
|
| 786 | +* A binding that does not satisfy the let-can-float invariant (the last two
|
|
| 787 | + examples above) is represented by a FloatCase, not a FloatLet:
|
|
| 788 | + FloatCase (a /# b) x# DEFAULT []
|
|
| 789 | + That is done once and for all by `unitLetFloat`, so a FloatLet in a LetFloats
|
|
| 790 | + is always a valid let-binding, and `wrapFloats` does not need to check.
|
|
| 791 | + Such bindings can arise from `makeTrivial`, because an argument need not
|
|
| 792 | + satisfy the let-can-float invariant. They also arise because
|
|
| 793 | + exprOkForSpeculation is conservative: e.g. it says False for (# s, x #)
|
|
| 794 | + where x is lifted, because it checks the arguments against the
|
|
| 795 | + (representation-polymorphic) type of the unboxed-tuple worker.
|
|
| 796 | + |
|
| 797 | +Note [FloatFlag for FloatCase] -- see `getFF_Case`
|
|
| 798 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 787 | 799 | As well as let-bindings, a LetFloats can contain single-alternative case
|
| 788 | 800 | floats (FloatCase), for example
|
| 789 | 801 | case e of b { (# a, c #) -> <hole> }
|
| ... | ... | @@ -795,12 +807,29 @@ These are classified just like a strict binding: |
| 795 | 807 | Being strict they are never FltLifted, so they never float to top level or into
|
| 796 | 808 | a recursive group.
|
| 797 | 809 | |
| 798 | -Currently, we never put a FloatTick in a LetFloats.
|
|
| 810 | +Note [FloatFlag for FloatTick] -- see `getFF_Tick`
|
|
| 811 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 812 | +A LetFloats can contain a FloatTick for soft-scoped ticks (only -- see the
|
|
| 813 | +invariant on FloatTick in GHC.Core).
|
|
| 814 | + |
|
| 815 | +* We certainly don't want a tick to go to top level, or into a recursive group,
|
|
| 816 | + so its FloatFlag is never FltLifted.
|
|
| 817 | + |
|
| 818 | +* A /non-counting/ tick (e.g. a source note) is FltOkSpec. Floating it out of
|
|
| 819 | + the RHS of a lazy binding
|
|
| 820 | + let x = tick<t> (let y = e1 in e2) in body
|
|
| 821 | + ==> tick<t> (let y = e1 in let x = e2 in body)
|
|
| 822 | + just brings more code (here `body`) under the tick, which is fine for a
|
|
| 823 | + soft-scoped tick.
|
|
| 824 | + |
|
| 825 | +* A /counting/ tick (e.g. an HPC tick) is FltCareful. Floating it out of a lazy
|
|
| 826 | + RHS would change when (and how often) it is counted: when the let is
|
|
| 827 | + executed rather than when `x` is evaluated.
|
|
| 799 | 828 | -}
|
| 800 | 829 | |
| 801 | 830 | data LetFloats = LetFloats FloatBinds FloatFlag
|
| 802 | 831 | -- See Note [LetFloats]
|
| 803 | - -- Contains only FloatLet and FloatCase; never FloatTick
|
|
| 832 | + -- Invariant: every FloatLet satisfies the let-can-float invariant
|
|
| 804 | 833 | |
| 805 | 834 | type JoinFloat = OutBind
|
| 806 | 835 | type JoinFloats = OrdList JoinFloat
|
| ... | ... | @@ -817,7 +846,7 @@ data FloatFlag |
| 817 | 846 | -- *and* ok-for-speculation
|
| 818 | 847 | -- Hence ok to float out of the RHS
|
| 819 | 848 | -- of a lazy non-recursive let binding
|
| 820 | - -- (but not to top level, or into a rec group)
|
|
| 849 | + -- (but /not/ to top level, or into a rec group)
|
|
| 821 | 850 | -- NB: consequence: all bindings satisfy let-can-float invariant
|
| 822 | 851 | |
| 823 | 852 | | FltCareful -- At least one binding is strict (or unlifted)
|
| ... | ... | @@ -899,37 +928,50 @@ emptyJoinFloats = nilOL |
| 899 | 928 | isEmptyJoinFloats :: JoinFloats -> Bool
|
| 900 | 929 | isEmptyJoinFloats = isNilOL
|
| 901 | 930 | |
| 931 | +getFF :: FloatBind -> FloatFlag
|
|
| 932 | +getFF (FloatCase e _ _ _) = getFF_Case e
|
|
| 933 | +getFF (FloatLet b) = getFF_Let b
|
|
| 934 | +getFF (FloatTick t) = getFF_Tick t
|
|
| 935 | + |
|
| 936 | +getFF_Let :: CoreBind -> FloatFlag
|
|
| 937 | +-- See Note [FloatFlag for FloatLet]
|
|
| 938 | +getFF_Let (Rec {}) = FltLifted
|
|
| 939 | +getFF_Let (NonRec bndr rhs)
|
|
| 940 | + | not (isStrictId bndr) = FltLifted -- Lazy lifted let
|
|
| 941 | + | exprIsTickedString rhs = FltLifted -- See (FFL2)
|
|
| 942 | + | exprOkForSpeculation rhs = FltOkSpec -- Unlifted, or strict lifted, and ok-for-spec (e.g. HNF)
|
|
| 943 | + | otherwise = FltCareful -- See (FFL1) Strict, e.g. let x* = factorial y
|
|
| 944 | + |
|
| 945 | +getFF_Case :: CoreExpr -> FloatFlag -- The CoreExpr is the scrutinee
|
|
| 946 | +-- Note [FloatFlag for FloatCase]
|
|
| 947 | +getFF_Case scrut | exprOkForSpeculation scrut = FltOkSpec
|
|
| 948 | + | otherwise = FltCareful
|
|
| 949 | + |
|
| 950 | +getFF_Tick :: CoreTickish -> FloatFlag
|
|
| 951 | +-- See Note [FloatFlag for FloatTick]
|
|
| 952 | +getFF_Tick t | tickishCounts t = FltCareful
|
|
| 953 | + | otherwise = FltOkSpec
|
|
| 954 | + |
|
| 902 | 955 | unitLetFloat :: OutBind -> LetFloats
|
| 903 | 956 | -- This key function constructs a singleton float with the right form
|
| 904 | 957 | -- If the binding does not satisfy the let-can-float invariant, it
|
| 905 | 958 | -- makes a FloatCase. See Note [LetFloats]
|
| 906 | -unitLetFloat bind = assert (all (not . isJoinId) (bindersOf bind)) $
|
|
| 907 | - mk_float bind
|
|
| 908 | - where
|
|
| 909 | - mk_float bind@(Rec {}) = let_float FltLifted bind
|
|
| 910 | - mk_float bind@(NonRec bndr rhs)
|
|
| 911 | - | not (isStrictId bndr) = let_float FltLifted bind
|
|
| 912 | - | exprIsTickedString rhs = let_float FltLifted bind
|
|
| 913 | - -- String literals can be floated freely.
|
|
| 914 | - -- See Note [Core top-level string literals] in GHC.Core.
|
|
| 915 | - | exprOkForSpeculation rhs = let_float FltOkSpec bind -- Unlifted, and lifted but ok-for-spec (eg HNF)
|
|
| 916 | - | needsCaseBinding (idType bndr) rhs
|
|
| 917 | - = pprTrace "TMP-unitLetFloat-case" (ppr bind) $
|
|
| 918 | - LetFloats (unitOL (FloatCase rhs bndr DEFAULT [])) FltCareful
|
|
| 919 | - -- Unlifted, and not ok-for-spec: does not satisfy let-can-float invariant
|
|
| 920 | - | otherwise = let_float FltCareful bind
|
|
| 921 | - |
|
| 922 | - let_float flag bind = LetFloats (unitOL (FloatLet bind)) flag
|
|
| 959 | +unitLetFloat bind
|
|
| 960 | + | NonRec bndr rhs <- bind
|
|
| 961 | + , needsCaseBinding (idType bndr) rhs
|
|
| 962 | + = -- This should never happen, but currently does because of #27910
|
|
| 963 | + LetFloats (unitOL (FloatCase rhs bndr DEFAULT [])) FltCareful
|
|
| 964 | + |
|
| 965 | + | otherwise
|
|
| 966 | + = assert (all (not . isJoinId) (bindersOf bind)) $
|
|
| 967 | + LetFloats (unitOL (FloatLet bind)) (getFF_Let bind)
|
|
| 923 | 968 | |
| 924 | 969 | unitCaseFloat :: OutExpr -> OutId -> AltCon -> [OutVar] -> LetFloats
|
| 925 | 970 | -- Constructs a singleton single-alternative case float
|
| 926 | 971 | -- case scrut of bndr { con bndrs -> <hole> }
|
| 927 | 972 | -- See Note [LetFloats]
|
| 928 | 973 | unitCaseFloat scrut bndr con bndrs
|
| 929 | - = LetFloats (unitOL (FloatCase scrut bndr con bndrs)) flag
|
|
| 930 | - where
|
|
| 931 | - flag | exprOkForSpeculation scrut = FltOkSpec
|
|
| 932 | - | otherwise = FltCareful
|
|
| 974 | + = LetFloats (unitOL (FloatCase scrut bndr con bndrs)) (getFF_Case scrut)
|
|
| 933 | 975 | |
| 934 | 976 | unitJoinFloat :: OutBind -> JoinFloats
|
| 935 | 977 | unitJoinFloat bind = assert (all isJoinId (bindersOf bind)) $
|
| ... | ... | @@ -978,12 +1020,34 @@ addLetFloats :: SimplFloats -> LetFloats -> SimplFloats |
| 978 | 1020 | -- Add the let-floats for env2 to env1;
|
| 979 | 1021 | -- *plus* the in-scope set for env2, which is bigger
|
| 980 | 1022 | -- than that for env1
|
| 981 | -addLetFloats floats let_floats
|
|
| 1023 | +addLetFloats floats let_floats@(LetFloats fbs _)
|
|
| 982 | 1024 | = floats { sfLetFloats = sfLetFloats floats `addLetFlts` let_floats
|
| 983 | - , sfInScope = sfInScope floats `extendInScopeFromLF` let_floats }
|
|
| 984 | - |
|
| 985 | -extendInScopeFromLF :: InScopeSet -> LetFloats -> InScopeSet
|
|
| 986 | -extendInScopeFromLF in_scope (LetFloats binds _)
|
|
| 1025 | + , sfInScope = sfInScope floats `extendInScopeFromFB` fbs }
|
|
| 1026 | + |
|
| 1027 | +addFloatBindsF :: FloatBinds -> SimplFloats -> SimplFloats
|
|
| 1028 | +-- (addFloatBindsF new_fbs floats) adds `new_fbs` /outside/ `floats`;
|
|
| 1029 | +-- i.e. `new_fbs` scope over `floats`
|
|
| 1030 | +-- Precondition: every FloatLet in `new_fbs` satisfies the let-can-float
|
|
| 1031 | +-- invariant (see the FloatBind declaration in GHC.Core), so we can add
|
|
| 1032 | +-- them directly; see Note [LetFloats]
|
|
| 1033 | +addFloatBindsF new_fbs floats@(SimplFloats { sfLetFloats = LetFloats lf_fbs lf_ff
|
|
| 1034 | + , sfInScope = in_scope })
|
|
| 1035 | + | isNilOL new_fbs
|
|
| 1036 | + = floats
|
|
| 1037 | + | otherwise
|
|
| 1038 | + = assertPpr (all ok_float new_fbs) (ppr new_fbs) $
|
|
| 1039 | + floats { sfLetFloats = LetFloats (new_fbs `appOL` lf_fbs)
|
|
| 1040 | + (foldr (andFF . getFF) lf_ff new_fbs)
|
|
| 1041 | + , sfInScope = in_scope `extendInScopeFromFB` new_fbs }
|
|
| 1042 | + where
|
|
| 1043 | + -- Check the invariants on FloatBind; see its declaration in GHC.Core
|
|
| 1044 | + ok_float (FloatLet (NonRec b r))
|
|
| 1045 | + | isId b, not (isCoVar b) = not (needsCaseBinding (idType b) r)
|
|
| 1046 | + ok_float (FloatTick t) = tickishHasSoftScope t
|
|
| 1047 | + ok_float _ = True
|
|
| 1048 | + |
|
| 1049 | +extendInScopeFromFB :: InScopeSet -> FloatBinds -> InScopeSet
|
|
| 1050 | +extendInScopeFromFB in_scope binds
|
|
| 987 | 1051 | = foldlOL extend in_scope binds
|
| 988 | 1052 | where
|
| 989 | 1053 | extend in_scope (FloatLet bind) = in_scope `extendInScopeSetBind` bind
|
| ... | ... | @@ -66,7 +66,7 @@ import GHC.Builtin.WiredIn.Ids( seqId ) |
| 66 | 66 | import qualified GHC.Data.List.Infinite as Inf
|
| 67 | 67 | import GHC.Data.Maybe ( isNothing, orElse, mapMaybe )
|
| 68 | 68 | import GHC.Data.FastString
|
| 69 | -import GHC.Data.OrdList ( fromOL ) -- TMP
|
|
| 69 | +import GHC.Data.OrdList ( unitOL )
|
|
| 70 | 70 | import GHC.Unit.Module ( moduleName )
|
| 71 | 71 | import GHC.Utils.Outputable
|
| 72 | 72 | import GHC.Utils.Panic
|
| ... | ... | @@ -1287,7 +1287,8 @@ simplExprF1 env expr@(Lam {}) cont |
| 1287 | 1287 | -- and likewise drop counts all binders (incl type lambdas)
|
| 1288 | 1288 | |
| 1289 | 1289 | simplExprF1 env expr@(Case scrut bndr _ alts) cont
|
| 1290 | - | Just (inner, outer) <- splitContForNoCaseCase env cont
|
|
| 1290 | + | Just (inner, outer) <- splitContForNoCaseCase env (isSingleton alts) cont
|
|
| 1291 | + -- isSingleton: push casts inside only if there is just one alternative
|
|
| 1291 | 1292 | -- See (COC-INV) in Note [sm_case_case: switching off case continuations]
|
| 1292 | 1293 | = do { (floats, expr') <- simplExprF env expr inner
|
| 1293 | 1294 | ; rebuildWithFloats env floats expr' outer }
|
| ... | ... | @@ -1314,9 +1315,12 @@ simplExprF1 env (Let (NonRec bndr rhs) body) cont |
| 1314 | 1315 | tick (PreInlineUnconditionally bndr)
|
| 1315 | 1316 | ; simplExprF env' body cont }
|
| 1316 | 1317 | |
| 1317 | -simplExprF1 env expr@(Let {}) cont
|
|
| 1318 | - | Just (inner, outer) <- splitContForNoCaseCase env cont
|
|
| 1318 | +simplExprF1 env expr@(Let bind _) cont
|
|
| 1319 | + | Just (inner, outer) <- splitContForNoCaseCase env (not (mightBeJoinBind bind)) cont
|
|
| 1319 | 1320 | -- See (COC-INV) in Note [sm_case_case: switching off case continuations]
|
| 1321 | + -- mightBeJoinBind: do not push a cast into a join point's RHS, because
|
|
| 1322 | + -- then we'd have to push it to every jump, including those in
|
|
| 1323 | + -- multi-alternative cases, where we don't want to push casts
|
|
| 1320 | 1324 | = do { (floats, expr') <- simplExprF env expr inner
|
| 1321 | 1325 | ; rebuildWithFloats env floats expr' outer }
|
| 1322 | 1326 | |
| ... | ... | @@ -1342,13 +1346,22 @@ simplExprF1 env (Let (Rec pairs) body) cont |
| 1342 | 1346 | simplRecE env pairs body cont
|
| 1343 | 1347 | |
| 1344 | 1348 | |
| 1345 | -splitContForNoCaseCase :: SimplEnv -> SimplCont
|
|
| 1349 | +mightBeJoinBind :: InBind -> Bool
|
|
| 1350 | +-- True if joinPointBind_maybe might succeed; cheap and conservative
|
|
| 1351 | +mightBeJoinBind bind = any might_be_join (bindersOf bind)
|
|
| 1352 | + where
|
|
| 1353 | + might_be_join b = isId b && (isJoinId b || isAlwaysTailCalled (idOccInfo b))
|
|
| 1354 | + |
|
| 1355 | +splitContForNoCaseCase :: SimplEnv
|
|
| 1356 | + -> Bool -- True <=> casts may go in `inner`
|
|
| 1357 | + -> SimplCont
|
|
| 1346 | 1358 | -> Maybe (SimplCont, SimplCont)
|
| 1347 | 1359 | -- When seCaseCase is off, this function splits `cont` into (inner, outer),
|
| 1348 | --- where `inner` has only applications, and `outer` is non-trivial
|
|
| 1349 | -splitContForNoCaseCase env cont
|
|
| 1360 | +-- where `inner` has only applications (and perhaps casts), and `outer` is
|
|
| 1361 | +-- non-trivial. See splitContArgs for the Bool.
|
|
| 1362 | +splitContForNoCaseCase env push_casts cont
|
|
| 1350 | 1363 | | seCaseCase env = Nothing
|
| 1351 | - | otherwise = splitContArgs cont
|
|
| 1364 | + | otherwise = splitContArgs push_casts cont
|
|
| 1352 | 1365 | |
| 1353 | 1366 | {- Note [Avoiding space leaks in OutType]
|
| 1354 | 1367 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1503,10 +1516,16 @@ simplTick env tickish expr cont |
| 1503 | 1516 | -- push the continuation inside the tick. This has the effect of moving the
|
| 1504 | 1517 | -- tick to the outside of a case or application context, allowing the normal
|
| 1505 | 1518 | -- 'case' and 'application' optimisations to fire.
|
| 1519 | + --
|
|
| 1520 | + -- We return the tick as a FloatTick, /outside/ the floats from `expr`.
|
|
| 1521 | + -- So all the code that was covered by the tick (including the floats,
|
|
| 1522 | + -- notably single-alternative case floats) remains covered, as soft scope
|
|
| 1523 | + -- requires; and yet `expr'` is exposed to the caller, e.g. for
|
|
| 1524 | + -- case-of-known-constructor in rebuildWithFloats.
|
|
| 1525 | + -- See Note [FloatFlag for FloatTick] in GHC.Core.Opt.Simplify.Env
|
|
| 1506 | 1526 | | tickishHasSoftScope tickish
|
| 1507 | 1527 | = do { (floats, expr') <- simplExprF env expr cont
|
| 1508 | - ; return (floats, mkTick tickish expr')
|
|
| 1509 | - }
|
|
| 1528 | + ; return (unitOL (FloatTick tickish) `addFloatBindsF` floats, expr') }
|
|
| 1510 | 1529 | |
| 1511 | 1530 | -- Push tick inside if the context looks like this will allow us to
|
| 1512 | 1531 | -- do a case-of-case - see Note [case-of-scc-of-case]
|
| ... | ... | @@ -2431,7 +2450,7 @@ simplOutId env fun cont |
| 2431 | 2450 | , ApplyToTy { sc_cont = cont2 } <- cont1
|
| 2432 | 2451 | , ApplyToVal { sc_cont = cont3, sc_arg = arg, sc_env = arg_se
|
| 2433 | 2452 | , sc_cast = arg_mco, sc_hole_ty = fun_ty } <- cont2
|
| 2434 | - = case splitContForNoCaseCase env cont3 of
|
|
| 2453 | + = case splitContForNoCaseCase env True cont3 of
|
|
| 2435 | 2454 | Nothing -> do { e' <- simplRunRW env fun arg arg_se arg_mco fun_ty cont3
|
| 2436 | 2455 | ; return (emptyFloats env, e') }
|
| 2437 | 2456 | Just (ink,outk) -> do { e' <- simplRunRW env fun arg arg_se arg_mco fun_ty ink
|
| ... | ... | @@ -2838,14 +2857,10 @@ fireRuleAFTER env rule_match arg_specs cont |
| 2838 | 2857 | | RM { rm_rule = rule, rm_rhs = rhs, rm_args = rhs_args
|
| 2839 | 2858 | , rm_floats = float_bs } <- rule_match
|
| 2840 | 2859 | = do { let env' = env `addNewInScopeIds` floatsBinders float_bs
|
| 2841 | - ; (floats, e') <- simplExprF env' rhs $
|
|
| 2842 | - pushOutArgs (exprType rhs) rhs_args $
|
|
| 2843 | - pushArgSpecs (drop (ruleArity rule) arg_specs) cont
|
|
| 2844 | - ; return $
|
|
| 2845 | - if isEmptyFloatBinds float_bs -- Not very pretty
|
|
| 2846 | - then (floats, e')
|
|
| 2847 | - else (emptyFloats env', GHC.Core.Make.wrapFloats float_bs $
|
|
| 2848 | - wrapFloats floats e') }
|
|
| 2860 | + ; addFloatBinds (contHoleScaling cont) float_bs $
|
|
| 2861 | + simplExprF env' rhs $
|
|
| 2862 | + pushOutArgs (exprType rhs) rhs_args $
|
|
| 2863 | + pushArgSpecs (drop (ruleArity rule) arg_specs) cont }
|
|
| 2849 | 2864 | |
| 2850 | 2865 | |
| 2851 | 2866 | tryRules :: SimplEnv -> [CoreRule]
|
| ... | ... | @@ -3553,7 +3568,6 @@ robust here. (Otherwise, there's a danger that we'll simply drop the |
| 3553 | 3568 | |
| 3554 | 3569 | Note [Scaling in case-of-case]
|
| 3555 | 3570 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 3556 | - |
|
| 3557 | 3571 | When two cases commute, if done naively, the multiplicities will be wrong:
|
| 3558 | 3572 | |
| 3559 | 3573 | case (case u of w[1] { (x[1], y[1]) } -> f x y) of w'[Many]
|
| ... | ... | @@ -3991,22 +4005,22 @@ All this should happen in one sweep. |
| 3991 | 4005 | |
| 3992 | 4006 | Note [FloatBinds from constructor wrappers]
|
| 3993 | 4007 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 3994 | -If we have FloatBinds coming from the constructor wrapper
|
|
| 3995 | -(as in Note [exprIsConApp_maybe on data constructors with wrappers]),
|
|
| 3996 | -we cannot float past them. We'd need to float the FloatBind
|
|
| 3997 | -together with the simplify floats, unfortunately the
|
|
| 3998 | -simplifier doesn't have case-floats. The simplest thing we can
|
|
| 3999 | -do is to wrap all the floats here. The next iteration of the
|
|
| 4000 | -simplifier will take care of all these cases and lets.
|
|
| 4008 | +exprIsConApp_maybe may return FloatBinds, e.g. coming from a constructor
|
|
| 4009 | +wrapper (as in Note [exprIsConApp_maybe on data constructors with wrappers]),
|
|
| 4010 | +or from looking through lets and single-alternative cases in the scrutinee.
|
|
| 4011 | +These floats scope over the result of case-of-known-constructor.
|
|
| 4012 | + |
|
| 4013 | +Since the Simplifier's floats can contain case-floats as well as let-floats
|
|
| 4014 | +(see Note [LetFloats] in GHC.Core.Opt.Simplify.Env), we simply add them to
|
|
| 4015 | +the SimplFloats, outside the floats from simplifying the alternative; see
|
|
| 4016 | +knownConCase_maybe. We do not wrap them around the result, because then a
|
|
| 4017 | +subsequent case-of-known-constructor on the result would have to walk
|
|
| 4018 | +through them all over again, which can be quadratic (#27737).
|
|
| 4001 | 4019 | |
| 4002 | 4020 | Given data T = MkT !Bool, this allows us to simplify
|
| 4003 | 4021 | case $WMkT b of { MkT x -> f x }
|
| 4004 | 4022 | to
|
| 4005 | 4023 | case b of { b' -> f b' }.
|
| 4006 | - |
|
| 4007 | -We could try and be more clever (like maybe `wfloats` only contains
|
|
| 4008 | -let binders, so we could float them). But the need for the extra
|
|
| 4009 | -complication is not clear.
|
|
| 4010 | 4024 | -}
|
| 4011 | 4025 | |
| 4012 | 4026 | knownConCase_maybe :: (SimplAltFlag, SimplEnv)
|
| ... | ... | @@ -4033,58 +4047,27 @@ knownConCase_maybe (saf,env) scrut case_bndr alts cont |
| 4033 | 4047 | -- as well as when it's an explicit constructor application
|
| 4034 | 4048 | , let env0 = setInScopeSet env in_scope'
|
| 4035 | 4049 | = Just $
|
| 4036 | - (if isEmptyFloatBinds wfloats then id else
|
|
| 4037 | - pprTrace "TMP-knownCon" (vcat [ text "nfloats" <+> ppr (length (fromOL wfloats))
|
|
| 4038 | - , text "scrut" <+> ppr scrut ])) $
|
|
| 4039 | 4050 | do { tick (KnownBranch case_bndr)
|
| 4040 | 4051 | ; let -- case_bndr_unf: see Note [Do not duplicate constructor applications]
|
| 4041 | 4052 | case_bndr_rhs | exprIsTrivial scrut = scrut
|
| 4042 | 4053 | | otherwise = con_app
|
| 4043 | 4054 | con_app = Var (dataConWorkId con) `mkTyApps` ty_args
|
| 4044 | 4055 | `mkApps` other_args
|
| 4045 | - ; wrapDataConFloats env wfloats case_bndr cont $
|
|
| 4056 | + -- The wfloats scope over the result
|
|
| 4057 | + -- See Note [FloatBinds from constructor wrappers]
|
|
| 4058 | + ; addFloatBinds hole_scaling wfloats $
|
|
| 4046 | 4059 | case findAlt (DataAlt con) alts of
|
| 4047 | 4060 | Nothing -> missingAlt env0 case_bndr alts cont
|
| 4048 | 4061 | Just (Alt DEFAULT bs rhs) -> simpl_rhs env0 case_bndr_rhs bs rhs
|
| 4049 | 4062 | Just (Alt _ bs rhs) -> knownCon env0 scrut con other_args
|
| 4050 | - case_bndr bs rhs cont
|
|
| 4051 | - }
|
|
| 4063 | + case_bndr bs rhs cont }
|
|
| 4052 | 4064 | |
| 4053 | 4065 | | otherwise
|
| 4054 | 4066 | = Nothing
|
| 4055 | 4067 | where
|
| 4056 | - simpl_rhs env case_bndr_rhs bs rhs
|
|
| 4057 | - = assert (null bs) $
|
|
| 4058 | - do { (floats1, env') <- simplAuxBind (saf,env) case_bndr case_bndr_rhs
|
|
| 4059 | - -- scrut is a constructor application,
|
|
| 4060 | - -- hence satisfies let-can-float invariant
|
|
| 4061 | - ; (floats2, expr') <- simplExprF env' rhs cont
|
|
| 4062 | - ; return (floats1 `addFloats` floats2, expr') }
|
|
| 4063 | - |
|
| 4064 | -wrapDataConFloats :: SimplEnv -> FloatBinds -> InId -> SimplCont
|
|
| 4065 | - -> SimplM (SimplFloats, OutExpr)
|
|
| 4066 | - -> SimplM (SimplFloats, OutExpr)
|
|
| 4067 | --- See Note [FloatBinds from constructor wrappers]
|
|
| 4068 | -wrapDataConFloats env wfloats case_bndr cont thing_inside
|
|
| 4069 | - | isEmptyFloatBinds wfloats
|
|
| 4070 | - = thing_inside
|
|
| 4071 | - | otherwise
|
|
| 4072 | - = do { (floats, expr) <- thing_inside
|
|
| 4073 | - ; return ( emptyFloats env
|
|
| 4074 | - , GHC.Core.Make.wrapFloats (fmap scale_float wfloats) $
|
|
| 4075 | - wrapFloats floats expr ) }
|
|
| 4076 | - where
|
|
| 4077 | - -- scale_float scales case-floats by the multiplicity of the continuation hole
|
|
| 4078 | - -- (see Note [Scaling in case-of-case]).
|
|
| 4079 | - -- Let floats are _not_ scaled, because they are aliases anyway.
|
|
| 4080 | - scale_float (GHC.Core.FloatCase scrut case_bndr con vars)
|
|
| 4081 | - = GHC.Core.FloatCase scrut (scale_id case_bndr) con (map scale_id vars)
|
|
| 4082 | - scale_float flt@(GHC.Core.FloatLet {}) = flt
|
|
| 4083 | - scale_float flt@(GHC.Core.FloatTick {}) = flt
|
|
| 4084 | - |
|
| 4085 | - scale_id id = scaleVarBy holeScaling id
|
|
| 4086 | - |
|
| 4087 | - holeScaling = contHoleScaling cont `mkMultMul` idMult case_bndr
|
|
| 4068 | + hole_scaling = idMult case_bndr `mkMultMul` contHoleScaling cont
|
|
| 4069 | + -- See Note [Scaling in case-of-case]
|
|
| 4070 | + -- This is the contHoleScaling of the original Select continuation
|
|
| 4088 | 4071 | -- We are in the following situation
|
| 4089 | 4072 | -- case[p] case[q] u of { D x -> C v } of { C x -> w }
|
| 4090 | 4073 | -- And we are producing case[??] u of { D x -> w[x\v]}
|
| ... | ... | @@ -4100,6 +4083,33 @@ wrapDataConFloats env wfloats case_bndr cont thing_inside |
| 4100 | 4083 | -- Which is ill-typed with respect to linearity. So it needs to be a
|
| 4101 | 4084 | -- case[Many].
|
| 4102 | 4085 | |
| 4086 | + simpl_rhs env case_bndr_rhs bs rhs
|
|
| 4087 | + = assert (null bs) $
|
|
| 4088 | + do { (floats1, env') <- simplAuxBind (saf,env) case_bndr case_bndr_rhs
|
|
| 4089 | + -- scrut is a constructor application,
|
|
| 4090 | + -- hence satisfies let-can-float invariant
|
|
| 4091 | + ; (floats2, expr') <- simplExprF env' rhs cont
|
|
| 4092 | + ; return (floats1 `addFloats` floats2, expr') }
|
|
| 4093 | + |
|
| 4094 | +addFloatBinds :: Mult -> FloatBinds
|
|
| 4095 | + -> SimplM (SimplFloats, a) -> SimplM (SimplFloats, a)
|
|
| 4096 | +-- (addFloatBinds scaling fbs thing_inside) adds `fbs` outside the floats
|
|
| 4097 | +-- returned by `thing_inside`. The `scaling` is the multiplicity of the
|
|
| 4098 | +-- continuation hole, by which case-floats are scaled, because they now
|
|
| 4099 | +-- scope over that continuation: see Note [Scaling in case-of-case].
|
|
| 4100 | +-- Let floats do not need this treatment
|
|
| 4101 | +addFloatBinds scaling fbs thing_inside
|
|
| 4102 | + | isEmptyFloatBinds fbs -- Short cut
|
|
| 4103 | + = thing_inside
|
|
| 4104 | + | otherwise
|
|
| 4105 | + = do { (floats, res) <- thing_inside
|
|
| 4106 | + ; return (fmap scale_float fbs `addFloatBindsF` floats, res) }
|
|
| 4107 | + where
|
|
| 4108 | + scale_float (FloatCase scrut b con vars)
|
|
| 4109 | + = FloatCase scrut (scale_id b) con (map scale_id vars)
|
|
| 4110 | + scale_float flt = flt
|
|
| 4111 | + |
|
| 4112 | + scale_id id = scaleVarBy scaling id
|
|
| 4103 | 4113 | |
| 4104 | 4114 | knownCon :: SimplEnv
|
| 4105 | 4115 | -> OutExpr -- The scrutinee
|
| ... | ... | @@ -632,19 +632,24 @@ contOutArgs env cont |
| 632 | 632 | -- No more arguments
|
| 633 | 633 | go _ = []
|
| 634 | 634 | |
| 635 | -splitContArgs :: SimplCont -> Maybe (SimplCont, SimplCont)
|
|
| 636 | --- Splits `cont` into (inner, outer), where `inner` has only
|
|
| 637 | --- applications and casts, and `outer` is non-trivial
|
|
| 638 | -splitContArgs cont@(ApplyToTy { sc_cont = cont1 })
|
|
| 639 | - = do { (inner, outer) <- splitContArgs cont1
|
|
| 635 | +splitContArgs :: Bool -> SimplCont -> Maybe (SimplCont, SimplCont)
|
|
| 636 | +-- (splitContArgs push_casts cont) splits `cont` into (inner, outer), where
|
|
| 637 | +-- `inner` has only applications, and casts if `push_casts` is True;
|
|
| 638 | +-- and `outer` is non-trivial.
|
|
| 639 | +-- The caller sets `push_casts` to False if `inner` will be pushed into many
|
|
| 640 | +-- case alternatives: pushing a cast into each of them duplicates the
|
|
| 641 | +-- coercion, which can be big (T5642)
|
|
| 642 | +splitContArgs push_casts cont@(ApplyToTy { sc_cont = cont1 })
|
|
| 643 | + = do { (inner, outer) <- splitContArgs push_casts cont1
|
|
| 640 | 644 | ; return (cont { sc_cont = inner }, outer) }
|
| 641 | -splitContArgs cont@(ApplyToVal { sc_cont = cont1 })
|
|
| 642 | - = do { (inner, outer) <- splitContArgs cont1
|
|
| 645 | +splitContArgs push_casts cont@(ApplyToVal { sc_cont = cont1 })
|
|
| 646 | + = do { (inner, outer) <- splitContArgs push_casts cont1
|
|
| 643 | 647 | ; return (cont { sc_cont = inner }, outer) }
|
| 644 | -splitContArgs cont@(CastIt { sc_cont = cont1 })
|
|
| 645 | - = do { (inner, outer) <- splitContArgs cont1
|
|
| 648 | +splitContArgs push_casts cont@(CastIt { sc_cont = cont1 })
|
|
| 649 | + | push_casts
|
|
| 650 | + = do { (inner, outer) <- splitContArgs push_casts cont1
|
|
| 646 | 651 | ; return (cont { sc_cont = inner }, outer) }
|
| 647 | -splitContArgs outer
|
|
| 652 | +splitContArgs _ outer
|
|
| 648 | 653 | | contIsStop outer = Nothing
|
| 649 | 654 | | otherwise = -- pprTrace "splitContHoleType" (ppr hole_ty) $
|
| 650 | 655 | return (mkBoringStop hole_ty, outer)
|
| 1 | 1 | |
| 2 | 2 | ==================== Exitification transformation ====================
|
| 3 | 3 | Result size of Exitification transformation
|
| 4 | - = {terms: 50, types: 22, coercions: 0, joins: 2/2}
|
|
| 4 | + = {terms: 33, types: 15, coercions: 0, joins: 2/2}
|
|
| 5 | 5 | |
| 6 | 6 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 7 | 7 | lvl :: Int
|
| ... | ... | @@ -11,7 +11,7 @@ lvl :: Int |
| 11 | 11 | Guidance=IF_ARGS [] 10 10}]
|
| 12 | 12 | lvl = GHC.Internal.Types.I# 0#
|
| 13 | 13 | |
| 14 | --- RHS size: {terms: 32, types: 14, coercions: 0, joins: 2/2}
|
|
| 14 | +-- RHS size: {terms: 29, types: 12, coercions: 0, joins: 2/2}
|
|
| 15 | 15 | small :: Int -> Int
|
| 16 | 16 | [LclIdX,
|
| 17 | 17 | Arity=1,
|
| ... | ... | @@ -22,7 +22,7 @@ small :: Int -> Int |
| 22 | 22 | Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
|
| 23 | 23 | Tmpl= \ (x [Dmd=S!P(SL)] :: Int) ->
|
| 24 | 24 | joinrec {
|
| 25 | - go [InlPrag=[2], Occ=T[2], Dmd=LC(S,C(1,!P(L)))]
|
|
| 25 | + go [InlPrag=[2], Occ=Many(T[2]), Dmd=LC(S,C(1,!P(L)))]
|
|
| 26 | 26 | :: Int -> Int -> Int
|
| 27 | 27 | [LclId[JoinId(2)(Nothing)],
|
| 28 | 28 | Arity=2,
|
| ... | ... | @@ -54,11 +54,11 @@ small :: Int -> Int |
| 54 | 54 | Guidance=IF_ARGS [0 51] 63 10}]
|
| 55 | 55 | $wgo (ww [Occ=Once2] :: GHC.Internal.Prim.Int#)
|
| 56 | 56 | (ww [Occ=Once1!, Dmd=SL] :: GHC.Internal.Prim.Int#)
|
| 57 | - = case ww of ds {
|
|
| 57 | + = case ww of wild {
|
|
| 58 | 58 | __DEFAULT ->
|
| 59 | 59 | jump go
|
| 60 | - (GHC.Internal.Types.I# (GHC.Internal.Prim.+# ww ds))
|
|
| 61 | - (GHC.Internal.Types.I# (GHC.Internal.Prim.-# ds 1#));
|
|
| 60 | + (GHC.Internal.Types.I# (GHC.Internal.Prim.+# ww wild))
|
|
| 61 | + (GHC.Internal.Types.I# (GHC.Internal.Prim.-# wild 1#));
|
|
| 62 | 62 | 0# ->
|
| 63 | 63 | case x of { GHC.Internal.Types.I# y [Occ=Once1] ->
|
| 64 | 64 | GHC.Internal.Types.I# (GHC.Internal.Prim.*# ww y)
|
| ... | ... | @@ -67,13 +67,12 @@ small :: Int -> Int |
| 67 | 67 | jump go lvl x}]
|
| 68 | 68 | small
|
| 69 | 69 | = \ (x [Dmd=S!P(SL)] :: Int) ->
|
| 70 | + case x of { GHC.Internal.Types.I# ww [Dmd=SL] ->
|
|
| 70 | 71 | join {
|
| 71 | 72 | exit :: GHC.Internal.Prim.Int# -> Int
|
| 72 | 73 | [LclId[JoinId(1)(Nothing)]]
|
| 73 | 74 | exit (ww :: GHC.Internal.Prim.Int#)
|
| 74 | - = case x of { GHC.Internal.Types.I# y ->
|
|
| 75 | - GHC.Internal.Types.I# (GHC.Internal.Prim.*# ww y)
|
|
| 76 | - } } in
|
|
| 75 | + = GHC.Internal.Types.I# (GHC.Internal.Prim.*# ww ww) } in
|
|
| 77 | 76 | joinrec {
|
| 78 | 77 | $wgo [InlPrag=[2], Occ=LoopBreaker]
|
| 79 | 78 | :: GHC.Internal.Prim.Int# -> GHC.Internal.Prim.Int# -> Int
|
| ... | ... | @@ -82,56 +81,17 @@ small |
| 82 | 81 | Str=<L><SL>,
|
| 83 | 82 | Unf=Unf{Src=<vanilla>, TopLvl=False,
|
| 84 | 83 | Value=True, ConLike=True, WorkFree=True, Expandable=True,
|
| 85 | - Guidance=IF_ARGS [0 32] 43 10}]
|
|
| 84 | + Guidance=IF_ARGS [0 32] 33 10}]
|
|
| 86 | 85 | $wgo (ww :: GHC.Internal.Prim.Int#)
|
| 87 | 86 | (ww [Dmd=SL] :: GHC.Internal.Prim.Int#)
|
| 88 | - = case ww of ds {
|
|
| 87 | + = case ww of wild {
|
|
| 89 | 88 | __DEFAULT ->
|
| 90 | 89 | jump $wgo
|
| 91 | - (GHC.Internal.Prim.+# ww ds) (GHC.Internal.Prim.-# ds 1#);
|
|
| 90 | + (GHC.Internal.Prim.+# ww wild) (GHC.Internal.Prim.-# wild 1#);
|
|
| 92 | 91 | 0# -> jump exit ww
|
| 93 | 92 | }; } in
|
| 94 | - case x of { GHC.Internal.Types.I# ww [Dmd=SL] -> jump $wgo 0# ww }
|
|
| 95 | - |
|
| 96 | --- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
|
|
| 97 | -$trModule :: GHC.Internal.Prim.Addr#
|
|
| 98 | -[LclId,
|
|
| 99 | - Unf=Unf{Src=<vanilla>, TopLvl=True,
|
|
| 100 | - Value=True, ConLike=True, WorkFree=True, Expandable=True,
|
|
| 101 | - Guidance=IF_ARGS [] 20 0}]
|
|
| 102 | -$trModule = "main"#
|
|
| 103 | - |
|
| 104 | --- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
|
| 105 | -$trModule :: GHC.Internal.Types.TrName
|
|
| 106 | -[LclId,
|
|
| 107 | - Unf=Unf{Src=<vanilla>, TopLvl=True,
|
|
| 108 | - Value=True, ConLike=True, WorkFree=True, Expandable=True,
|
|
| 109 | - Guidance=IF_ARGS [] 10 10}]
|
|
| 110 | -$trModule = GHC.Internal.Types.TrNameS $trModule
|
|
| 111 | - |
|
| 112 | --- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}
|
|
| 113 | -$trModule :: GHC.Internal.Prim.Addr#
|
|
| 114 | -[LclId,
|
|
| 115 | - Unf=Unf{Src=<vanilla>, TopLvl=True,
|
|
| 116 | - Value=True, ConLike=True, WorkFree=True, Expandable=True,
|
|
| 117 | - Guidance=IF_ARGS [] 30 0}]
|
|
| 118 | -$trModule = "T20510"#
|
|
| 119 | - |
|
| 120 | --- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
|
| 121 | -$trModule :: GHC.Internal.Types.TrName
|
|
| 122 | -[LclId,
|
|
| 123 | - Unf=Unf{Src=<vanilla>, TopLvl=True,
|
|
| 124 | - Value=True, ConLike=True, WorkFree=True, Expandable=True,
|
|
| 125 | - Guidance=IF_ARGS [] 10 10}]
|
|
| 126 | -$trModule = GHC.Internal.Types.TrNameS $trModule
|
|
| 127 | - |
|
| 128 | --- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
|
|
| 129 | -T20510.$trModule :: GHC.Internal.Types.Module
|
|
| 130 | -[LclIdX,
|
|
| 131 | - Unf=Unf{Src=<vanilla>, TopLvl=True,
|
|
| 132 | - Value=True, ConLike=True, WorkFree=True, Expandable=True,
|
|
| 133 | - Guidance=IF_ARGS [] 10 10}]
|
|
| 134 | -T20510.$trModule = GHC.Internal.Types.Module $trModule $trModule
|
|
| 93 | + jump $wgo 0# ww
|
|
| 94 | + }
|
|
| 135 | 95 | |
| 136 | 96 | |
| 137 | 97 |
| ... | ... | @@ -59,135 +59,133 @@ objects: |
| 59 | 59 | arity: 0
|
| 60 | 60 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 61 | 61 | used items: named item ‘primes’
|
| 62 | - object ‘primes2_@name_suffix@’:
|
|
| 62 | + object ‘primes’:
|
|
| 63 | 63 | arity: 0
|
| 64 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 65 | - used items:
|
|
| 66 | - object ‘primes2_sat_@name_suffix@’:
|
|
| 67 | - arity: 0
|
|
| 68 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 69 | - used items:
|
|
| 70 | - object ‘primes2_sat_@name_suffix@’:
|
|
| 71 | - arity: 0
|
|
| 72 | - literals:
|
|
| 73 | - label ‘_hpc_tickboxes_Example_hpc’
|
|
| 74 | - word 3
|
|
| 75 | - info table of ‘IS’
|
|
| 76 | - used items:
|
|
| 77 | - named item ‘$fNumNatural’
|
|
| 78 | - named item ‘fromInteger’
|
|
| 79 | - named item ‘$fEnumNatural’
|
|
| 80 | - named item ‘enumFrom’
|
|
| 81 | - object ‘primes2_sat_@name_suffix@’:
|
|
| 82 | - arity: 0
|
|
| 83 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 84 | - used items: named item ‘isPrime_@name_suffix@’
|
|
| 85 | - named item ‘filter’
|
|
| 86 | - object ‘isPrime_@name_suffix@’:
|
|
| 87 | - arity: 1
|
|
| 88 | 64 | literals:
|
| 89 | 65 | label ‘_hpc_tickboxes_Example_hpc’
|
| 66 | + info table of ‘(:)’
|
|
| 90 | 67 | used items:
|
| 91 | - object ‘isPrime_sat_@name_suffix@’:
|
|
| 68 | + object ‘isPrime_@name_suffix@’:
|
|
| 92 | 69 | arity: 1
|
| 93 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 70 | + literals:
|
|
| 71 | + label ‘_hpc_tickboxes_Example_hpc’
|
|
| 94 | 72 | used items:
|
| 95 | - object ‘isPrime_sat_@name_suffix@’:
|
|
| 73 | + object ‘isPrime_primes_sat_@name_suffix@’:
|
|
| 96 | 74 | arity: 1
|
| 97 | 75 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 98 | 76 | used items:
|
| 99 | - object ‘isPrime_sat_@name_suffix@’:
|
|
| 100 | - arity: 0
|
|
| 101 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 102 | - used items: named item ‘primes’
|
|
| 103 | - object ‘isPrime_sat_@name_suffix@’:
|
|
| 77 | + object ‘isPrime_primes_sat_@name_suffix@’:
|
|
| 104 | 78 | arity: 1
|
| 105 | 79 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 106 | 80 | used items:
|
| 107 | - object ‘isPrime_sat_@name_suffix@’:
|
|
| 81 | + object ‘isPrime_primes_sat_@name_suffix@’:
|
|
| 108 | 82 | arity: 0
|
| 109 | 83 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 110 | - used items:
|
|
| 111 | - object ‘v_@name_suffix@’:
|
|
| 112 | - arity: 0
|
|
| 113 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 114 | - used items:
|
|
| 115 | - named item ‘$fIntegralInteger’
|
|
| 116 | - named item ‘$fNumNatural’
|
|
| 117 | - named item ‘(^)’
|
|
| 118 | - object ‘v1_@name_suffix@’:
|
|
| 119 | - arity: 0
|
|
| 120 | - literals:
|
|
| 121 | - label ‘_hpc_tickboxes_Example_hpc’
|
|
| 122 | - word 2
|
|
| 123 | - info table of ‘IS’
|
|
| 124 | - used items: <none>
|
|
| 125 | - object ‘pap_@name_suffix@’:
|
|
| 126 | - arity: 3
|
|
| 127 | - literals: <none>
|
|
| 128 | - used items: <none>
|
|
| 129 | - object ‘isPrime_sat_@name_suffix@’:
|
|
| 84 | + used items: named item ‘primes’
|
|
| 85 | + object ‘isPrime_primes_sat_@name_suffix@’:
|
|
| 130 | 86 | arity: 1
|
| 131 | 87 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 132 | 88 | used items:
|
| 133 | - object ‘v_@name_suffix@’:
|
|
| 89 | + object ‘isPrime_primes_sat_@name_suffix@’:
|
|
| 134 | 90 | arity: 0
|
| 135 | 91 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 136 | 92 | used items:
|
| 137 | - named item ‘$fOrdNatural’
|
|
| 138 | - named item ‘(<=)’
|
|
| 139 | - object ‘v1_@name_suffix@’:
|
|
| 93 | + object ‘v_@name_suffix@’:
|
|
| 94 | + arity: 0
|
|
| 95 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 96 | + used items:
|
|
| 97 | + named item ‘$fIntegralInteger’
|
|
| 98 | + named item ‘$fNumNatural’
|
|
| 99 | + named item ‘(^)’
|
|
| 100 | + object ‘v1_@name_suffix@’:
|
|
| 101 | + arity: 0
|
|
| 102 | + literals:
|
|
| 103 | + label ‘_hpc_tickboxes_Example_hpc’
|
|
| 104 | + word 2
|
|
| 105 | + info table of ‘IS’
|
|
| 106 | + used items: <none>
|
|
| 107 | + object ‘pap_@name_suffix@’:
|
|
| 108 | + arity: 3
|
|
| 109 | + literals: <none>
|
|
| 110 | + used items: <none>
|
|
| 111 | + object ‘isPrime_primes_sat_@name_suffix@’:
|
|
| 140 | 112 | arity: 1
|
| 141 | 113 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 142 | - used items: <none>
|
|
| 114 | + used items:
|
|
| 115 | + object ‘v_@name_suffix@’:
|
|
| 116 | + arity: 0
|
|
| 117 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 118 | + used items:
|
|
| 119 | + named item ‘$fOrdNatural’
|
|
| 120 | + named item ‘(<=)’
|
|
| 121 | + object ‘v1_@name_suffix@’:
|
|
| 122 | + arity: 1
|
|
| 123 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 124 | + used items: <none>
|
|
| 125 | + object ‘pap_@name_suffix@’:
|
|
| 126 | + arity: 3
|
|
| 127 | + literals: <none>
|
|
| 128 | + used items: <none>
|
|
| 129 | + named item ‘(.)’
|
|
| 130 | + named item ‘takeWhile’
|
|
| 131 | + object ‘isPrime_primes_sat_@name_suffix@’:
|
|
| 132 | + arity: 1
|
|
| 133 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 134 | + used items:
|
|
| 135 | + object ‘v_@name_suffix@’:
|
|
| 136 | + arity: 0
|
|
| 137 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 138 | + used items:
|
|
| 143 | 139 | object ‘pap_@name_suffix@’:
|
| 144 | - arity: 3
|
|
| 140 | + arity: 2
|
|
| 145 | 141 | literals: <none>
|
| 146 | - used items: <none>
|
|
| 147 | - named item ‘(.)’
|
|
| 148 | - named item ‘takeWhile’
|
|
| 149 | - object ‘isPrime_sat_@name_suffix@’:
|
|
| 150 | - arity: 1
|
|
| 142 | + used items:
|
|
| 143 | + named item ‘$fIntegralNatural’
|
|
| 144 | + named item ‘divides’
|
|
| 145 | + object ‘v1_@name_suffix@’:
|
|
| 146 | + arity: 1
|
|
| 147 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 148 | + used items: <none>
|
|
| 149 | + object ‘pap_@name_suffix@’:
|
|
| 150 | + arity: 3
|
|
| 151 | + literals: <none>
|
|
| 152 | + used items: <none>
|
|
| 153 | + named item ‘$fFoldableList’
|
|
| 154 | + named item ‘any’
|
|
| 155 | + named item ‘not’
|
|
| 156 | + object ‘primes_sat_@name_suffix@’:
|
|
| 157 | + arity: 1
|
|
| 158 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 159 | + used items:
|
|
| 160 | + object ‘primes_sat_@name_suffix@’:
|
|
| 161 | + arity: 0
|
|
| 151 | 162 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 152 | 163 | used items:
|
| 153 | - object ‘v_@name_suffix@’:
|
|
| 164 | + object ‘primes_sat_@name_suffix@’:
|
|
| 154 | 165 | arity: 0
|
| 155 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 166 | + literals:
|
|
| 167 | + label ‘_hpc_tickboxes_Example_hpc’
|
|
| 168 | + word 3
|
|
| 169 | + info table of ‘IS’
|
|
| 156 | 170 | used items:
|
| 157 | - object ‘pap_@name_suffix@’:
|
|
| 158 | - arity: 2
|
|
| 159 | - literals: <none>
|
|
| 160 | - used items:
|
|
| 161 | - named item ‘$fIntegralNatural’
|
|
| 162 | - named item ‘divides’
|
|
| 163 | - object ‘v1_@name_suffix@’:
|
|
| 164 | - arity: 1
|
|
| 165 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 166 | - used items: <none>
|
|
| 167 | - object ‘pap_@name_suffix@’:
|
|
| 168 | - arity: 3
|
|
| 169 | - literals: <none>
|
|
| 170 | - used items: <none>
|
|
| 171 | - named item ‘$fFoldableList’
|
|
| 172 | - named item ‘any’
|
|
| 173 | - named item ‘not’
|
|
| 174 | - object ‘primes’:
|
|
| 175 | - arity: 0
|
|
| 176 | - literals:
|
|
| 177 | - label ‘_hpc_tickboxes_Example_hpc’
|
|
| 178 | - info table of ‘(:)’
|
|
| 179 | - used items:
|
|
| 180 | - named item ‘primes2_@name_suffix@’
|
|
| 181 | - named item ‘primes1_@name_suffix@’
|
|
| 182 | - object ‘primes1_@name_suffix@’:
|
|
| 183 | - arity: 0
|
|
| 184 | - literals:
|
|
| 185 | - label ‘_hpc_tickboxes_Example_hpc’
|
|
| 186 | - word 2
|
|
| 187 | - info table of ‘IS’
|
|
| 188 | - used items:
|
|
| 189 | - named item ‘$fNumNatural’
|
|
| 190 | - named item ‘fromInteger’
|
|
| 171 | + named item ‘$fNumNatural’
|
|
| 172 | + named item ‘fromInteger’
|
|
| 173 | + named item ‘$fEnumNatural’
|
|
| 174 | + named item ‘enumFrom’
|
|
| 175 | + object ‘primes_sat_@name_suffix@’:
|
|
| 176 | + arity: 1
|
|
| 177 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 178 | + used items: <none>
|
|
| 179 | + named item ‘filter’
|
|
| 180 | + object ‘primes_sat_@name_suffix@’:
|
|
| 181 | + arity: 0
|
|
| 182 | + literals:
|
|
| 183 | + label ‘_hpc_tickboxes_Example_hpc’
|
|
| 184 | + word 2
|
|
| 185 | + info table of ‘IS’
|
|
| 186 | + used items:
|
|
| 187 | + named item ‘$fNumNatural’
|
|
| 188 | + named item ‘fromInteger’
|
|
| 191 | 189 | object ‘fibonaccisPtr’:
|
| 192 | 190 | arity: 0
|
| 193 | 191 | literals:
|
| ... | ... | @@ -245,63 +243,59 @@ objects: |
| 245 | 243 | arity: 0
|
| 246 | 244 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 247 | 245 | used items: named item ‘fibonaccis’
|
| 248 | - object ‘positiveFibonaccis1_@name_suffix@’:
|
|
| 246 | + object ‘fibonaccis’:
|
|
| 249 | 247 | arity: 0
|
| 250 | 248 | literals:
|
| 251 | 249 | label ‘_hpc_tickboxes_Example_hpc’
|
| 252 | 250 | info table of ‘(:)’
|
| 253 | 251 | used items:
|
| 254 | - named item ‘positiveFibonaccis2_@name_suffix@’
|
|
| 255 | - named item ‘positiveFibonaccis_@name_suffix@’
|
|
| 256 | - object ‘positiveFibonaccis2_@name_suffix@’:
|
|
| 257 | - arity: 0
|
|
| 258 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 259 | - used items:
|
|
| 260 | - object ‘positiveFibonaccis2_sat_@name_suffix@’:
|
|
| 261 | - arity: 0
|
|
| 262 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 263 | - used items: named item ‘positiveFibonaccis1_@name_suffix@’
|
|
| 264 | - object ‘positiveFibonaccis2_sat_@name_suffix@’:
|
|
| 265 | - arity: 0
|
|
| 252 | + object ‘positiveFibonaccis_@name_suffix@’:
|
|
| 253 | + arity: 1
|
|
| 254 | + literals:
|
|
| 255 | + label ‘_hpc_tickboxes_Example_hpc’
|
|
| 256 | + info table of ‘(:)’
|
|
| 257 | + used items:
|
|
| 258 | + object ‘positiveFibonaccis_fibonaccis_sat_@name_suffix@’:
|
|
| 259 | + arity: 1
|
|
| 260 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 261 | + used items:
|
|
| 262 | + object ‘positiveFibonaccis_fibonaccis_sat_@name_suffix@’:
|
|
| 263 | + arity: 1
|
|
| 264 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 265 | + used items: <none>
|
|
| 266 | + object ‘positiveFibonaccis_fibonaccis_sat_@name_suffix@’:
|
|
| 267 | + arity: 0
|
|
| 268 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 269 | + used items: named item ‘fibonaccis’
|
|
| 270 | + object ‘positiveFibonaccis_fibonaccis_sat_@name_suffix@’:
|
|
| 271 | + arity: 0
|
|
| 272 | + literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 273 | + used items:
|
|
| 274 | + named item ‘$fNumNatural’
|
|
| 275 | + named item ‘(+)’
|
|
| 276 | + named item ‘zipWith’
|
|
| 277 | + object ‘positiveFibonaccis_fibonaccis_sat_@name_suffix@’:
|
|
| 278 | + arity: 0
|
|
| 279 | + literals:
|
|
| 280 | + label ‘_hpc_tickboxes_Example_hpc’
|
|
| 281 | + word 1
|
|
| 282 | + info table of ‘IS’
|
|
| 283 | + used items:
|
|
| 284 | + named item ‘$fNumNatural’
|
|
| 285 | + named item ‘fromInteger’
|
|
| 286 | + object ‘fibonaccis_sat_@name_suffix@’:
|
|
| 287 | + arity: 1
|
|
| 266 | 288 | literals: label ‘_hpc_tickboxes_Example_hpc’
|
| 267 | - used items: named item ‘fibonaccis’
|
|
| 268 | - object ‘positiveFibonaccis2_sat_@name_suffix@’:
|
|
| 289 | + used items: <none>
|
|
| 290 | + object ‘fibonaccis_sat_@name_suffix@’:
|
|
| 269 | 291 | arity: 0
|
| 270 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 292 | + literals:
|
|
| 293 | + label ‘_hpc_tickboxes_Example_hpc’
|
|
| 294 | + word 0
|
|
| 295 | + info table of ‘IS’
|
|
| 271 | 296 | used items:
|
| 272 | 297 | named item ‘$fNumNatural’
|
| 273 | - named item ‘(+)’
|
|
| 274 | - named item ‘zipWith’
|
|
| 275 | - object ‘fibonaccis’:
|
|
| 276 | - arity: 0
|
|
| 277 | - literals:
|
|
| 278 | - label ‘_hpc_tickboxes_Example_hpc’
|
|
| 279 | - info table of ‘(:)’
|
|
| 280 | - used items:
|
|
| 281 | - named item ‘fibonaccis2_@name_suffix@’
|
|
| 282 | - named item ‘fibonaccis1_@name_suffix@’
|
|
| 283 | - object ‘fibonaccis2_@name_suffix@’:
|
|
| 284 | - arity: 0
|
|
| 285 | - literals: label ‘_hpc_tickboxes_Example_hpc’
|
|
| 286 | - used items: named item ‘positiveFibonaccis1_@name_suffix@’
|
|
| 287 | - object ‘positiveFibonaccis_@name_suffix@’:
|
|
| 288 | - arity: 0
|
|
| 289 | - literals:
|
|
| 290 | - label ‘_hpc_tickboxes_Example_hpc’
|
|
| 291 | - word 1
|
|
| 292 | - info table of ‘IS’
|
|
| 293 | - used items:
|
|
| 294 | - named item ‘$fNumNatural’
|
|
| 295 | - named item ‘fromInteger’
|
|
| 296 | - object ‘fibonaccis1_@name_suffix@’:
|
|
| 297 | - arity: 0
|
|
| 298 | - literals:
|
|
| 299 | - label ‘_hpc_tickboxes_Example_hpc’
|
|
| 300 | - word 0
|
|
| 301 | - info table of ‘IS’
|
|
| 302 | - used items:
|
|
| 303 | - named item ‘$fNumNatural’
|
|
| 304 | - named item ‘fromInteger’
|
|
| 298 | + named item ‘fromInteger’
|
|
| 305 | 299 | object ‘$dTypeable2_@name_suffix@’:
|
| 306 | 300 | arity: 0
|
| 307 | 301 | literals: <none>
|