packages feed

fir-0.1.0.0: src/SPIRV/Control.hs

{-# LANGUAGE AllowAmbiguousTypes   #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE DerivingStrategies    #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE PatternSynonyms       #-}
{-# LANGUAGE PolyKinds             #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeFamilies          #-}

{-|
Module: SPIRV.Control

This module enumerates SPIR-V control parameters:

  * selection control parameters (SPIR-V specification §3.22 __Selection Control__),
  * loop control parameters (SPIR-V specification §3.23 __Loop Control__),
  * function control parameters (SPIR-V specification §3.24 __Function Control__).

These are used both at the type-level and value-level.

-}

module SPIRV.Control
  ( Inlineability(..)
  , SideEffects(..)
  , FunctionControl
  , type NoFunctionControl, pattern NoFunctionControl
  , SelectionControl(..), pattern NoSelectionControl
  , LoopUnrolling(..)
  , LoopDependency(..)
  , LoopControl
  , type NoLoopControl, pattern NoLoopControl
  )
  where

-- base
import Data.Word
  ( Word32 )
import GHC.TypeLits
  ( Nat, KnownNat )

-- binary
import qualified Data.Binary.Put as Binary

-- fir
import Data.Binary.Class.Put
  ( Put(..) )
import Data.Type.Known
  ( Demotable(Demote), Known(known), knownValue )

------------------------------------------------------------------------------------------------
-- function control

data Inlineability = Inline | DontInline
  deriving stock ( Eq, Show )
data SideEffects = OnlyReads | NoSideEffects
  deriving stock ( Eq, Show )

type FunctionControl = ( Maybe Inlineability, Maybe SideEffects )

type NoFunctionControl = ( '( 'Nothing, 'Nothing ) :: FunctionControl )

pattern NoFunctionControl :: FunctionControl
pattern NoFunctionControl = ( Nothing, Nothing )

instance Put FunctionControl where
  wordCount _ = 1
  put ( i, s ) = put w
    where w :: Word32
          w = wi + ws
          wi = case i of
                  Nothing         -> 0
                  Just Inline     -> 1
                  Just DontInline -> 2
          ws = case s of
                  Nothing            -> 0
                  Just OnlyReads     -> 4
                  Just NoSideEffects -> 8

instance Demotable Inlineability where
  type Demote Inlineability = Inlineability
instance Known Inlineability 'Inline where
  known = Inline
instance Known Inlineability 'DontInline where
  known = DontInline

instance Demotable SideEffects where
  type Demote SideEffects = SideEffects
instance Known SideEffects 'OnlyReads where
  known = OnlyReads
instance Known SideEffects 'NoSideEffects where
  known = NoSideEffects


------------------------------------------------------------------------------------------------
-- selection control

data SelectionControl
  = Flatten
  | DontFlatten
  deriving stock ( Eq, Show )

pattern NoSelectionControl :: Maybe SelectionControl
pattern NoSelectionControl = Nothing

instance Put SelectionControl where
  wordCount _ = 1
  put Flatten     = put @Word32 1
  put DontFlatten = put @Word32 2

instance Put (Maybe SelectionControl) where
  wordCount _ = 1
  put Nothing            = put @Word32 0
  put (Just Flatten    ) = put @Word32 1
  put (Just DontFlatten) = put @Word32 2

instance Demotable SelectionControl where
  type Demote SelectionControl = SelectionControl
instance Known SelectionControl Flatten where
  known = Flatten
instance Known SelectionControl DontFlatten where
  known = DontFlatten

------------------------------------------------------------------------------------------------
-- loop control

data LoopUnrolling
  = Unroll
  | DontUnroll
  deriving stock ( Eq, Show )

data LoopDependency n
  = DependencyInfinite
  | DependencyLength n
  deriving stock ( Eq, Show )

type LoopControl n = ( Maybe LoopUnrolling, Maybe (LoopDependency n) )
type NoLoopControl = ( '( Nothing, Nothing ) :: LoopControl Nat )
pattern NoLoopControl :: LoopControl Word32
pattern NoLoopControl = ( Nothing, Nothing )

instance Demotable LoopUnrolling where
  type Demote LoopUnrolling = LoopUnrolling
instance Known LoopUnrolling Unroll where
  known = Unroll
instance Known LoopUnrolling DontUnroll where
  known = DontUnroll

instance Demotable (LoopDependency Nat) where
  type Demote (LoopDependency Nat) = LoopDependency Word32
instance Known (LoopDependency Nat) DependencyInfinite where
  known = DependencyInfinite
instance KnownNat l => Known (LoopDependency Nat) (DependencyLength l) where
  known = DependencyLength ( knownValue @l )


instance Put (LoopControl Word32) where
  wordCount (_, Just (DependencyLength _)) = 2
  wordCount _                              = 1
  put ( u, d ) = put w *> mbPutDependencyLength
    where w :: Word32
          w = wu + wd
          wu = case u of
                  Nothing         -> 0
                  Just Unroll     -> 1
                  Just DontUnroll -> 2
          wd = case d of
                  Nothing                   -> 0
                  Just DependencyInfinite   -> 4
                  Just (DependencyLength _) -> 8
          mbPutDependencyLength :: Binary.PutM ()
          mbPutDependencyLength = case d of
            Just (DependencyLength l) -> put l
            _                         -> pure ()