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

Commits:

11 changed files:

Changes:

  • compiler/GHC/CmmToAsm/CFG.hs
    ... ... @@ -885,17 +885,15 @@ loopInfo cfg root = LoopInfo { liBackEdges = backEdges
    885 885
           in  map (\n -> (n, loopCount n)) $ nodes :: [(BlockId, Int)]
    
    886 886
     
    
    887 887
         mkDomMap :: Tree BlockId -> LabelMap LabelSet
    
    888
    -    mkDomMap root = mapFromList $ go setEmpty root
    
    888
    +    -- The entry/root dominates every block and is deliberately excluded, so its
    
    889
    +    -- children start from the empty dominator set.
    
    890
    +    mkDomMap (Node _root children) = foldl' (go setEmpty) mapEmpty children
    
    889 891
           where
    
    890
    -        go :: LabelSet -> Tree BlockId -> [(Label,LabelSet)]
    
    891
    -        go parents (Node lbl [])
    
    892
    -          =  [(lbl, parents)]
    
    893
    -        go parents (Node _ leaves)
    
    894
    -          = let nodes = map rootLabel leaves
    
    895
    -                entries = map (\x -> (x,parents)) nodes
    
    896
    -            in  entries ++ concatMap
    
    897
    -                            (\n -> go (setInsert (rootLabel n) parents) n)
    
    898
    -                            leaves
    
    892
    +        -- `doms`: the dominators of `lbl`, i.e. its ancestors in the dominator
    
    893
    +        -- tree excluding the tree root.
    
    894
    +        go :: LabelSet -> LabelMap LabelSet -> Tree BlockId -> LabelMap LabelSet
    
    895
    +        go doms acc (Node lbl kids)
    
    896
    +          = foldl' (go (setInsert lbl doms)) (mapInsert lbl doms acc) kids
    
    899 897
     
    
    900 898
     -- We make the CFG a Hoopl Graph, so we can reuse revPostOrder.
    
    901 899
     newtype BlockNode (e :: Extensibility) (x :: Extensibility) = BN (BlockId,[BlockId])
    

  • compiler/GHC/CmmToAsm/Reg/Linear.hs
    ... ... @@ -367,7 +367,7 @@ initBlock id block_live
    367 367
                               Nothing ->
    
    368 368
                                 setFreeRegsR    (frInitFreeRegs platform)
    
    369 369
                               Just live ->
    
    370
    -                            setFreeRegsR $ foldl' (flip $ frAllocateReg platform) (frInitFreeRegs platform)
    
    370
    +                            setFreeRegsR $ foldl' (flip frAllocateReg) (frInitFreeRegs platform)
    
    371 371
                                                       (nonDetEltsUniqSet $ takeRealRegs $ getRegs live)
    
    372 372
                                 -- See Note [Unique Determinism and code generation]
    
    373 373
                             setAssigR       emptyRegMap
    
    ... ... @@ -638,20 +638,19 @@ genRaInsn block_live new_instrs block_id instr r_dying w_dying = do
    638 638
     
    
    639 639
     releaseRegs :: FR freeRegs => [Reg] -> RegM freeRegs ()
    
    640 640
     releaseRegs regs = do
    
    641
    -  platform <- getPlatform
    
    642 641
       assig <- getAssigR
    
    643 642
       free <- getFreeRegsR
    
    644 643
     
    
    645 644
       let loop assig !free [] = do setAssigR assig; setFreeRegsR free; return ()
    
    646
    -      loop assig !free (RegReal rr : rs) = loop assig (frReleaseReg platform rr free) rs
    
    645
    +      loop assig !free (RegReal rr : rs) = loop assig (frReleaseReg rr free) rs
    
    647 646
           loop assig !free (r:rs) =
    
    648 647
              case lookupUFM assig r of
    
    649 648
              Just (Loc (InBoth real _) _) ->
    
    650 649
                loop (delFromUFM assig r)
    
    651
    -                (frReleaseReg platform real free) rs
    
    650
    +                (frReleaseReg real free) rs
    
    652 651
              Just (Loc (InReg real) _) ->
    
    653 652
                loop (delFromUFM assig r)
    
    654
    -                (frReleaseReg platform real free) rs
    
    653
    +                (frReleaseReg real free) rs
    
    655 654
              _ ->
    
    656 655
                loop (delFromUFM assig r) free rs
    
    657 656
       loop assig free regs
    
    ... ... @@ -716,7 +715,7 @@ saveClobberedTemps clobbered dying
    716 715
     
    
    717 716
                 freeRegs <- getFreeRegsR
    
    718 717
                 let regclass = targetClassOfRealReg platform reg
    
    719
    -                freeRegs_thisClass = frGetFreeRegs platform regclass freeRegs
    
    718
    +                freeRegs_thisClass = frGetFreeRegs regclass freeRegs
    
    720 719
     
    
    721 720
                 case filter (`notElem` clobbered) freeRegs_thisClass of
    
    722 721
     
    
    ... ... @@ -724,7 +723,7 @@ saveClobberedTemps clobbered dying
    724 723
                   -- clobbered by this instruction; use it to save the
    
    725 724
                   -- clobbered value.
    
    726 725
                   (my_reg : _) -> do
    
    727
    -                  setFreeRegsR (frAllocateReg platform my_reg freeRegs)
    
    726
    +                  setFreeRegsR (frAllocateReg my_reg freeRegs)
    
    728 727
     
    
    729 728
                       let new_assign = addToUFM_Directly assig temp (Loc (InReg my_reg) fmt)
    
    730 729
                       let instr = mkRegRegMoveInstr config fmt
    
    ... ... @@ -763,13 +762,13 @@ clobberRegs clobbered
    763 762
                      Unified   ->   Unified.allRegClasses
    
    764 763
                      Separate  ->  Separate.allRegClasses
    
    765 764
                      NoVectors -> NoVectors.allRegClasses
    
    766
    -            allFreeRegs = foldMap (\ rc -> frGetFreeRegs platform rc freeregs) allRegClasses
    
    765
    +            allFreeRegs = foldMap (\ rc -> frGetFreeRegs rc freeregs) allRegClasses
    
    767 766
     
    
    768 767
             let extra_clobbered = [ r | r <- clobbered, r `elem` allFreeRegs ]
    
    769 768
     
    
    770
    -        setFreeRegsR $! foldl' (flip $ frAllocateReg platform) freeregs extra_clobbered
    
    769
    +        setFreeRegsR $! foldl' (flip frAllocateReg) freeregs extra_clobbered
    
    771 770
     
    
    772
    -        -- setFreeRegsR $! foldl' (flip $ frAllocateReg platform) freeregs clobbered
    
    771
    +        -- setFreeRegsR $! foldl' (flip frAllocateReg) freeregs clobbered
    
    773 772
     
    
    774 773
             assig           <- getAssigR
    
    775 774
             setAssigR $! clobber assig (nonDetUFMToList assig)
    
    ... ... @@ -896,7 +895,7 @@ allocRegsAndSpill_spill reading keep spills alloc r@(VirtualRegWithFormat vr vrF
    896 895
      = do   platform <- getPlatform
    
    897 896
             freeRegs <- getFreeRegsR
    
    898 897
             let regclass = classOfVirtualReg (platformArch platform) vr
    
    899
    -            freeRegs_thisClass = frGetFreeRegs platform regclass freeRegs :: [RealReg]
    
    898
    +            freeRegs_thisClass = frGetFreeRegs regclass freeRegs :: [RealReg]
    
    900 899
     
    
    901 900
             -- Can we put the variable into a register it already was?
    
    902 901
             pref_reg <- findPrefRealReg vr
    
    ... ... @@ -915,7 +914,7 @@ allocRegsAndSpill_spill reading keep spills alloc r@(VirtualRegWithFormat vr vrF
    915 914
     
    
    916 915
                     setAssigR $ toRegMap
    
    917 916
                               $ (addToUFM assig vr $! newLocation spill_loc $ RealRegUsage final_reg vrFmt)
    
    918
    -                setFreeRegsR $  frAllocateReg platform final_reg freeRegs
    
    917
    +                setFreeRegsR $  frAllocateReg final_reg freeRegs
    
    919 918
     
    
    920 919
                     allocateRegsAndSpill reading keep spills' (final_reg : alloc) rs
    
    921 920
     
    

  • compiler/GHC/CmmToAsm/Reg/Linear/FreeRegs.hs
    ... ... @@ -43,49 +43,51 @@ import qualified GHC.CmmToAsm.RV64.Instr as RV64.Instr
    43 43
     import qualified GHC.CmmToAsm.LA64.Instr    as LA64.Instr
    
    44 44
     
    
    45 45
     class Show freeRegs => FR freeRegs where
    
    46
    -    frAllocateReg :: Platform -> RealReg -> freeRegs -> freeRegs
    
    47
    -    frGetFreeRegs :: Platform -> RegClass -> freeRegs -> [RealReg]
    
    46
    +    frAllocateReg :: RealReg -> freeRegs -> freeRegs
    
    47
    +    frGetFreeRegs :: RegClass -> freeRegs -> [RealReg]
    
    48
    +    -- | The initial allocatable set is platform-dependent. See Note
    
    49
    +    -- [Aarch64 Register x18 at Darwin and Windows].
    
    48 50
         frInitFreeRegs :: Platform -> freeRegs
    
    49
    -    frReleaseReg :: Platform -> RealReg -> freeRegs -> freeRegs
    
    51
    +    frReleaseReg :: RealReg -> freeRegs -> freeRegs
    
    50 52
     
    
    51 53
     instance FR X86.FreeRegs where
    
    52
    -    frAllocateReg  = \_ -> X86.allocateReg
    
    54
    +    frAllocateReg  = X86.allocateReg
    
    53 55
         frGetFreeRegs  = X86.getFreeRegs
    
    54 56
         frInitFreeRegs = X86.initFreeRegs
    
    55
    -    frReleaseReg   = \_ -> X86.releaseReg
    
    57
    +    frReleaseReg   = X86.releaseReg
    
    56 58
     
    
    57 59
     instance FR X86_64.FreeRegs where
    
    58
    -    frAllocateReg  = \_ -> X86_64.allocateReg
    
    60
    +    frAllocateReg  = X86_64.allocateReg
    
    59 61
         frGetFreeRegs  = X86_64.getFreeRegs
    
    60 62
         frInitFreeRegs = X86_64.initFreeRegs
    
    61
    -    frReleaseReg   = \_ -> X86_64.releaseReg
    
    63
    +    frReleaseReg   = X86_64.releaseReg
    
    62 64
     
    
    63 65
     instance FR PPC.FreeRegs where
    
    64
    -    frAllocateReg  = \_ -> PPC.allocateReg
    
    65
    -    frGetFreeRegs  = \_ -> PPC.getFreeRegs
    
    66
    +    frAllocateReg  = PPC.allocateReg
    
    67
    +    frGetFreeRegs  = PPC.getFreeRegs
    
    66 68
         frInitFreeRegs = PPC.initFreeRegs
    
    67
    -    frReleaseReg   = \_ -> PPC.releaseReg
    
    69
    +    frReleaseReg   = PPC.releaseReg
    
    68 70
     
    
    69 71
     instance FR AArch64.FreeRegs where
    
    70
    -    frAllocateReg = \_ -> AArch64.allocateReg
    
    71
    -    frGetFreeRegs = \_ -> AArch64.getFreeRegs
    
    72
    +    frAllocateReg = AArch64.allocateReg
    
    73
    +    frGetFreeRegs = AArch64.getFreeRegs
    
    72 74
         frInitFreeRegs = AArch64.initFreeRegs
    
    73
    -    frReleaseReg = \_ -> AArch64.releaseReg
    
    75
    +    frReleaseReg = AArch64.releaseReg
    
    74 76
     
    
    75 77
     instance FR RV64.FreeRegs where
    
    76
    -    frAllocateReg = const RV64.allocateReg
    
    77
    -    frGetFreeRegs = const RV64.getFreeRegs
    
    78
    +    frAllocateReg = RV64.allocateReg
    
    79
    +    frGetFreeRegs = RV64.getFreeRegs
    
    78 80
         frInitFreeRegs = RV64.initFreeRegs
    
    79
    -    frReleaseReg = const RV64.releaseReg
    
    81
    +    frReleaseReg = RV64.releaseReg
    
    80 82
     
    
    81 83
     instance FR LA64.FreeRegs where
    
    82
    -    frAllocateReg = \_ -> LA64.allocateReg
    
    83
    -    frGetFreeRegs = \_ -> LA64.getFreeRegs
    
    84
    +    frAllocateReg = LA64.allocateReg
    
    85
    +    frGetFreeRegs = LA64.getFreeRegs
    
    84 86
         frInitFreeRegs = LA64.initFreeRegs
    
    85
    -    frReleaseReg = \_ -> LA64.releaseReg
    
    87
    +    frReleaseReg = LA64.releaseReg
    
    86 88
     
    
    87 89
     allFreeRegs :: FR freeRegs => Platform -> freeRegs -> [RealReg]
    
    88
    -allFreeRegs plat fr = foldMap (\rcls -> frGetFreeRegs plat rcls fr) allRegClasses
    
    90
    +allFreeRegs plat fr = foldMap (\rcls -> frGetFreeRegs rcls fr) allRegClasses
    
    89 91
       where
    
    90 92
         allRegClasses =
    
    91 93
           case registerArch (platformArch plat) of
    

  • compiler/GHC/CmmToAsm/Reg/Linear/JoinToTargets.hs
    ... ... @@ -15,7 +15,6 @@ import GHC.CmmToAsm.Reg.Linear.Base
    15 15
     import GHC.CmmToAsm.Reg.Linear.FreeRegs
    
    16 16
     import GHC.CmmToAsm.Reg.Liveness
    
    17 17
     import GHC.CmmToAsm.Instr
    
    18
    -import GHC.CmmToAsm.Config
    
    19 18
     import GHC.CmmToAsm.Types
    
    20 19
     
    
    21 20
     import GHC.Platform.Reg
    
    ... ... @@ -132,12 +131,9 @@ joinToTargets_first block_live new_blocks block_id instr dest dests
    132 131
             block_assig src_assig
    
    133 132
             to_free
    
    134 133
     
    
    135
    - = do   config <- getConfig
    
    136
    -        let platform = ncgPlatform config
    
    137
    -
    
    138
    -        -- free up the regs that are not live on entry to this block.
    
    134
    + = do   -- free up the regs that are not live on entry to this block.
    
    139 135
             freeregs        <- getFreeRegsR
    
    140
    -        let freeregs' = foldl' (flip $ frReleaseReg platform) freeregs to_free
    
    136
    +        let freeregs' = foldl' (flip frReleaseReg) freeregs to_free
    
    141 137
     
    
    142 138
             -- remember the current assignment on entry to this block.
    
    143 139
             setBlockAssigR (updateBlockAssignment dest (freeregs', src_assig) block_assig)
    

  • compiler/GHC/CmmToAsm/Reg/Linear/X86.hs
    ... ... @@ -25,17 +25,17 @@ initFreeRegs :: Platform -> FreeRegs
    25 25
     initFreeRegs platform
    
    26 26
             = foldl' (flip releaseReg) noFreeRegs (allocatableRegs platform)
    
    27 27
     
    
    28
    -getFreeRegs :: Platform -> RegClass -> FreeRegs -> [RealReg] -- lazily
    
    29
    -getFreeRegs platform cls (FreeRegs f) =
    
    28
    +getFreeRegs :: RegClass -> FreeRegs -> [RealReg] -- lazily
    
    29
    +getFreeRegs cls (FreeRegs f) =
    
    30 30
       case cls of
    
    31 31
         RcInteger ->
    
    32 32
           [ RealRegSingle i
    
    33
    -      | i <- intregnos platform
    
    33
    +      | i <- intregnos PW4
    
    34 34
           , testBit f i
    
    35 35
           ]
    
    36 36
         RcFloatOrVector ->
    
    37 37
           [ RealRegSingle i
    
    38
    -      | i <- xmmregnos platform
    
    38
    +      | i <- xmmregnos PW4
    
    39 39
           , testBit f i
    
    40 40
           ]
    
    41 41
     
    

  • compiler/GHC/CmmToAsm/Reg/Linear/X86_64.hs
    ... ... @@ -25,17 +25,17 @@ initFreeRegs :: Platform -> FreeRegs
    25 25
     initFreeRegs platform
    
    26 26
             = foldl' (flip releaseReg) noFreeRegs (allocatableRegs platform)
    
    27 27
     
    
    28
    -getFreeRegs :: Platform -> RegClass -> FreeRegs -> [RealReg] -- lazily
    
    29
    -getFreeRegs platform cls (FreeRegs f) =
    
    28
    +getFreeRegs :: RegClass -> FreeRegs -> [RealReg] -- lazily
    
    29
    +getFreeRegs cls (FreeRegs f) =
    
    30 30
       case cls of
    
    31 31
         RcInteger ->
    
    32 32
           [ RealRegSingle i
    
    33
    -      | i <- intregnos platform
    
    33
    +      | i <- intregnos PW8
    
    34 34
           , testBit f i
    
    35 35
           ]
    
    36 36
         RcFloatOrVector ->
    
    37 37
           [ RealRegSingle i
    
    38
    -      | i <- xmmregnos platform
    
    38
    +      | i <- xmmregnos PW8
    
    39 39
           , testBit f i
    
    40 40
           ]
    
    41 41
     
    

  • compiler/GHC/CmmToAsm/X86/RegInfo.hs
    ... ... @@ -41,9 +41,11 @@ regColors platform = listToUFM (normalRegColors platform)
    41 41
     
    
    42 42
     normalRegColors :: Platform -> [(RealReg,String)]
    
    43 43
     normalRegColors platform =
    
    44
    -    zip (map realRegSingle [0..lastint platform]) colors
    
    45
    -        ++ zip (map realRegSingle [firstxmm..lastxmm platform]) greys
    
    44
    +    zip (map realRegSingle [0..lastint wordSize]) colors
    
    45
    +        ++ zip (map realRegSingle [firstxmm..lastxmm wordSize]) greys
    
    46 46
       where
    
    47
    +    wordSize = platformWordSize platform
    
    48
    +
    
    47 49
         -- 16 colors - enough for amd64 gp regs
    
    48 50
         colors = ["#800000","#ff0000","#808000","#ffff00","#008000"
    
    49 51
                  ,"#00ff00","#008080","#00ffff","#000080","#0000ff"
    

  • compiler/GHC/CmmToAsm/X86/Regs.hs
    ... ... @@ -194,27 +194,23 @@ spRel platform n
    194 194
     firstxmm :: RegNo
    
    195 195
     firstxmm  = 16
    
    196 196
     
    
    197
    ---  on 32bit platformOSs, only the first 8 XMM/YMM/ZMM registers are available
    
    198
    -lastxmm :: Platform -> RegNo
    
    199
    -lastxmm platform
    
    200
    - | target32Bit platform = firstxmm + 7  -- xmm0 - xmmm7
    
    201
    - | otherwise            = firstxmm + 15 -- xmm0 -xmm15
    
    197
    +--  on 32bit platforms, only the first 8 XMM/YMM/ZMM registers are available
    
    198
    +lastxmm :: PlatformWordSize -> RegNo
    
    199
    +lastxmm PW4 = firstxmm + 7  -- xmm0 - xmm7
    
    200
    +lastxmm PW8 = firstxmm + 15 -- xmm0 - xmm15
    
    202 201
     
    
    203
    -lastint :: Platform -> RegNo
    
    204
    -lastint platform
    
    205
    - | target32Bit platform = 7 -- not %r8..%r15
    
    206
    - | otherwise            = 15
    
    202
    +lastint :: PlatformWordSize -> RegNo
    
    203
    +lastint PW4 = 7 -- not %r8..%r15
    
    204
    +lastint PW8 = 15
    
    207 205
     
    
    208
    -intregnos :: Platform -> [RegNo]
    
    209
    -intregnos platform = [0 .. lastint platform]
    
    206
    +intregnos :: PlatformWordSize -> [RegNo]
    
    207
    +intregnos wordSize = [0 .. lastint wordSize]
    
    210 208
     
    
    211
    -
    
    212
    -
    
    213
    -xmmregnos :: Platform -> [RegNo]
    
    214
    -xmmregnos platform = [firstxmm  .. lastxmm platform]
    
    209
    +xmmregnos :: PlatformWordSize -> [RegNo]
    
    210
    +xmmregnos wordSize = [firstxmm .. lastxmm wordSize]
    
    215 211
     
    
    216 212
     floatregnos :: Platform -> [RegNo]
    
    217
    -floatregnos platform = xmmregnos platform
    
    213
    +floatregnos platform = xmmregnos (platformWordSize platform)
    
    218 214
     
    
    219 215
     -- argRegs is the set of regs which are read for an n-argument call to C.
    
    220 216
     -- For archs which pass all args on the stack (x86), is empty.
    
    ... ... @@ -224,7 +220,7 @@ argRegs _ = panic "MachRegs.argRegs(x86): should not be used!"
    224 220
     
    
    225 221
     -- | The complete set of machine registers.
    
    226 222
     allMachRegNos :: Platform -> [RegNo]
    
    227
    -allMachRegNos platform = intregnos platform ++ floatregnos platform
    
    223
    +allMachRegNos platform = intregnos (platformWordSize platform) ++ floatregnos platform
    
    228 224
     
    
    229 225
     -- | Take the class of a register.
    
    230 226
     {-# INLINE classOfRealReg #-}
    
    ... ... @@ -236,9 +232,11 @@ classOfRealReg :: Platform -> RealReg -> RegClass
    236 232
     classOfRealReg platform reg
    
    237 233
         = case reg of
    
    238 234
             RealRegSingle i
    
    239
    -            | i <= lastint platform -> RcInteger
    
    240
    -            | i <= lastxmm platform -> RcFloatOrVector
    
    235
    +            | i <= lastint wordSize -> RcInteger
    
    236
    +            | i <= lastxmm wordSize -> RcFloatOrVector
    
    241 237
                 | otherwise             -> panic "X86.Reg.classOfRealReg registerSingle too high"
    
    238
    +  where
    
    239
    +    wordSize = platformWordSize platform
    
    242 240
     
    
    243 241
     -- machine specific ------------------------------------------------------------
    
    244 242
     
    

  • testsuite/driver/junit.py
    ... ... @@ -14,12 +14,13 @@ def junit(t: TestRun) -> ET.ElementTree:
    14 14
                                                  + len(t.unexpected_stat_failures)
    
    15 15
                                                  + len(t.unexpected_passes)),
    
    16 16
                                   errors = str(len(t.framework_failures)),
    
    17
    +                              skipped = str(len(t.fragile_failures)),
    
    17 18
                                   timestamp = datetime.now().isoformat())
    
    18 19
     
    
    19
    -    for res_type, group in [('stat failure', t.unexpected_stat_failures),
    
    20
    -                            ('unexpected failure', t.unexpected_failures),
    
    21
    -                            ('unexpected pass', t.unexpected_passes),
    
    22
    -                            ('fragile failure', t.fragile_failures)]:
    
    20
    +    for kind, res_type, group in [('failure', 'stat failure', t.unexpected_stat_failures),
    
    21
    +                                  ('failure', 'unexpected failure', t.unexpected_failures),
    
    22
    +                                  ('failure', 'unexpected pass', t.unexpected_passes),
    
    23
    +                                  ('skipped', 'fragile failure', t.fragile_failures)]:
    
    23 24
             for tr in group:
    
    24 25
                 testcase = ET.SubElement(testsuite, 'testcase',
    
    25 26
                                          classname = tr.way,
    
    ... ... @@ -30,7 +31,7 @@ def junit(t: TestRun) -> ET.ElementTree:
    30 31
                 if tr.stderr:
    
    31 32
                     message += ['', 'stderr:', '==========', tr.stderr]
    
    32 33
     
    
    33
    -            result = ET.SubElement(testcase, 'failure',
    
    34
    +            result = ET.SubElement(testcase, kind,
    
    34 35
                                        type = res_type,
    
    35 36
                                        message = tr.reason)
    
    36 37
                 result.text = '\n'.join(message)
    

  • testsuite/tests/perf/compiler/all.T
    ... ... @@ -857,3 +857,18 @@ test ('T26989',
    857 857
           multimod_compile,
    
    858 858
           ['T26989', '-v0 -O'])
    
    859 859
     
    
    860
    +# A single Cmm procedure with thousands of basic blocks (diamonds plus periodic
    
    861
    +# backedges), stressing the native code generator's CFG construction, edge-weight
    
    862
    +# estimation, register allocation and block layout. Works with all NCG backends
    
    863
    +# (X86, AArch64, WASM, etc.). See #27448.
    
    864
    +test('ManyBasicBlocks',
    
    865
    +     [ only_ways(['optasm']),
    
    866
    +       unless(have_ncg(), skip),
    
    867
    +       cmm_src,
    
    868
    +       collect_compiler_stats('bytes allocated', 2),
    
    869
    +       pre_cmd('./genManyBasicBlocks'),
    
    870
    +       extra_files(['genManyBasicBlocks']),
    
    871
    +     ],
    
    872
    +     compile,
    
    873
    +     ['-O -v0'])
    
    874
    +

  • testsuite/tests/perf/compiler/genManyBasicBlocks
    1
    +#!/usr/bin/env bash
    
    2
    +set -euo pipefail
    
    3
    +
    
    4
    +# Generate a Cmm source file that is intentionally heavy on control flow.
    
    5
    +#
    
    6
    +# The benchmark shape is one large procedure containing:
    
    7
    +#   - many split/left/right/join diamonds
    
    8
    +#   - periodic backedges that make each chunk a natural loop
    
    9
    +#
    
    10
    +# It produces thousands of actual basic blocks in a single Cmm graph (rather
    
    11
    +# than merely a very large source file), stressing the native code generator's
    
    12
    +# CFG construction, edge-weight estimation, register allocation and block
    
    13
    +# layout.
    
    14
    +#
    
    15
    +# Based on GitLab snippet #6044
    
    16
    +#
    
    17
    +# Tuning knobs:
    
    18
    +#   STAGES       Number of diamond stages to generate. Default: 2048
    
    19
    +#   LOOP_PERIOD  Number of stages per loop chunk. Default: 16
    
    20
    +#   LOOP_TRIPS   Runtime trip count for each chunk. Default: 2
    
    21
    +#   OUT          Output file. Default: ManyBasicBlocks.cmm
    
    22
    +
    
    23
    +: "${STAGES:=2048}"
    
    24
    +: "${LOOP_PERIOD:=16}"
    
    25
    +: "${LOOP_TRIPS:=2}"
    
    26
    +: "${OUT:=ManyBasicBlocks.cmm}"
    
    27
    +
    
    28
    +die() {
    
    29
    +  printf '%s\n' "$*" >&2
    
    30
    +  exit 1
    
    31
    +}
    
    32
    +
    
    33
    +check_nat() {
    
    34
    +  local value=$1
    
    35
    +  local name=$2
    
    36
    +
    
    37
    +  [[ $value =~ ^[0-9]+$ ]] || die "$name must be a non-negative integer"
    
    38
    +}
    
    39
    +
    
    40
    +check_nat "$STAGES" STAGES
    
    41
    +check_nat "$LOOP_PERIOD" LOOP_PERIOD
    
    42
    +check_nat "$LOOP_TRIPS" LOOP_TRIPS
    
    43
    +
    
    44
    +(( STAGES > 0 )) || die "STAGES must be greater than zero"
    
    45
    +(( LOOP_PERIOD > 0 )) || die "LOOP_PERIOD must be greater than zero"
    
    46
    +(( LOOP_TRIPS > 0 )) || die "LOOP_TRIPS must be greater than zero"
    
    47
    +
    
    48
    +chunk_count=$(( (STAGES + LOOP_PERIOD - 1) / LOOP_PERIOD ))
    
    49
    +block_count=$(( 1 + 4 * STAGES + chunk_count ))
    
    50
    +
    
    51
    +emit() {
    
    52
    +  printf '%s\n' "$*"
    
    53
    +}
    
    54
    +
    
    55
    +{
    
    56
    +  emit "// Generated by genManyBasicBlocks"
    
    57
    +  emit "//"
    
    58
    +  emit "// Parameters:"
    
    59
    +  emit "//   STAGES=${STAGES}"
    
    60
    +  emit "//   LOOP_PERIOD=${LOOP_PERIOD}"
    
    61
    +  emit "//   LOOP_TRIPS=${LOOP_TRIPS}"
    
    62
    +  emit "//"
    
    63
    +  emit "// Approximate block count: ${block_count}"
    
    64
    +  emit "#include \"Cmm.h\""
    
    65
    +  emit
    
    66
    +  emit "many_basic_blocks (W_ seed) {"
    
    67
    +  emit "  W_ acc;"
    
    68
    +  emit "  W_ mix;"
    
    69
    +  for ((chunk = 0; chunk < chunk_count; chunk++)); do
    
    70
    +    emit "  W_ trip${chunk};"
    
    71
    +  done
    
    72
    +  emit
    
    73
    +  emit "entry:"
    
    74
    +  emit "  acc = seed;"
    
    75
    +  emit "  mix = seed + (17 :: W_);"
    
    76
    +  for ((chunk = 0; chunk < chunk_count; chunk++)); do
    
    77
    +    emit "  trip${chunk} = 0;"
    
    78
    +  done
    
    79
    +  emit "  goto split0;"
    
    80
    +  emit
    
    81
    +
    
    82
    +  for ((stage = 0; stage < STAGES; stage++)); do
    
    83
    +    next_stage=$(( stage + 1 ))
    
    84
    +    chunk=$(( stage / LOOP_PERIOD ))
    
    85
    +    stage1=$(( 4 * stage + 1 ))
    
    86
    +    stage2=$(( 4 * stage + 2 ))
    
    87
    +    stage3=$(( 4 * stage + 3 ))
    
    88
    +    stage4=$(( 4 * stage + 4 ))
    
    89
    +
    
    90
    +    emit "split${stage}:"
    
    91
    +    emit "  mix = mix + (${stage1} :: W_);"
    
    92
    +    emit "  if (((mix + (${stage2} :: W_)) % (7 :: W_)) < (3 :: W_)) {"
    
    93
    +    emit "    goto left${stage};"
    
    94
    +    emit "  }"
    
    95
    +    emit "  goto right${stage};"
    
    96
    +    emit
    
    97
    +
    
    98
    +    emit "left${stage}:"
    
    99
    +    emit "  acc = acc + (${stage3} :: W_);"
    
    100
    +    emit "  mix = mix + (${stage4} :: W_);"
    
    101
    +    emit "  goto join${stage};"
    
    102
    +    emit
    
    103
    +
    
    104
    +    emit "right${stage}:"
    
    105
    +    emit "  acc = acc + (${stage4} :: W_);"
    
    106
    +    emit "  mix = mix + (${stage3} :: W_);"
    
    107
    +    emit "  goto join${stage};"
    
    108
    +    emit
    
    109
    +
    
    110
    +    emit "join${stage}:"
    
    111
    +    emit "  acc = acc + mix + (${stage1} :: W_);"
    
    112
    +    if (( next_stage == STAGES || next_stage % LOOP_PERIOD == 0 )); then
    
    113
    +      emit "  goto latch${chunk};"
    
    114
    +    else
    
    115
    +      emit "  goto split${next_stage};"
    
    116
    +    fi
    
    117
    +    emit
    
    118
    +  done
    
    119
    +
    
    120
    +  for ((chunk = 0; chunk < chunk_count; chunk++)); do
    
    121
    +    loop_start=$(( chunk * LOOP_PERIOD ))
    
    122
    +    next_stage=$(( (chunk + 1) * LOOP_PERIOD ))
    
    123
    +    latch_mix=$(( 1000000 + chunk ))
    
    124
    +    latch_acc=$(( 2000000 + chunk ))
    
    125
    +
    
    126
    +    emit "latch${chunk}:"
    
    127
    +    emit "  trip${chunk} = trip${chunk} + (1 :: W_);"
    
    128
    +    emit "  mix = mix + (${latch_mix} :: W_);"
    
    129
    +    emit "  acc = acc + (${latch_acc} :: W_);"
    
    130
    +    emit "  if (trip${chunk} < (${LOOP_TRIPS} :: W_)) {"
    
    131
    +    emit "    goto split${loop_start};"
    
    132
    +    emit "  }"
    
    133
    +    if (( next_stage < STAGES )); then
    
    134
    +      emit "  goto split${next_stage};"
    
    135
    +    else
    
    136
    +      emit "  return (acc);"
    
    137
    +    fi
    
    138
    +    emit
    
    139
    +  done
    
    140
    +
    
    141
    +  emit "}"
    
    142
    +} > "$OUT"