Migrate cvs diff from fptools-assoc branch
[ghc-hetmet.git] / compiler / deSugar / DsForeign.lhs
1 %
2 % (c) The AQUA Project, Glasgow University, 1998
3 %
4 \section[DsCCall]{Desugaring \tr{foreign} declarations}
5
6 Expanding out @foreign import@ and @foreign export@ declarations.
7
8 \begin{code}
9 module DsForeign ( dsForeigns ) where
10
11 #include "HsVersions.h"
12 import TcRnMonad        -- temp
13
14 import CoreSyn
15
16 import DsCCall          ( dsCCall, mkFCall, boxResult, unboxArg, resultWrapper )
17 import DsMonad
18
19 import HsSyn            ( ForeignDecl(..), ForeignExport(..), LForeignDecl,
20                           ForeignImport(..), CImportSpec(..) )
21 import DataCon          ( splitProductType_maybe )
22 #ifdef DEBUG
23 import DataCon          ( dataConSourceArity )
24 import Type             ( isUnLiftedType )
25 #endif
26 import MachOp           ( machRepByteWidth, MachRep(..) )
27 import SMRep            ( argMachRep, typeCgRep )
28 import CoreUtils        ( exprType, mkInlineMe )
29 import Id               ( Id, idType, idName, mkSysLocal, setInlinePragma )
30 import Literal          ( Literal(..), mkStringLit )
31 import Module           ( moduleNameFS, moduleName )
32 import Name             ( getOccString, NamedThing(..) )
33 import Type             ( repType, coreEqType )
34 import Coercion         ( mkUnsafeCoercion )
35 import TcType           ( Type, mkFunTys, mkForAllTys, mkTyConApp,
36                           mkFunTy, tcSplitTyConApp_maybe, tcSplitIOType_maybe,
37                           tcSplitForAllTys, tcSplitFunTys, tcTyConAppArgs,
38                           isBoolTy
39                         )
40
41 import BasicTypes       ( Boxity(..) )
42 import HscTypes         ( ForeignStubs(..) )
43 import ForeignCall      ( ForeignCall(..), CCallSpec(..), 
44                           Safety(..), 
45                           CExportSpec(..), CLabelString,
46                           CCallConv(..), ccallConvToInt,
47                           ccallConvAttribute
48                         )
49 import TysWiredIn       ( unitTy, tupleTyCon )
50 import TysPrim          ( addrPrimTy, mkStablePtrPrimTy, alphaTy, intPrimTy )
51 import PrelNames        ( stablePtrTyConName, newStablePtrName, bindIOName,
52                           checkDotnetResName )
53 import BasicTypes       ( Activation( NeverActive ) )
54 import SrcLoc           ( Located(..), unLoc )
55 import Outputable
56 import Maybe            ( fromJust, isNothing )
57 import FastString
58 \end{code}
59
60 Desugaring of @foreign@ declarations is naturally split up into
61 parts, an @import@ and an @export@  part. A @foreign import@ 
62 declaration
63 \begin{verbatim}
64   foreign import cc nm f :: prim_args -> IO prim_res
65 \end{verbatim}
66 is the same as
67 \begin{verbatim}
68   f :: prim_args -> IO prim_res
69   f a1 ... an = _ccall_ nm cc a1 ... an
70 \end{verbatim}
71 so we reuse the desugaring code in @DsCCall@ to deal with these.
72
73 \begin{code}
74 type Binding = (Id, CoreExpr)   -- No rec/nonrec structure;
75                                 -- the occurrence analyser will sort it all out
76
77 dsForeigns :: [LForeignDecl Id] 
78            -> DsM (ForeignStubs, [Binding])
79 dsForeigns [] 
80   = returnDs (NoStubs, [])
81 dsForeigns fos
82   = foldlDs combine (ForeignStubs empty empty [] [], []) fos
83  where
84   combine stubs (L loc decl) = putSrcSpanDs loc (combine1 stubs decl)
85
86   combine1 (ForeignStubs acc_h acc_c acc_hdrs acc_feb, acc_f) 
87            (ForeignImport id _ spec)
88     = traceIf (text "fi start" <+> ppr id)      `thenDs` \ _ ->
89       dsFImport (unLoc id) spec                 `thenDs` \ (bs, h, c, mbhd) -> 
90       traceIf (text "fi end" <+> ppr id)        `thenDs` \ _ ->
91       returnDs (ForeignStubs (h $$ acc_h)
92                              (c $$ acc_c)
93                              (addH mbhd acc_hdrs)
94                              acc_feb, 
95                 bs ++ acc_f)
96
97   combine1 (ForeignStubs acc_h acc_c acc_hdrs acc_feb, acc_f) 
98            (ForeignExport (L _ id) _ (CExport (CExportStatic ext_nm cconv)))
99     = dsFExport id (idType id) 
100                 ext_nm cconv False                 `thenDs` \(h, c, _, _) ->
101       returnDs (ForeignStubs (h $$ acc_h) (c $$ acc_c) acc_hdrs (id:acc_feb), 
102                 acc_f)
103
104   addH Nothing  ls = ls
105   addH (Just e) ls
106    | e `elem` ls = ls
107    | otherwise   = e:ls
108 \end{code}
109
110
111 %************************************************************************
112 %*                                                                      *
113 \subsection{Foreign import}
114 %*                                                                      *
115 %************************************************************************
116
117 Desugaring foreign imports is just the matter of creating a binding
118 that on its RHS unboxes its arguments, performs the external call
119 (using the @CCallOp@ primop), before boxing the result up and returning it.
120
121 However, we create a worker/wrapper pair, thus:
122
123         foreign import f :: Int -> IO Int
124 ==>
125         f x = IO ( \s -> case x of { I# x# ->
126                          case fw s x# of { (# s1, y# #) ->
127                          (# s1, I# y# #)}})
128
129         fw s x# = ccall f s x#
130
131 The strictness/CPR analyser won't do this automatically because it doesn't look
132 inside returned tuples; but inlining this wrapper is a Really Good Idea 
133 because it exposes the boxing to the call site.
134
135 \begin{code}
136 dsFImport :: Id
137           -> ForeignImport
138           -> DsM ([Binding], SDoc, SDoc, Maybe FastString)
139 dsFImport id (CImport cconv safety header lib spec)
140   = dsCImport id spec cconv safety no_hdrs        `thenDs` \(ids, h, c) ->
141     returnDs (ids, h, c, if no_hdrs then Nothing else Just header)
142   where
143     no_hdrs = nullFS header
144
145   -- FIXME: the `lib' field is needed for .NET ILX generation when invoking
146   --        routines that are external to the .NET runtime, but GHC doesn't
147   --        support such calls yet; if `nullFastString lib', the value was not given
148 dsFImport id (DNImport spec)
149   = dsFCall id (DNCall spec) True {- No headers -} `thenDs` \(ids, h, c) ->
150     returnDs (ids, h, c, Nothing)
151
152 dsCImport :: Id
153           -> CImportSpec
154           -> CCallConv
155           -> Safety
156           -> Bool       -- True <=> no headers in the f.i decl
157           -> DsM ([Binding], SDoc, SDoc)
158 dsCImport id (CLabel cid) _ _ no_hdrs
159  = resultWrapper (idType id) `thenDs` \ (resTy, foRhs) ->
160    ASSERT(fromJust resTy `coreEqType` addrPrimTy)    -- typechecker ensures this
161     let rhs = foRhs (mkLit (MachLabel cid Nothing)) in
162     returnDs ([(setImpInline no_hdrs id, rhs)], empty, empty)
163 dsCImport id (CFunction target) cconv safety no_hdrs
164   = dsFCall id (CCall (CCallSpec target cconv safety)) no_hdrs
165 dsCImport id CWrapper cconv _ _
166   = dsFExportDynamic id cconv
167
168 setImpInline :: Bool    -- True <=> No #include headers 
169                         -- in the foreign import declaration
170              -> Id -> Id
171 -- If there is a #include header in the foreign import
172 -- we make the worker non-inlinable, because we currently
173 -- don't keep the #include stuff in the CCallId, and hence
174 -- it won't be visible in the importing module, which can be
175 -- fatal. 
176 -- (The #include stuff is just collected from the foreign import
177 --  decls in a module.)
178 -- If you want to do cross-module inlining of the c-calls themselves,
179 -- put the #include stuff in the package spec, not the foreign 
180 -- import decl.
181 setImpInline True  id = id
182 setImpInline False id = id `setInlinePragma` NeverActive
183 \end{code}
184
185
186 %************************************************************************
187 %*                                                                      *
188 \subsection{Foreign calls}
189 %*                                                                      *
190 %************************************************************************
191
192 \begin{code}
193 dsFCall fn_id fcall no_hdrs
194   = let
195         ty                   = idType fn_id
196         (tvs, fun_ty)        = tcSplitForAllTys ty
197         (arg_tys, io_res_ty) = tcSplitFunTys fun_ty
198                 -- Must use tcSplit* functions because we want to 
199                 -- see that (IO t) in the corner
200     in
201     newSysLocalsDs arg_tys                      `thenDs` \ args ->
202     mapAndUnzipDs unboxArg (map Var args)       `thenDs` \ (val_args, arg_wrappers) ->
203
204     let
205         work_arg_ids  = [v | Var v <- val_args] -- All guaranteed to be vars
206
207         forDotnet = 
208          case fcall of
209            DNCall{} -> True
210            _        -> False
211
212         topConDs
213           | forDotnet = 
214              dsLookupGlobalId checkDotnetResName `thenDs` \ check_id -> 
215              return (Just check_id)
216           | otherwise = return Nothing
217              
218         augmentResultDs
219           | forDotnet = 
220                 newSysLocalDs addrPrimTy `thenDs` \ err_res -> 
221                 returnDs (\ (mb_res_ty, resWrap) ->
222                               case mb_res_ty of
223                                 Nothing -> (Just (mkTyConApp (tupleTyCon Unboxed 1)
224                                                              [ addrPrimTy ]),
225                                                  resWrap)
226                                 Just x  -> (Just (mkTyConApp (tupleTyCon Unboxed 2)
227                                                              [ x, addrPrimTy ]),
228                                                  resWrap))
229           | otherwise = returnDs id
230     in
231     augmentResultDs                                  `thenDs` \ augment -> 
232     topConDs                                         `thenDs` \ topCon -> 
233     boxResult augment topCon io_res_ty `thenDs` \ (ccall_result_ty, res_wrapper) ->
234
235     newUnique                                   `thenDs` \ ccall_uniq ->
236     newUnique                                   `thenDs` \ work_uniq ->
237     let
238         -- Build the worker
239         worker_ty     = mkForAllTys tvs (mkFunTys (map idType work_arg_ids) ccall_result_ty)
240         the_ccall_app = mkFCall ccall_uniq fcall val_args ccall_result_ty
241         work_rhs      = mkLams tvs (mkLams work_arg_ids the_ccall_app)
242         work_id       = setImpInline no_hdrs $  -- See comments with setImpInline
243                         mkSysLocal FSLIT("$wccall") work_uniq worker_ty
244
245         -- Build the wrapper
246         work_app     = mkApps (mkVarApps (Var work_id) tvs) val_args
247         wrapper_body = foldr ($) (res_wrapper work_app) arg_wrappers
248         wrap_rhs     = mkInlineMe (mkLams (tvs ++ args) wrapper_body)
249     in
250     returnDs ([(work_id, work_rhs), (fn_id, wrap_rhs)], empty, empty)
251 \end{code}
252
253
254 %************************************************************************
255 %*                                                                      *
256 \subsection{Foreign export}
257 %*                                                                      *
258 %************************************************************************
259
260 The function that does most of the work for `@foreign export@' declarations.
261 (see below for the boilerplate code a `@foreign export@' declaration expands
262  into.)
263
264 For each `@foreign export foo@' in a module M we generate:
265 \begin{itemize}
266 \item a C function `@foo@', which calls
267 \item a Haskell stub `@M.$ffoo@', which calls
268 \end{itemize}
269 the user-written Haskell function `@M.foo@'.
270
271 \begin{code}
272 dsFExport :: Id                 -- Either the exported Id, 
273                                 -- or the foreign-export-dynamic constructor
274           -> Type               -- The type of the thing callable from C
275           -> CLabelString       -- The name to export to C land
276           -> CCallConv
277           -> Bool               -- True => foreign export dynamic
278                                 --         so invoke IO action that's hanging off 
279                                 --         the first argument's stable pointer
280           -> DsM ( SDoc         -- contents of Module_stub.h
281                  , SDoc         -- contents of Module_stub.c
282                  , [MachRep]    -- primitive arguments expected by stub function
283                  , Int          -- size of args to stub function
284                  )
285
286 dsFExport fn_id ty ext_name cconv isDyn
287    = 
288      let
289         (_tvs,sans_foralls)             = tcSplitForAllTys ty
290         (fe_arg_tys', orig_res_ty)      = tcSplitFunTys sans_foralls
291         -- We must use tcSplits here, because we want to see 
292         -- the (IO t) in the corner of the type!
293         fe_arg_tys | isDyn     = tail fe_arg_tys'
294                    | otherwise = fe_arg_tys'
295      in
296         -- Look at the result type of the exported function, orig_res_ty
297         -- If it's IO t, return         (t, True)
298         -- If it's plain t, return      (t, False)
299      (case tcSplitIOType_maybe orig_res_ty of
300         Just (ioTyCon, res_ty) -> returnDs (res_ty, True)
301                 -- The function already returns IO t
302         Nothing                -> returnDs (orig_res_ty, False) 
303                 -- The function returns t
304      )                                  `thenDs` \ (res_ty,             -- t
305                                                     is_IO_res_ty) ->    -- Bool
306      returnDs $
307        mkFExportCBits ext_name 
308                       (if isDyn then Nothing else Just fn_id)
309                       fe_arg_tys res_ty is_IO_res_ty cconv
310 \end{code}
311
312 @foreign import "wrapper"@ (previously "foreign export dynamic") lets
313 you dress up Haskell IO actions of some fixed type behind an
314 externally callable interface (i.e., as a C function pointer). Useful
315 for callbacks and stuff.
316
317 \begin{verbatim}
318 type Fun = Bool -> Int -> IO Int
319 foreign import "wrapper" f :: Fun -> IO (FunPtr Fun)
320
321 -- Haskell-visible constructor, which is generated from the above:
322 -- SUP: No check for NULL from createAdjustor anymore???
323
324 f :: Fun -> IO (FunPtr Fun)
325 f cback =
326    bindIO (newStablePtr cback)
327           (\StablePtr sp# -> IO (\s1# ->
328               case _ccall_ createAdjustor cconv sp# ``f_helper'' <arg info> s1# of
329                  (# s2#, a# #) -> (# s2#, A# a# #)))
330
331 foreign import "&f_helper" f_helper :: FunPtr (StablePtr Fun -> Fun)
332
333 -- and the helper in C:
334
335 f_helper(StablePtr s, HsBool b, HsInt i)
336 {
337         rts_evalIO(rts_apply(rts_apply(deRefStablePtr(s), 
338                                        rts_mkBool(b)), rts_mkInt(i)));
339 }
340 \end{verbatim}
341
342 \begin{code}
343 dsFExportDynamic :: Id
344                  -> CCallConv
345                  -> DsM ([Binding], SDoc, SDoc)
346 dsFExportDynamic id cconv
347   =  newSysLocalDs ty                            `thenDs` \ fe_id ->
348      getModuleDs                                `thenDs` \ mod -> 
349      let 
350         -- hack: need to get at the name of the C stub we're about to generate.
351        fe_nm       = mkFastString (unpackFS (zEncodeFS (moduleNameFS (moduleName mod))) ++ "_" ++ toCName fe_id)
352      in
353      newSysLocalDs arg_ty                       `thenDs` \ cback ->
354      dsLookupGlobalId newStablePtrName          `thenDs` \ newStablePtrId ->
355      dsLookupTyCon stablePtrTyConName           `thenDs` \ stable_ptr_tycon ->
356      let
357         mk_stbl_ptr_app = mkApps (Var newStablePtrId) [ Type arg_ty, Var cback ]
358         stable_ptr_ty   = mkTyConApp stable_ptr_tycon [arg_ty]
359         export_ty       = mkFunTy stable_ptr_ty arg_ty
360      in
361      dsLookupGlobalId bindIOName                `thenDs` \ bindIOId ->
362      newSysLocalDs stable_ptr_ty                `thenDs` \ stbl_value ->
363      dsFExport id export_ty fe_nm cconv True    
364                 `thenDs` \ (h_code, c_code, arg_reps, args_size) ->
365      let
366       stbl_app cont ret_ty = mkApps (Var bindIOId)
367                                     [ Type stable_ptr_ty
368                                     , Type ret_ty       
369                                     , mk_stbl_ptr_app
370                                     , cont
371                                     ]
372        {-
373         The arguments to the external function which will
374         create a little bit of (template) code on the fly
375         for allowing the (stable pointed) Haskell closure
376         to be entered using an external calling convention
377         (stdcall, ccall).
378        -}
379       adj_args      = [ mkIntLitInt (ccallConvToInt cconv)
380                       , Var stbl_value
381                       , mkLit (MachLabel fe_nm mb_sz_args)
382                       , mkLit (mkStringLit arg_type_info)
383                       ]
384         -- name of external entry point providing these services.
385         -- (probably in the RTS.) 
386       adjustor   = FSLIT("createAdjustor")
387       
388       arg_type_info = map repCharCode arg_reps
389       repCharCode F32 = 'f'
390       repCharCode F64 = 'd'
391       repCharCode I64 = 'l'
392       repCharCode _   = 'i'
393
394         -- Determine the number of bytes of arguments to the stub function,
395         -- so that we can attach the '@N' suffix to its label if it is a
396         -- stdcall on Windows.
397       mb_sz_args = case cconv of
398                       StdCallConv -> Just args_size
399                       _           -> Nothing
400
401      in
402      dsCCall adjustor adj_args PlayRisky io_res_ty      `thenDs` \ ccall_adj ->
403         -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback
404      let ccall_adj_ty = exprType ccall_adj
405          ccall_io_adj = mkLams [stbl_value]                  $
406                         (pprTrace "DsForeign: why is there an unsafeCoerce here?" (text "") $
407                         (Cast ccall_adj (mkUnsafeCoercion ccall_adj_ty io_res_ty )))
408
409          io_app = mkLams tvs     $
410                   mkLams [cback] $
411                   stbl_app ccall_io_adj res_ty
412          fed = (id `setInlinePragma` NeverActive, io_app)
413                 -- Never inline the f.e.d. function, because the litlit
414                 -- might not be in scope in other modules.
415      in
416      returnDs ([fed], h_code, c_code)
417
418  where
419   ty                    = idType id
420   (tvs,sans_foralls)    = tcSplitForAllTys ty
421   ([arg_ty], io_res_ty) = tcSplitFunTys sans_foralls
422   [res_ty]              = tcTyConAppArgs io_res_ty
423         -- Must use tcSplit* to see the (IO t), which is a newtype
424
425 toCName :: Id -> String
426 toCName i = showSDoc (pprCode CStyle (ppr (idName i)))
427 \end{code}
428
429 %*
430 %
431 \subsection{Generating @foreign export@ stubs}
432 %
433 %*
434
435 For each @foreign export@ function, a C stub function is generated.
436 The C stub constructs the application of the exported Haskell function 
437 using the hugs/ghc rts invocation API.
438
439 \begin{code}
440 mkFExportCBits :: FastString
441                -> Maybe Id      -- Just==static, Nothing==dynamic
442                -> [Type] 
443                -> Type 
444                -> Bool          -- True <=> returns an IO type
445                -> CCallConv 
446                -> (SDoc, 
447                    SDoc,
448                    [MachRep],   -- the argument reps
449                    Int          -- total size of arguments
450                   )
451 mkFExportCBits c_nm maybe_target arg_htys res_hty is_IO_res_ty cc 
452  = (header_bits, c_bits, 
453     [rep | (_,_,_,rep) <- arg_info],  -- just the real args
454     sum [ machRepByteWidth rep | (_,_,_,rep) <- aug_arg_info] -- all the args
455     )
456  where
457   -- list the arguments to the C function
458   arg_info :: [(SDoc,           -- arg name
459                 SDoc,           -- C type
460                 Type,           -- Haskell type
461                 MachRep)]       -- the MachRep
462   arg_info  = [ (text ('a':show n), showStgType ty, ty, 
463                  typeMachRep (getPrimTyOf ty))
464               | (ty,n) <- zip arg_htys [1..] ]
465
466   -- add some auxiliary args; the stable ptr in the wrapper case, and
467   -- a slot for the dummy return address in the wrapper + ccall case
468   aug_arg_info
469     | isNothing maybe_target = stable_ptr_arg : insertRetAddr cc arg_info
470     | otherwise              = arg_info
471
472   stable_ptr_arg = 
473         (text "the_stableptr", text "StgStablePtr", undefined,
474          typeMachRep (mkStablePtrPrimTy alphaTy))
475
476   -- stuff to do with the return type of the C function
477   res_hty_is_unit = res_hty `coreEqType` unitTy -- Look through any newtypes
478
479   cResType | res_hty_is_unit = text "void"
480            | otherwise       = showStgType res_hty
481
482   -- Now we can cook up the prototype for the exported function.
483   pprCconv = case cc of
484                 CCallConv   -> empty
485                 StdCallConv -> text (ccallConvAttribute cc)
486
487   header_bits = ptext SLIT("extern") <+> fun_proto <> semi
488
489   fun_proto = cResType <+> pprCconv <+> ftext c_nm <>
490               parens (hsep (punctuate comma (map (\(nm,ty,_,_) -> ty <+> nm) 
491                                                  aug_arg_info)))
492
493   -- the target which will form the root of what we ask rts_evalIO to run
494   the_cfun
495      = case maybe_target of
496           Nothing    -> text "(StgClosure*)deRefStablePtr(the_stableptr)"
497           Just hs_fn -> char '&' <> ppr hs_fn <> text "_closure"
498
499   cap = text "cap" <> comma
500
501   -- the expression we give to rts_evalIO
502   expr_to_run
503      = foldl appArg the_cfun arg_info -- NOT aug_arg_info
504        where
505           appArg acc (arg_cname, _, arg_hty, _) 
506              = text "rts_apply" 
507                <> parens (cap <> acc <> comma <> mkHObj arg_hty <> parens (cap <> arg_cname))
508
509   -- various other bits for inside the fn
510   declareResult = text "HaskellObj ret;"
511   declareCResult | res_hty_is_unit = empty
512                  | otherwise       = cResType <+> text "cret;"
513
514   assignCResult | res_hty_is_unit = empty
515                 | otherwise       =
516                         text "cret=" <> unpackHObj res_hty <> parens (text "ret") <> semi
517
518   -- an extern decl for the fn being called
519   extern_decl
520      = case maybe_target of
521           Nothing -> empty
522           Just hs_fn -> text "extern StgClosure " <> ppr hs_fn <> text "_closure" <> semi
523
524    
525    -- Initialise foreign exports by registering a stable pointer from an
526    -- __attribute__((constructor)) function.
527    -- The alternative is to do this from stginit functions generated in
528    -- codeGen/CodeGen.lhs; however, stginit functions have a negative impact
529    -- on binary sizes and link times because the static linker will think that
530    -- all modules that are imported directly or indirectly are actually used by
531    -- the program.
532    -- (this is bad for big umbrella modules like Graphics.Rendering.OpenGL)
533
534   initialiser
535      = case maybe_target of
536           Nothing -> empty
537           Just hs_fn ->
538             vcat
539              [ text "static void stginit_export_" <> ppr hs_fn
540                   <> text "() __attribute__((constructor));"
541              , text "static void stginit_export_" <> ppr hs_fn <> text "()"
542              , braces (text "getStablePtr"
543                 <> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")
544                 <> semi)
545              ]
546
547   -- finally, the whole darn thing
548   c_bits =
549     space $$
550     extern_decl $$
551     fun_proto  $$
552     vcat 
553      [ lbrace
554      ,   text "Capability *cap;"
555      ,   declareResult
556      ,   declareCResult
557      ,   text "cap = rts_lock();"
558           -- create the application + perform it.
559      ,   text "cap=rts_evalIO" <> parens (
560                 cap <>
561                 text "rts_apply" <> parens (
562                     cap <>
563                     text "(HaskellObj)"
564                  <> text (if is_IO_res_ty 
565                                 then "runIO_closure" 
566                                 else "runNonIO_closure")
567                  <> comma
568                  <> expr_to_run
569                 ) <+> comma
570                <> text "&ret"
571              ) <> semi
572      ,   text "rts_checkSchedStatus" <> parens (doubleQuotes (ftext c_nm)
573                                                 <> comma <> text "cap") <> semi
574      ,   assignCResult
575      ,   text "rts_unlock(cap);"
576      ,   if res_hty_is_unit then empty
577             else text "return cret;"
578      , rbrace
579      ] $$
580     initialiser
581
582 -- NB. the calculation here isn't strictly speaking correct.
583 -- We have a primitive Haskell type (eg. Int#, Double#), and
584 -- we want to know the size, when passed on the C stack, of
585 -- the associated C type (eg. HsInt, HsDouble).  We don't have
586 -- this information to hand, but we know what GHC's conventions
587 -- are for passing around the primitive Haskell types, so we
588 -- use that instead.  I hope the two coincide --SDM
589 typeMachRep ty = argMachRep (typeCgRep ty)
590
591 mkHObj :: Type -> SDoc
592 mkHObj t = text "rts_mk" <> text (showFFIType t)
593
594 unpackHObj :: Type -> SDoc
595 unpackHObj t = text "rts_get" <> text (showFFIType t)
596
597 showStgType :: Type -> SDoc
598 showStgType t = text "Hs" <> text (showFFIType t)
599
600 showFFIType :: Type -> String
601 showFFIType t = getOccString (getName tc)
602  where
603   tc = case tcSplitTyConApp_maybe (repType t) of
604             Just (tc,_) -> tc
605             Nothing     -> pprPanic "showFFIType" (ppr t)
606
607 #if !defined(x86_64_TARGET_ARCH)
608 insertRetAddr CCallConv args = ret_addr_arg : args
609 insertRetAddr _ args = args
610 #else
611 -- On x86_64 we insert the return address after the 6th
612 -- integer argument, because this is the point at which we
613 -- need to flush a register argument to the stack (See rts/Adjustor.c for
614 -- details).
615 insertRetAddr CCallConv args = go 0 args
616   where  go 6 args = ret_addr_arg : args
617          go n (arg@(_,_,_,rep):args)
618           | I64 <- rep = arg : go (n+1) args
619           | otherwise  = arg : go n     args
620          go n [] = []
621 insertRetAddr _ args = args
622 #endif
623
624 ret_addr_arg = (text "original_return_addr", text "void*", undefined, 
625                 typeMachRep addrPrimTy)
626
627 -- This function returns the primitive type associated with the boxed
628 -- type argument to a foreign export (eg. Int ==> Int#).
629 getPrimTyOf :: Type -> Type
630 getPrimTyOf ty
631   | isBoolTy rep_ty = intPrimTy
632   -- Except for Bool, the types we are interested in have a single constructor
633   -- with a single primitive-typed argument (see TcType.legalFEArgTyCon).
634   | otherwise =
635   case splitProductType_maybe rep_ty of
636      Just (_, _, data_con, [prim_ty]) ->
637         ASSERT(dataConSourceArity data_con == 1)
638         ASSERT2(isUnLiftedType prim_ty, ppr prim_ty)
639         prim_ty
640      _other -> pprPanic "DsForeign.getPrimTyOf" (ppr ty)
641   where
642         rep_ty = repType ty
643 \end{code}