Simon Jakobi pushed to branch wip/sjakobi/T27368-ppr at Glasgow Haskell Compiler / GHC
Commits:
-
8022a6e5
by Simon Jakobi at 2026-08-04T17:22:29+02:00
8 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/Makefile
- + testsuite/tests/cmm/should_compile/T27368-ppr-debug.cmm
- + testsuite/tests/cmm/should_compile/T27368-ppr-debug.stdout
- 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,28 @@ 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.
|
|
| 155 | +--
|
|
| 156 | +-- Under @-dppr-debug@ the unreachable blocks stored in the graph are appended
|
|
| 157 | +-- too. See Note [unreachable blocks] in "GHC.Cmm.Pipeline".
|
|
| 154 | 158 | pprCmmGraph :: Platform -> CmmGraph -> SDoc
|
| 155 | 159 | pprCmmGraph platform g
|
| 156 | 160 | = text "{" <> text "offset"
|
| 157 | - $$ nest 2 (vcat $ map (pdoc platform) blocks)
|
|
| 161 | + $$ nest 2 (ppr_blocks blocks $$ unreachable)
|
|
| 158 | 162 | $$ 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.
|
|
| 163 | + where
|
|
| 164 | + ppr_blocks :: [CmmBlock] -> SDoc
|
|
| 165 | + ppr_blocks = vcat . map (pdoc platform)
|
|
| 166 | + |
|
| 167 | + blocks = revPostorder g
|
|
| 168 | + |
|
| 169 | + unreachable = getPprDebug $ \debug ->
|
|
| 170 | + if not debug || mapNull dead_blocks
|
|
| 171 | + then empty
|
|
| 172 | + else text "// unreachable blocks:"
|
|
| 173 | + $$ nest 2 (ppr_blocks (mapElems dead_blocks))
|
|
| 174 | + |
|
| 175 | + dead_blocks = foldl' (\bs b -> mapDelete (entryLabel b) bs) (toBlockMap g) blocks
|
|
| 163 | 176 | |
| 164 | 177 | revPostorder :: CmmGraph -> [CmmBlock]
|
| 165 | 178 | 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
|
| ... | ... | @@ -16,3 +16,16 @@ T16930: |
| 16 | 16 | |
| 17 | 17 | T23610:
|
| 18 | 18 | '$(TEST_HC)' $(TEST_HC_OPTS) T23610.cmm -S
|
| 19 | + |
|
| 20 | +# The three seds below, in order:
|
|
| 21 | +# 1. Keep only the "Parsed Cmm" dump, since that is the one stage where the
|
|
| 22 | +# unreachable block still exists.
|
|
| 23 | +# 2. Rewrite goto targets: their label uniques survive -dsuppress-uniques
|
|
| 24 | +# (#21310).
|
|
| 25 | +# 3. Drop the "// CmmAssign"-style node annotations, which pprNode emits
|
|
| 26 | +# only on DEBUG compilers.
|
|
| 27 | +T27368-ppr-debug:
|
|
| 28 | + '$(TEST_HC)' $(TEST_HC_OPTS) -c -no-hs-main -ddump-cmm-verbose-by-proc -dppr-debug -dsuppress-uniques -dsuppress-ticks T27368-ppr-debug.cmm 2>&1 \
|
|
| 29 | + | sed -n '/^==* Parsed Cmm/,/^ \}\]/p' \
|
|
| 30 | + | sed 's/goto c[0-9A-Za-z]*/goto _lbl_/g' \
|
|
| 31 | + | sed 's| *// Cmm[A-Za-z]*$$||' |
| 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 | +==================== Parsed Cmm ====================
|
|
| 2 | +[testUnreachable() { // [R1]
|
|
| 3 | + { info_tbls: []
|
|
| 4 | + stack_info: arg_space: 8
|
|
| 5 | + }
|
|
| 6 | + {offset
|
|
| 7 | + _lbl_:
|
|
| 8 | + __locVar_::I64 = R1;
|
|
| 9 | + if (__locVar_::I64 > 0) goto _lbl_; else goto _lbl_;
|
|
| 10 | + _lbl_:
|
|
| 11 | + goto _lbl_;
|
|
| 12 | + _lbl_:
|
|
| 13 | + __locVar_::I64 = __locVar_::I64 - 1;
|
|
| 14 | + R1 = __locVar_::I64;
|
|
| 15 | + call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8;
|
|
| 16 | + _lbl_:
|
|
| 17 | + goto _lbl_;
|
|
| 18 | + _lbl_:
|
|
| 19 | + R1 = __locVar_::I64;
|
|
| 20 | + call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8;
|
|
| 21 | + // unreachable blocks:
|
|
| 22 | + _lbl_:
|
|
| 23 | + __locVar_::I64 = __locVar_::I64 + 42;
|
|
| 24 | + R1 = __locVar_::I64;
|
|
| 25 | + call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8;
|
|
| 26 | + }
|
|
| 27 | + }] |
| ... | ... | @@ -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 | +# Skipped on wordsize(32) targets, where the dump would say I32/P32.
|
|
| 18 | +test('T27368-ppr-debug', [when(wordsize(32), skip)], makefile_test, ['T27368-ppr-debug'])
|
|
| 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 '
|