fir-0.1.0.0: src/FIR/ProgramState.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-|
Module: FIR.ProgramState
Defines the type-level data used for the state of the indexed monad used to construct programs:
> program :: Program (i :: ProgramState) (j :: ProgramState) (a :: Type)
See "FIR.Module.Program".
The program state consists of:
* the bindings that are in scope (such as built-in variables or user-defined variables),
* the function context (whether the current code is contained within a function/entry-point, or is at the top-level),
* information associated to the functions and entry-points relevant to the program,
such as whether they have been defined yet or only declared.
* the data of which SPIR-V backend we are using: Vulkan or OpenCL.
-}
module FIR.ProgramState where
-- base
import Data.Kind
( Type )
import Data.Word
( Word32 )
import GHC.TypeLits
( Symbol, KnownSymbol
, TypeError, ErrorMessage(..)
)
import GHC.TypeNats
( Nat )
-- text-short
import Data.Text.Short
( ShortText )
-- fir
import Data.Type.Known
( Demotable(Demote)
, Known(known), knownValue
)
import Data.Type.Map
( Map, (:->) )
import FIR.Binding
( BindingsMap
, Permissions
)
import FIR.Prim.RayTracing
( RayQueryState )
import FIR.Prim.Types
( KnownVars(knownVars) )
import qualified SPIRV.Control as SPIRV
import qualified SPIRV.Decoration as SPIRV
import qualified SPIRV.PrimTy as SPIRV
( PrimTy )
import qualified SPIRV.Stage as SPIRV
import qualified SPIRV.Storage as SPIRV
-------------------------------------------------------------------
-- | Data (kind) used to keep track of function context at the type-level.
data FunctionContext lit nat bindings mbIface where
TopLevel :: FunctionContext lit nat bindings iface
InFunction :: lit -> bindings -> FunctionContext lit nat bindings mbIface
InEntryPoint
:: lit
-> SPIRV.ExecutionInfo nat em
-> mbIface
-> FunctionContext lit nat bindings mbIface
deriving stock instance ( Show lit, Show bindings, Show nat, Show mbIface )
=> Show ( FunctionContext lit nat bindings mbIface )
type InterfaceVariable nat ty = ([SPIRV.Decoration nat], ty)
type TLInterfaceVariable = InterfaceVariable Nat Type
type VLInterfaceVariable = InterfaceVariable Word32 SPIRV.PrimTy
type TLInterface
= [ SPIRV.StorageClass :-> [ Symbol :-> TLInterfaceVariable ] ]
type VLInterface
= [ SPIRV.StorageClass :-> [ ShortText :-> VLInterfaceVariable ] ]
-- | A type-level function context.
type TLFunctionContext
= FunctionContext
Symbol
Nat
BindingsMap
( Maybe TLInterface )
-- | A value-level function context.
type VLFunctionContext
= FunctionContext
ShortText
Word32
[ ( ShortText, (SPIRV.PrimTy, Permissions) ) ]
( Maybe VLInterface )
instance Demotable TLFunctionContext where
type Demote TLFunctionContext = VLFunctionContext
instance Known TLFunctionContext 'TopLevel where
known = TopLevel
instance ( KnownVars args
, KnownSymbol fnName
)
=> Known TLFunctionContext ('InFunction fnName args) where
known = InFunction
( knownValue @fnName )
( knownVars @args )
instance ( Known (SPIRV.ExecutionInfo Nat stage) stageInfo
, KnownSymbol stageName
)
=> Known TLFunctionContext
( 'InEntryPoint
stageName
( stageInfo :: SPIRV.ExecutionInfo Nat stage )
('Just iface)
) where
known = InEntryPoint
( knownValue @stageName )
( knownValue @stageInfo )
Nothing
data Definedness
= Declared
| Defined
-- | Keeps track of a function at the type level.
data FunctionInfo where
FunctionInfo
:: BindingsMap
-> Type
-> SPIRV.FunctionControl
-> Definedness
-> FunctionInfo
-- | Keeps track of an entry point at the type level:
--
-- - a type level 'SPIRV.ExecutionInfo' recording the stage as well as additional
-- stage information,
-- - the entry point interface (input/output variables which it uses),
-- (or Nothing if the interface has not yet been computed).
data EntryPointInfo where
EntryPointInfo
:: SPIRV.ExecutionInfo Nat stage
-> TLInterface
-> Definedness
-> EntryPointInfo
newtype CFGState = CFGState { loopDepth :: Nat }
-- | State that is used in the user-facing indexed monad (at the type level).
-- Consists of:
--
-- - a type-level list of which bindings are in scope,
-- such as user-defined functions, user-defined variables
-- and built-in variables,
-- - a context – whether code in the current indexed monadic state
-- occurs inside a function or entry-point body –
-- - the current control-flow state,
-- - which functions are to be declared,
-- whether they have been declared yet,
-- and some further information (arguments, function control),
-- - which entry points are to be declared,
-- whether they have been declared yet, together with
-- some additional info pertaining to their respective execution modes,
-- and their interfaces (user defined inputs/outputs),
-- - the state of all current ray-query operations,
-- - which SPIR-V backend is being used (Vulkan or OpenCL).
data ProgramState
= ProgramState
{ bindings :: BindingsMap
, context :: TLFunctionContext
, cfgState :: CFGState
, functions :: Map Symbol FunctionInfo
, entryPoints :: Map Symbol EntryPointInfo
, interface :: TLInterface
, rayQueries :: Map Symbol RayQueryState
, backend :: SPIRV.Backend
}
type family Bindings ( s :: ProgramState ) :: BindingsMap where
Bindings ('ProgramState bds _ _ _ _ _ _ _) = bds
type family CFGInfo ( s :: ProgramState ) :: CFGState where
CFGInfo ('ProgramState _ _ cfg _ _ _ _ _) = cfg
type family FunctionInfos ( s :: ProgramState ) :: Map Symbol FunctionInfo where
FunctionInfos ('ProgramState _ _ _ fs _ _ _ _) = fs
type family EntryPointInfos ( s :: ProgramState ) :: Map Symbol EntryPointInfo where
EntryPointInfos ('ProgramState _ _ _ _ eps _ _ _) = eps
type family ExecutionContext ( s :: ProgramState ) :: Maybe SPIRV.ExecutionModel where
ExecutionContext ('ProgramState _ ('InEntryPoint _ (info :: SPIRV.ExecutionInfo Nat stage) _) _ _ _ _ _ _)
= Just stage
ExecutionContext _
= Nothing
type family RayQueries ( s :: ProgramState ) :: Map Symbol RayQueryState where
RayQueries ('ProgramState _ _ _ _ _ _ rayQueries _) = rayQueries
executionContext :: VLFunctionContext -> Maybe (ShortText, SPIRV.ExecutionModel)
executionContext (InEntryPoint stageName stageInfo _) = Just (stageName, SPIRV.modelOf stageInfo)
executionContext _ = Nothing
type family ExecutionContext' ( s :: ProgramState ) :: SPIRV.ExecutionModel where
ExecutionContext' ('ProgramState _ ('InEntryPoint _ (info :: SPIRV.ExecutionInfo Nat stage) _) _ _ _ _ _ _)
= stage
ExecutionContext' _
= TypeError
( Text "Cannot access stage context: not within a stage." )
type family ExecutionInfoContext
( s :: ProgramState )
:: Maybe (SPIRV.ExecutionInfo Nat (ExecutionContext' s))
where
ExecutionInfoContext ('ProgramState _ ('InEntryPoint _ info _) _ _ _ _ _ _)
= Just info
ExecutionInfoContext _ = 'Nothing