[project @ 2003-05-29 14:39:26 by sof]
[ghc-hetmet.git] / ghc / compiler / deSugar / DsCCall.lhs
1 %
2 % (c) The AQUA Project, Glasgow University, 1994-1998
3 %
4 \section[DsCCall]{Desugaring \tr{_ccall_}s and \tr{_casm_}s}
5
6 \begin{code}
7 module DsCCall 
8         ( dsCCall
9         , mkFCall
10         , unboxArg
11         , boxResult
12         , resultWrapper
13         ) where
14
15 #include "HsVersions.h"
16
17 import CoreSyn
18
19 import DsMonad
20
21 import CoreUtils        ( exprType, mkCoerce2 )
22 import Id               ( Id, mkWildId )
23 import MkId             ( mkFCallId, realWorldPrimId, mkPrimOpId )
24 import Maybes           ( maybeToBool )
25 import ForeignCall      ( ForeignCall(..), CCallSpec(..), CCallTarget(..), Safety, CCallConv(..) )
26 import DataCon          ( splitProductType_maybe, dataConSourceArity, dataConWrapId )
27 import ForeignCall      ( ForeignCall, CCallTarget(..) )
28
29 import TcType           ( tcSplitTyConApp_maybe )
30 import Type             ( Type, isUnLiftedType, mkFunTys, mkFunTy,
31                           tyVarsOfType, mkForAllTys, mkTyConApp, 
32                           isPrimitiveType, splitTyConApp_maybe, 
33                           splitNewType_maybe, splitForAllTy_maybe,
34                           splitTyConApp,
35                           isUnboxedTupleType
36                         )
37
38 import PrimOp           ( PrimOp(..) )
39 import TysPrim          ( realWorldStatePrimTy, intPrimTy,
40                           byteArrayPrimTyCon, mutableByteArrayPrimTyCon,
41                           addrPrimTy
42                         )
43 import TyCon            ( TyCon, tyConDataCons, tyConName )
44 import TysWiredIn       ( unitDataConId,
45                           unboxedSingletonDataCon, unboxedPairDataCon,
46                           unboxedSingletonTyCon, unboxedPairTyCon,
47                           trueDataCon, falseDataCon, 
48                           trueDataConId, falseDataConId,
49                           listTyCon, charTyCon, stringTy,
50                           tupleTyCon, tupleCon
51                         )
52 import BasicTypes       ( Boxity(..) )
53 import Literal          ( mkMachInt )
54 import CStrings         ( CLabelString )
55 import PrelNames        ( Unique, hasKey, ioTyConKey, boolTyConKey, unitTyConKey,
56                           int8TyConKey, int16TyConKey, int32TyConKey,
57                           word8TyConKey, word16TyConKey, word32TyConKey
58                           -- dotnet interop
59                           , marshalStringName, unmarshalStringName
60                           , marshalObjectName, unmarshalObjectName
61                           , objectTyConName
62                         )
63 import VarSet           ( varSetElems )
64 import Constants        ( wORD_SIZE)
65 import Outputable
66 \end{code}
67
68 Desugaring of @ccall@s consists of adding some state manipulation,
69 unboxing any boxed primitive arguments and boxing the result if
70 desired.
71
72 The state stuff just consists of adding in
73 @PrimIO (\ s -> case s of { S# s# -> ... })@ in an appropriate place.
74
75 The unboxing is straightforward, as all information needed to unbox is
76 available from the type.  For each boxed-primitive argument, we
77 transform:
78 \begin{verbatim}
79    _ccall_ foo [ r, t1, ... tm ] e1 ... em
80    |
81    |
82    V
83    case e1 of { T1# x1# ->
84    ...
85    case em of { Tm# xm# -> xm#
86    ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
87    } ... }
88 \end{verbatim}
89
90 The reboxing of a @_ccall_@ result is a bit tricker: the types don't
91 contain information about the state-pairing functions so we have to
92 keep a list of \tr{(type, s-p-function)} pairs.  We transform as
93 follows:
94 \begin{verbatim}
95    ccall# foo [ r, t1#, ... tm# ] e1# ... em#
96    |
97    |
98    V
99    \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
100           (StateAnd<r># result# state#) -> (R# result#, realWorld#)
101 \end{verbatim}
102
103 \begin{code}
104 dsCCall :: CLabelString -- C routine to invoke
105         -> [CoreExpr]   -- Arguments (desugared)
106         -> Safety       -- Safety of the call
107         -> Bool         -- True <=> really a "_casm_"
108         -> Type         -- Type of the result: IO t
109         -> DsM CoreExpr
110
111 dsCCall lbl args may_gc is_asm result_ty
112   = mapAndUnzipDs unboxArg args        `thenDs` \ (unboxed_args, arg_wrappers) ->
113     boxResult [] id Nothing result_ty  `thenDs` \ (ccall_result_ty, res_wrapper) ->
114     getUniqueDs                        `thenDs` \ uniq ->
115     let
116         target | is_asm    = CasmTarget lbl
117                | otherwise = StaticTarget lbl
118         the_fcall    = CCall (CCallSpec target CCallConv may_gc)
119         the_prim_app = mkFCall uniq the_fcall unboxed_args ccall_result_ty
120     in
121     returnDs (foldr ($) (res_wrapper the_prim_app) arg_wrappers)
122
123 mkFCall :: Unique -> ForeignCall 
124         -> [CoreExpr]   -- Args
125         -> Type         -- Result type
126         -> CoreExpr
127 -- Construct the ccall.  The only tricky bit is that the ccall Id should have
128 -- no free vars, so if any of the arg tys do we must give it a polymorphic type.
129 --      [I forget *why* it should have no free vars!]
130 -- For example:
131 --      mkCCall ... [s::StablePtr (a->b), x::Addr, c::Char]
132 --
133 -- Here we build a ccall thus
134 --      (ccallid::(forall a b.  StablePtr (a -> b) -> Addr -> Char -> IO Addr))
135 --                      a b s x c
136 mkFCall uniq the_fcall val_args res_ty
137   = mkApps (mkVarApps (Var the_fcall_id) tyvars) val_args
138   where
139     arg_tys = map exprType val_args
140     body_ty = (mkFunTys arg_tys res_ty)
141     tyvars  = varSetElems (tyVarsOfType body_ty)
142     ty      = mkForAllTys tyvars body_ty
143     the_fcall_id = mkFCallId uniq the_fcall ty
144 \end{code}
145
146 \begin{code}
147 unboxArg :: CoreExpr                    -- The supplied argument
148          -> DsM (CoreExpr,              -- To pass as the actual argument
149                  CoreExpr -> CoreExpr   -- Wrapper to unbox the arg
150                 )
151 -- Example: if the arg is e::Int, unboxArg will return
152 --      (x#::Int#, \W. case x of I# x# -> W)
153 -- where W is a CoreExpr that probably mentions x#
154
155 unboxArg arg
156   -- Primtive types: nothing to unbox
157   | isPrimitiveType arg_ty
158   = returnDs (arg, \body -> body)
159
160   -- Recursive newtypes
161   | Just rep_ty <- splitNewType_maybe arg_ty
162   = unboxArg (mkCoerce2 rep_ty arg_ty arg)
163       
164   -- Booleans
165   | Just (tc,_) <- splitTyConApp_maybe arg_ty, 
166     tc `hasKey` boolTyConKey
167   = newSysLocalDs intPrimTy             `thenDs` \ prim_arg ->
168     returnDs (Var prim_arg,
169               \ body -> Case (Case arg (mkWildId arg_ty)
170                                        [(DataAlt falseDataCon,[],mkIntLit 0),
171                                         (DataAlt trueDataCon, [],mkIntLit 1)])
172                              prim_arg 
173                              [(DEFAULT,[],body)])
174
175   -- Data types with a single constructor, which has a single, primitive-typed arg
176   -- This deals with Int, Float etc
177   | is_product_type && data_con_arity == 1 
178   = ASSERT(isUnLiftedType data_con_arg_ty1 )    -- Typechecker ensures this
179     newSysLocalDs arg_ty                `thenDs` \ case_bndr ->
180     newSysLocalDs data_con_arg_ty1      `thenDs` \ prim_arg ->
181     returnDs (Var prim_arg,
182               \ body -> Case arg case_bndr [(DataAlt data_con,[prim_arg],body)]
183     )
184
185   -- Byte-arrays, both mutable and otherwise; hack warning
186   -- We're looking for values of type ByteArray, MutableByteArray
187   --    data ByteArray          ix = ByteArray        ix ix ByteArray#
188   --    data MutableByteArray s ix = MutableByteArray ix ix (MutableByteArray# s)
189   | is_product_type &&
190     data_con_arity == 3 &&
191     maybeToBool maybe_arg3_tycon &&
192     (arg3_tycon ==  byteArrayPrimTyCon ||
193      arg3_tycon ==  mutableByteArrayPrimTyCon)
194     -- and, of course, it is an instance of CCallable
195   = newSysLocalDs arg_ty                `thenDs` \ case_bndr ->
196     newSysLocalsDs data_con_arg_tys     `thenDs` \ vars@[l_var, r_var, arr_cts_var] ->
197     returnDs (Var arr_cts_var,
198               \ body -> Case arg case_bndr [(DataAlt data_con,vars,body)]
199     )
200
201   | Just (tc, [arg_ty]) <- splitTyConApp_maybe arg_ty,
202     tc == listTyCon,
203     Just (cc,[]) <- splitTyConApp_maybe arg_ty,
204     cc == charTyCon
205     -- String; dotnet only
206   = dsLookupGlobalId marshalStringName `thenDs` \ unpack_id ->
207     newSysLocalDs addrPrimTy           `thenDs` \ prim_string ->
208     returnDs (Var prim_string,
209               \ body ->
210                 let
211                  io_ty = exprType body
212                  (Just (_,[io_arg])) = tcSplitTyConApp_maybe io_ty
213                 in
214                 mkApps (Var unpack_id)
215                        [ Type io_arg
216                        , arg
217                        , Lam prim_string body
218                        ])
219   | Just (tc, [arg_ty]) <- splitTyConApp_maybe arg_ty,
220     tyConName tc == objectTyConName
221     -- Object; dotnet only
222   = dsLookupGlobalId marshalObjectName `thenDs` \ unpack_id ->
223     newSysLocalDs addrPrimTy           `thenDs` \ prim_obj  ->
224     returnDs (Var prim_obj,
225               \ body ->
226                 let
227                  io_ty = exprType body
228                  (Just (_,[io_arg])) = tcSplitTyConApp_maybe io_ty
229                 in
230                 mkApps (Var unpack_id)
231                        [ Type io_arg
232                        , arg
233                        , Lam prim_obj body
234                        ])
235
236   | otherwise
237   = getSrcLocDs `thenDs` \ l ->
238     pprPanic "unboxArg: " (ppr l <+> ppr arg_ty)
239   where
240     arg_ty                                      = exprType arg
241     maybe_product_type                          = splitProductType_maybe arg_ty
242     is_product_type                             = maybeToBool maybe_product_type
243     Just (_, _, data_con, data_con_arg_tys)     = maybe_product_type
244     data_con_arity                              = dataConSourceArity data_con
245     (data_con_arg_ty1 : _)                      = data_con_arg_tys
246
247     (_ : _ : data_con_arg_ty3 : _) = data_con_arg_tys
248     maybe_arg3_tycon               = splitTyConApp_maybe data_con_arg_ty3
249     Just (arg3_tycon,_)            = maybe_arg3_tycon
250 \end{code}
251
252
253 \begin{code}
254 boxResult :: [Id]
255           -> ((Maybe Type, CoreExpr -> CoreExpr) -> (Maybe Type, CoreExpr -> CoreExpr))
256           -> Maybe Id
257           -> Type
258           -> DsM (Type, CoreExpr -> CoreExpr)
259
260 -- Takes the result of the user-level ccall: 
261 --      either (IO t), 
262 --      or maybe just t for an side-effect-free call
263 -- Returns a wrapper for the primitive ccall itself, along with the
264 -- type of the result of the primitive ccall.  This result type
265 -- will be of the form  
266 --      State# RealWorld -> (# State# RealWorld, t' #)
267 -- where t' is the unwrapped form of t.  If t is simply (), then
268 -- the result type will be 
269 --      State# RealWorld -> (# State# RealWorld #)
270
271 boxResult arg_ids augment mbTopCon result_ty
272   = case tcSplitTyConApp_maybe result_ty of
273         -- This split absolutely has to be a tcSplit, because we must
274         -- see the IO type; and it's a newtype which is transparent to splitTyConApp.
275
276         -- The result is IO t, so wrap the result in an IO constructor
277         Just (io_tycon, [io_res_ty]) | io_tycon `hasKey` ioTyConKey
278                 -> resultWrapper io_res_ty             `thenDs` \ res ->
279                    let aug_res          = augment res
280                        extra_result_tys =
281                          case aug_res of
282                            (Just ty,_) 
283                              | isUnboxedTupleType ty ->
284                                 let (Just (_, ls)) = splitTyConApp_maybe ty in tail ls
285                            _ -> []
286                    in
287                    mk_alt (return_result extra_result_tys) aug_res 
288                                                         `thenDs` \ (ccall_res_ty, the_alt) ->
289                    newSysLocalDs  realWorldStatePrimTy  `thenDs` \ state_id ->
290                    let
291                         io_data_con = head (tyConDataCons io_tycon)
292                         toIOCon = 
293                           case mbTopCon of
294                             Nothing -> dataConWrapId io_data_con
295                             Just x  -> x
296                         wrap = \ the_call -> 
297                                  mkApps (Var toIOCon)
298                                            [ Type io_res_ty, 
299                                              Lam state_id $
300                                               Case (App the_call (Var state_id))
301                                                    (mkWildId ccall_res_ty)
302                                                    [the_alt]
303                                            ]
304                    in
305                    returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
306                 where
307                    return_result ts state anss 
308                      = mkConApp (tupleCon Unboxed (2 + length ts))
309                                 (Type realWorldStatePrimTy : Type io_res_ty : map Type ts ++
310                                  state : anss) 
311         -- It isn't, so do unsafePerformIO
312         -- It's not conveniently available, so we inline it
313         other -> resultWrapper result_ty            `thenDs` \ res ->
314                  mk_alt return_result (augment res) `thenDs` \ (ccall_res_ty, the_alt) ->
315                  let
316                     wrap = \ the_call -> Case (App the_call (Var realWorldPrimId)) 
317                                               (mkWildId ccall_res_ty)
318                                               [the_alt]
319                  in
320                  returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
321               where
322                  return_result state [ans] = ans
323                  return_result _ _ = panic "return_result: expected single result"
324   where
325     mk_alt return_result (Nothing, wrap_result)
326         =       -- The ccall returns ()
327           newSysLocalDs realWorldStatePrimTy    `thenDs` \ state_id ->
328           let
329                 the_rhs = return_result (Var state_id) 
330                                         [wrap_result (panic "boxResult")]
331
332                 ccall_res_ty = mkTyConApp unboxedSingletonTyCon [realWorldStatePrimTy]
333                 the_alt      = (DataAlt unboxedSingletonDataCon, [state_id], the_rhs)
334           in
335           returnDs (ccall_res_ty, the_alt)
336
337     mk_alt return_result (Just prim_res_ty, wrap_result)
338                 -- The ccall returns a non-() value
339         | isUnboxedTupleType prim_res_ty
340         = let
341                 (Just (_, ls@(prim_res_ty1:extras))) = splitTyConApp_maybe prim_res_ty
342                 arity = 1 + length ls
343           in
344           mapDs newSysLocalDs ls                `thenDs` \ args_ids@(result_id:as) ->
345           newSysLocalDs realWorldStatePrimTy    `thenDs` \ state_id ->
346           let
347                 the_rhs = return_result (Var state_id) 
348                                         (wrap_result (Var result_id) : map Var as)
349                 ccall_res_ty = mkTyConApp (tupleTyCon Unboxed arity)
350                                           (realWorldStatePrimTy : ls)
351                 the_alt      = ( DataAlt (tupleCon Unboxed arity)
352                                , (state_id : args_ids)
353                                , the_rhs
354                                )
355           in
356           returnDs (ccall_res_ty, the_alt)
357         | otherwise
358         =       
359           newSysLocalDs prim_res_ty             `thenDs` \ result_id ->
360           newSysLocalDs realWorldStatePrimTy    `thenDs` \ state_id ->
361           let
362                 the_rhs = return_result (Var state_id) 
363                                         [wrap_result (Var result_id)]
364
365                 ccall_res_ty = mkTyConApp unboxedPairTyCon [realWorldStatePrimTy, prim_res_ty]
366                 the_alt      = (DataAlt unboxedPairDataCon, [state_id, result_id], the_rhs)
367           in
368           returnDs (ccall_res_ty, the_alt)
369
370
371 resultWrapper :: Type
372               -> DsM (Maybe Type,               -- Type of the expected result, if any
373                       CoreExpr -> CoreExpr)     -- Wrapper for the result 
374 resultWrapper result_ty
375   -- Base case 1: primitive types
376   | isPrimitiveType result_ty
377   = returnDs (Just result_ty, \e -> e)
378
379   -- Base case 2: the unit type ()
380   | Just (tc,_) <- maybe_tc_app, tc `hasKey` unitTyConKey
381   = returnDs (Nothing, \e -> Var unitDataConId)
382
383   -- Base case 3: the boolean type
384   | Just (tc,_) <- maybe_tc_app, tc `hasKey` boolTyConKey
385   = returnDs
386      (Just intPrimTy, \e -> Case e (mkWildId intPrimTy)
387                                    [(DEFAULT             ,[],Var trueDataConId ),
388                                     (LitAlt (mkMachInt 0),[],Var falseDataConId)])
389
390   -- Recursive newtypes
391   | Just rep_ty <- splitNewType_maybe result_ty
392   = resultWrapper rep_ty `thenDs` \ (maybe_ty, wrapper) ->
393     returnDs (maybe_ty, \e -> mkCoerce2 result_ty rep_ty (wrapper e))
394
395   -- The type might contain foralls (eg. for dummy type arguments,
396   -- referring to 'Ptr a' is legal).
397   | Just (tyvar, rest) <- splitForAllTy_maybe result_ty
398   = resultWrapper rest `thenDs` \ (maybe_ty, wrapper) ->
399     returnDs (maybe_ty, \e -> Lam tyvar (wrapper e))
400
401   -- Data types with a single constructor, which has a single arg
402   | Just (tycon, tycon_arg_tys, data_con, data_con_arg_tys) <- splitProductType_maybe result_ty,
403     dataConSourceArity data_con == 1
404   = let
405         (unwrapped_res_ty : _) = data_con_arg_tys
406         narrow_wrapper         = maybeNarrow tycon
407     in
408     resultWrapper unwrapped_res_ty `thenDs` \ (maybe_ty, wrapper) ->
409     returnDs
410       (maybe_ty, \e -> mkApps (Var (dataConWrapId data_con)) 
411                               (map Type tycon_arg_tys ++ [wrapper (narrow_wrapper e)]))
412
413     -- Strings; 'dotnet' only.
414   | Just (tc, [arg_ty]) <- maybe_tc_app,               tc == listTyCon,
415     Just (cc,[])        <- splitTyConApp_maybe arg_ty, cc == charTyCon
416   = dsLookupGlobalId unmarshalStringName        `thenDs` \ pack_id ->
417     returnDs (Just addrPrimTy,
418               \ e -> App (Var pack_id) e)
419
420     -- Objects; 'dotnet' only.
421   | Just (tc, [arg_ty]) <- maybe_tc_app, 
422     tyConName tc == objectTyConName
423   = dsLookupGlobalId unmarshalObjectName        `thenDs` \ pack_id ->
424     returnDs (Just addrPrimTy,
425               \ e -> App (Var pack_id) e)
426
427   | otherwise
428   = pprPanic "resultWrapper" (ppr result_ty)
429   where
430     maybe_tc_app = splitTyConApp_maybe result_ty
431
432 -- When the result of a foreign call is smaller than the word size, we
433 -- need to sign- or zero-extend the result up to the word size.  The C
434 -- standard appears to say that this is the responsibility of the
435 -- caller, not the callee.
436
437 maybeNarrow :: TyCon -> (CoreExpr -> CoreExpr)
438 maybeNarrow tycon
439   | tycon `hasKey` int8TyConKey   = \e -> App (Var (mkPrimOpId Narrow8IntOp)) e
440   | tycon `hasKey` int16TyConKey  = \e -> App (Var (mkPrimOpId Narrow16IntOp)) e
441   | tycon `hasKey` int32TyConKey
442          && wORD_SIZE > 4         = \e -> App (Var (mkPrimOpId Narrow32IntOp)) e
443
444   | tycon `hasKey` word8TyConKey  = \e -> App (Var (mkPrimOpId Narrow8WordOp)) e
445   | tycon `hasKey` word16TyConKey = \e -> App (Var (mkPrimOpId Narrow16WordOp)) e
446   | tycon `hasKey` word32TyConKey
447          && wORD_SIZE > 4         = \e -> App (Var (mkPrimOpId Narrow32WordOp)) e
448   | otherwise                     = id
449 \end{code}