Simon Jakobi pushed to branch wip/sjakobi/udfm-placement at Glasgow Haskell Compiler / GHC

Commits:

1 changed file:

Changes:

  • compiler/GHC/Types/Unique/DFM.hs
    ... ... @@ -74,6 +74,7 @@ import GHC.Prelude
    74 74
     
    
    75 75
     import GHC.Types.Unique ( Uniquable(..), Unique, getKey, mkUniqueGrimily )
    
    76 76
     import GHC.Utils.Outputable
    
    77
    +import GHC.Utils.Panic (panic)
    
    77 78
     
    
    78 79
     import qualified GHC.Data.Word64Map.Strict as MS
    
    79 80
     import qualified GHC.Data.Word64Map as M
    
    ... ... @@ -135,19 +136,24 @@ import qualified GHC.Data.Word64Set as W
    135 136
     
    
    136 137
     -- | A type of values carrying an insertion tag
    
    137 138
     data TaggedVal val =
    
    138
    -  TaggedVal
    
    139
    -    !val
    
    140
    -    {-# UNPACK #-} !Int -- ^ insertion tag
    
    139
    +    TaggedVal
    
    140
    +      !val
    
    141
    +      {-# UNPACK #-} !Int -- ^ insertion tag
    
    142
    +  | TaggedHole            -- ^ placement-sort gap sentinel; never stored in a map.
    
    143
    +                          --   See Note [Sorting a UDFM].
    
    141 144
       deriving stock (Data, Functor, Foldable, Traversable)
    
    142 145
     
    
    143 146
     taggedFst :: TaggedVal val -> val
    
    144 147
     taggedFst (TaggedVal v _) = v
    
    148
    +taggedFst TaggedHole      = panic "taggedFst: TaggedHole"
    
    145 149
     
    
    146 150
     taggedSnd :: TaggedVal val -> Int
    
    147 151
     taggedSnd (TaggedVal _ i) = i
    
    152
    +taggedSnd TaggedHole      = panic "taggedSnd: TaggedHole"
    
    148 153
     
    
    149 154
     instance Eq val => Eq (TaggedVal val) where
    
    150 155
       (TaggedVal v1 _) == (TaggedVal v2 _) = v1 == v2
    
    156
    +  _                == _                = panic "TaggedVal (==): TaggedHole"
    
    151 157
     
    
    152 158
     -- | Type of unique deterministic finite maps
    
    153 159
     --
    
    ... ... @@ -207,7 +213,7 @@ addToUDFM_Directly :: UniqDFM key elt -> Unique -> elt -> UniqDFM key elt
    207 213
     addToUDFM_Directly (UDFM m i) u v
    
    208 214
       = UDFM (MS.insertWith tf (getKey u) (TaggedVal v i) m) (i + 1)
    
    209 215
       where
    
    210
    -    tf (TaggedVal new_v _) (TaggedVal _ old_i) = TaggedVal new_v old_i
    
    216
    +    tf new old = TaggedVal (taggedFst new) (taggedSnd old)
    
    211 217
           -- Keep the old tag, but insert the new value
    
    212 218
           -- This means that udfmToList typically returns elements
    
    213 219
           -- in the order of insertion, rather than the reverse
    
    ... ... @@ -224,8 +230,8 @@ addToUDFM_C_Directly
    224 230
     addToUDFM_C_Directly f (UDFM m i) u v
    
    225 231
       = UDFM (MS.insertWith tf (getKey u) (TaggedVal v i) m) (i + 1)
    
    226 232
         where
    
    227
    -      tf (TaggedVal new_v _) (TaggedVal old_v old_i)
    
    228
    -         = TaggedVal (f old_v new_v) old_i
    
    233
    +      tf new old
    
    234
    +         = TaggedVal (f (taggedFst old) (taggedFst new)) (taggedSnd old)
    
    229 235
               -- Flip the arguments, because M.insertWith uses  (new->old->result)
    
    230 236
               --                         but f            needs (old->new->result)
    
    231 237
               -- Like addToUDFM_Directly, keep the old tag
    
    ... ... @@ -378,7 +384,7 @@ foldWithKeyUDFM k z m = foldr (uncurry k) z (udfmToList m)
    378 384
     nonDetStrictFoldUDFM :: (elt -> a -> a) -> a -> UniqDFM key elt -> a
    
    379 385
     nonDetStrictFoldUDFM k z (UDFM m _i) = foldl' k' z m
    
    380 386
       where
    
    381
    -    k' acc (TaggedVal v _) = k v acc
    
    387
    +    k' acc tv = k (taggedFst tv) acc
    
    382 388
     
    
    383 389
     {- Note [Cost of deterministic iteration]
    
    384 390
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -440,22 +446,13 @@ folding the sorted elements with no intermediate list. foldUDFM is INLINE and
    440 446
     dispatches through the out-of-line fold_elts_nonempty, where the fusion happens
    
    441 447
     once -- so the fold is list-free without inlining the sort into every consumer.
    
    442 448
     
    
    443
    -Holes: slots whose tag never occurs keep the initial sentinel, a TaggedVal
    
    444
    -with tag -1. Real tags are non-negative, so the readout skips on tag < 0 and
    
    445
    -never reads the sentinel's value field. But that field is strict, so the
    
    446
    -sentinel still needs a value in WHNF: a panic thunk is out (it would be forced
    
    447
    --- and crash -- the moment the readout inspects a hole's tag). We use
    
    448
    -@unsafeCoerce ()@: () is a static, already-evaluated nullary constructor, so
    
    449
    -the sentinel is one shared top-level value -- no per-call allocation, and it
    
    450
    -retains nothing.
    
    451
    -
    
    452
    -The unsafeCoerce is safe here because r is always a lifted, boxed (pointer)
    
    453
    -type -- it comes from the map's elements -- so a pointer to () has the right
    
    454
    -representation. The GC only ever traces that pointer (() is a valid closure);
    
    455
    -the value is never evaluated or used as an r, since the readout takes values
    
    456
    -only from filled slots. Borrowing a real element instead would also type-check
    
    457
    -but costs a per-call thunk that retains the whole source map until the holes
    
    458
    -are read.
    
    449
    +Holes: slots whose tag never occurs keep the initial sentinel, the nullary
    
    450
    +constructor TaggedHole. The readout distinguishes it from a real TaggedVal by
    
    451
    +constructor, so it never touches a filled element's value in a hole slot.
    
    452
    +TaggedHole is static (a nullary constructor is a single shared closure), so
    
    453
    +newSmallArray fills every slot with the same pointer -- no per-call allocation,
    
    454
    +nothing retained. TaggedHole must never be stored in a map; the accessors
    
    455
    +(taggedFst, taggedSnd) panic on it to catch any invariant violation.
    
    459 456
     
    
    460 457
     This sorting method loses when ub is much larger than n = M.size m: ub never
    
    461 458
     shrinks (overwrites keep bumping it, delete/filter shrink n but not ub). We
    
    ... ... @@ -487,10 +484,10 @@ placementSort :: forall e r. Int
    487 484
                                   -- consuming fold. See Note [Sorting a UDFM].
    
    488 485
     placementSort ub mk m = build gen
    
    489 486
       where
    
    490
    -    -- The tag -1 marks unfilled slots; the value field is never read, but it
    
    491
    -    -- is strict, so it needs a WHNF value of type r. See Note [Sorting a UDFM].
    
    487
    +    -- Unfilled slots hold the TaggedHole sentinel; the readout skips it.
    
    488
    +    -- See Note [Sorting a UDFM].
    
    492 489
         hole :: TaggedVal r
    
    493
    -    hole = TaggedVal (unsafeCoerce ()) (-1)
    
    490
    +    hole = TaggedHole
    
    494 491
     
    
    495 492
         fill :: SmallMutableArray s (TaggedVal r) -> State# s -> (# State# s, () #)
    
    496 493
         fill marr s = case M.traverseWithKey_ write m of ST st -> st s
    
    ... ... @@ -511,17 +508,17 @@ placementSort ub mk m = build gen
    511 508
             readout :: SmallArray (TaggedVal r) -> Int -> b
    
    512 509
             readout arr j
    
    513 510
               | j >= ub   = nil
    
    514
    -          | t < 0     = readout arr (j + 1)
    
    515
    -          | otherwise = cons v (readout arr (j + 1))
    
    516
    -          where TaggedVal v t = indexSmallArray arr j
    
    511
    +          | otherwise = case indexSmallArray arr j of
    
    512
    +              TaggedHole    -> readout arr (j + 1)
    
    513
    +              TaggedVal v _ -> cons v (readout arr (j + 1))
    
    517 514
     
    
    518 515
     filterUDFM :: (elt -> Bool) -> UniqDFM key elt -> UniqDFM key elt
    
    519
    -filterUDFM p (UDFM m i) = UDFM (M.filter (\(TaggedVal v _) -> p v) m) i
    
    516
    +filterUDFM p (UDFM m i) = UDFM (M.filter (p . taggedFst) m) i
    
    520 517
     
    
    521 518
     filterUDFM_Directly :: (Unique -> elt -> Bool) -> UniqDFM key elt -> UniqDFM key elt
    
    522 519
     filterUDFM_Directly p (UDFM m i) = UDFM (M.filterWithKey p' m) i
    
    523 520
       where
    
    524
    -  p' k (TaggedVal v _) = p (mkUniqueGrimily k) v
    
    521
    +  p' k tv = p (mkUniqueGrimily k) (taggedFst tv)
    
    525 522
     
    
    526 523
     udfmRestrictKeys :: UniqDFM key elt -> UniqDFM key elt2 -> UniqDFM key elt
    
    527 524
     udfmRestrictKeys (UDFM a i) (UDFM b _) = UDFM (M.restrictKeys a (M.keysSet b)) i
    
    ... ... @@ -645,7 +642,7 @@ alterUDFM f (UDFM m i) k =
    645 642
       UDFM (M.alter alterf (getKey $ getUnique k) m) (i + 1)
    
    646 643
       where
    
    647 644
       alterf Nothing = inject $ f Nothing
    
    648
    -  alterf (Just (TaggedVal v _)) = inject $ f (Just v)
    
    645
    +  alterf (Just tv) = inject $ f (Just (taggedFst tv))
    
    649 646
       inject Nothing = Nothing
    
    650 647
       inject (Just v) = Just $ TaggedVal v i
    
    651 648
     
    
    ... ... @@ -664,7 +661,7 @@ upsertUDFM f (UDFM m i) k =
    664 661
       UDFM (MS.upsert upsertf (getKey $ getUnique k) m) (i + 1)
    
    665 662
       where
    
    666 663
         upsertf Nothing = TaggedVal (f Nothing) i
    
    667
    -    upsertf (Just (TaggedVal v _)) = TaggedVal (f (Just v)) i
    
    664
    +    upsertf (Just tv) = TaggedVal (f (Just (taggedFst tv))) i
    
    668 665
     
    
    669 666
     -- | The expression (@'alterUDFM_L' f map k@) alters value @x@ at @k@, or absence
    
    670 667
     -- thereof and returns the new element at @k@ if there is any.
    
    ... ... @@ -687,7 +684,7 @@ alterUDFM_L f (UDFM m i) k =
    687 684
       where
    
    688 685
       alterf :: Maybe (TaggedVal elt) -> (Maybe (TaggedVal elt))
    
    689 686
       alterf Nothing = inject $ f Nothing
    
    690
    -  alterf (Just (TaggedVal v _)) = inject $ f (Just v)
    
    687
    +  alterf (Just tv) = inject $ f (Just (taggedFst tv))
    
    691 688
       inject Nothing = Nothing
    
    692 689
       inject (Just v) = Just $ TaggedVal v i
    
    693 690