Simon Jakobi pushed to branch wip/sjakobi/T27368-cbe-compress at Glasgow Haskell Compiler / GHC
Commits:
-
a0539f8e
by Simon Jakobi at 2026-09-01T09:46:06+02:00
3 changed files:
Changes:
| ... | ... | @@ -59,18 +59,25 @@ import qualified Data.List.NonEmpty as NE |
| 59 | 59 | -- hashes, and at most once otherwise. Previously, we were slower, and people
|
| 60 | 60 | -- rightfully complained: #10397
|
| 61 | 61 | |
| 62 | +-- The input graph may contain unreachable blocks (see
|
|
| 63 | +-- Note [unreachable blocks] in GHC.Cmm.Pipeline). They take part in
|
|
| 64 | +-- deduplication like any other block, and stay in the graph unless
|
|
| 65 | +-- eliminated by a merge (deleteLosers removes those).
|
|
| 66 | + |
|
| 62 | 67 | -- TODO: Use optimization fuel
|
| 63 | 68 | elimCommonBlocks :: CmmGraph -> CmmGraph
|
| 64 | 69 | elimCommonBlocks g =
|
| 65 | 70 | assert (g_entry g == g_entry g') g'
|
| 66 | 71 | where
|
| 67 | - g' = replaceLabels env $ copyTicks env g
|
|
| 72 | + g' = replaceLabels env $ deleteLosers $ copyTicks env g
|
|
| 73 | + deleteLosers g0
|
|
| 74 | + | mapNull env = g0
|
|
| 75 | + | otherwise = ofBlockMap (g_entry g0)
|
|
| 76 | + (toBlockMap g0 `mapDifference` env)
|
|
| 68 | 77 | env = resolveSubst (iterate mapEmpty blocks_with_key)
|
| 69 | - -- The order of blocks doesn't matter here. While we could use
|
|
| 70 | - -- revPostorder which drops unreachable blocks this is done in
|
|
| 71 | - -- ContFlowOpt already which runs before this pass. So we use
|
|
| 72 | - -- toBlockList since it is faster.
|
|
| 73 | - -- One exception: The entry block most come first or we risk eliminating it
|
|
| 78 | + -- The order of blocks doesn't matter here, so we use toBlockList,
|
|
| 79 | + -- which is faster than revPostorder.
|
|
| 80 | + -- One exception: The entry block must come first or we risk eliminating it
|
|
| 74 | 81 | -- in favour of another block. See Note [Retain entry block during common block elimination.]
|
| 75 | 82 | groups = groupByInt hash_block (toBlockListEntryFirst g) :: [[CmmBlock]]
|
| 76 | 83 | blocks_with_key = [ [ (successors b, [b]) | b <- bs] | bs <- groups]
|
| ... | ... | @@ -42,9 +42,10 @@ import Control.Monad |
| 42 | 42 | -- L2: goto L3;
|
| 43 | 43 | -- L3: ...
|
| 44 | 44 | --
|
| 45 | --- In this situation we say that we shortcut L2 to L3. One of
|
|
| 45 | +-- In this situation we say that we shortcut L2 to L3. One of the
|
|
| 46 | 46 | -- consequences of shortcutting is that some blocks of code may become
|
| 47 | --- unreachable (in the example above this is true for L2).
|
|
| 47 | +-- unreachable (in the example above this is true for L2). See
|
|
| 48 | +-- Note [unreachable blocks] in GHC.Cmm.Pipeline.
|
|
| 48 | 49 | |
| 49 | 50 | |
| 50 | 51 | -- Note [Control-flow optimisations]
|
| ... | ... | @@ -66,7 +67,7 @@ import Control.Monad |
| 66 | 67 | --
|
| 67 | 68 | -- Blocks are processed using postorder DFS traversal. A side effect
|
| 68 | 69 | -- of determining traversal order with a graph search is elimination
|
| 69 | --- of any blocks that are unreachable.
|
|
| 70 | +-- of any blocks that are unreachable in the input.
|
|
| 70 | 71 | --
|
| 71 | 72 | -- Transformations are improved by working from the end of the graph
|
| 72 | 73 | -- towards the beginning, because we may be able to perform many
|
| ... | ... | @@ -341,8 +342,7 @@ blockConcat splitting_procs g@CmmGraph { g_entry = entry_id } |
| 341 | 342 | -- Invariant: if a block has no predecessors it should be dropped from the
|
| 342 | 343 | -- graph because it is unreachable. maybe_concat is constructed to maintain
|
| 343 | 344 | -- that invariant, but calling replaceLabels may introduce unreachable blocks.
|
| 344 | --- We rely on subsequent passes in the Cmm pipeline to remove unreachable
|
|
| 345 | --- blocks.
|
|
| 345 | +-- See Note [unreachable blocks] in GHC.Cmm.Pipeline.
|
|
| 346 | 346 | incPreds, decPreds :: BlockId -> LabelMap Int -> LabelMap Int
|
| 347 | 347 | incPreds bid edges = mapInsertWith (+) bid 1 edges
|
| 348 | 348 | decPreds bid edges = case mapLookup bid edges of
|
| ... | ... | @@ -358,6 +358,20 @@ containing junk code. These aren't necessarily a problem, but |
| 358 | 358 | removing them is good because it might save time in the native code
|
| 359 | 359 | generator later.
|
| 360 | 360 | |
| 361 | +Who removes them, and when? Any pass that rebuilds the graph from
|
|
| 362 | +revPostorder drops them as a side effect. Normally the first pass to
|
|
| 363 | +do so is stack layout. In addition, removeUnreachableBlocksProc at the
|
|
| 364 | +very end of cpsTop removes the blocks that the second round of
|
|
| 365 | +control-flow optimisation orphans, and prunes their info tables. No
|
|
| 366 | +pass between the first control-flow optimisation and stack layout
|
|
| 367 | +removes unreachable blocks (common block elimination deletes the losing
|
|
| 368 | +blocks of its merges, but leaves other unreachable code alone), so every
|
|
| 369 | +pass in that window may encounter them.
|
|
| 370 | + |
|
| 371 | +Note that unreachable blocks are not entirely harmless, though: some later
|
|
| 372 | +passes read them. callProcPoints, for example, folds over the whole block map,
|
|
| 373 | +so a stale edge in an unreachable block caused the panic in #27368.
|
|
| 374 | + |
|
| 361 | 375 | To make unreachable blocks visible in -ddump-cmm-* output, add -dppr-debug.
|
| 362 | 376 | -}
|
| 363 | 377 |