merge GHC HEAD
[ghc-hetmet.git] / compiler / deSugar / DsForeign.lhs
index 751c504..aee1594 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,9 +18,8 @@ import DsMonad
 
 import HsSyn
 import DataCon
-import MachOp
-import SMRep
 import CoreUtils
+import CoreUnfold
 import Id
 import Literal
 import Module
@@ -37,6 +29,8 @@ import TyCon
 import Coercion
 import TcType
 
+import CmmExpr
+import CmmUtils
 import HscTypes
 import ForeignCall
 import TysWiredIn
@@ -48,7 +42,7 @@ import Outputable
 import FastString
 import Config
 import Constants
-
+import OrdList
 import Data.Maybe
 import Data.List
 \end{code}
@@ -71,9 +65,9 @@ type Binding = (Id, CoreExpr) -- No rec/nonrec structure;
                                -- the occurrence analyser will sort it all out
 
 dsForeigns :: [LForeignDecl Id] 
-          -> DsM (ForeignStubs, [Binding])
+          -> DsM (ForeignStubs, OrdList Binding)
 dsForeigns [] 
-  = return (NoStubs, [])
+  = return (NoStubs, nilOL)
 dsForeigns fos = do
     fives <- mapM do_ldecl fos
     let
@@ -84,7 +78,7 @@ dsForeigns fos = do
     return (ForeignStubs 
              (vcat hs)
              (vcat cs $$ vcat fe_init_code),
-           (concat bindss))
+            foldr (appOL . toOL) nilOL bindss)
   where
    do_ldecl (L loc decl) = putSrcSpanDs loc (do_decl decl)
             
@@ -128,17 +122,10 @@ 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)
 
-  -- FIXME: the `lib' field is needed for .NET ILX generation when invoking
-  --       routines that are external to the .NET runtime, but GHC doesn't
-  --       support such calls yet; if `nullFastString lib', the value was not given
-dsFImport id (DNImport spec) = do
-    (ids, h, c) <- dsFCall id (DNCall spec)
-    return (ids, h, c)
-
 dsCImport :: Id
          -> CImportSpec
          -> CCallConv
@@ -146,14 +133,21 @@ dsCImport :: Id
          -> DsM ([Binding], SDoc, SDoc)
 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
+   ASSERT(fromJust resTy `eqType` addrPrimTy)    -- typechecker ensures this
     let
-        rhs = foRhs (mkLit (MachLabel cid stdcall_info))
+        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 _
@@ -167,10 +161,9 @@ 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 (machRepByteWidth . typeMachRep . getPrimTyOf) fe_arg_tys)
+       (_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}
@@ -183,6 +176,7 @@ fun_type_arg_stdcall_info _other_conv _
 %************************************************************************
 
 \begin{code}
+dsFCall :: Id -> ForeignCall -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)
 dsFCall fn_id fcall = do
     let
         ty                   = idType fn_id
@@ -197,31 +191,7 @@ dsFCall fn_id fcall = do
     let
         work_arg_ids  = [v | Var v <- val_args] -- All guaranteed to be vars
 
-        forDotnet =
-         case fcall of
-           DNCall{} -> True
-           _        -> False
-
-        topConDs
-          | forDotnet = Just <$> dsLookupGlobalId checkDotnetResName
-          | otherwise = return Nothing
-
-        augmentResultDs
-          | forDotnet = do
-                err_res <- newSysLocalDs addrPrimTy
-                return (\ (mb_res_ty, resWrap) ->
-                              case mb_res_ty of
-                                Nothing -> (Just (mkTyConApp (tupleTyCon Unboxed 1)
-                                                             [ addrPrimTy ]),
-                                                 resWrap)
-                                Just x  -> (Just (mkTyConApp (tupleTyCon Unboxed 2)
-                                                             [ x, addrPrimTy ]),
-                                                 resWrap))
-          | otherwise = return id
-
-    augment <- augmentResultDs
-    topCon <- topConDs
-    (ccall_result_ty, res_wrapper) <- boxResult augment topCon io_res_ty
+    (ccall_result_ty, res_wrapper) <- boxResult io_res_ty
 
     ccall_uniq <- newUnique
     work_uniq  <- newUnique
@@ -235,14 +205,48 @@ dsFCall fn_id fcall = do
         -- Build the wrapper
         work_app     = mkApps (mkVarApps (Var work_id) tvs) val_args
         wrapper_body = foldr ($) (res_wrapper work_app) arg_wrappers
-        wrap_rhs     = mkInlineMe (mkLams (tvs ++ args) wrapper_body)
+        wrap_rhs     = mkLams (tvs ++ args) wrapper_body
+        fn_id_w_inl  = fn_id `setIdUnfolding` mkInlineUnfolding (Just (length args)) wrap_rhs
     
-    return ([(work_id, work_rhs), (fn_id, wrap_rhs)], empty, empty)
+    return ([(work_id, work_rhs), (fn_id_w_inl, wrap_rhs)], empty, empty)
 \end{code}
 
 
 %************************************************************************
 %*                                                                     *
+\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}
 %*                                                                     *
 %************************************************************************
@@ -254,7 +258,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@'.
 
@@ -288,7 +292,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) 
@@ -360,8 +364,8 @@ 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.) 
@@ -377,9 +381,9 @@ dsFExportDynamic id cconv = do
     ccall_adj <- dsCCall adjustor adj_args PlayRisky (mkTyConApp io_tc [res_ty])
         -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback
 
-    let io_app = mkLams tvs                $
-                 Lam cback                 $
-                 mkCoerceI (mkSymCoI co)   $
+    let io_app = mkLams tvs                  $
+                 Lam cback                   $
+                 mkCoerce (mkSymCo co) $
                  mkApps (Var bindIOId)
                         [ Type stable_ptr_ty
                         , Type res_ty       
@@ -387,7 +391,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.
 
@@ -429,19 +433,26 @@ 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
@@ -468,18 +479,32 @@ 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
+  res_hty_is_unit = res_hty `eqType` unitTy    -- Look through any newtypes
 
   cResType | res_hty_is_unit = text "void"
           | otherwise       = showStgType res_hty
 
+  -- when the return type is integral and word-sized or smaller, it
+  -- must be assigned as type ffi_arg (#3516).  To see what type
+  -- libffi is expecting here, take a look in its own testsuite, e.g.
+  -- libffi/testsuite/libffi.call/cls_align_ulonglong.c
+  ffi_cResType
+     | is_ffi_arg_type = text "ffi_arg"
+     | otherwise       = cResType
+     where
+       res_ty_key = getUnique (getName (typeTyCon res_hty))
+       is_ffi_arg_type = res_ty_key `notElem`
+              [floatTyConKey, doubleTyConKey,
+               int64TyConKey, word64TyConKey]
+
   -- Now we can cook up the prototype for the exported function.
   pprCconv = case cc of
                CCallConv   -> empty
                StdCallConv -> text (ccallConvAttribute cc)
+                _           -> panic ("mkFExportCBits/pprCconv " ++ showPpr cc)
 
   header_bits = ptext (sLit "extern") <+> fun_proto <> semi
 
@@ -499,7 +524,7 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
   the_cfun
      = case maybe_target of
           Nothing    -> text "(StgClosure*)deRefStablePtr(the_stableptr)"
-          Just hs_fn -> char '&' <> ppr hs_fn <> text "_closure"
+          Just hs_fn -> char '&' <> ppr hs_fn <> text (closureSuffix hs_fn)
 
   cap = text "cap" <> comma
 
@@ -524,9 +549,8 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
   extern_decl
      = case maybe_target of
           Nothing -> empty
-          Just hs_fn -> text "extern StgClosure " <> ppr hs_fn <> text "_closure" <> semi
+          Just hs_fn -> text "extern StgClosure " <> ppr hs_fn <> text (closureSuffix hs_fn) <> semi
 
-   
   -- finally, the whole darn thing
   c_bits =
     space $$
@@ -556,14 +580,18 @@ mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc
                                                <> comma <> text "cap") <> semi
      ,   assignCResult
      ,   ptext (sLit "rts_unlock(cap);")
-     ,   if res_hty_is_unit then empty
-            else if libffi 
-                  then char '*' <> parens (cResType <> char '*') <> 
+     ,   ppUnless res_hty_is_unit $
+         if libffi 
+                  then char '*' <> parens (ffi_cResType <> char '*') <>
                        ptext (sLit "resp = cret;")
                   else ptext (sLit "return cret;")
      , rbrace
      ]
 
+closureSuffix :: Id -> String
+closureSuffix hs_fn =
+    if depth==0 then "_closure" else "_"++(show depth)++"closure"
+        where depth = getNameDepth (Var.varName hs_fn)
 
 foreignExportInitialiser :: Id -> SDoc
 foreignExportInitialiser hs_fn =
@@ -580,20 +608,10 @@ foreignExportInitialiser hs_fn =
          <> text "() __attribute__((constructor));"
     , text "static void stginit_export_" <> ppr hs_fn <> text "()"
     , braces (text "getStablePtr"
-       <> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")
+       <> parens (text "(StgPtr) &" <> ppr hs_fn <> text (closureSuffix hs_fn))
        <> semi)
     ]
 
-
--- 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)
 
@@ -604,12 +622,15 @@ showStgType :: Type -> SDoc
 showStgType t = text "Hs" <> text (showFFIType t)
 
 showFFIType :: Type -> String
-showFFIType t = getOccString (getName tc)
- where
-  tc = case tcSplitTyConApp_maybe (repType t) of
-           Just (tc,_) -> tc
-           Nothing     -> pprPanic "showFFIType" (ppr t)
+showFFIType t = getOccString (getName (typeTyCon t))
+
+typeTyCon :: Type -> TyCon
+typeTyCon ty = case tcSplitTyConApp_maybe (repType ty) of
+                 Just (tc,_) -> tc
+                Nothing     -> pprPanic "DsForeign.typeTyCon" (ppr ty)
 
+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
@@ -619,16 +640,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#).
@@ -652,7 +676,7 @@ getPrimTyOf ty
 -- e.g. 'W' is a signed 32-bit integer.
 primTyDescChar :: Type -> Char
 primTyDescChar ty
- | ty `coreEqType` unitTy = 'v'
+ | ty `eqType` unitTy = 'v'
  | otherwise
  = case typePrimRep (getPrimTyOf ty) of
      IntRep     -> signed_word