Simon Peyton Jones pushed to branch wip/spj-try-opt-coercion at Glasgow Haskell Compiler / GHC
Commits:
-
2b2ee165
by Simon Peyton Jones at 2026-01-12T17:31:42+00:00
18 changed files:
- compiler/GHC/Builtin/PrimOps.hs
- compiler/GHC/Core.hs
- compiler/GHC/Core/Coercion/Opt.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Make.hs
- compiler/GHC/Core/Opt/CSE.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Core/Opt/FloatIn.hs
- compiler/GHC/Core/Opt/SetLevels.hs
- compiler/GHC/Core/Opt/Simplify/Env.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Opt/Simplify/Utils.hs
- compiler/GHC/Core/Opt/Specialise.hs
- compiler/GHC/Core/SimpleOpt.hs
- compiler/GHC/Core/TyCo/FVs.hs
- compiler/GHC/Core/TyCo/Subst.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/Stg/Lint.hs
Changes:
| ... | ... | @@ -435,12 +435,12 @@ follows, in decreasing order of permissiveness: |
| 435 | 435 | NoEffect, we may float such an invalid call out of a dead branch
|
| 436 | 436 | and speculatively evaluate it.
|
| 437 | 437 | |
| 438 | - In particular, we cannot safely rewrite such an invalid call to a
|
|
| 439 | - runtime error; we must emit code that produces a valid Word32#.
|
|
| 440 | - (If we're lucky, Core Lint may complain that the result of such a
|
|
| 441 | - rewrite violates the let-can-float invariant (#16742), but the
|
|
| 442 | - rewrite is always wrong!) See also Note [Guarding against silly shifts]
|
|
| 443 | - in GHC.Core.Opt.ConstantFold.
|
|
| 438 | + In particular, we cannot safely rewrite such an invalid call to a runtime
|
|
| 439 | + error; we must emit code that produces a valid Word32#. (If we're lucky,
|
|
| 440 | + Core Lint may complain that the result of such a rewrite violates
|
|
| 441 | + Note [Core binding invariants: nested non-rec] (#16742), but the rewrite
|
|
| 442 | + is always wrong!) See also Note [Guarding against silly shifts] in
|
|
| 443 | + GHC.Core.Opt.ConstantFold.
|
|
| 444 | 444 | |
| 445 | 445 | Marking uncheckedShiftLWord32# as CanFail instead of NoEffect
|
| 446 | 446 | would give us the freedom to rewrite such invalid calls to runtime
|
| ... | ... | @@ -578,12 +578,12 @@ Several predicates on primops test this flag: |
| 578 | 578 | where it is guarded by exprOkToDiscard, which in turn checks
|
| 579 | 579 | primOpOkToDiscard.
|
| 580 | 580 | |
| 581 | - * The "no-float-out" thing is achieved by ensuring that we never
|
|
| 582 | - let-bind a saturated primop application unless it has NoEffect.
|
|
| 583 | - The RHS of a let-binding (which can float in and out freely)
|
|
| 584 | - satisfies exprOkForSpeculation; this is the let-can-float
|
|
| 585 | - invariant. And exprOkForSpeculation is false of a saturated
|
|
| 586 | - primop application unless it has NoEffect.
|
|
| 581 | + * The "no-float-out" thing is achieved by ensuring that we never let-bind a
|
|
| 582 | + saturated primop application unless it has NoEffect. The RHS of a
|
|
| 583 | + let-binding (which can float in and out freely) satisfies
|
|
| 584 | + exprOkForSpeculation; this is Note [Core binding invariants: nested non-rec].
|
|
| 585 | + And exprOkForSpeculation is false of a saturated primop application unless it
|
|
| 586 | + has NoEffect.
|
|
| 587 | 587 | |
| 588 | 588 | * So primops that aren't NoEffect will appear only as the
|
| 589 | 589 | scrutinees of cases, and that's why the FloatIn pass is capable
|
| ... | ... | @@ -188,8 +188,7 @@ These data types are the heart of the compiler |
| 188 | 188 | -- this corresponds to allocating a thunk for the things
|
| 189 | 189 | -- bound and then executing the sub-expression.
|
| 190 | 190 | --
|
| 191 | --- See Note [Core letrec invariant]
|
|
| 192 | --- See Note [Core let-can-float invariant]
|
|
| 191 | +-- See Note [Core binding invariants]
|
|
| 193 | 192 | -- See Note [Representation polymorphism invariants]
|
| 194 | 193 | -- See Note [Core type and coercion invariant]
|
| 195 | 194 | --
|
| ... | ... | @@ -393,25 +392,37 @@ extremely difficult to GUARANTEE it: |
| 393 | 392 | |
| 394 | 393 | * See Note [Shadowing in SpecConstr] in GHC.Core.Opt.SpecContr
|
| 395 | 394 | |
| 396 | -Note [Core letrec invariant]
|
|
| 397 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 398 | -The Core letrec invariant:
|
|
| 395 | +Note [Core binding invariants]
|
|
| 396 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 397 | +A core binding, `CoreBind`, obeys these invariants:
|
|
| 399 | 398 | |
| 400 | - The right hand sides of all /top-level/ or /recursive/
|
|
| 401 | - bindings must be of lifted type
|
|
| 399 | +* For /top level/ or /recursive/ bindings,
|
|
| 400 | + see Note [Top-level binding invariants]
|
|
| 402 | 401 | |
| 403 | -See "Type#type_classification" in GHC.Core.Type
|
|
| 404 | -for the meaning of "lifted" vs. "unlifted".
|
|
| 402 | +* For /nested/ (not top-level) /non-recursive/ bindings,
|
|
| 403 | + see Note [Nested binding invariants]
|
|
| 404 | + |
|
| 405 | +Note [Top-level binding invariants]
|
|
| 406 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 407 | +A /top-level/ or /recursive/ binding must
|
|
| 405 | 408 | |
| 406 | -For the non-top-level, non-recursive case see
|
|
| 407 | -Note [Core let-can-float invariant].
|
|
| 409 | + * be of lifted type
|
|
| 410 | +OR
|
|
| 411 | + * have a RHS that is a primitive string literal
|
|
| 412 | + (see Note [Core top-level string literals], or
|
|
| 413 | +OR
|
|
| 414 | + * have a rhs that is (Coercion co)
|
|
| 415 | +OR
|
|
| 416 | + * be a worker or wrapper for an unlifted non-newtype data constructor; see (TL1).
|
|
| 408 | 417 | |
| 409 | -At top level, however, there are two exceptions to this rule:
|
|
| 418 | +For the non-top-level, non-recursive case see Note [Nested binding invariants].
|
|
| 419 | +(NB: this Note applies to recursive as well as top-level bindings, but I wanted
|
|
| 420 | +a short title!)
|
|
| 410 | 421 | |
| 411 | -(TL1) A top-level binding is allowed to bind primitive string literal,
|
|
| 412 | - (which is unlifted). See Note [Core top-level string literals].
|
|
| 422 | +See "Type#type_classification" in GHC.Core.Type
|
|
| 423 | +for the meaning of "lifted" vs. "unlifted".
|
|
| 413 | 424 | |
| 414 | -(TL2) In Core, we generate a top-level binding for every non-newtype data
|
|
| 425 | +(TL1) In Core, we generate a top-level binding for every non-newtype data
|
|
| 415 | 426 | constructor worker or wrapper
|
| 416 | 427 | e.g. data T = MkT Int
|
| 417 | 428 | we generate
|
| ... | ... | @@ -428,16 +439,17 @@ constructor worker or wrapper |
| 428 | 439 | S1 = S1
|
| 429 | 440 | We allow this top-level unlifted binding to exist.
|
| 430 | 441 | |
| 431 | -Note [Core let-can-float invariant]
|
|
| 432 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 433 | -The let-can-float invariant:
|
|
| 434 | - |
|
| 435 | - The right hand side of a /non-top-level/, /non-recursive/ binding
|
|
| 436 | - may be of unlifted type, but only if
|
|
| 437 | - the expression is ok-for-speculation
|
|
| 438 | - or the 'Let' is for a join point.
|
|
| 442 | +Note [Nested binding invariants]
|
|
| 443 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 444 | +A /non-top-level/, /non-recursive/ binding must
|
|
| 445 | + * Be a join point; see Note [Invariants on join points]
|
|
| 446 | +OR
|
|
| 447 | + * Be of lifted type
|
|
| 448 | +OR
|
|
| 449 | + * Have a RHS that is ok-for-speculation
|
|
| 439 | 450 | |
| 440 | - (For top-level or recursive lets see Note [Core letrec invariant].)
|
|
| 451 | +NB: this only applies to /non-recursive/ bindings. For recursive
|
|
| 452 | +(or top-level) bindings see Note [Top-level binding invariants].
|
|
| 441 | 453 | |
| 442 | 454 | This means that the let can be floated around
|
| 443 | 455 | without difficulty. For example, this is OK:
|
| ... | ... | @@ -454,14 +466,14 @@ In this situation you should use @case@ rather than a @let@. The function |
| 454 | 466 | alternatively use 'GHC.Core.Make.mkCoreLet' rather than this constructor directly,
|
| 455 | 467 | which will generate a @case@ if necessary
|
| 456 | 468 | |
| 457 | -The let-can-float invariant is initially enforced by mkCoreLet in GHC.Core.Make.
|
|
| 469 | +The Core binding invariants are initially enforced by mkCoreLet in GHC.Core.Make.
|
|
| 458 | 470 | |
| 459 | 471 | Historical Note [The let/app invariant]
|
| 460 | 472 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 461 | -Before 2022 GHC used the "let/app invariant", which applied the let-can-float rules
|
|
| 462 | -to the argument of an application, as well as to the RHS of a let. This made some
|
|
| 463 | -kind of sense, because 'let' can always be encoded as application:
|
|
| 464 | - let x=rhs in b = (\x.b) rhs
|
|
| 473 | +Before 2022 GHC used the "let/app invariant", which applied
|
|
| 474 | +Note [Nested binding invariants] to the argument of an application,
|
|
| 475 | +as well as to the RHS of a let. This made some kind of sense, because 'let' can
|
|
| 476 | +always be encoded as application: let x=rhs in b = (\x.b) rhs
|
|
| 465 | 477 | |
| 466 | 478 | But the let/app invariant got in the way of RULES; see #19313. For example
|
| 467 | 479 | up :: Int# -> Int#
|
| ... | ... | @@ -472,7 +484,7 @@ Indeed RULES is a big reason that GHC doesn't use ANF, where the argument of an |
| 472 | 484 | application is always a variable or a constant. To allow RULES to work nicely
|
| 473 | 485 | we need to allow lots of things in the arguments of a call.
|
| 474 | 486 | |
| 475 | -TL;DR: we relaxed the let/app invariant to become the let-can-float invariant.
|
|
| 487 | +TL;DR: we relaxed the let/app invariant to focus just on /bindings/.
|
|
| 476 | 488 | |
| 477 | 489 | Note [Core top-level string literals]
|
| 478 | 490 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -631,13 +643,33 @@ checked by Core Lint. |
| 631 | 643 | |
| 632 | 644 | Note [Core type and coercion invariant]
|
| 633 | 645 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 634 | -We allow a /non-recursive/, /non-top-level/ let to bind type and
|
|
| 635 | -coercion variables. These can be very convenient for postponing type
|
|
| 636 | -substitutions until the next run of the simplifier.
|
|
| 646 | +We allow `let` to bind type and coercion variables.
|
|
| 647 | + |
|
| 648 | +* A type or coercion binding is always /non-recursive/
|
|
| 649 | + |
|
| 650 | +* A type binding cannot be top level (yet) but a coercion binding
|
|
| 651 | + can be top-level.
|
|
| 637 | 652 | |
| 638 | 653 | * A type variable binding must have a RHS of (Type ty)
|
| 639 | 654 | |
| 640 | 655 | * A coercion variable binding must have a RHS of (Coercion co)
|
| 656 | + See Note [Coercion bindings]
|
|
| 657 | + |
|
| 658 | + |
|
| 659 | +Note [Coercion bindings]
|
|
| 660 | +~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 661 | +We allow non-recursive let-bindings for coercion variables, CoVars,
|
|
| 662 | +of type (t1 ~r# t2).
|
|
| 663 | + |
|
| 664 | +The /main motivation/ is to support sharing:
|
|
| 665 | + let g::T a ~# b
|
|
| 666 | + g = Coercion <some big coercion?
|
|
| 667 | + in ...g..g..g...
|
|
| 668 | +If we simply duplicate `g` at every occurrence site, we can bloat the
|
|
| 669 | +size of the program, increasing both compile time and .hi-file sizes.
|
|
| 670 | + |
|
| 671 | +* A coercion binding always has a RHS of (Coercion co).
|
|
| 672 | + See Note [Core type and coercion invariants].
|
|
| 641 | 673 | |
| 642 | 674 | It is possible to have terms that return a coercion, but we use
|
| 643 | 675 | case-binding for those; e.g.
|
| ... | ... | @@ -650,6 +682,15 @@ substitutions until the next run of the simplifier. |
| 650 | 682 | Note [Equality superclasses in quantified constraints]
|
| 651 | 683 | in GHC.Tc.Solver.Dict
|
| 652 | 684 | |
| 685 | +* Coercion bindings can be top level. And a top-level coercion binding can be
|
|
| 686 | + exported, and hence must:
|
|
| 687 | + * Have a GlobalId.
|
|
| 688 | + * Appear as a declaration in an interface file
|
|
| 689 | + That means that a coercion might mention a CoVar that is an imported GlobalId.
|
|
| 690 | + Just as for Core expressions, the free variable finder for Coercions can
|
|
| 691 | + ignore GlobalIds.
|
|
| 692 | + |
|
| 693 | + |
|
| 653 | 694 | Note [Representation polymorphism invariants]
|
| 654 | 695 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 655 | 696 | GHC allows us to abstract over calling conventions using **representation polymorphism**.
|
| ... | ... | @@ -846,7 +887,7 @@ Join points must follow these invariants: |
| 846 | 887 | However, join points have simpler invariants in other ways
|
| 847 | 888 | |
| 848 | 889 | 5. A join point can have an unboxed type without the RHS being
|
| 849 | - ok-for-speculation (i.e. drop the let-can-float invariant)
|
|
| 890 | + ok-for-speculation; see
|
|
| 850 | 891 | e.g. let j :: Int# = factorial x in ...
|
| 851 | 892 | |
| 852 | 893 | 6. The RHS of join point is not required to have a fixed runtime representation,
|
| ... | ... | @@ -2053,8 +2094,8 @@ mkDoubleLitDouble :: Double -> Expr b |
| 2053 | 2094 | mkDoubleLit d = Lit (mkLitDouble d)
|
| 2054 | 2095 | mkDoubleLitDouble d = Lit (mkLitDouble (toRational d))
|
| 2055 | 2096 | |
| 2056 | --- | Bind all supplied binding groups over an expression in a nested let expression. Assumes
|
|
| 2057 | --- that the rhs satisfies the let-can-float invariant. Prefer to use
|
|
| 2097 | +-- | Bind all supplied binding groups over an expression in a nested let expression.
|
|
| 2098 | +-- Assumes that the rhs satisfies Note [Nested binding invariants]. Prefer to use
|
|
| 2058 | 2099 | -- 'GHC.Core.Make.mkCoreLets' if possible, which does guarantee the invariant
|
| 2059 | 2100 | mkLets :: [Bind b] -> Expr b -> Expr b
|
| 2060 | 2101 | -- | Bind all supplied binders over an expression in a nested lambda expression. Prefer to
|
| ... | ... | @@ -46,7 +46,7 @@ Note [Coercion optimisation] |
| 46 | 46 | This module does coercion optimisation. The purpose is to reduce the size
|
| 47 | 47 | of the coercions that the compiler carries around -- they are just proofs,
|
| 48 | 48 | and serve no runtime need. So the purpose of coercion optimisation is simply
|
| 49 | -to shrink coercions and thereby reduce compile time.
|
|
| 49 | +to shrink coercions and thereby reduce compile time and .hi file sizes.
|
|
| 50 | 50 | |
| 51 | 51 | See the paper
|
| 52 | 52 | Evidence normalization in Systtem FV (RTA'13)
|
| ... | ... | @@ -57,7 +57,7 @@ However, although powerful and occasionally very effective, coercion |
| 57 | 57 | optimisation can itself be very expensive (#26679). So we apply it sparingly:
|
| 58 | 58 | |
| 59 | 59 | * In the Simplifier, function `rebuild_go`, we use `isReflexiveCo` (which
|
| 60 | - computes the type of the coercion) to eliminate reflexive coercion, just
|
|
| 60 | + computes the type of the coercion) to eliminate reflexive coercions, just
|
|
| 61 | 61 | before we build a cast (e |> co).
|
| 62 | 62 | |
| 63 | 63 | (More precisely, we use `isReflexiveCoIgnoringMultiplicity;
|
| ... | ... | @@ -196,6 +196,10 @@ We use the following invariants: |
| 196 | 196 | %********************************************************************* -}
|
| 197 | 197 | |
| 198 | 198 | optCoProgram :: CoreProgram -> CoreProgram
|
| 199 | +-- Apply optCoercion to all coercions in /expressions/
|
|
| 200 | +-- There may also be coercions in /types/ but we `optCoProgram` doesn't
|
|
| 201 | +-- look at them; they are typically fewer and smaller, and it doesn't seem
|
|
| 202 | +-- worth the cost of traversing and rebuilding all the types in the program.
|
|
| 199 | 203 | optCoProgram binds
|
| 200 | 204 | = map go binds
|
| 201 | 205 | where
|
| ... | ... | @@ -237,7 +241,24 @@ optCoAlt is (Alt k bs e) |
| 237 | 241 | %* *
|
| 238 | 242 | %********************************************************************* -}
|
| 239 | 243 | |
| 244 | +{- Note [optCoRefl]
|
|
| 245 | +~~~~~~~~~~~~~~~~~~~~
|
|
| 246 | +`optCoRefl` is an experimental cheap-and-cheerful version of `optCoercion`.
|
|
| 247 | + |
|
| 248 | +* It focuses entirely on chains of TransCo, thus
|
|
| 249 | + co1 ; co2 ; co3 ; ... ; con
|
|
| 250 | + |
|
| 251 | +* It looks for sub-sequences in this chain that are Refl, based on their
|
|
| 252 | + types. The clever business is all in `gobble`, which springs into action
|
|
| 253 | + when we find a `TransCo`.
|
|
| 254 | + |
|
| 255 | +* It can sometimes do a bit more than `optCoercion`. It'll eliminate /any/
|
|
| 256 | + subsequence of co1..con that is reflexive, whereas `optCoercion` just works
|
|
| 257 | + left-to-right, and won't spot (co1 ; co2 ; sym co2)
|
|
| 258 | +-}
|
|
| 259 | + |
|
| 240 | 260 | optCoRefl :: Coercion -> Coercion
|
| 261 | +-- See Note [optCoRefl]
|
|
| 241 | 262 | optCoRefl in_co
|
| 242 | 263 | #ifdef DEBUG
|
| 243 | 264 | -- Debug check that optCoRefl doesn't change the type
|
| ... | ... | @@ -586,8 +586,7 @@ lintLetBind top_lvl rec_flag binder rhs rhs_ty |
| 586 | 586 | ; checkL (not (isCoVar binder) || isCoArg rhs)
|
| 587 | 587 | (mkLetErr binder rhs)
|
| 588 | 588 | |
| 589 | - -- Check the let-can-float invariant
|
|
| 590 | - -- See Note [Core let-can-float invariant] in GHC.Core
|
|
| 589 | + -- Check Note [Core binding invariants] in GHC.Core
|
|
| 591 | 590 | ; checkL (bindingIsOk top_lvl rec_flag binder binder_ty rhs) $
|
| 592 | 591 | mkLetErr binder rhs
|
| 593 | 592 | |
| ... | ... | @@ -647,6 +646,7 @@ lintLetBind top_lvl rec_flag binder rhs rhs_ty |
| 647 | 646 | -- the unfolding is a SimplifiableCoreExpr. Give up for now.
|
| 648 | 647 | |
| 649 | 648 | bindingIsOk :: TopLevelFlag -> RecFlag -> OutId -> OutType -> CoreExpr -> Bool
|
| 649 | +-- Checks the invariants of Note [Core binding invariants] in GHC.Core
|
|
| 650 | 650 | bindingIsOk top_lvl rec_flag binder binder_ty rhs
|
| 651 | 651 | | isCoVar binder
|
| 652 | 652 | = isCoArg rhs
|
| ... | ... | @@ -112,8 +112,9 @@ sortQuantVars vs = sorted_tcvs ++ ids |
| 112 | 112 | -- | Bind a binding group over an expression, using a @let@ or @case@ as
|
| 113 | 113 | -- appropriate (see "GHC.Core#let_can_float_invariant")
|
| 114 | 114 | mkCoreLet :: HasDebugCallStack => CoreBind -> CoreExpr -> CoreExpr
|
| 115 | -mkCoreLet (NonRec bndr rhs) body -- See Note [Core let-can-float invariant]
|
|
| 116 | - = bindNonRec bndr rhs body
|
|
| 115 | +mkCoreLet (NonRec bndr rhs) body
|
|
| 116 | + = -- See Note [Core binding invariants: nested non-rec]
|
|
| 117 | + bindNonRec bndr rhs body
|
|
| 117 | 118 | mkCoreLet bind body
|
| 118 | 119 | = Let bind body
|
| 119 | 120 |
| ... | ... | @@ -288,8 +288,8 @@ all trivial expressions. Consider |
| 288 | 288 | case x |> co of (y::Array# Int) { ... }
|
| 289 | 289 | |
| 290 | 290 | We do not want to extend the substitution with (y -> x |> co); since y
|
| 291 | -is of unlifted type, this would destroy the let-can-float invariant if
|
|
| 292 | -(x |> co) was not ok-for-speculation.
|
|
| 291 | +is of unlifted type, this would destroy Note [Nested binding invariants]
|
|
| 292 | +if (x |> co) was not ok-for-speculation.
|
|
| 293 | 293 | |
| 294 | 294 | But surely (x |> co) is ok-for-speculation, because it's a trivial
|
| 295 | 295 | expression, and x's type is also unlifted, presumably. Well, maybe
|
| ... | ... | @@ -1606,11 +1606,11 @@ as follows: |
| 1606 | 1606 | let x = I# (error "invalid shift")
|
| 1607 | 1607 | in ...
|
| 1608 | 1608 | |
| 1609 | -This was originally done in the fix to #16449 but this breaks the
|
|
| 1610 | -let-can-float invariant (see Note [Core let-can-float invariant] in
|
|
| 1611 | -GHC.Core) as noted in #16742. For the reasons discussed under
|
|
| 1612 | -"NoEffect" in Note [Classifying primop effects] (in GHC.Builtin.PrimOps)
|
|
| 1613 | -there is no safe way to rewrite the argument of I# such that it bottoms.
|
|
| 1609 | +This was originally done in the fix to #16449 but this breaks
|
|
| 1610 | +Note [Nested binding invariants] in GHC.Core, as noted in #16742. For the
|
|
| 1611 | +reasons discussed under "NoEffect" in Note [Classifying primop effects] (in
|
|
| 1612 | +GHC.Builtin.PrimOps) there is no safe way to rewrite the argument of I# such
|
|
| 1613 | +that it bottoms.
|
|
| 1614 | 1614 | |
| 1615 | 1615 | Consequently we instead take advantage of the fact that the result of a
|
| 1616 | 1616 | large shift is unspecified (see associated documentation in primops.txt.pp)
|
| ... | ... | @@ -2177,15 +2177,15 @@ BigNat). These rules implement the same kind of constant folding as we have for |
| 2177 | 2177 | Int#/Word#/etc. primops. See builtinBignumRules.
|
| 2178 | 2178 | |
| 2179 | 2179 | These rules are built-in because they can't be expressed as regular rules for
|
| 2180 | -now. The reason is that due to the let-can-float invariant (see Note [Core
|
|
| 2181 | -let-can-float invariant] in GHC.Core), GHC is too conservative with some bignum
|
|
| 2182 | -operations and they don't match rules. For example:
|
|
| 2180 | +now. The reason is that due to Note [Nested binding invariants] in GHC.Core,
|
|
| 2181 | +GHC is too conservative with some bignum operations and they don't match rules.
|
|
| 2182 | +For example:
|
|
| 2183 | 2183 | |
| 2184 | 2184 | case integerAdd 1 x of r { _ -> integerAdd 1 r }
|
| 2185 | 2185 | |
| 2186 | 2186 | doesn't constant-fold into `integerAdd 2 x` with a regular rule. That's because
|
| 2187 | 2187 | GHC never floats in `integerAdd 1 x` to form `integerAdd 1 (integerAdd 1 x)`
|
| 2188 | -because of the let-can-float invariant (it doesn't know if `integerAdd`
|
|
| 2188 | +because of Note [Nested binding invariants] (it doesn't know if `integerAdd`
|
|
| 2189 | 2189 | terminates).
|
| 2190 | 2190 | |
| 2191 | 2191 | In the built-in rule for `integerAdd` we can access the unfolding of `r` and we
|
| ... | ... | @@ -665,7 +665,8 @@ noFloatIntoRhs is_rec bndr rhs |
| 665 | 665 | = isRec is_rec -- Joins are one-shot iff non-recursive
|
| 666 | 666 | |
| 667 | 667 | | definitelyUnliftedType (idType bndr)
|
| 668 | - = True -- Preserve let-can-float invariant, see Note [noFloatInto considerations]
|
|
| 668 | + = True -- Preserve Note [Nested binding invariants],
|
|
| 669 | + -- see Note [noFloatInto considerations]
|
|
| 669 | 670 | |
| 670 | 671 | | otherwise
|
| 671 | 672 | = noFloatIntoArg rhs
|
| ... | ... | @@ -690,7 +691,7 @@ When do we want to float bindings into |
| 690 | 691 | - noFloatIntoArg: the argument of a function application
|
| 691 | 692 | |
| 692 | 693 | Definitely don't float into RHS if it has unlifted type;
|
| 693 | -that would destroy the let-can-float invariant.
|
|
| 694 | +that would destroy Note [Nested binding invariants].
|
|
| 694 | 695 | |
| 695 | 696 | * Wrinkle 1: do not float in if
|
| 696 | 697 | (a) any non-one-shot value lambdas
|
| ... | ... | @@ -1003,12 +1003,11 @@ Why? Because it's important /not/ to transform |
| 1003 | 1003 | let x = a /# 3
|
| 1004 | 1004 | to
|
| 1005 | 1005 | let x = case bx of I# a -> a /# 3
|
| 1006 | -because the let binding no
|
|
| 1007 | -longer obeys the let-can-float invariant. But (a /# 3) is ok-for-spec
|
|
| 1008 | -due to a special hack that says division operators can't fail
|
|
| 1009 | -when the denominator is definitely non-zero. And yet that
|
|
| 1010 | -same expression says False to exprIsCheap. Simplest way to
|
|
| 1011 | -guarantee the let-can-float invariant is to use the same function!
|
|
| 1006 | +because the let binding no longer obeys Note [Nested binding invariants].
|
|
| 1007 | +But (a /# 3) is ok-for-spec due to a special hack that says division operators
|
|
| 1008 | +can't fail when the denominator is definitely non-zero. And yet that same
|
|
| 1009 | +expression says False to exprIsCheap. Simplest way to guarantee
|
|
| 1010 | +Note [Nested binding invariants] is to use the same function!
|
|
| 1012 | 1011 | |
| 1013 | 1012 | If an expression is okay for speculation, we could also float it out
|
| 1014 | 1013 | *without* boxing and unboxing, since evaluating it early is okay.
|
| ... | ... | @@ -749,8 +749,8 @@ Examples |
| 749 | 749 | NonRec x# (y +# 3) FltOkSpec -- Unboxed, but ok-for-spec'n
|
| 750 | 750 | |
| 751 | 751 | NonRec x* (f y) FltCareful -- Strict binding; might fail or diverge
|
| 752 | - NonRec x# (a /# b) FltCareful -- Might fail; does not satisfy let-can-float invariant
|
|
| 753 | - NonRec x# (f y) FltCareful -- Might diverge; does not satisfy let-can-float invariant
|
|
| 752 | + NonRec x# (a /# b) FltCareful -- Might fail; does not satisfy Note [Nested binding invariants]
|
|
| 753 | + NonRec x# (f y) FltCareful -- Might diverge; does not satisfy Note [Nested binding invariants]
|
|
| 754 | 754 | -}
|
| 755 | 755 | |
| 756 | 756 | data LetFloats = LetFloats (OrdList OutBind) FloatFlag
|
| ... | ... | @@ -763,7 +763,7 @@ data FloatFlag |
| 763 | 763 | = FltLifted -- All bindings are lifted and lazy *or*
|
| 764 | 764 | -- consist of a single primitive string literal
|
| 765 | 765 | -- Hence ok to float to top level, or recursive
|
| 766 | - -- NB: consequence: all bindings satisfy let-can-float invariant
|
|
| 766 | + -- NB: consequence: all bindings satisfy Note [Nested binding invariants]
|
|
| 767 | 767 | |
| 768 | 768 | | FltOkSpec -- All bindings are FltLifted *or*
|
| 769 | 769 | -- strict (perhaps because unlifted,
|
| ... | ... | @@ -772,12 +772,12 @@ data FloatFlag |
| 772 | 772 | -- Hence ok to float out of the RHS
|
| 773 | 773 | -- of a lazy non-recursive let binding
|
| 774 | 774 | -- (but not to top level, or into a rec group)
|
| 775 | - -- NB: consequence: all bindings satisfy let-can-float invariant
|
|
| 775 | + -- NB: consequence: all bindings satisfy Note [Nested binding invariants]
|
|
| 776 | 776 | |
| 777 | 777 | | FltCareful -- At least one binding is strict (or unlifted)
|
| 778 | 778 | -- and not guaranteed cheap
|
| 779 | 779 | -- Do not float these bindings out of a lazy let!
|
| 780 | - -- NB: some bindings may not satisfy let-can-float
|
|
| 780 | + -- NB: some bindings may not satisfy Note [Nested binding invariants]
|
|
| 781 | 781 | |
| 782 | 782 | instance Outputable LetFloats where
|
| 783 | 783 | ppr (LetFloats binds ff) = ppr ff $$ ppr (fromOL binds)
|
| ... | ... | @@ -962,8 +962,8 @@ wrapFloats (SimplFloats { sfLetFloats = LetFloats bs flag |
| 962 | 962 | -- Note: Always safe to put the joins on the inside
|
| 963 | 963 | -- since the values can't refer to them
|
| 964 | 964 | where
|
| 965 | - mk_let | FltCareful <- flag = mkCoreLet -- need to enforce let-can-float-invariant
|
|
| 966 | - | otherwise = Let -- let-can-float invariant hold
|
|
| 965 | + mk_let | FltCareful <- flag = mkCoreLet -- Need to enforce Note [Nested binding invariants]
|
|
| 966 | + | otherwise = Let -- Note [Nested binding invariants] holds
|
|
| 967 | 967 | |
| 968 | 968 | wrapJoinFloatsX :: SimplFloats -> OutExpr -> (SimplFloats, OutExpr)
|
| 969 | 969 | -- Wrap the sfJoinFloats of the env around the expression,
|
| ... | ... | @@ -315,7 +315,7 @@ simplLazyBind :: TopLevelFlag -> RecFlag |
| 315 | 315 | -> (InExpr, SimplEnv) -- The RHS and its static environment
|
| 316 | 316 | -> SimplM (SimplFloats, SimplEnv)
|
| 317 | 317 | -- Precondition: Ids only, no TyVars; not a JoinId
|
| 318 | --- Precondition: rhs obeys the let-can-float invariant
|
|
| 318 | +-- Precondition: rhs obeys Note [Nested binding invariants]
|
|
| 319 | 319 | simplLazyBind top_lvl is_rec (bndr,unf_se) (bndr1,env) (rhs,rhs_se)
|
| 320 | 320 | = assert (isId bndr )
|
| 321 | 321 | assertPpr (not (isJoinId bndr)) (ppr bndr) $
|
| ... | ... | @@ -397,7 +397,7 @@ simplAuxBind :: String |
| 397 | 397 | -- The binder comes from a case expression (case binder or alternative)
|
| 398 | 398 | -- and so does not have rules, unfolding, inline pragmas etc.
|
| 399 | 399 | --
|
| 400 | --- Precondition: rhs satisfies the let-can-float invariant
|
|
| 400 | +-- Precondition: rhs satisfies Note [Nested binding invariants]
|
|
| 401 | 401 | |
| 402 | 402 | simplAuxBind _str env bndr new_rhs
|
| 403 | 403 | | assertPpr (isId bndr && not (isJoinId bndr)) (ppr bndr) $
|
| ... | ... | @@ -950,7 +950,7 @@ completeBind :: BindContext |
| 950 | 950 | -- * or by adding to the floats in the envt
|
| 951 | 951 | --
|
| 952 | 952 | -- Binder /can/ be a JoinId
|
| 953 | --- Precondition: rhs obeys the let-can-float invariant
|
|
| 953 | +-- Precondition: rhs obeys Note [Nested binding invariants]
|
|
| 954 | 954 | completeBind bind_cxt (old_bndr, unf_se) (new_bndr, new_rhs, env)
|
| 955 | 955 | | isCoVar old_bndr
|
| 956 | 956 | = case new_rhs of
|
| ... | ... | @@ -1290,7 +1290,7 @@ simplExprF1 env (Let (NonRec bndr rhs) body) cont |
| 1290 | 1290 | ; simplExprF (extendTvSubst env bndr ty') body cont }
|
| 1291 | 1291 | |
| 1292 | 1292 | | Just env' <- preInlineUnconditionally env NotTopLevel bndr rhs env
|
| 1293 | - -- Because of the let-can-float invariant, it's ok to
|
|
| 1293 | + -- Because of Note [Nested binding invariants], it's ok to
|
|
| 1294 | 1294 | -- inline freely, or to drop the binding if it is dead.
|
| 1295 | 1295 | = do { simplTrace "SimplBindr:inline-uncond2" (ppr bndr <+> ppr rhs) $
|
| 1296 | 1296 | tick (PreInlineUnconditionally bndr)
|
| ... | ... | @@ -1594,13 +1594,13 @@ rebuild_go env expr cont |
| 1594 | 1594 | completeBindX :: SimplEnv
|
| 1595 | 1595 | -> FromWhat
|
| 1596 | 1596 | -> InId -> OutExpr -- Non-recursively bind this Id to this (simplified) expression
|
| 1597 | - -- (the let-can-float invariant may not be satisfied)
|
|
| 1597 | + -- (Note [Nested binding invariants] may not be satisfied)
|
|
| 1598 | 1598 | -> InExpr -- In this body
|
| 1599 | 1599 | -> SimplCont -- Consumed by this continuation
|
| 1600 | 1600 | -> SimplM (SimplFloats, OutExpr)
|
| 1601 | 1601 | completeBindX env from_what bndr rhs body cont
|
| 1602 | 1602 | | FromBeta arg_levity <- from_what
|
| 1603 | - , needsCaseBindingL arg_levity rhs -- Enforcing the let-can-float-invariant
|
|
| 1603 | + , needsCaseBindingL arg_levity rhs -- Enforcing Note [Nested binding invariants]
|
|
| 1604 | 1604 | = do { (env1, bndr1) <- simplNonRecBndr env bndr -- Lambda binders don't have rules
|
| 1605 | 1605 | ; (floats, expr') <- simplNonRecBody env1 from_what body cont
|
| 1606 | 1606 | -- Do not float floats past the Case binder below
|
| ... | ... | @@ -1887,7 +1887,7 @@ simplNonRecE :: HasDebugCallStack |
| 1887 | 1887 | -- It deals with strict bindings, via the StrictBind continuation,
|
| 1888 | 1888 | -- which may abort the whole process.
|
| 1889 | 1889 | --
|
| 1890 | --- from_what=FromLet => the RHS satisfies the let-can-float invariant
|
|
| 1890 | +-- from_what=FromLet => the RHS satisfies Note [Nested binding invariants]
|
|
| 1891 | 1891 | -- Otherwise it may or may not satisfy it.
|
| 1892 | 1892 | |
| 1893 | 1893 | simplNonRecE env from_what bndr (rhs, rhs_se) body cont
|
| ... | ... | @@ -1910,7 +1910,7 @@ simplNonRecE env from_what bndr (rhs, rhs_se) body cont |
| 1910 | 1910 | is_strict_bind = case from_what of
|
| 1911 | 1911 | FromBeta Unlifted -> True
|
| 1912 | 1912 | -- If we are coming from a beta-reduction (FromBeta) we must
|
| 1913 | - -- establish the let-can-float invariant, so go via StrictBind
|
|
| 1913 | + -- establish Note [Nested binding invariants], so go via StrictBind
|
|
| 1914 | 1914 | -- If not, the invariant holds already, and it's optional.
|
| 1915 | 1915 | |
| 1916 | 1916 | -- (FromBeta Lifted) or FromLet: look at the demand info
|
| ... | ... | @@ -2857,7 +2857,7 @@ this transformation: |
| 2857 | 2857 | We treat the unlifted and lifted cases separately:
|
| 2858 | 2858 | |
| 2859 | 2859 | * Unlifted case: 'e' satisfies exprOkForSpeculation
|
| 2860 | - (ok-for-spec is needed to satisfy the let-can-float invariant).
|
|
| 2860 | + (ok-for-spec is needed to satisfy Note [Nested binding invariants].
|
|
| 2861 | 2861 | This turns case a +# b of r -> ...r...
|
| 2862 | 2862 | into let r = a +# b in ...r...
|
| 2863 | 2863 | and thence .....(a +# b)....
|
| ... | ... | @@ -3112,7 +3112,7 @@ rebuildCase env scrut case_bndr alts cont |
| 3112 | 3112 | assert (null bs) $
|
| 3113 | 3113 | do { (floats1, env') <- simplAuxBind "rebuildCase" env case_bndr case_bndr_rhs
|
| 3114 | 3114 | -- scrut is a constructor application,
|
| 3115 | - -- hence satisfies let-can-float invariant
|
|
| 3115 | + -- hence satisfies Note [Nested binding invariants]
|
|
| 3116 | 3116 | ; (floats2, expr') <- simplExprF env' rhs cont
|
| 3117 | 3117 | ; case wfloats of
|
| 3118 | 3118 | [] -> return (floats1 `addFloats` floats2, expr')
|
| ... | ... | @@ -3624,11 +3624,11 @@ We pin on a (OtherCon []) unfolding to the case-binder of a Case, |
| 3624 | 3624 | even though it'll be over-ridden in every case alternative with a more
|
| 3625 | 3625 | informative unfolding. Why? Because suppose a later, less clever, pass
|
| 3626 | 3626 | simply replaces all occurrences of the case binder with the binder itself;
|
| 3627 | -then Lint may complain about the let-can-float invariant. Example
|
|
| 3627 | +then Lint may complain about failing Note [Nested binding invariants]. Example
|
|
| 3628 | 3628 | case e of b { DEFAULT -> let v = reallyUnsafePtrEquality# b y in ....
|
| 3629 | 3629 | ; K -> blah }
|
| 3630 | 3630 | |
| 3631 | -The let-can-float invariant requires that y is evaluated in the call to
|
|
| 3631 | +Note [Nested binding invariants] requires that y is evaluated in the call to
|
|
| 3632 | 3632 | reallyUnsafePtrEquality#, which it is. But we still want that to be true if we
|
| 3633 | 3633 | propagate binders to occurrences.
|
| 3634 | 3634 | |
| ... | ... | @@ -3732,7 +3732,8 @@ knownCon env scrut dc_floats dc dc_ty_args dc_args bndr bs rhs cont |
| 3732 | 3732 | -- occur in the RHS; and simplAuxBind may therefore discard it.
|
| 3733 | 3733 | -- Nevertheless we must keep it if the case-binder is alive,
|
| 3734 | 3734 | -- because it may be used in the con_app. See Note [knownCon occ info]
|
| 3735 | - ; (floats1, env2) <- simplAuxBind "knownCon" env' b' arg -- arg satisfies let-can-float invariant
|
|
| 3735 | + -- NB: arg satisfies Note [Nested binding invariants]
|
|
| 3736 | + ; (floats1, env2) <- simplAuxBind "knownCon" env' b' arg
|
|
| 3736 | 3737 | ; (floats2, env3) <- bind_args env2 bs' args
|
| 3737 | 3738 | ; return (floats1 `addFloats` floats2, env3) }
|
| 3738 | 3739 |
| ... | ... | @@ -1491,8 +1491,8 @@ preInlineUnconditionally |
| 1491 | 1491 | :: SimplEnv -> TopLevelFlag -> InId
|
| 1492 | 1492 | -> InExpr -> StaticEnv -- These two go together
|
| 1493 | 1493 | -> Maybe SimplEnv -- Returned env has extended substitution
|
| 1494 | --- Precondition: rhs satisfies the let-can-float invariant
|
|
| 1495 | --- See Note [Core let-can-float invariant] in GHC.Core
|
|
| 1494 | +-- Precondition: rhs satisfies Note [Nested binding invariants]
|
|
| 1495 | +-- See Note [Nested binding invariants] in GHC.Core
|
|
| 1496 | 1496 | -- Reason: we don't want to inline single uses, or discard dead bindings,
|
| 1497 | 1497 | -- for unlifted, side-effect-ful bindings
|
| 1498 | 1498 | preInlineUnconditionally env top_lvl bndr rhs rhs_env
|
| ... | ... | @@ -1638,8 +1638,7 @@ postInlineUnconditionally |
| 1638 | 1638 | -> InId -> OutId -- The binder (*not* a CoVar), including its unfolding
|
| 1639 | 1639 | -> OutExpr
|
| 1640 | 1640 | -> Bool
|
| 1641 | --- Precondition: rhs satisfies the let-can-float invariant
|
|
| 1642 | --- See Note [Core let-can-float invariant] in GHC.Core
|
|
| 1641 | +-- Precondition: rhs satisfies Note [Nested binding invariants] in GHC.Core
|
|
| 1643 | 1642 | -- Reason: we don't want to inline single uses, or discard dead bindings,
|
| 1644 | 1643 | -- for unlifted, side-effect-ful bindings
|
| 1645 | 1644 | postInlineUnconditionally env bind_cxt old_bndr bndr rhs
|
| ... | ... | @@ -1944,7 +1944,7 @@ case) do not float the binding itself unless it satisfies exprIsTopLevelBindable |
| 1944 | 1944 | This is conservative: maybe the RHS of `x` has a free var that would stop it
|
| 1945 | 1945 | floating to top level anyway; but that is hard to spot (since we don't know what
|
| 1946 | 1946 | the non-top-level in-scope binders are) and rare (since the binding must satisfy
|
| 1947 | -Note [Core let-can-float invariant] in GHC.Core).
|
|
| 1947 | +Note [Nested binding invariants] in GHC.Core).
|
|
| 1948 | 1948 | |
| 1949 | 1949 | |
| 1950 | 1950 | Note [Specialising Calls]
|
| ... | ... | @@ -381,7 +381,7 @@ simple_app env e0@(Lam {}) as0@(_:_) |
| 381 | 381 | -- See Note [Dark corner with representation polymorphism]
|
| 382 | 382 | needsCaseBinding (idType b') (snd a)
|
| 383 | 383 | -- This arg must not be inlined (side-effects) and cannot be let-bound,
|
| 384 | - -- due to the let-can-float invariant. So simply case-bind it here.
|
|
| 384 | + -- due to Note [Nested binding invariants]. So simply case-bind it here.
|
|
| 385 | 385 | , let a' = simple_opt_clo (soeInScope env) a
|
| 386 | 386 | = mkDefaultCase a' b' $ do_beta env' body as
|
| 387 | 387 |
| ... | ... | @@ -350,7 +350,8 @@ deepTcvFolder = TyCoFolder { tcf_view = noView -- See Note [Free vars and synon |
| 350 | 350 | where
|
| 351 | 351 | do_tcv is v = EndoOS do_it
|
| 352 | 352 | where
|
| 353 | - do_it acc | not (isLocalVar v) = acc
|
|
| 353 | + do_it acc | not (isLocalVar v) = acc -- A CoVar can be a GlobalId
|
|
| 354 | + -- See Note [Coercion bindings] in GHC.Core
|
|
| 354 | 355 | | v `elemVarSet` is = acc
|
| 355 | 356 | | v `elemVarSet` acc = acc
|
| 356 | 357 | | otherwise = appEndoOS (deep_ty (varType v)) $
|
| ... | ... | @@ -1040,7 +1040,7 @@ substTyCoBndr subst (Named (Bndr tv vis)) = (subst', Named (Bndr tv' vis)) |
| 1040 | 1040 | {- Note [Keeping the substitution empty]
|
| 1041 | 1041 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 1042 | 1042 | A very common situation is where we run over a term doing no cloning,
|
| 1043 | -no substitution, nothing. In that case the TCvSubst till be empty, and
|
|
| 1043 | +no substitution, nothing. In that case the TCvSubst will be empty, and
|
|
| 1044 | 1044 | it is /very/ valuable to /keep/ it empty:
|
| 1045 | 1045 | |
| 1046 | 1046 | * It's wasted effort to build up an identity substitution mapping
|
| ... | ... | @@ -1813,13 +1813,11 @@ exprIsUnaryClassFun _ = False |
| 1813 | 1813 | -- See also Note [Classifying primop effects] in "GHC.Builtin.PrimOps"
|
| 1814 | 1814 | -- and Note [Transformations affected by primop effects].
|
| 1815 | 1815 | --
|
| 1816 | --- 'exprOkForSpeculation' is used to define Core's let-can-float
|
|
| 1817 | --- invariant. (See Note [Core let-can-float invariant] in
|
|
| 1818 | --- "GHC.Core".) It is therefore frequently called on arguments of
|
|
| 1819 | --- unlifted type, especially via 'needsCaseBinding'. But it is
|
|
| 1820 | --- sometimes called on expressions of lifted type as well. For
|
|
| 1821 | --- example, see Note [Speculative evaluation] in "GHC.CoreToStg.Prep".
|
|
| 1822 | - |
|
| 1816 | +-- 'exprOkForSpeculation' is used in the definition of Note [Nested binding
|
|
| 1817 | +-- invariants]in GHC.Core. It is therefore frequently called on arguments of
|
|
| 1818 | +-- unlifted type, especially via 'needsCaseBinding'. But it is sometimes
|
|
| 1819 | +-- called on expressions of lifted type as well. For example, see
|
|
| 1820 | +-- Note [Speculative evaluation] in "GHC.CoreToStg.Prep".
|
|
| 1823 | 1821 | |
| 1824 | 1822 | exprOkForSpeculation, exprOkToDiscard :: CoreExpr -> Bool
|
| 1825 | 1823 | exprOkForSpeculation = expr_ok fun_always_ok primOpOkForSpeculation
|
| ... | ... | @@ -2044,12 +2042,14 @@ But we restrict it sharply: |
| 2044 | 2042 | ; False -> e2 }
|
| 2045 | 2043 | in ...) ...
|
| 2046 | 2044 | |
| 2047 | - Does the RHS of v satisfy the let-can-float invariant? Previously we said
|
|
| 2048 | - yes, on the grounds that y is evaluated. But the binder-swap done
|
|
| 2049 | - by GHC.Core.Opt.SetLevels would transform the inner alternative to
|
|
| 2045 | + Does the RHS of v satisfy Note [Nested binding invariants]?
|
|
| 2046 | + Previously we said yes, on the grounds that y is evaluated. But the
|
|
| 2047 | + binder-swap done by GHC.Core.Opt.SetLevels would transform the inner
|
|
| 2048 | + alternative to
|
|
| 2049 | + |
|
| 2050 | 2050 | DEFAULT -> ... (let v::Int# = case x of { ... }
|
| 2051 | 2051 | in ...) ....
|
| 2052 | - which does /not/ satisfy the let-can-float invariant, because x is
|
|
| 2052 | + which does /not/ satisfy Note [Nested bindings invariants], because x is
|
|
| 2053 | 2053 | not evaluated. See Note [Binder-swap during float-out]
|
| 2054 | 2054 | in GHC.Core.Opt.SetLevels. To avoid this awkwardness it seems simpler
|
| 2055 | 2055 | to stick to unlifted scrutinees where the issue does not
|
| ... | ... | @@ -2134,7 +2134,7 @@ extremely useful for float-out, changes these expressions to |
| 2134 | 2134 | |
| 2135 | 2135 | And now the expression does not obey the let-can-float invariant! Yikes!
|
| 2136 | 2136 | Moreover we really might float (dataToTagLarge# x) outside the case,
|
| 2137 | -and then it really, really doesn't obey the let-can-float invariant.
|
|
| 2137 | +and then it really, really doesn't obey Note [Nested binding invariants].
|
|
| 2138 | 2138 | |
| 2139 | 2139 | The solution is simple: exprOkForSpeculation does not try to take
|
| 2140 | 2140 | advantage of the evaluated-ness of (lifted) variables. And it returns
|
| ... | ... | @@ -2144,7 +2144,8 @@ by marking the relevant primops as "ThrowsException" or |
| 2144 | 2144 | GHC.Builtin.PrimOps.
|
| 2145 | 2145 | |
| 2146 | 2146 | Note that exprIsHNF /can/ and does take advantage of evaluated-ness;
|
| 2147 | -it doesn't have the trickiness of the let-can-float invariant to worry about.
|
|
| 2147 | +it doesn't have the trickiness of Note [Nested binding invariants]
|
|
| 2148 | +to worry about.
|
|
| 2148 | 2149 | |
| 2149 | 2150 | ************************************************************************
|
| 2150 | 2151 | * *
|
| ... | ... | @@ -5,9 +5,8 @@ A lint pass to check basic STG invariants: |
| 5 | 5 | |
| 6 | 6 | - Variables should be defined before used.
|
| 7 | 7 | |
| 8 | -- Let bindings should not have unboxed types (unboxed bindings should only
|
|
| 9 | - appear in case), except when they're join points (see Note [Core let-can-float
|
|
| 10 | - invariant] and #14117).
|
|
| 8 | +- Let bindings: see Note [Core binding invariants] in GHC.Core.
|
|
| 9 | + (See #14117).
|
|
| 11 | 10 | |
| 12 | 11 | - If linting after unarisation, invariants listed in Note [Post-unarisation
|
| 13 | 12 | invariants].
|