2 % (c) The AQUA Project, Glasgow University, 1994-1998
4 \section[DsCCall]{Desugaring C calls}
15 #include "HsVersions.h"
22 import CoreUtils ( exprType, coreAltType, mkCoerce2 )
23 import Id ( Id, mkWildId )
24 import MkId ( mkFCallId, realWorldPrimId, mkPrimOpId )
25 import Maybes ( maybeToBool )
26 import ForeignCall ( ForeignCall(..), CCallSpec(..), CCallTarget(..), Safety,
27 CCallConv(..), CLabelString )
28 import DataCon ( splitProductType_maybe, dataConSourceArity, dataConWrapId )
29 import ForeignCall ( ForeignCall, CCallTarget(..) )
31 import TcType ( tcSplitTyConApp_maybe )
32 import Type ( Type, isUnLiftedType, mkFunTys, mkFunTy,
33 tyVarsOfType, mkForAllTys, mkTyConApp,
34 isPrimitiveType, splitTyConApp_maybe,
35 splitRecNewType_maybe, splitForAllTy_maybe,
39 import PrimOp ( PrimOp(..) )
40 import TysPrim ( realWorldStatePrimTy, intPrimTy,
41 byteArrayPrimTyCon, mutableByteArrayPrimTyCon,
44 import TyCon ( TyCon, tyConDataCons, tyConName )
45 import TysWiredIn ( unitDataConId,
46 unboxedSingletonDataCon, unboxedPairDataCon,
47 unboxedSingletonTyCon, unboxedPairTyCon,
48 trueDataCon, falseDataCon,
49 trueDataConId, falseDataConId,
50 listTyCon, charTyCon, boolTy,
53 import BasicTypes ( Boxity(..) )
54 import Literal ( mkMachInt )
55 import PrelNames ( Unique, hasKey, ioTyConKey, boolTyConKey, unitTyConKey,
56 int8TyConKey, int16TyConKey, int32TyConKey,
57 word8TyConKey, word16TyConKey, word32TyConKey
59 , marshalStringName, unmarshalStringName
60 , marshalObjectName, unmarshalObjectName
63 import VarSet ( varSetElems )
64 import Constants ( wORD_SIZE)
73 Desugaring of @ccall@s consists of adding some state manipulation,
74 unboxing any boxed primitive arguments and boxing the result if
77 The state stuff just consists of adding in
78 @PrimIO (\ s -> case s of { S# s# -> ... })@ in an appropriate place.
80 The unboxing is straightforward, as all information needed to unbox is
81 available from the type. For each boxed-primitive argument, we
84 _ccall_ foo [ r, t1, ... tm ] e1 ... em
88 case e1 of { T1# x1# ->
90 case em of { Tm# xm# -> xm#
91 ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
95 The reboxing of a @_ccall_@ result is a bit tricker: the types don't
96 contain information about the state-pairing functions so we have to
97 keep a list of \tr{(type, s-p-function)} pairs. We transform as
100 ccall# foo [ r, t1#, ... tm# ] e1# ... em#
104 \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
105 (StateAnd<r># result# state#) -> (R# result#, realWorld#)
109 dsCCall :: CLabelString -- C routine to invoke
110 -> [CoreExpr] -- Arguments (desugared)
111 -> Safety -- Safety of the call
112 -> Type -- Type of the result: IO t
115 dsCCall lbl args may_gc result_ty
116 = mapAndUnzipDs unboxArg args `thenDs` \ (unboxed_args, arg_wrappers) ->
117 boxResult [] id Nothing result_ty `thenDs` \ (ccall_result_ty, res_wrapper) ->
118 newUnique `thenDs` \ uniq ->
120 target = StaticTarget lbl
121 the_fcall = CCall (CCallSpec target CCallConv may_gc)
122 the_prim_app = mkFCall uniq the_fcall unboxed_args ccall_result_ty
124 returnDs (foldr ($) (res_wrapper the_prim_app) arg_wrappers)
126 mkFCall :: Unique -> ForeignCall
127 -> [CoreExpr] -- Args
128 -> Type -- Result type
130 -- Construct the ccall. The only tricky bit is that the ccall Id should have
131 -- no free vars, so if any of the arg tys do we must give it a polymorphic type.
132 -- [I forget *why* it should have no free vars!]
134 -- mkCCall ... [s::StablePtr (a->b), x::Addr, c::Char]
136 -- Here we build a ccall thus
137 -- (ccallid::(forall a b. StablePtr (a -> b) -> Addr -> Char -> IO Addr))
139 mkFCall uniq the_fcall val_args res_ty
140 = mkApps (mkVarApps (Var the_fcall_id) tyvars) val_args
142 arg_tys = map exprType val_args
143 body_ty = (mkFunTys arg_tys res_ty)
144 tyvars = varSetElems (tyVarsOfType body_ty)
145 ty = mkForAllTys tyvars body_ty
146 the_fcall_id = mkFCallId uniq the_fcall ty
150 unboxArg :: CoreExpr -- The supplied argument
151 -> DsM (CoreExpr, -- To pass as the actual argument
152 CoreExpr -> CoreExpr -- Wrapper to unbox the arg
154 -- Example: if the arg is e::Int, unboxArg will return
155 -- (x#::Int#, \W. case x of I# x# -> W)
156 -- where W is a CoreExpr that probably mentions x#
159 -- Primtive types: nothing to unbox
160 | isPrimitiveType arg_ty
161 = returnDs (arg, \body -> body)
163 -- Recursive newtypes
164 | Just rep_ty <- splitRecNewType_maybe arg_ty
165 = unboxArg (mkCoerce2 rep_ty arg_ty arg)
168 | Just (tc,_) <- splitTyConApp_maybe arg_ty,
169 tc `hasKey` boolTyConKey
170 = newSysLocalDs intPrimTy `thenDs` \ prim_arg ->
171 returnDs (Var prim_arg,
172 \ body -> Case (Case arg (mkWildId arg_ty) intPrimTy
173 [(DataAlt falseDataCon,[],mkIntLit 0),
174 (DataAlt trueDataCon, [],mkIntLit 1)])
175 -- In increasing tag order!
180 -- Data types with a single constructor, which has a single, primitive-typed arg
181 -- This deals with Int, Float etc; also Ptr, ForeignPtr
182 | is_product_type && data_con_arity == 1
183 = ASSERT2(isUnLiftedType data_con_arg_ty1, pprType arg_ty)
184 -- Typechecker ensures this
185 newSysLocalDs arg_ty `thenDs` \ case_bndr ->
186 newSysLocalDs data_con_arg_ty1 `thenDs` \ prim_arg ->
187 returnDs (Var prim_arg,
188 \ body -> Case arg case_bndr (exprType body) [(DataAlt data_con,[prim_arg],body)]
191 -- Byte-arrays, both mutable and otherwise; hack warning
192 -- We're looking for values of type ByteArray, MutableByteArray
193 -- data ByteArray ix = ByteArray ix ix ByteArray#
194 -- data MutableByteArray s ix = MutableByteArray ix ix (MutableByteArray# s)
196 data_con_arity == 3 &&
197 maybeToBool maybe_arg3_tycon &&
198 (arg3_tycon == byteArrayPrimTyCon ||
199 arg3_tycon == mutableByteArrayPrimTyCon)
200 -- and, of course, it is an instance of CCallable
201 = newSysLocalDs arg_ty `thenDs` \ case_bndr ->
202 newSysLocalsDs data_con_arg_tys `thenDs` \ vars@[l_var, r_var, arr_cts_var] ->
203 returnDs (Var arr_cts_var,
204 \ body -> Case arg case_bndr (exprType body) [(DataAlt data_con,vars,body)]
208 | Just (tc, [arg_ty]) <- splitTyConApp_maybe arg_ty,
210 Just (cc,[]) <- splitTyConApp_maybe arg_ty,
212 -- String; dotnet only
213 = dsLookupGlobalId marshalStringName `thenDs` \ unpack_id ->
214 newSysLocalDs addrPrimTy `thenDs` \ prim_string ->
215 returnDs (Var prim_string,
218 io_ty = exprType body
219 (Just (_,[io_arg])) = tcSplitTyConApp_maybe io_ty
221 mkApps (Var unpack_id)
224 , Lam prim_string body
226 | Just (tc, [arg_ty]) <- splitTyConApp_maybe arg_ty,
227 tyConName tc == objectTyConName
228 -- Object; dotnet only
229 = dsLookupGlobalId marshalObjectName `thenDs` \ unpack_id ->
230 newSysLocalDs addrPrimTy `thenDs` \ prim_obj ->
231 returnDs (Var prim_obj,
234 io_ty = exprType body
235 (Just (_,[io_arg])) = tcSplitTyConApp_maybe io_ty
237 mkApps (Var unpack_id)
244 = getSrcSpanDs `thenDs` \ l ->
245 pprPanic "unboxArg: " (ppr l <+> ppr arg_ty)
247 arg_ty = exprType arg
248 maybe_product_type = splitProductType_maybe arg_ty
249 is_product_type = maybeToBool maybe_product_type
250 Just (_, _, data_con, data_con_arg_tys) = maybe_product_type
251 data_con_arity = dataConSourceArity data_con
252 (data_con_arg_ty1 : _) = data_con_arg_tys
254 (_ : _ : data_con_arg_ty3 : _) = data_con_arg_tys
255 maybe_arg3_tycon = splitTyConApp_maybe data_con_arg_ty3
256 Just (arg3_tycon,_) = maybe_arg3_tycon
262 -> ((Maybe Type, CoreExpr -> CoreExpr) -> (Maybe Type, CoreExpr -> CoreExpr))
265 -> DsM (Type, CoreExpr -> CoreExpr)
267 -- Takes the result of the user-level ccall:
269 -- or maybe just t for an side-effect-free call
270 -- Returns a wrapper for the primitive ccall itself, along with the
271 -- type of the result of the primitive ccall. This result type
272 -- will be of the form
273 -- State# RealWorld -> (# State# RealWorld, t' #)
274 -- where t' is the unwrapped form of t. If t is simply (), then
275 -- the result type will be
276 -- State# RealWorld -> (# State# RealWorld #)
278 boxResult arg_ids augment mbTopCon result_ty
279 = case tcSplitTyConApp_maybe result_ty of
280 -- This split absolutely has to be a tcSplit, because we must
281 -- see the IO type; and it's a newtype which is transparent to splitTyConApp.
283 -- The result is IO t, so wrap the result in an IO constructor
284 Just (io_tycon, [io_res_ty]) | io_tycon `hasKey` ioTyConKey
285 -> resultWrapper io_res_ty `thenDs` \ res ->
286 let aug_res = augment res
290 | isUnboxedTupleType ty ->
291 let (Just (_, ls)) = splitTyConApp_maybe ty in tail ls
294 mk_alt (return_result extra_result_tys) aug_res
295 `thenDs` \ (ccall_res_ty, the_alt) ->
296 newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
298 io_data_con = head (tyConDataCons io_tycon)
301 Nothing -> dataConWrapId io_data_con
307 Case (App the_call (Var state_id))
308 (mkWildId ccall_res_ty)
309 (coreAltType the_alt)
313 returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
315 return_result ts state anss
316 = mkConApp (tupleCon Unboxed (2 + length ts))
317 (Type realWorldStatePrimTy : Type io_res_ty : map Type ts ++
319 -- It isn't, so do unsafePerformIO
320 -- It's not conveniently available, so we inline it
321 other -> resultWrapper result_ty `thenDs` \ res ->
322 mk_alt return_result (augment res) `thenDs` \ (ccall_res_ty, the_alt) ->
324 wrap = \ the_call -> Case (App the_call (Var realWorldPrimId))
325 (mkWildId ccall_res_ty)
326 (coreAltType the_alt)
329 returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
331 return_result state [ans] = ans
332 return_result _ _ = panic "return_result: expected single result"
334 mk_alt return_result (Nothing, wrap_result)
335 = -- The ccall returns ()
336 newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
338 the_rhs = return_result (Var state_id)
339 [wrap_result (panic "boxResult")]
341 ccall_res_ty = mkTyConApp unboxedSingletonTyCon [realWorldStatePrimTy]
342 the_alt = (DataAlt unboxedSingletonDataCon, [state_id], the_rhs)
344 returnDs (ccall_res_ty, the_alt)
346 mk_alt return_result (Just prim_res_ty, wrap_result)
347 -- The ccall returns a non-() value
348 | isUnboxedTupleType prim_res_ty
350 Just (_, ls) = splitTyConApp_maybe prim_res_ty
351 arity = 1 + length ls
353 mappM newSysLocalDs ls `thenDs` \ args_ids@(result_id:as) ->
354 newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
356 the_rhs = return_result (Var state_id)
357 (wrap_result (Var result_id) : map Var as)
358 ccall_res_ty = mkTyConApp (tupleTyCon Unboxed arity)
359 (realWorldStatePrimTy : ls)
360 the_alt = ( DataAlt (tupleCon Unboxed arity)
361 , (state_id : args_ids)
365 returnDs (ccall_res_ty, the_alt)
367 = newSysLocalDs prim_res_ty `thenDs` \ result_id ->
368 newSysLocalDs realWorldStatePrimTy `thenDs` \ state_id ->
370 the_rhs = return_result (Var state_id)
371 [wrap_result (Var result_id)]
373 ccall_res_ty = mkTyConApp unboxedPairTyCon [realWorldStatePrimTy, prim_res_ty]
374 the_alt = (DataAlt unboxedPairDataCon, [state_id, result_id], the_rhs)
376 returnDs (ccall_res_ty, the_alt)
379 resultWrapper :: Type
380 -> DsM (Maybe Type, -- Type of the expected result, if any
381 CoreExpr -> CoreExpr) -- Wrapper for the result
382 resultWrapper result_ty
383 -- Base case 1: primitive types
384 | isPrimitiveType result_ty
385 = returnDs (Just result_ty, \e -> e)
387 -- Base case 2: the unit type ()
388 | Just (tc,_) <- maybe_tc_app, tc `hasKey` unitTyConKey
389 = returnDs (Nothing, \e -> Var unitDataConId)
391 -- Base case 3: the boolean type
392 | Just (tc,_) <- maybe_tc_app, tc `hasKey` boolTyConKey
394 (Just intPrimTy, \e -> Case e (mkWildId intPrimTy)
396 [(DEFAULT ,[],Var trueDataConId ),
397 (LitAlt (mkMachInt 0),[],Var falseDataConId)])
399 -- Recursive newtypes
400 | Just rep_ty <- splitRecNewType_maybe result_ty
401 = resultWrapper rep_ty `thenDs` \ (maybe_ty, wrapper) ->
402 returnDs (maybe_ty, \e -> mkCoerce2 result_ty rep_ty (wrapper e))
404 -- The type might contain foralls (eg. for dummy type arguments,
405 -- referring to 'Ptr a' is legal).
406 | Just (tyvar, rest) <- splitForAllTy_maybe result_ty
407 = resultWrapper rest `thenDs` \ (maybe_ty, wrapper) ->
408 returnDs (maybe_ty, \e -> Lam tyvar (wrapper e))
410 -- Data types with a single constructor, which has a single arg
411 -- This includes types like Ptr and ForeignPtr
412 | Just (tycon, tycon_arg_tys, data_con, data_con_arg_tys) <- splitProductType_maybe result_ty,
413 dataConSourceArity data_con == 1
415 (unwrapped_res_ty : _) = data_con_arg_tys
416 narrow_wrapper = maybeNarrow tycon
418 resultWrapper unwrapped_res_ty `thenDs` \ (maybe_ty, wrapper) ->
420 (maybe_ty, \e -> mkApps (Var (dataConWrapId data_con))
421 (map Type tycon_arg_tys ++ [wrapper (narrow_wrapper e)]))
423 -- Strings; 'dotnet' only.
424 | Just (tc, [arg_ty]) <- maybe_tc_app, tc == listTyCon,
425 Just (cc,[]) <- splitTyConApp_maybe arg_ty, cc == charTyCon
426 = dsLookupGlobalId unmarshalStringName `thenDs` \ pack_id ->
427 returnDs (Just addrPrimTy,
428 \ e -> App (Var pack_id) e)
430 -- Objects; 'dotnet' only.
431 | Just (tc, [arg_ty]) <- maybe_tc_app,
432 tyConName tc == objectTyConName
433 = dsLookupGlobalId unmarshalObjectName `thenDs` \ pack_id ->
434 returnDs (Just addrPrimTy,
435 \ e -> App (Var pack_id) e)
438 = pprPanic "resultWrapper" (ppr result_ty)
440 maybe_tc_app = splitTyConApp_maybe result_ty
442 -- When the result of a foreign call is smaller than the word size, we
443 -- need to sign- or zero-extend the result up to the word size. The C
444 -- standard appears to say that this is the responsibility of the
445 -- caller, not the callee.
447 maybeNarrow :: TyCon -> (CoreExpr -> CoreExpr)
449 | tycon `hasKey` int8TyConKey = \e -> App (Var (mkPrimOpId Narrow8IntOp)) e
450 | tycon `hasKey` int16TyConKey = \e -> App (Var (mkPrimOpId Narrow16IntOp)) e
451 | tycon `hasKey` int32TyConKey
452 && wORD_SIZE > 4 = \e -> App (Var (mkPrimOpId Narrow32IntOp)) e
454 | tycon `hasKey` word8TyConKey = \e -> App (Var (mkPrimOpId Narrow8WordOp)) e
455 | tycon `hasKey` word16TyConKey = \e -> App (Var (mkPrimOpId Narrow16WordOp)) e
456 | tycon `hasKey` word32TyConKey
457 && wORD_SIZE > 4 = \e -> App (Var (mkPrimOpId Narrow32WordOp)) e