Simon Jakobi pushed to branch wip/sjakobi/clabel-monomorphic at Glasgow Haskell Compiler / GHC
WARNING: The push did not contain any new commits, but force pushed to delete the commits and changes below.
Deleted commits:
bf52c492 by Simon Jakobi at 2026-06-11T08:50:35+02:00
Only treat continuations of reachable calls as proc points
callProcPoints used to fold over the whole block map, which can
contain unreachable blocks: the control-flow optimiser and the common
block eliminator both leave them behind, and they are only removed at
the end of the Cmm pipeline (Note [unreachable blocks]).
In particular, when CBE merges duplicated call blocks it leaves the
losing copy in the block map, and the continuation of such a dead call
can itself be unreachable. callProcPoints would still collect that
continuation, attachContInfoTables would attach an info table to it,
but stack layout (which only walks reachable blocks) produced no stack
map for it, so setInfoTableStackMap panicked:
ghc: panic! (the 'impossible' happened)
setInfoTableStackMap
This was triggered by compiling GHC.CmmToAsm.Dwarf.Types with -O2
after the previous commit reshaped the CLabel printers, but the bug is
latent and independent of that change.
Fix: make callProcPoints fold over revPostorder, i.e. reachable blocks
only. Also correct the stale comment in elimCommonBlocks claiming that
ContFlowOpt has already removed unreachable blocks, and extend
Note [unreachable blocks] with the invariant and a warning that the
Cmm pretty-printer hides unreachable blocks in dumps.
Co-Authored-By: Claude Fable 5
- - - - -
3 changed files:
- compiler/GHC/Cmm/CommonBlockElim.hs
- compiler/GHC/Cmm/Pipeline.hs
- compiler/GHC/Cmm/ProcPoint.hs
Changes:
=====================================
compiler/GHC/Cmm/CommonBlockElim.hs
=====================================
@@ -63,10 +63,16 @@ elimCommonBlocks :: CmmGraph -> CmmGraph
elimCommonBlocks g = replaceLabels env $ copyTicks env g
where
env = iterate mapEmpty blocks_with_key
- -- The order of blocks doesn't matter here. While we could use
- -- revPostorder which drops unreachable blocks this is done in
- -- ContFlowOpt already which runs before this pass. So we use
- -- toBlockList since it is faster.
+ -- The order of blocks doesn't matter here. Note that toBlockList
+ -- includes unreachable blocks (ContFlowOpt leaves them in the block
+ -- map, see Note [unreachable blocks] in GHC.Cmm.Pipeline), so we may
+ -- hash and merge dead blocks, and a live block may even be
+ -- substituted by an unreachable duplicate (resurrecting it). That is
+ -- semantically harmless since the blocks are identical, but it means
+ -- this pass both consumes and produces unreachable blocks; passes
+ -- between this one and the final removeUnreachableBlocksProc must
+ -- not let blocks that are unreachable here influence the reachable
+ -- part of the graph (see e.g. callProcPoints in GHC.Cmm.ProcPoint).
groups = groupByInt hash_block (toBlockList g) :: [[CmmBlock]]
blocks_with_key = [ [ (successors b, [b]) | b <- bs] | bs <- groups]
=====================================
compiler/GHC/Cmm/Pipeline.hs
=====================================
@@ -352,10 +352,22 @@ _GLOBAL_OFFSET_TABLE_, regardless of which entry point we arrived via.
{- Note [unreachable blocks]
~~~~~~~~~~~~~~~~~~~~~~~~~
-The control-flow optimiser sometimes leaves unreachable blocks behind
-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.
+The control-flow optimiser and the common block eliminator sometimes
+leave unreachable blocks behind containing junk code; they are only
+removed here, at the end of the pipeline. Removing them earlier would
+cost extra reachability passes, but deferring the removal means every
+pass in between runs on a block map that may contain unreachable
+blocks, and must take care that they don't influence the reachable
+part of the graph. In particular, the continuation of a call in an
+unreachable block may itself be unreachable, so it must not be treated
+as a proc point: stack layout only lays out reachable blocks, and an
+info table attached (by attachContInfoTables) to a continuation
+without a stack map makes setInfoTableStackMap panic. See
+callProcPoints in GHC.Cmm.ProcPoint.
+
+Beware also that the Cmm pretty-printer omits unreachable blocks, so
+they do not show up in -ddump-cmm-* output; a dump can therefore look
+consistent while the underlying block map is not.
-}
=====================================
compiler/GHC/Cmm/ProcPoint.hs
=====================================
@@ -173,8 +173,16 @@ procPointLattice = DataflowLattice unreached add_to
-- introduced because they're reachable from multiple proc points.
--
-- Extract the set of Continuation BlockIds, see Note [Continuation BlockIds].
+--
+-- We must consider only *reachable* blocks: the common block eliminator
+-- leaves duplicated (hence unreachable) call blocks in the block map
+-- (see Note [unreachable blocks] in GHC.Cmm.Pipeline), and the
+-- continuation of such a dead call may itself be unreachable. Stack
+-- layout only lays out reachable blocks, so a continuation collected
+-- from a dead call would get an info table (attachContInfoTables) but
+-- no stack map, making setInfoTableStackMap panic.
callProcPoints :: CmmGraph -> ProcPointSet
-callProcPoints g = foldlGraphBlocks add (setSingleton (g_entry g)) g
+callProcPoints g = foldl' add (setSingleton (g_entry g)) (revPostorder g)
where add :: LabelSet -> CmmBlock -> LabelSet
add set b = case lastNode b of
CmmCall {cml_cont = Just k} -> setInsert k set
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/bf52c49204953d0ffd2b1c5a74003f48...
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/bf52c49204953d0ffd2b1c5a74003f48...
You're receiving this email because of your account on gitlab.haskell.org.