Simon Jakobi pushed to branch wip/sjakobi/T27368-cbe-compress at Glasgow Haskell Compiler / GHC
Commits:
-
df456631
by Simon Jakobi at 2026-08-31T17:15:50+02:00
4 changed files:
- + changelog.d/27368
- compiler/GHC/Cmm/CommonBlockElim.hs
- + testsuite/tests/codeGen/should_compile/T27368.hs
- testsuite/tests/codeGen/should_compile/all.T
Changes:
| 1 | +section: compiler
|
|
| 2 | +synopsis: Fix a ``setInfoTableStackMap`` panic caused by common block elimination
|
|
| 3 | + leaving references to eliminated blocks.
|
|
| 4 | +issues: #27368
|
|
| 5 | +mrs: !16543 |
| ... | ... | @@ -65,7 +65,7 @@ elimCommonBlocks g = |
| 65 | 65 | assert (g_entry g == g_entry g') g'
|
| 66 | 66 | where
|
| 67 | 67 | g' = replaceLabels env $ copyTicks env g
|
| 68 | - env = iterate mapEmpty blocks_with_key
|
|
| 68 | + env = resolveSubst (iterate mapEmpty blocks_with_key)
|
|
| 69 | 69 | -- The order of blocks doesn't matter here. While we could use
|
| 70 | 70 | -- revPostorder which drops unreachable blocks this is done in
|
| 71 | 71 | -- ContFlowOpt already which runs before this pass. So we use
|
| ... | ... | @@ -86,6 +86,27 @@ elimCommonBlocks g = |
| 86 | 86 | -- If we don't we end up with #27722 where the entry block was eliminated in favour
|
| 87 | 87 | -- of another block.
|
| 88 | 88 | |
| 89 | +{- Note [Resolving the CBE substitution]
|
|
| 90 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 91 | +The substitution that `iterate` produces may contain chains
|
|
| 92 | +(k1 :-> k2, k2 :-> k3): the winner of one merge can lose a later one.
|
|
| 93 | +So before applying it we resolve each entry to the end of its chain
|
|
| 94 | +(resolveSubst).
|
|
| 95 | + |
|
| 96 | +Applying the unresolved substitution instead would let replaceLabels leave
|
|
| 97 | +edges pointing at eliminated labels. Such edges can occur in blocks that
|
|
| 98 | +themselves lost a merge, i.e. in unreachable code, but even there they can be
|
|
| 99 | +harmful (see #27368). Also see Note [unreachable blocks] in GHC.Cmm.Pipeline.
|
|
| 100 | +-}
|
|
| 101 | + |
|
| 102 | +-- | Resolve the substitution: follow chains (@k1 :-> k2@, @k2 :-> k3@)
|
|
| 103 | +-- to their ends, so that every eliminated label maps directly to its
|
|
| 104 | +-- final surviving representative.
|
|
| 105 | +--
|
|
| 106 | +-- See Note [Resolving the CBE substitution].
|
|
| 107 | +resolveSubst :: Subst -> Subst
|
|
| 108 | +resolveSubst env = mapMap (lookupBid env) env
|
|
| 109 | + |
|
| 89 | 110 | -- Invariant: The blocks in the list are pairwise distinct
|
| 90 | 111 | -- (so avoid comparing them again)
|
| 91 | 112 | type DistinctBlocks = [CmmBlock]
|
| 1 | +-- The two branches share an identical suffix from the inner case
|
|
| 2 | +-- onwards, so common block elimination merges the duplicated call
|
|
| 3 | +-- blocks over several rounds, building a substitution chain. Without
|
|
| 4 | +-- resolving that chain, compiling this module at -O panicked in
|
|
| 5 | +-- setInfoTableStackMap (#27368). See
|
|
| 6 | +-- Note [Resolving the CBE substitution] in GHC.Cmm.CommonBlockElim.
|
|
| 7 | + |
|
| 8 | +module T27368 (f) where
|
|
| 9 | + |
|
| 10 | +{-# NOINLINE put #-}
|
|
| 11 | +put :: Int -> Int -> IO ()
|
|
| 12 | +put h x = if h + x == 12345 then errorWithoutStackTrace "boom" else pure ()
|
|
| 13 | + |
|
| 14 | +data T = J Int | K
|
|
| 15 | + |
|
| 16 | +f :: Int -> Bool -> T -> IO ()
|
|
| 17 | +f h a t = do
|
|
| 18 | + if a
|
|
| 19 | + then do put h 1; case t of { J _ -> put h 3; K -> put h 4 }; put h 0; put h 0
|
|
| 20 | + else do put h 2; case t of { J _ -> put h 3; K -> put h 4 }; put h 0; put h 0
|
|
| 21 | + put h 0 |
| ... | ... | @@ -150,3 +150,5 @@ test('T16351', normal, compile, ['-O2 -ddump-simpl -dno-typeable-binds -dsuppres |
| 150 | 150 | test('T20298a', normal, compile, ['-O2 -ddump-simpl -dno-typeable-binds -dsuppress-all -dsuppress-uniques'])
|
| 151 | 151 | test('T20298b', normal, compile, ['-O2 -dno-bignum-rules -ddump-simpl -dno-typeable-binds -dsuppress-all -dsuppress-uniques'])
|
| 152 | 152 | test('T20298c', normal, compile, ['-O2 -dno-builtin-rules -ddump-simpl -dno-typeable-binds -dsuppress-all -dsuppress-uniques'])
|
| 153 | + |
|
| 154 | +test('T27368', normal, compile, ['-O']) |