content: -- | In the context of this module, a "size" is any kind of tunable
  -- (run-time) constant.
  module Futhark.IR.GPU.Sizes
    ( SizeClass (..),
      sizeDefault,
      KernelPath,
      Count (..),
      NumBlocks,
      BlockSize,
      NumThreads,
    )
  where
  
  import Data.Int (Int64)
  import Data.Traversable
  import Futhark.IR.Prop.Names (FreeIn)
  import Futhark.Transform.Substitute
  import Futhark.Util.IntegralExp (IntegralExp)
  import Futhark.Util.Pretty
  import Language.Futhark.Core (Name)
  import Prelude hiding (id, (.))
  
  -- | An indication of which comparisons have been performed to get to
  -- this point, as well as the result of each comparison.
  type KernelPath = [(Name, Bool)]
  
  -- | The class of some kind of configurable size.  Each class may
  -- impose constraints on the valid values.
  data SizeClass
    = -- | A threshold with an optional default.
      SizeThreshold KernelPath (Maybe Int64)
    | SizeThreadBlock
    | -- | The number of thread blocks.
      SizeGrid
    | SizeTile
    | SizeRegTile
    | -- | Likely not useful on its own, but querying the
      -- maximum can be handy.
      SizeSharedMemory
    | -- | A bespoke size with a default.
      SizeBespoke Name Int64
    | -- | Amount of registers available per threadblock. Mostly
      -- meaningful for querying the maximum.
      SizeRegisters
    | -- | Amount of L2 cache memory, in bytes. Mostly meaningful for
      -- querying the maximum.
      SizeCache
    deriving (Eq, Ord, Show)
  
  instance Pretty SizeClass where
    pretty (SizeThreshold path def) =
      "threshold" <> parens (def' <> comma <+> hsep (map pStep path))
      where
        pStep (v, True) = pretty v
        pStep (v, False) = "!" <> pretty v
        def' = maybe "def" pretty def
    pretty SizeThreadBlock = "thread_block_size"
    pretty SizeGrid = "grid_size"
    pretty SizeTile = "tile_size"
    pretty SizeRegTile = "reg_tile_size"
    pretty SizeSharedMemory = "shared_memory"
    pretty (SizeBespoke k def) =
      "bespoke" <> parens (pretty k <> comma <+> pretty def)
    pretty SizeRegisters = "registers"
    pretty SizeCache = "cache"
  
  -- | The default value for the size.  If 'Nothing', that means the backend gets to decide.
  sizeDefault :: SizeClass -> Maybe Int64
  sizeDefault (SizeThreshold _ x) = x
  sizeDefault (SizeBespoke _ x) = Just x
  sizeDefault _ = Nothing
  
  -- | A wrapper supporting a phantom type for indicating what we are counting.
  newtype Count u e = Count {unCount :: e}
    deriving (Eq, Ord, Show, Num, IntegralExp, FreeIn, Pretty, Substitute)
  
  instance Functor (Count u) where
    fmap = fmapDefault
  
  instance Foldable (Count u) where
    foldMap = foldMapDefault
  
  instance Traversable (Count u) where
    traverse f (Count x) = Count <$> f x
  
  -- | Phantom type for the number of blocks of some kernel.
  data NumBlocks
  
  -- | Phantom type for the block size of some kernel.
  data BlockSize
  
  -- | Phantom type for number of threads.
  data NumThreads
  