sheaf pushed to branch wip/T26878 at Glasgow Haskell Compiler / GHC
Commits:
-
7a5b42ad
by sheaf at 2026-03-16T16:38:57+01:00
5 changed files:
- compiler/GHC/Core/Utils.hs
- compiler/GHC/Types/Tickish.hs
- + testsuite/tests/simplCore/should_compile/T26941.hs
- + testsuite/tests/simplCore/should_compile/T26941_aux.hs
- testsuite/tests/simplCore/should_compile/all.T
Changes:
| ... | ... | @@ -303,101 +303,194 @@ mkCast expr co |
| 303 | 303 | * *
|
| 304 | 304 | ********************************************************************* -}
|
| 305 | 305 | |
| 306 | --- | Wraps the given expression in the source annotation, dropping the
|
|
| 307 | --- annotation if possible.
|
|
| 306 | +-- | Wraps the given expression in a Tick, floating the tick as far into
|
|
| 307 | +-- the AST as possible in order to try to satisfy the tick's desired placement
|
|
| 308 | +-- properties (as per Note [Tickish placement] in GHC.Types.Tickish).
|
|
| 309 | +--
|
|
| 310 | +-- Prefer using 'mkTick' over explicit use of the 'Tick' constructor.
|
|
| 311 | +--
|
|
| 312 | +-- Also performs small on-the-fly optimisations:
|
|
| 313 | +--
|
|
| 314 | +-- * Eliminate unnecessary ticks by either absorbing them into existing ones
|
|
| 315 | +-- or dropping them if that is valid (e.g. dropping profiling ticks around
|
|
| 316 | +-- types, coercions and literals).
|
|
| 317 | +-- * Split profiling ticks into counting/scoping parts so that the two parts
|
|
| 318 | +-- can be placed independently into the AST.
|
|
| 308 | 319 | mkTick :: CoreTickish -> CoreExpr -> CoreExpr
|
| 309 | -mkTick t orig_expr = mkTick' id orig_expr
|
|
| 320 | +mkTick t orig_expr = mkTick' orig_expr
|
|
| 310 | 321 | where
|
| 311 | 322 | -- Some ticks (cost-centres) can be split in two, with the
|
| 312 | 323 | -- non-counting part having laxer placement properties.
|
| 313 | - canSplit = tickishCanSplit t && tickishPlace (mkNoCount t) /= tickishPlace t
|
|
| 324 | + -- See Note [Scoping ticks and counting ticks] in GHC.Types.Tickish.
|
|
| 325 | + can_split = tickishCanSplit t
|
|
| 314 | 326 | |
| 315 | - -- mkTick' handles floating of ticks *into* the expression.
|
|
| 316 | - mkTick' :: (CoreExpr -> CoreExpr) -- Apply before adding tick (float with)
|
|
| 317 | - -- Always a composition of (Tick t) wrappers
|
|
| 318 | - -> CoreExpr -- Current expression
|
|
| 319 | - -> CoreExpr
|
|
| 320 | - -- So in the call (mkTick' rest e), the expression
|
|
| 321 | - -- (rest e)
|
|
| 322 | - -- has the same type as e
|
|
| 323 | - -- Returns an expression equivalent to (Tick t (rest e))
|
|
| 324 | - mkTick' rest expr = case expr of
|
|
| 325 | - -- Float ticks into unsafe coerce the same way we would do with a cast.
|
|
| 326 | - Case scrut bndr ty alts@[Alt ac abs _rhs]
|
|
| 327 | - | Just rhs <- isUnsafeEqualityCase scrut bndr alts
|
|
| 328 | - -> Case scrut bndr ty [Alt ac abs (mkTick' rest rhs)]
|
|
| 327 | + stop_here e = Tick t e -- Just wrap `t` around the current expression
|
|
| 328 | + -- That's the default option!
|
|
| 329 | 329 | |
| 330 | - -- Cost centre ticks should never be reordered relative to each
|
|
| 331 | - -- other. Therefore we can stop whenever two collide.
|
|
| 330 | + -- mkTick' handles floating of tick `t` *into* the expression.
|
|
| 331 | + mkTick' :: CoreExpr -> CoreExpr
|
|
| 332 | + mkTick' expr = case expr of
|
|
| 332 | 333 | Tick t2 e
|
| 333 | - | ProfNote{} <- t2, ProfNote{} <- t -> Tick t $ rest expr
|
|
| 334 | 334 | |
| 335 | - -- Otherwise we assume that ticks of different placements float
|
|
| 336 | - -- through each other.
|
|
| 337 | - | tickishPlace t2 /= tickishPlace t -> Tick t2 $ mkTick' rest e
|
|
| 335 | + -- Common up ticks when possible, including profiling ticks that
|
|
| 336 | + -- share a cost centre and source notes that subsume one another.
|
|
| 337 | + | Just t' <- combineTickish_maybe t t2
|
|
| 338 | + -> mkTick t' e
|
|
| 338 | 339 | |
| 339 | - -- For annotations this is where we make sure to not introduce
|
|
| 340 | - -- redundant ticks.
|
|
| 341 | - | tickishContains t t2 -> mkTick' rest e -- Drop t2
|
|
| 342 | - | tickishContains t2 t -> rest e -- Drop t
|
|
| 343 | - | otherwise -> mkTick' (rest . Tick t2) e
|
|
| 340 | + -- Profiling ticks for different cost centres should never be reordered
|
|
| 341 | + -- relative to each other. Therefore, we stop whenever two collide.
|
|
| 342 | + | ProfNote {} <- t
|
|
| 343 | + , ProfNote {} <- t2
|
|
| 344 | + -> stop_here expr
|
|
| 344 | 345 | |
| 345 | - -- Ticks don't care about types, so we just float all ticks
|
|
| 346 | - -- through them. Note that it's not enough to check for these
|
|
| 347 | - -- cases top-level. While mkTick will never produce Core with type
|
|
| 348 | - -- expressions below ticks, such constructs can be the result of
|
|
| 349 | - -- unfoldings. We therefore make an effort to put everything into
|
|
| 350 | - -- the right place no matter what we start with.
|
|
| 351 | - Cast e co -> mkCast (mkTick' rest e) co
|
|
| 352 | - Coercion co -> Tick t $ rest (Coercion co)
|
|
| 346 | + -- Ticks of different placements float through each other, so that each
|
|
| 347 | + -- tick can be floated into its expected position in the AST.
|
|
| 348 | + -- See Note [Tickish placement] in GHC.Types.Tickish.
|
|
| 349 | + | tickishPlace t2 /= tickishPlace t
|
|
| 350 | + -> Tick t2 $ mkTick' e
|
|
| 351 | + |
|
| 352 | + | otherwise
|
|
| 353 | + -> stop_here expr -- Always safe
|
|
| 353 | 354 | |
| 354 | 355 | Lam x e
|
| 355 | 356 | -- Always float through type lambdas. Even for non-type lambdas,
|
| 356 | 357 | -- floating is allowed for all but the most strict placement rule.
|
| 357 | 358 | | not (isRuntimeVar x) || tickishPlace t /= PlaceRuntime
|
| 358 | - -> Lam x $ mkTick' rest e
|
|
| 359 | + -> Lam x $ mkTick' e
|
|
| 359 | 360 | |
| 360 | - -- If it is both counting and scoped, we split the tick into its
|
|
| 361 | - -- two components, often allowing us to keep the counting tick on
|
|
| 362 | - -- the outside of the lambda and push the scoped tick inside.
|
|
| 363 | - -- The point of this is that the counting tick can probably be
|
|
| 364 | - -- floated, and the lambda may then be in a position to be
|
|
| 365 | - -- beta-reduced.
|
|
| 366 | - | canSplit
|
|
| 367 | - -> Tick (mkNoScope t) $ rest $ Lam x $ mkTick (mkNoCount t) e
|
|
| 361 | + -- Push SCCs into lambdas.
|
|
| 362 | + -- See PSCC2 in Note [Pushing SCCs inwards].
|
|
| 363 | + | can_split
|
|
| 364 | + -> Tick (mkNoScope t) $ Lam x $ mkTick (mkNoCount t) e
|
|
| 368 | 365 | |
| 369 | 366 | App f arg
|
| 370 | - -- Always float through type applications.
|
|
| 367 | + -- All ticks float inwards through non-runtime arguments, as per
|
|
| 368 | + -- Note [Tickish placement] in GHC.Types.Tickish.
|
|
| 371 | 369 | | not (isRuntimeArg arg)
|
| 372 | - -> App (mkTick' rest f) arg
|
|
| 370 | + -> App (mkTick' f) arg
|
|
| 373 | 371 | |
| 374 | - -- We can also float through constructor applications, placement
|
|
| 375 | - -- permitting. Again we can split.
|
|
| 376 | - | isSaturatedConApp expr && (tickishPlace t==PlaceCostCentre || canSplit)
|
|
| 372 | + -- Push SCCs into saturated constructor applications.
|
|
| 373 | + -- See PSCC3 in Note [Pushing SCCs inwards].
|
|
| 374 | + | isSaturatedConApp expr
|
|
| 375 | + , tickishPlace t == PlaceCostCentre || can_split
|
|
| 377 | 376 | -> if tickishPlace t == PlaceCostCentre
|
| 378 | - then rest $ tickHNFArgs t expr
|
|
| 379 | - else Tick (mkNoScope t) $ rest $ tickHNFArgs (mkNoCount t) expr
|
|
| 377 | + then tickHNFArgs t expr
|
|
| 378 | + else Tick (mkNoScope t) $ tickHNFArgs (mkNoCount t) expr
|
|
| 379 | + |
|
| 380 | + -- Ticks don't care about types, so we just float all ticks
|
|
| 381 | + -- through them. Note that it's not enough to check for these
|
|
| 382 | + -- cases at the top-level. While mkTick will never produce Core with type
|
|
| 383 | + -- expressions below ticks, such constructs can be the result of
|
|
| 384 | + -- unfoldings. We therefore make an effort to put everything into
|
|
| 385 | + -- the right place no matter what we start with.
|
|
| 386 | + Cast e co -> mkCast (mkTick' e) co
|
|
| 387 | + |
|
| 388 | + -- Float ticks into 'unsafeCoerce' the same way we would do with a cast.
|
|
| 389 | + Case scrut bndr ty alts@[Alt ac abs _rhs]
|
|
| 390 | + | Just rhs <- isUnsafeEqualityCase scrut bndr alts
|
|
| 391 | + -> Case scrut bndr ty [Alt ac abs (mkTick' rhs)]
|
|
| 380 | 392 | |
| 381 | 393 | Var x
|
| 382 | - | notFunction && tickishPlace t == PlaceCostCentre
|
|
| 383 | - -> rest expr -- Drop t
|
|
| 384 | - | notFunction && canSplit
|
|
| 385 | - -> Tick (mkNoScope t) $ rest expr
|
|
| 394 | + -- Drop SCCs around non-function variables.
|
|
| 395 | + -- See PSCC1 in Note [Pushing SCCs inwards].
|
|
| 396 | + | notFunction
|
|
| 397 | + -- Does the tick `t` contain an SCC we can drop?
|
|
| 398 | + , tickishPlace t == PlaceCostCentre || can_split
|
|
| 399 | + -> if tickishPlace t == PlaceCostCentre
|
|
| 400 | + then expr -- Drop pure SCC ticks: scc<foo> (x :: Int) ==> x
|
|
| 401 | + else
|
|
| 402 | + -- Drop the scoping part of the tick, but keep the counting part.
|
|
| 403 | + Tick (mkNoScope t) expr
|
|
| 386 | 404 | where
|
| 387 | - -- SCCs can be eliminated on variables provided the variable
|
|
| 388 | - -- is not a function. In these cases the SCC makes no difference:
|
|
| 389 | - -- the cost of evaluating the variable will be attributed to its
|
|
| 390 | - -- definition site. When the variable refers to a function, however,
|
|
| 391 | - -- an SCC annotation on the variable affects the cost-centre stack
|
|
| 392 | - -- when the function is called, so we must retain those.
|
|
| 393 | 405 | notFunction = not (isFunTy (idType x))
|
| 394 | 406 | |
| 395 | - Lit{}
|
|
| 396 | - | tickishPlace t == PlaceCostCentre
|
|
| 397 | - -> rest expr -- Drop t
|
|
| 407 | + -- It doesn't make sense to wrap static data (such as coercions, types and literals)
|
|
| 408 | + -- in a tick which compiles to code, as the code will never be run.
|
|
| 409 | + --
|
|
| 410 | + -- It is in fact actively harmful, because Core Lint will fail on a
|
|
| 411 | + -- coercion binding such as let co = <scc> (...), see #26941.
|
|
| 412 | + -- It makes more sense to discard the cost centre tick rather than weakening
|
|
| 413 | + -- Core Lint.
|
|
| 414 | + e@(Coercion {}) | tickishIsCode t -> e
|
|
| 415 | + e@(Type {}) | tickishIsCode t -> e
|
|
| 416 | + e@(Lit {}) | tickishIsCode t -> e
|
|
| 417 | + |
|
| 418 | + -- Catch-all: annotate where we stand.
|
|
| 419 | + -- In particular (but not only): Let, most Cases.
|
|
| 420 | + _any -> Tick t expr
|
|
| 421 | + |
|
| 422 | +{- Note [Pushing SCCs inwards]
|
|
| 423 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 424 | +Amongst all ticks, SCCs have the laxest placement properties (PlaceCostCentre,
|
|
| 425 | +as described in Note [Tickish placement] GHC.Types.Tickish):
|
|
| 426 | + |
|
| 427 | + PSCC1: SCCs around non-function variables can be eliminated.
|
|
| 428 | + The cost of evaluating the variable will be attributed to its definition
|
|
| 429 | + site, so the SCC makes no difference. Example:
|
|
| 430 | + |
|
| 431 | + scc<foo> (x :: Int) ==> x
|
|
| 398 | 432 | |
| 399 | - -- Catch-all: Annotate where we stand
|
|
| 400 | - _any -> Tick t $ rest expr
|
|
| 433 | + NB: this is only valid when the variable is not a function. For example, in:
|
|
| 434 | + |
|
| 435 | + scc<foo> (f :: Int -> Int)
|
|
| 436 | + |
|
| 437 | + we must retain the cost centre annotation, as it affects the cost-centre
|
|
| 438 | + pointer when the function is called. Discarding the SCC in this case would
|
|
| 439 | + defeat the profiling mechanism entirely!
|
|
| 440 | + |
|
| 441 | + PSCC2: SCCs can be pushed into lambdas.
|
|
| 442 | + |
|
| 443 | + scc<foo> (\x -> e) ==> \x -> scc<foo> e
|
|
| 444 | + |
|
| 445 | + PSCC3: We can push SCCs into (saturated) constructor applications.
|
|
| 446 | + For example, for an arity 2 data constructor 'D':
|
|
| 447 | + |
|
| 448 | + scc<foo> (D e1 e2) ==> D (scc<foo> e1) (scc<foo> e2)
|
|
| 449 | + |
|
| 450 | +Now, two kinds of ticks contain SCCs:
|
|
| 451 | + |
|
| 452 | + - bare SCCs (i.e. ProfNote with profNoteCounts = False, profNoteScopes = True)
|
|
| 453 | + - profiling ticks that both count and scope
|
|
| 454 | + |
|
| 455 | +The above explanation deals with bare SCCs. When handling profiling ticks that
|
|
| 456 | +both count and scope, we can split tick into two, so that the scoping part can
|
|
| 457 | +be pushed inwards (or even discarded). Specifically, we perform the following
|
|
| 458 | +transformations:
|
|
| 459 | + |
|
| 460 | + PSCC1: Drop the SCC around non-function variables, keeping only the counting
|
|
| 461 | + part:
|
|
| 462 | + |
|
| 463 | + scctick<foo> (x :: Int) ==> tick<foo> x
|
|
| 464 | + |
|
| 465 | + PSCC2: Push the SCC inside lambdas:
|
|
| 466 | + |
|
| 467 | + scctick<foo> (\x. e) ==> tick<foo> (\x. scc<foo> e)
|
|
| 468 | + |
|
| 469 | + NB: we must keep the counting part outside the lambda, in order to preserve
|
|
| 470 | + tick counter tallies – it would not be sound to push the counting part inside.
|
|
| 471 | + |
|
| 472 | + PSCC3: Push the SCC inside saturated contructor applications.
|
|
| 473 | + |
|
| 474 | + scctick<foo> (D e1 e2) ==> tick<foo> (D (scc<foo> e1) (scc<foo> e2))
|
|
| 475 | + |
|
| 476 | +The benefit of these transformation is that the counting part, tick<foo>, can
|
|
| 477 | +likely be floated out of the way, which may expose additional optimisation
|
|
| 478 | +opportunities. For example:
|
|
| 479 | + |
|
| 480 | + (scctick<foo> (\x. e)) arg
|
|
| 481 | + |
|
| 482 | + ==>{PSCC2}
|
|
| 483 | + |
|
| 484 | + (tick<foo> (\x. scc<foo> e)) arg
|
|
| 485 | + |
|
| 486 | + ==>{GHC.Core.Opt.FloatOut.floatExpr, because 'tick<foo>' has no scope}
|
|
| 487 | + |
|
| 488 | + tick<foo> ((\x. scc<foo> e) arg)
|
|
| 489 | + |
|
| 490 | + ==>{beta reduction}
|
|
| 491 | + |
|
| 492 | + tick<foo> (let x = arg in scc<foo> e)
|
|
| 493 | +-}
|
|
| 401 | 494 | |
| 402 | 495 | mkTicks :: [CoreTickish] -> CoreExpr -> CoreExpr
|
| 403 | 496 | mkTicks ticks expr = foldr mkTick expr ticks
|
| ... | ... | @@ -17,6 +17,7 @@ module GHC.Types.Tickish ( |
| 17 | 17 | TickishPlacement(..),
|
| 18 | 18 | tickishPlace,
|
| 19 | 19 | tickishContains,
|
| 20 | + combineTickish_maybe,
|
|
| 20 | 21 | |
| 21 | 22 | -- * Breakpoint tick identifiers
|
| 22 | 23 | BreakpointId(..), BreakTickIndex
|
| ... | ... | @@ -261,8 +262,12 @@ Ticks have two independent attributes: |
| 261 | 262 | |
| 262 | 263 | See Note [Scoped ticks]
|
| 263 | 264 | |
| 265 | +Note that profiling notes which both count and scope can be split into two
|
|
| 266 | +separate ticks, one that counts and doesn't scope and one that scopes and doesn't
|
|
| 267 | +count; see 'tickishCanSplit', 'mkNoCount' and 'mkNoScope'.
|
|
| 268 | + |
|
| 264 | 269 | Note [Counting ticks]
|
| 265 | -~~~~~~~~~~~~~~~~~~~~
|
|
| 270 | +~~~~~~~~~~~~~~~~~~~~~
|
|
| 266 | 271 | The following ticks count:
|
| 267 | 272 | - ProfNote ticks with profNoteCounts = True
|
| 268 | 273 | - HPC ticks
|
| ... | ... | @@ -290,7 +295,7 @@ sharing, so in practice the actual number of ticks may vary, except |
| 290 | 295 | that we never change the value from zero to non-zero or vice-versa.
|
| 291 | 296 | |
| 292 | 297 | Note [Scoped ticks]
|
| 293 | -~~~~~~~~~~~~~~~~~~~~
|
|
| 298 | +~~~~~~~~~~~~~~~~~~~
|
|
| 294 | 299 | The following ticks are scoped:
|
| 295 | 300 | - ProfNote ticks with profNoteScope = True
|
| 296 | 301 | - Breakpoints
|
| ... | ... | @@ -375,6 +380,44 @@ Whether we are allowed to float in additional cost depends on the tick: |
| 375 | 380 | |
| 376 | 381 | While these transformations are legal, we want to make a best effort to
|
| 377 | 382 | only make use of them where it exposes transformation opportunities.
|
| 383 | + |
|
| 384 | +Note [Tickish placement]
|
|
| 385 | +~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 386 | +The placement behaviour of ticks (i.e. which terms we want the tick to be placed
|
|
| 387 | +around in the AST) is governed by 'TickishPlacement'. We generally try to push
|
|
| 388 | +ticks inwards until they end up placed around the kind of term expected by their
|
|
| 389 | +placement rules.
|
|
| 390 | + |
|
| 391 | +From most restrictive to least restrictive placement rules:
|
|
| 392 | + |
|
| 393 | + - PlaceRuntime: counting ticks.
|
|
| 394 | + |
|
| 395 | + Ticks with 'PlaceRuntime' placement want to be placed on run-time expressions.
|
|
| 396 | + They can be moved through pure compile-time constructs such as other ticks,
|
|
| 397 | + casts or type lambdas.
|
|
| 398 | + |
|
| 399 | + This is the most restrictive placement rule for ticks, as all tickishs have
|
|
| 400 | + in common that they want to track runtime processes.
|
|
| 401 | + |
|
| 402 | + Any tick that counts (see Note [Counting ticks]) has 'PlaceRuntime' placement.
|
|
| 403 | + |
|
| 404 | + - PlaceNonLam: source notes.
|
|
| 405 | + |
|
| 406 | + Like PlaceRuntime, but we can also float the tick through value lambdas.
|
|
| 407 | + This makes sense where there is little difference between annotating the
|
|
| 408 | + lambda and annotating the lambda's code.
|
|
| 409 | + |
|
| 410 | + - PlaceCostCentre: non-counting profiling ticks.
|
|
| 411 | + |
|
| 412 | + In addition to floating through lambdas, cost-centre style tickishs can also
|
|
| 413 | + be moved from constructors and non-function variables. For example:
|
|
| 414 | + |
|
| 415 | + let x = scc<...> C (scc<...> y) (scc<...> 3) in ...
|
|
| 416 | + |
|
| 417 | + Neither the constructor application, the variable or the literal are likely
|
|
| 418 | + to have any cost worth mentioning. And even if 'y' names a thunk, the call
|
|
| 419 | + would not care about the evaluation context. Therefore, removing all
|
|
| 420 | + annotations in the above example is safe.
|
|
| 378 | 421 | -}
|
| 379 | 422 | |
| 380 | 423 | -- | Returns @True@ for ticks that can be floated upwards easily even
|
| ... | ... | @@ -441,35 +484,19 @@ isProfTick _ = False |
| 441 | 484 | -- annotating for example using @mkTick@. If we find that we want to
|
| 442 | 485 | -- put a tickish on an expression ruled out here, we try to float it
|
| 443 | 486 | -- inwards until we find a suitable expression.
|
| 487 | +--
|
|
| 488 | +-- See Note [Tickish placement].
|
|
| 444 | 489 | data TickishPlacement =
|
| 445 | 490 | |
| 446 | - -- | Place ticks exactly on run-time expressions. We can still
|
|
| 447 | - -- move the tick through pure compile-time constructs such as
|
|
| 448 | - -- other ticks, casts or type lambdas. This is the most
|
|
| 449 | - -- restrictive placement rule for ticks, as all tickishs have in
|
|
| 450 | - -- common that they want to track runtime processes. The only
|
|
| 451 | - -- legal placement rule for counting ticks.
|
|
| 452 | - -- NB: We generally try to move these as close to the relevant
|
|
| 453 | - -- runtime expression as possible. This means they get pushed through
|
|
| 454 | - -- tyoe arguments. E.g. we create `(tick f) @Bool` instead of `tick (f @Bool)`.
|
|
| 491 | + -- | Place ticks exactly on run-time expressions, moving them through pure
|
|
| 492 | + -- compile-time constructs such as other ticks, casts or type lambdas.
|
|
| 455 | 493 | PlaceRuntime
|
| 456 | 494 | |
| 457 | - -- | As @PlaceRuntime@, but we float the tick through all
|
|
| 458 | - -- lambdas. This makes sense where there is little difference
|
|
| 459 | - -- between annotating the lambda and annotating the lambda's code.
|
|
| 495 | + -- | As @PlaceRuntime@, but also allow to float the tick through all lambdas.
|
|
| 460 | 496 | | PlaceNonLam
|
| 461 | 497 | |
| 462 | - -- | In addition to floating through lambdas, cost-centre style
|
|
| 463 | - -- tickishs can also be moved from constructors, non-function
|
|
| 464 | - -- variables and literals. For example:
|
|
| 465 | - --
|
|
| 466 | - -- let x = scc<...> C (scc<...> y) (scc<...> 3) in ...
|
|
| 467 | - --
|
|
| 468 | - -- Neither the constructor application, the variable or the
|
|
| 469 | - -- literal are likely to have any cost worth mentioning. And even
|
|
| 470 | - -- if y names a thunk, the call would not care about the
|
|
| 471 | - -- evaluation context. Therefore removing all annotations in the
|
|
| 472 | - -- above example is safe.
|
|
| 498 | + -- | As 'PlaceNonLam', but also float through constructors, non-function
|
|
| 499 | + -- variables and literals.
|
|
| 473 | 500 | | PlaceCostCentre
|
| 474 | 501 | |
| 475 | 502 | deriving (Eq,Show)
|
| ... | ... | @@ -477,7 +504,9 @@ data TickishPlacement = |
| 477 | 504 | instance Outputable TickishPlacement where
|
| 478 | 505 | ppr = text . show
|
| 479 | 506 | |
| 480 | --- | Placement behaviour we want for the ticks
|
|
| 507 | +-- | Placement behaviour we want for the ticks.
|
|
| 508 | +--
|
|
| 509 | +-- See Note [Tickish placement].
|
|
| 481 | 510 | tickishPlace :: GenTickish pass -> TickishPlacement
|
| 482 | 511 | tickishPlace n@ProfNote{}
|
| 483 | 512 | | profNoteCount n = PlaceRuntime
|
| ... | ... | @@ -486,6 +515,43 @@ tickishPlace HpcTick{} = PlaceRuntime |
| 486 | 515 | tickishPlace Breakpoint{} = PlaceRuntime
|
| 487 | 516 | tickishPlace SourceNote{} = PlaceNonLam
|
| 488 | 517 | |
| 518 | +-- | Merge two ticks into one, if that is possible.
|
|
| 519 | +--
|
|
| 520 | +-- Examples:
|
|
| 521 | +--
|
|
| 522 | +-- - combine two source note ticks if one contains the other,
|
|
| 523 | +-- - combine a non-counting profiling tick with a non-scoping profiling tick
|
|
| 524 | +-- for the same cost centre
|
|
| 525 | +-- - combine two equal breakpoint ticks or HPC ticks
|
|
| 526 | +combineTickish_maybe :: Eq (GenTickish pass)
|
|
| 527 | + => GenTickish pass -> GenTickish pass -> Maybe (GenTickish pass)
|
|
| 528 | +combineTickish_maybe
|
|
| 529 | + (ProfNote { profNoteCC = cc1, profNoteCount = cnt1, profNoteScope = scope1 })
|
|
| 530 | + (ProfNote { profNoteCC = cc2, profNoteCount = cnt2, profNoteScope = scope2 })
|
|
| 531 | + | cc1 == cc2
|
|
| 532 | + , not cnt1 || not cnt2
|
|
| 533 | + = Just $ ProfNote { profNoteCC = cc1
|
|
| 534 | + , profNoteCount = cnt1 || cnt2
|
|
| 535 | + , profNoteScope = scope1 || scope2
|
|
| 536 | + }
|
|
| 537 | +combineTickish_maybe t1@(SourceNote sp1 n1) t2@(SourceNote sp2 n2)
|
|
| 538 | + | n1 == n2
|
|
| 539 | + , sp1 `containsSpan` sp2
|
|
| 540 | + = Just t1
|
|
| 541 | + | n1 == n2
|
|
| 542 | + , sp2 `containsSpan` sp1
|
|
| 543 | + = Just t2
|
|
| 544 | + -- NB: it would be possible to use 'combineRealSrcSpans' instead,
|
|
| 545 | + -- but that has the risk of combining many source note ticks into a single
|
|
| 546 | + -- tick with a huge source span.
|
|
| 547 | +combineTickish_maybe t1@(HpcTick {}) t2@(HpcTick {})
|
|
| 548 | + | t1 == t2
|
|
| 549 | + = Just t1
|
|
| 550 | +combineTickish_maybe t1@(Breakpoint {}) t2@(Breakpoint {})
|
|
| 551 | + | t1 == t2
|
|
| 552 | + = Just t1
|
|
| 553 | +combineTickish_maybe _ _ = Nothing
|
|
| 554 | + |
|
| 489 | 555 | -- | Returns whether one tick "contains" the other one, therefore
|
| 490 | 556 | -- making the second tick redundant.
|
| 491 | 557 | tickishContains :: Eq (GenTickish pass)
|
| 1 | +{-# LANGUAGE DataKinds #-}
|
|
| 2 | +{-# LANGUAGE GADTs #-}
|
|
| 3 | +{-# LANGUAGE TypeOperators #-}
|
|
| 4 | + |
|
| 5 | +module T26941 where
|
|
| 6 | + |
|
| 7 | +import GHC.TypeLits
|
|
| 8 | + |
|
| 9 | +import T26941_aux ( SMayNat(SKnown), ListH, shxHead )
|
|
| 10 | + |
|
| 11 | +shsHead :: ListH (Just n : sh) Int -> SNat n
|
|
| 12 | +shsHead shx =
|
|
| 13 | + case shxHead shx of
|
|
| 14 | + SKnown SNat -> SNat |
| 1 | +{-# LANGUAGE DataKinds #-}
|
|
| 2 | +{-# LANGUAGE GADTs #-}
|
|
| 3 | +{-# LANGUAGE StandaloneKindSignatures #-}
|
|
| 4 | +{-# LANGUAGE TypeOperators #-}
|
|
| 5 | + |
|
| 6 | +module T26941_aux where
|
|
| 7 | + |
|
| 8 | +import Data.Kind
|
|
| 9 | +import GHC.TypeLits
|
|
| 10 | + |
|
| 11 | +shxHead :: ListH (n : sh) i -> SMayNat i n
|
|
| 12 | +shxHead list = {-# SCC "bad_scc" #-}
|
|
| 13 | + ( case list of (i `ConsKnown` _) -> SKnown i )
|
|
| 14 | + |
|
| 15 | +type ListH :: [Maybe Nat] -> Type -> Type
|
|
| 16 | +data ListH sh i where
|
|
| 17 | + ConsKnown :: SNat n -> ListH sh i -> ListH (Just n : sh) i
|
|
| 18 | + |
|
| 19 | +data SMayNat i n where
|
|
| 20 | + SKnown :: SNat n -> SMayNat i (Just n) |
| ... | ... | @@ -568,6 +568,8 @@ test('T26117', [grep_errmsg(r'==')], compile, ['-O -ddump-simpl -dsuppress-uniqu |
| 568 | 568 | test('T26349', normal, compile, ['-O -ddump-rules'])
|
| 569 | 569 | test('T26681', normal, compile, ['-O'])
|
| 570 | 570 | |
| 571 | +test('T26941', [extra_files(['T26941_aux.hs']), req_profiling], multimod_compile, ['T26941', '-v0 -O -prof'])
|
|
| 572 | + |
|
| 571 | 573 | # T26709: we expect three `case` expressions not four
|
| 572 | 574 | test('T26709', [grep_errmsg(r'case')],
|
| 573 | 575 | multimod_compile,
|