fir-0.1.0.0: src/FIR/Validation/Interface.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-|
Module: FIR.Validation.Interface
Validates the layout of individual entry point input/output interfaces.
For instance:
* inputs/outputs in entry point interfaces must not overlap,
* types within a location must use a consistent base type,
e.g. a 'Float' and a 'Word32' cannot share a location.
-}
module FIR.Validation.Interface
( ValidInterface )
where
-- base
import Data.Kind
( Type, Constraint )
import GHC.TypeLits
( Symbol
, TypeError, ErrorMessage(..)
)
import GHC.TypeNats
( Nat )
-- fir
import Data.Type.Map
( (:->)((:->)), Lookup )
import Data.Type.Maybe
( SequenceMaybe )
import FIR.Prim.Struct
( LocationSlot(LocationSlot) )
import FIR.ProgramState
( TLInterfaceVariable
, EntryPointInfo(EntryPointInfo)
)
import FIR.Validation.Arrayness
( IsPatchVariable(..), ImplicitArrayness(..)
, Arrayness, RemoveArrayness
)
import FIR.Validation.Layout
( ValidLayout )
import qualified SPIRV.Decoration as SPIRV
( Decoration(..) )
import qualified SPIRV.Stage as SPIRV
( ExecutionModel(..), ExecutionInfo(..) )
import qualified SPIRV.Storage as SPIRV
( StorageClass(Input,Output) )
------------------------------------------------------------------------
type family ValidInterface ( epName :: Symbol ) ( nfo :: EntryPointInfo ) :: Constraint where
ValidInterface epName ( 'EntryPointInfo xNfo globals _ )
= ( ValidLayout ( LocationSlotsFromDecorations epName xNfo SPIRV.Input ( SequenceMaybe ( Lookup SPIRV.Input globals ) ) )
, ValidLayout ( LocationSlotsFromDecorations epName xNfo SPIRV.Output ( SequenceMaybe ( Lookup SPIRV.Output globals ) ) )
)
type family LocationSlotsFromDecorations
( emName :: Symbol )
( xNfo :: SPIRV.ExecutionInfo Nat em )
( inOut :: SPIRV.StorageClass )
( globals :: [ Symbol :-> TLInterfaceVariable ] )
:: [ LocationSlot Nat :-> Type ]
where
LocationSlotsFromDecorations _ _ _ '[] = '[]
LocationSlotsFromDecorations
emName ( xNfo :: SPIRV.ExecutionInfo Nat em )
inOut ( ( varName ':-> '(decs, ty) ) ': globals )
= AddLocationSlotIfNecessary varName ty decs emName em inOut
( Arrayness inOut decs xNfo )
( LocationSlotsFromDecorations emName xNfo inOut globals )
type family AddLocationSlotIfNecessary
( varName :: Symbol )
( ty :: Type )
( decs :: [ SPIRV.Decoration Nat ] )
( emName :: Symbol )
( em :: SPIRV.ExecutionModel )
( inOut :: SPIRV.StorageClass )
( arrayness :: ImplicitArrayness )
( slots :: [ LocationSlot Nat :-> Type ] )
:: [ LocationSlot Nat :-> Type ]
where
AddLocationSlotIfNecessary _ _ _ _ _ _ ('NoImplicitArrayness 'IsPatch) slots
-- ignore patch variables
= slots
-- otherwise, add the located type (after removing the implicit arrayness)
AddLocationSlotIfNecessary varName ty decs emName em inOut arrayness slots
= AddLocationSlot varName
( RemoveArrayness varName inOut emName em ty arrayness )
( LocationDecorations decs )
slots
type family AddLocationSlot
( k :: Symbol )
( ty :: Type )
( locInfo :: ( [Nat], [Nat] ) )
( slots :: [ LocationSlot Nat :-> Type ] )
:: [ LocationSlot Nat :-> Type ]
where
AddLocationSlot k ty locInfo slots
= ( LocationSlotFromDecorations k locInfo ':-> ty ) ': slots
type family LocationSlotFromDecorations
( k :: Symbol )
( locInfo :: ( [Nat], [Nat] ) )
:: LocationSlot Nat
where
LocationSlotFromDecorations _ '( '[l] , '[c] )
= 'LocationSlot l c
LocationSlotFromDecorations _ '( '[l] , '[] )
= 'LocationSlot l 0
LocationSlotFromDecorations k '( '[l] , cs )
= TypeError
( Text "Global named " :<>: ShowType k
:<>: Text " has more than one 'Component' decoration:"
:$$: ShowType cs
)
LocationSlotFromDecorations k '( '[] , _ )
= TypeError
( Text "Global named " :<>: ShowType k
:<>: Text " is missing a 'Location' decoration."
)
LocationSlotFromDecorations k '( ls , _ )
= TypeError
( Text "Global named " :<>: ShowType k
:<>: Text " has more than one 'Location' decoration:"
:$$: ShowType ls
)
type family LocationDecorations
( decs :: [SPIRV.Decoration Nat] )
:: ( [Nat], [Nat] )
where
LocationDecorations '[] = '( '[], '[] )
LocationDecorations ( SPIRV.Location l ': decs )
= CombineLocations '( Just l, 'Nothing ) ( LocationDecorations decs )
LocationDecorations ( SPIRV.Component c ': decs )
= CombineLocations '( 'Nothing, 'Just c ) ( LocationDecorations decs )
LocationDecorations ( _ ': decs ) = LocationDecorations decs
type family CombineLocations
( lc :: ( Maybe Nat, Maybe Nat ) )
( lcs :: ( [Nat], [Nat] ) )
:: ( [Nat], [Nat] )
where
CombineLocations '(Just l, Just c) '(ls, cs) = '( l ': ls, c ': cs )
CombineLocations '(Just l, _ ) '(ls, cs) = '( l ': ls, cs )
CombineLocations '(_ , Just c) '(ls, cs) = '( ls, c ': cs )
CombineLocations _ lcs = lcs