[project @ 2000-04-05 16:25:51 by simonpj]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsForeign.lhs
index 84ccaf4..c1fb6fe 100644 (file)
@@ -12,73 +12,79 @@ module DsForeign ( dsForeigns ) where
 
 import CoreSyn
 
-import DsCCall         ( dsCCall, boxResult, unboxArg, wrapUnboxedValue        )
+import DsCCall         ( dsCCall, mkCCall, boxResult, unboxArg )
 import DsMonad
 import DsUtils
 
-import HsSyn           ( ExtName(..), ForeignDecl(..), isDynamic, ForKind(..) )
+import HsSyn           ( ExtName(..), ForeignDecl(..), isDynamicExtName, ForKind(..) )
+import HsDecls         ( extNameStatic )
 import CallConv
 import TcHsSyn         ( TypecheckedForeignDecl )
-import CoreUtils       ( coreExprType )
-import Const           ( Con(..), mkMachInt )
-import DataCon         ( DataCon, dataConId )
-import Id              ( Id, idType, idName, 
-                         mkIdVisible, mkWildId
+import CoreUtils       ( exprType, mkInlineMe, bindNonRec )
+import DataCon         ( DataCon, dataConWrapId )
+import Id              ( Id, idType, idName, mkWildId, mkVanillaId )
+import MkId            ( mkWorkerId )
+import Literal         ( Literal(..) )
+import Module          ( Module, moduleUserString )
+import Name            ( mkGlobalName, nameModule, nameOccName, getOccString, 
+                         mkForeignExportOcc, isLocalName,
+                         NamedThing(..), Provenance(..), ExportFlag(..)
                        )
-import Const           ( Literal(..) )
-import Name            ( getOccString, NamedThing(..) )
-import PrelVals                ( realWorldPrimId )
 import PrelInfo                ( deRefStablePtr_NAME, bindIO_NAME, makeStablePtr_NAME )
-import Type            ( splitAlgTyConApp_maybe, 
+import Type            ( unUsgTy,
                          splitTyConApp_maybe, splitFunTys, splitForAllTys,
                          Type, mkFunTys, mkForAllTys, mkTyConApp,
                          mkTyVarTy, mkFunTy, splitAppTy
                        )
-import PrimOp          ( PrimOp(..) )
+import PrimOp          ( PrimOp(..), CCall(..), CCallTarget(..) )
 import Var             ( TyVar )
 import TysPrim         ( realWorldStatePrimTy, addrPrimTy )
 import TysWiredIn      ( unitTyCon, addrTy, stablePtrTyCon,
                          unboxedTupleCon, addrDataCon
                        )
 import Unique
+import Maybes          ( maybeToBool )
 import Outputable
 \end{code}
 
 Desugaring of @foreign@ declarations is naturally split up into
 parts, an @import@ and an @export@  part. A @foreign import@ 
-declaration 
-
+declaration
+\begin{verbatim}
   foreign import cc nm f :: prim_args -> IO prim_res
-
+\end{verbatim}
 is the same as
-
+\begin{verbatim}
   f :: prim_args -> IO prim_res
   f a1 ... an = _ccall_ nm cc a1 ... an
-
+\end{verbatim}
 so we reuse the desugaring code in @DsCCall@ to deal with these.
 
 \begin{code}
-dsForeigns :: [TypecheckedForeignDecl] 
+dsForeigns :: Module
+           -> [TypecheckedForeignDecl] 
           -> DsM ( [CoreBind]        -- desugared foreign imports
                   , [CoreBind]        -- helper functions for foreign exports
-                 , SDoc              -- Header file prototypes for "foreign exported" functions.
-                 , SDoc              -- C stubs to use when calling "foreign exported" funs.
+                 , SDoc              -- Header file prototypes for
+                                      -- "foreign exported" functions.
+                 , SDoc              -- C stubs to use when calling
+                                      -- "foreign exported" functions.
                  )
-dsForeigns fos = foldlDs combine ([],[],empty,empty) fos
+dsForeigns mod_name fos = foldlDs combine ([],[],empty,empty) fos
  where
   combine (acc_fi, acc_fe, acc_h, acc_c) fo@(ForeignDecl i imp_exp _ ext_nm cconv _) 
     | isForeignImport =   -- foreign import (dynamic)?
-        dsFImport i (idType i) uns ext_nm cconv  `thenDs` \ b -> 
-       returnDs (b:acc_fi, acc_fe, acc_h, acc_c)
+        dsFImport i (idType i) uns ext_nm cconv  `thenDs` \ bs -> 
+       returnDs (bs ++ acc_fi, acc_fe, acc_h, acc_c)
     | isForeignLabel = 
         dsFLabel i ext_nm `thenDs` \ b -> 
        returnDs (b:acc_fi, acc_fe, acc_h, acc_c)
-    | isDynamic ext_nm =
-        dsFExportDynamic i (idType i) ext_nm cconv  `thenDs` \ (fi,fe,h,c) -> 
+    | isDynamicExtName ext_nm =
+        dsFExportDynamic i (idType i) mod_name ext_nm cconv  `thenDs` \ (fi,fe,h,c) -> 
        returnDs (fi:acc_fi, fe:acc_fe, h $$ acc_h, c $$ acc_c)
 
     | otherwise               =  -- foreign export
-        dsFExport i (idType i) ext_nm cconv False   `thenDs` \ (fe,h,c) ->
+        dsFExport i (idType i) mod_name ext_nm cconv False   `thenDs` \ (fe,h,c) ->
        returnDs (acc_fi, fe:acc_fe, h $$ acc_h, c $$ acc_c)
    where
     isForeignImport = 
@@ -97,7 +103,22 @@ dsForeigns fos = foldlDs combine ([],[],empty,empty) fos
 
 Desugaring foreign imports is just the matter of creating a binding
 that on its RHS unboxes its arguments, performs the external call
-(using the CCallOp primop), before boxing the result up and returning it.
+(using the @CCallOp@ primop), before boxing the result up and returning it.
+
+However, we create a worker/wrapper pair, thus:
+
+       foreign import f :: Int -> IO Int
+==>
+       f x = IO ( \s -> case x of { I# x# ->
+                        case fw s x# of { (# s1, y# #) ->
+                        (# s1, I# y# #)}})
+
+       fw s x# = ccall f s x#
+
+The strictness/CPR analyser won't do this automatically because it doesn't look
+inside returned tuples; but inlining this wrapper is a Really Good Idea 
+because it exposes the boxing to the call site.
+                       
 
 \begin{code}
 dsFImport :: Id
@@ -105,107 +126,65 @@ dsFImport :: Id
          -> Bool               -- True <=> might cause Haskell GC
          -> ExtName
          -> CallConv
-         -> DsM CoreBind
-dsFImport nm ty may_not_gc ext_name cconv =
-    newSysLocalDs realWorldStatePrimTy `thenDs` \ old_s ->
-    splitForeignTyDs ty                        `thenDs` \ (tvs, args, mbIoDataCon, io_res_ty)  ->
-    let
-        the_state_arg
-          | is_io_action = old_s
-          | otherwise    = realWorldPrimId
-
-         arg_exprs = map (Var) args
-
-        is_io_action =
-           case mbIoDataCon of
-             Nothing -> False
-             _       -> True
+         -> DsM [CoreBind]
+dsFImport fn_id ty may_not_gc ext_name cconv 
+  = let
+       (tvs, fun_ty)        = splitForAllTys ty
+       (arg_tys, io_res_ty) = splitFunTys fun_ty
     in
-    mapAndUnzipDs unboxArg arg_exprs    `thenDs` \ (unboxed_args, arg_wrappers) ->
-    (if not is_io_action then
-       newSysLocalDs realWorldStatePrimTy `thenDs` \ state_tok ->
-       wrapUnboxedValue io_res_ty         `thenDs` \ (ccall_result_ty, v, res_v) ->
-       returnDs ( ccall_result_ty
-                , \ prim_app -> Case prim_app  (mkWildId ccall_result_ty)
-                                   [(DataCon (unboxedTupleCon 2), [state_tok, v], res_v)])
-     else
-       boxResult io_res_ty)                    `thenDs` \ (final_result_ty, res_wrapper) ->
+    newSysLocalsDs arg_tys                     `thenDs` \ args ->
+    mapAndUnzipDs unboxArg (map Var args)      `thenDs` \ (val_args, arg_wrappers) ->
+    boxResult io_res_ty                                `thenDs` \ (ccall_result_ty, res_wrapper) ->
+
     (case ext_name of
        Dynamic       -> getUniqueDs `thenDs` \ u -> 
-                       returnDs (Right u)
-       ExtName fs _  -> returnDs (Left fs))    `thenDs` \ label ->
-    let
-       val_args   = Var the_state_arg : unboxed_args
-       final_args = Type inst_ty : val_args
-
-       -- A CCallOp has type (forall a. a), so we must instantiate
-       -- it at the full type, including the state argument
-       inst_ty = mkFunTys (map coreExprType val_args) final_result_ty
-
-       the_ccall_op = CCallOp label False (not may_not_gc) cconv
-
-       the_prim_app = mkPrimApp the_ccall_op (final_args :: [CoreArg])
-
-       body     = foldr ($) (res_wrapper the_prim_app) arg_wrappers
+                       returnDs (DynamicTarget u)
+       ExtName fs _  -> returnDs (StaticTarget fs))    `thenDs` \ lbl ->
 
-       the_body 
-         | not is_io_action = body
-         | otherwise        = Lam old_s body
-    in
-    newSysLocalDs (coreExprType the_body) `thenDs` \ ds ->
+    getUniqueDs                                                `thenDs` \ ccall_uniq ->
+    getUniqueDs                                                `thenDs` \ work_uniq ->
     let
-      io_app = 
-        case mbIoDataCon of
-         Nothing -> Var ds
-         Just ioDataCon ->
-              mkApps (Var (dataConId ioDataCon)) 
-                     [Type io_res_ty, Var ds]
-
-      fo_rhs = mkLams (tvs ++ args)
-                     (Let (NonRec ds (the_body::CoreExpr)) io_app)
+       -- Build the worker
+       work_arg_ids  = [v | Var v <- val_args]         -- All guaranteed to be vars
+       worker_ty     = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)
+       the_ccall     = CCall lbl False (not may_not_gc) cconv
+       the_ccall_app = mkCCall ccall_uniq the_ccall val_args ccall_result_ty
+       work_rhs      = mkLams tvs (mkLams work_arg_ids the_ccall_app)
+       work_id       = mkWorkerId work_uniq fn_id worker_ty
+
+       -- 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)
     in
-    returnDs (NonRec nm fo_rhs)
+    returnDs [NonRec fn_id wrap_rhs, NonRec work_id work_rhs]
 \end{code}
 
-Given the type of a foreign import declaration, split it up into
-its constituent parts.
-
-\begin{code}
-splitForeignTyDs :: Type -> DsM ([TyVar], [Id], Maybe DataCon, Type)
-splitForeignTyDs ty = 
-    newSysLocalsDs arg_tys  `thenDs` \ ds_args ->
-    case splitAlgTyConApp_maybe res_ty of
-       Just (_,(io_res_ty:_),(ioCon:_)) ->   -- .... -> IO t
-            returnDs (tvs, ds_args, Just ioCon, io_res_ty)
-       _   ->                               -- .... -> t
-            returnDs (tvs, ds_args, Nothing, res_ty)
-  where
-   (arg_tys, res_ty)   = splitFunTys sans_foralls
-   (tvs, sans_foralls) = splitForAllTys ty
-
-\end{code}
-
-foreign labels 
+Foreign labels 
 
 \begin{code}
 dsFLabel :: Id -> ExtName -> DsM CoreBind
 dsFLabel nm ext_name = returnDs (NonRec nm fo_rhs)
   where
    fo_rhs = mkConApp addrDataCon [mkLit (MachLitLit enm addrPrimTy)]
-   enm    =
-    case ext_name of
-      ExtName f _ -> f
-      Dynamic    -> panic "dsFLabel: Dynamic - shouldn't ever happen."
-
+   enm    = extNameStatic ext_name
 \end{code}
 
-The function that does most of the work for 'foreign export' declarations.
-(see below for the boilerplate code a 'foreign export' declaration expands
+The function that does most of the work for `@foreign export@' declarations.
+(see below for the boilerplate code a `@foreign export@' declaration expands
  into.)
 
+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
+\end{itemize}
+the user-written Haskell function `@M.foo@'.
+
 \begin{code}
 dsFExport :: Id
          -> Type               -- Type of foreign export.
+         -> Module
          -> ExtName
          -> CallConv
          -> Bool               -- True => invoke IO action that's hanging off 
@@ -214,8 +193,21 @@ dsFExport :: Id
                 , SDoc
                 , SDoc
                 )
-dsFExport i ty ext_name cconv isDyn =
-     newSysLocalDs  helper_ty                          `thenDs` \ f_helper ->
+dsFExport i ty mod_name ext_name cconv isDyn =
+     getUniqueDs                                       `thenDs` \ uniq ->
+     getSrcLocDs                                       `thenDs` \ src_loc ->
+     let
+       f_helper_glob = mkVanillaId helper_name helper_ty
+                     where
+                       name                = idName i
+                       mod     
+                        | isLocalName name = mod_name
+                        | otherwise        = nameModule name
+
+                       occ                 = mkForeignExportOcc (nameOccName name)
+                       prov                = LocalDef src_loc Exported
+                       helper_name         = mkGlobalName uniq mod occ prov
+     in
      newSysLocalsDs fe_arg_tys                         `thenDs` \ fe_args ->
      (if isDyn then 
         newSysLocalDs stbl_ptr_ty                      `thenDs` \ stbl_ptr ->
@@ -225,7 +217,7 @@ dsFExport i ty ext_name cconv isDyn =
         the_deref_app = mkApps (Var deRefStablePtrId)
                                [ Type stbl_ptr_to_ty, Var stbl_ptr ]
         in
-       newSysLocalDs (coreExprType the_deref_app)       `thenDs` \ x_deref_app ->
+       newSysLocalDs (exprType the_deref_app)   `thenDs` \ x_deref_app ->
         dsLookupGlobalValue bindIO_NAME                         `thenDs` \ bindIOId ->
        newSysLocalDs (mkFunTy stbl_ptr_to_ty 
                               (mkTyConApp ioTyCon [res_ty])) `thenDs` \ x_cont ->
@@ -244,7 +236,7 @@ dsFExport i ty ext_name cconv isDyn =
         returnDs (i, 
                  \ body -> body,
                  panic "stbl_ptr"  -- should never be touched.
-                 ))                                    `thenDs` \ (i, getFun_wrapper, stbl_ptr) ->
+                 ))                    `thenDs` \ (i, getFun_wrapper, stbl_ptr) ->
      let
       wrapper_args
        | isDyn      = stbl_ptr:fe_args
@@ -258,18 +250,15 @@ dsFExport i ty ext_name cconv isDyn =
          getFun_wrapper $
         mkApps (Var i) (map (Type . mkTyVarTy) tvs ++ map Var fe_args)
      in
-     getModuleAndGroupDs               `thenDs` \ (mod,_) -> 
+     getModuleDs                       `thenDs` \ mod -> 
      getUniqueDs                       `thenDs` \ uniq ->
      let
       the_body = mkLams (tvs ++ wrapper_args) the_app
+      c_nm     = extNameStatic ext_name
 
-      c_nm =
-        case ext_name of
-         ExtName fs _ -> fs
-         Dynamic      -> panic "dsFExport: Dynamic - shouldn't ever happen."
-
-      f_helper_glob    = mkIdVisible mod uniq f_helper
-      (h_stub, c_stub) = fexportEntry c_nm f_helper_glob wrapper_arg_tys the_result_ty cconv isDyn
+      (h_stub, c_stub) = fexportEntry (moduleUserString mod)
+                                     c_nm f_helper_glob
+                                      wrapper_arg_tys the_result_ty cconv isDyn
      in
      returnDs (NonRec f_helper_glob the_body, h_stub, c_stub)
 
@@ -311,7 +300,7 @@ dsFExport i ty ext_name cconv isDyn =
    
 \end{code}
 
-"foreign export dynamic" lets you dress up Haskell IO actions
+@foreign export dynamic@ lets you dress up Haskell IO actions
 of some fixed type behind an externally callable interface (i.e.,
 as a C function pointer). Useful for callbacks and stuff.
 
@@ -343,22 +332,24 @@ foreign export "f_helper" f_helper :: StablePtr (Addr -> Int -> IO Int) -> Addr
 \begin{code}
 dsFExportDynamic :: Id
                 -> Type                -- Type of foreign export.
+                -> Module
                 -> ExtName
                 -> CallConv
                 -> DsM (CoreBind, CoreBind, SDoc, SDoc)
-dsFExportDynamic i ty ext_name cconv =
+dsFExportDynamic i ty mod_name ext_name cconv =
      newSysLocalDs ty                                   `thenDs` \ fe_id ->
      let 
         -- hack: need to get at the name of the C stub we're about to generate.
        fe_nm      = toCName fe_id
        fe_ext_name = ExtName (_PK_ fe_nm) Nothing
      in
-     dsFExport  i export_ty fe_ext_name cconv True `thenDs` \ (fe@(NonRec fe_helper fe_expr), h_code, c_code) ->
-     newSysLocalDs arg_ty                         `thenDs` \ cback ->
+     dsFExport  i export_ty mod_name fe_ext_name cconv True
+     `thenDs` \ (fe@(NonRec fe_helper fe_expr), h_code, c_code) ->
+     newSysLocalDs arg_ty                                  `thenDs` \ cback ->
      dsLookupGlobalValue makeStablePtr_NAME       `thenDs` \ makeStablePtrId ->
      let
        mk_stbl_ptr_app    = mkApps (Var makeStablePtrId) [ Type arg_ty, Var cback ]
-       mk_stbl_ptr_app_ty = coreExprType mk_stbl_ptr_app
+       mk_stbl_ptr_app_ty = exprType mk_stbl_ptr_app
      in
      newSysLocalDs mk_stbl_ptr_app_ty                  `thenDs` \ x_mk_stbl_ptr_app ->
      dsLookupGlobalValue bindIO_NAME                   `thenDs` \ bindIOId ->
@@ -381,7 +372,7 @@ dsFExportDynamic i ty ext_name cconv =
        to be entered using an external calling convention
        (stdcall, ccall).
        -}
-      adj_args      = [ mkLit (mkMachInt (fromInt (callConvToInt cconv)))
+      adj_args      = [ mkIntLitInt (callConvToInt cconv)
                      , Var stbl_value
                      , mkLit (MachLitLit (_PK_ fe_nm) addrPrimTy)
                      ]
@@ -390,16 +381,16 @@ dsFExportDynamic i ty ext_name cconv =
       adjustor     = SLIT("createAdjustor")
      in
      dsCCall adjustor adj_args False False addrTy `thenDs` \ ccall_adj ->
-     let ccall_adj_ty = coreExprType ccall_adj
+     let ccall_adj_ty = exprType ccall_adj
      in
      newSysLocalDs ccall_adj_ty                          `thenDs` \ x_ccall_adj ->
      let ccall_io_adj = 
            mkLams [stbl_value]              $
            bindNonRec x_ccall_adj ccall_adj $
-           Note (Coerce (mkTyConApp ioTyCon [res_ty]) ccall_adj_ty)
+           Note (Coerce (mkTyConApp ioTyCon [res_ty]) (unUsgTy ccall_adj_ty))
                 (Var x_ccall_adj)
      in
-     newSysLocalDs (coreExprType ccall_io_adj)   `thenDs` \ x_ccall_io_adj ->
+     newSysLocalDs (exprType ccall_io_adj)       `thenDs` \ x_ccall_io_adj ->
      let io_app = mkLams tvs    $
                  mkLams [cback] $
                  stbl_app x_ccall_io_adj ccall_io_adj addrTy
@@ -430,14 +421,15 @@ The C stub constructs the application of the exported Haskell function
 using the hugs/ghc rts invocation API.
 
 \begin{code}
-fexportEntry :: FAST_STRING 
+fexportEntry :: String
+            -> FAST_STRING
             -> Id 
             -> [Type] 
             -> Maybe Type 
             -> CallConv 
             -> Bool
             -> (SDoc, SDoc)
-fexportEntry c_nm helper args res cc isDyn = (header_bits, c_bits)
+fexportEntry mod_nm c_nm helper args res cc isDyn = (header_bits, c_bits)
  where
    -- name of the (Haskell) helper function generated by the desugarer.
   h_nm     = ppr helper <> text "_closure"
@@ -483,7 +475,7 @@ fexportEntry c_nm helper args res cc isDyn = (header_bits, c_bits)
 
   returnResult = 
     text "rts_checkSchedStatus" <> 
-    parens (doubleQuotes (ptext c_nm) <> comma <> text "rc") <> semi $$
+    parens (doubleQuotes (text mod_nm <> char '.' <> ptext c_nm) <> comma <> text "rc") <> semi $$
     (case res of
       Nothing -> text "return"
       Just _  -> text "return" <> parens (res_name)) <> semi
@@ -507,19 +499,20 @@ fexportEntry c_nm helper args res cc isDyn = (header_bits, c_bits)
                                , head args : addrTy : tail args)
     | otherwise = (mkCArgNames 0 args, args)
 
-  mkCArgNames n as = zipWith (\ _ n -> text ('a':show n)) as [n..] 
+mkCArgNames :: Int -> [a] -> [SDoc]
+mkCArgNames n as = zipWith (\ _ n -> text ('a':show n)) as [n..] 
 
 mkHObj :: Type -> SDoc
-mkHObj t = text "rts_mk" <> showFFIType t
+mkHObj t = text "rts_mk" <> text (showFFIType t)
 
 unpackHObj :: Type -> SDoc
-unpackHObj t = text "rts_get" <> showFFIType t
+unpackHObj t = text "rts_get" <> text (showFFIType t)
 
 showStgType :: Type -> SDoc
-showStgType t = text "Stg" <> showFFIType t
+showStgType t = text "Stg" <> text (showFFIType t)
 
-showFFIType :: Type -> SDoc
-showFFIType t = text (getOccString (getName tc))
+showFFIType :: Type -> String
+showFFIType t = getOccString (getName tc)
  where
   tc = case splitTyConApp_maybe t of
            Just (tc,_) -> tc