packages feed

fir-0.1.0.0: src/SPIRV/PrimOp.hs

{-# LANGUAGE DerivingStrategies    #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE MultiParamTypeClasses #-}

{-|
Module: SPIRV.PrimOp

This module categorises the raw primitive OpCodes from "SPIRV.Operation".

This allows easier use of operations by generalising over certain aspects,
such as unifying the various arithmetic and logical operations.
For instance, instead of having to distinguish:

  * @UMin@, unsigned integer minimum,
  * @SMin@, signed integer minimum, and
  * @FMin@, floating point minimum,

one can simply refer to the @Min@ operation defined in this module,
and the functions within this module will dispatch the correct primitive
operation depending on the types involved.

Refer also to the module "FIR.Prim.Op", which ties these into the rest of the library.
-}

module SPIRV.PrimOp
  ( PrimOp(..)
  , BoolPrimOp(..), EqPrimOp(..), OrdPrimOp(..)
  , BitPrimOp(..)
  , NumPrimOp(..), FloatPrimOp(..)
  , VecPrimOp(..), MatPrimOp(..)
  , ConvPrimOp(..)
  , GeomPrimOp(..)
  , SyncPrimOp(..)
  , GroupPrimOp(..), GroupNumOp(..), GroupBitwiseOp(..), GroupLogicOp(..)
  , RayPrimOp(..)
  , opAndReturnType, op
  ) where

-- base
import Prelude
  hiding ( Ordering(..) )
import Control.Arrow
  ( second )
import Data.Word
  ( Word32 )

-- fir
import SPIRV.Operation
import SPIRV.PrimTy
  ( PrimTy(..) )
import SPIRV.ScalarTy
  ( ScalarTy(..), Signedness(..) )
import SPIRV.Stage
  ( Backend(Vulkan, OpenCL) )

-------------------------------------------------------------------------------
-- names of primitive operations

data PrimOp where
  BoolOp  :: BoolPrimOp                                  -> PrimOp
  EqOp    :: EqPrimOp                        -> PrimTy   -> PrimOp
  OrdOp   :: OrdPrimOp                       -> ScalarTy -> PrimOp
  BitOp   :: BitPrimOp                       -> ScalarTy -> PrimOp
  NumOp   :: NumPrimOp                       -> ScalarTy -> PrimOp
  FloatOp :: FloatPrimOp                     -> ScalarTy -> PrimOp
  VecOp   :: VecPrimOp   -> Word32           -> PrimTy   -> PrimOp
  MatOp   :: MatPrimOp   -> Word32 -> Word32 -> ScalarTy -> PrimOp
  ConvOp  :: ConvPrimOp  -> ScalarTy         -> ScalarTy -> PrimOp
  CastOp  ::                                    PrimTy   -> PrimOp
  GeomOp  :: GeomPrimOp                                  -> PrimOp
  SyncOp  :: SyncPrimOp                                  -> PrimOp
  GroupOp :: GroupPrimOp                                 -> PrimOp
  RayOp   :: RayPrimOp                                   -> PrimOp
  deriving stock Show

data BoolPrimOp
  = BoolOr
  | BoolAnd
  | BoolNot
  deriving stock Show

data EqPrimOp
  = Equal
  | NotEqual
  deriving stock Show

data OrdPrimOp
  = GT
  | GTE
  | LT
  | LTE
  | Min
  | Max
  deriving stock Show

data BitPrimOp
  = BitAnd
  | BitOr
  | BitXor
  | BitNot
  | ReverseBits
  -- | Right shift: logical for unsigned integers, arithmetic for signed integers
  -- (as 'Data.Bits.shiftR').
  | BitShiftRight
  | BitShiftLeft
  deriving stock Show

data NumPrimOp
  -- additive monoid
  = Add
  -- semiring
  | Mul
  -- additive group
  | Sub
  | Neg
  -- signed
  | Abs
  | Sign
  -- division ring
  | Div
  -- archimedean ordered group
  | Mod
  | Rem
  | Quot
  deriving stock Show

data FloatPrimOp
  = FSin
  | FCos
  | FTan
  | FAsin
  | FAcos
  | FAtan
  | FSinh
  | FCosh
  | FTanh
  | FAsinh
  | FAcosh
  | FAtanh
  | FAtan2
  | FPow
  | FExp
  | FLog
  | FSqrt
  | FInvSqrt
  | FIsNaN
  | FIsInf
  deriving stock Show

data VecPrimOp
  = Vectorise PrimOp
  | DotV
  | VMulK
  | CrossV
  | NormaliseV
  deriving stock Show

data MatPrimOp
  = MMulK
  | MMulV
  | VMulM
  | MMulM
  | Transp
  | Det
  | Inv
  | Out
  deriving stock Show

data ConvPrimOp
  = Convert
  | CTruncate
  | CRound
  | CCeiling
  | CFloor
  deriving stock Show

data GeomPrimOp
  = EmitGeometryVertex
  | EndGeometryPrimitive
  deriving stock Show

data SyncPrimOp
  = ControlSync
  | MemorySync
  deriving stock Show

data GroupPrimOp
  = GroupNumOp     GroupNumOp     ScalarTy
  | GroupBitwiseOp GroupBitwiseOp ScalarTy
  | GroupLogicOp   GroupLogicOp
  deriving stock Show

data GroupNumOp
  = GroupAdd
  | GroupMin
  | GroupMax
  | GroupMul
  deriving stock Show

data GroupBitwiseOp
  = GroupBitwiseAnd
  | GroupBitwiseOr
  | GroupBitwiseXor
  deriving stock Show

data GroupLogicOp
  = GroupLogicalAnd
  | GroupLogicalOr
  | GroupLogicalXor
  deriving stock Show

data RayPrimOp
  = RT_ReportIntersection
  | RT_IgnoreIntersection
  | RT_TerminateRay
  | RT_AccelerationStructureFromDeviceAddress
  deriving stock Show

backendOp :: Backend -> Operation -> Operation -> Operation
backendOp Vulkan o _ = o
backendOp OpenCL _ o = o

opAndReturnType :: Backend -> PrimOp -> (Operation, PrimTy)
opAndReturnType _ (BoolOp boolOp)
  = ( booleanOp  boolOp
    , Boolean
    )
opAndReturnType _ (EqOp eqOp s)
  = ( equalityOp eqOp s
    , Boolean
    )
opAndReturnType bk (OrdOp ordOp s)
  = orderOp bk ordOp s
opAndReturnType _ (BitOp bitOp s)
  = bitwiseOp bitOp s
opAndReturnType _ (CastOp s)
  = castOp s
opAndReturnType bk (NumOp numOp s)
  = second Scalar (numericOp bk numOp s)
opAndReturnType bk (FloatOp flOp s)
  = floatingOp bk flOp s
opAndReturnType bk (VecOp vecOp n ty)
  = vectorOp bk vecOp n ty
opAndReturnType bk (MatOp matOp n m s)
  = matrixOp bk matOp n m s
opAndReturnType bk (ConvOp cOp s1 s2)
  = second Scalar (convOp bk cOp s1 s2)
opAndReturnType _ (GeomOp gOp)
  = geomOp gOp
opAndReturnType _ (SyncOp sOp)
  = syncOp sOp
opAndReturnType bk (GroupOp gOp)
  = groupOp bk gOp
opAndReturnType _ (RayOp rOp)
  = rayOp rOp

op :: Backend -> PrimOp -> Operation
op bkend = fst . opAndReturnType bkend

booleanOp :: BoolPrimOp -> Operation
booleanOp BoolOr  = LogicalOr
booleanOp BoolAnd = LogicalAnd
booleanOp BoolNot = LogicalNot

equalityOp :: EqPrimOp -> PrimTy -> Operation
equalityOp Equal    (Scalar (Floating  _)) = FOrdEqual -- not reflexive!
equalityOp Equal    (Scalar (Integer _ _)) = IEqual
equalityOp Equal    Boolean                = LogicalEqual
equalityOp NotEqual (Scalar (Floating  _)) = FOrdNotEqual
equalityOp NotEqual (Scalar (Integer _ _)) = INotEqual
equalityOp NotEqual Boolean                = LogicalNotEqual
equalityOp primOp ty = error $ "internal error: unsupported type " ++ show ty ++ " with equality operation " ++ show primOp

orderOp :: Backend -> OrdPrimOp -> ScalarTy -> (Operation, PrimTy)
orderOp _  GT  (Integer Unsigned _) = ( UGreaterThan        , Boolean )
orderOp _  GT  (Integer Signed   _) = ( SGreaterThan        , Boolean )
orderOp _  GT  (Floating         _) = ( FOrdGreaterThan     , Boolean )
orderOp _  GTE (Integer Unsigned _) = ( UGreaterThanEqual   , Boolean )
orderOp _  GTE (Integer Signed   _) = ( SGreaterThanEqual   , Boolean )
orderOp _  GTE (Floating         _) = ( FOrdGreaterThanEqual, Boolean )
orderOp _  LT  (Integer Unsigned _) = ( ULessThan           , Boolean )
orderOp _  LT  (Integer Signed   _) = ( SLessThan           , Boolean )
orderOp _  LT  (Floating         _) = ( FOrdLessThan        , Boolean )
orderOp _  LTE (Integer Unsigned _) = ( ULessThanEqual      , Boolean )
orderOp _  LTE (Integer Signed   _) = ( SLessThanEqual      , Boolean )
orderOp _  LTE (Floating         _) = ( FOrdLessThanEqual   , Boolean )
orderOp bk Min (Integer Unsigned w) = ( backendOp bk GLSL_UMin OpenCL_UMin , Scalar (Integer Unsigned w) )
orderOp bk Min (Integer Signed   w) = ( backendOp bk GLSL_SMin OpenCL_SMin , Scalar (Integer Signed   w) )
orderOp bk Min (Floating         w) = ( backendOp bk GLSL_FMin OpenCL_FMin , Scalar (Floating         w) )
orderOp bk Max (Integer Unsigned w) = ( backendOp bk GLSL_UMax OpenCL_UMax , Scalar (Integer Unsigned w) )
orderOp bk Max (Integer Signed   w) = ( backendOp bk GLSL_SMax OpenCL_SMax , Scalar (Integer Signed   w) )
orderOp bk Max (Floating         w) = ( backendOp bk GLSL_FMax OpenCL_FMax , Scalar (Floating         w) )

bitwiseOp :: BitPrimOp -> ScalarTy -> (Operation, PrimTy)
bitwiseOp BitAnd s = (BitwiseAnd, Scalar s)
bitwiseOp BitOr  s = (BitwiseOr , Scalar s)
bitwiseOp BitXor s = (BitwiseXor, Scalar s)
bitwiseOp BitNot s = (Not       , Scalar s)
bitwiseOp ReverseBits s = (BitReverse, Scalar s)
bitwiseOp BitShiftRight s@(Integer Unsigned _) = (ShiftRightLogical   , Scalar s)
bitwiseOp BitShiftRight s@(Integer Signed   _) = (ShiftRightArithmetic, Scalar s)
bitwiseOp BitShiftRight s@(Floating         _) = error ( "bitwiseOp: cannot shift a value of type " ++ show s )
bitwiseOp BitShiftLeft  s = (ShiftLeftLogical, Scalar s)

castOp :: PrimTy -> (Operation, PrimTy)
castOp s = (BitCast, s)

numericOp :: Backend -> NumPrimOp -> ScalarTy -> (Operation, ScalarTy)
-- additive monoid
numericOp _  Add  (Floating         w) = ( FAdd   , Floating         w )
numericOp _  Add  (Integer s        w) = ( IAdd   , Integer s        w )
-- semiring
numericOp _  Mul  (Floating         w) = ( FMul   , Floating         w )
numericOp _  Mul  (Integer s        w) = ( IMul   , Integer s        w )
-- additive group
numericOp _  Sub  (Floating         w) = ( FSub   , Floating         w )
numericOp _  Sub  (Integer s        w) = ( ISub   , Integer s        w )
numericOp _  Neg  (Floating         w) = ( FNegate, Floating         w )
numericOp _  Neg  (Integer Signed   w) = ( SNegate, Integer Signed   w )
numericOp _  Neg  (Integer Unsigned _) = error "internal error: 'negate' called on unsigned type"
-- signed
numericOp bk Abs  (Floating         w) = ( backendOp bk GLSL_FAbs OpenCL_FAbs  , Floating         w )
numericOp bk Abs  (Integer Signed   w) = ( backendOp bk GLSL_SAbs OpenCL_SAbs  , Integer Signed   w )
numericOp _  Abs  (Integer Unsigned _) = error "internal error: 'abs' called on unsigned type"
numericOp bk Sign (Floating         w) = ( backendOp bk GLSL_FSign OpenCL_FSign, Floating         w )
numericOp bk Sign (Integer Signed   w) 
  | OpenCL <- bk = error "TODO: OpenCL backend does not support 'signum' operation on integer types"
  | otherwise =  ( GLSL_SSign  , Integer Signed   w )
numericOp _  Sign (Integer Unsigned _) = error "internal error: 'signum' called on unsigned type"
-- division ring
numericOp _  Div  (Floating         w) = ( FDiv   , Floating         w )
numericOp _  Div  (Integer  _       _) = error "internal error: Div used with integral type"
-- archimedean ordered group
numericOp _  Mod  (Floating         w) = ( FMod   , Floating         w )
numericOp _  Mod  (Integer Signed   w) = ( SMod   , Integer Signed   w )
numericOp _  Mod  (Integer Unsigned w) = ( UMod   , Integer Unsigned w )
numericOp _  Rem  (Floating         w) = ( FRem   , Floating         w )
numericOp _  Rem  (Integer Signed   w) = ( SRem   , Integer Signed   w )
numericOp _  Rem  (Integer Unsigned w) = ( UMod   , Integer Unsigned w ) -- URem pointless for unsigned type
numericOp _  Quot (Integer Signed   w) = ( SDiv   , Integer Signed   w )
numericOp _  Quot (Integer Unsigned w) = ( UDiv   , Integer Unsigned w )
numericOp _  Quot (Floating         _) = error "internal error: Quot used with floating-point type"

floatingOp :: Backend -> FloatPrimOp -> ScalarTy -> (Operation, PrimTy)
floatingOp bk FSin     s = ( backendOp bk GLSL_Sin     OpenCL_Sin     , Scalar s )
floatingOp bk FCos     s = ( backendOp bk GLSL_Cos     OpenCL_Cos     , Scalar s )
floatingOp bk FTan     s = ( backendOp bk GLSL_Tan     OpenCL_Tan     , Scalar s )
floatingOp bk FAsin    s = ( backendOp bk GLSL_Asin    OpenCL_Asin    , Scalar s )
floatingOp bk FAcos    s = ( backendOp bk GLSL_Acos    OpenCL_Acos    , Scalar s )
floatingOp bk FAtan    s = ( backendOp bk GLSL_Atan    OpenCL_Atan    , Scalar s )
floatingOp bk FSinh    s = ( backendOp bk GLSL_Sinh    OpenCL_Sinh    , Scalar s )
floatingOp bk FCosh    s = ( backendOp bk GLSL_Cosh    OpenCL_Cosh    , Scalar s )
floatingOp bk FTanh    s = ( backendOp bk GLSL_Tanh    OpenCL_Tanh    , Scalar s )
floatingOp bk FAsinh   s = ( backendOp bk GLSL_Asinh   OpenCL_Asinh   , Scalar s )
floatingOp bk FAcosh   s = ( backendOp bk GLSL_Acosh   OpenCL_Acosh   , Scalar s )
floatingOp bk FAtanh   s = ( backendOp bk GLSL_Atanh   OpenCL_Atanh   , Scalar s )
floatingOp bk FAtan2   s = ( backendOp bk GLSL_Atan2   OpenCL_Atan2   , Scalar s )
floatingOp bk FPow     s = ( backendOp bk GLSL_Pow     OpenCL_Pow     , Scalar s )
floatingOp bk FExp     s = ( backendOp bk GLSL_Exp     OpenCL_Exp     , Scalar s )
floatingOp bk FLog     s = ( backendOp bk GLSL_Log     OpenCL_Log     , Scalar s )
floatingOp bk FSqrt    s = ( backendOp bk GLSL_Sqrt    OpenCL_Sqrt    , Scalar s )
floatingOp bk FInvSqrt s = ( backendOp bk GLSL_InvSqrt OpenCL_InvSqrt , Scalar s )
floatingOp _  FIsNaN   _ = ( IsNan, Boolean )
floatingOp _  FIsInf   _ = ( IsInf, Boolean )

vectorOp :: Backend -> VecPrimOp -> Word32 -> PrimTy -> (Operation, PrimTy)
vectorOp bk (Vectorise prim) n ty = ( op bk prim, Vector n ty )
vectorOp _  DotV       _ (Scalar (Floating w)) = ( Dot, Scalar (Floating w) )
vectorOp _  DotV       _ _                     = error "internal error: dot product: vector elements must be of floating-point type."
vectorOp _  VMulK      n (Scalar (Floating w)) = ( VectorTimesScalar, Vector n (Scalar (Floating w)) )
vectorOp _  VMulK      _ _                     = error "internal error: scalar multiplication: vector elements must be of floating-point type."
vectorOp bk CrossV     n (Scalar (Floating w)) = ( backendOp bk GLSL_Cross OpenCL_Cross, Vector n (Scalar (Floating w)) )
vectorOp _  CrossV     _ _                     = error "internal error: cross product: vector elements must be of floating-point type."
vectorOp bk NormaliseV n (Scalar (Floating w)) = ( backendOp bk GLSL_Normalize OpenCL_Normalize, Vector n (Scalar (Floating w)) )
vectorOp _  NormaliseV _ _                     = error "internal error: normalise: vector elements must be of floating-point type."

matrixOp :: Backend -> MatPrimOp -> Word32 -> Word32 -> ScalarTy -> (Operation, PrimTy)
matrixOp _  MMulK  n m s = ( MatrixTimesScalar, Matrix n m s )
matrixOp _  MMulV  n _ s = ( MatrixTimesVector, Vector n   (Scalar s) )
matrixOp _  VMulM  n _ s = ( VectorTimesMatrix, Vector n   (Scalar s) )
matrixOp _  MMulM  n m s = ( MatrixTimesMatrix, Matrix n m s )
matrixOp _  Transp n m s = ( Transpose        , Matrix n m s )
matrixOp bk Det    _ _ s
  | Vulkan <- bk = ( GLSL_Determinant      , Scalar     s )
  | otherwise    = error "todo: determinant not implemented in OpenCL backend"
matrixOp bk Inv    n m s
  | Vulkan <- bk = ( GLSL_MatrixInverse    , Matrix n m s )
  | otherwise    = error "todo: matrix inverse not implemented in OpenCL backend"
matrixOp _  Out    n m s = ( OuterProduct     , Matrix n m s )

convOp :: Backend -> ConvPrimOp -> ScalarTy -> ScalarTy -> (Operation, ScalarTy)
convOp _  Convert (Integer Signed   _) (Floating         w) = ( ConvertSToF, Floating         w )
convOp _  Convert (Integer Unsigned _) (Floating         w) = ( ConvertUToF, Floating         w )
convOp _  Convert (Floating         _) (Integer Signed   w) = ( ConvertFToS, Integer Signed   w )
convOp _  Convert (Floating         _) (Integer Unsigned w) = ( ConvertFToU, Integer Unsigned w )
convOp bk Convert (Integer Unsigned v) (Integer Signed   w)
  | OpenCL <- bk = ( SatConvertUToS, Integer Signed w )
  | v == w = ( BitCast, Integer Signed   w )
  | otherwise = error "internal error: unsupported conversion between integer types of different width and sign"
convOp bk Convert (Integer Signed   v) (Integer Unsigned w)
  | OpenCL <- bk = ( SatConvertSToU, Integer Unsigned w )
  | v == w = ( BitCast    , Integer Unsigned w )
  | otherwise = error "internal error: unsupported conversion between integer types of different width and sign"
convOp _  Convert (Floating         v) (Floating         w)
  | v /= w = ( FConvert, Floating         w)
convOp _  Convert (Integer Signed   v) (Integer Signed   w)
  | v /= w = ( SConvert, Integer Signed   w)
convOp _  Convert (Integer Unsigned v) (Integer Unsigned w)
  | v /= w = ( UConvert, Integer Unsigned w)
convOp _  CTruncate (Floating _) (Integer Signed   w) = ( ConvertFToS, Integer Signed   w )
convOp _  CTruncate (Floating _) (Integer Unsigned w) = ( ConvertFToU, Integer Unsigned w )
convOp bk CTruncate (Floating v) (Floating w)
  | v == w    = ( backendOp bk GLSL_Trunc OpenCL_Trunc, Floating w )
  | otherwise = error "internal error: unsupported truncation between floating point types of different widths"
convOp bk CRound    (Floating v) (Floating w)
  | v == w    = ( backendOp bk GLSL_Round OpenCL_Round, Floating w )
  | otherwise = error "internal error: unsupported rounding between floating point types of different widths"
convOp bk CFloor    (Floating v) (Floating w)
  | v == w    = ( backendOp bk GLSL_Floor OpenCL_Floor, Floating w )
  | otherwise = error "internal error: unsupported floor operation between floating point types of different widths"
convOp bk CCeiling (Floating v) (Floating w)
  | v == w    = ( backendOp bk GLSL_Ceil OpenCL_Ceil, Floating w )
  | otherwise = error "internal error: unsupported ceiling operation between floating point types of different widths"
convOp _  cOp a b
  = error $ "internal error: unsupported operation " ++ show cOp ++ " from type " ++ show a ++ " to type " ++ show b

geomOp :: GeomPrimOp -> (Operation, PrimTy)
geomOp EmitGeometryVertex   = ( EmitVertex  , Unit )
geomOp EndGeometryPrimitive = ( EndPrimitive, Unit )

syncOp :: SyncPrimOp -> (Operation, PrimTy)
syncOp ControlSync = ( ControlBarrier, Unit )
syncOp MemorySync  = ( MemoryBarrier , Unit )

groupOp :: Backend -> GroupPrimOp -> (Operation, PrimTy)
groupOp bk (GroupNumOp gpOp s) = second Scalar $ groupNumOp bk gpOp s
groupOp OpenCL gpOp = error $ "internal error: OpenCL backend does not support group operation " ++ show gpOp
groupOp _ (GroupBitwiseOp gpOp s) = (groupBitwiseOp gpOp, Scalar s)
groupOp _ (GroupLogicOp   gpOp)   = (groupLogicOp gpOp, Boolean)

groupNumOp :: Backend -> GroupNumOp -> ScalarTy -> (Operation, ScalarTy)
groupNumOp OpenCL GroupAdd (Floating         w) = ( GroupFAdd, Floating         w )
groupNumOp OpenCL GroupAdd (Integer s        w) = ( GroupIAdd, Integer s        w )
groupNumOp OpenCL GroupMax (Floating         w) = ( GroupFMax, Floating         w )
groupNumOp OpenCL GroupMax (Integer Signed   w) = ( GroupSMax, Integer Signed   w )
groupNumOp OpenCL GroupMax (Integer Unsigned w) = ( GroupUMax, Integer Unsigned w )
groupNumOp OpenCL GroupMin (Floating         w) = ( GroupFMin, Floating         w )
groupNumOp OpenCL GroupMin (Integer Signed   w) = ( GroupSMin, Integer Signed   w )
groupNumOp OpenCL GroupMin (Integer Unsigned w) = ( GroupUMin, Integer Unsigned w )
groupNumOp Vulkan GroupAdd (Floating         w) = ( GroupNonUniformFAdd, Floating         w )
groupNumOp Vulkan GroupAdd (Integer s        w) = ( GroupNonUniformIAdd, Integer s        w )
groupNumOp Vulkan GroupMul (Floating         w) = ( GroupNonUniformFMul, Floating         w )
groupNumOp Vulkan GroupMul (Integer s        w) = ( GroupNonUniformIMul, Integer s        w )
groupNumOp Vulkan GroupMax (Floating         w) = ( GroupNonUniformFMax, Floating         w )
groupNumOp Vulkan GroupMax (Integer Signed   w) = ( GroupNonUniformSMax, Integer Signed   w )
groupNumOp Vulkan GroupMax (Integer Unsigned w) = ( GroupNonUniformUMax, Integer Unsigned w )
groupNumOp Vulkan GroupMin (Floating         w) = ( GroupNonUniformFMin, Floating         w )
groupNumOp Vulkan GroupMin (Integer Signed   w) = ( GroupNonUniformSMin, Integer Signed   w )
groupNumOp Vulkan GroupMin (Integer Unsigned w) = ( GroupNonUniformUMin, Integer Unsigned w )
groupNumOp OpenCL GroupMul _ =
  error "internal error: OpenCL backend does not support GroupMul operation"

groupBitwiseOp :: GroupBitwiseOp -> Operation
groupBitwiseOp GroupBitwiseAnd = GroupNonUniformBitwiseAnd
groupBitwiseOp GroupBitwiseOr  = GroupNonUniformBitwiseOr
groupBitwiseOp GroupBitwiseXor = GroupNonUniformBitwiseXor

groupLogicOp :: GroupLogicOp -> Operation
groupLogicOp GroupLogicalAnd = GroupNonUniformLogicalAnd
groupLogicOp GroupLogicalOr  = GroupNonUniformLogicalOr
groupLogicOp GroupLogicalXor = GroupNonUniformLogicalXor

rayOp :: RayPrimOp -> (Operation, PrimTy)
rayOp RT_ReportIntersection                     = ( ReportIntersection, Boolean )
rayOp RT_IgnoreIntersection                     = ( IgnoreIntersection, Unit )
rayOp RT_TerminateRay                           = ( TerminateRay, Unit )
rayOp RT_AccelerationStructureFromDeviceAddress = ( ConvertUToAccelerationStructure, AccelerationStructure )