Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
-
e9623c94
by Simon Peyton Jones at 2026-03-31T21:01:01+01:00
-
3a33983b
by Simon Peyton Jones at 2026-03-31T21:01:02+01:00
-
690acec9
by Simon Peyton Jones at 2026-03-31T21:01:02+01:00
-
c7ac6d41
by Simon Jakobi at 2026-03-31T19:20:43-04:00
20 changed files:
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/Core/Opt/Arity.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/Tidy.hs
- compiler/GHC/Core/Unfold.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Driver/Main.hs
- compiler/GHC/Stg/Lint.hs
- compiler/GHC/Types/Id.hs
- compiler/GHC/Types/Id/Info.hs
- testsuite/tests/arityanal/should_compile/Arity01.stderr
- testsuite/tests/arityanal/should_compile/Arity05.stderr
- testsuite/tests/arityanal/should_compile/Arity08.stderr
- testsuite/tests/arityanal/should_compile/Arity11.stderr
- testsuite/tests/arityanal/should_compile/Arity14.stderr
- + testsuite/tests/perf/compiler/T13960.hs
- testsuite/tests/perf/compiler/all.T
- testsuite/tests/simplCore/should_compile/T15205.stderr
- testsuite/tests/wasm/should_run/control-flow/LoadCmmGroup.hs
Changes:
| ... | ... | @@ -807,16 +807,23 @@ the former has an additional type binder. Hmmm.... |
| 807 | 807 | |
| 808 | 808 | Note [Eta expanding primops]
|
| 809 | 809 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 810 | - |
|
| 811 | 810 | STG requires that primop applications be saturated. This makes code generation
|
| 812 | 811 | significantly simpler since otherwise we would need to define a calling
|
| 813 | 812 | convention for curried applications that can accommodate representation
|
| 814 | 813 | polymorphism.
|
| 815 | 814 | |
| 816 | -To ensure saturation, CorePrep eta expands all primop applications as
|
|
| 817 | -described in Note [Eta expansion of hasNoBinding things in CorePrep] in
|
|
| 815 | +To ensure saturation, CorePrep eta expands all primop applications
|
|
| 816 | +as described in Note [Eta expansion of unsaturated calls] in
|
|
| 818 | 817 | GHC.Core.Prep.
|
| 819 | 818 | |
| 819 | +Side note: this decision is somewhat in flux: see comments with `hasNoBinding`.
|
|
| 820 | +The question is: do we generate a trivial wrapper for each primop
|
|
| 821 | + (+#) x y = (+#) x y
|
|
| 822 | +and now we can call that wrapper unsaturated. But in practice we
|
|
| 823 | +might never call it because in practice Prep eta-expands all partial
|
|
| 824 | +applications!
|
|
| 825 | + |
|
| 826 | + |
|
| 820 | 827 | Historical Note:
|
| 821 | 828 | |
| 822 | 829 | For a short period around GHC 8.8 we rewrote unsaturated primop applications to
|
| ... | ... | @@ -2551,9 +2551,6 @@ This reduces clutter, sometimes a lot. See Note [Do not eta-expand PAPs] |
| 2551 | 2551 | in GHC.Core.Opt.Simplify.Utils, where we are careful not to eta-expand
|
| 2552 | 2552 | a PAP. If eta-expanding is bad, then eta-reducing is good!
|
| 2553 | 2553 | |
| 2554 | -Also the code generator likes eta-reduced PAPs; see GHC.CoreToStg.Prep
|
|
| 2555 | -Note [No eta reduction needed in rhsToBody].
|
|
| 2556 | - |
|
| 2557 | 2554 | But note that we don't want to eta-reduce
|
| 2558 | 2555 | \x y. f <expensive> x y
|
| 2559 | 2556 | to
|
| ... | ... | @@ -3247,9 +3247,14 @@ case we can clearly specialise. But there are wrinkles: |
| 3247 | 3247 | |
| 3248 | 3248 | (ID6) The Main Plan says that it's worth specialising if the argument is an application
|
| 3249 | 3249 | of a dictionary contructor. But what if the dictionary has no methods? Then we
|
| 3250 | - gain nothing by specialising, unless the /superclasses/ are interesting. A case
|
|
| 3251 | - in point is constraint tuples (% d1, .., dn %); a constraint N-tuple is a class
|
|
| 3252 | - with N superclasses and no methods.
|
|
| 3250 | + gain nothing by specialising, unless the /superclasses/ are interesting.
|
|
| 3251 | + |
|
| 3252 | + So if there are no methods, we recursively call `interestingDict` on the
|
|
| 3253 | + superclasses. Why recurse? If we have
|
|
| 3254 | + \d1 d2. f (CTuple d1 d2)
|
|
| 3255 | + If `d1 and `d2` are uninteresting dictionaries, then so is (CTuple d1 d2).
|
|
| 3256 | + (Remember: a constraint tuple is just a class with N superclasses and no methods.)
|
|
| 3257 | + See discussion on #26831.
|
|
| 3253 | 3258 | |
| 3254 | 3259 | (ID7) A unary (single-method) class is currently represented by (meth |> co). We
|
| 3255 | 3260 | will unwrap the cast (see (ID5)) and then want to reply "yes" if the method
|
| ... | ... | @@ -165,6 +165,7 @@ computeCbvInfo fun_id rhs |
| 165 | 165 | map mkMark val_args
|
| 166 | 166 | |
| 167 | 167 | cbv_bndr | any isMarkedCbv cbv_marks
|
| 168 | + -- isMarkedCbv: see (CBV2) in Note [CBV Function Ids: overview]
|
|
| 168 | 169 | = cbv_marks `seqList` setIdCbvMarks fun_id cbv_marks
|
| 169 | 170 | -- seqList: avoid retaining the original rhs
|
| 170 | 171 | |
| ... | ... | @@ -176,6 +177,7 @@ computeCbvInfo fun_id rhs |
| 176 | 177 | -- We don't set CBV marks on functions which take unboxed tuples or sums as
|
| 177 | 178 | -- arguments. Doing so would require us to compute the result of unarise
|
| 178 | 179 | -- here in order to properly determine argument positions at runtime.
|
| 180 | + -- See (CBV1) in Note [CBV Function Ids: overview]
|
|
| 179 | 181 | --
|
| 180 | 182 | -- In practice this doesn't matter much. Most "interesting" functions will
|
| 181 | 183 | -- get a W/W split which will eliminate unboxed tuple arguments, and unboxed
|
| ... | ... | @@ -779,22 +779,28 @@ litSize _other = 0 -- Must match size of nullary constructors |
| 779 | 779 | |
| 780 | 780 | classOpSize :: UnfoldingOpts -> Class -> [Id] -> [CoreExpr] -> ExprSize
|
| 781 | 781 | -- See (IA1) in Note [Interesting arguments] in GHC.Core.Opt.Simplify.Utils
|
| 782 | -classOpSize opts cls top_args args
|
|
| 783 | - | isUnaryClass cls
|
|
| 784 | - = sizeZero -- See (UCM4) in Note [Unary class magic] in GHC.Core.TyCon
|
|
| 785 | - | otherwise
|
|
| 786 | - = case args of
|
|
| 787 | - [] -> sizeZero
|
|
| 788 | - (arg1:other_args) -> SizeIs (size other_args) (arg_discount arg1) 0
|
|
| 782 | +classOpSize _opts _cls _top_args []
|
|
| 783 | + = sizeZero -- A non-applied classop
|
|
| 784 | +classOpSize opts cls top_args (dict_arg:other_val_args)
|
|
| 785 | + = SizeIs size (arg_discount dict_arg) 0
|
|
| 789 | 786 | where
|
| 790 | - size other_args = 20 + (10 * length other_args)
|
|
| 787 | + size | isUnaryClass cls = 0 -- See (UCM4) in Note [Unary class magic] in GHC.Core.TyCon
|
|
| 788 | + | otherwise = 20 + (10 * length other_val_args)
|
|
| 791 | 789 | |
| 792 | 790 | -- If the class op is scrutinising a lambda bound dictionary then
|
| 793 | 791 | -- give it a discount, to encourage the inlining of this function
|
| 794 | - -- The actual discount is rather arbitrarily chosen
|
|
| 795 | - arg_discount (Var dict) | dict `elem` top_args
|
|
| 796 | - = unitBag (dict, unfoldingDictDiscount opts)
|
|
| 797 | - arg_discount _ = emptyBag
|
|
| 792 | + arg_discount (Cast arg _co) = arg_discount arg
|
|
| 793 | + arg_discount (Var dict) | dict `elem` top_args = unitBag (dict, dict_discount)
|
|
| 794 | + arg_discount _ = emptyBag
|
|
| 795 | + |
|
| 796 | + -- If we have (class-op d arg1 .. argn) then it's super-good to inline
|
|
| 797 | + -- to expose `d`; not only can we do the dictionary selection
|
|
| 798 | + -- (class-op d), but that will likely expose a lambda which we can then
|
|
| 799 | + -- apply. In that case (n > 0), we add `unfoldingFunAppDiscount`.
|
|
| 800 | + -- See the discussion on #26831, esp "Delicate inlining".
|
|
| 801 | + dict_discount
|
|
| 802 | + | null other_val_args = unfoldingDictDiscount opts
|
|
| 803 | + | otherwise = unfoldingDictDiscount opts + unfoldingFunAppDiscount opts
|
|
| 798 | 804 | |
| 799 | 805 | -- | The size of a function call
|
| 800 | 806 | callSize
|
| ... | ... | @@ -39,6 +39,8 @@ import GHC.Types.Basic ( Arity, TypeOrConstraint(..) ) |
| 39 | 39 | import GHC.Types.Literal
|
| 40 | 40 | import GHC.Types.ForeignCall
|
| 41 | 41 | import GHC.Types.IPE
|
| 42 | +import GHC.Types.Unique.Supply
|
|
| 43 | +import GHC.Types.Unique
|
|
| 42 | 44 | |
| 43 | 45 | import GHC.Unit.Module
|
| 44 | 46 | import GHC.Platform ( Platform )
|
| ... | ... | @@ -49,297 +51,309 @@ import GHC.Utils.Outputable |
| 49 | 51 | import GHC.Utils.Monad
|
| 50 | 52 | import GHC.Utils.Misc (HasDebugCallStack)
|
| 51 | 53 | import GHC.Utils.Panic
|
| 54 | +import GHC.Data.FastString
|
|
| 52 | 55 | |
| 53 | 56 | import Control.Monad (ap)
|
| 54 | 57 | |
| 55 | --- Note [Live vs free]
|
|
| 56 | --- ~~~~~~~~~~~~~~~~~~~
|
|
| 57 | ---
|
|
| 58 | --- The two are not the same. Liveness is an operational property rather
|
|
| 59 | --- than a semantic one. A variable is live at a particular execution
|
|
| 60 | --- point if it can be referred to directly again. In particular, a dead
|
|
| 61 | --- variable's stack slot (if it has one):
|
|
| 62 | ---
|
|
| 63 | --- - should be stubbed to avoid space leaks, and
|
|
| 64 | --- - may be reused for something else.
|
|
| 65 | ---
|
|
| 66 | --- There ought to be a better way to say this. Here are some examples:
|
|
| 67 | ---
|
|
| 68 | --- let v = [q] \[x] -> e
|
|
| 69 | --- in
|
|
| 70 | --- ...v... (but no q's)
|
|
| 71 | ---
|
|
| 72 | --- Just after the `in', v is live, but q is dead. If the whole of that
|
|
| 73 | --- let expression was enclosed in a case expression, thus:
|
|
| 74 | ---
|
|
| 75 | --- case (let v = [q] \[x] -> e in ...v...) of
|
|
| 76 | --- alts[...q...]
|
|
| 77 | ---
|
|
| 78 | --- (ie `alts' mention `q'), then `q' is live even after the `in'; because
|
|
| 79 | --- we'll return later to the `alts' and need it.
|
|
| 80 | ---
|
|
| 81 | --- Let-no-escapes make this a bit more interesting:
|
|
| 82 | ---
|
|
| 83 | --- let-no-escape v = [q] \ [x] -> e
|
|
| 84 | --- in
|
|
| 85 | --- ...v...
|
|
| 86 | ---
|
|
| 87 | --- Here, `q' is still live at the `in', because `v' is represented not by
|
|
| 88 | --- a closure but by the current stack state. In other words, if `v' is
|
|
| 89 | --- live then so is `q'. Furthermore, if `e' mentions an enclosing
|
|
| 90 | --- let-no-escaped variable, then its free variables are also live if `v' is.
|
|
| 58 | +{- Note [Live vs free]
|
|
| 59 | +~~~~~~~~~~~~~~~~~~~~~~
|
|
| 60 | +The two are not the same. Liveness is an operational property rather
|
|
| 61 | +than a semantic one. A variable is live at a particular execution
|
|
| 62 | +point if it can be referred to directly again. In particular, a dead
|
|
| 63 | +variable's stack slot (if it has one):
|
|
| 91 | 64 | |
| 92 | --- Note [What are these SRTs all about?]
|
|
| 93 | --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 94 | ---
|
|
| 95 | --- Consider the Core program,
|
|
| 96 | ---
|
|
| 97 | --- fibs = go 1 1
|
|
| 98 | --- where go a b = let c = a + c
|
|
| 99 | --- in c : go b c
|
|
| 100 | --- add x = map (\y -> x*y) fibs
|
|
| 101 | ---
|
|
| 102 | --- In this case we have a CAF, 'fibs', which is quite large after evaluation and
|
|
| 103 | --- has only one possible user, 'add'. Consequently, we want to ensure that when
|
|
| 104 | --- all references to 'add' die we can garbage collect any bit of 'fibs' that we
|
|
| 105 | --- have evaluated.
|
|
| 106 | ---
|
|
| 107 | --- However, how do we know whether there are any references to 'fibs' still
|
|
| 108 | --- around? Afterall, the only reference to it is buried in the code generated
|
|
| 109 | --- for 'add'. The answer is that we record the CAFs referred to by a definition
|
|
| 110 | --- in its info table, namely a part of it known as the Static Reference Table
|
|
| 111 | --- (SRT).
|
|
| 112 | ---
|
|
| 113 | --- Since SRTs are so common, we use a special compact encoding for them in: we
|
|
| 114 | --- produce one table containing a list of CAFs in a module and then include a
|
|
| 115 | --- bitmap in each info table describing which entries of this table the closure
|
|
| 116 | --- references.
|
|
| 117 | ---
|
|
| 118 | --- See also: commentary/rts/storage/gc/CAFs on the GHC Wiki.
|
|
| 65 | + - should be stubbed to avoid space leaks, and
|
|
| 66 | + - may be reused for something else.
|
|
| 119 | 67 | |
| 120 | --- Note [What is a non-escaping let]
|
|
| 121 | --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 122 | ---
|
|
| 123 | --- NB: Nowadays this is recognized by the occurrence analyser by turning a
|
|
| 124 | --- "non-escaping let" into a join point. The following is then an operational
|
|
| 125 | --- account of join points.
|
|
| 126 | ---
|
|
| 127 | --- Consider:
|
|
| 128 | ---
|
|
| 129 | --- let x = fvs \ args -> e
|
|
| 130 | --- in
|
|
| 131 | --- if ... then x else
|
|
| 132 | --- if ... then x else ...
|
|
| 133 | ---
|
|
| 134 | --- `x' is used twice (so we probably can't unfold it), but when it is
|
|
| 135 | --- entered, the stack is deeper than it was when the definition of `x'
|
|
| 136 | --- happened. Specifically, if instead of allocating a closure for `x',
|
|
| 137 | --- we saved all `x's fvs on the stack, and remembered the stack depth at
|
|
| 138 | --- that moment, then whenever we enter `x' we can simply set the stack
|
|
| 139 | --- pointer(s) to these remembered (compile-time-fixed) values, and jump
|
|
| 140 | --- to the code for `x'.
|
|
| 141 | ---
|
|
| 142 | --- All of this is provided x is:
|
|
| 143 | --- 1. non-updatable;
|
|
| 144 | --- 2. guaranteed to be entered before the stack retreats -- ie x is not
|
|
| 145 | --- buried in a heap-allocated closure, or passed as an argument to
|
|
| 146 | --- something;
|
|
| 147 | --- 3. all the enters have exactly the right number of arguments,
|
|
| 148 | --- no more no less;
|
|
| 149 | --- 4. all the enters are tail calls; that is, they return to the
|
|
| 150 | --- caller enclosing the definition of `x'.
|
|
| 151 | ---
|
|
| 152 | --- Under these circumstances we say that `x' is non-escaping.
|
|
| 153 | ---
|
|
| 154 | --- An example of when (4) does not hold:
|
|
| 155 | ---
|
|
| 156 | --- let x = ...
|
|
| 157 | --- in case x of ...alts...
|
|
| 158 | ---
|
|
| 159 | --- Here, `x' is certainly entered only when the stack is deeper than when
|
|
| 160 | --- `x' is defined, but here it must return to ...alts... So we can't just
|
|
| 161 | --- adjust the stack down to `x''s recalled points, because that would lost
|
|
| 162 | --- alts' context.
|
|
| 163 | ---
|
|
| 164 | --- Things can get a little more complicated. Consider:
|
|
| 165 | ---
|
|
| 166 | --- let y = ...
|
|
| 167 | --- in let x = fvs \ args -> ...y...
|
|
| 168 | --- in ...x...
|
|
| 169 | ---
|
|
| 170 | --- Now, if `x' is used in a non-escaping way in ...x..., and `y' is used in a
|
|
| 171 | --- non-escaping way in ...y..., then `y' is non-escaping.
|
|
| 172 | ---
|
|
| 173 | --- `x' can even be recursive! Eg:
|
|
| 174 | ---
|
|
| 175 | --- letrec x = [y] \ [v] -> if v then x True else ...
|
|
| 176 | --- in
|
|
| 177 | --- ...(x b)...
|
|
| 68 | +There ought to be a better way to say this. Here are some examples:
|
|
| 178 | 69 | |
| 179 | --- Note [Cost-centre initialization plan]
|
|
| 180 | --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 181 | ---
|
|
| 182 | --- Previously `coreToStg` was initializing cost-centre stack fields as `noCCS`,
|
|
| 183 | --- and the fields were then fixed by a separate pass `stgMassageForProfiling`.
|
|
| 184 | --- We now initialize these correctly. The initialization works like this:
|
|
| 185 | ---
|
|
| 186 | --- - For non-top level bindings always use `currentCCS`.
|
|
| 187 | ---
|
|
| 188 | --- - For top-level bindings, check if the binding is a CAF
|
|
| 189 | ---
|
|
| 190 | --- - CAF: If -fcaf-all is enabled, create a new CAF just for this CAF
|
|
| 191 | --- and use it. Note that these new cost centres need to be
|
|
| 192 | --- collected to be able to generate cost centre initialization
|
|
| 193 | --- code, so `coreToTopStgRhs` now returns `CollectedCCs`.
|
|
| 194 | ---
|
|
| 195 | --- If -fcaf-all is not enabled, use "all CAFs" cost centre.
|
|
| 196 | ---
|
|
| 197 | --- - Non-CAF: Top-level (static) data is not counted in heap profiles; nor
|
|
| 198 | --- do we set CCCS from it; so we just slam in
|
|
| 199 | --- dontCareCostCentre.
|
|
| 200 | - |
|
| 201 | --- Note [Coercion tokens]
|
|
| 202 | --- ~~~~~~~~~~~~~~~~~~~~~~
|
|
| 203 | --- In coreToStgArgs, we drop type arguments completely, but we replace
|
|
| 204 | --- coercions with a special coercionToken# placeholder. Why? Consider:
|
|
| 205 | ---
|
|
| 206 | --- f :: forall a. Int ~# Bool -> a
|
|
| 207 | --- f = /\a. \(co :: Int ~# Bool) -> error "impossible"
|
|
| 208 | ---
|
|
| 209 | --- If we erased the coercion argument completely, we’d end up with just
|
|
| 210 | --- f = error "impossible", but then f `seq` () would be ⊥!
|
|
| 211 | ---
|
|
| 212 | --- This is an artificial example, but back in the day we *did* treat
|
|
| 213 | --- coercion lambdas like type lambdas, and we had bug reports as a
|
|
| 214 | --- result. So now we treat coercion lambdas like value lambdas, but we
|
|
| 215 | --- treat coercions themselves as zero-width arguments — coercionToken#
|
|
| 216 | --- has representation VoidRep — which gets the best of both worlds.
|
|
| 217 | ---
|
|
| 218 | --- (For the gory details, see also the (unpublished) paper, “Practical
|
|
| 219 | --- aspects of evidence-based compilation in System FC.”)
|
|
| 70 | + let v = [q] \[x] -> e
|
|
| 71 | + in
|
|
| 72 | + ...v... (but no q's)
|
|
| 220 | 73 | |
| 221 | --- Note [Saturation of data constructors in STG]
|
|
| 222 | --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 223 | --- We guarantee that `StgConApp` is an exactly-saturated application of a data
|
|
| 224 | --- constructor worker.
|
|
| 225 | ---
|
|
| 226 | --- * If the data constructor is /under/-saturated we just fall through to build
|
|
| 227 | --- a `StgApp`. Remember, data constructor workers have a regular top-level definition
|
|
| 228 | --- (injected by GHC.CoreToStg.Prep.mkDataConWorkers) so we can partially apply
|
|
| 229 | --- that function.
|
|
| 230 | ---
|
|
| 231 | --- * If the data constructor is /over/-saturated, which can happen (see #23865) we again
|
|
| 232 | --- fall through to `StgApp`. That will fail horribly at runtime (by applying data
|
|
| 233 | --- constructor to an argument) but it should be in dead code, and at least the compiler
|
|
| 234 | --- itself won't crash. (We could inject an error-thunk instead.)
|
|
| 74 | +Just after the `in', v is live, but q is dead. If the whole of that
|
|
| 75 | +let expression was enclosed in a case expression, thus:
|
|
| 76 | + |
|
| 77 | + case (let v = [q] \[x] -> e in ...v...) of
|
|
| 78 | + alts[...q...]
|
|
| 79 | + |
|
| 80 | +(ie `alts' mention `q'), then `q' is live even after the `in'; because
|
|
| 81 | +we'll return later to the `alts' and need it.
|
|
| 82 | + |
|
| 83 | +Let-no-escapes make this a bit more interesting:
|
|
| 84 | + |
|
| 85 | + let-no-escape v = [q] \ [x] -> e
|
|
| 86 | + in
|
|
| 87 | + ...v...
|
|
| 88 | + |
|
| 89 | +Here, `q' is still live at the `in', because `v' is represented not by
|
|
| 90 | +a closure but by the current stack state. In other words, if `v' is
|
|
| 91 | +live then so is `q'. Furthermore, if `e' mentions an enclosing
|
|
| 92 | +let-no-escaped variable, then its free variables are also live if `v' is.
|
|
| 93 | + |
|
| 94 | +Note [What are these SRTs all about?]
|
|
| 95 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 96 | + |
|
| 97 | +Consider the Core program,
|
|
| 98 | + |
|
| 99 | + fibs = go 1 1
|
|
| 100 | + where go a b = let c = a + c
|
|
| 101 | + in c : go b c
|
|
| 102 | + add x = map (\y -> x*y) fibs
|
|
| 103 | + |
|
| 104 | +In this case we have a CAF, 'fibs', which is quite large after evaluation and
|
|
| 105 | +has only one possible user, 'add'. Consequently, we want to ensure that when
|
|
| 106 | +all references to 'add' die we can garbage collect any bit of 'fibs' that we
|
|
| 107 | +have evaluated.
|
|
| 108 | + |
|
| 109 | +However, how do we know whether there are any references to 'fibs' still
|
|
| 110 | +around? Afterall, the only reference to it is buried in the code generated
|
|
| 111 | +for 'add'. The answer is that we record the CAFs referred to by a definition
|
|
| 112 | +in its info table, namely a part of it known as the Static Reference Table
|
|
| 113 | +(SRT).
|
|
| 235 | 114 | |
| 115 | +Since SRTs are so common, we use a special compact encoding for them in: we
|
|
| 116 | +produce one table containing a list of CAFs in a module and then include a
|
|
| 117 | +bitmap in each info table describing which entries of this table the closure
|
|
| 118 | +references.
|
|
| 119 | + |
|
| 120 | +See also: commentary/rts/storage/gc/CAFs on the GHC Wiki.
|
|
| 121 | + |
|
| 122 | +Note [What is a non-escaping let]
|
|
| 123 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 124 | + |
|
| 125 | +NB: Nowadays this is recognized by the occurrence analyser by turning a
|
|
| 126 | +"non-escaping let" into a join point. The following is then an operational
|
|
| 127 | +account of join points.
|
|
| 128 | + |
|
| 129 | +Consider:
|
|
| 130 | + |
|
| 131 | + let x = fvs \ args -> e
|
|
| 132 | + in
|
|
| 133 | + if ... then x else
|
|
| 134 | + if ... then x else ...
|
|
| 135 | + |
|
| 136 | +`x' is used twice (so we probably can't unfold it), but when it is
|
|
| 137 | +entered, the stack is deeper than it was when the definition of `x'
|
|
| 138 | +happened. Specifically, if instead of allocating a closure for `x',
|
|
| 139 | +we saved all `x's fvs on the stack, and remembered the stack depth at
|
|
| 140 | +that moment, then whenever we enter `x' we can simply set the stack
|
|
| 141 | +pointer(s) to these remembered (compile-time-fixed) values, and jump
|
|
| 142 | +to the code for `x'.
|
|
| 143 | + |
|
| 144 | +All of this is provided x is:
|
|
| 145 | + 1. non-updatable;
|
|
| 146 | + 2. guaranteed to be entered before the stack retreats -- ie x is not
|
|
| 147 | + buried in a heap-allocated closure, or passed as an argument to
|
|
| 148 | + something;
|
|
| 149 | + 3. all the enters have exactly the right number of arguments,
|
|
| 150 | + no more no less;
|
|
| 151 | + 4. all the enters are tail calls; that is, they return to the
|
|
| 152 | + caller enclosing the definition of `x'.
|
|
| 153 | + |
|
| 154 | +Under these circumstances we say that `x' is non-escaping.
|
|
| 155 | + |
|
| 156 | +An example of when (4) does not hold:
|
|
| 157 | + |
|
| 158 | + let x = ...
|
|
| 159 | + in case x of ...alts...
|
|
| 160 | + |
|
| 161 | +Here, `x' is certainly entered only when the stack is deeper than when
|
|
| 162 | +`x' is defined, but here it must return to ...alts... So we can't just
|
|
| 163 | +adjust the stack down to `x''s recalled points, because that would lost
|
|
| 164 | +alts' context.
|
|
| 165 | + |
|
| 166 | +Things can get a little more complicated. Consider:
|
|
| 167 | + |
|
| 168 | + let y = ...
|
|
| 169 | + in let x = fvs \ args -> ...y...
|
|
| 170 | + in ...x...
|
|
| 171 | + |
|
| 172 | +Now, if `x' is used in a non-escaping way in ...x..., and `y' is used in a
|
|
| 173 | +non-escaping way in ...y..., then `y' is non-escaping.
|
|
| 174 | + |
|
| 175 | +`x' can even be recursive! Eg:
|
|
| 176 | + |
|
| 177 | + letrec x = [y] \ [v] -> if v then x True else ...
|
|
| 178 | + in
|
|
| 179 | + ...(x b)...
|
|
| 180 | + |
|
| 181 | +Note [Cost-centre initialization plan]
|
|
| 182 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 183 | + |
|
| 184 | +Previously `coreToStg` was initializing cost-centre stack fields as `noCCS`,
|
|
| 185 | +and the fields were then fixed by a separate pass `stgMassageForProfiling`.
|
|
| 186 | +We now initialize these correctly. The initialization works like this:
|
|
| 187 | + |
|
| 188 | + - For non-top level bindings always use `currentCCS`.
|
|
| 189 | + |
|
| 190 | + - For top-level bindings, check if the binding is a CAF
|
|
| 191 | + |
|
| 192 | + - CAF: If -fcaf-all is enabled, create a new CAF just for this CAF
|
|
| 193 | + and use it. Note that these new cost centres need to be
|
|
| 194 | + collected to be able to generate cost centre initialization
|
|
| 195 | + code, so `coreToTopStgRhs` now returns `CollectedCCs`.
|
|
| 196 | + |
|
| 197 | + If -fcaf-all is not enabled, use "all CAFs" cost centre.
|
|
| 198 | + |
|
| 199 | + - Non-CAF: Top-level (static) data is not counted in heap profiles; nor
|
|
| 200 | + do we set CCCS from it; so we just slam in
|
|
| 201 | + dontCareCostCentre.
|
|
| 202 | + |
|
| 203 | +Note [Coercion tokens]
|
|
| 204 | +~~~~~~~~~~~~~~~~~~~~~~
|
|
| 205 | +In coreToStgArgs, we drop type arguments completely, but we replace
|
|
| 206 | +coercions with a special coercionToken# placeholder. Why? Consider:
|
|
| 207 | + |
|
| 208 | + f :: forall a. Int ~# Bool -> a
|
|
| 209 | + f = /\a. \(co :: Int ~# Bool) -> error "impossible"
|
|
| 210 | + |
|
| 211 | +If we erased the coercion argument completely, we’d end up with just
|
|
| 212 | +f = error "impossible", but then f `seq` () would be ⊥!
|
|
| 213 | + |
|
| 214 | +This is an artificial example, but back in the day we *did* treat
|
|
| 215 | +coercion lambdas like type lambdas, and we had bug reports as a
|
|
| 216 | +result. So now we treat coercion lambdas like value lambdas, but we
|
|
| 217 | +treat coercions themselves as zero-width arguments — coercionToken#
|
|
| 218 | +has representation VoidRep — which gets the best of both worlds.
|
|
| 219 | + |
|
| 220 | +(For the gory details, see also the (unpublished) paper, “Practical
|
|
| 221 | +aspects of evidence-based compilation in System FC.”)
|
|
| 222 | + |
|
| 223 | +Note [Saturation of data constructors in STG]
|
|
| 224 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 225 | +We guarantee that `StgConApp` is an exactly-saturated application of a data
|
|
| 226 | +constructor worker.
|
|
| 227 | + |
|
| 228 | +* If the data constructor is /under/-saturated we just fall through to build
|
|
| 229 | + a `StgApp`. Remember, data constructor workers have a regular top-level definition
|
|
| 230 | + (injected by GHC.CoreToStg.Prep.mkDataConWorkers) so we can partially apply
|
|
| 231 | + that function.
|
|
| 232 | + |
|
| 233 | +* If the data constructor is /over/-saturated, which can happen (see #23865) we again
|
|
| 234 | + fall through to `StgApp`. That will fail horribly at runtime (by applying data
|
|
| 235 | + constructor to an argument) but it should be in dead code, and at least the compiler
|
|
| 236 | + itself won't crash. (We could inject an error-thunk instead.)
|
|
| 237 | + |
|
| 238 | +Note [Naked lambdas in coreToStgExpr]
|
|
| 239 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 240 | +Consider
|
|
| 241 | + f x = case x of
|
|
| 242 | + True -> \y. y+x
|
|
| 243 | + False -> blah
|
|
| 244 | +If `f` is not eta expanded (which would have happened in Prep if it was
|
|
| 245 | +going to happen at all, the code for f must allocate a closure for the
|
|
| 246 | +(\y. y+x). So the STG code we want has
|
|
| 247 | + |
|
| 248 | + True -> let pap = \y. y+x
|
|
| 249 | + in pap
|
|
| 250 | + |
|
| 251 | +The Lam case of `coreToStgExpr` deals with adding this `StgLet`. It's the
|
|
| 252 | +main reason we need a unique supply in the monad.
|
|
| 253 | + |
|
| 254 | +Historical note: in the past, Prep guaranteed there would be no such naked
|
|
| 255 | +lambdas, so we didn't need a unique supply at all. But that proved too hard
|
|
| 256 | +in the end (see Note [Eta expansion and the CorePrep invariants]) so we
|
|
| 257 | +just deal with it here; it's very easy.
|
|
| 258 | +-}
|
|
| 236 | 259 | |
| 237 | 260 | -- --------------------------------------------------------------
|
| 238 | 261 | -- Setting variable info: top-level, binds, RHSs
|
| 239 | 262 | -- --------------------------------------------------------------
|
| 240 | 263 | |
| 241 | 264 | |
| 242 | -coreToStg :: CoreToStgOpts -> Module -> ModLocation -> CoreProgram
|
|
| 243 | - -> ([StgTopBinding], InfoTableProvMap, CollectedCCs)
|
|
| 244 | -coreToStg opts@CoreToStgOpts
|
|
| 245 | - { coreToStg_ways = ways
|
|
| 246 | - , coreToStg_AutoSccsOnIndividualCafs = opt_AutoSccsOnIndividualCafs
|
|
| 247 | - , coreToStg_InfoTableMap = opt_InfoTableMap
|
|
| 248 | - , coreToStg_stgDebugOpts = stgDebugOpts
|
|
| 249 | - } this_mod ml pgm
|
|
| 250 | - = (pgm'', denv, final_ccs)
|
|
| 265 | +coreToStg :: CoreToStgOpts -> Module -> ModLocation
|
|
| 266 | + -> CoreProgram
|
|
| 267 | + -> IO ([StgTopBinding], InfoTableProvMap, CollectedCCs)
|
|
| 268 | +coreToStg opts this_mod ml pgm
|
|
| 269 | + = do { us <- mkSplitUniqSupply StgTag
|
|
| 270 | + ; let (_, (local_ccs, local_cc_stacks), pgm')
|
|
| 271 | + = initCts opts us $
|
|
| 272 | + coreTopBindsToStg opts this_mod emptyCollectedCCs pgm
|
|
| 273 | + |
|
| 274 | + -- See Note [Mapping Info Tables to Source Positions]
|
|
| 275 | + (!pgm'', !denv)
|
|
| 276 | + | opt_InfoTableMap
|
|
| 277 | + = collectDebugInformation stgDebugOpts ml pgm'
|
|
| 278 | + | otherwise = (pgm', emptyInfoTableProvMap)
|
|
| 279 | + |
|
| 280 | + final_ccs
|
|
| 281 | + | prof && opt_AutoSccsOnIndividualCafs
|
|
| 282 | + = (local_ccs,local_cc_stacks) -- don't need "all CAFs" CC
|
|
| 283 | + | prof
|
|
| 284 | + = (all_cafs_cc:local_ccs, all_cafs_ccs:local_cc_stacks)
|
|
| 285 | + | otherwise
|
|
| 286 | + = emptyCollectedCCs
|
|
| 287 | + |
|
| 288 | + ; return (pgm'', denv, final_ccs) }
|
|
| 251 | 289 | where
|
| 252 | - (_, (local_ccs, local_cc_stacks), pgm')
|
|
| 253 | - = coreTopBindsToStg opts this_mod emptyVarEnv emptyCollectedCCs pgm
|
|
| 254 | - |
|
| 255 | - -- See Note [Mapping Info Tables to Source Positions]
|
|
| 256 | - (!pgm'', !denv)
|
|
| 257 | - | opt_InfoTableMap
|
|
| 258 | - = collectDebugInformation stgDebugOpts ml pgm'
|
|
| 259 | - | otherwise = (pgm', emptyInfoTableProvMap)
|
|
| 290 | + CoreToStgOpts { coreToStg_ways = ways
|
|
| 291 | + , coreToStg_AutoSccsOnIndividualCafs = opt_AutoSccsOnIndividualCafs
|
|
| 292 | + , coreToStg_InfoTableMap = opt_InfoTableMap
|
|
| 293 | + , coreToStg_stgDebugOpts = stgDebugOpts }
|
|
| 294 | + = opts
|
|
| 260 | 295 | |
| 261 | 296 | prof = hasWay ways WayProf
|
| 262 | - |
|
| 263 | - final_ccs
|
|
| 264 | - | prof && opt_AutoSccsOnIndividualCafs
|
|
| 265 | - = (local_ccs,local_cc_stacks) -- don't need "all CAFs" CC
|
|
| 266 | - | prof
|
|
| 267 | - = (all_cafs_cc:local_ccs, all_cafs_ccs:local_cc_stacks)
|
|
| 268 | - | otherwise
|
|
| 269 | - = emptyCollectedCCs
|
|
| 270 | - |
|
| 271 | 297 | (all_cafs_cc, all_cafs_ccs) = getAllCAFsCC this_mod
|
| 272 | 298 | |
| 273 | 299 | coreTopBindsToStg
|
| 274 | 300 | :: CoreToStgOpts
|
| 275 | 301 | -> Module
|
| 276 | - -> IdEnv HowBound -- environment for the bindings
|
|
| 277 | 302 | -> CollectedCCs
|
| 278 | 303 | -> CoreProgram
|
| 279 | - -> (IdEnv HowBound, CollectedCCs, [StgTopBinding])
|
|
| 304 | + -> CtsM (IdEnv HowBound, CollectedCCs, [StgTopBinding])
|
|
| 305 | + |
|
| 306 | +coreTopBindsToStg _ _ ccs []
|
|
| 307 | + = do { env <- getCtsEnv
|
|
| 308 | + ; return (env, ccs, []) }
|
|
| 280 | 309 | |
| 281 | -coreTopBindsToStg _ _ env ccs []
|
|
| 282 | - = (env, ccs, [])
|
|
| 283 | -coreTopBindsToStg opts this_mod env ccs (b:bs)
|
|
| 310 | +coreTopBindsToStg opts this_mod ccs (b:bs)
|
|
| 284 | 311 | | NonRec _ rhs <- b, isTyCoArg rhs
|
| 285 | - = coreTopBindsToStg opts this_mod env1 ccs1 bs
|
|
| 312 | + = coreTopBindsToStg opts this_mod ccs bs
|
|
| 286 | 313 | | otherwise
|
| 287 | - = (env2, ccs2, b':bs')
|
|
| 288 | - where
|
|
| 289 | - (env1, ccs1, b' ) = coreTopBindToStg opts this_mod env ccs b
|
|
| 290 | - (env2, ccs2, bs') = coreTopBindsToStg opts this_mod env1 ccs1 bs
|
|
| 314 | + = do { (env1, ccs1, b' ) <- coreTopBindToStg opts this_mod ccs b
|
|
| 315 | + ; (env2, ccs2, bs') <- setCtsEnv env1 $
|
|
| 316 | + coreTopBindsToStg opts this_mod ccs1 bs
|
|
| 317 | + ; return (env2, ccs2, b':bs') }
|
|
| 291 | 318 | |
| 292 | 319 | coreTopBindToStg
|
| 293 | 320 | :: CoreToStgOpts
|
| 294 | 321 | -> Module
|
| 295 | - -> IdEnv HowBound
|
|
| 296 | 322 | -> CollectedCCs
|
| 297 | 323 | -> CoreBind
|
| 298 | - -> (IdEnv HowBound, CollectedCCs, StgTopBinding)
|
|
| 324 | + -> CtsM (IdEnv HowBound, CollectedCCs, StgTopBinding)
|
|
| 299 | 325 | |
| 300 | -coreTopBindToStg _ _ env ccs (NonRec id e)
|
|
| 326 | +coreTopBindToStg _ _ ccs (NonRec id e)
|
|
| 301 | 327 | | Just str <- exprIsTickedString_maybe e
|
| 302 | 328 | -- top-level string literal
|
| 303 | 329 | -- See Note [Core top-level string literals] in GHC.Core
|
| 304 | - = let
|
|
| 305 | - env' = extendVarEnv env id how_bound
|
|
| 306 | - how_bound = LetBound TopLet 0
|
|
| 307 | - in (env', ccs, StgTopStringLit id str)
|
|
| 308 | - |
|
| 309 | -coreTopBindToStg opts@CoreToStgOpts
|
|
| 310 | - { coreToStg_platform = platform
|
|
| 311 | - } this_mod env ccs (NonRec id rhs)
|
|
| 312 | - = let
|
|
| 313 | - env' = extendVarEnv env id how_bound
|
|
| 314 | - how_bound = LetBound TopLet $! manifestArity rhs
|
|
| 315 | - |
|
| 316 | - (ccs', (id', stg_rhs)) =
|
|
| 317 | - initCts platform env $
|
|
| 318 | - coreToTopStgRhs opts this_mod ccs (id,rhs)
|
|
| 319 | - |
|
| 320 | - bind = StgTopLifted $ StgNonRec id' stg_rhs
|
|
| 321 | - in
|
|
| 322 | - -- NB: previously the assertion printed 'rhs' and 'bind'
|
|
| 323 | - -- as well as 'id', but that led to a black hole
|
|
| 324 | - -- where printing the assertion error tripped the
|
|
| 325 | - -- assertion again!
|
|
| 326 | - (env', ccs', bind)
|
|
| 327 | - |
|
| 328 | -coreTopBindToStg opts@CoreToStgOpts
|
|
| 329 | - { coreToStg_platform = platform
|
|
| 330 | - } this_mod env ccs (Rec pairs)
|
|
| 330 | + = do { env <- getCtsEnv
|
|
| 331 | + ; let env' = extendVarEnv env id how_bound
|
|
| 332 | + how_bound = LetBound TopLet 0
|
|
| 333 | + ; return (env', ccs, StgTopStringLit id str) }
|
|
| 334 | + |
|
| 335 | +coreTopBindToStg opts this_mod ccs (NonRec id rhs)
|
|
| 336 | + = do { (ccs', (id', stg_rhs)) <- coreToTopStgRhs opts this_mod ccs (id,rhs)
|
|
| 337 | + |
|
| 338 | + ; env <- getCtsEnv
|
|
| 339 | + ; let env' = extendVarEnv env id how_bound
|
|
| 340 | + how_bound = LetBound TopLet $! manifestArity rhs
|
|
| 341 | + bind = StgTopLifted $ StgNonRec id' stg_rhs
|
|
| 342 | + ; return (env', ccs', bind) }
|
|
| 343 | + |
|
| 344 | +coreTopBindToStg opts this_mod ccs (Rec pairs)
|
|
| 331 | 345 | = assert (not (null pairs)) $
|
| 332 | - let
|
|
| 333 | - extra_env' = [ (b, LetBound TopLet $! manifestArity rhs)
|
|
| 334 | - | (b, rhs) <- pairs ]
|
|
| 335 | - env' = extendVarEnvList env extra_env'
|
|
| 336 | - |
|
| 337 | - -- generate StgTopBindings and CAF cost centres created for CAFs
|
|
| 338 | - (ccs', stg_rhss)
|
|
| 339 | - = initCts platform env' $ mapAccumLM (coreToTopStgRhs opts this_mod) ccs pairs
|
|
| 340 | - bind = StgTopLifted $ StgRec stg_rhss
|
|
| 341 | - in
|
|
| 342 | - (env', ccs', bind)
|
|
| 346 | + do { env <- getCtsEnv
|
|
| 347 | + ; let extra_env' = [ (b, LetBound TopLet $! manifestArity rhs)
|
|
| 348 | + | (b, rhs) <- pairs ]
|
|
| 349 | + env' = extendVarEnvList env extra_env'
|
|
| 350 | + |
|
| 351 | + -- Generate StgTopBindings and CAF cost centres created for CAFs
|
|
| 352 | + ; (ccs', stg_rhss) <- setCtsEnv env' $
|
|
| 353 | + mapAccumLM (coreToTopStgRhs opts this_mod) ccs pairs
|
|
| 354 | + ; let bind = StgTopLifted $ StgRec stg_rhss
|
|
| 355 | + |
|
| 356 | + ; return (env', ccs', bind) }
|
|
| 343 | 357 | |
| 344 | 358 | coreToTopStgRhs
|
| 345 | 359 | :: CoreToStgOpts
|
| ... | ... | @@ -420,16 +434,24 @@ coreToStgExpr expr@(App _ _) |
| 420 | 434 | res_ty = exprType expr
|
| 421 | 435 | (app_head, args, ticks) = myCollectArgs expr res_ty
|
| 422 | 436 | |
| 423 | -coreToStgExpr expr@(Lam _ _)
|
|
| 424 | - = let
|
|
| 425 | - (args, body) = myCollectBinders expr
|
|
| 426 | - in
|
|
| 427 | - case filterStgBinders args of
|
|
| 428 | - |
|
| 429 | - [] -> coreToStgExpr body
|
|
| 430 | - |
|
| 431 | - _ -> pprPanic "coretoStgExpr" $
|
|
| 432 | - text "Unexpected value lambda:" $$ ppr expr
|
|
| 437 | +coreToStgExpr expr@(Lam {})
|
|
| 438 | + | null val_bndrs
|
|
| 439 | + = coreToStgExpr body
|
|
| 440 | + | otherwise
|
|
| 441 | + = -- See Note [Naked lambdas in coreToStgExpr]
|
|
| 442 | + do { body' <- extendVarEnvCts [ (a, LambdaBound) | a <- val_bndrs ] $
|
|
| 443 | + coreToStgExpr body
|
|
| 444 | + ; uniq <- getCtsUnique
|
|
| 445 | + ; let body_ty = exprType body
|
|
| 446 | + fun_ty = mkLamTypes val_bndrs body_ty
|
|
| 447 | + -- This type is a bit ill-formed but it doesn't matter
|
|
| 448 | + rhs = StgRhsClosure noExtFieldSilent currentCCS
|
|
| 449 | + ReEntrant val_bndrs body' body_ty
|
|
| 450 | + tmp_fun = mkSysLocal (fsLit "pap") uniq ManyTy fun_ty
|
|
| 451 | + ; return (StgLet noExtFieldSilent (StgNonRec tmp_fun rhs) $
|
|
| 452 | + StgApp tmp_fun []) }
|
|
| 453 | + where
|
|
| 454 | + (val_bndrs, body) = myCollectBinders NotJoinPoint expr
|
|
| 433 | 455 | |
| 434 | 456 | coreToStgExpr (Tick tick expr)
|
| 435 | 457 | = do
|
| ... | ... | @@ -634,8 +656,13 @@ coreToStgArgs (arg : args) = do -- Non-type argument |
| 634 | 656 | stg_arg_rep = stgArgRep arg'
|
| 635 | 657 | bad_args = not (primRepsCompatible platform arg_rep stg_arg_rep)
|
| 636 | 658 | |
| 637 | - massertPpr (length ticks' <= 1) (text "More than one Tick in trivial arg:" <+> ppr arg)
|
|
| 638 | - warnPprTraceM bad_args "Dangerous-looking argument. Probable cause: bad unsafeCoerce#" (ppr arg)
|
|
| 659 | + -- Yikes! This assert FAILS in tests T13658, T14779b
|
|
| 660 | + -- It has been so for ages, but without the "() <-" it was lazily dropped
|
|
| 661 | + -- Hence commenting it out: see #27132
|
|
| 662 | + -- massertPpr (length ticks' <= 1) (text "More than one Tick in trivial arg:" <+> ppr arg)
|
|
| 663 | + |
|
| 664 | + () <- warnPprTraceM bad_args
|
|
| 665 | + "Dangerous-looking argument. Probable cause: bad unsafeCoerce#" (ppr arg)
|
|
| 639 | 666 | |
| 640 | 667 | return (arg' : stg_args, ticks' ++ ticks)
|
| 641 | 668 | |
| ... | ... | @@ -710,12 +737,11 @@ coreToStgRhs (bndr, rhs) = do |
| 710 | 737 | -- coreToStgExpr that can handle value lambdas.
|
| 711 | 738 | coreToMkStgRhs :: HasDebugCallStack => Id -> CoreExpr -> CtsM MkStgRhs
|
| 712 | 739 | coreToMkStgRhs bndr expr = do
|
| 713 | - let (args, body) = myCollectBinders expr
|
|
| 714 | - let args' = filterStgBinders args
|
|
| 715 | - extendVarEnvCts [ (a, LambdaBound) | a <- args' ] $ do
|
|
| 740 | + let (bndrs, body) = myCollectBinders (idJoinPointHood bndr) expr
|
|
| 741 | + extendVarEnvCts [ (a, LambdaBound) | a <- bndrs ] $ do
|
|
| 716 | 742 | body' <- coreToStgExpr body
|
| 717 | 743 | let mk_rhs = MkStgRhs
|
| 718 | - { rhs_args = args'
|
|
| 744 | + { rhs_args = bndrs
|
|
| 719 | 745 | , rhs_expr = body'
|
| 720 | 746 | , rhs_type = exprType body
|
| 721 | 747 | , rhs_is_join = isJoinId bndr
|
| ... | ... | @@ -733,7 +759,7 @@ coreToMkStgRhs bndr expr = do |
| 733 | 759 | newtype CtsM a = CtsM
|
| 734 | 760 | { unCtsM :: Platform -- Needed for checking for bad coercions in coreToStgArgs
|
| 735 | 761 | -> IdEnv HowBound
|
| 736 | - -> a
|
|
| 762 | + -> UniqSM a
|
|
| 737 | 763 | }
|
| 738 | 764 | deriving (Functor)
|
| 739 | 765 | |
| ... | ... | @@ -769,20 +795,22 @@ data LetInfo |
| 769 | 795 | |
| 770 | 796 | -- The std monad functions:
|
| 771 | 797 | |
| 772 | -initCts :: Platform -> IdEnv HowBound -> CtsM a -> a
|
|
| 773 | -initCts platform env m = unCtsM m platform env
|
|
| 774 | - |
|
| 798 | +initCts :: CoreToStgOpts -> UniqSupply -> CtsM a -> a
|
|
| 799 | +initCts opts us cts_m
|
|
| 800 | + = initUs_ us $
|
|
| 801 | + unCtsM cts_m (coreToStg_platform opts) emptyVarEnv
|
|
| 775 | 802 | |
| 776 | 803 | |
| 777 | 804 | {-# INLINE thenCts #-}
|
| 778 | 805 | {-# INLINE returnCts #-}
|
| 779 | 806 | |
| 780 | 807 | returnCts :: a -> CtsM a
|
| 781 | -returnCts e = CtsM $ \_ _ -> e
|
|
| 808 | +returnCts e = CtsM $ \_ _ -> return e
|
|
| 782 | 809 | |
| 783 | 810 | thenCts :: CtsM a -> (a -> CtsM b) -> CtsM b
|
| 784 | -thenCts m k = CtsM $ \platform env
|
|
| 785 | - -> unCtsM (k (unCtsM m platform env)) platform env
|
|
| 811 | +thenCts m k = CtsM $ \platform env ->
|
|
| 812 | + do { v <- unCtsM m platform env
|
|
| 813 | + ; unCtsM (k v) platform env }
|
|
| 786 | 814 | |
| 787 | 815 | instance Applicative CtsM where
|
| 788 | 816 | pure = returnCts
|
| ... | ... | @@ -792,17 +820,26 @@ instance Monad CtsM where |
| 792 | 820 | (>>=) = thenCts
|
| 793 | 821 | |
| 794 | 822 | getPlatform :: CtsM Platform
|
| 795 | -getPlatform = CtsM const
|
|
| 823 | +getPlatform = CtsM $ \platform _ -> return platform
|
|
| 796 | 824 | |
| 797 | 825 | -- Functions specific to this monad:
|
| 798 | 826 | |
| 827 | +setCtsEnv :: IdEnv HowBound -> CtsM a -> CtsM a
|
|
| 828 | +setCtsEnv env thing = CtsM $ \platform _ -> unCtsM thing platform env
|
|
| 829 | + |
|
| 830 | +getCtsEnv :: CtsM (IdEnv HowBound)
|
|
| 831 | +getCtsEnv = CtsM $ \_ env -> return env
|
|
| 832 | + |
|
| 833 | +getCtsUnique :: CtsM Unique
|
|
| 834 | +getCtsUnique = CtsM $ \_ _ -> getUniqueM
|
|
| 835 | + |
|
| 799 | 836 | extendVarEnvCts :: [(Id, HowBound)] -> CtsM a -> CtsM a
|
| 800 | 837 | extendVarEnvCts ids_w_howbound expr
|
| 801 | 838 | = CtsM $ \platform env
|
| 802 | 839 | -> unCtsM expr platform (extendVarEnvList env ids_w_howbound)
|
| 803 | 840 | |
| 804 | 841 | lookupVarCts :: Id -> CtsM HowBound
|
| 805 | -lookupVarCts v = CtsM $ \_ env -> lookupBinding env v
|
|
| 842 | +lookupVarCts v = CtsM $ \_ env -> return (lookupBinding env v)
|
|
| 806 | 843 | |
| 807 | 844 | lookupBinding :: IdEnv HowBound -> Id -> HowBound
|
| 808 | 845 | lookupBinding env v = case lookupVarEnv env v of
|
| ... | ... | @@ -814,13 +851,26 @@ lookupBinding env v = case lookupVarEnv env v of |
| 814 | 851 | filterStgBinders :: [Var] -> [Var]
|
| 815 | 852 | filterStgBinders bndrs = filter isId bndrs
|
| 816 | 853 | |
| 817 | -myCollectBinders :: Expr Var -> ([Var], Expr Var)
|
|
| 818 | -myCollectBinders expr
|
|
| 854 | +myCollectBinders :: JoinPointHood -> Expr Var -> ([Var], Expr Var)
|
|
| 855 | +-- Collect the binders from a lambda:
|
|
| 856 | +-- * Dropping type lambdas
|
|
| 857 | +-- * Stopping at join-point arity
|
|
| 858 | +myCollectBinders NotJoinPoint expr
|
|
| 819 | 859 | = go [] expr
|
| 820 | 860 | where
|
| 821 | - go bs (Lam b e) = go (b:bs) e
|
|
| 822 | - go bs (Cast e _) = go bs e
|
|
| 823 | - go bs e = (reverse bs, e)
|
|
| 861 | + go bs (Lam b e) | isRuntimeVar b = go (b:bs) e
|
|
| 862 | + | otherwise = go bs e
|
|
| 863 | + go bs (Cast e _) = go bs e
|
|
| 864 | + go bs e = (reverse bs, e)
|
|
| 865 | + |
|
| 866 | +myCollectBinders (JoinPoint n) expr
|
|
| 867 | + = go n [] expr
|
|
| 868 | + where
|
|
| 869 | + go n bs e | n==0 = (reverse bs, e)
|
|
| 870 | + go n bs (Lam b e) | isRuntimeVar b = go (n-1) (b:bs) e
|
|
| 871 | + | otherwise = go (n-1) bs e
|
|
| 872 | + go n bs (Cast e _) = go n bs e
|
|
| 873 | + go _ bs e = (reverse bs, e)
|
|
| 824 | 874 | |
| 825 | 875 | -- | If the argument expression is (potential chain of) 'App', return the head
|
| 826 | 876 | -- of the app chain, and collect ticks/args along the chain.
|
| ... | ... | @@ -144,16 +144,13 @@ Here is the syntax of the Core produced by CorePrep: |
| 144 | 144 | |
| 145 | 145 | Expressions
|
| 146 | 146 | body ::= app
|
| 147 | - | let(rec) x = rhs in body -- Boxed only
|
|
| 147 | + | let(rec) x = body in body -- Boxed only
|
|
| 148 | 148 | | case body of pat -> body
|
| 149 | - | /\a. body | /\c. body
|
|
| 149 | + | /\a. body | /\c. body | \x. body
|
|
| 150 | 150 | | body |> co
|
| 151 | 151 | |
| 152 | - Right hand sides (only place where value lambdas can occur)
|
|
| 153 | - rhs ::= /\a.rhs | \x.rhs | body
|
|
| 154 | - |
|
| 155 | -We define a synonym for each of these non-terminals. Functions
|
|
| 156 | -with the corresponding name produce a result in that syntax.
|
|
| 152 | +We define a synonym for each of these non-terminals, CpeArg, CpeApp, and
|
|
| 153 | +CpeBody. Functions with the corresponding name produce a result in that syntax.
|
|
| 157 | 154 | |
| 158 | 155 | Note [Cloning in CorePrep]
|
| 159 | 156 | ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -218,7 +215,6 @@ So our plan is: |
| 218 | 215 | type CpeArg = CoreExpr -- Non-terminal 'arg'
|
| 219 | 216 | type CpeApp = CoreExpr -- Non-terminal 'app'
|
| 220 | 217 | type CpeBody = CoreExpr -- Non-terminal 'body'
|
| 221 | -type CpeRhs = CoreExpr -- Non-terminal 'rhs'
|
|
| 222 | 218 | |
| 223 | 219 | {-
|
| 224 | 220 | ************************************************************************
|
| ... | ... | @@ -261,7 +257,7 @@ corePrepExpr logger config expr = do |
| 261 | 257 | withTiming logger (text "CorePrep [expr]") (\e -> e `seq` ()) $ do
|
| 262 | 258 | us <- mkSplitUniqSupply StgTag
|
| 263 | 259 | let initialCorePrepEnv = mkInitialCorePrepEnv config
|
| 264 | - let new_expr = initUs_ us (cpeBodyNF initialCorePrepEnv expr)
|
|
| 260 | + let new_expr = initUs_ us (cpeBody initialCorePrepEnv expr)
|
|
| 265 | 261 | putDumpFileMaybe logger Opt_D_dump_prep "CorePrep" FormatCore (ppr new_expr)
|
| 266 | 262 | return new_expr
|
| 267 | 263 | |
| ... | ... | @@ -665,16 +661,16 @@ cpeBind top_lvl env (Rec pairs) |
| 665 | 661 | ---------------
|
| 666 | 662 | cpePair :: TopLevelFlag -> RecFlag -> Demand -> Levity
|
| 667 | 663 | -> CorePrepEnv -> OutId -> CoreExpr
|
| 668 | - -> UniqSM (Floats, CpeRhs)
|
|
| 664 | + -> UniqSM (Floats, CpeBody)
|
|
| 669 | 665 | -- Used for all bindings
|
| 670 | 666 | -- The binder is already cloned, hence an OutId
|
| 671 | 667 | cpePair top_lvl is_rec dmd lev env0 bndr rhs
|
| 672 | 668 | = assert (isNothing $ joinPointBinding_maybe bndr rhs) $ -- those should use cpeJoinPair
|
| 673 | - do { (floats1, rhs1) <- cpeRhsE env rhs
|
|
| 669 | + do { (floats1, rhs1) <- cpeBodyF env rhs
|
|
| 674 | 670 | |
| 675 | 671 | -- See if we are allowed to float this stuff out of the RHS
|
| 676 | 672 | ; let dec = want_float_from_rhs floats1 rhs1
|
| 677 | - ; (floats2, rhs2) <- executeFloatDecision env dec floats1 rhs1
|
|
| 673 | + (floats2, rhs2) = executeFloatDecision dec floats1 rhs1
|
|
| 678 | 674 | |
| 679 | 675 | -- Make the arity match up
|
| 680 | 676 | ; (floats3, rhs3)
|
| ... | ... | @@ -717,7 +713,7 @@ it seems good for CorePrep to be robust. |
| 717 | 713 | |
| 718 | 714 | ---------------
|
| 719 | 715 | cpeJoinPair :: CorePrepEnv -> JoinId -> CoreExpr
|
| 720 | - -> UniqSM (JoinId, CpeRhs)
|
|
| 716 | + -> UniqSM (JoinId, CpeBody)
|
|
| 721 | 717 | -- Used for all join bindings
|
| 722 | 718 | -- No eta-expansion: see Note [Do not eta-expand join points] in GHC.Core.Opt.Simplify.Utils
|
| 723 | 719 | cpeJoinPair env bndr rhs
|
| ... | ... | @@ -729,7 +725,7 @@ cpeJoinPair env bndr rhs |
| 729 | 725 | |
| 730 | 726 | ; (env', bndrs') <- cpCloneBndrs env bndrs
|
| 731 | 727 | |
| 732 | - ; body' <- cpeBodyNF env' body -- Will let-bind the body if it starts
|
|
| 728 | + ; body' <- cpeBody env' body -- Will let-bind the body if it starts
|
|
| 733 | 729 | -- with a lambda
|
| 734 | 730 | |
| 735 | 731 | ; let rhs' = mkCoreLams bndrs' body'
|
| ... | ... | @@ -757,10 +753,20 @@ for us to mess with the arity because a join point is never exported. |
| 757 | 753 | -}
|
| 758 | 754 | |
| 759 | 755 | -- ---------------------------------------------------------------------------
|
| 760 | --- CpeRhs: produces a result satisfying CpeRhs
|
|
| 756 | +-- cpeBodyF: produces a result satisfying CpeBody
|
|
| 761 | 757 | -- ---------------------------------------------------------------------------
|
| 762 | 758 | |
| 763 | -cpeRhsE :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)
|
|
| 759 | +cpeBodyF :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeBody)
|
|
| 760 | +-- | Convert a 'CoreExpr' so it satisfies 'CpeBody'; also produce
|
|
| 761 | +-- a list of 'Floats' which are being propagated upwards. In
|
|
| 762 | +-- fact, this function is used in only two cases: to
|
|
| 763 | +-- implement 'cpeBody' (which is what you usually want),
|
|
| 764 | +-- and in the case when a let-binding is in a case scrutinee--here,
|
|
| 765 | +-- we can always float out:
|
|
| 766 | +--
|
|
| 767 | +-- case (let x = y in z) of ...
|
|
| 768 | +-- ==> let x = y in case z of ...
|
|
| 769 | +--
|
|
| 764 | 770 | -- If
|
| 765 | 771 | -- e ===> (bs, e')
|
| 766 | 772 | -- then
|
| ... | ... | @@ -769,32 +775,32 @@ cpeRhsE :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs) |
| 769 | 775 | -- For example
|
| 770 | 776 | -- f (g x) ===> ([v = g x], f v)
|
| 771 | 777 | |
| 772 | -cpeRhsE env (Type ty)
|
|
| 778 | +cpeBodyF env (Type ty)
|
|
| 773 | 779 | = return (emptyFloats, Type (cpSubstTy env ty))
|
| 774 | -cpeRhsE env (Coercion co)
|
|
| 780 | +cpeBodyF env (Coercion co)
|
|
| 775 | 781 | = return (emptyFloats, Coercion (cpSubstCo env co))
|
| 776 | -cpeRhsE env expr@(Lit lit)
|
|
| 782 | +cpeBodyF env expr@(Lit lit)
|
|
| 777 | 783 | | LitNumber LitNumBigNat i <- lit
|
| 778 | 784 | = cpeBigNatLit env i
|
| 779 | 785 | | otherwise = return (emptyFloats, expr)
|
| 780 | -cpeRhsE env expr@(Var {}) = cpeApp env expr
|
|
| 781 | -cpeRhsE env expr@(App {}) = cpeApp env expr
|
|
| 786 | +cpeBodyF env expr@(Var {}) = cpeApp env expr
|
|
| 787 | +cpeBodyF env expr@(App {}) = cpeApp env expr
|
|
| 782 | 788 | |
| 783 | -cpeRhsE env (Let bind body)
|
|
| 789 | +cpeBodyF env (Let bind body)
|
|
| 784 | 790 | = do { (env', bind_floats, maybe_bind') <- cpeBind NotTopLevel env bind
|
| 785 | - ; (body_floats, body') <- cpeRhsE env' body
|
|
| 791 | + ; (body_floats, body') <- cpeBodyF env' body
|
|
| 786 | 792 | ; let expr' = case maybe_bind' of Just bind' -> Let bind' body'
|
| 787 | 793 | Nothing -> body'
|
| 788 | 794 | ; return (bind_floats `appFloats` body_floats, expr') }
|
| 789 | 795 | |
| 790 | -cpeRhsE env (Tick tickish expr)
|
|
| 796 | +cpeBodyF env (Tick tickish expr)
|
|
| 791 | 797 | -- Pull out ticks if they are allowed to be floated.
|
| 792 | 798 | | tickishFloatable tickish
|
| 793 | - = do { (floats, body) <- cpeRhsE env expr
|
|
| 799 | + = do { (floats, body) <- cpeBodyF env expr
|
|
| 794 | 800 | -- See [Floating Ticks in CorePrep]
|
| 795 | 801 | ; return (FloatTick tickish `consFloat` floats, body) }
|
| 796 | 802 | | otherwise
|
| 797 | - = do { body <- cpeBodyNF env expr
|
|
| 803 | + = do { body <- cpeBody env expr
|
|
| 798 | 804 | ; return (emptyFloats, mkTick tickish' body) }
|
| 799 | 805 | where
|
| 800 | 806 | tickish' | Breakpoint ext bid fvs <- tickish
|
| ... | ... | @@ -803,17 +809,17 @@ cpeRhsE env (Tick tickish expr) |
| 803 | 809 | | otherwise
|
| 804 | 810 | = tickish
|
| 805 | 811 | |
| 806 | -cpeRhsE env (Cast expr co)
|
|
| 807 | - = do { (floats, expr') <- cpeRhsE env expr
|
|
| 812 | +cpeBodyF env (Cast expr co)
|
|
| 813 | + = do { (floats, expr') <- cpeBodyF env expr
|
|
| 808 | 814 | ; return (floats, Cast expr' (cpSubstCo env co)) }
|
| 809 | 815 | |
| 810 | -cpeRhsE env expr@(Lam {})
|
|
| 816 | +cpeBodyF env expr@(Lam {})
|
|
| 811 | 817 | = do { let (bndrs,body) = collectBinders expr
|
| 812 | 818 | ; (env', bndrs') <- cpCloneBndrs env bndrs
|
| 813 | - ; body' <- cpeBodyNF env' body
|
|
| 819 | + ; body' <- cpeBody env' body
|
|
| 814 | 820 | ; return (emptyFloats, mkLams bndrs' body') }
|
| 815 | 821 | |
| 816 | -cpeRhsE env (Case scrut bndr _ alts@[Alt con [covar] _])
|
|
| 822 | +cpeBodyF env (Case scrut bndr _ alts@[Alt con [covar] _])
|
|
| 817 | 823 | -- See (U3) in Note [Implementing unsafeCoerce]
|
| 818 | 824 | -- We need make the Case float, otherwise we get
|
| 819 | 825 | -- let x = case ... of UnsafeRefl co ->
|
| ... | ... | @@ -828,7 +834,7 @@ cpeRhsE env (Case scrut bndr _ alts@[Alt con [covar] _]) |
| 828 | 834 | -- Note that `x` is a value here. This is visible in the GHCi debugger tests
|
| 829 | 835 | -- (such as `print003`).
|
| 830 | 836 | | Just rhs <- isUnsafeEqualityCase scrut bndr alts
|
| 831 | - = do { (floats_scrut, scrut) <- cpeBody env scrut
|
|
| 837 | + = do { (floats_scrut, scrut) <- cpeBodyF env scrut
|
|
| 832 | 838 | |
| 833 | 839 | ; (env, bndr') <- cpCloneBndr env bndr
|
| 834 | 840 | ; (env, covar') <- cpCloneCoVarBndr env covar
|
| ... | ... | @@ -836,19 +842,19 @@ cpeRhsE env (Case scrut bndr _ alts@[Alt con [covar] _]) |
| 836 | 842 | -- See Note [Cloning CoVars and TyVars]
|
| 837 | 843 | |
| 838 | 844 | -- Up until here this should do exactly the same as the regular code
|
| 839 | - -- path of `cpeRhsE Case{}`.
|
|
| 840 | - ; (floats_rhs, rhs) <- cpeBody env rhs
|
|
| 845 | + -- path of `cpeBodyF Case{}`.
|
|
| 846 | + ; (floats_rhs, rhs) <- cpeBodyF env rhs
|
|
| 841 | 847 | -- ... but we want to float `floats_rhs` as in (U3) so that rhs' might
|
| 842 | 848 | -- become a value
|
| 843 | 849 | ; let case_float = UnsafeEqualityCase scrut bndr' con [covar']
|
| 844 | 850 | -- NB: It is OK to "evaluate" the proof eagerly.
|
| 845 | 851 | -- Usually there's the danger that we float the unsafeCoerce out of
|
| 846 | 852 | -- a branching Case alt. Not so here, because the regular code path
|
| 847 | - -- for `cpeRhsE Case{}` will not float out of alts.
|
|
| 853 | + -- for `cpeBodyF Case{}` will not float out of alts.
|
|
| 848 | 854 | floats = snocFloat floats_scrut case_float `appFloats` floats_rhs
|
| 849 | 855 | ; return (floats, rhs) }
|
| 850 | 856 | |
| 851 | -cpeRhsE env (Case scrut bndr _ [Alt (DataAlt dc) [token_out, res] rhs])
|
|
| 857 | +cpeBodyF env (Case scrut bndr _ [Alt (DataAlt dc) [token_out, res] rhs])
|
|
| 852 | 858 | -- See item (SEQ4) of Note [seq# magic]. We want to match
|
| 853 | 859 | -- case seq# @a @RealWorld <ok-to-discard> s of (# s', _ #) -> rhs[s']
|
| 854 | 860 | -- and simplify to rhs[s]. Triggers in T15226.
|
| ... | ... | @@ -869,10 +875,10 @@ cpeRhsE env (Case scrut bndr _ [Alt (DataAlt dc) [token_out, res] rhs]) |
| 869 | 875 | -- often zaps the OccInfo on case-alternative binders (see Note [DataAlt occ info]
|
| 870 | 876 | -- in GHC.Core.Opt.Simplify.Iteration) because the scrutinee is not a
|
| 871 | 877 | -- variable, and in that case the zapping doesn't happen; see that Note.
|
| 872 | - = cpeRhsE (extendCorePrepEnv env token_out token_in') rhs
|
|
| 878 | + = cpeBodyF (extendCorePrepEnv env token_out token_in') rhs
|
|
| 873 | 879 | |
| 874 | -cpeRhsE env (Case scrut bndr ty alts)
|
|
| 875 | - = do { (floats, scrut') <- cpeBody env scrut
|
|
| 880 | +cpeBodyF env (Case scrut bndr ty alts)
|
|
| 881 | + = do { (floats, scrut') <- cpeBodyF env scrut
|
|
| 876 | 882 | ; (env', bndr2) <- cpCloneBndr env bndr
|
| 877 | 883 | ; let bndr3 = bndr2 `setIdUnfolding` evaldUnfolding
|
| 878 | 884 | ; let alts'
|
| ... | ... | @@ -885,7 +891,7 @@ cpeRhsE env (Case scrut bndr ty alts) |
| 885 | 891 | , not (altsAreExhaustive alts)
|
| 886 | 892 | = addDefault alts (Just err)
|
| 887 | 893 | | otherwise = alts
|
| 888 | - where err = mkImpossibleExpr ty "cpeRhsE: missing case alternative"
|
|
| 894 | + where err = mkImpossibleExpr ty "cpeBodyF: missing case alternative"
|
|
| 889 | 895 | ; alts'' <- mapM (sat_alt env') alts'
|
| 890 | 896 | |
| 891 | 897 | ; case alts'' of
|
| ... | ... | @@ -896,7 +902,7 @@ cpeRhsE env (Case scrut bndr ty alts) |
| 896 | 902 | where
|
| 897 | 903 | sat_alt env (Alt con bs rhs)
|
| 898 | 904 | = do { (env2, bs') <- cpCloneBndrs env bs
|
| 899 | - ; rhs' <- cpeBodyNF env2 rhs
|
|
| 905 | + ; rhs' <- cpeBody env2 rhs
|
|
| 900 | 906 | ; return (Alt con bs' rhs') }
|
| 901 | 907 | |
| 902 | 908 | -- ---------------------------------------------------------------------------
|
| ... | ... | @@ -908,74 +914,10 @@ cpeRhsE env (Case scrut bndr ty alts) |
| 908 | 914 | -- let-bound using 'wrapBinds'). Generally you want this, esp.
|
| 909 | 915 | -- when you've reached a binding form (e.g., a lambda) and
|
| 910 | 916 | -- floating any further would be incorrect.
|
| 911 | -cpeBodyNF :: CorePrepEnv -> CoreExpr -> UniqSM CpeBody
|
|
| 912 | -cpeBodyNF env expr
|
|
| 913 | - = do { (floats, body) <- cpeBody env expr
|
|
| 914 | - ; return (wrapBinds floats body) }
|
|
| 915 | - |
|
| 916 | --- | Convert a 'CoreExpr' so it satisfies 'CpeBody'; also produce
|
|
| 917 | --- a list of 'Floats' which are being propagated upwards. In
|
|
| 918 | --- fact, this function is used in only two cases: to
|
|
| 919 | --- implement 'cpeBodyNF' (which is what you usually want),
|
|
| 920 | --- and in the case when a let-binding is in a case scrutinee--here,
|
|
| 921 | --- we can always float out:
|
|
| 922 | ---
|
|
| 923 | --- case (let x = y in z) of ...
|
|
| 924 | --- ==> let x = y in case z of ...
|
|
| 925 | ---
|
|
| 926 | -cpeBody :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeBody)
|
|
| 917 | +cpeBody :: CorePrepEnv -> CoreExpr -> UniqSM CpeBody
|
|
| 927 | 918 | cpeBody env expr
|
| 928 | - = do { (floats1, rhs) <- cpeRhsE env expr
|
|
| 929 | - ; (floats2, body) <- rhsToBody env rhs
|
|
| 930 | - ; return (floats1 `appFloats` floats2, body) }
|
|
| 931 | - |
|
| 932 | ---------
|
|
| 933 | -rhsToBody :: CorePrepEnv -> CpeRhs -> UniqSM (Floats, CpeBody)
|
|
| 934 | --- Remove top level lambdas by let-binding
|
|
| 935 | - |
|
| 936 | -rhsToBody env (Tick t expr)
|
|
| 937 | - | tickishHasNoScope t -- only float out of non-scoped annotations
|
|
| 938 | - = do { (floats, expr') <- rhsToBody env expr
|
|
| 939 | - ; return (floats, mkTick t expr') }
|
|
| 940 | - |
|
| 941 | -rhsToBody env (Cast e co)
|
|
| 942 | - -- You can get things like
|
|
| 943 | - -- case e of { p -> coerce t (\s -> ...) }
|
|
| 944 | - = do { (floats, e') <- rhsToBody env e
|
|
| 945 | - ; return (floats, Cast e' co) }
|
|
| 946 | - |
|
| 947 | -rhsToBody env expr@(Lam {}) -- See Note [No eta reduction needed in rhsToBody]
|
|
| 948 | - | all isTyVar bndrs -- Type lambdas are ok
|
|
| 949 | - = return (emptyFloats, expr)
|
|
| 950 | - | otherwise -- Some value lambdas
|
|
| 951 | - = do { let rhs = cpeEtaExpand (exprArity expr) expr
|
|
| 952 | - ; fn <- newVar env (exprType rhs)
|
|
| 953 | - ; let float = Float (NonRec fn rhs) LetBound TopLvlFloatable
|
|
| 954 | - ; return (unitFloat float, Var fn) }
|
|
| 955 | - where
|
|
| 956 | - (bndrs,_) = collectBinders expr
|
|
| 957 | - |
|
| 958 | -rhsToBody _env expr = return (emptyFloats, expr)
|
|
| 959 | - |
|
| 960 | - |
|
| 961 | -{- Note [No eta reduction needed in rhsToBody]
|
|
| 962 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 963 | -Historical note. In the olden days we used to have a Prep-specific
|
|
| 964 | -eta-reduction step in rhsToBody:
|
|
| 965 | - rhsToBody expr@(Lam {})
|
|
| 966 | - | Just no_lam_result <- tryEtaReducePrep bndrs body
|
|
| 967 | - = return (emptyFloats, no_lam_result)
|
|
| 968 | - |
|
| 969 | -The goal was to reduce
|
|
| 970 | - case x of { p -> \xs. map f xs }
|
|
| 971 | - ==> case x of { p -> map f }
|
|
| 972 | - |
|
| 973 | -to avoid allocating a lambda. Of course, we'd allocate a PAP
|
|
| 974 | -instead, which is hardly better, but that's the way it was.
|
|
| 975 | - |
|
| 976 | -Now we simply don't bother with this. It doesn't seem to be a win,
|
|
| 977 | -and it's extra work.
|
|
| 978 | --}
|
|
| 919 | + = do { (floats, body) <- cpeBodyF env expr
|
|
| 920 | + ; return (wrapBinds floats body) }
|
|
| 979 | 921 | |
| 980 | 922 | -- ---------------------------------------------------------------------------
|
| 981 | 923 | -- CpeApp: produces a result satisfying CpeApp
|
| ... | ... | @@ -1060,8 +1002,8 @@ body of the eta-expansion lambda, resulting in |
| 1060 | 1002 | which is unproblematic.
|
| 1061 | 1003 | -}
|
| 1062 | 1004 | |
| 1063 | -cpeApp :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)
|
|
| 1064 | --- May return a CpeRhs (instead of CpeApp) because of saturating primops
|
|
| 1005 | +cpeApp :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeBody)
|
|
| 1006 | +-- May return a CpeBody (instead of CpeApp) because of saturating primops
|
|
| 1065 | 1007 | cpeApp top_env expr
|
| 1066 | 1008 | = do { let (terminal, args) = collect_args expr
|
| 1067 | 1009 | -- ; pprTraceM "cpeApp" $ (ppr expr)
|
| ... | ... | @@ -1103,7 +1045,7 @@ cpeApp top_env expr |
| 1103 | 1045 | cpe_app :: CorePrepEnv
|
| 1104 | 1046 | -> CoreExpr -- The thing we are calling
|
| 1105 | 1047 | -> [ArgInfo]
|
| 1106 | - -> UniqSM (Floats, CpeRhs)
|
|
| 1048 | + -> UniqSM (Floats, CpeBody)
|
|
| 1107 | 1049 | cpe_app env (Var f) (AIApp Type{} : AIApp arg : args)
|
| 1108 | 1050 | | f `hasKey` lazyIdKey -- Replace (lazy a) with a, and
|
| 1109 | 1051 | -- See Note [lazyId magic] in GHC.Types.Id.Make
|
| ... | ... | @@ -1156,7 +1098,7 @@ cpeApp top_env expr |
| 1156 | 1098 | -- case thing of res { __DEFAULT -> (# token, res#) } },
|
| 1157 | 1099 | -- allocating CaseBound Floats for token and thing as needed
|
| 1158 | 1100 | = do { (floats1, token) <- cpeArg env topDmd token
|
| 1159 | - ; (floats2, thing) <- cpeBody env thing
|
|
| 1101 | + ; (floats2, thing) <- cpeBodyF env thing
|
|
| 1160 | 1102 | ; case_bndr <- (`setIdUnfolding` evaldUnfolding) <$> newVar env ty
|
| 1161 | 1103 | ; let tup = mkCoreUnboxedTuple [token, Var case_bndr]
|
| 1162 | 1104 | ; let float = mkCaseFloat case_bndr thing
|
| ... | ... | @@ -1173,9 +1115,10 @@ cpeApp top_env expr |
| 1173 | 1115 | then Just $! idArity v_hd
|
| 1174 | 1116 | else Nothing
|
| 1175 | 1117 | Nothing -> Nothing
|
| 1176 | - -- ; pprTraceM "cpe_app:stricts:" (ppr v <+> ppr args $$ ppr stricts $$ ppr (idCbvMarks_maybe v))
|
|
| 1177 | 1118 | ; (app, floats, unsat_ticks) <- rebuild_app env args e2 emptyFloats stricts min_arity
|
| 1178 | - ; mb_saturate hd app floats unsat_ticks depth }
|
|
| 1119 | + ; case hd of
|
|
| 1120 | + Nothing -> do { massert (null unsat_ticks); return (floats, app) }
|
|
| 1121 | + Just fn_id -> return (floats, maybeSaturate fn_id app depth unsat_ticks) }
|
|
| 1179 | 1122 | where
|
| 1180 | 1123 | depth = val_args args
|
| 1181 | 1124 | stricts = case idDmdSig v of
|
| ... | ... | @@ -1190,8 +1133,8 @@ cpeApp top_env expr |
| 1190 | 1133 | -- partial application might be seq'd
|
| 1191 | 1134 | |
| 1192 | 1135 | -- We inlined into something that's not a var and has no args.
|
| 1193 | - -- Bounce it back up to cpeRhsE.
|
|
| 1194 | - cpe_app env fun [] = cpeRhsE env fun
|
|
| 1136 | + -- Bounce it back up to cpeBodyF.
|
|
| 1137 | + cpe_app env fun [] = cpeBodyF env fun
|
|
| 1195 | 1138 | |
| 1196 | 1139 | -- Here we get:
|
| 1197 | 1140 | -- N-variable fun, better let-bind it
|
| ... | ... | @@ -1202,7 +1145,8 @@ cpeApp top_env expr |
| 1202 | 1145 | -- If evalDmd says that it's sure to be evaluated,
|
| 1203 | 1146 | -- we'll end up case-binding it
|
| 1204 | 1147 | ; (app, floats,unsat_ticks) <- rebuild_app env args fun' fun_floats [] Nothing
|
| 1205 | - ; mb_saturate Nothing app floats unsat_ticks (val_args args) }
|
|
| 1148 | + ; massert (null unsat_ticks)
|
|
| 1149 | + ; return (floats, app) }
|
|
| 1206 | 1150 | |
| 1207 | 1151 | -- Count the number of value arguments *and* coercions (since we don't eliminate the later in STG)
|
| 1208 | 1152 | val_args :: [ArgInfo] -> Int
|
| ... | ... | @@ -1223,13 +1167,6 @@ cpeApp top_env expr |
| 1223 | 1167 | | isTypeArg e = n
|
| 1224 | 1168 | | otherwise = n+1
|
| 1225 | 1169 | |
| 1226 | - -- Saturate if necessary
|
|
| 1227 | - mb_saturate head app floats unsat_ticks depth =
|
|
| 1228 | - case head of
|
|
| 1229 | - Just fn_id -> do { sat_app <- maybeSaturate fn_id app depth unsat_ticks
|
|
| 1230 | - ; return (floats, sat_app) }
|
|
| 1231 | - _other -> do { massert (null unsat_ticks)
|
|
| 1232 | - ; return (floats, app) }
|
|
| 1233 | 1170 | |
| 1234 | 1171 | -- Deconstruct and rebuild the application, floating any non-atomic
|
| 1235 | 1172 | -- arguments to the outside. We collect the type of the expression,
|
| ... | ... | @@ -1561,11 +1498,11 @@ Wrinkles: |
| 1561 | 1498 | cpeArg :: CorePrepEnv -> Demand
|
| 1562 | 1499 | -> CoreArg -> UniqSM (Floats, CpeArg)
|
| 1563 | 1500 | cpeArg env dmd arg
|
| 1564 | - = do { (floats1, arg1) <- cpeRhsE env arg -- arg1 can be a lambda
|
|
| 1501 | + = do { (floats1, arg1) <- cpeBodyF env arg -- arg1 can be a lambda
|
|
| 1565 | 1502 | ; let arg_ty = exprType arg1
|
| 1566 | 1503 | lev = typeLevity arg_ty
|
| 1567 | 1504 | dec = wantFloatLocal NonRecursive dmd lev floats1 arg1
|
| 1568 | - ; (floats2, arg2) <- executeFloatDecision env dec floats1 arg1
|
|
| 1505 | + (floats2, arg2) = executeFloatDecision dec floats1 arg1
|
|
| 1569 | 1506 | -- Else case: arg1 might have lambdas, and we can't
|
| 1570 | 1507 | -- put them inside a wrapBinds
|
| 1571 | 1508 | |
| ... | ... | @@ -1580,7 +1517,12 @@ cpeArg env dmd arg |
| 1580 | 1517 | arg3 = cpeEtaExpand arity arg2
|
| 1581 | 1518 | -- See Note [Eta expansion of arguments in CorePrep]
|
| 1582 | 1519 | ; let (arg_float, v') = mkNonRecFloat env lev v arg3
|
| 1583 | - ---; pprTraceM "cpeArg" (ppr arg1 $$ ppr dec $$ ppr arg2)
|
|
| 1520 | +-- ; pprTraceM "cpeArg" (vcat [ text "arg1" <+> ppr arg1
|
|
| 1521 | +-- , text "decision" <+> ppr dec
|
|
| 1522 | +-- , text "arg2" <+> ppr arg2
|
|
| 1523 | +-- , text "arity" <+> ppr arity
|
|
| 1524 | +-- , text "arg3" <+> ppr arg3
|
|
| 1525 | +-- ])
|
|
| 1584 | 1526 | ; return (snocFloat floats2 arg_float, varToCoreExpr v') }
|
| 1585 | 1527 | }
|
| 1586 | 1528 | |
| ... | ... | @@ -1617,59 +1559,56 @@ eta_would_wreck_join (Tick _ e) = eta_would_wreck_join e |
| 1617 | 1559 | eta_would_wreck_join (Case _ _ _ alts) = any eta_would_wreck_join (rhssOfAlts alts)
|
| 1618 | 1560 | eta_would_wreck_join _ = False
|
| 1619 | 1561 | |
| 1620 | -maybeSaturate :: Id -> CpeApp -> Int -> [CoreTickish] -> UniqSM CpeRhs
|
|
| 1562 | +maybeSaturate :: Id -> CpeApp
|
|
| 1563 | + -> Int -- Number of value arguments in the application
|
|
| 1564 | + -> [CoreTickish]
|
|
| 1565 | + -> CpeBody
|
|
| 1621 | 1566 | maybeSaturate fn expr n_args unsat_ticks
|
| 1622 | - | hasNoBinding fn -- There's no binding
|
|
| 1623 | - -- See Note [Eta expansion of hasNoBinding things in CorePrep]
|
|
| 1624 | - = return $ wrapLamBody (\body -> foldr mkTick body unsat_ticks) sat_expr
|
|
| 1625 | - |
|
| 1626 | - | mark_arity > 0 -- A call-by-value function.
|
|
| 1627 | - -- See Note [CBV Function Ids: overview]
|
|
| 1628 | - , not applied_marks
|
|
| 1629 | - = assertPpr
|
|
| 1630 | - ( not (isJoinId fn)) -- See Note [Do not eta-expand join points]
|
|
| 1631 | - ( ppr fn $$ text "expr:" <+> ppr expr $$ text "n_args:" <+> ppr n_args $$
|
|
| 1632 | - text "marks:" <+> ppr (idCbvMarks_maybe fn) $$
|
|
| 1633 | - text "join_arity" <+> ppr (idJoinPointHood fn) $$
|
|
| 1634 | - text "fn_arity" <+> ppr fn_arity
|
|
| 1635 | - ) $
|
|
| 1636 | - -- pprTrace "maybeSat"
|
|
| 1637 | - -- ( ppr fn $$ text "expr:" <+> ppr expr $$ text "n_args:" <+> ppr n_args $$
|
|
| 1638 | - -- text "marks:" <+> ppr (idCbvMarks_maybe fn) $$
|
|
| 1639 | - -- text "join_arity" <+> ppr (isJoinId_maybe fn) $$
|
|
| 1640 | - -- text "fn_arity" <+> ppr fn_arity $$
|
|
| 1641 | - -- text "excess_arity" <+> ppr excess_arity $$
|
|
| 1642 | - -- text "mark_arity" <+> ppr mark_arity
|
|
| 1643 | - -- ) $
|
|
| 1644 | - return sat_expr
|
|
| 1567 | + | isJoinId fn -- Never eta-expand a call to a join point
|
|
| 1568 | + -- See Note [Do not eta-expand join points]
|
|
| 1569 | + = assertPpr (not must_eta_expand) (ppr expr) $
|
|
| 1570 | + -- assertPpr: check that all arguments that need to be passed cbv
|
|
| 1571 | + -- are visible, so the backend can evalaute them if required
|
|
| 1572 | + expr
|
|
| 1573 | + |
|
| 1574 | + | must_eta_expand || desirable_to_eta_expand
|
|
| 1575 | + -- n_args > 0: do not eta-expand a naked variable!
|
|
| 1576 | + = wrapLamBody (mkTicks unsat_ticks) $
|
|
| 1577 | + cpeEtaExpand excess_arity expr
|
|
| 1645 | 1578 | |
| 1646 | 1579 | | otherwise
|
| 1647 | - = assert (null unsat_ticks) $
|
|
| 1648 | - return expr
|
|
| 1580 | + = expr
|
|
| 1581 | + |
|
| 1649 | 1582 | where
|
| 1650 | - mark_arity = idCbvMarkArity fn
|
|
| 1651 | - fn_arity = idArity fn
|
|
| 1652 | - excess_arity = (max fn_arity mark_arity) - n_args
|
|
| 1653 | - sat_expr = cpeEtaExpand excess_arity expr
|
|
| 1654 | - applied_marks = n_args >= (length . dropWhile (not . isMarkedCbv) .
|
|
| 1655 | - reverse . expectJust $ (idCbvMarks_maybe fn))
|
|
| 1656 | - -- For join points we never eta-expand (See Note [Do not eta-expand join points])
|
|
| 1657 | - -- so we assert all arguments that need to be passed cbv are visible so that the
|
|
| 1658 | - -- backend can evalaute them if required..
|
|
| 1583 | + must_eta_expand
|
|
| 1584 | + = (hasNoBinding fn && fn_arity > n_args)
|
|
| 1585 | + -- hasNoBinding functions must be saturated
|
|
| 1586 | + || (mark_arity > n_args)
|
|
| 1587 | + -- CBV functions must be CBV-saturated
|
|
| 1588 | + |
|
| 1589 | + desirable_to_eta_expand = fn_arity > n_args && n_args > 0
|
|
| 1590 | + -- n_args > 0: do not eta-expand a naked variable unless we have to
|
|
| 1591 | + |
|
| 1592 | + mark_arity = idCbvMarkArity fn
|
|
| 1593 | + fn_arity = idArity fn
|
|
| 1594 | + excess_arity = (max fn_arity mark_arity) - n_args
|
|
| 1659 | 1595 | |
| 1660 | 1596 | {- Note [Eta expansion]
|
| 1661 | 1597 | ~~~~~~~~~~~~~~~~~~~~~~~
|
| 1662 | -Eta expand to match the arity claimed by the binder Remember,
|
|
| 1663 | -CorePrep must not change arity
|
|
| 1598 | +Eta expand to match the arity claimed by the binder.
|
|
| 1599 | +Remember, CorePrep must not change arity
|
|
| 1664 | 1600 | |
| 1665 | 1601 | Eta expansion might not have happened already, because it is done by
|
| 1666 | 1602 | the simplifier only when there at least one lambda already.
|
| 1667 | 1603 | |
| 1668 | -NB1:we could refrain when the RHS is trivial (which can happen
|
|
| 1669 | - for exported things). This would reduce the amount of code
|
|
| 1670 | - generated (a little) and make things a little worse for
|
|
| 1671 | - code compiled without -O. The case in point is data constructor
|
|
| 1672 | - wrappers.
|
|
| 1604 | +We do eta-expansion (via `cpeEtaExpand`) in three places:
|
|
| 1605 | + |
|
| 1606 | +* At let-bindings; in `cpePair`
|
|
| 1607 | + |
|
| 1608 | +* On function arguments: in `cpeArg`
|
|
| 1609 | + See Note [Eta expansion of arguments in CorePrep]
|
|
| 1610 | + |
|
| 1611 | +* At un-saturated function calls: in `maybeSaturate`
|
|
| 1673 | 1612 | |
| 1674 | 1613 | NB2: we have to be careful that the result of etaExpand doesn't
|
| 1675 | 1614 | invalidate any of the assumptions that CorePrep is attempting
|
| ... | ... | @@ -1677,12 +1616,37 @@ NB2: we have to be careful that the result of etaExpand doesn't |
| 1677 | 1616 | an SCC note - we're now careful in etaExpand to make sure the
|
| 1678 | 1617 | SCC is pushed inside any new lambdas that are generated.
|
| 1679 | 1618 | |
| 1680 | -Note [Eta expansion of hasNoBinding things in CorePrep]
|
|
| 1681 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1682 | -maybeSaturate deals with eta expanding to saturate things that can't deal
|
|
| 1683 | -with unsaturated applications (identified by 'hasNoBinding', currently
|
|
| 1684 | -foreign calls, unboxed tuple/sum constructors, and representation-polymorphic
|
|
| 1685 | -primitives such as 'coerce' and 'unsafeCoerce#').
|
|
| 1619 | +Note [Eta expansion for let-bindings]
|
|
| 1620 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1621 | +Given f = rhs, we eta-expand `rhs` to match f's arity.
|
|
| 1622 | + |
|
| 1623 | +We could refrain when the RHS is trivial (which can happen for exported things).
|
|
| 1624 | +This would reduce the amount of code generated (a little) and make things a
|
|
| 1625 | +little worse for code compiled without -O. The case in point is data
|
|
| 1626 | +constructor wrappers.
|
|
| 1627 | + |
|
| 1628 | +Note [Eta expansion of unsaturated calls]
|
|
| 1629 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1630 | +Give a call (f a1..an), where `f` is a known function with arity greater than `n`,
|
|
| 1631 | +there are three reasons we might want to eta-expand:
|
|
| 1632 | + |
|
| 1633 | +* Must eta-expand: if `f` is a `hasNoBinding` function, we must saturate
|
|
| 1634 | + it, because the function has no (curried) binding to call. Currently
|
|
| 1635 | + this includes:
|
|
| 1636 | + - foreign calls,
|
|
| 1637 | + - unboxed tuple/sum constructors
|
|
| 1638 | + - representation-polymorphic primitives such as 'coerce' and 'unsafeCoerce#'
|
|
| 1639 | + - primops (for now anyway; see comments in `hasNoBinding`)
|
|
| 1640 | + |
|
| 1641 | +* Must eta-expand: if `f` has a call-by-value calling convention, we /must/
|
|
| 1642 | + call it with evaluated arguments. The back end deals with adding the
|
|
| 1643 | + necessary evaluation at the call site, but we must first ensure that it is
|
|
| 1644 | + saturated.
|
|
| 1645 | + |
|
| 1646 | +* May eta-expand: consider
|
|
| 1647 | + \x -> f x True
|
|
| 1648 | + where `f` has arity 3. Then it's much better to eta-expand f so we have
|
|
| 1649 | + \xy -> f x True y
|
|
| 1686 | 1650 | |
| 1687 | 1651 | Historical Note: Note that eta expansion in CorePrep used to be very fragile
|
| 1688 | 1652 | due to the "prediction" of CAFfyness that we used to make during tidying. We
|
| ... | ... | @@ -1694,7 +1658,7 @@ Note [Eta expansion and the CorePrep invariants] |
| 1694 | 1658 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1695 | 1659 | It turns out to be much much easier to do eta expansion
|
| 1696 | 1660 | *after* the main CorePrep stuff. But that places constraints
|
| 1697 | -on the eta expander: given a CpeRhs, it must return a CpeRhs.
|
|
| 1661 | +on the eta expander: given a CpeBody, it must return a CpeBody.
|
|
| 1698 | 1662 | |
| 1699 | 1663 | For example here is what we do not want:
|
| 1700 | 1664 | f = /\a -> g (h 3) -- h has arity 2
|
| ... | ... | @@ -1706,6 +1670,26 @@ and now we do NOT want eta expansion to give |
| 1706 | 1670 | Instead GHC.Core.Opt.Arity.etaExpand gives
|
| 1707 | 1671 | f = /\a -> \y -> let s = h 3 in g s y
|
| 1708 | 1672 | |
| 1673 | +Another example:
|
|
| 1674 | + f x = case x of
|
|
| 1675 | + A -> \y. e
|
|
| 1676 | + B -> hnb 3 -- where `hnb` has no binding
|
|
| 1677 | + C -> z
|
|
| 1678 | +Then we may eta-expand `hnb` to get
|
|
| 1679 | + f x = case x of
|
|
| 1680 | + A -> \y. e
|
|
| 1681 | + B -> \y. hnb 3 y
|
|
| 1682 | + C -> z
|
|
| 1683 | +Now we come to the binding of `f` itself, and eta-expand that, to give
|
|
| 1684 | + f x y = case x of
|
|
| 1685 | + A -> e
|
|
| 1686 | + B -> hnb 3 y
|
|
| 1687 | + C -> z y
|
|
| 1688 | +Notice how important it is that the eta-expansion for `f` doesn't
|
|
| 1689 | +generate any crap like
|
|
| 1690 | + B -> (\y. hnb 3 y) y
|
|
| 1691 | +Fortunately, the eta-expander is careful not to do so.
|
|
| 1692 | + |
|
| 1709 | 1693 | Note [Eta expansion of arguments in CorePrep]
|
| 1710 | 1694 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1711 | 1695 | Suppose `g = \x y. blah` and consider the expression `f (g x)`; we ANFise to
|
| ... | ... | @@ -1798,7 +1782,7 @@ There is a nasty Wrinkle: |
| 1798 | 1782 | #24471 is a good example, where Prep took 25% of compile time!
|
| 1799 | 1783 | -}
|
| 1800 | 1784 | |
| 1801 | -cpeEtaExpand :: Arity -> CpeRhs -> CpeRhs
|
|
| 1785 | +cpeEtaExpand :: Arity -> CpeBody -> CpeBody
|
|
| 1802 | 1786 | cpeEtaExpand arity expr
|
| 1803 | 1787 | | arity == 0 = expr
|
| 1804 | 1788 | | otherwise = etaExpand arity expr
|
| ... | ... | @@ -2165,9 +2149,6 @@ isEmptyFloats (Floats _ b) = isNilOL b |
| 2165 | 2149 | getFloats :: Floats -> OrdList FloatingBind
|
| 2166 | 2150 | getFloats = fs_binds
|
| 2167 | 2151 | |
| 2168 | -unitFloat :: FloatingBind -> Floats
|
|
| 2169 | -unitFloat = snocFloat emptyFloats
|
|
| 2170 | - |
|
| 2171 | 2152 | floatInfo :: FloatingBind -> FloatInfo
|
| 2172 | 2153 | floatInfo (Float _ _ info) = info
|
| 2173 | 2154 | floatInfo UnsafeEqualityCase{} = LazyContextFloatable -- See Note [Floating in CorePrep]
|
| ... | ... | @@ -2255,7 +2236,7 @@ decideFloatInfo FIA{fia_levity=lev, fia_demand=dmd, fia_is_hnf=is_hnf, |
| 2255 | 2236 | | Lifted <- lev = (LetBound, TopLvlFloatable)
|
| 2256 | 2237 | -- And these float freely but can't be speculated, hence LetBound
|
| 2257 | 2238 | |
| 2258 | -mkCaseFloat :: Id -> CpeRhs -> FloatingBind
|
|
| 2239 | +mkCaseFloat :: Id -> CpeBody -> FloatingBind
|
|
| 2259 | 2240 | mkCaseFloat bndr scrut
|
| 2260 | 2241 | = -- pprTrace "mkCaseFloat" (ppr bndr <+> ppr (bound,info)
|
| 2261 | 2242 | -- -- <+> ppr is_lifted <+> ppr is_strict
|
| ... | ... | @@ -2273,7 +2254,7 @@ mkCaseFloat bndr scrut |
| 2273 | 2254 | -- (ok-for-spec case bindings are unlikely anyway.)
|
| 2274 | 2255 | }
|
| 2275 | 2256 | |
| 2276 | -mkNonRecFloat :: CorePrepEnv -> Levity -> Id -> CpeRhs -> (FloatingBind, Id)
|
|
| 2257 | +mkNonRecFloat :: CorePrepEnv -> Levity -> Id -> CpeBody -> (FloatingBind, Id)
|
|
| 2277 | 2258 | mkNonRecFloat env lev bndr rhs
|
| 2278 | 2259 | = -- pprTrace "mkNonRecFloat" (ppr bndr <+> ppr (bound,info)
|
| 2279 | 2260 | -- <+> if is_strict then text "strict" else if is_lifted then text "lazy" else text "unlifted"
|
| ... | ... | @@ -2413,24 +2394,18 @@ instance Outputable FloatDecision where |
| 2413 | 2394 | ppr FloatNone = text "none"
|
| 2414 | 2395 | ppr FloatAll = text "all"
|
| 2415 | 2396 | |
| 2416 | -executeFloatDecision :: CorePrepEnv -> FloatDecision -> Floats -> CpeRhs -> UniqSM (Floats, CpeRhs)
|
|
| 2417 | -executeFloatDecision env dec floats rhs
|
|
| 2397 | +executeFloatDecision :: FloatDecision -> Floats -> CpeBody -> (Floats, CpeBody)
|
|
| 2398 | +executeFloatDecision dec floats rhs
|
|
| 2418 | 2399 | = case dec of
|
| 2419 | - FloatAll -> return (floats, rhs)
|
|
| 2420 | - FloatNone
|
|
| 2421 | - | isEmptyFloats floats -> return (emptyFloats, rhs)
|
|
| 2422 | - | otherwise -> do { (floats', body) <- rhsToBody env rhs
|
|
| 2423 | - ; return (emptyFloats, wrapBinds floats $
|
|
| 2424 | - wrapBinds floats' body) }
|
|
| 2425 | - -- FloatNone case: `rhs` might have lambdas, and we can't
|
|
| 2426 | - -- put them inside a wrapBinds, which expects a `CpeBody`.
|
|
| 2400 | + FloatAll -> (floats, rhs)
|
|
| 2401 | + FloatNone -> (emptyFloats, wrapBinds floats rhs)
|
|
| 2427 | 2402 | |
| 2428 | 2403 | wantFloatTop :: Floats -> FloatDecision
|
| 2429 | 2404 | wantFloatTop fs
|
| 2430 | 2405 | | fs_info fs `floatsAtLeastAsFarAs` TopLvlFloatable = FloatAll
|
| 2431 | 2406 | | otherwise = FloatNone
|
| 2432 | 2407 | |
| 2433 | -wantFloatLocal :: RecFlag -> Demand -> Levity -> Floats -> CpeRhs -> FloatDecision
|
|
| 2408 | +wantFloatLocal :: RecFlag -> Demand -> Levity -> Floats -> CpeBody -> FloatDecision
|
|
| 2434 | 2409 | -- See Note [wantFloatLocal]
|
| 2435 | 2410 | wantFloatLocal is_rec rhs_dmd rhs_lev floats rhs
|
| 2436 | 2411 | | isEmptyFloats floats -- Well yeah...
|
| ... | ... | @@ -2479,7 +2454,7 @@ zero free variables.) |
| 2479 | 2454 | In general, the inliner is good at eliminating these let-bindings. However,
|
| 2480 | 2455 | there is one case where these trivial updatable thunks can arise: when
|
| 2481 | 2456 | we are optimizing away 'lazy' (see Note [lazyId magic], and also
|
| 2482 | -'cpeRhsE'.) Then, we could have started with:
|
|
| 2457 | +'cpeBodyF'.) Then, we could have started with:
|
|
| 2483 | 2458 | |
| 2484 | 2459 | let x :: ()
|
| 2485 | 2460 | x = lazy @() y
|
| ... | ... | @@ -2783,8 +2758,7 @@ wrapTicks floats expr |
| 2783 | 2758 | -- ---------------------------------------------------------------------------
|
| 2784 | 2759 | |
| 2785 | 2760 | -- | Converts Bignum literals into their final CoreExpr
|
| 2786 | -cpeBigNatLit
|
|
| 2787 | - :: CorePrepEnv -> Integer -> UniqSM (Floats, CpeRhs)
|
|
| 2761 | +cpeBigNatLit :: CorePrepEnv -> Integer -> UniqSM (Floats, CpeBody)
|
|
| 2788 | 2762 | cpeBigNatLit env i = assert (i >= 0) $ do
|
| 2789 | 2763 | let
|
| 2790 | 2764 | platform = cp_platform (cpe_config env)
|
| ... | ... | @@ -2434,8 +2434,8 @@ myCoreToStg :: Logger -> DynFlags -> [Var] |
| 2434 | 2434 | , CollectedCCs -- CAF cost centre info (declared and used)
|
| 2435 | 2435 | , StgCgInfos )
|
| 2436 | 2436 | myCoreToStg logger dflags ic_inscope for_bytecode this_mod ml prepd_binds = do
|
| 2437 | - let (stg_binds, denv, cost_centre_info)
|
|
| 2438 | - = {-# SCC "Core2Stg" #-}
|
|
| 2437 | + (stg_binds, denv, cost_centre_info)
|
|
| 2438 | + <- {-# SCC "Core2Stg" #-}
|
|
| 2439 | 2439 | coreToStg (initCoreToStgOpts dflags) this_mod ml prepd_binds
|
| 2440 | 2440 | |
| 2441 | 2441 | (stg_binds_with_fvs,stg_cg_info)
|
| ... | ... | @@ -105,7 +105,7 @@ import GHC.Core ( AltCon(..) ) |
| 105 | 105 | import GHC.Core.Type
|
| 106 | 106 | import GHC.Core.Lint ( lintMessage )
|
| 107 | 107 | |
| 108 | -import GHC.Types.Basic ( TopLevelFlag(..), isTopLevel, isMarkedCbv )
|
|
| 108 | +import GHC.Types.Basic ( TopLevelFlag(..), isTopLevel )
|
|
| 109 | 109 | import GHC.Types.CostCentre ( isCurrentCCS )
|
| 110 | 110 | import GHC.Types.Id
|
| 111 | 111 | import GHC.Types.Var.Set
|
| ... | ... | @@ -123,12 +123,9 @@ import GHC.Unit.Module ( Module ) |
| 123 | 123 | import GHC.Data.Bag ( Bag, emptyBag, isEmptyBag, snocBag, bagToList )
|
| 124 | 124 | |
| 125 | 125 | import Control.Monad
|
| 126 | -import Data.Maybe
|
|
| 127 | -import GHC.Utils.Misc
|
|
| 128 | 126 | import GHC.Core.Multiplicity (scaledThing)
|
| 129 | 127 | import GHC.Settings (Platform)
|
| 130 | 128 | import GHC.Core.TyCon (primRepCompatible, primRepsCompatible)
|
| 131 | -import GHC.Utils.Panic.Plain (panic)
|
|
| 132 | 129 | |
| 133 | 130 | lintStgTopBindings :: forall a . (OutputablePass a, BinderP a ~ Id)
|
| 134 | 131 | => Platform
|
| ... | ... | @@ -174,36 +171,37 @@ lintStgTopBindings platform logger diag_opts opts extra_vars this_mod unarised w |
| 174 | 171 | lint_bind (StgTopStringLit v _) = return [v]
|
| 175 | 172 | |
| 176 | 173 | lintStgConArg :: StgArg -> LintM ()
|
| 177 | -lintStgConArg arg = do
|
|
| 178 | - unarised <- lf_unarised <$> getLintFlags
|
|
| 179 | - when unarised $ case stgArgRep_maybe arg of
|
|
| 180 | - -- Note [Post-unarisation invariants], invariant 4
|
|
| 181 | - Just [_] -> pure ()
|
|
| 182 | - badRep -> addErrL $
|
|
| 183 | - text "Non-unary constructor arg: " <> ppr arg $$
|
|
| 184 | - text "Its PrimReps are: " <> ppr badRep
|
|
| 185 | - |
|
| 186 | - case arg of
|
|
| 187 | - StgLitArg _ -> pure ()
|
|
| 188 | - StgVarArg v -> lintStgVar v
|
|
| 174 | +lintStgConArg arg
|
|
| 175 | + = do { lintStgArg arg
|
|
| 176 | + |
|
| 177 | + ; unarised <- lf_unarised <$> getLintFlags
|
|
| 178 | + ; when unarised $ case stgArgRep_maybe arg of
|
|
| 179 | + -- Note [Post-unarisation invariants], invariant 4
|
|
| 180 | + Just [_] -> pure ()
|
|
| 181 | + badRep -> addErrL $
|
|
| 182 | + text "Non-unary constructor arg: " <> ppr arg $$
|
|
| 183 | + text "Its PrimReps are: " <> ppr badRep }
|
|
| 189 | 184 | |
| 190 | 185 | lintStgFunArg :: StgArg -> LintM ()
|
| 191 | -lintStgFunArg arg = do
|
|
| 192 | - unarised <- lf_unarised <$> getLintFlags
|
|
| 193 | - when unarised $ case stgArgRep_maybe arg of
|
|
| 194 | - -- Note [Post-unarisation invariants], invariant 3
|
|
| 195 | - Just [] -> pure ()
|
|
| 196 | - Just [_] -> pure ()
|
|
| 197 | - badRep -> addErrL $
|
|
| 198 | - text "Function arg is not unary or void: " <> ppr arg $$
|
|
| 199 | - text "Its PrimReps are: " <> ppr badRep
|
|
| 200 | - |
|
| 201 | - case arg of
|
|
| 202 | - StgLitArg _ -> pure ()
|
|
| 203 | - StgVarArg v -> lintStgVar v
|
|
| 204 | - |
|
| 205 | -lintStgVar :: Id -> LintM ()
|
|
| 206 | -lintStgVar id = checkInScope id
|
|
| 186 | +lintStgFunArg arg
|
|
| 187 | + = do { lintStgArg arg
|
|
| 188 | + |
|
| 189 | + ; unarised <- lf_unarised <$> getLintFlags
|
|
| 190 | + ; when unarised $ case stgArgRep_maybe arg of
|
|
| 191 | + -- Note [Post-unarisation invariants], invariant 3
|
|
| 192 | + Just [] -> pure ()
|
|
| 193 | + Just [_] -> pure ()
|
|
| 194 | + badRep -> addErrL $
|
|
| 195 | + text "Function arg is not unary or void: " <> ppr arg $$
|
|
| 196 | + text "Its PrimReps are: " <> ppr badRep }
|
|
| 197 | + |
|
| 198 | +lintStgArg :: StgArg -> LintM ()
|
|
| 199 | +lintStgArg (StgLitArg _) = pure ()
|
|
| 200 | +lintStgArg (StgVarArg v) = do { lintStgVarOcc v
|
|
| 201 | + ; lintAppCbvMarks v [] }
|
|
| 202 | + |
|
| 203 | +lintStgVarOcc :: Id -> LintM ()
|
|
| 204 | +lintStgVarOcc id = checkInScope id
|
|
| 207 | 205 | |
| 208 | 206 | lintStgBinds
|
| 209 | 207 | :: (OutputablePass a, BinderP a ~ Id)
|
| ... | ... | @@ -275,13 +273,11 @@ lintStgExpr :: (OutputablePass a, BinderP a ~ Id) => GenStgExpr a -> LintM () |
| 275 | 273 | |
| 276 | 274 | lintStgExpr (StgLit _) = return ()
|
| 277 | 275 | |
| 278 | -lintStgExpr e@(StgApp fun args) = do
|
|
| 279 | - lintStgVar fun
|
|
| 280 | - mapM_ lintStgFunArg args
|
|
| 281 | - lintAppCbvMarks e
|
|
| 282 | - lintStgAppReps fun args
|
|
| 283 | - |
|
| 284 | - |
|
| 276 | +lintStgExpr (StgApp fun args)
|
|
| 277 | + = do { lintStgVarOcc fun
|
|
| 278 | + ; mapM_ lintStgFunArg args
|
|
| 279 | + ; lintAppCbvMarks fun args
|
|
| 280 | + ; lintStgAppReps fun args }
|
|
| 285 | 281 | |
| 286 | 282 | lintStgExpr app@(StgConApp con _n args _arg_tys) = do
|
| 287 | 283 | -- unboxed sums should vanish during unarise
|
| ... | ... | @@ -413,22 +409,20 @@ lintStgAppReps fun args = do |
| 413 | 409 | |
| 414 | 410 | match_args actual_arg_reps fun_arg_tys_reps
|
| 415 | 411 | |
| 416 | -lintAppCbvMarks :: OutputablePass pass
|
|
| 417 | - => GenStgExpr pass -> LintM ()
|
|
| 418 | -lintAppCbvMarks e@(StgApp fun args) = do
|
|
| 419 | - lf <- getLintFlags
|
|
| 420 | - when (lf_unarised lf) $ do
|
|
| 412 | +lintAppCbvMarks :: Id -> [StgArg] -> LintM ()
|
|
| 413 | +lintAppCbvMarks fun args
|
|
| 414 | + | idCbvMarkArity fun > length args
|
|
| 421 | 415 | -- A function which expects a unlifted argument as n'th argument
|
| 422 | 416 | -- always needs to be applied to n arguments.
|
| 423 | 417 | -- See Note [CBV Function Ids: overview].
|
| 424 | - let marks = fromMaybe [] $ idCbvMarks_maybe fun
|
|
| 425 | - when (length (dropWhileEndLE (not . isMarkedCbv) marks) > length args) $ do
|
|
| 426 | - addErrL $ hang (text "Undersatured cbv marked ID in App" <+> ppr e ) 2 $
|
|
| 427 | - (text "marks" <> ppr marks $$
|
|
| 428 | - text "args" <> ppr args $$
|
|
| 429 | - text "arity" <> ppr (idArity fun) $$
|
|
| 430 | - text "join_arity" <> ppr (idJoinPointHood fun))
|
|
| 431 | -lintAppCbvMarks _ = panic "impossible - lintAppCbvMarks"
|
|
| 418 | + = addErrL $ hang (text "Undersatured cbv marked ID in App" <+> ppr fun)
|
|
| 419 | + 2 (vcat [ text "marks" <> ppr (idCbvMarks_maybe fun)
|
|
| 420 | + , text "args" <> ppr args
|
|
| 421 | + , text "arity" <> ppr (idArity fun)
|
|
| 422 | + , text "join_arity" <> ppr (idJoinPointHood fun) ])
|
|
| 423 | + |
|
| 424 | + | otherwise
|
|
| 425 | + = return ()
|
|
| 432 | 426 | |
| 433 | 427 | {-
|
| 434 | 428 | ************************************************************************
|
| ... | ... | @@ -852,7 +852,7 @@ idCbvMarks_maybe id = case idDetails id of |
| 852 | 852 | _ -> Nothing
|
| 853 | 853 | |
| 854 | 854 | -- Id must be called with at least this arity in order to allow arguments to
|
| 855 | --- be passed unlifted.
|
|
| 855 | +-- be passed unlifted. Return 0 if there are no CBV marks.
|
|
| 856 | 856 | idCbvMarkArity :: Id -> Arity
|
| 857 | 857 | idCbvMarkArity fn = maybe 0 length (idCbvMarks_maybe fn)
|
| 858 | 858 |
| ... | ... | @@ -210,6 +210,7 @@ data IdDetails |
| 210 | 210 | -- Can also work as a WorkerLikeId if given `CbvMark`s.
|
| 211 | 211 | -- See Note [CBV Function Ids: overview]
|
| 212 | 212 | -- The [CbvMark] is always empty (and ignored) until after Tidy.
|
| 213 | + |
|
| 213 | 214 | | WorkerLikeId [CbvMark]
|
| 214 | 215 | -- ^ An 'Id' for a worker like function, which might expect some arguments to be
|
| 215 | 216 | -- passed both evaluated and tagged.
|
| ... | ... | @@ -217,8 +218,10 @@ data IdDetails |
| 217 | 218 | -- aren't used unapplied.
|
| 218 | 219 | -- See Note [CBV Function Ids: overview]
|
| 219 | 220 | -- See Note [EPT enforcement]
|
| 220 | - -- The [CbvMark] is always empty (and ignored) until after Tidy for ids from the current
|
|
| 221 | - -- module.
|
|
| 221 | + -- Invariants:
|
|
| 222 | + -- - the [CbvMark] is always empty (and ignored) until after Tidy
|
|
| 223 | + -- for ids from the current module
|
|
| 224 | + -- - If non-empty, at least is isMarkedCbbv; see (CBV2)
|
|
| 222 | 225 | |
| 223 | 226 | data RecSelInfo
|
| 224 | 227 | = RSI { rsi_def :: [ConLike] -- Record selector defined for these
|
| ... | ... | @@ -297,9 +300,7 @@ Here's how it all works: |
| 297 | 300 | to identify strict arguments. See Note [Call-by-value for worker args] for
|
| 298 | 301 | how a worker guarantees to be strict in strict datacon fields.
|
| 299 | 302 | |
| 300 | - TODO: We currently don't do this for arguments that are unboxed sums or tuples,
|
|
| 301 | - because then we'd have to predict the result of unarisation. But it would be nice to
|
|
| 302 | - do so. See `computeCbvInfo`.
|
|
| 303 | + See (CBV1) and (CBV2).
|
|
| 303 | 304 | |
| 304 | 305 | * During CorePrep calls to CBV Ids are eta expanded.
|
| 305 | 306 | See `GHC.CoreToStg.Prep.maybeSaturate`.
|
| ... | ... | @@ -319,6 +320,16 @@ Here's how it all works: |
| 319 | 320 | * Imported functions may be CBV, and then there is no point in eta-reducing
|
| 320 | 321 | them; we'll just have to eta-expand later; see GHC.Core.Opt.Arity.cantEtaReduceFun.
|
| 321 | 322 | |
| 323 | +Wrinkles
|
|
| 324 | + |
|
| 325 | +(CBV1) We do not set the CBV-marks for a function that takes an unboxed sum or tuple,
|
|
| 326 | + as an argument, because then we'd have to predict the result of unarisation.
|
|
| 327 | + It would be nice to do so in future. See `computeCbvInfo`.
|
|
| 328 | + |
|
| 329 | +(CBV2) We do not set CBV-marks if none of them are `isMarkedCbv`. Why not?
|
|
| 330 | + Because if none are CBV then there is nothing special to do for this function;
|
|
| 331 | + in particular, we don't need to saturate its calls. See `computeCbvInfo`.
|
|
| 332 | + |
|
| 322 | 333 | *** SPJ really? Andreas? ****
|
| 323 | 334 | We only use this for workers and specialized versions of SpecConstr
|
| 324 | 335 | But we also check other functions during tidy and potentially turn some of them into
|
| ... | ... | @@ -5,19 +5,19 @@ Result size of Tidy Core = {terms: 71, types: 43, coercions: 0, joins: 0/0} |
| 5 | 5 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 6 | 6 | F1.f2 :: Integer
|
| 7 | 7 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 8 | -F1.f2 = GHC.Num.Integer.IS 1#
|
|
| 8 | +F1.f2 = GHC.Internal.Bignum.Integer.IS 1#
|
|
| 9 | 9 | |
| 10 | 10 | Rec {
|
| 11 | 11 | -- RHS size: {terms: 24, types: 6, coercions: 0, joins: 0/0}
|
| 12 | 12 | F1.f1_h1 [Occ=LoopBreaker] :: Integer -> Integer -> Integer -> Integer
|
| 13 | 13 | [GblId, Arity=3, Str=<1L><1L><SL>, Unf=OtherCon []]
|
| 14 | 14 | F1.f1_h1
|
| 15 | - = \ (n :: Integer) (x :: Integer) (eta [OS=OneShot] :: Integer) ->
|
|
| 15 | + = \ (n :: Integer) (x [OS=OneShot] :: Integer) (eta [OS=OneShot] :: Integer) ->
|
|
| 16 | 16 | case x of x1 { __DEFAULT ->
|
| 17 | 17 | case n of y1 { __DEFAULT ->
|
| 18 | - case GHC.Num.Integer.integerLt# x1 y1 of {
|
|
| 18 | + case GHC.Internal.Bignum.Integer.integerLt# x1 y1 of {
|
|
| 19 | 19 | __DEFAULT -> eta;
|
| 20 | - 1# -> F1.f1_h1 y1 (GHC.Num.Integer.integerAdd x1 F1.f2) (GHC.Num.Integer.integerAdd x1 eta)
|
|
| 20 | + 1# -> F1.f1_h1 y1 (GHC.Internal.Bignum.Integer.integerAdd x1 F1.f2) (GHC.Internal.Bignum.Integer.integerAdd x1 eta)
|
|
| 21 | 21 | }
|
| 22 | 22 | }
|
| 23 | 23 | }
|
| ... | ... | @@ -26,7 +26,7 @@ end Rec } |
| 26 | 26 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 27 | 27 | F1.f3 :: Integer
|
| 28 | 28 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 29 | -F1.f3 = GHC.Num.Integer.IS 5#
|
|
| 29 | +F1.f3 = GHC.Internal.Bignum.Integer.IS 5#
|
|
| 30 | 30 | |
| 31 | 31 | -- RHS size: {terms: 4, types: 0, coercions: 0, joins: 0/0}
|
| 32 | 32 | f1 :: Integer
|
| ... | ... | @@ -36,27 +36,27 @@ f1 = F1.f1_h1 F1.f3 F1.f2 F1.f3 |
| 36 | 36 | -- RHS size: {terms: 14, types: 5, coercions: 0, joins: 0/0}
|
| 37 | 37 | g :: Integer -> Integer -> Integer -> Integer -> Integer -> Integer
|
| 38 | 38 | [GblId, Arity=5, Str=<1L><SL><SL><SL><SL>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [0 0 0 0 0] 120 0}]
|
| 39 | -g = \ (x1 :: Integer) (x2 :: Integer) (x3 :: Integer) (x4 :: Integer) (x5 :: Integer) -> GHC.Num.Integer.integerAdd (GHC.Num.Integer.integerAdd (GHC.Num.Integer.integerAdd (GHC.Num.Integer.integerAdd x1 x2) x3) x4) x5
|
|
| 39 | +g = \ (x1 :: Integer) (x2 :: Integer) (x3 :: Integer) (x4 :: Integer) (x5 :: Integer) -> GHC.Internal.Bignum.Integer.integerAdd (GHC.Internal.Bignum.Integer.integerAdd (GHC.Internal.Bignum.Integer.integerAdd (GHC.Internal.Bignum.Integer.integerAdd x1 x2) x3) x4) x5
|
|
| 40 | 40 | |
| 41 | 41 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 42 | 42 | F1.s1 :: Integer
|
| 43 | 43 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 44 | -F1.s1 = GHC.Num.Integer.IS 3#
|
|
| 44 | +F1.s1 = GHC.Internal.Bignum.Integer.IS 3#
|
|
| 45 | 45 | |
| 46 | 46 | -- RHS size: {terms: 8, types: 7, coercions: 0, joins: 0/0}
|
| 47 | 47 | s :: forall {t1} {t2}. Num t1 => (t1 -> t2) -> t2
|
| 48 | -[GblId, Arity=2, Str=<MP(A,A,A,A,A,A,1C(1,L))><1C(1,L)>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [30 60] 50 0}]
|
|
| 48 | +[GblId, Arity=2, Str=<MP(A,A,A,A,A,A,1C(1,L))><1C(1,L)>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [90 60] 50 0}]
|
|
| 49 | 49 | s = \ (@t) (@t1) ($dNum :: Num t) (f :: t -> t1) -> f (fromInteger @t $dNum F1.s1)
|
| 50 | 50 | |
| 51 | 51 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 52 | 52 | F1.h1 :: Integer
|
| 53 | 53 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 54 | -F1.h1 = GHC.Num.Integer.IS 24#
|
|
| 54 | +F1.h1 = GHC.Internal.Bignum.Integer.IS 24#
|
|
| 55 | 55 | |
| 56 | 56 | -- RHS size: {terms: 4, types: 1, coercions: 0, joins: 0/0}
|
| 57 | 57 | h :: Integer -> Integer
|
| 58 | 58 | [GblId, Arity=1, Str=<SL>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 30 0}]
|
| 59 | -h = \ (x5 :: Integer) -> GHC.Num.Integer.integerAdd F1.h1 x5
|
|
| 59 | +h = \ (x5 :: Integer) -> GHC.Internal.Bignum.Integer.integerAdd F1.h1 x5
|
|
| 60 | 60 | |
| 61 | 61 | |
| 62 | 62 |
| ... | ... | @@ -5,27 +5,27 @@ Result size of Tidy Core = {terms: 42, types: 44, coercions: 0, joins: 0/0} |
| 5 | 5 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 6 | 6 | F5.f5g1 :: Integer
|
| 7 | 7 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 8 | -F5.f5g1 = GHC.Num.Integer.IS 1#
|
|
| 8 | +F5.f5g1 = GHC.Internal.Bignum.Integer.IS 1#
|
|
| 9 | 9 | |
| 10 | 10 | -- RHS size: {terms: 12, types: 9, coercions: 0, joins: 0/0}
|
| 11 | 11 | f5g :: forall {a} {t}. Num a => (t -> a) -> t -> a
|
| 12 | -[GblId, Arity=3, Str=<SP(1C(1,C(1,L)),A,A,A,A,A,MC(1,L))><MC(1,L)><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [60 60 0] 90 0}]
|
|
| 12 | +[GblId, Arity=3, Str=<SP(1C(1,C(1,L)),A,A,A,A,A,MC(1,L))><MC(1,L)><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [180 60 0] 90 0}]
|
|
| 13 | 13 | f5g = \ (@a) (@t) ($dNum :: Num a) (h :: t -> a) (z :: t) -> + @a $dNum (h z) (fromInteger @a $dNum F5.f5g1)
|
| 14 | 14 | |
| 15 | 15 | -- RHS size: {terms: 17, types: 12, coercions: 0, joins: 0/0}
|
| 16 | 16 | f5h :: forall {a} {t}. Num a => (t -> a) -> t -> (t -> a) -> a
|
| 17 | -[GblId, Arity=4, Str=<SP(SC(S,C(1,L)),A,A,A,A,A,MC(1,L))><MC(1,L)><L><MC(1,L)>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [90 60 0 60] 150 0}]
|
|
| 17 | +[GblId, Arity=4, Str=<SP(SC(S,C(1,L)),A,A,A,A,A,MC(1,L))><MC(1,L)><L><MC(1,L)>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [270 60 0 60] 150 0}]
|
|
| 18 | 18 | f5h = \ (@a) (@t) ($dNum :: Num a) (f :: t -> a) (x :: t) (g :: t -> a) -> + @a $dNum (f x) (+ @a $dNum (g x) (fromInteger @a $dNum F5.f5g1))
|
| 19 | 19 | |
| 20 | 20 | -- RHS size: {terms: 4, types: 1, coercions: 0, joins: 0/0}
|
| 21 | 21 | f5y :: Integer -> Integer
|
| 22 | 22 | [GblId, Arity=1, Str=<1L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 30 0}]
|
| 23 | -f5y = \ (y :: Integer) -> GHC.Num.Integer.integerAdd y F5.f5g1
|
|
| 23 | +f5y = \ (y :: Integer) -> GHC.Internal.Bignum.Integer.integerAdd y F5.f5g1
|
|
| 24 | 24 | |
| 25 | 25 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 26 | 26 | f5 :: Integer
|
| 27 | 27 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 28 | -f5 = GHC.Num.Integer.IS 3#
|
|
| 28 | +f5 = GHC.Internal.Bignum.Integer.IS 3#
|
|
| 29 | 29 | |
| 30 | 30 | |
| 31 | 31 |
| ... | ... | @@ -4,7 +4,7 @@ Result size of Tidy Core = {terms: 24, types: 18, coercions: 0, joins: 0/0} |
| 4 | 4 | |
| 5 | 5 | -- RHS size: {terms: 20, types: 10, coercions: 0, joins: 0/0}
|
| 6 | 6 | f8f :: forall {p}. Num p => Bool -> p -> p -> p
|
| 7 | -[GblId, Arity=4, Str=<LP(SC(S,C(1,L)),A,MC(1,C(1,L)),A,A,A,A)><1L><L><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [90 30 0 0] 140 0}]
|
|
| 7 | +[GblId, Arity=4, Str=<LP(SC(S,C(1,L)),A,MC(1,C(1,L)),A,A,A,A)><1L><L><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [270 30 0 0] 140 0}]
|
|
| 8 | 8 | f8f
|
| 9 | 9 | = \ (@p) ($dNum :: Num p) (b :: Bool) (x :: p) (y :: p) ->
|
| 10 | 10 | case b of {
|
| ... | ... | @@ -15,7 +15,7 @@ f8f |
| 15 | 15 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 16 | 16 | f8 :: Integer
|
| 17 | 17 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 18 | -f8 = GHC.Num.Integer.IS 2#
|
|
| 18 | +f8 = GHC.Internal.Bignum.Integer.IS 2#
|
|
| 19 | 19 | |
| 20 | 20 | |
| 21 | 21 |
| ... | ... | @@ -5,57 +5,23 @@ Result size of Tidy Core = {terms: 136, types: 75, coercions: 0, joins: 2/7} |
| 5 | 5 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 6 | 6 | F11.fib3 :: Integer
|
| 7 | 7 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 8 | -F11.fib3 = GHC.Num.Integer.IS 1#
|
|
| 8 | +F11.fib3 = GHC.Internal.Bignum.Integer.IS 1#
|
|
| 9 | 9 | |
| 10 | 10 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 11 | 11 | F11.fib2 :: Integer
|
| 12 | 12 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 13 | -F11.fib2 = GHC.Num.Integer.IS 2#
|
|
| 14 | - |
|
| 15 | -Rec {
|
|
| 16 | --- RHS size: {terms: 38, types: 13, coercions: 0, joins: 2/2}
|
|
| 17 | -F11.f11_fib [Occ=LoopBreaker] :: Integer -> Integer
|
|
| 18 | -[GblId, Arity=1, Str=<SL>, Unf=OtherCon []]
|
|
| 19 | -F11.f11_fib
|
|
| 20 | - = \ (ds :: Integer) ->
|
|
| 21 | - join {
|
|
| 22 | - $j [Dmd=ML] :: Integer
|
|
| 23 | - [LclId[JoinId(0)(Nothing)]]
|
|
| 24 | - $j
|
|
| 25 | - = join {
|
|
| 26 | - $j1 [Dmd=ML] :: Integer
|
|
| 27 | - [LclId[JoinId(0)(Nothing)]]
|
|
| 28 | - $j1 = GHC.Num.Integer.integerAdd (F11.f11_fib (GHC.Num.Integer.integerSub ds F11.fib3)) (F11.f11_fib (GHC.Num.Integer.integerSub ds F11.fib2)) } in
|
|
| 29 | - case ds of {
|
|
| 30 | - GHC.Num.Integer.IS x1 ->
|
|
| 31 | - case x1 of {
|
|
| 32 | - __DEFAULT -> jump $j1;
|
|
| 33 | - 1# -> F11.fib3
|
|
| 34 | - };
|
|
| 35 | - GHC.Num.Integer.IP x1 -> jump $j1;
|
|
| 36 | - GHC.Num.Integer.IN x1 -> jump $j1
|
|
| 37 | - } } in
|
|
| 38 | - case ds of {
|
|
| 39 | - GHC.Num.Integer.IS x1 ->
|
|
| 40 | - case x1 of {
|
|
| 41 | - __DEFAULT -> jump $j;
|
|
| 42 | - 0# -> F11.fib3
|
|
| 43 | - };
|
|
| 44 | - GHC.Num.Integer.IP x1 -> jump $j;
|
|
| 45 | - GHC.Num.Integer.IN x1 -> jump $j
|
|
| 46 | - }
|
|
| 47 | -end Rec }
|
|
| 13 | +F11.fib2 = GHC.Internal.Bignum.Integer.IS 2#
|
|
| 48 | 14 | |
| 49 | 15 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 50 | 16 | F11.fib1 :: Integer
|
| 51 | 17 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 52 | -F11.fib1 = GHC.Num.Integer.IS 0#
|
|
| 18 | +F11.fib1 = GHC.Internal.Bignum.Integer.IS 0#
|
|
| 53 | 19 | |
| 54 | 20 | -- RHS size: {terms: 54, types: 27, coercions: 0, joins: 0/5}
|
| 55 | -fib :: forall {t} {a}. (Eq t, Num t, Num a) => t -> a
|
|
| 56 | -[GblId, Arity=4, Str=<SP(SC(S,C(1,L)),A)><LP(A,LC(L,C(1,L)),A,A,A,A,L)><LP(LC(S,C(1,L)),A,A,A,A,A,MC(1,L))><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [60 150 60 0] 480 0}]
|
|
| 21 | +fib :: forall {t1} {t2}. (Eq t1, Num t1, Num t2) => t1 -> t2
|
|
| 22 | +[GblId, Arity=4, Str=<SP(SC(S,C(1,L)),A)><LP(A,LC(L,C(1,L)),A,A,A,A,L)><LP(LC(S,C(1,L)),A,A,A,A,A,MC(1,L))><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [180 450 180 0] 480 0}]
|
|
| 57 | 23 | fib
|
| 58 | - = \ (@t) (@a) ($dEq :: Eq t) ($dNum :: Num t) ($dNum1 :: Num a) (eta :: t) ->
|
|
| 24 | + = \ (@t) (@t1) ($dEq :: Eq t) ($dNum :: Num t) ($dNum1 :: Num t1) (eta :: t) ->
|
|
| 59 | 25 | let {
|
| 60 | 26 | lvl :: t
|
| 61 | 27 | [LclId]
|
| ... | ... | @@ -65,32 +31,66 @@ fib |
| 65 | 31 | [LclId]
|
| 66 | 32 | lvl1 = fromInteger @t $dNum F11.fib2 } in
|
| 67 | 33 | let {
|
| 68 | - lvl2 :: a
|
|
| 34 | + lvl2 :: t1
|
|
| 69 | 35 | [LclId]
|
| 70 | - lvl2 = fromInteger @a $dNum1 F11.fib3 } in
|
|
| 36 | + lvl2 = fromInteger @t1 $dNum1 F11.fib3 } in
|
|
| 71 | 37 | let {
|
| 72 | 38 | lvl3 :: t
|
| 73 | 39 | [LclId]
|
| 74 | 40 | lvl3 = fromInteger @t $dNum F11.fib1 } in
|
| 75 | 41 | letrec {
|
| 76 | - fib4 [Occ=LoopBreaker, Dmd=SC(S,L)] :: t -> a
|
|
| 42 | + fib4 [Occ=LoopBreaker, Dmd=SC(S,L)] :: t -> t1
|
|
| 77 | 43 | [LclId, Arity=1, Str=<L>, Unf=OtherCon []]
|
| 78 | 44 | fib4
|
| 79 | 45 | = \ (ds :: t) ->
|
| 80 | 46 | case == @t $dEq ds lvl3 of {
|
| 81 | 47 | False ->
|
| 82 | 48 | case == @t $dEq ds lvl of {
|
| 83 | - False -> + @a $dNum1 (fib4 (- @t $dNum ds lvl)) (fib4 (- @t $dNum ds lvl1));
|
|
| 49 | + False -> + @t1 $dNum1 (fib4 (- @t $dNum ds lvl)) (fib4 (- @t $dNum ds lvl1));
|
|
| 84 | 50 | True -> lvl2
|
| 85 | 51 | };
|
| 86 | 52 | True -> lvl2
|
| 87 | 53 | }; } in
|
| 88 | 54 | fib4 eta
|
| 89 | 55 | |
| 56 | +Rec {
|
|
| 57 | +-- RHS size: {terms: 38, types: 13, coercions: 0, joins: 2/2}
|
|
| 58 | +F11.f11_fib [Occ=LoopBreaker] :: Integer -> Integer
|
|
| 59 | +[GblId, Arity=1, Str=<SL>, Unf=OtherCon []]
|
|
| 60 | +F11.f11_fib
|
|
| 61 | + = \ (ds :: Integer) ->
|
|
| 62 | + join {
|
|
| 63 | + $j [Dmd=ML] :: Integer
|
|
| 64 | + [LclId[JoinId(0)(Nothing)]]
|
|
| 65 | + $j
|
|
| 66 | + = join {
|
|
| 67 | + $j1 [Dmd=ML] :: Integer
|
|
| 68 | + [LclId[JoinId(0)(Nothing)]]
|
|
| 69 | + $j1 = GHC.Internal.Bignum.Integer.integerAdd (F11.f11_fib (GHC.Internal.Bignum.Integer.integerSub ds F11.fib3)) (F11.f11_fib (GHC.Internal.Bignum.Integer.integerSub ds F11.fib2)) } in
|
|
| 70 | + case ds of {
|
|
| 71 | + GHC.Internal.Bignum.Integer.IS x ->
|
|
| 72 | + case x of {
|
|
| 73 | + __DEFAULT -> jump $j1;
|
|
| 74 | + 1# -> F11.fib3
|
|
| 75 | + };
|
|
| 76 | + GHC.Internal.Bignum.Integer.IP x -> jump $j1;
|
|
| 77 | + GHC.Internal.Bignum.Integer.IN x -> jump $j1
|
|
| 78 | + } } in
|
|
| 79 | + case ds of {
|
|
| 80 | + GHC.Internal.Bignum.Integer.IS x ->
|
|
| 81 | + case x of {
|
|
| 82 | + __DEFAULT -> jump $j;
|
|
| 83 | + 0# -> F11.fib3
|
|
| 84 | + };
|
|
| 85 | + GHC.Internal.Bignum.Integer.IP x -> jump $j;
|
|
| 86 | + GHC.Internal.Bignum.Integer.IN x -> jump $j
|
|
| 87 | + }
|
|
| 88 | +end Rec }
|
|
| 89 | + |
|
| 90 | 90 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 91 | 91 | F11.f3 :: Integer
|
| 92 | 92 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 93 | -F11.f3 = GHC.Num.Integer.IS 1000#
|
|
| 93 | +F11.f3 = GHC.Internal.Bignum.Integer.IS 1000#
|
|
| 94 | 94 | |
| 95 | 95 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 96 | 96 | F11.f11_x :: Integer
|
| ... | ... | @@ -100,7 +100,7 @@ F11.f11_x = F11.f11_fib F11.f3 |
| 100 | 100 | -- RHS size: {terms: 4, types: 1, coercions: 0, joins: 0/0}
|
| 101 | 101 | F11.f11f1 :: Integer -> Integer
|
| 102 | 102 | [GblId, Arity=1, Str=<SL>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [0] 30 0}]
|
| 103 | -F11.f11f1 = \ (y :: Integer) -> GHC.Num.Integer.integerAdd F11.f11_x y
|
|
| 103 | +F11.f11f1 = \ (y :: Integer) -> GHC.Internal.Bignum.Integer.integerAdd F11.f11_x y
|
|
| 104 | 104 | |
| 105 | 105 | -- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
|
| 106 | 106 | f11f :: forall {p}. p -> Integer -> Integer
|
| ... | ... | @@ -110,22 +110,22 @@ f11f = \ (@p) _ [Occ=Dead] -> F11.f11f1 |
| 110 | 110 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 111 | 111 | F11.f5 :: Integer
|
| 112 | 112 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 113 | -F11.f5 = GHC.Num.Integer.IS 6#
|
|
| 113 | +F11.f5 = GHC.Internal.Bignum.Integer.IS 6#
|
|
| 114 | 114 | |
| 115 | 115 | -- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
|
| 116 | 116 | F11.f4 :: Integer
|
| 117 | 117 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False, WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 30 0}]
|
| 118 | -F11.f4 = GHC.Num.Integer.integerAdd F11.f11_x F11.f5
|
|
| 118 | +F11.f4 = GHC.Internal.Bignum.Integer.integerAdd F11.f11_x F11.f5
|
|
| 119 | 119 | |
| 120 | 120 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 121 | 121 | F11.f2 :: Integer
|
| 122 | 122 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 123 | -F11.f2 = GHC.Num.Integer.IS 8#
|
|
| 123 | +F11.f2 = GHC.Internal.Bignum.Integer.IS 8#
|
|
| 124 | 124 | |
| 125 | 125 | -- RHS size: {terms: 3, types: 0, coercions: 0, joins: 0/0}
|
| 126 | 126 | F11.f1 :: Integer
|
| 127 | 127 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=False, ConLike=False, WorkFree=False, Expandable=False, Guidance=IF_ARGS [] 30 0}]
|
| 128 | -F11.f1 = GHC.Num.Integer.integerAdd F11.f11_x F11.f2
|
|
| 128 | +F11.f1 = GHC.Internal.Bignum.Integer.integerAdd F11.f11_x F11.f2
|
|
| 129 | 129 | |
| 130 | 130 | -- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
|
| 131 | 131 | f11 :: (Integer, Integer)
|
| ... | ... | @@ -133,7 +133,4 @@ f11 :: (Integer, Integer) |
| 133 | 133 | f11 = (F11.f4, F11.f1)
|
| 134 | 134 | |
| 135 | 135 | |
| 136 | ------- Local rules for imported ids --------
|
|
| 137 | -"SPEC fib @Integer @Integer" forall ($dEq :: Eq Integer) ($dNum :: Num Integer) ($dNum1 :: Num Integer). fib @Integer @Integer $dEq $dNum $dNum1 = F11.f11_fib
|
|
| 138 | - |
|
| 139 | 136 |
| ... | ... | @@ -3,18 +3,18 @@ |
| 3 | 3 | Result size of Tidy Core = {terms: 44, types: 38, coercions: 0, joins: 0/3}
|
| 4 | 4 | |
| 5 | 5 | -- RHS size: {terms: 3, types: 2, coercions: 0, joins: 0/0}
|
| 6 | -F14.f1 :: forall {t}. t -> t
|
|
| 6 | +F14.f1 :: forall t. t -> t
|
|
| 7 | 7 | [GblId, Arity=1, Str=<1L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=True)}]
|
| 8 | 8 | F14.f1 = \ (@t) (y :: t) -> y
|
| 9 | 9 | |
| 10 | 10 | -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
|
| 11 | 11 | F14.f2 :: Integer
|
| 12 | 12 | [GblId, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [] 10 10}]
|
| 13 | -F14.f2 = GHC.Num.Integer.IS 1#
|
|
| 13 | +F14.f2 = GHC.Internal.Bignum.Integer.IS 1#
|
|
| 14 | 14 | |
| 15 | 15 | -- RHS size: {terms: 36, types: 23, coercions: 0, joins: 0/3}
|
| 16 | 16 | f14 :: forall {t}. (Ord t, Num t) => t -> t -> t -> t
|
| 17 | -[GblId, Arity=4, Str=<SP(A,A,SC(S,C(1,L)),A,A,A,A,A)><LP(LC(L,C(1,L)),A,A,A,A,A,MC(1,L))><L><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [30 90 0 0] 310 0}]
|
|
| 17 | +[GblId, Arity=4, Str=<SP(A,A,SC(S,C(1,L)),A,A,A,A,A)><LP(LC(L,C(1,L)),A,A,A,A,A,MC(1,L))><L><L>, Unf=Unf{Src=<vanilla>, TopLvl=True, Value=True, ConLike=True, WorkFree=True, Expandable=True, Guidance=IF_ARGS [90 270 0 0] 310 0}]
|
|
| 18 | 18 | f14
|
| 19 | 19 | = \ (@t) ($dOrd :: Ord t) ($dNum :: Num t) (eta :: t) (eta1 :: t) ->
|
| 20 | 20 | let {
|
| ... | ... | @@ -25,7 +25,7 @@ f14 |
| 25 | 25 | f3 [Occ=LoopBreaker, Dmd=SC(S,C(1,L))] :: t -> t -> t -> t
|
| 26 | 26 | [LclId, Arity=2, Str=<L><L>, Unf=OtherCon []]
|
| 27 | 27 | f3
|
| 28 | - = \ (n :: t) (x :: t) ->
|
|
| 28 | + = \ (n :: t) (x [OS=OneShot] :: t) ->
|
|
| 29 | 29 | case < @t $dOrd x n of {
|
| 30 | 30 | False -> F14.f1 @t;
|
| 31 | 31 | True ->
|
| 1 | +{-# LANGUAGE OverloadedStrings #-}
|
|
| 2 | + |
|
| 3 | +-- GHC used to run out of simplifier ticks due to inlining the internals of
|
|
| 4 | +-- `toStrict . toLazyByteString`.
|
|
| 5 | +module T13960 (breaks) where
|
|
| 6 | + |
|
| 7 | +import Data.ByteString (ByteString)
|
|
| 8 | +import Data.ByteString.Builder (Builder, stringUtf8, toLazyByteString)
|
|
| 9 | +import Data.ByteString.Lazy (toStrict)
|
|
| 10 | +import Data.String (IsString(..))
|
|
| 11 | + |
|
| 12 | +newtype Query = Query ByteString
|
|
| 13 | + |
|
| 14 | +toByteString :: Builder -> ByteString
|
|
| 15 | +toByteString x = toStrict (toLazyByteString x)
|
|
| 16 | + |
|
| 17 | +instance IsString Query where
|
|
| 18 | + fromString = Query . toByteString . stringUtf8
|
|
| 19 | + |
|
| 20 | +breaks :: [(Query, Query)]
|
|
| 21 | +breaks =
|
|
| 22 | + [ ("query001a", "query001b")
|
|
| 23 | + , ("query002a", "query002b")
|
|
| 24 | + , ("query003a", "query003b")
|
|
| 25 | + , ("query004a", "query004b")
|
|
| 26 | + , ("query005a", "query005b")
|
|
| 27 | + , ("query006a", "query006b")
|
|
| 28 | + , ("query007a", "query007b")
|
|
| 29 | + , ("query008a", "query008b")
|
|
| 30 | + , ("query009a", "query009b")
|
|
| 31 | + , ("query010a", "query010b")
|
|
| 32 | + , ("query011a", "query011b")
|
|
| 33 | + , ("query012a", "query012b")
|
|
| 34 | + , ("query013a", "query013b")
|
|
| 35 | + , ("query014a", "query014b")
|
|
| 36 | + , ("query015a", "query015b")
|
|
| 37 | + , ("query016a", "query016b")
|
|
| 38 | + , ("query017a", "query017b")
|
|
| 39 | + , ("query018a", "query018b")
|
|
| 40 | + , ("query019a", "query019b")
|
|
| 41 | + , ("query020a", "query020b")
|
|
| 42 | + , ("query021a", "query021b")
|
|
| 43 | + , ("query022a", "query022b")
|
|
| 44 | + , ("query023a", "query023b")
|
|
| 45 | + , ("query024a", "query024b")
|
|
| 46 | + , ("query025a", "query025b")
|
|
| 47 | + , ("query026a", "query026b")
|
|
| 48 | + , ("query027a", "query027b")
|
|
| 49 | + , ("query028a", "query028b")
|
|
| 50 | + , ("query029a", "query029b")
|
|
| 51 | + , ("query030a", "query030b")
|
|
| 52 | + , ("query031a", "query031b")
|
|
| 53 | + , ("query032a", "query032b")
|
|
| 54 | + , ("query033a", "query033b")
|
|
| 55 | + , ("query034a", "query034b")
|
|
| 56 | + , ("query035a", "query035b")
|
|
| 57 | + , ("query036a", "query036b")
|
|
| 58 | + , ("query037a", "query037b")
|
|
| 59 | + , ("query038a", "query038b")
|
|
| 60 | + , ("query039a", "query039b")
|
|
| 61 | + , ("query040a", "query040b")
|
|
| 62 | + , ("query041a", "query041b")
|
|
| 63 | + , ("query042a", "query042b")
|
|
| 64 | + , ("query043a", "query043b")
|
|
| 65 | + , ("query044a", "query044b")
|
|
| 66 | + , ("query045a", "query045b")
|
|
| 67 | + , ("query046a", "query046b")
|
|
| 68 | + , ("query047a", "query047b")
|
|
| 69 | + , ("query048a", "query048b")
|
|
| 70 | + , ("query049a", "query049b")
|
|
| 71 | + , ("query050a", "query050b")
|
|
| 72 | + ] |
| ... | ... | @@ -686,6 +686,12 @@ test ('T13820', |
| 686 | 686 | ],
|
| 687 | 687 | compile,
|
| 688 | 688 | ['-v0'])
|
| 689 | +test ('T13960',
|
|
| 690 | + [ collect_compiler_stats('peak_megabytes_allocated', 20),
|
|
| 691 | + collect_compiler_stats('bytes allocated', 2),
|
|
| 692 | + ],
|
|
| 693 | + compile,
|
|
| 694 | + ['-O'])
|
|
| 689 | 695 | test ('T14766',
|
| 690 | 696 | [ collect_compiler_stats('bytes allocated',2),
|
| 691 | 697 | pre_cmd('python3 genT14766.py > T14766.hs'),
|
| ... | ... | @@ -10,7 +10,7 @@ f :: forall a b. C a b => a -> b |
| 10 | 10 | Str=<1P(A,1C(1,C(1,L)))><L>,
|
| 11 | 11 | Unf=Unf{Src=<vanilla>, TopLvl=True,
|
| 12 | 12 | Value=True, ConLike=True, WorkFree=True, Expandable=True,
|
| 13 | - Guidance=IF_ARGS [30 0] 40 0}]
|
|
| 13 | + Guidance=IF_ARGS [90 0] 40 0}]
|
|
| 14 | 14 | f = \ (@a) (@b) ($dC :: C a b) (x :: a) -> op @a @b $dC x x
|
| 15 | 15 | |
| 16 | 16 |
| ... | ... | @@ -91,12 +91,17 @@ stgify :: ModSummary -> ModGuts -> Ghc [StgTopBinding] |
| 91 | 91 | stgify summary guts = do
|
| 92 | 92 | hsc_env <- getSession
|
| 93 | 93 | let dflags = hsc_dflags hsc_env
|
| 94 | - prepd_binds <- liftIO $ do
|
|
| 94 | + liftIO $ do
|
|
| 95 | 95 | cp_cfg <- initCorePrepConfig hsc_env
|
| 96 | - corePrepPgm (hsc_logger hsc_env) cp_cfg (initCorePrepPgmConfig dflags (interactiveInScope $ hsc_IC hsc_env)) this_mod core_binds
|
|
| 97 | - return $ fstOf3 $ coreToStg (initCoreToStgOpts dflags) (ms_mod summary) (ms_location summary) prepd_binds
|
|
| 98 | - where this_mod = mg_module guts
|
|
| 99 | - core_binds = mg_binds guts
|
|
| 96 | + prepd_binds <- corePrepPgm (hsc_logger hsc_env) cp_cfg
|
|
| 97 | + (initCorePrepPgmConfig dflags (interactiveInScope $ hsc_IC hsc_env))
|
|
| 98 | + this_mod core_binds
|
|
| 99 | + (binds, _, _) <- coreToStg (initCoreToStgOpts dflags) (ms_mod summary)
|
|
| 100 | + (ms_location summary) prepd_binds
|
|
| 101 | + return binds
|
|
| 102 | + where
|
|
| 103 | + this_mod = mg_module guts
|
|
| 104 | + core_binds = mg_binds guts
|
|
| 100 | 105 | |
| 101 | 106 | slurpCmm :: HscEnv -> FilePath -> IO (CmmGroup)
|
| 102 | 107 | slurpCmm hsc_env filename = runHsc hsc_env $ do
|