Simon Jakobi pushed to branch wip/sjakobi/cbe2 at Glasgow Haskell Compiler / GHC

Commits:

2 changed files:

Changes:

  • compiler/GHC/Cmm/CommonBlockElim.hs
    ... ... @@ -71,7 +71,11 @@ elimCommonBlocksWith :: (Label -> Label -> Bool) -> CmmGraph -> CmmGraph
    71 71
     elimCommonBlocksWith ok_to_merge g =
    
    72 72
         replaceLabels env $ copyTicks env g
    
    73 73
       where
    
    74
    -     env = iterate ok_to_merge mapEmpty blocks_with_key
    
    74
    +     -- The entry block must never be eliminated: its label is the
    
    75
    +     -- procedure's externally visible symbol.  (It may still absorb
    
    76
    +     -- duplicates as the surviving block.)
    
    77
    +     ok_to_merge' l1 l2 = l1 /= g_entry g && ok_to_merge l1 l2
    
    78
    +     env = iterate ok_to_merge' mapEmpty blocks_with_key
    
    75 79
          -- The order of blocks doesn't matter here. While we could use
    
    76 80
          -- revPostorder which drops unreachable blocks this is done in
    
    77 81
          -- ContFlowOpt already which runs before this pass. So we use
    

  • compiler/GHC/Cmm/Pipeline.hs
    ... ... @@ -33,6 +33,15 @@ import GHC.Platform
    33 33
     import Control.Monad
    
    34 34
     import GHC.Utils.Monad (mapAccumLM)
    
    35 35
     
    
    36
    +import System.Environment (lookupEnv)
    
    37
    +import System.IO.Unsafe (unsafePerformIO)
    
    38
    +
    
    39
    +-- TEMPORARY measurement hack, not for committing: GHC_CBE2=0 disables the
    
    40
    +-- second CBE pass, giving a same-binary A/B for size/perf comparisons.
    
    41
    +{-# NOINLINE cbe2Enabled #-}
    
    42
    +cbe2Enabled :: Bool
    
    43
    +cbe2Enabled = unsafePerformIO (lookupEnv "GHC_CBE2") /= Just "0"
    
    44
    +
    
    36 45
     -----------------------------------------------------------------------------
    
    37 46
     -- | Top level driver for C-- pipeline
    
    38 47
     -----------------------------------------------------------------------------
    
    ... ... @@ -144,7 +153,7 @@ cpsTop logger platform cfg dus proc =
    144 153
           ----------- Second common-block elimination ------------------------------
    
    145 154
           -- See Note [Second pass of CBE]
    
    146 155
           (g, call_pps) <-
    
    147
    -        if cmmOptElimCommonBlks cfg && cmmOptSink cfg && not splitting_proc_points
    
    156
    +        if cbe2Enabled && cmmOptElimCommonBlks cfg && cmmOptSink cfg && not splitting_proc_points
    
    148 157
               then do
    
    149 158
                 let stackmap_key lbl = stackMapLivenessKey platform
    
    150 159
                                          <$> mapLookup lbl stackmaps
    
    ... ... @@ -366,6 +375,12 @@ Wrinkles:
    366 375
     * Merging can drop return-point labels, so the call proc-point set is
    
    367 376
       recomputed before CAF analysis and attachContInfoTables.
    
    368 377
     
    
    378
    +* The graph's entry block must never be the eliminated side of a merge: its
    
    379
    +  label is the procedure's externally visible symbol.  Post-layout blocks are
    
    380
    +  bare enough that this genuinely happens (observed on nofib's real/veritas,
    
    381
    +  producing undefined symbol references at link time).
    
    382
    +  elimCommonBlocksWith enforces this for every CBE run.
    
    383
    +
    
    369 384
     * We don't run the pass when splitting proc points (unregisterised or
    
    370 385
       non-TNTC backends): merging blocks reachable from different proc points
    
    371 386
       breaks splitAtProcPoints' invariant that each block is reachable from