Desugaring for "foreign import prim"
[ghc-hetmet.git] / compiler / deSugar / DsForeign.lhs
index 1b269fa..9dea2ad 100644 (file)
@@ -6,13 +6,6 @@
 Desugaring foreign declarations (see also DsCCall).
 
 \begin{code}
-{-# OPTIONS -w #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and fix
--- any warnings in the module. See
---     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
--- for details
-
 module DsForeign ( dsForeigns ) where
 
 #include "HsVersions.h"
@@ -25,17 +18,19 @@ import DsMonad
 
 import HsSyn
 import DataCon
-import MachOp
-import SMRep
 import CoreUtils
 import Id
 import Literal
 import Module
 import Name
 import Type
+import TyCon
 import Coercion
 import TcType
+import Var
 
+import CmmExpr
+import CmmUtils
 import HscTypes
 import ForeignCall
 import TysWiredIn
@@ -96,6 +91,8 @@ dsForeigns fos = do
    do_decl (ForeignExport (L _ id) _ (CExport (CExportStatic ext_nm cconv))) = do
       (h, c, _, _) <- dsFExport id (idType id) ext_nm cconv False
       return (h, c, [id], [])
+
+   do_decl d = pprPanic "dsForeigns/do_decl" (ppr d)
 \end{code}
 
 
@@ -127,7 +124,7 @@ because it exposes the boxing to the call site.
 dsFImport :: Id
          -> ForeignImport
          -> DsM ([Binding], SDoc, SDoc)
-dsFImport id (CImport cconv safety header lib spec) = do
+dsFImport id (CImport cconv safety _ _ spec) = do
     (ids, h, c) <- dsCImport id spec cconv safety
     return (ids, h, c)
 
@@ -143,15 +140,41 @@ dsCImport :: Id
          -> CCallConv
          -> Safety
          -> DsM ([Binding], SDoc, SDoc)
-dsCImport id (CLabel cid) _ _ = do
-   (resTy, foRhs) <- resultWrapper (idType id)
+dsCImport id (CLabel cid) cconv _ = do
+   let ty = idType id
+       fod = case splitTyConApp_maybe (repType ty) of
+             Just (tycon, _)
+              | tyConUnique tycon == funPtrTyConKey ->
+                 IsFunction
+             _ -> IsData
+   (resTy, foRhs) <- resultWrapper ty
    ASSERT(fromJust resTy `coreEqType` addrPrimTy)    -- typechecker ensures this
-    let rhs = foRhs (mkLit (MachLabel cid Nothing)) in
+    let
+        rhs = foRhs (Lit (MachLabel cid stdcall_info fod))
+        stdcall_info = fun_type_arg_stdcall_info cconv ty
+    in
     return ([(id, rhs)], empty, empty)
+
+dsCImport id (CFunction target) cconv@PrimCallConv safety
+  = dsPrimCall id (CCall (CCallSpec target cconv safety))
 dsCImport id (CFunction target) cconv safety
   = dsFCall id (CCall (CCallSpec target cconv safety))
 dsCImport id CWrapper cconv _
   = dsFExportDynamic id cconv
+
+-- For stdcall labels, if the type was a FunPtr or newtype thereof,
+-- then we need to calculate the size of the arguments in order to add
+-- the @n suffix to the label.
+fun_type_arg_stdcall_info :: CCallConv -> Type -> Maybe Int
+fun_type_arg_stdcall_info StdCallConv ty
+  | Just (tc,[arg_ty]) <- splitTyConApp_maybe (repType ty),
+    tyConUnique tc == funPtrTyConKey
+  = let
+       (_tvs,sans_foralls)        = tcSplitForAllTys arg_ty
+       (fe_arg_tys, _orig_res_ty) = tcSplitFunTys sans_foralls
+    in Just $ sum (map (widthInBytes . typeWidth . typeCmmType . getPrimTyOf) fe_arg_tys)
+fun_type_arg_stdcall_info _other_conv _
+  = Nothing
 \end{code}
 
 
@@ -162,6 +185,7 @@ dsCImport id CWrapper cconv _
 %************************************************************************
 
 \begin{code}
+dsFCall :: Id -> ForeignCall -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)
 dsFCall fn_id fcall = do
     let
         ty                   = idType fn_id
@@ -187,7 +211,6 @@ dsFCall fn_id fcall = do
 
         augmentResultDs
           | forDotnet = do
-                err_res <- newSysLocalDs addrPrimTy
                 return (\ (mb_res_ty, resWrap) ->
                               case mb_res_ty of
                                 Nothing -> (Just (mkTyConApp (tupleTyCon Unboxed 1)
@@ -209,7 +232,7 @@ dsFCall fn_id fcall = do
         worker_ty     = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)
         the_ccall_app = mkFCall ccall_uniq fcall val_args ccall_result_ty
         work_rhs      = mkLams tvs (mkLams work_arg_ids the_ccall_app)
-        work_id       = mkSysLocal FSLIT("$wccall") work_uniq worker_ty
+        work_id       = mkSysLocal (fsLit "$wccall") work_uniq worker_ty
 
         -- Build the wrapper
         work_app     = mkApps (mkVarApps (Var work_id) tvs) val_args
@@ -222,6 +245,39 @@ dsFCall fn_id fcall = do
 
 %************************************************************************
 %*                                                                     *
+\subsection{Primitive calls}
+%*                                                                     *
+%************************************************************************
+
+This is for `@foreign import prim@' declarations.
+
+Currently, at the core level we pretend that these primitive calls are
+foreign calls. It may make more sense in future to have them as a distinct
+kind of Id, or perhaps to bundle them with PrimOps since semantically and
+for calling convention they are really prim ops.
+
+\begin{code}
+dsPrimCall :: Id -> ForeignCall -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)
+dsPrimCall fn_id fcall = do
+    let
+        ty                   = idType fn_id
+        (tvs, fun_ty)        = tcSplitForAllTys ty
+        (arg_tys, io_res_ty) = tcSplitFunTys fun_ty
+                -- Must use tcSplit* functions because we want to
+                -- see that (IO t) in the corner
+
+    args <- newSysLocalsDs arg_tys
+
+    ccall_uniq <- newUnique
+    let
+        call_app = mkFCall ccall_uniq fcall (map Var args) io_res_ty
+        rhs      = mkLams tvs (mkLams args call_app)
+    return ([(fn_id, rhs)], empty, empty)
+
+\end{code}
+
+%************************************************************************
+%*                                                                     *
 \subsection{Foreign export}
 %*                                                                     *
 %************************************************************************
@@ -233,7 +289,7 @@ The function that does most of the work for `@foreign export@' declarations.
 For each `@foreign export foo@' in a module M we generate:
 \begin{itemize}
 \item a C function `@foo@', which calls
-\item a Haskell stub `@M.$ffoo@', which calls
+\item a Haskell stub `@M.\$ffoo@', which calls
 \end{itemize}
 the user-written Haskell function `@M.foo@'.
 
@@ -267,7 +323,7 @@ dsFExport fn_id ty ext_name cconv isDyn=  do
     (res_ty,             -- t
      is_IO_res_ty) <-    -- Bool
         case tcSplitIOType_maybe orig_res_ty of
-           Just (ioTyCon, res_ty, co) -> return (res_ty, True)
+           Just (_ioTyCon, res_ty, _co) -> return (res_ty, True)
                    -- The function already returns IO t
                    -- ToDo: what about the coercion?
            Nothing                    -> return (orig_res_ty, False) 
@@ -339,12 +395,12 @@ dsFExportDynamic id cconv = do
          -}
         adj_args      = [ mkIntLitInt (ccallConvToInt cconv)
                         , Var stbl_value
-                        , mkLit (MachLabel fe_nm mb_sz_args)
-                        , mkLit (mkStringLit typestring)
+                        , Lit (MachLabel fe_nm mb_sz_args IsFunction)
+                        , Lit (mkMachString typestring)
                         ]
           -- name of external entry point providing these services.
           -- (probably in the RTS.) 
-        adjustor   = FSLIT("createAdjustor")
+        adjustor   = fsLit "createAdjustor"
         
           -- Determine the number of bytes of arguments to the stub function,
           -- so that we can attach the '@N' suffix to its label if it is a
@@ -366,7 +422,7 @@ dsFExportDynamic id cconv = do
                         , Lam stbl_value ccall_adj
                         ]
 
-        fed = (id `setInlinePragma` NeverActive, io_app)
+        fed = (id `setInlineActivation` NeverActive, io_app)
                -- Never inline the f.e.d. function, because the litlit
                -- might not be in scope in other modules.
 
@@ -408,24 +464,31 @@ mkFExportCBits :: FastString
                  )
 mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc 
  = (header_bits, c_bits, type_string,
-    sum [ machRepByteWidth rep | (_,_,_,rep) <- aug_arg_info] -- all the args
+    sum [ widthInBytes (typeWidth rep) | (_,_,_,rep) <- aug_arg_info] -- all the args
+        -- NB. the calculation here isn't strictly speaking correct.
+        -- We have a primitive Haskell type (eg. Int#, Double#), and
+        -- we want to know the size, when passed on the C stack, of
+        -- the associated C type (eg. HsInt, HsDouble).  We don't have
+        -- this information to hand, but we know what GHC's conventions
+        -- are for passing around the primitive Haskell types, so we
+        -- use that instead.  I hope the two coincide --SDM
     )
  where
   -- list the arguments to the C function
   arg_info :: [(SDoc,          -- arg name
                SDoc,           -- C type
                Type,           -- Haskell type
-               MachRep)]       -- the MachRep
+               CmmType)]       -- the CmmType
   arg_info  = [ let stg_type = showStgType ty in
                 (arg_cname n stg_type,
                  stg_type,
                  ty, 
-                typeMachRep (getPrimTyOf ty))
+                typeCmmType (getPrimTyOf ty))
              | (ty,n) <- zip arg_htys [1::Int ..] ]
 
   arg_cname n stg_ty
         | libffi    = char '*' <> parens (stg_ty <> char '*') <> 
-                      ptext SLIT("args") <> brackets (int (n-1))
+                      ptext (sLit "args") <> brackets (int (n-1))
         | otherwise = text ('a':show n)
 
   -- generate a libffi-style stub if this is a "wrapper" and libffi is enabled
@@ -447,7 +510,7 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
 
   stable_ptr_arg = 
        (text "the_stableptr", text "StgStablePtr", undefined,
-        typeMachRep (mkStablePtrPrimTy alphaTy))
+        typeCmmType (mkStablePtrPrimTy alphaTy))
 
   -- stuff to do with the return type of the C function
   res_hty_is_unit = res_hty `coreEqType` unitTy        -- Look through any newtypes
@@ -459,8 +522,9 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
   pprCconv = case cc of
                CCallConv   -> empty
                StdCallConv -> text (ccallConvAttribute cc)
+                _           -> panic ("mkFExportCBits/pprCconv " ++ showPpr cc)
 
-  header_bits = ptext SLIT("extern") <+> fun_proto <> semi
+  header_bits = ptext (sLit "extern") <+> fun_proto <> semi
 
   fun_args
     | null aug_arg_info = text "void"
@@ -469,8 +533,8 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
 
   fun_proto
     | libffi
-      = ptext SLIT("void") <+> ftext c_nm <> 
-          parens (ptext SLIT("void *cif STG_UNUSED, void* resp, void** args, void* the_stableptr"))
+      = ptext (sLit "void") <+> ftext c_nm <> 
+          parens (ptext (sLit "void *cif STG_UNUSED, void* resp, void** args, void* the_stableptr"))
     | otherwise
       = cResType <+> pprCconv <+> ftext c_nm <> parens fun_args
 
@@ -513,33 +577,33 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
     fun_proto  $$
     vcat 
      [ lbrace
-     ,   ptext SLIT("Capability *cap;")
+     ,   ptext (sLit "Capability *cap;")
      ,   declareResult
      ,   declareCResult
      ,   text "cap = rts_lock();"
          -- create the application + perform it.
-     ,   ptext SLIT("cap=rts_evalIO") <> parens (
+     ,   ptext (sLit "cap=rts_evalIO") <> parens (
                cap <>
-               ptext SLIT("rts_apply") <> parens (
+               ptext (sLit "rts_apply") <> parens (
                    cap <>
                    text "(HaskellObj)"
                 <> ptext (if is_IO_res_ty 
-                               then SLIT("runIO_closure")
-                               else SLIT("runNonIO_closure"))
+                               then (sLit "runIO_closure")
+                               else (sLit "runNonIO_closure"))
                 <> comma
                 <> expr_to_run
                ) <+> comma
               <> text "&ret"
             ) <> semi
-     ,   ptext SLIT("rts_checkSchedStatus") <> parens (doubleQuotes (ftext c_nm)
+     ,   ptext (sLit "rts_checkSchedStatus") <> parens (doubleQuotes (ftext c_nm)
                                                <> comma <> text "cap") <> semi
      ,   assignCResult
-     ,   ptext SLIT("rts_unlock(cap);")
+     ,   ptext (sLit "rts_unlock(cap);")
      ,   if res_hty_is_unit then empty
             else if libffi 
                   then char '*' <> parens (cResType <> char '*') <> 
-                       ptext SLIT("resp = cret;")
-                  else ptext SLIT("return cret;")
+                       ptext (sLit "resp = cret;")
+                  else ptext (sLit "return cret;")
      , rbrace
      ]
 
@@ -564,15 +628,6 @@ foreignExportInitialiser hs_fn =
     ]
 
 
--- NB. the calculation here isn't strictly speaking correct.
--- We have a primitive Haskell type (eg. Int#, Double#), and
--- we want to know the size, when passed on the C stack, of
--- the associated C type (eg. HsInt, HsDouble).  We don't have
--- this information to hand, but we know what GHC's conventions
--- are for passing around the primitive Haskell types, so we
--- use that instead.  I hope the two coincide --SDM
-typeMachRep ty = argMachRep (typeCgRep ty)
-
 mkHObj :: Type -> SDoc
 mkHObj t = text "rts_mk" <> text (showFFIType t)
 
@@ -589,6 +644,8 @@ showFFIType t = getOccString (getName tc)
            Just (tc,_) -> tc
            Nothing     -> pprPanic "showFFIType" (ppr t)
 
+insertRetAddr :: CCallConv -> [(SDoc, SDoc, Type, CmmType)]
+                           -> [(SDoc, SDoc, Type, CmmType)]
 #if !defined(x86_64_TARGET_ARCH)
 insertRetAddr CCallConv args = ret_addr_arg : args
 insertRetAddr _ args = args
@@ -598,16 +655,19 @@ insertRetAddr _ args = args
 -- need to flush a register argument to the stack (See rts/Adjustor.c for
 -- details).
 insertRetAddr CCallConv args = go 0 args
-  where  go 6 args = ret_addr_arg : args
+  where  go :: Int -> [(SDoc, SDoc, Type, CmmType)]
+                   -> [(SDoc, SDoc, Type, CmmType)]
+         go 6 args = ret_addr_arg : args
         go n (arg@(_,_,_,rep):args)
-         | I64 <- rep = arg : go (n+1) args
+         | cmmEqType_ignoring_ptrhood rep b64 = arg : go (n+1) args
          | otherwise  = arg : go n     args
-        go n [] = []
+        go _ [] = []
 insertRetAddr _ args = args
 #endif
 
+ret_addr_arg :: (SDoc, SDoc, Type, CmmType)
 ret_addr_arg = (text "original_return_addr", text "void*", undefined, 
-               typeMachRep addrPrimTy)
+               typeCmmType addrPrimTy)
 
 -- This function returns the primitive type associated with the boxed
 -- type argument to a foreign export (eg. Int ==> Int#).