packages feed

accelerate-llvm-1.4.0.0: src/LLVM/AST/Type/GetElementPtr.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# OPTIONS_HADDOCK hide #-}
module LLVM.AST.Type.GetElementPtr where

import LLVM.AST.Type.Downcast
import LLVM.AST.Type.Representation


-- | A @getelementptr@ instruction. The @op@ parameter is the type of operands
-- (in practice, 'LLVM.AST.Type.Operand.Operand' or
-- 'LLVM.AST.Type.Constant.Constant'). The @ptra@ and @ptrb@ type indices are
-- the input and output /pointer/ type.
--
-- The type of indices is unconstrained, which is more flexible than reality,
-- and the kind of operands must be uniform, which is /less/ flexible than
-- reality. Reality is quite cumbersome:
-- * When indexing into a structure (currently unsupported by this data type),
--   the index type must be @i32@ and its value must be constant.
-- * When indexing into an array, the index type may be any /integral/ type,
--   signed or unsigned, which are then treated as signed integers.
--
-- <https://llvm.org/docs/LangRef.html#getelementptr-instruction>
data GetElementPtr op ptra ptrb where
  GEP :: Type a
      -> op (Ptr a)
      -> op i             -- ^ the offset to the initial pointer (counted in pointees, not in bytes)
      -> GEPIndex op a b  -- ^ field/index selection path
      -> GetElementPtr op (Ptr a) (Ptr b)

-- | A convenience pattern synonym for the common case of a full path of length 1.
pattern GEP1 :: ScalarType a -> op (Ptr a) -> op i -> GetElementPtr op (Ptr a) (Ptr a)
pattern GEP1 ty ptr ix <- GEP (PrimType (ScalarPrimType ty)) ptr ix (GEPEmpty (ScalarPrimType _))
  where GEP1 ty ptr ix = GEP (PrimType (ScalarPrimType ty)) ptr ix (GEPEmpty (ScalarPrimType ty))

-- | An index sequence that goes from a 'Ptr a' to a 'Ptr b'. Note that this
-- data type is indexed with the base types of the pointers, not the pointer
-- types themselves.
data GEPIndex op a b where
  GEPEmpty :: PrimType b -> GEPIndex op b b
  GEPArray :: op i       -> GEPIndex op a b -> GEPIndex op (LLArray a) b
  -- TODO: structure indexing

instance (forall i. Downcast (op i) v) => Downcast (GEPIndex op a b) [v] where
  downcast (GEPEmpty _) = []
  downcast (GEPArray i l) = downcast i : downcast l

gepIndexOutType :: GEPIndex op a b -> PrimType b
gepIndexOutType (GEPEmpty t) = t
gepIndexOutType (GEPArray _ l) = gepIndexOutType l

instance TypeOf op => TypeOf (GetElementPtr op ptra) where
  typeOf (GEP _ p _ path) =
    case typeOf p of
      PrimType (PtrPrimType _ addr) -> PrimType (PtrPrimType (gepIndexOutType path) addr)
      _ -> error "Pointer type is not a pointer type"