2 % (c) The AQUA Project, Glasgow University, 1994-1995
4 \section[DsCCall]{Desugaring \tr{_ccall_}s and \tr{_casm_}s}
7 #include "HsVersions.h"
9 module DsCCall ( dsCCall ) where
13 import AbsSyn -- the stuff being desugared
14 import PlainCore -- the output of desugaring
15 import DsMonad -- the monadery used in the desugarer
18 import TysPrim -- ****** ToDo: PROPERLY
22 import Id ( getInstantiatedDataConSig, mkTupleCon, DataCon(..) )
23 import Maybes ( maybeToBool, Maybe(..) )
25 #if USE_ATTACK_PRAGMAS
31 Desugaring of @ccall@s consists of adding some state manipulation,
32 unboxing any boxed primitive arguments and boxing the result if
35 The state stuff just consists of adding in
36 @\ s -> case s of { S# s# -> ... }@ in an appropriate place.
38 The unboxing is straightforward, as all information needed to unbox is
39 available from the type. For each boxed-primitive argument, we
42 _ccall_ foo [ r, t1, ... tm ] e1 ... em
46 case e1 of { T1# x1# ->
48 case em of { Tm# xm# -> xm#
49 ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
53 The reboxing of a @_ccall_@ result is a bit tricker: the types don't
54 contain information about the state-pairing functions so we have to
55 keep a list of \tr{(type, s-p-function)} pairs. We transform as
58 ccall# foo [ r, t1#, ... tm# ] e1# ... em#
62 \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
63 (StateAnd<r># result# state#) -> (R# result#, realWorld#)
67 dsCCall :: FAST_STRING -- C routine to invoke
68 -> [PlainCoreExpr] -- Arguments (desugared)
69 -> Bool -- True <=> might cause Haskell GC
70 -> Bool -- True <=> really a "_casm_"
71 -> UniType -- Type of the result (a boxed-prim type)
74 dsCCall label args may_gc is_asm result_ty
75 = newSysLocalDs realWorldStateTy `thenDs` \ old_s ->
77 mapAndUnzipDs unboxArg (CoVar old_s : args) `thenDs` \ (final_args, arg_wrappers) ->
79 boxResult result_ty `thenDs` \ (final_result_ty, res_wrapper) ->
82 the_ccall_op = CCallOp label is_asm may_gc
83 (map typeOfCoreExpr final_args)
86 mkCoPrimDs the_ccall_op
87 [] -- ***NOTE*** no ty apps; the types are inside the_ccall_op.
88 final_args `thenDs` \ the_prim_app ->
90 the_body = foldr apply (res_wrapper the_prim_app) arg_wrappers
92 returnDs (CoLam [old_s] the_body)
98 unboxArg :: PlainCoreExpr -- The supplied argument
99 -> DsM (PlainCoreExpr, -- To pass as the actual argument
100 PlainCoreExpr -> PlainCoreExpr -- Wrapper to unbox the arg
105 -- ADR Question: can this ever be used? None of the PrimTypes are
106 -- instances of the _CCallable class.
108 = returnDs (arg, \body -> body)
112 -- ToDo (ADR): - allow synonyms of Strings too?
113 = newSysLocalDs byteArrayPrimTy `thenDs` \ prim_arg ->
114 mkCoAppDs (CoVar packStringForCId) arg `thenDs` \ pack_appn ->
115 returnDs (CoVar prim_arg,
116 \body -> CoCase pack_appn (CoPrimAlts []
117 (CoBindDefault prim_arg body))
121 -- oops: we can't see the data constructors!!!
122 = can't_see_datacons_error "argument" arg_ty
124 -- Byte-arrays, both mutable and otherwise
125 -- (HACKy method -- but we really don't want the TyCons wired-in...) [WDP 94/10]
127 length data_con_arg_tys == 2 &&
128 not (isPrimType data_con_arg_ty1) &&
129 isPrimType data_con_arg_ty2
130 -- and, of course, it is an instance of _CCallable
131 -- ( tycon == byteArrayTyCon ||
132 -- tycon == mutableByteArrayTyCon )
133 = newSysLocalsDs data_con_arg_tys `thenDs` \ vars@[ixs_var, arr_cts_var] ->
134 returnDs (CoVar arr_cts_var,
135 \ body -> CoCase arg (CoAlgAlts [(the_data_con,vars,body)]
139 -- Data types with a single constructor, which has a single, primitive-typed arg
140 | maybeToBool maybe_boxed_prim_arg_ty
141 = newSysLocalDs the_prim_arg_ty `thenDs` \ prim_arg ->
142 returnDs (CoVar prim_arg,
143 \ body -> CoCase arg (CoAlgAlts [(box_data_con,[prim_arg],body)]
146 -- ... continued below ....
149 As an experiment, I'm going to unpack any "acceptably small"
150 enumeration. This code will never get used in the main version
151 because enumerations would have triggered type errors but I've
152 disabled type-checking in my version. ADR
154 To Will: It might be worth leaving this in (but commented out) until
155 we decide what's happening with enumerations. ADR
160 -- Data types with a nullary constructors (enumeration)
161 | isEnumerationType arg_ty && -- enumeration
162 (length data_cons) <= 5 -- "acceptably short"
163 = newSysLocalDs the_prim_arg_ty `thenDs` \ prim_arg ->
166 alts = [ (con, [], mkMachInt i) | (con,i) <- data_cons `zip` [0..] ]
167 arg_tag = CoCase arg (CoAlgAlts alts) CoNoDefault
170 returnDs (CoVar prim_arg,
171 \ body -> CoCase arg_tag (CoPrimAlts [(prim_arg, body)] CoNoDefault)
177 -- ... continued from above ....
179 = pprPanic "unboxArg: " (ppr PprDebug arg_ty)
181 arg_ty = typeOfCoreExpr arg
183 maybe_boxed_prim_arg_ty = maybeBoxedPrimType arg_ty
184 (Just (box_data_con, the_prim_arg_ty)) = maybe_boxed_prim_arg_ty
186 maybe_data_type = getUniDataTyCon_maybe arg_ty
187 is_data_type = maybeToBool maybe_data_type
188 (Just (tycon, tycon_arg_tys, data_cons)) = maybe_data_type
189 (the_data_con : other_data_cons) = data_cons
191 (_, data_con_arg_tys, _) = getInstantiatedDataConSig the_data_con tycon_arg_tys
192 (data_con_arg_ty1 : data_con_arg_ty2 : _) = data_con_arg_tys
194 can't_see_datacons_error thing ty
195 = error (ppShow 100 (ppBesides [ppStr "ERROR: Can't see the data constructor(s) for _ccall_/_casm_ ", ppStr thing, ppStr "; type: ", ppr PprForUser ty]))
200 tuple_con_2 = mkTupleCon 2 -- out here to avoid CAF (sigh)
201 covar_tuple_con_0 = CoVar (mkTupleCon 0) -- ditto
203 boxResult :: UniType -- Type of desired result
204 -> DsM (UniType, -- Type of the result of the ccall itself
205 PlainCoreExpr -> PlainCoreExpr) -- Wrapper for the ccall
209 -- oops! can't see the data constructors
210 = can't_see_datacons_error "result" result_ty
212 -- Data types with a single constructor, which has a single, primitive-typed arg
213 | (maybeToBool maybe_data_type) && -- Data type
214 (null other_data_cons) && -- Just one constr
215 not (null data_con_arg_tys) && null other_args_tys && -- Just one arg
216 isPrimType the_prim_result_ty -- of primitive type
218 newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
219 newSysLocalDs the_prim_result_ty `thenDs` \ prim_result_id ->
221 mkCoConDs stateDataCon [realWorldTy] [CoVar prim_state_id] `thenDs` \ new_state ->
222 mkCoConDs the_data_con tycon_arg_tys [CoVar prim_result_id] `thenDs` \ the_result ->
224 mkCoConDs tuple_con_2
225 [result_ty, realWorldStateTy]
226 [the_result, new_state] `thenDs` \ the_pair ->
228 the_alt = (state_and_prim_datacon, [prim_state_id, prim_result_id], the_pair)
230 returnDs (state_and_prim_ty,
231 \prim_app -> CoCase prim_app (CoAlgAlts [the_alt] CoNoDefault)
234 -- Data types with a single nullary constructor
235 | (maybeToBool maybe_data_type) && -- Data type
236 (null other_data_cons) && -- Just one constr
237 (null data_con_arg_tys)
239 newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
241 mkCoConDs stateDataCon [realWorldTy] [CoVar prim_state_id] `thenDs` \ new_state ->
243 mkCoConDs tuple_con_2
244 [result_ty, realWorldStateTy]
245 [covar_tuple_con_0, new_state] `thenDs` \ the_pair ->
248 the_alt = (stateDataCon, [prim_state_id], the_pair)
250 returnDs (realWorldStateTy,
251 \prim_app -> CoCase prim_app (CoAlgAlts [the_alt] CoNoDefault)
257 -- Data types with several nullary constructors (Enumerated types)
258 | isEnumerationType result_ty && -- Enumeration
259 (length data_cons) <= 5 -- fairly short
261 newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
262 newSysLocalDs intPrimTy `thenDs` \ prim_result_id ->
264 mkCoConDs stateDataCon [realWorldTy] [CoVar prim_state_id] `thenDs` \ new_state ->
267 alts = [ (mkMachInt i, con) | (i, con) <- [0..] `zip` data_cons ]
268 the_result = CoCase prim_result_id (CoPrimAlts alts) CoNoDefault
271 mkCoConDs (mkTupleCon 2)
272 [result_ty, realWorldStateTy]
273 [the_result, new_state] `thenDs` \ the_pair ->
275 the_alt = (state_and_prim_datacon, [prim_state_id, prim_result_id], the_pair)
277 returnDs (state_and_prim_ty,
278 \prim_app -> CoCase prim_app (CoAlgAlts [the_alt] CoNoDefault)
283 = pprPanic "boxResult: " (ppr PprDebug result_ty)
286 maybe_data_type = getUniDataTyCon_maybe result_ty
287 Just (tycon, tycon_arg_tys, data_cons) = maybe_data_type
288 (the_data_con : other_data_cons) = data_cons
290 (_, data_con_arg_tys, _) = getInstantiatedDataConSig the_data_con tycon_arg_tys
291 (the_prim_result_ty : other_args_tys) = data_con_arg_tys
293 (state_and_prim_datacon, state_and_prim_ty) = getStatePairingConInfo the_prim_result_ty