Simon Jakobi pushed to branch wip/sjakobi/T27368-ppr at Glasgow Haskell Compiler / GHC
Commits:
-
7496cace
by Simon Jakobi at 2026-07-28T23:59:34+02:00
7 changed files:
- + changelog.d/T27368-ppr-unreachable-cmm-blocks.md
- compiler/GHC/Cmm.hs
- compiler/GHC/Cmm/Pipeline.hs
- docs/users_guide/debugging.rst
- + testsuite/tests/cmm/should_compile/T27368-ppr-debug.cmm
- + testsuite/tests/cmm/should_compile/T27368-ppr-debug.stderr
- testsuite/tests/cmm/should_compile/all.T
Changes:
| 1 | +section: cmm
|
|
| 2 | +issues: #27368
|
|
| 3 | +mrs: !16417
|
|
| 4 | +synopsis:
|
|
| 5 | + Cmm dumps now show unreachable blocks under ``-dppr-debug``
|
|
| 6 | +description:
|
|
| 7 | + Unreachable blocks stay in a Cmm graph's block map for most of the Cmm
|
|
| 8 | + pipeline, but ``-ddump-cmm-*`` only ever printed the blocks reachable from
|
|
| 9 | + the graph's entry. Adding ``-dppr-debug`` now appends the stored but
|
|
| 10 | + unreachable blocks, which makes bugs like #27368 visible in the dumps. |
| ... | ... | @@ -151,15 +151,24 @@ instance OutputableP Platform CmmGraph where |
| 151 | 151 | toBlockMap :: CmmGraph -> LabelMap CmmBlock
|
| 152 | 152 | toBlockMap (CmmGraph {g_graph=GMany NothingO body NothingO}) = body
|
| 153 | 153 | |
| 154 | +-- | Print the blocks reachable from the entry, in reverse postorder. Under
|
|
| 155 | +-- @-dppr-debug@ the blocks that are stored in the graph but unreachable are
|
|
| 156 | +-- appended too; see Note [unreachable blocks] in "GHC.Cmm.Pipeline".
|
|
| 154 | 157 | pprCmmGraph :: Platform -> CmmGraph -> SDoc
|
| 155 | 158 | pprCmmGraph platform g
|
| 156 | 159 | = text "{" <> text "offset"
|
| 157 | - $$ nest 2 (vcat $ map (pdoc platform) blocks)
|
|
| 160 | + $$ nest 2 (vcat (map (pdoc platform) blocks) $$ unreachable)
|
|
| 158 | 161 | $$ text "}"
|
| 159 | - where blocks = revPostorder g
|
|
| 160 | - -- revPostorder has the side-effect of discarding unreachable code,
|
|
| 161 | - -- so pretty-printed Cmm will omit any unreachable blocks. This can
|
|
| 162 | - -- sometimes be confusing.
|
|
| 162 | + where
|
|
| 163 | + blocks = revPostorder g
|
|
| 164 | + |
|
| 165 | + unreachable = getPprDebug $ \debug ->
|
|
| 166 | + if not debug || mapNull dead_blocks
|
|
| 167 | + then empty
|
|
| 168 | + else text "// unreachable blocks:"
|
|
| 169 | + $$ nest 2 (vcat $ map (pdoc platform) (mapElems dead_blocks))
|
|
| 170 | + |
|
| 171 | + dead_blocks = foldl' (\bs b -> mapDelete (entryLabel b) bs) (toBlockMap g) blocks
|
|
| 163 | 172 | |
| 164 | 173 | revPostorder :: CmmGraph -> [CmmBlock]
|
| 165 | 174 | revPostorder g = {-# SCC "revPostorder" #-}
|
| ... | ... | @@ -357,6 +357,7 @@ containing junk code. These aren't necessarily a problem, but |
| 357 | 357 | removing them is good because it might save time in the native code
|
| 358 | 358 | generator later.
|
| 359 | 359 | |
| 360 | +To make unreachable blocks visible in -ddump-cmm-* output, add -dppr-debug.
|
|
| 360 | 361 | -}
|
| 361 | 362 | |
| 362 | 363 | dumpGraph :: Logger -> Platform -> Bool -> DumpFlag -> String -> CmmGraph -> IO ()
|
| ... | ... | @@ -564,6 +564,11 @@ C-\- representation |
| 564 | 564 | |
| 565 | 565 | These flags dump various phases of GHC's C-\- pipeline.
|
| 566 | 566 | |
| 567 | +Dumps of Cmm graphs print the blocks reachable from the entry, in reverse
|
|
| 568 | +post-order. To also show unreachable blocks, which can linger in the graph,
|
|
| 569 | +add :ghc-flag:`-dppr-debug`. These blocks are then listed under a
|
|
| 570 | +``// unreachable blocks:`` heading.
|
|
| 571 | + |
|
| 567 | 572 | .. ghc-flag:: -ddump-cmm-verbose-by-proc
|
| 568 | 573 | :shortdesc: Show output from main C-\- pipeline passes (grouped by proc)
|
| 569 | 574 | :type: dynamic
|
| ... | ... | @@ -574,9 +579,6 @@ These flags dump various phases of GHC's C-\- pipeline. |
| 574 | 579 | the chosen backend. Currently only the NCG backends runs
|
| 575 | 580 | additional passes ( :ghc-flag:`-ddump-opt-cmm` ).
|
| 576 | 581 | |
| 577 | - Cmm dumps don't include unreachable blocks since we print
|
|
| 578 | - blocks in reverse post-order.
|
|
| 579 | - |
|
| 580 | 582 | .. ghc-flag:: -ddump-cmm-verbose
|
| 581 | 583 | :shortdesc: Write output from main C-\- pipeline passes to files
|
| 582 | 584 | :type: dynamic
|
| 1 | +#include "Cmm.h"
|
|
| 2 | + |
|
| 3 | +// The block "dead" is stored in the graph but no block branches to it, so it
|
|
| 4 | +// only shows up in Cmm dumps under -dppr-debug.
|
|
| 5 | +testUnreachable (W_ x)
|
|
| 6 | +{
|
|
| 7 | + if (x > 0) {
|
|
| 8 | + goto live;
|
|
| 9 | + }
|
|
| 10 | + return (x);
|
|
| 11 | + |
|
| 12 | +dead:
|
|
| 13 | + x = x + 42;
|
|
| 14 | + return (x);
|
|
| 15 | + |
|
| 16 | +live:
|
|
| 17 | + x = x - 1;
|
|
| 18 | + return (x);
|
|
| 19 | +} |
| 1 | +// unreachable blocks: |
| ... | ... | @@ -13,6 +13,9 @@ test('T20725', normal, compile, ['-package ghc']) |
| 13 | 13 | test('T23610', normal, makefile_test, ['T23610'])
|
| 14 | 14 | test('T24224', [cmm_src, grep_errmsg(r'(F64.*);', [1]), only_ways(['normal'])], compile, ['-no-hs-main -ddump-cmm -dsuppress-all -dsuppress-uniques'])
|
| 15 | 15 | test('T24474', cmm_src, compile, ['-optc-g3'])
|
| 16 | +# -dppr-debug makes stored-but-unreachable blocks visible in Cmm dumps (#27368)
|
|
| 17 | +test('T27368-ppr-debug', [cmm_src, grep_errmsg(r'(// unreachable blocks:)', [1]), only_ways(['normal'])],
|
|
| 18 | + compile, ['-no-hs-main -ddump-cmm-verbose-by-proc -dppr-debug -dsuppress-uniques'])
|
|
| 16 | 19 | test('T24474-cmm-gets-c-opts', cmm_src, compile, ['-optc-DFOO'])
|
| 17 | 20 | test('T24474-cmm-opt-order', cmm_src, compile, ['-optc-DFOO '
|
| 18 | 21 | '-optCmmP-UFOO '
|