packages feed

fir-0.1.0.0: src/FIR/Prim/Op.hs

{-# LANGUAGE AllowAmbiguousTypes    #-}
{-# LANGUAGE DataKinds              #-}
{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs                  #-}
{-# LANGUAGE InstanceSigs           #-}
{-# LANGUAGE PolyKinds              #-}
{-# LANGUAGE ScopedTypeVariables    #-}
{-# LANGUAGE TypeApplications       #-}
{-# LANGUAGE TypeFamilies           #-}
{-# LANGUAGE TypeOperators          #-}
{-# LANGUAGE UndecidableInstances   #-}

{-|
Module: FIR.Prim.Op

Recall that the AST has a 'FIR.AST.PrimOp' constructor
of the following type:

>   PrimOp :: PrimOp op a
>          => Proxy a -> Proxy op -> AST (PrimOpType op a)

This module provides the wrapper type class 'PrimOp' which relates
the internal SPIR-V operation names (as defined in "SPIRV.PrimOp")
with their types within the context of the AST.

This module also specifies which operations can be vectorised.
-}

module FIR.Prim.Op where

-- base
import Prelude
  ( Show(..), Functor(..), fromIntegral )
import Control.Applicative
  ( liftA2 )
import Data.Proxy
  ( Proxy(Proxy) )
import GHC.TypeNats
  ( Nat, KnownNat, natVal )

-- fir
import Data.Constraint.All
  ( All )
import FIR.AST.Type
  ( AugType(Val, (:-->)), Eff, FunArgs, UnderlyingType, Nullary
  , ApplyFAug
  )
import FIR.Prelude
import FIR.Prim.RayTracing
  ( AccelerationStructure )
import FIR.Prim.Types
  ( PrimTy, ScalarTy
  , primTy, scalarTy
  )
import FIR.ProgramState
  ( ProgramState )
import Math.Linear
  ( V, M
  , Semimodule((^*)), Inner(dot, normalise), Cross(cross)
  , Matrix(..)
  )
import Math.Logic.Bits
  ( Bits(..), BitShift(..), BitCast(..) )
import Math.Logic.Class
  ( Boolean(..), Eq(..), Ord(..) )
import Math.Algebra.Class
  ( AdditiveMonoid(..), CancellativeAdditiveMonoid(..), AdditiveGroup(..)
  , Semiring(..), Signed(..)
  , Archimedean(..)
  , DivisionRing(..)
  , Floating(..), RealFloat(..)
  , Convert(..), Rounding(..)
  )
import qualified SPIRV.PrimOp as SPIRV
import qualified SPIRV.PrimTy as SPIRV
  ( PrimTy(..) )

-------------------------------------------------------------------------------
-- primitive operations

class All Nullary ( FunArgs (PrimOpAugType op a) ) => PrimOp (op :: opKind) (a :: k) | op -> k where
  type PrimOpAugType op a :: AugType
  op :: PrimOpType op a
  op = error
    ( "unsupported primitive operation " <> show ( opName @_ @_ @op @a ) )
  opName :: SPIRV.PrimOp
  opSing :: Maybe (SPrimOp a op)
  opSing = Nothing
  vectorisation :: KnownNat n => Maybe (VecPrimOpType n op a)
  vectorisation = Nothing

type PrimOpType op a = UnderlyingType ( PrimOpAugType op a )

-- some singletons for primitive operations
-- (only defining those that we use in code generation)
data SPrimOp (a :: k) (op :: opKind) :: Type where
  SMul :: (ScalarTy a, Semiring a) => SPrimOp a SPIRV.Mul
  
-- data type recording type-level information regarding vectorisation of primops
data VecPrimOpType (n :: Nat) op a where
  VecPrimOpType
    :: ( PrimOp ('Vectorise op) vec
       , All PrimTyVal (FunArgs (PrimOpAugType op a))
       , PrimOpAugType ('Vectorise op) vec ~ ApplyFAug (V n) (PrimOpAugType op a)
       )
    => Proxy vec -> VecPrimOpType n op a

newtype Vectorise a = Vectorise a

class    ( v ~ Val (UnderlyingType v), PrimTy (UnderlyingType v) ) => PrimTyVal v
instance ( v ~ Val (UnderlyingType v), PrimTy (UnderlyingType v) ) => PrimTyVal v

-------------------------------------------------------------------------------
-- instances

-- boolean operations
instance PrimOp SPIRV.BoolOr Bool where
  type PrimOpAugType SPIRV.BoolOr Bool = Val Bool :--> Val Bool :--> Val Bool
  op = (||)
  opName = SPIRV.BoolOp SPIRV.BoolOr
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BoolOr Bool)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n Bool))
instance PrimOp SPIRV.BoolAnd Bool where
  type PrimOpAugType SPIRV.BoolAnd Bool = Val Bool :--> Val Bool :--> Val Bool
  op = (&&)
  opName = SPIRV.BoolOp SPIRV.BoolAnd
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BoolAnd Bool)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n Bool))
instance PrimOp SPIRV.BoolNot Bool where
  type PrimOpAugType SPIRV.BoolNot Bool = Val Bool :--> Val Bool
  op = not
  opName = SPIRV.BoolOp SPIRV.BoolNot
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BoolNot Bool)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n Bool))

-- equality operations
instance (PrimTy a, Eq a, Logic a ~ Bool) => PrimOp SPIRV.Equal (a :: Type) where
  type PrimOpAugType SPIRV.Equal a = Val a :--> Val a :--> Val Bool
  op = (==)
  opName = SPIRV.EqOp SPIRV.Equal (primTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Equal a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (PrimTy a, Eq a, Logic a ~ Bool) => PrimOp SPIRV.NotEqual (a :: Type) where
  type PrimOpAugType SPIRV.NotEqual a = Val a :--> Val a :--> Val Bool
  op = (/=)
  opName = SPIRV.EqOp SPIRV.NotEqual (primTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.NotEqual a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))

-- comparison
instance (ScalarTy a, Ord a, Logic a ~ Bool) => PrimOp SPIRV.GT (a :: Type) where
  type PrimOpAugType SPIRV.GT a = Val a :--> Val a :--> Val Bool
  op = (>)
  opName = SPIRV.OrdOp SPIRV.GT (scalarTy @a)
instance (ScalarTy a, Ord a, Logic a ~ Bool) => PrimOp SPIRV.GTE (a :: Type) where
  type PrimOpAugType SPIRV.GTE a = Val a :--> Val a :--> Val Bool
  op = (>=)
  opName = SPIRV.OrdOp SPIRV.GTE (scalarTy @a)
instance (ScalarTy a, Ord a, Logic a ~ Bool) => PrimOp SPIRV.LT (a :: Type) where
  type PrimOpAugType SPIRV.LT a = Val a :--> Val a :--> Val Bool
  op = (<)
  opName = SPIRV.OrdOp SPIRV.LT (scalarTy @a)
instance (ScalarTy a, Ord a, Logic a ~ Bool) => PrimOp SPIRV.LTE (a :: Type) where
  type PrimOpAugType SPIRV.LTE a = Val a :--> Val a :--> Val Bool
  op = (<=)
  opName = SPIRV.OrdOp SPIRV.LTE (scalarTy @a)
instance (ScalarTy a, Ord a, Logic a ~ Bool) => PrimOp SPIRV.Min (a :: Type) where
  type PrimOpAugType SPIRV.Min a = Val a :--> Val a :--> Val a
  op = min
  opName = SPIRV.OrdOp SPIRV.Min (scalarTy @a)
instance (ScalarTy a, Ord a, Logic a ~ Bool) => PrimOp SPIRV.Max (a :: Type) where
  type PrimOpAugType SPIRV.Max a = Val a :--> Val a :--> Val a
  op = max
  opName = SPIRV.OrdOp SPIRV.Max (scalarTy @a)

-- bitwise operations
instance (ScalarTy a, Bits a) => PrimOp SPIRV.BitAnd (a :: Type) where
  type PrimOpAugType SPIRV.BitAnd a = Val a :--> Val a :--> Val a
  op = (.&.)
  opName = SPIRV.BitOp SPIRV.BitAnd (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BitAnd a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Bits a) => PrimOp SPIRV.BitOr (a :: Type) where
  type PrimOpAugType SPIRV.BitOr a = Val a :--> Val a :--> Val a
  op = (.|.)
  opName = SPIRV.BitOp SPIRV.BitOr (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BitOr a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Bits a) => PrimOp SPIRV.BitXor (a :: Type) where
  type PrimOpAugType SPIRV.BitXor a = Val a :--> Val a :--> Val a
  op = xor
  opName = SPIRV.BitOp SPIRV.BitXor (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BitXor a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Bits a) => PrimOp SPIRV.BitNot (a :: Type) where
  type PrimOpAugType SPIRV.BitNot a = Val a :--> Val a
  op = complement
  opName = SPIRV.BitOp SPIRV.BitNot (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BitNot a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Bits a) => PrimOp SPIRV.ReverseBits (a :: Type) where
  type PrimOpAugType SPIRV.ReverseBits a = Val a :--> Val a
  op = bitReverse
  opName = SPIRV.BitOp SPIRV.ReverseBits (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.ReverseBits a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance forall (b :: Type) (s :: Type). (ScalarTy b, PrimTy s, BitShift '(b,s))
        => PrimOp SPIRV.BitShiftRight '(b,s) where
  type PrimOpAugType SPIRV.BitShiftRight '(b,s) = Val b :--> Val s :--> Val b
  op = shiftR
  opName = SPIRV.BitOp SPIRV.BitShiftRight (scalarTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BitShiftRight '(b,s))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n b, V n s))
instance forall (b :: Type) (s :: Type). (ScalarTy b, PrimTy s, BitShift '(b,s))
      => PrimOp SPIRV.BitShiftLeft '(b,s) where
  type PrimOpAugType SPIRV.BitShiftLeft '(b,s) = Val b :--> Val s :--> Val b
  op = shiftL
  opName = SPIRV.BitOp SPIRV.BitShiftLeft (scalarTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.BitShiftLeft '(b,s))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n b, V n s))

-- bitcast operation
instance (ScalarTy a, ScalarTy b, BitCast a b) => PrimOp SPIRV.CastOp '(a,b) where
  type PrimOpAugType SPIRV.CastOp '(a,b) = Val a :--> Val b
  op = bitcast
  opName = SPIRV.CastOp (primTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.CastOp '(a,b))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n a, V n b))

-- numeric operations
instance (ScalarTy a, AdditiveMonoid a) => PrimOp SPIRV.Add (a :: Type) where
  type PrimOpAugType SPIRV.Add a = Val a :--> Val a :--> Val a
  op = (+)
  opName = SPIRV.NumOp SPIRV.Add (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Add a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Semiring a) => PrimOp SPIRV.Mul (a :: Type) where
  type PrimOpAugType SPIRV.Mul a = Val a :--> Val a :--> Val a
  op = (*)
  opName = SPIRV.NumOp SPIRV.Mul (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Mul a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
  opSing = Just SMul
instance (ScalarTy a, CancellativeAdditiveMonoid a) => PrimOp SPIRV.Sub (a :: Type) where
  type PrimOpAugType SPIRV.Sub a = Val a :--> Val a :--> Val a
  op = (-)
  opName = SPIRV.NumOp SPIRV.Sub (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Sub a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, AdditiveGroup a) => PrimOp SPIRV.Neg (a :: Type) where
  type PrimOpAugType SPIRV.Neg a = Val a :--> Val a
  op = negate
  opName = SPIRV.NumOp SPIRV.Neg (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Neg a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Signed a) => PrimOp SPIRV.Abs (a :: Type) where
  type PrimOpAugType SPIRV.Abs a = Val a :--> Val a
  op = abs
  opName = SPIRV.NumOp SPIRV.Abs (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Abs a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Signed a) => PrimOp SPIRV.Sign (a :: Type) where
  type PrimOpAugType SPIRV.Sign a = Val a :--> Val a
  op = signum
  opName = SPIRV.NumOp SPIRV.Sign (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Sign a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, DivisionRing a) => PrimOp SPIRV.Div (a :: Type) where
  type PrimOpAugType SPIRV.Div a = Val a :--> Val a :--> Val a
  op = (/)
  opName = SPIRV.NumOp SPIRV.Div (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Div a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Archimedean a) => PrimOp SPIRV.Mod (a :: Type) where
  type PrimOpAugType SPIRV.Mod a = Val a :--> Val a :--> Val a
  op = mod
  opName = SPIRV.NumOp SPIRV.Mod (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Mod a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Archimedean a) => PrimOp SPIRV.Rem (a :: Type) where
  type PrimOpAugType SPIRV.Rem a = Val a :--> Val a :--> Val a
  op = rem
  opName = SPIRV.NumOp SPIRV.Rem (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Rem a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Archimedean a) => PrimOp SPIRV.Quot (a :: Type) where
  type PrimOpAugType SPIRV.Quot a = Val a :--> Val a :--> Val a
  op = div
  opName = SPIRV.NumOp SPIRV.Quot (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Quot a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))


-- floating operations
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FSin (a :: Type) where
  type PrimOpAugType SPIRV.FSin a = Val a :--> Val a
  op = sin
  opName = SPIRV.FloatOp SPIRV.FSin (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FSin a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FCos (a :: Type) where
  type PrimOpAugType SPIRV.FCos a = Val a :--> Val a
  op = cos
  opName = SPIRV.FloatOp SPIRV.FCos (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FCos a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FTan (a :: Type) where
  type PrimOpAugType SPIRV.FTan a = Val a :--> Val a
  op = tan
  opName = SPIRV.FloatOp SPIRV.FTan (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FTan a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FAsin (a :: Type) where
  type PrimOpAugType SPIRV.FAsin a = Val a :--> Val a
  op = asin
  opName = SPIRV.FloatOp SPIRV.FAsin (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FAsin a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FAcos (a :: Type) where
  type PrimOpAugType SPIRV.FAcos a = Val a :--> Val a
  op = acos
  opName = SPIRV.FloatOp SPIRV.FAcos (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FAcos a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FAtan (a :: Type) where
  type PrimOpAugType SPIRV.FAtan a = Val a :--> Val a
  op = atan
  opName = SPIRV.FloatOp SPIRV.FAtan (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FAtan a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FSinh (a :: Type) where
  type PrimOpAugType SPIRV.FSinh a = Val a :--> Val a
  op = sinh
  opName = SPIRV.FloatOp SPIRV.FSinh (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FSinh a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FCosh (a :: Type) where
  type PrimOpAugType SPIRV.FCosh a = Val a :--> Val a
  op = cosh
  opName = SPIRV.FloatOp SPIRV.FCosh (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FCosh a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FTanh (a :: Type) where
  type PrimOpAugType SPIRV.FTanh a = Val a :--> Val a
  op = tanh
  opName = SPIRV.FloatOp SPIRV.FTanh (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FTanh a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FAsinh (a :: Type) where
  type PrimOpAugType SPIRV.FAsinh a = Val a :--> Val a
  op = asinh
  opName = SPIRV.FloatOp SPIRV.FAsinh (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FAsinh a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FAcosh (a :: Type) where
  type PrimOpAugType SPIRV.FAcosh a = Val a :--> Val a
  op = acosh
  opName = SPIRV.FloatOp SPIRV.FAcosh (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FAcosh a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FAtanh (a :: Type) where
  type PrimOpAugType SPIRV.FAtanh a = Val a :--> Val a
  op = atanh
  opName = SPIRV.FloatOp SPIRV.FAtanh (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FAtanh a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, RealFloat a) => PrimOp SPIRV.FAtan2 (a :: Type) where
  type PrimOpAugType SPIRV.FAtan2 a = Val a :--> Val a :--> Val a
  op = atan2
  opName = SPIRV.FloatOp SPIRV.FAtan2 (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FAtan2 a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FPow (a :: Type) where
  type PrimOpAugType SPIRV.FPow a = Val a :--> Val a :--> Val a
  op = (**)
  opName = SPIRV.FloatOp SPIRV.FPow (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FPow a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FExp (a :: Type) where
  type PrimOpAugType SPIRV.FExp a = Val a :--> Val a
  op = exp
  opName = SPIRV.FloatOp SPIRV.FExp (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FExp a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FLog (a :: Type) where
  type PrimOpAugType SPIRV.FLog a = Val a :--> Val a
  op = log
  opName = SPIRV.FloatOp SPIRV.FLog (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FLog a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FSqrt (a :: Type) where
  type PrimOpAugType SPIRV.FSqrt a = Val a :--> Val a
  op = sqrt
  opName = SPIRV.FloatOp SPIRV.FSqrt (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FSqrt a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, Floating a) => PrimOp SPIRV.FInvSqrt (a :: Type) where
  type PrimOpAugType SPIRV.FInvSqrt a = Val a :--> Val a
  op = recip . sqrt
  opName = SPIRV.FloatOp SPIRV.FInvSqrt (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FInvSqrt a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, RealFloat a, Logic a ~ Bool) => PrimOp SPIRV.FIsNaN (a :: Type) where
  type PrimOpAugType SPIRV.FIsNaN a = Val a :--> Val Bool
  op = isNaN
  opName = SPIRV.FloatOp SPIRV.FIsNaN (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FIsNaN a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))
instance (ScalarTy a, RealFloat a, Logic a ~ Bool) => PrimOp SPIRV.FIsInf (a :: Type) where
  type PrimOpAugType SPIRV.FIsInf a = Val a :--> Val Bool
  op = isInfinite
  opName = SPIRV.FloatOp SPIRV.FIsInf (scalarTy @a)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.FIsInf a)
  vectorisation = Just $ VecPrimOpType (Proxy @(V n a))

-- numeric conversions
instance ( ScalarTy a, ScalarTy b, Convert '(a,b) ) => PrimOp SPIRV.Convert '(a,b) where
  type PrimOpAugType SPIRV.Convert '(a,b) = Val a :--> Val b
  op = convert
  opName = SPIRV.ConvOp SPIRV.Convert (scalarTy @a) (scalarTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.Convert '(a,b))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n a, V n b))
instance ( ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp SPIRV.CTruncate '(a,b) where
  type PrimOpAugType SPIRV.CTruncate '(a,b) = Val a :--> Val b
  op = truncate
  opName = SPIRV.ConvOp SPIRV.CTruncate (scalarTy @a) (scalarTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.CTruncate '(a,b))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n a, V n b))
instance ( ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp SPIRV.CRound '(a,b) where
  type PrimOpAugType SPIRV.CRound '(a,b) = Val a :--> Val b
  op = round
  opName = SPIRV.ConvOp SPIRV.CRound (scalarTy @a) (scalarTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.CRound '(a,b))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n a, V n b))
instance ( ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp SPIRV.CFloor '(a,b) where
  type PrimOpAugType SPIRV.CFloor '(a,b) = Val a :--> Val b
  op = floor
  opName = SPIRV.ConvOp SPIRV.CFloor (scalarTy @a) (scalarTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.CFloor '(a,b))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n a, V n b))
instance ( ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp SPIRV.CCeiling '(a,b) where
  type PrimOpAugType SPIRV.CCeiling '(a,b) = Val a :--> Val b
  op = ceiling
  opName = SPIRV.ConvOp SPIRV.CCeiling (scalarTy @a) (scalarTy @b)
  vectorisation :: forall n. KnownNat n => Maybe (VecPrimOpType n SPIRV.CCeiling '(a,b))
  vectorisation = Just $ VecPrimOpType (Proxy @'(V n a, V n b))

-- geometry primitive instructions
instance PrimOp SPIRV.EmitGeometryVertex (i :: ProgramState) where
  type PrimOpAugType SPIRV.EmitGeometryVertex i = Eff i i ()
  opName = SPIRV.GeomOp SPIRV.EmitGeometryVertex
instance PrimOp SPIRV.EndGeometryPrimitive (i :: ProgramState) where
  type PrimOpAugType SPIRV.EndGeometryPrimitive i = Eff i i ()
  opName = SPIRV.GeomOp SPIRV.EndGeometryPrimitive

-- memory synchronisation instructions
instance PrimOp SPIRV.ControlSync (i :: ProgramState) where
  type PrimOpAugType SPIRV.ControlSync i = Val Word32 :--> Val Word32 :--> Val Word32 :--> Eff i i ()
  opName = SPIRV.SyncOp SPIRV.ControlSync
instance PrimOp SPIRV.MemorySync (i :: ProgramState) where
  type PrimOpAugType SPIRV.MemorySync i = Val Word32 :--> Val Word32 :--> Eff i i ()
  opName = SPIRV.SyncOp SPIRV.MemorySync

-- non uniform subgroup instructions
instance ( ScalarTy a, AdditiveMonoid a) => PrimOp SPIRV.GroupAdd '(i :: ProgramState, a) where
    type PrimOpAugType SPIRV.GroupAdd '(i,a) = Val Word32 :--> Val Word32 :--> Val a :--> Eff i i a
    opName = SPIRV.GroupOp $ SPIRV.GroupNumOp SPIRV.GroupAdd (scalarTy @a)
instance ( ScalarTy a, Semiring a) => PrimOp SPIRV.GroupMul '(i :: ProgramState, a)  where
    type PrimOpAugType SPIRV.GroupMul '(i,a) = Val Word32 :--> Val Word32 :--> Val a :--> Eff i i a
    opName = SPIRV.GroupOp $ SPIRV.GroupNumOp SPIRV.GroupMul (scalarTy @a)    
instance ( ScalarTy a, Ord a) => PrimOp SPIRV.GroupMin '(i :: ProgramState, a)  where
    type PrimOpAugType SPIRV.GroupMin '(i,a) = Val Word32 :--> Val Word32 :--> Val a :--> Eff i i a
    opName = SPIRV.GroupOp $ SPIRV.GroupNumOp SPIRV.GroupMin (scalarTy @a)
instance ( ScalarTy a, Ord a) => PrimOp SPIRV.GroupMax '(i :: ProgramState, a)  where
    type PrimOpAugType SPIRV.GroupMax '(i,a) = Val Word32 :--> Val Word32 :--> Val a :--> Eff i i a
    opName = SPIRV.GroupOp $ SPIRV.GroupNumOp SPIRV.GroupMax (scalarTy @a)
instance ( ScalarTy a ) => PrimOp SPIRV.GroupBitwiseAnd '(i :: ProgramState, a) where
    type PrimOpAugType SPIRV.GroupBitwiseAnd '(i,a) = Val Word32 :--> Val Word32 :--> Val a :--> Eff i i a
    opName = SPIRV.GroupOp $ SPIRV.GroupBitwiseOp SPIRV.GroupBitwiseAnd (scalarTy @a)
instance ( ScalarTy a ) => PrimOp SPIRV.GroupBitwiseOr '(i :: ProgramState, a) where
    type PrimOpAugType SPIRV.GroupBitwiseOr '(i,a) = Val Word32 :--> Val Word32 :--> Val a :--> Eff i i a
    opName = SPIRV.GroupOp $ SPIRV.GroupBitwiseOp SPIRV.GroupBitwiseOr (scalarTy @a)
instance ( ScalarTy a ) => PrimOp SPIRV.GroupBitwiseXor '(i :: ProgramState, a) where
    type PrimOpAugType SPIRV.GroupBitwiseXor '(i,a) = Val Word32 :--> Val Word32 :--> Val a :--> Eff i i a
    opName = SPIRV.GroupOp $ SPIRV.GroupBitwiseOp SPIRV.GroupBitwiseXor (scalarTy @a)
instance PrimOp SPIRV.GroupLogicalAnd (i :: ProgramState)  where
    type PrimOpAugType SPIRV.GroupLogicalAnd i = Val Word32 :--> Val Word32 :--> Val Bool :--> Eff i i Bool
    opName = SPIRV.GroupOp $ SPIRV.GroupLogicOp SPIRV.GroupLogicalAnd
instance PrimOp SPIRV.GroupLogicalOr (i :: ProgramState)  where
    type PrimOpAugType SPIRV.GroupLogicalOr i = Val Word32 :--> Val Word32 :--> Val Bool :--> Eff i i Bool
    opName = SPIRV.GroupOp $ SPIRV.GroupLogicOp SPIRV.GroupLogicalOr
instance PrimOp SPIRV.GroupLogicalXor (i :: ProgramState)  where
    type PrimOpAugType SPIRV.GroupLogicalXor i = Val Word32 :--> Val Word32 :--> Val Bool :--> Eff i i Bool
    opName = SPIRV.GroupOp $ SPIRV.GroupLogicOp SPIRV.GroupLogicalXor

-- ray tracing instructions
instance PrimOp SPIRV.RT_ReportIntersection (i :: ProgramState) where
  type PrimOpAugType SPIRV.RT_ReportIntersection i = Val Float :--> Val Word32 :--> Eff i i Bool
  opName = SPIRV.RayOp SPIRV.RT_ReportIntersection
instance PrimOp SPIRV.RT_IgnoreIntersection (i :: ProgramState) where
  type PrimOpAugType SPIRV.RT_IgnoreIntersection i = Eff i i ()
  opName = SPIRV.RayOp SPIRV.RT_IgnoreIntersection
instance PrimOp SPIRV.RT_TerminateRay (i :: ProgramState) where
  type PrimOpAugType SPIRV.RT_TerminateRay i = Eff i i ()
  opName = SPIRV.RayOp SPIRV.RT_TerminateRay
instance PrimOp SPIRV.RT_AccelerationStructureFromDeviceAddress '() where
  type PrimOpAugType SPIRV.RT_AccelerationStructureFromDeviceAddress _ = Val Word64 :--> Val AccelerationStructure
  opName = SPIRV.RayOp SPIRV.RT_AccelerationStructureFromDeviceAddress

-- vector operations
-- doing it by hand because I'm an idiot who doesn't know better

val :: forall n. KnownNat n => Word32
val = fromIntegral ( natVal (Proxy @n) )


instance KnownNat n => PrimOp ('Vectorise SPIRV.BoolOr) (V n Bool) where
  type PrimOpAugType ('Vectorise SPIRV.BoolOr) (V n Bool) = Val (V n Bool) :--> Val (V n Bool) :--> Val (V n Bool)
  op = liftA2 (||)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BoolOr @Bool)) (val @n) SPIRV.Boolean
instance KnownNat n => PrimOp ('Vectorise SPIRV.BoolAnd) (V n Bool) where
  type PrimOpAugType ('Vectorise SPIRV.BoolAnd) (V n Bool) = Val (V n Bool) :--> Val (V n Bool) :--> Val (V n Bool)
  op = liftA2 (&&)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BoolAnd @Bool)) (val @n) SPIRV.Boolean
instance KnownNat n => PrimOp ('Vectorise SPIRV.BoolNot) (V n Bool) where
  type PrimOpAugType ('Vectorise SPIRV.BoolNot) (V n Bool) = Val (V n Bool) :--> Val (V n Bool)
  op = fmap not
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BoolNot @Bool)) (val @n) SPIRV.Boolean

instance ( KnownNat n, PrimTy a, Eq a, Logic a ~ Bool ) => PrimOp ('Vectorise SPIRV.Equal) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Equal) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n Bool)
  op = liftA2 (==)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Equal @a)) (val @n) SPIRV.Boolean
instance ( KnownNat n, PrimTy a, Eq a, Logic a ~ Bool ) => PrimOp ('Vectorise SPIRV.NotEqual) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.NotEqual) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n Bool)
  op = liftA2 (/=)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.NotEqual @a)) (val @n) SPIRV.Boolean

instance (KnownNat n, ScalarTy a, AdditiveMonoid a) => PrimOp ('Vectorise SPIRV.GroupAdd) '(i :: ProgramState, V n a)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupAdd) '(i,V n a) = Val Word32 :--> Val Word32 :--> Val (V n a) :--> Eff i i (V n a)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupAdd @'(i, a))) (val @n) (primTy @a)
instance (KnownNat n, ScalarTy a, Semiring a) => PrimOp ('Vectorise SPIRV.GroupMul) '(i :: ProgramState, V n a)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupMul) '(i,V n a) = Val Word32 :--> Val Word32 :--> Val (V n a) :--> Eff i i (V n a)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupMul @'(i, a))) (val @n) (primTy @a)    
instance (KnownNat n, ScalarTy a, Ord a) => PrimOp ('Vectorise SPIRV.GroupMin) '(i :: ProgramState, V n a)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupMin) '(i,V n a) = Val Word32 :--> Val Word32 :--> Val (V n a) :--> Eff i i (V n a)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupMin @'(i, a))) (val @n) (primTy @a)
instance (KnownNat n, ScalarTy a, Ord a) => PrimOp ('Vectorise SPIRV.GroupMax) '(i :: ProgramState, V n a)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupMax) '(i,V n a) = Val Word32 :--> Val Word32 :--> Val (V n a) :--> Eff i i (V n a)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupMax @'(i, a))) (val @n) (primTy @a)
instance (KnownNat n, ScalarTy a, Bits a) => PrimOp ('Vectorise SPIRV.GroupBitwiseAnd) '(i :: ProgramState, V n a)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupBitwiseAnd) '(i,V n a) = Val Word32 :--> Val Word32 :--> Val (V n a) :--> Eff i i (V n a)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupBitwiseAnd @'(i, a))) (val @n) (primTy @a)
instance (KnownNat n, ScalarTy a, Bits a) => PrimOp ('Vectorise SPIRV.GroupBitwiseOr) '(i :: ProgramState, V n a)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupBitwiseOr) '(i,V n a) = Val Word32 :--> Val Word32 :--> Val (V n a) :--> Eff i i (V n a)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupBitwiseOr @'(i, a))) (val @n) (primTy @a)
instance (KnownNat n, ScalarTy a, Bits a) => PrimOp ('Vectorise SPIRV.GroupBitwiseXor) '(i :: ProgramState, V n a)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupBitwiseXor) '(i,V n a) = Val Word32 :--> Val Word32 :--> Val (V n a) :--> Eff i i (V n a)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupBitwiseXor @'(i, a))) (val @n) (primTy @a)
instance (KnownNat n) => PrimOp ('Vectorise SPIRV.GroupLogicalAnd) '(i :: ProgramState, n :: Nat)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupLogicalAnd) '(i,n) = Val Word32 :--> Val Word32 :--> Val (V n Bool) :--> Eff i i (V n Bool)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupLogicalAnd @i)) (val @n) SPIRV.Boolean
instance (KnownNat n) => PrimOp ('Vectorise SPIRV.GroupLogicalOr) '(i :: ProgramState, n :: Nat)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupLogicalOr) '(i,n) = Val Word32 :--> Val Word32 :--> Val (V n Bool) :--> Eff i i (V n Bool)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupLogicalOr @i)) (val @n) SPIRV.Boolean
instance (KnownNat n) => PrimOp ('Vectorise SPIRV.GroupLogicalXor) '(i :: ProgramState, n :: Nat)  where
  type PrimOpAugType ('Vectorise SPIRV.GroupLogicalXor) '(i,n) = Val Word32 :--> Val Word32 :--> Val (V n Bool) :--> Eff i i (V n Bool)
  opName = SPIRV.VecOp (SPIRV.Vectorise  (opName @_ @_ @SPIRV.GroupLogicalXor @i)) (val @n) SPIRV.Boolean

instance ( KnownNat n, ScalarTy a, Bits a ) => PrimOp ('Vectorise SPIRV.BitAnd) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.BitAnd) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 (.&.)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BitAnd @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Bits a  ) => PrimOp ('Vectorise SPIRV.BitOr) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.BitOr) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 (.|.)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BitOr @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Bits a  ) => PrimOp ('Vectorise SPIRV.BitXor) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.BitXor) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 xor
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BitXor @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Bits a ) => PrimOp ('Vectorise SPIRV.BitNot) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.BitNot) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap complement
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BitNot @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Bits a ) => PrimOp ('Vectorise SPIRV.ReverseBits) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.ReverseBits) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap bitReverse
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.ReverseBits @a)) (val @n) (primTy @a)

instance ( KnownNat n, ScalarTy a, ScalarTy b, BitCast a b ) => PrimOp ('Vectorise SPIRV.CastOp) '(V n a, V n b) where
  type PrimOpAugType ('Vectorise SPIRV.CastOp) '(V n a, V n b) = Val (V n a) :--> Val (V n b)
  op = fmap bitcast
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.CastOp @'(a,b))) (val @n) (primTy @b)

instance ( KnownNat n, ScalarTy b, PrimTy s, BitShift '(b,s) ) => PrimOp ('Vectorise SPIRV.BitShiftRight) '(V n b, V n s) where
  type PrimOpAugType ('Vectorise SPIRV.BitShiftRight) '(V n b, V n s) = Val (V n b) :--> Val (V n s) :--> Val (V n b)
  op = liftA2 shiftR
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BitShiftRight @'(b,s))) (val @n) (primTy @b)
instance ( KnownNat n, ScalarTy b, PrimTy s, BitShift '(b,s) ) => PrimOp ('Vectorise SPIRV.BitShiftLeft) '(V n b, V n s) where
  type PrimOpAugType ('Vectorise SPIRV.BitShiftLeft) '(V n b, V n s) = Val (V n b) :--> Val (V n s) :--> Val (V n b)
  op = liftA2 shiftL
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.BitShiftLeft @'(b,s))) (val @n) (primTy @b)

instance ( KnownNat n, ScalarTy a, AdditiveMonoid a ) => PrimOp ('Vectorise SPIRV.Add) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Add) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 (+)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Add @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, CancellativeAdditiveMonoid a ) => PrimOp ('Vectorise SPIRV.Sub) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Sub) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 (-)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Sub @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, AdditiveGroup a ) => PrimOp ('Vectorise SPIRV.Neg) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Neg) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap negate
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Neg @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Semiring a ) => PrimOp ('Vectorise SPIRV.Mul) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Mul) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 (*)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Mul @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Signed a ) => PrimOp ('Vectorise SPIRV.Abs) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Abs) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap abs
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Abs @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Signed a ) => PrimOp ('Vectorise SPIRV.Sign) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Sign) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap signum
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Sign @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, DivisionRing a ) => PrimOp ('Vectorise SPIRV.Div) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Div) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 (/)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Div @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Archimedean a ) => PrimOp ('Vectorise SPIRV.Mod) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Mod) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 mod
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Mod @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Archimedean a ) => PrimOp ('Vectorise SPIRV.Rem) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Rem) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 rem
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Rem @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Archimedean a ) => PrimOp ('Vectorise SPIRV.Quot) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.Quot) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 div
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Quot @a)) (val @n) (primTy @a)

instance ( KnownNat n, ScalarTy a, ScalarTy b, Convert '(a,b) ) => PrimOp ('Vectorise SPIRV.Convert) '(V n a, V n b) where
  type PrimOpAugType ('Vectorise SPIRV.Convert) '(V n a, V n b) = Val (V n a) :--> Val (V n b)
  op = fmap convert
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.Convert @'(a,b))) (val @n) (primTy @b)
instance ( KnownNat n, ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp ('Vectorise SPIRV.CTruncate) '(V n a, V n b) where
  type PrimOpAugType ('Vectorise SPIRV.CTruncate) '(V n a, V n b) = Val (V n a) :--> Val (V n b)
  op = fmap truncate
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.CTruncate @'(a,b))) (val @n) (primTy @b)
instance ( KnownNat n, ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp ('Vectorise SPIRV.CRound) '(V n a, V n b) where
  type PrimOpAugType ('Vectorise SPIRV.CRound) '(V n a, V n b) = Val (V n a) :--> Val (V n b)
  op = fmap round
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.CRound @'(a,b))) (val @n) (primTy @b)
instance ( KnownNat n, ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp ('Vectorise SPIRV.CFloor) '(V n a, V n b) where
  type PrimOpAugType ('Vectorise SPIRV.CFloor) '(V n a, V n b) = Val (V n a) :--> Val (V n b)
  op = fmap floor
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.CFloor @'(a,b))) (val @n) (primTy @b)
instance ( KnownNat n, ScalarTy a, ScalarTy b, Rounding '(a,b) ) => PrimOp ('Vectorise SPIRV.CCeiling) '(V n a, V n b) where
  type PrimOpAugType ('Vectorise SPIRV.CCeiling) '(V n a, V n b) = Val (V n a) :--> Val (V n b)
  op = fmap ceiling
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.CCeiling @'(a,b))) (val @n) (primTy @b)

instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FSin) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FSin) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap sin
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FSin @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FCos) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FCos) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap cos
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FCos @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FTan) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FTan) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap tan
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FTan @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FAsin) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FAsin) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap asin
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FAsin @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FAcos) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FAcos) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap acos
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FAcos @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FAtan) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FAtan) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap atan
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FAtan @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FSinh) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FSinh) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap sinh
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FSinh @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FCosh) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FCosh) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap cosh
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FCosh @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FTanh) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FTanh) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap tanh
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FTanh @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FAsinh) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FAsinh) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap asinh
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FAsinh @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FAcosh) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FAcosh) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap acosh
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FAcosh @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FAtanh) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FAtanh) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap atanh
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FAtanh @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, RealFloat a ) => PrimOp ('Vectorise SPIRV.FAtan2) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FAtan2) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 atan2
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FAtan2 @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FPow) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FPow) (V n a) = Val (V n a) :--> Val (V n a) :--> Val (V n a)
  op = liftA2 (**)
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FPow @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FExp) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FExp) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap exp
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FExp @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FLog) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FLog) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap log
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FLog @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FSqrt) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FSqrt) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap sqrt
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FSqrt @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp ('Vectorise SPIRV.FInvSqrt) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FInvSqrt) (V n a) = Val (V n a) :--> Val (V n a)
  op = fmap ( recip . sqrt )
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FInvSqrt @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, RealFloat a, Logic a ~ Bool) => PrimOp ('Vectorise SPIRV.FIsNaN) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FIsNaN) (V n a) = Val (V n a) :--> Val (V n Bool)
  op = fmap isNaN
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FIsNaN @a)) (val @n) (primTy @a)
instance ( KnownNat n, ScalarTy a, RealFloat a, Logic a ~ Bool) => PrimOp ('Vectorise SPIRV.FIsInf) (V n a) where
  type PrimOpAugType ('Vectorise SPIRV.FIsInf) (V n a) = Val (V n a) :--> Val (V n Bool)
  op = fmap isInfinite
  opName = SPIRV.VecOp (SPIRV.Vectorise (opName @_ @_ @SPIRV.FIsInf @a)) (val @n) (primTy @a)

instance ( KnownNat n, ScalarTy a, Floating a ) => PrimOp SPIRV.DotV (V n a) where
  type PrimOpAugType SPIRV.DotV (V n a) = Val (V n a) :--> Val (V n a) :--> Val a
  op = dot
  opName = SPIRV.VecOp SPIRV.DotV (val @n) (primTy @a)
-- vector times scalar operation requires floating point type in SPIR-V
instance ( KnownNat n, ScalarTy a, Semiring a, Floating a ) => PrimOp SPIRV.VMulK (V n a) where 
  type PrimOpAugType SPIRV.VMulK (V n a) = Val (V n a) :--> Val a :--> Val (V n a)
  op = (^*)
  opName = SPIRV.VecOp SPIRV.VMulK (val @n) (primTy @a)
instance ( n ~ 3, ScalarTy a, Floating a ) => PrimOp SPIRV.CrossV (V n a) where
  type PrimOpAugType SPIRV.CrossV (V n a) = Val (V 3 a) :--> Val (V 3 a) :--> Val (V 3 a)
  op = cross
  opName = SPIRV.VecOp SPIRV.CrossV 3 (primTy @a)
instance ( KnownNat n, ScalarTy a, Floating a) => PrimOp SPIRV.NormaliseV (V n a) where
  type PrimOpAugType SPIRV.NormaliseV (V n a) = Val (V n a) :--> Val (V n a)
  op = normalise
  opName = SPIRV.VecOp SPIRV.NormaliseV (val @n) (primTy @a)


instance ( KnownNat i, KnownNat j, ScalarTy a, Floating a ) => PrimOp SPIRV.MMulK '(a,i,j) where
  type PrimOpAugType SPIRV.MMulK '(a,i,j) = Val (M i j a) :--> Val a :--> Val (M i j a)
  op = (!*)
  opName = SPIRV.MatOp SPIRV.MMulK (val @i) (val @j) (scalarTy @a)
instance ( KnownNat i, KnownNat j, ScalarTy a, Floating a ) => PrimOp SPIRV.MMulV '(a,i,j) where
  type PrimOpAugType SPIRV.MMulV '(a,i,j) = Val (M i j a) :--> Val (V j a) :--> Val (V i a)
  op = (!*^)
  opName = SPIRV.MatOp SPIRV.MMulV (val @i) (val @j) (scalarTy @a)
instance ( KnownNat i, KnownNat j, ScalarTy a, Floating a ) => PrimOp SPIRV.VMulM '(a,i,j) where
  type PrimOpAugType SPIRV.VMulM '(a,i,j) = Val (V i a) :--> Val (M i j a) :--> Val (V j a)
  op = (^*!)
  opName = SPIRV.MatOp SPIRV.VMulM (val @i) (val @j) (scalarTy @a)
instance ( KnownNat i, KnownNat j, KnownNat k, ScalarTy a, Floating a ) => PrimOp SPIRV.MMulM '(a,i,j,k) where
  type PrimOpAugType SPIRV.MMulM '(a,i,j,k) = Val (M i j a) :--> Val (M j k a) :--> Val (M i k a)
  op = (!*!)
  opName = SPIRV.MatOp SPIRV.MMulM (val @i) (val @k) (scalarTy @a)
instance ( KnownNat i, KnownNat j, ScalarTy a, Floating a ) => PrimOp SPIRV.Transp '(a,i,j) where
  type PrimOpAugType SPIRV.Transp '(a,i,j) = Val (M i j a) :--> Val (M j i a)
  op = transpose
  opName = SPIRV.MatOp SPIRV.Transp (val @j) (val @i) (scalarTy @a)
instance ( KnownNat i, ScalarTy a, Floating a ) => PrimOp SPIRV.Det '(a,i) where
  type PrimOpAugType SPIRV.Det '(a,i) = Val (M i i a) :--> Val a
  op = determinant
  opName = SPIRV.MatOp SPIRV.Det (val @i) (val @i) (scalarTy @a)
instance ( KnownNat i, ScalarTy a, Floating a ) => PrimOp SPIRV.Inv '(a,i) where
  type PrimOpAugType SPIRV.Inv '(a,i) = Val (M i i a) :--> Val (M i i a)
  op = inverse
  opName = SPIRV.MatOp SPIRV.Inv (val @i) (val @i) (scalarTy @a)