[project @ 2000-04-05 16:25:51 by simonpj]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsForeign.lhs
index 1abd67f..c1fb6fe 100644 (file)
@@ -12,36 +12,38 @@ 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 CoreUtils       ( exprType, mkInlineMe, bindNonRec )
+import DataCon         ( DataCon, dataConWrapId )
 import Id              ( Id, idType, idName, mkWildId, mkVanillaId )
-import Const           ( Literal(..) )
-import Module          ( Module )
+import MkId            ( mkWorkerId )
+import Literal         ( Literal(..) )
+import Module          ( Module, moduleUserString )
 import Name            ( mkGlobalName, nameModule, nameOccName, getOccString, 
                          mkForeignExportOcc, isLocalName,
                          NamedThing(..), Provenance(..), ExportFlag(..)
                        )
-import PrelInfo                ( deRefStablePtr_NAME, bindIO_NAME, makeStablePtr_NAME, realWorldPrimId )
-import Type            ( splitAlgTyConApp_maybe, 
+import PrelInfo                ( deRefStablePtr_NAME, bindIO_NAME, makeStablePtr_NAME )
+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}
 
@@ -72,12 +74,12 @@ 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 =
+    | 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)
 
@@ -103,104 +105,69 @@ 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.
 
+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
          -> Type               -- Type of foreign import.
          -> 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` \ lbl ->
-    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 lbl False (not may_not_gc) cconv
+                       returnDs (DynamicTarget u)
+       ExtName fs _  -> returnDs (StaticTarget fs))    `thenDs` \ lbl ->
 
-       the_prim_app = mkPrimApp the_ccall_op (final_args :: [CoreArg])
-
-       body     = foldr ($) (res_wrapper the_prim_app) arg_wrappers
-
-       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)
-                     (mkDsLet (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.
@@ -250,7 +217,7 @@ dsFExport i ty mod_name 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 ->
@@ -283,17 +250,14 @@ dsFExport i ty mod_name 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."
-
-      (h_stub, c_stub) = fexportEntry c_nm f_helper_glob
+      (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)
@@ -385,7 +349,7 @@ dsFExportDynamic i ty mod_name ext_name cconv =
      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 ->
@@ -408,7 +372,7 @@ dsFExportDynamic i ty mod_name 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)
                      ]
@@ -417,16 +381,16 @@ dsFExportDynamic i ty mod_name 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
@@ -457,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"
@@ -510,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