[Git][ghc/ghc][master] Cmm: print unreachable blocks under -dppr-debug (#27368)
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC Commits: 0779e12c by Simon Jakobi at 2026-08-07T12:36:11-04:00 Cmm: print unreachable blocks under -dppr-debug (#27368) Unreachable blocks linger in a CmmGraph's block map for most of the Cmm pipeline, but pprCmmGraph only ever printed the blocks reachable from the entry, so dumps looked consistent while the graph was not. Issues like #27368 were hard to debug due to this. pprCmmGraph now appends the stored-but-unreachable blocks under a "// unreachable blocks:" heading when -dppr-debug is on. See Note [unreachable blocks] in GHC.Cmm.Pipeline. Assisted-by: Claude Opus 5 - - - - - 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: ===================================== changelog.d/T27368-ppr-unreachable-cmm-blocks.md ===================================== @@ -0,0 +1,10 @@ +section: cmm +issues: #27368 +mrs: !16417 +synopsis: + Cmm dumps now show unreachable blocks under ``-dppr-debug`` +description: + Unreachable blocks stay in a Cmm graph's block map for most of the Cmm + pipeline, but ``-ddump-cmm-*`` only ever printed the blocks reachable from + the graph's entry. Adding ``-dppr-debug`` now appends the stored but + unreachable blocks, which makes bugs like #27368 visible in the dumps. ===================================== compiler/GHC/Cmm.hs ===================================== @@ -151,15 +151,28 @@ instance OutputableP Platform CmmGraph where toBlockMap :: CmmGraph -> LabelMap CmmBlock toBlockMap (CmmGraph {g_graph=GMany NothingO body NothingO}) = body +-- | Print the blocks reachable from the entry, in reverse postorder. +-- +-- Under @-dppr-debug@ the unreachable blocks stored in the graph are appended +-- too. See Note [unreachable blocks] in "GHC.Cmm.Pipeline". pprCmmGraph :: Platform -> CmmGraph -> SDoc pprCmmGraph platform g = text "{" <> text "offset" - $$ nest 2 (vcat $ map (pdoc platform) blocks) + $$ nest 2 (ppr_blocks blocks $$ unreachable) $$ text "}" - where blocks = revPostorder g - -- revPostorder has the side-effect of discarding unreachable code, - -- so pretty-printed Cmm will omit any unreachable blocks. This can - -- sometimes be confusing. + where + ppr_blocks :: [CmmBlock] -> SDoc + ppr_blocks = vcat . map (pdoc platform) + + blocks = revPostorder g + + unreachable = getPprDebug $ \debug -> + if not debug || mapNull dead_blocks + then empty + else text "// unreachable blocks:" + $$ nest 2 (ppr_blocks (mapElems dead_blocks)) + + dead_blocks = foldl' (\bs b -> mapDelete (entryLabel b) bs) (toBlockMap g) blocks revPostorder :: CmmGraph -> [CmmBlock] revPostorder g = {-# SCC "revPostorder" #-} ===================================== compiler/GHC/Cmm/Pipeline.hs ===================================== @@ -358,6 +358,7 @@ containing junk code. These aren't necessarily a problem, but removing them is good because it might save time in the native code generator later. +To make unreachable blocks visible in -ddump-cmm-* output, add -dppr-debug. -} dumpGraph :: Logger -> Platform -> Bool -> DumpFlag -> String -> CLabel -> CmmGraph -> IO () ===================================== docs/users_guide/debugging.rst ===================================== @@ -564,6 +564,11 @@ C-\- representation These flags dump various phases of GHC's C-\- pipeline. +Dumps of Cmm graphs print the blocks reachable from the entry, in reverse +post-order. To also show unreachable blocks, which can linger in the graph, +add :ghc-flag:`-dppr-debug`. These blocks are then listed under a +``// unreachable blocks:`` heading. + .. ghc-flag:: -ddump-cmm-verbose-by-proc :shortdesc: Show output from main C-\- pipeline passes (grouped by proc) :type: dynamic @@ -574,9 +579,6 @@ These flags dump various phases of GHC's C-\- pipeline. the chosen backend. Currently only the NCG backends runs additional passes ( :ghc-flag:`-ddump-opt-cmm` ). - Cmm dumps don't include unreachable blocks since we print - blocks in reverse post-order. - .. ghc-flag:: -ddump-cmm-verbose :shortdesc: Write output from main C-\- pipeline passes to files :type: dynamic ===================================== testsuite/tests/cmm/should_compile/Makefile ===================================== @@ -16,3 +16,16 @@ T16930: T23610: '$(TEST_HC)' $(TEST_HC_OPTS) T23610.cmm -S + +# The three seds below, in order: +# 1. Keep only the "Parsed Cmm" dump, since that is the one stage where the +# unreachable block still exists. +# 2. Rewrite goto targets: their label uniques survive -dsuppress-uniques +# (#21310). +# 3. Drop the "// CmmAssign"-style node annotations, which pprNode emits +# only on DEBUG compilers. +T27368-ppr-debug: + '$(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 \ + | sed -n '/^==* Parsed Cmm/,/^ \}\]/p' \ + | sed 's/goto c[0-9A-Za-z]*/goto _lbl_/g' \ + | sed 's| *// Cmm[A-Za-z]*$$||' ===================================== testsuite/tests/cmm/should_compile/T27368-ppr-debug.cmm ===================================== @@ -0,0 +1,19 @@ +#include "Cmm.h" + +// The block "dead" is stored in the graph but no block branches to it, so it +// only shows up in Cmm dumps under -dppr-debug. +testUnreachable (W_ x) +{ + if (x > 0) { + goto live; + } + return (x); + +dead: + x = x + 42; + return (x); + +live: + x = x - 1; + return (x); +} ===================================== testsuite/tests/cmm/should_compile/T27368-ppr-debug.stdout ===================================== @@ -0,0 +1,27 @@ +==================== Parsed Cmm ==================== +[testUnreachable() { // [R1] + { info_tbls: [] + stack_info: arg_space: 8 + } + {offset + _lbl_: + __locVar_::I64 = R1; + if (__locVar_::I64 > 0) goto _lbl_; else goto _lbl_; + _lbl_: + goto _lbl_; + _lbl_: + __locVar_::I64 = __locVar_::I64 - 1; + R1 = __locVar_::I64; + call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8; + _lbl_: + goto _lbl_; + _lbl_: + R1 = __locVar_::I64; + call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8; + // unreachable blocks: + _lbl_: + __locVar_::I64 = __locVar_::I64 + 42; + R1 = __locVar_::I64; + call (P64[(old + 8)])(R1) args: 8, res: 0, upd: 8; + } + }] ===================================== testsuite/tests/cmm/should_compile/all.T ===================================== @@ -13,6 +13,11 @@ test('T20725', normal, compile, ['-package ghc']) test('T23610', normal, makefile_test, ['T23610']) test('T24224', [cmm_src, grep_errmsg(r'(F64.*);', [1]), only_ways(['normal'])], compile, ['-no-hs-main -ddump-cmm -dsuppress-all -dsuppress-uniques']) test('T24474', cmm_src, compile, ['-optc-g3']) +# -dppr-debug makes stored-but-unreachable blocks visible in Cmm dumps (#27368). +# Skipped on wordsize(32) targets, where the dump would say I32/P32, and on +# unregisterised builds, which print call targets with an extra load. +test('T27368-ppr-debug', [when(wordsize(32), skip), when(unregisterised(), skip)], + makefile_test, ['T27368-ppr-debug']) test('T24474-cmm-gets-c-opts', cmm_src, compile, ['-optc-DFOO']) test('T24474-cmm-opt-order', cmm_src, compile, ['-optc-DFOO ' '-optCmmP-UFOO ' View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0779e12ce2cd57034aae61dc67e5f621... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/0779e12ce2cd57034aae61dc67e5f621... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Marge Bot (@marge-bot)