Simon Jakobi pushed to branch wip/sjakobi/T27619-liveness-fixpoint-formats at Glasgow Haskell Compiler / GHC

Commits:

4 changed files:

Changes:

  • compiler/GHC/CmmToAsm/Format.hs
    ... ... @@ -23,6 +23,7 @@ module GHC.CmmToAsm.Format (
    23 23
         vecFormat,
    
    24 24
         isVecFormat,
    
    25 25
         cmmTypeFormat,
    
    26
    +    compareFormat,
    
    26 27
         formatToWidth,
    
    27 28
         scalarWidth,
    
    28 29
         formatInBytes,
    
    ... ... @@ -40,11 +41,13 @@ where
    40 41
     
    
    41 42
     import GHC.Prelude
    
    42 43
     
    
    44
    +import Data.Semigroup ( (<>) )
    
    45
    +
    
    43 46
     import GHC.Cmm
    
    44 47
     import GHC.Platform.Reg ( Reg(..), RealReg, VirtualReg )
    
    45 48
     import GHC.Types.Unique ( Uniquable(..) )
    
    46 49
     import GHC.Types.Unique.Set
    
    47
    -import GHC.Utils.Outputable
    
    50
    +import GHC.Utils.Outputable hiding ( (<>) )
    
    48 51
     import GHC.Utils.Panic
    
    49 52
     
    
    50 53
     {- Note [GHC's data format representations]
    
    ... ... @@ -92,7 +95,8 @@ data Format
    92 95
             | FF64
    
    93 96
             | VecFormat !Length       -- ^ number of elements (always at least 2)
    
    94 97
                         !ScalarFormat -- ^ format of each element
    
    95
    -        deriving (Show, Eq, Ord)
    
    98
    +        deriving (Show, Eq)
    
    99
    +        -- No Ord: see Note [Format order is width-major]
    
    96 100
     
    
    97 101
     pattern IntegerFormat :: Format
    
    98 102
     pattern IntegerFormat <- ( isIntegerFormat -> True )
    
    ... ... @@ -117,7 +121,7 @@ data ScalarFormat
    117 121
       | FmtInt64
    
    118 122
       | FmtFloat
    
    119 123
       | FmtDouble
    
    120
    -  deriving (Show, Eq, Ord)
    
    124
    +  deriving (Show, Eq)
    
    121 125
     
    
    122 126
     scalarFormatFormat :: ScalarFormat -> Format
    
    123 127
     scalarFormatFormat = \case
    
    ... ... @@ -248,6 +252,50 @@ scalarWidth = \case
    248 252
     formatInBytes :: Format -> Int
    
    249 253
     formatInBytes = widthInBytes . formatToWidth
    
    250 254
     
    
    255
    +{- Note [Format order is width-major]
    
    256
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    257
    +'Format' has no 'Ord' instance: the only meaningful order on formats is by
    
    258
    +width, and code that needs "at least as wide" should say so by comparing
    
    259
    +'formatToWidth' results.
    
    260
    +
    
    261
    +'compareFormat' exists for one caller: 'maxRegWithFormat' in
    
    262
    +GHC.CmmToAsm.Reg.Regs, which joins the formats recorded for a register during
    
    263
    +liveness analysis. That join must be a max in a *total* order. Width alone is
    
    264
    +not total: distinct formats can share a width, e.g. VecFormat 2 FmtDouble and
    
    265
    +VecFormat 4 FmtFloat. If the join broke such ties by argument order, two
    
    266
    +blocks in a loop could swap same-width formats on every iteration of the
    
    267
    +liveness fixpoint, and the fixpoint would never converge. See
    
    268
    +Note [Convergence of the liveness fixpoint] in GHC.CmmToAsm.Reg.Liveness.
    
    269
    +So 'compareFormat' refines width order with an arbitrary but fixed tiebreak.
    
    270
    +-}
    
    271
    +
    
    272
    +-- | Total order on formats: by width, with an arbitrary but fixed tiebreak
    
    273
    +-- between distinct formats of the same width.
    
    274
    +--
    
    275
    +-- See Note [Format order is width-major].
    
    276
    +compareFormat :: Format -> Format -> Ordering
    
    277
    +compareFormat f1 f2 =
    
    278
    +    compare (formatToWidth f1) (formatToWidth f2) <> compare (tag f1) (tag f2)
    
    279
    +  where
    
    280
    +    tag :: Format -> (Int, Length)
    
    281
    +    tag = \case
    
    282
    +      II8           -> (0, 0)
    
    283
    +      II16          -> (1, 0)
    
    284
    +      II32          -> (2, 0)
    
    285
    +      II64          -> (3, 0)
    
    286
    +      FF32          -> (4, 0)
    
    287
    +      FF64          -> (5, 0)
    
    288
    +      VecFormat l s -> (6 + scalarTag s, l)
    
    289
    +
    
    290
    +    scalarTag :: ScalarFormat -> Int
    
    291
    +    scalarTag = \case
    
    292
    +      FmtInt8   -> 0
    
    293
    +      FmtInt16  -> 1
    
    294
    +      FmtInt32  -> 2
    
    295
    +      FmtInt64  -> 3
    
    296
    +      FmtFloat  -> 4
    
    297
    +      FmtDouble -> 5
    
    298
    +
    
    251 299
     --------------------------------------------------------------------------------
    
    252 300
     
    
    253 301
     -- | A typed virtual register: a virtual register, together with the specific
    

  • compiler/GHC/CmmToAsm/PPC/CodeGen.hs
    ... ... @@ -484,7 +484,7 @@ getRegister' _ _ (CmmMachOp (MO_SS_Conv src tgt) [CmmLoad mem pk _])
    484 484
       , src < tgt = do
    
    485 485
           let format = cmmTypeFormat pk
    
    486 486
           -- lwa is DS-form. See Note [Power instruction format]
    
    487
    -      let form = if format >= II32 then DS else D
    
    487
    +      let form = if formatToWidth format >= W32 then DS else D
    
    488 488
           Amode addr addr_code <- getAmode form mem
    
    489 489
           let code dst = assert (format == intFormat src)
    
    490 490
                          $ addr_code `snocOL` LA format dst addr
    

  • compiler/GHC/CmmToAsm/Reg/Liveness.hs
    ... ... @@ -939,7 +939,8 @@ test:
    939 939
     
    
    940 940
     The fixpoint terminates because the entries can only grow: registers are
    
    941 941
     only added, formats only increase via 'maxRegWithFormat' joins, and both
    
    942
    -lattices are finite.
    
    942
    +lattices are finite. This needs the join to be a max in a total order on
    
    943
    +formats. See Note [Format order is width-major] in GHC.CmmToAsm.Format.
    
    943 944
     -}
    
    944 945
     
    
    945 946
     
    

  • compiler/GHC/CmmToAsm/Reg/Regs.hs
    ... ... @@ -20,7 +20,8 @@ module GHC.CmmToAsm.Reg.Regs (
    20 20
     import GHC.Prelude
    
    21 21
     
    
    22 22
     import GHC.Platform.Reg     ( Reg )
    
    23
    -import GHC.CmmToAsm.Format  ( Format, RegWithFormat(..), isVecFormat )
    
    23
    +import GHC.CmmToAsm.Format  ( Format, RegWithFormat(..), isVecFormat,
    
    24
    +                              compareFormat, formatToWidth )
    
    24 25
     
    
    25 26
     import GHC.Utils.Outputable ( Outputable )
    
    26 27
     import GHC.Types.Unique     ( Uniquable(..) )
    
    ... ... @@ -39,11 +40,13 @@ newtype Regs = Regs { getRegs :: UniqSet RegWithFormat }
    39 40
     
    
    40 41
     maxRegWithFormat :: RegWithFormat -> RegWithFormat -> RegWithFormat
    
    41 42
     maxRegWithFormat r1@(RegWithFormat _ fmt1) r2@(RegWithFormat _ fmt2)
    
    42
    -  = if fmt1 >= fmt2
    
    43
    -    then r1
    
    44
    -    else r2
    
    45
    -  -- Re-using one of the arguments avoids allocating a new 'RegWithFormat',
    
    46
    -  -- compared with returning 'RegWithFormat r1 (max fmt1 fmt2)'.
    
    43
    +  | LT <- compareFormat fmt1 fmt2 = r2
    
    44
    +  | otherwise                     = r1
    
    45
    +  -- The join must be a max in a total order ('compareFormat', not a width
    
    46
    +  -- comparison), or the liveness fixpoint may not converge.
    
    47
    +  -- See Note [Format order is width-major] in GHC.CmmToAsm.Format.
    
    48
    +  --
    
    49
    +  -- Re-using one of the arguments avoids allocating a new 'RegWithFormat'.
    
    47 50
     
    
    48 51
     noRegs :: Regs
    
    49 52
     noRegs = Regs emptyUniqSet
    
    ... ... @@ -66,7 +69,7 @@ minusCoveredRegs = coerce $ minusUniqSet_C f
    66 69
       where
    
    67 70
         f :: RegWithFormat -> RegWithFormat -> Maybe RegWithFormat
    
    68 71
         f r1@(RegWithFormat _ fmt1) (RegWithFormat _ fmt2) =
    
    69
    -      if fmt2 >= fmt1
    
    72
    +      if formatToWidth fmt2 >= formatToWidth fmt1
    
    70 73
                ||
    
    71 74
              not ( isVecFormat fmt1 )
    
    72 75
               -- See Wrinkle [Don't allow scalar partial writes]
    
    ... ... @@ -99,7 +102,7 @@ shrinkingRegs = coerce $ minusUniqSet_C f
    99 102
       where
    
    100 103
         f :: RegWithFormat -> RegWithFormat -> Maybe RegWithFormat
    
    101 104
         f (RegWithFormat _ fmt1) r2@(RegWithFormat _ fmt2)
    
    102
    -      | fmt2 < fmt1
    
    105
    +      | formatToWidth fmt2 < formatToWidth fmt1
    
    103 106
           = Just r2
    
    104 107
           | otherwise
    
    105 108
           = Nothing