packages feed

accelerate-llvm-1.3.0.0: src/Data/Array/Accelerate/LLVM/CodeGen/IR.hs

{-# LANGUAGE GADTs         #-}
{-# LANGUAGE LambdaCase    #-}
{-# LANGUAGE RankNTypes    #-}
{-# LANGUAGE TypeFamilies  #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_HADDOCK hide #-}
-- |
-- Module      : Data.Array.Accelerate.LLVM.CodeGen.IR
-- Copyright   : [2015..2020] The Accelerate Team
-- License     : BSD3
--
-- Maintainer  : Trevor L. McDonell <trevor.mcdonell@gmail.com>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)
--

module Data.Array.Accelerate.LLVM.CodeGen.IR (

  Operands(..),
  IROP(..),

) where

import LLVM.AST.Type.Name
import LLVM.AST.Type.Operand
import LLVM.AST.Type.Representation

import Data.Array.Accelerate.Error
import Data.Primitive.Vec

import qualified Data.ByteString.Short                              as B


-- We use a data family to represent sequences of LLVM (scalar) operands
-- representing a single Accelerate type. Using a data family rather than a type
-- family means that Operands is bijective.
--
data family Operands e :: *
data instance Operands ()         = OP_Unit
data instance Operands Int        = OP_Int     (Operand Int)
data instance Operands Int8       = OP_Int8    (Operand Int8)
data instance Operands Int16      = OP_Int16   (Operand Int16)
data instance Operands Int32      = OP_Int32   (Operand Int32)
data instance Operands Int64      = OP_Int64   (Operand Int64)
data instance Operands Word       = OP_Word    (Operand Word)
data instance Operands Word8      = OP_Word8   (Operand Word8)
data instance Operands Word16     = OP_Word16  (Operand Word16)
data instance Operands Word32     = OP_Word32  (Operand Word32)
data instance Operands Word64     = OP_Word64  (Operand Word64)
data instance Operands Half       = OP_Half    (Operand Half)
data instance Operands Float      = OP_Float   (Operand Float)
data instance Operands Double     = OP_Double  (Operand Double)
data instance Operands Bool       = OP_Bool    (Operand Bool)
data instance Operands (Vec n a)  = OP_Vec     (Operand (Vec n a))
data instance Operands (a,b)      = OP_Pair    (Operands a) (Operands b)


-- | Given some evidence that 'IR a' represents a scalar type, it can be
-- converted between the IR and Operand data types.
--
class IROP dict where
  op :: HasCallStack => dict a -> Operands a -> Operand a
  ir :: HasCallStack => dict a -> Operand a -> Operands a

instance IROP Type where
  ir VoidType     _ = OP_Unit
  ir (PrimType t) x = ir t x

  op VoidType     _ = LocalReference VoidType (Name B.empty)
  op (PrimType t) x = op t x

instance IROP PrimType where
  op (ScalarPrimType t) = op t
  op BoolPrimType       = \case OP_Bool x -> x
  op t                  = internalError ("unhandled type: " ++ show t)
  ir (ScalarPrimType t) = ir t
  ir BoolPrimType       = OP_Bool
  ir t                  = internalError ("unhandled type: " ++ show t)

instance IROP ScalarType where
  op (SingleScalarType t) = op t
  op (VectorScalarType t) = op t
  ir (SingleScalarType t) = ir t
  ir (VectorScalarType t) = ir t

instance IROP SingleType where
  op (NumSingleType t) = op t
  ir (NumSingleType t) = ir t

instance IROP VectorType where
  op (VectorType _ v) = single v
    where
      single :: SingleType t -> Operands (Vec n t) -> Operand (Vec n t)
      single (NumSingleType t) = num t

      num :: NumType t -> Operands (Vec n t) -> Operand (Vec n t)
      num (IntegralNumType t) = integral t
      num (FloatingNumType t) = floating t

      integral :: IntegralType t -> Operands (Vec n t) -> Operand (Vec n t)
      integral TypeInt    (OP_Vec x) = x
      integral TypeInt8   (OP_Vec x) = x
      integral TypeInt16  (OP_Vec x) = x
      integral TypeInt32  (OP_Vec x) = x
      integral TypeInt64  (OP_Vec x) = x
      integral TypeWord   (OP_Vec x) = x
      integral TypeWord8  (OP_Vec x) = x
      integral TypeWord16 (OP_Vec x) = x
      integral TypeWord32 (OP_Vec x) = x
      integral TypeWord64 (OP_Vec x) = x

      floating :: FloatingType t -> Operands (Vec n t) -> Operand (Vec n t)
      floating TypeHalf   (OP_Vec x) = x
      floating TypeFloat  (OP_Vec x) = x
      floating TypeDouble (OP_Vec x) = x

  ir (VectorType _ v) = single v
    where
      single :: SingleType t -> Operand (Vec n t) -> Operands (Vec n t)
      single (NumSingleType t) = num t

      num :: NumType t -> Operand (Vec n t) -> Operands (Vec n t)
      num (IntegralNumType t) = integral t
      num (FloatingNumType t) = floating t

      integral :: IntegralType t -> Operand (Vec n t) -> Operands (Vec n t)
      integral TypeInt    = OP_Vec
      integral TypeInt8   = OP_Vec
      integral TypeInt16  = OP_Vec
      integral TypeInt32  = OP_Vec
      integral TypeInt64  = OP_Vec
      integral TypeWord   = OP_Vec
      integral TypeWord8  = OP_Vec
      integral TypeWord16 = OP_Vec
      integral TypeWord32 = OP_Vec
      integral TypeWord64 = OP_Vec

      floating :: FloatingType t -> Operand (Vec n t) -> Operands (Vec n t)
      floating TypeHalf   = OP_Vec
      floating TypeFloat  = OP_Vec
      floating TypeDouble = OP_Vec

instance IROP NumType where
  op (IntegralNumType t) = op t
  op (FloatingNumType t) = op t
  ir (IntegralNumType t) = ir t
  ir (FloatingNumType t) = ir t

instance IROP IntegralType where
  op TypeInt     (OP_Int     x) = x
  op TypeInt8    (OP_Int8    x) = x
  op TypeInt16   (OP_Int16   x) = x
  op TypeInt32   (OP_Int32   x) = x
  op TypeInt64   (OP_Int64   x) = x
  op TypeWord    (OP_Word    x) = x
  op TypeWord8   (OP_Word8   x) = x
  op TypeWord16  (OP_Word16  x) = x
  op TypeWord32  (OP_Word32  x) = x
  op TypeWord64  (OP_Word64  x) = x
  --
  ir TypeInt     = OP_Int
  ir TypeInt8    = OP_Int8
  ir TypeInt16   = OP_Int16
  ir TypeInt32   = OP_Int32
  ir TypeInt64   = OP_Int64
  ir TypeWord    = OP_Word
  ir TypeWord8   = OP_Word8
  ir TypeWord16  = OP_Word16
  ir TypeWord32  = OP_Word32
  ir TypeWord64  = OP_Word64

instance IROP FloatingType where
  op TypeHalf   (OP_Half   x) = x
  op TypeFloat  (OP_Float  x) = x
  op TypeDouble (OP_Double x) = x
  --
  ir TypeHalf   = OP_Half
  ir TypeFloat  = OP_Float
  ir TypeDouble = OP_Double