intsToReverseBitmap :: DynFlags
                    -> Int      -- ^ size in bits
                    -> [Int]    -- ^ sorted indices of zeros free of duplicates
                    -> Bitmap
intsToReverseBitmap dflags size = go 0
  where
    word_sz = wORD_SIZE_IN_BITS dflags
    oneAt :: Int -> StgWord
    oneAt i = toStgWord dflags 1 `shiftL` i

    -- It is important that we maintain strictness here.
    -- See Note [Strictness when building Bitmaps].
    go :: Int -> [Int] -> Bitmap
    go !pos slots
      | size <= pos = []
      | otherwise =
        (foldl' xor (toStgWord dflags init) (map (\i->oneAt (i - pos)) these)) :
          go (pos + word_sz) rest
      where
        (these,rest) = span (< (pos + word_sz)) slots
        remain = size - pos
        init
          | remain >= word_sz = -1
          | otherwise         = (1 `shiftL` remain) - 1

{-

Note [Strictness when building Bitmaps]
========================================

One of the places where @Bitmap@ is used is in in building Static Reference
Tables (SRTs) (in @GHC.Cmm.Info.Build.procpointSRT@). In #7450 it was noticed
that some test cases (particularly those whose C-- have large numbers of CAFs)
produced large quantities of allocations from this function.

The source traced back to 'intsToBitmap', which was lazily subtracting the word
size from the elements of the tail of the @slots@ list and recursively invoking
itself with the result. This resulted in large numbers of subtraction thunks
being built up. Here we take care to avoid passing new thunks to the recursive
call. Instead we pass the unmodified tail along with an explicit position
accumulator, which get subtracted in the fold when we compute the Word.

-}

{- |
Magic number, must agree with @BITMAP_BITS_SHIFT@ in InfoTables.h.
Some kinds of bitmap pack a size\/bitmap into a single word if
possible, or fall back to an external pointer when the bitmap is too
large.  This value represents the largest size of bitmap that can be
packed into a single word.
-}
intsToReverseBitmap :: DynFlags
                    -> Int      -- ^ size in bits
                    -> [Int]    -- ^ sorted indices of zeros free of duplicates
                    -> Bitmap
intsToReverseBitmap dflags size = go 0
  where
    word_sz = wORD_SIZE_IN_BITS dflags
    oneAt :: Int -> StgWord
    oneAt i = toStgWord dflags 1 `shiftL` i

    -- It is important that we maintain strictness here.
    -- See Note [Strictness when building Bitmaps].
    go :: Int -> [Int] -> Bitmap
    go !pos slots
      | size <= pos = []
      | otherwise =
        (foldl' xor (toStgWord dflags init) (map (\i->oneAt (i - pos)) these)) :
          go (pos + word_sz) rest
      where
        (these,rest) = span (< (pos + word_sz)) slots
        remain = size - pos
        init
          | remain >= word_sz = -1
          | otherwise         = (1 `shiftL` remain) - 1

{-

Note [Strictness when building Bitmaps]
========================================

One of the places where @Bitmap@ is used is in in building Static Reference
Tables (SRTs) (in @GHC.Cmm.Info.Build.procpointSRT@). In #7450 it was noticed
that some test cases (particularly those whose C-- have large numbers of CAFs)
produced large quantities of allocations from this function.

The source traced back to 'intsToBitmap', which was lazily subtracting the word
size from the elements of the tail of the @slots@ list and recursively invoking
itself with the result. This resulted in large numbers of subtraction thunks
being built up. Here we take care to avoid passing new thunks to the recursive
call. Instead we pass the unmodified tail along with an explicit position
accumulator, which get subtracted in the fold when we compute the Word.

-}

{- |
Magic number, must agree with @BITMAP_BITS_SHIFT@ in InfoTables.h.
Some kinds of bitmap pack a size\/bitmap into a single word if
possible, or fall back to an external pointer when the bitmap is too
large.  This value represents the largest size of bitmap that can be
packed into a single word.
-}
intsToReverseBitmap dflags size = go 0
  where
    word_sz = wORD_SIZE_IN_BITS dflags
    oneAt :: Int -> StgWord
    oneAt i = toStgWord dflags 1 `shiftL` i

    -- It is important that we maintain strictness here.
    -- See Note [Strictness when building Bitmaps].
    go :: Int -> [Int] -> Bitmap
    go !pos slots
      | size <= pos = []
      | otherwise =
        (foldl' xor (toStgWord dflags init) (map (\i->oneAt (i - pos)) these)) :
          go (pos + word_sz) rest
      where
        (these,rest) = span (< (pos + word_sz)) slots
        remain = size - pos
        init
          | remain >= word_sz = -1
          | otherwise         = (1 `shiftL` remain) - 1

{-

Note [Strictness when building Bitmaps]
========================================

One of the places where @Bitmap@ is used is in in building Static Reference
Tables (SRTs) (in @GHC.Cmm.Info.Build.procpointSRT@). In #7450 it was noticed
that some test cases (particularly those whose C-- have large numbers of CAFs)
produced large quantities of allocations from this function.

The source traced back to 'intsToBitmap', which was lazily subtracting the word
size from the elements of the tail of the @slots@ list and recursively invoking
itself with the result. This resulted in large numbers of subtraction thunks
being built up. Here we take care to avoid passing new thunks to the recursive
call. Instead we pass the unmodified tail along with an explicit position
accumulator, which get subtracted in the fold when we compute the Word.

-}

{- |
Magic number, must agree with @BITMAP_BITS_SHIFT@ in InfoTables.h.
Some kinds of bitmap pack a size\/bitmap into a single word if
possible, or fall back to an external pointer when the bitmap is too
large.  This value represents the largest size of bitmap that can be
packed into a single word.
-}