Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC

Commits:

5 changed files:

Changes:

  • changelog.d/T27722-cbe-entry-block.md
    1 1
     section: cmm
    
    2 2
     issues: #27722
    
    3
    -mrs: !16592
    
    3
    +mrs: !16592 !16861
    
    4 4
     synopsis:
    
    5 5
       Fix common block elimination dropping entry block info table in hand written cmm.

  • compiler/GHC/Cmm/CommonBlockElim.hs
    ... ... @@ -66,25 +66,23 @@ elimCommonBlocks g =
    66 66
       where
    
    67 67
          g' = replaceLabels env $ copyTicks env g
    
    68 68
          env = iterate mapEmpty blocks_with_key
    
    69
    -     -- The order of blocks doesn't matter here. While we could use
    
    70
    -     -- revPostorder which drops unreachable blocks this is done in
    
    71
    -     -- ContFlowOpt already which runs before this pass. So we use
    
    72
    -     -- toBlockList since it is faster.
    
    73
    -     -- One exception: The entry block most come first or we risk eliminating it
    
    74
    -     -- in favour of another block. See Note [Retain entry block during common block elimination.]
    
    75
    -     groups = groupByInt hash_block (toBlockListEntryFirst g) :: [[CmmBlock]]
    
    76 69
          blocks_with_key = [ [ (successors b, [b]) | b <- bs] | bs <- groups]
    
    77
    -
    
    78
    --- Note [Retain entry block during common block elimination.]
    
    79
    --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    80
    --- At the stage we run common block elimination (CBE) we only have one info
    
    81
    --- table for the entry label. Which means we can get away without applying the
    
    82
    --- block label substitution to the info table *as long as we keep the first block*.
    
    83
    --- When combining blocks the first block in the list of blocks is kept, and the later
    
    84
    --- one eliminated, so we can achieve this by simply using toBlockListEntryFirst.
    
    70
    +     groups = groupByInt hash_block candidates :: [[CmmBlock]]
    
    71
    +     -- See Note [Retain entry block during common block elimination]
    
    72
    +     candidates = filter ((/= g_entry g) . entryLabel) (toBlockList g)
    
    73
    +
    
    74
    +-- Note [Retain entry block during common block elimination]
    
    75
    +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    76
    +-- When CBE runs, only the entry label has an info table, so we can get away
    
    77
    +-- without applying the block label substitution to info tables, as long as we
    
    78
    +-- preserve the entry block (#27722). We achieve this by simply keeping it out
    
    79
    +-- of the list of candidates for elimination.
    
    85 80
     --
    
    86
    --- If we don't we end up with #27722 where the entry block was eliminated in favour
    
    87
    --- of another block.
    
    81
    +-- The downside is that any duplicates of the entry block stay unmerged. This
    
    82
    +-- should be very rare though, and only affects hand-written Cmm: the entry
    
    83
    +-- block of any proc generated from STG contains the stack check (see
    
    84
    +-- entryHeapCheck in GHC.StgToCmm.Heap) and is therefore distinct from any
    
    85
    +-- other block in the same proc.
    
    88 86
     
    
    89 87
     -- Invariant: The blocks in the list are pairwise distinct
    
    90 88
     -- (so avoid comparing them again)
    

  • testsuite/tests/cmm/should_run/T27722.hs
    1
    +import Control.Monad
    
    2
    +import Foreign.Ptr
    
    3
    +import System.Exit
    
    4
    +
    
    5
    +foreign import ccall "&zork_info" zork_info :: Ptr ()
    
    6
    +
    
    7
    +main :: IO ()
    
    8
    +main = when (zork_info == nullPtr) exitFailure

  • testsuite/tests/cmm/should_run/T27722_cmm.cmm
    1
    +#include "Cmm.h"
    
    2
    +
    
    3
    +// Regression test for #27722: common block elimination (CBE) must not
    
    4
    +// eliminate the entry block, because the proc's info table refers to it.
    
    5
    +// With the bug, zork_info is never emitted and T27722.hs fails to link.
    
    6
    +//
    
    7
    +// The entry block only becomes a duplicate in the third round of CBE:
    
    8
    +// round 1 merges the two then-blocks (both duplicates of the entry
    
    9
    +// block), round 2 merges E1 and E2, and only then does the entry block
    
    10
    +// match the surviving then-block.
    
    11
    +//
    
    12
    +// The then-blocks are braced if-bodies so that, like the entry block,
    
    13
    +// they carry two source notes (braces and statement): CBE's block hash
    
    14
    +// counts tick nodes (#27877), and blocks with different hashes are never
    
    15
    +// compared.
    
    16
    +INFO_TABLE_RET (zork, RET_SMALL)
    
    17
    +    return ()
    
    18
    +{
    
    19
    +  bits64 x;
    
    20
    +  x = 1 :: bits64;
    
    21
    +  goto E1;
    
    22
    +E1:
    
    23
    +  if (x > 0 :: bits64) { x = 1 :: bits64; goto E2; } else { goto D; }
    
    24
    +E2:
    
    25
    +  if (x > 0 :: bits64) { x = 1 :: bits64; goto E2; } else { goto D; }
    
    26
    +D:
    
    27
    +  if (x > 1 :: bits64) goto E1;
    
    28
    +  goto E2;
    
    29
    +}

  • testsuite/tests/cmm/should_run/all.T
    ... ... @@ -60,3 +60,6 @@ test('T27447',
    60 60
          ],
    
    61 61
          multi_compile_and_run,
    
    62 62
          ['T27447', [('T27447_cmm.cmm', '')], ''])
    
    63
    +
    
    64
    +test('T27722', [req_cmm], multi_compile_and_run,
    
    65
    +     ['T27722', [('T27722_cmm.cmm', '')], '-O'])