module UHC.Light.Compiler.Core.FFI
( tyNmFFIBoxBasicAnnot
, tyNmGBMayLiveAsTaggedPtr, tyNmGBTagPtrBasicAnnot
, ffiMkArgUnpack
, ffiMkResPack
, ffiEvalAdapt
, ffiCoreEvalAdapt
, ffiCoreMk
, ffeCoreMk
, ffiMbIORes
, ffiIOAdapt
, ffiCoreIOAdapt )
where
import UHC.Light.Compiler.Base.HsName.Builtin
import UHC.Light.Compiler.CodeGen.BuiltinSizeInfo
import UHC.Light.Compiler.Opts
import UHC.Light.Compiler.Base.Target
import UHC.Light.Compiler.Base.Common
import UHC.Light.Compiler.Base.TermLike
import qualified Data.Map as Map
import Data.List
import Data.Maybe
import UHC.Light.Compiler.CodeGen.BasicAnnot
import UHC.Light.Compiler.Ty
import UHC.Light.Compiler.Gam.DataGam
import UHC.Light.Compiler.AbstractCore
import UHC.Light.Compiler.Core
import UHC.Light.Compiler.Core.Utils
import qualified UHC.Light.Compiler.Core.SysF.AsTy as SysF
import UHC.Light.Compiler.Foreign.Extract
import UHC.Light.Compiler.Foreign.Boxing
import UHC.Light.Compiler.CodeGen.BuiltinPrims
tyNmFFIBoxBasicAnnot :: EHCOpts -> HsName -> Maybe BasicAnnot
tyNmFFIBoxBasicAnnot opts
= const Nothing
tyNmGBMayLiveAsTaggedPtr :: EHCOpts -> HsName -> Maybe BuiltinInfo
tyNmGBMayLiveAsTaggedPtr opts
| otherwise = const Nothing
tyNmGBTagPtrBasicAnnot :: EHCOpts -> Bool -> HsName -> BasicAnnot -> BasicAnnot
tyNmGBTagPtrBasicAnnot opts box t annot
= case tyNmGBMayLiveAsTaggedPtr opts t of
Just x
| otherwise -> annot
Nothing -> annot
ffiMkArgUnpack
:: EHCOpts
-> DataGam
-> (HsName -> BasicAnnot -> HsName -> intro)
-> (HsName -> HsName -> intro)
-> (HsName -> HsName -> intro)
-> (HsName -> HsName -> intro)
-> (HsName -> HsName -> intro)
-> HsName
-> Ty
-> intro
ffiMkArgUnpack
opts dataGam
mkNodeI mkEnumI mkVarI mkOpaqI mkPtrI
argNm ty
= mk
where tyNm = tyAppFunConNm ty
mbAnn = tyNmFFIBoxBasicAnnot opts tyNm
mk | isJust mbAnn = mkNodeI tyNm (tyNmGBTagPtrBasicAnnot opts False tyNm (fromJust mbAnn)) argNm
| tyNmIsFFIEnumable dataGam tyNm = mkEnumI tyNm argNm
| isJust (recMbRecRow ty) = mkVarI tyNm argNm
| tyNmIsFFIOpaque dataGam tyNm = mkOpaqI tyNm argNm
| otherwise = mkPtrI tyNm argNm
ffiMkResPack
:: EHCOpts
-> DataGam
-> (BasicAnnot -> HsName -> intro)
-> (HsName -> HsName -> intro)
-> (HsName -> intro)
-> (HsName -> HsName -> intro)
-> (e -> intro -> e -> e)
-> (Ty -> HsName -> HsName -> e)
-> (Ty -> HsName -> HsName -> e)
-> (Ty -> HsName -> HsName -> e)
-> (Ty -> HsName -> HsName -> e)
-> HsName
-> Ty
-> e
-> e
ffiMkResPack
opts dataGam
mkNodeI mkEnumI mkOpaqI mkPtrI
mkBindE
mkNodeE mkEnumE mkOpaqE mkPtrE
resNm resTy res
= mk
where resTyNm = tyAppFunConNm resTy
mbAnn = tyNmFFIBoxBasicAnnot opts resTyNm
mkE e = e resTy resTyNm resNm
mk | isJust mbAnn = mkBindE res (mkNodeI (tyNmGBTagPtrBasicAnnot opts True resTyNm (fromJust mbAnn)) resNm) (mkE mkNodeE)
| tyNmIsFFIEnumable dataGam resTyNm = mkBindE res (mkEnumI resTyNm resNm) (mkE mkEnumE)
| isRec && arity == 0 = mkBindE res (mkEnumI recNm resNm) (mkE mkEnumE)
| isRec = mkBindE res (mkPtrI recNm resNm) (mkE mkPtrE )
| tyNmIsFFIOpaque dataGam resTyNm = mkBindE res (mkOpaqI resNm) (mkE mkOpaqE)
| otherwise = mkBindE res (mkPtrI resTyNm resNm) (mkE mkPtrE )
where isRec = isJust $ recMbRecRow resTy
arity = length $ snd $ tyRecExts resTy
recNm = builtinRecNm arity
ffiMbIORes :: EHCOpts -> Ty -> Maybe Ty
ffiMbIORes opts resTy
= case appMbConApp resTy of
Just (n,[a]) | ehcOptBuiltin opts ehbnIO == n
-> Just a
_ -> Nothing
ffiIOAdapt
:: EHCOpts
-> (UID -> HsName)
-> (HsName -> Ty -> e -> e)
-> (HsName -> Ty -> HsName -> Ty -> e -> e)
-> UID
-> Ty
-> ( [Ty]
, [HsName]
, e -> e
)
ffiIOAdapt
opts
mkUniqNm
mkUnitRes
mkTupledRes
uniq iores
= ([tyState],[nmState],wrapRes)
where tyState = appCon $ ehcOptBuiltin opts ehbnRealWorld
[nmState,nmRes,nmIgnoreRes] = take 3 (map (mkUniqNm) (iterate uidNext uniq))
wrapRes = mkTupledRes nmState (appDbg "ffiIOAdapt.mkTupledRes.state") nmRes (appDbg "ffiIOAdapt.mkTupledRes.res") . dealWithUnitRes
where dealWithUnitRes
= case tyMbRecExts iores of
Just (_,[]) -> mkUnitRes nmIgnoreRes (appDbg "ffiIOAdapt.mkUnitRes")
_ -> id
ffiCoreIOAdapt
:: EHCOpts
-> UID
-> Ty
-> ([Ty],[HsName],CExpr -> CExpr)
ffiCoreIOAdapt
opts
uniq iores
= ffiIOAdapt
opts
mkHNm
(\ nmIgnoreRes ty r -> acoreLet1StrictTy nmIgnoreRes (SysF.ty2TyCforFFI opts ty) r $ acoreTup [] )
(\nmState _ nmRes ty r -> acoreLet1StrictTy nmRes (SysF.ty2TyCforFFI opts ty) r $ acoreTup [acoreVar nmState,acoreVar nmRes])
uniq iores
ffiEvalAdapt
:: ((HsName,Ty,intro,Bool) -> e -> e)
-> ((HsName,Ty,e,Bool) -> e)
-> [(HsName,Ty,intro,Bool)]
-> (HsName,Ty,e,Bool)
-> e
ffiEvalAdapt
evalBindArg
evalRes
args
res
= foldr evalBindArg (evalRes res) args
ffiCoreEvalAdapt
:: EHCOpts
-> [(HsName,Ty,HsName,Bool)]
-> (HsName,Ty,CExpr,Bool)
-> CExpr
ffiCoreEvalAdapt opts
= ffiEvalAdapt
(\(n,ty,i,ev) e -> (if ev then acoreLet1StrictTy else acoreLet1PlainTy) i (SysF.ty2TyCforFFI opts ty) (acoreVar n) e)
(\(n,ty,e,ev) -> if ev then acoreLet1StrictTy n (SysF.ty2TyCforFFI opts ty) e (acoreVar n) else e )
ffiCoreMk
:: EHCOpts
-> ( Ty -> CExpr
)
-> UID
-> RCEEnv
-> ForeignExtraction
-> Ty
-> CExpr
ffiCoreMk
opts
(mkFFI)
uniq rceEnv
foreignEntInfo
tyFFI
= acoreLamTy (zip nmArgL (map (SysF.ty2TyCforFFI opts) argTyL) ++ zip nmArgLExtra (repeat $ acoreTyErr "ffiCoreMk.nmArgLExtra.TBD"))
$ ffiCoreEvalAdapt opts
( zip4 nmArgL argTyL nmArgPatL primArgNeedsEvalL )
( nmEvalRes
, resTyAdapted
, wrapRes
$ acoreApp (mkFFI $ argTyL `appArr` resTyAdapted)
$ map acoreVar nmArgPatL
, primResNeedsEval
)
where (argTyL,resTy) = appUnArr tyFFI
argLen = length argTyL
(_,u1,u2) = mkNewLevUID2 uniq
(nmRes:nmEvalRes:nmArgL) = take (argLen + 2) (map mkHNm (iterate uidNext u1))
nmArgPatL = map (hsnUniqify HsNameUniqifier_FFIArg) nmArgL
(resTyAdapted,argTyLExtra,nmArgLExtra,wrapRes)
=
case ffiMbIORes opts resTy of
Just iores
-> (iores,a,n,w)
where (a,n,w) = ffiCoreIOAdapt opts u2 iores
_ ->
(resTy,[],[],id)
mbPrimNeedEval = maybe Nothing lookupPrimNeedsEval $ forextractMbEnt foreignEntInfo
primArgNeedsEvalL
= take argLen $ maybe (repeat True) (\p -> primArgNeedEval p ++ repeat True) mbPrimNeedEval
primResNeedsEval
= maybe False primResNeedEval mbPrimNeedEval
ffeCoreMk
:: EHCOpts
-> UID
-> RCEEnv
-> Ty
-> ( CExpr -> CExpr
, Ty
)
ffeCoreMk
opts uniq rceEnv
tyFFE
= ( \e ->
acoreLamTy (zipWith (\a t -> (a, SysF.ty2TyCforFFI opts t)) nmArgL argTyL)
$ acoreLet1StrictTy nmEvalRes (SysF.ty2TyCforFFI opts resTyAdapted)
(wrapRes $ acoreApp e $ map acoreVar nmArgL ++ argLExtra)
(acoreVar nmEvalRes)
, argTyL `appArr` resTyAdapted
)
where (argTyL,resTy) = appUnArr tyFFE
argLen = length argTyL
(nmRes:nmEvalRes:nmIOEvalRes:nmArgL) = map mkHNm $ mkNewLevUIDL (argLen+3) uniq
(resTyAdapted,argLExtra,wrapRes)
=
case ffiMbIORes opts resTy of
Just iores
-> ( iores
, [acoreTup []]
, \e -> acoreExprSatSelCaseTy rceEnv (Just (nmIOEvalRes,acoreTyErr "ffeCoreMk.wrapRes")) e CTagRec nmIOEvalRes 1 Nothing
)
_ ->
(resTy,[],id)