{-# LANGUAGE MultiWayIf #-}

module GHC.HsToCore.Foreign.Utils
  ( Binding
  , getPrimTyOf
  , primTyDescChar
  , ppPrimTyConStgType
  )
where

import GHC.Prelude

import GHC.Platform

import GHC.Tc.Utils.TcType

import GHC.Core (CoreExpr)
import GHC.Core.DataCon
import GHC.Core.TyCon
import GHC.Core.TyCo.Rep

import GHC.Types.Id
import GHC.Types.RepType

import GHC.Builtin.Types
import GHC.Builtin.Types.Prim

import GHC.Utils.Outputable
import GHC.Utils.Panic

type Binding = (Id, CoreExpr) -- No rec/nonrec structure;
                              -- the occurrence analyser will sort it all out

-- This function returns the primitive type associated with the boxed
-- type argument to a foreign export (eg. Int ==> Int#).
getPrimTyOf :: Type -> UnaryType
getPrimTyOf :: Type -> Type
getPrimTyOf Type
ty
  | Type -> Bool
isBoolTy Type
rep_ty = Type
intPrimTy
  -- Except for Bool, the types we are interested in have a single constructor
  -- with a single primitive-typed argument (see TcType.legalFEArgTyCon).
  | Bool
otherwise =
  case Type -> Maybe (TyCon, [Type], DataCon, [Scaled Type])
splitDataProductType_maybe Type
rep_ty of
     Just (TyCon
_, [Type]
_, DataCon
data_con, [Scaled Type
_ Type
prim_ty]) ->
        Bool -> Type -> Type
forall a. HasCallStack => Bool -> a -> a
assert (DataCon -> Arity
dataConSourceArity DataCon
data_con Arity -> Arity -> Bool
forall a. Eq a => a -> a -> Bool
== Arity
1) (Type -> Type) -> Type -> Type
forall a b. (a -> b) -> a -> b
$
        Bool -> SDoc -> Type -> Type
forall a. HasCallStack => Bool -> SDoc -> a -> a
assertPpr (HasDebugCallStack => Type -> Bool
Type -> Bool
isUnliftedType Type
prim_ty) (Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr Type
prim_ty)
          -- NB: it's OK to call isUnliftedType here, as we don't allow
          -- representation-polymorphic types in foreign import/export declarations
        Type
prim_ty
     Maybe (TyCon, [Type], DataCon, [Scaled Type])
_other -> String -> SDoc -> Type
forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"getPrimTyOf" (Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr Type
ty)
  where
        rep_ty :: Type
rep_ty = Type -> Type
unwrapType Type
ty

-- represent a primitive type as a Char, for building a string that
-- described the foreign function type.  The types are size-dependent,
-- e.g. 'W' is a signed 32-bit integer.
primTyDescChar :: Platform -> Type -> Char
primTyDescChar :: Platform -> Type -> Char
primTyDescChar !Platform
platform Type
ty
 | Type
ty Type -> Type -> Bool
`eqType` Type
unitTy = Char
'v'
 | Bool
otherwise
 = case HasDebugCallStack => Type -> PrimRep
Type -> PrimRep
typePrimRepU (Type -> Type
getPrimTyOf Type
ty) of
     PrimRep
IntRep      -> Char
signed_word
     PrimRep
WordRep     -> Char
unsigned_word
     PrimRep
Int8Rep     -> Char
'B'
     PrimRep
Word8Rep    -> Char
'b'
     PrimRep
Int16Rep    -> Char
'S'
     PrimRep
Word16Rep   -> Char
's'
     PrimRep
Int32Rep    -> Char
'W'
     PrimRep
Word32Rep   -> Char
'w'
     PrimRep
Int64Rep    -> Char
'L'
     PrimRep
Word64Rep   -> Char
'l'
     PrimRep
AddrRep     -> Char
'p'
     PrimRep
FloatRep    -> Char
'f'
     PrimRep
DoubleRep   -> Char
'd'
     PrimRep
_           -> String -> SDoc -> Char
forall a. HasCallStack => String -> SDoc -> a
pprPanic String
"primTyDescChar" (Type -> SDoc
forall a. Outputable a => a -> SDoc
ppr Type
ty)
  where
    (Char
signed_word, Char
unsigned_word) = case Platform -> PlatformWordSize
platformWordSize Platform
platform of
      PlatformWordSize
PW4 -> (Char
'W',Char
'w')
      PlatformWordSize
PW8 -> (Char
'L',Char
'l')

-- | Printed C Type to be used with CAPI calling convention
ppPrimTyConStgType :: TyCon -> Maybe String
ppPrimTyConStgType :: TyCon -> Maybe String
ppPrimTyConStgType TyCon
tc =
  if | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
charPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgChar"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
intPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgInt"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
int8PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgInt8"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
int16PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgInt16"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
int32PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgInt32"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
int64PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgInt64"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
wordPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgWord"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
word8PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgWord8"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
word16PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgWord16"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
word32PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgWord32"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
word64PrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgWord64"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
floatPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgFloat"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
doublePrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgDouble"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
addrPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgAddr"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
stablePtrPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgStablePtr"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
arrayPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"const StgAddr"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
mutableArrayPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgAddr"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
byteArrayPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"const StgAddr"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
mutableByteArrayPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgAddr"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
smallArrayPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"const StgAddr"
     | TyCon
tc TyCon -> TyCon -> Bool
forall a. Eq a => a -> a -> Bool
== TyCon
smallMutableArrayPrimTyCon -> String -> Maybe String
forall a. a -> Maybe a
Just String
"StgAddr"
     | Bool
otherwise -> Maybe String
forall a. Maybe a
Nothing