fir-0.1.0.0: src/CodeGen/PrimOps.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-|
Module: CodeGen.PrimOps
Code generation for primitive operations (e.g. arithmetic operations).
-}
module CodeGen.PrimOps
( primOp, operationInstruction )
where
-- base
import Control.Monad
( when )
import Data.Foldable
( for_ )
import Data.Proxy
( Proxy )
-- lens
import Control.Lens
( view )
-- mtl
import Control.Monad.Except
( throwError )
-- text-short
import qualified Data.Text.Short as ShortText
( pack )
-- fir
import CodeGen.Application
( Application(Applied)
, traverseASTs
)
import CodeGen.Binary
( instruction )
import {-# SOURCE #-} CodeGen.CodeGen
( CodeGen(codeGenArgs), codeGen )
import CodeGen.Debug
( whenAsserting )
import CodeGen.IDs
( typeID )
import CodeGen.Instruction
( toArgs
, ID(ID)
, Instruction(..)
)
import CodeGen.Monad
( CGMonad, MonadFresh(fresh) )
import CodeGen.State
( _backend, _spirvVersion, requireCapabilities, requireExtensions )
import FIR.AST
( AST, PrimOpF(..) )
import FIR.AST.Type
( Nullary )
import FIR.Prim.Op
( PrimOp(opName) )
import qualified SPIRV.PrimOp as SPIRV
import qualified SPIRV.PrimTy as SPIRV
import qualified SPIRV.Requirements as SPIRV
import qualified SPIRV.Operation as SPIRV
( Operation )
import qualified SPIRV.Version as SPIRV
----------------------------------------------------------------------------
-- primops
instance CodeGen AST => CodeGen (PrimOpF AST) where
codeGenArgs ( Applied ( PrimOpF ( _ :: Proxy a ) ( _ :: Proxy op ) ) as ) =
primOp ( opName @_ @_ @op @a ) =<< traverseASTs @Nullary codeGen as
primOp :: SPIRV.PrimOp -> [ (ID, SPIRV.PrimTy) ] -> CGMonad (ID, SPIRV.PrimTy)
primOp prim as = do
bk <- view _backend
let
op :: SPIRV.Operation
retTy :: SPIRV.PrimTy
(op, retTy) = SPIRV.opAndReturnType bk prim
minVer :: SPIRV.Version
minVer = SPIRV.primOpMinVersion bk prim
requireCapabilities $ SPIRV.primOpCapabilities bk prim
requireExtensions $ SPIRV.primOpExtensions bk prim
ver <- view _spirvVersion
whenAsserting . when ( ver < minVer ) . throwError $
"primOp: operation " <> ShortText.pack ( show prim ) <> "\n\
\requires SPIR-V version " <> ShortText.pack ( show minVer ) <> ",\n\
\but current version is " <> ShortText.pack ( show ver ) <> "."
whenAsserting . for_ ( SPIRV.primOpUnsupported bk prim ) $ \ reason ->
throwError $
"primOp: operation " <> ShortText.pack ( show prim ) <> " is not supported:\n"
<> ShortText.pack reason <> "."
operationInstruction op retTy ( map fst as )
operationInstruction :: SPIRV.Operation -> SPIRV.PrimTy -> [ ID ] -> CGMonad (ID, SPIRV.PrimTy)
operationInstruction op retTy as = case retTy of
SPIRV.Unit -> do
instruction
Instruction
{ operation = op
, resTy = Nothing
, resID = Nothing
, args = toArgs as
}
pure (ID 0, retTy) -- ID should not be used
_ -> do
resTyID <- typeID retTy
v <- fresh
instruction
Instruction
{ operation = op
, resTy = Just resTyID
, resID = Just v
, args = toArgs as
}
pure (v, retTy)