Simon Jakobi pushed to branch wip/sjakobi/T27368-cbe-compress at Glasgow Haskell Compiler / GHC

Commits:

4 changed files:

Changes:

  • changelog.d/27368
    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

  • compiler/GHC/Cmm/CommonBlockElim.hs
    ... ... @@ -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]
    

  • testsuite/tests/codeGen/should_compile/T27368.hs
    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

  • testsuite/tests/codeGen/should_compile/all.T
    ... ... @@ -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'])