[project @ 2000-03-23 17:45:17 by simonpj]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsForeign.lhs
index 4f4e285..2766fa9 100644 (file)
@@ -12,18 +12,19 @@ module DsForeign ( dsForeigns ) where
 
 import CoreSyn
 
-import DsCCall         ( dsCCall, boxResult, unboxArg, wrapUnboxedValue        )
+import DsCCall         ( dsCCall, mkCCall, boxResult, unboxArg, wrapUnboxedValue )
 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 )
+import DataCon         ( DataCon, dataConWrapId )
 import Id              ( Id, idType, idName, mkWildId, mkVanillaId )
-import Const           ( Literal(..) )
+import MkId            ( mkCCallOpId, mkWorkerId )
+import Literal         ( Literal(..) )
 import Module          ( Module, moduleUserString )
 import Name            ( mkGlobalName, nameModule, nameOccName, getOccString, 
                          mkForeignExportOcc, isLocalName,
@@ -35,13 +36,14 @@ import Type         ( splitAlgTyConApp_maybe,  unUsgTy,
                          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
 
 #if __GLASGOW_HASKELL__ >= 404
@@ -76,12 +78,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)
 
@@ -107,90 +109,92 @@ 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, arg_tys, mbIoDataCon, io_res_ty) = splitForeignTyDs ty
+       is_io_action                           = maybeToBool mbIoDataCon
     in
-    mapAndUnzipDs unboxArg arg_exprs    `thenDs` \ (unboxed_args, arg_wrappers) ->
+    newSysLocalsDs arg_tys                     `thenDs` \ args ->
+    newSysLocalDs realWorldStatePrimTy         `thenDs` \ old_s ->
+    mapAndUnzipDs unboxArg (map Var args)      `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) ->
+       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)])
+                                   [(DataAlt (unboxedTupleCon 2), [state_tok, v], res_v)])
      else
-       boxResult io_res_ty)                    `thenDs` \ (final_result_ty, res_wrapper) ->
+       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
-
-       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)
-                     (mkDsLet (NonRec ds (the_body::CoreExpr)) io_app)
+       the_state_arg | is_io_action = old_s
+                     | otherwise    = realWorldPrimId
+
+       -- Build the worker
+       val_args      = Var the_state_arg : unboxed_args
+       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
+        io_app              = case mbIoDataCon of
+                          Nothing        -> wrapper_body
+                          Just ioDataCon -> mkApps (Var (dataConWrapId ioDataCon)) 
+                                                   [Type io_res_ty, Lam old_s wrapper_body]
+        wrap_rhs = mkInlineMe (mkLams (tvs ++ args) io_app)
     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
+splitForeignTyDs :: Type -> ([TyVar], [Type], Maybe DataCon, Type)
+splitForeignTyDs ty
+  = case splitAlgTyConApp_maybe res_ty of
        Just (_,(io_res_ty:_),(ioCon:_)) ->   -- .... -> IO t
-            returnDs (tvs, ds_args, Just ioCon, io_res_ty)
+            (tvs, arg_tys, Just ioCon, io_res_ty)
        _   ->                               -- .... -> t
-            returnDs (tvs, ds_args, Nothing, res_ty)
+            (tvs, arg_tys, Nothing, res_ty)
   where
    (arg_tys, res_ty)   = splitFunTys sans_foralls
    (tvs, sans_foralls) = splitForAllTys ty
-
 \end{code}
 
 foreign labels 
@@ -200,11 +204,7 @@ 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.
@@ -254,7 +254,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 ->
@@ -291,11 +291,7 @@ dsFExport i ty mod_name ext_name cconv isDyn =
      getUniqueDs                       `thenDs` \ uniq ->
      let
       the_body = mkLams (tvs ++ wrapper_args) the_app
-
-      c_nm =
-        case ext_name of
-         ExtName fs _ -> fs
-         Dynamic      -> panic "dsFExport: Dynamic - shouldn't ever happen."
+      c_nm     = extNameStatic ext_name
 
       (h_stub, c_stub) = fexportEntry (moduleUserString mod)
                                      c_nm f_helper_glob
@@ -390,7 +386,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 ->
@@ -413,7 +409,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)
                      ]
@@ -422,7 +418,7 @@ 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 = 
@@ -431,7 +427,7 @@ dsFExportDynamic i ty mod_name ext_name cconv =
            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