2 % (c) The AQUA Project, Glasgow University, 1994-1996
4 \section[DsCCall]{Desugaring \tr{_ccall_}s and \tr{_casm_}s}
14 , can'tSeeDataConsPanic
17 #include "HsVersions.h"
24 import TcHsSyn ( maybeBoxedPrimType )
25 import CoreUtils ( coreExprType )
26 import Id ( Id, dataConArgTys, idType )
27 import Maybes ( maybeToBool )
28 import PrelVals ( packStringForCId )
29 import PrimOp ( PrimOp(..) )
31 import Type ( isUnpointedType, splitAlgTyConApp_maybe,
32 splitTyConApp_maybe, splitFunTys, splitForAllTys,
35 import TyCon ( tyConDataCons )
36 import TysPrim ( byteArrayPrimTy, realWorldStatePrimTy,
37 byteArrayPrimTyCon, mutableByteArrayPrimTyCon )
38 import TysWiredIn ( getStatePairingConInfo,
39 unitDataCon, stringTy,
40 realWorldStateTy, stateDataCon
45 Desugaring of @ccall@s consists of adding some state manipulation,
46 unboxing any boxed primitive arguments and boxing the result if
49 The state stuff just consists of adding in
50 @PrimIO (\ s -> case s of { S# s# -> ... })@ in an appropriate place.
52 The unboxing is straightforward, as all information needed to unbox is
53 available from the type. For each boxed-primitive argument, we
56 _ccall_ foo [ r, t1, ... tm ] e1 ... em
60 case e1 of { T1# x1# ->
62 case em of { Tm# xm# -> xm#
63 ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
67 The reboxing of a @_ccall_@ result is a bit tricker: the types don't
68 contain information about the state-pairing functions so we have to
69 keep a list of \tr{(type, s-p-function)} pairs. We transform as
72 ccall# foo [ r, t1#, ... tm# ] e1# ... em#
76 \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
77 (StateAnd<r># result# state#) -> (R# result#, realWorld#)
81 dsCCall :: FAST_STRING -- C routine to invoke
82 -> [CoreExpr] -- Arguments (desugared)
83 -> Bool -- True <=> might cause Haskell GC
84 -> Bool -- True <=> really a "_casm_"
85 -> Type -- Type of the result (a boxed-prim IO type)
88 dsCCall label args may_gc is_asm io_result_ty
89 = newSysLocalDs realWorldStatePrimTy `thenDs` \ old_s ->
91 mapAndUnzipDs unboxArg args `thenDs` \ (unboxed_args, arg_wrappers) ->
93 final_args = Var old_s : unboxed_args
94 (ioOkDataCon, _, result_ty) = getIoOkDataCon io_result_ty
97 boxResult ioOkDataCon result_ty `thenDs` \ (final_result_ty, res_wrapper) ->
100 the_ccall_op = CCallOp (Left label) is_asm may_gc cCallConv
101 (map coreExprType final_args)
104 mkPrimDs the_ccall_op (map VarArg final_args) `thenDs` \ the_prim_app ->
106 the_body = foldr ($) (res_wrapper the_prim_app) arg_wrappers
108 returnDs (Lam (ValBinder old_s) the_body)
112 unboxArg :: CoreExpr -- The supplied argument
113 -> DsM (CoreExpr, -- To pass as the actual argument
114 CoreExpr -> CoreExpr -- Wrapper to unbox the arg
119 -- ADR Question: can this ever be used? None of the PrimTypes are
120 -- instances of the CCallable class.
123 -- Oh yes they are, I've just added them :-) Having _ccall_ and _casm_
124 -- that accept unboxed arguments is a Good Thing if you have a stub generator
125 -- which generates the boiler-plate box-unbox code for you, i.e., it may help
126 -- us nuke this very module :-)
128 | isUnpointedType arg_ty
129 = returnDs (arg, \body -> body)
133 = newSysLocalDs byteArrayPrimTy `thenDs` \ prim_arg ->
134 mkAppDs (Var packStringForCId) [VarArg arg] `thenDs` \ pack_appn ->
135 returnDs (Var prim_arg,
136 \body -> Case pack_appn (PrimAlts []
137 (BindDefault prim_arg body))
141 -- oops: we can't see the data constructors!!!
142 = can'tSeeDataConsPanic "argument" arg_ty
144 -- Byte-arrays, both mutable and otherwise; hack warning
146 length data_con_arg_tys == 2 &&
147 maybeToBool maybe_arg2_tycon &&
148 (arg2_tycon == byteArrayPrimTyCon ||
149 arg2_tycon == mutableByteArrayPrimTyCon)
150 -- and, of course, it is an instance of CCallable
151 = newSysLocalsDs data_con_arg_tys `thenDs` \ vars@[ixs_var, arr_cts_var] ->
152 returnDs (Var arr_cts_var,
153 \ body -> Case arg (AlgAlts [(the_data_con,vars,body)]
157 -- Data types with a single constructor, which has a single, primitive-typed arg
158 | maybeToBool maybe_boxed_prim_arg_ty
159 = newSysLocalDs the_prim_arg_ty `thenDs` \ prim_arg ->
160 returnDs (Var prim_arg,
161 \ body -> Case arg (AlgAlts [(box_data_con,[prim_arg],body)]
166 = getSrcLocDs `thenDs` \ l ->
167 pprPanic "unboxArg: " (ppr l <+> ppr arg_ty)
169 arg_ty = coreExprType arg
171 maybe_boxed_prim_arg_ty = maybeBoxedPrimType arg_ty
172 (Just (box_data_con, the_prim_arg_ty)) = maybe_boxed_prim_arg_ty
174 maybe_data_type = splitAlgTyConApp_maybe arg_ty
175 is_data_type = maybeToBool maybe_data_type
176 (Just (tycon, tycon_arg_tys, data_cons)) = maybe_data_type
177 (the_data_con : other_data_cons) = data_cons
179 data_con_arg_tys = dataConArgTys the_data_con tycon_arg_tys
180 (data_con_arg_ty1 : data_con_arg_ty2 : _) = data_con_arg_tys
182 maybe_arg2_tycon = splitTyConApp_maybe data_con_arg_ty2
183 Just (arg2_tycon,_) = maybe_arg2_tycon
185 can'tSeeDataConsPanic thing ty
186 = pprPanic "ERROR: Can't see the data constructor(s) for _ccall_/_casm_/foreign declaration"
187 (hcat [text thing, text "; type: ", ppr ty, text "(try compiling with -fno-prune-tydecls ..)\n"])
192 boxResult :: Id -- IOok constructor
193 -> Type -- Type of desired result
194 -> DsM (Type, -- Type of the result of the ccall itself
195 CoreExpr -> CoreExpr) -- Wrapper for the ccall
197 boxResult ioOkDataCon result_ty
199 -- oops! can't see the data constructors
200 = can'tSeeDataConsPanic "result" result_ty
202 -- Data types with a single constructor, which has a single, primitive-typed arg
203 | (maybeToBool maybe_data_type) && -- Data type
204 (null other_data_cons) && -- Just one constr
205 not (null data_con_arg_tys) && null other_args_tys && -- Just one arg
206 isUnpointedType the_prim_result_ty -- of primitive type
208 newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
209 wrapUnboxedValue result_ty `thenDs` \ (state_and_prim_datacon,
210 state_and_prim_ty, prim_result_id, the_result) ->
212 [TyArg result_ty, VarArg (Var prim_state_id), VarArg the_result]
213 `thenDs` \ the_pair ->
215 the_alt = (state_and_prim_datacon, [prim_state_id, prim_result_id], the_pair)
217 returnDs (state_and_prim_ty,
218 \prim_app -> Case prim_app (AlgAlts [the_alt] NoDefault)
221 -- Data types with a single nullary constructor
222 | (maybeToBool maybe_data_type) && -- Data type
223 (null other_data_cons) && -- Just one constr
224 (null data_con_arg_tys)
226 newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
229 [TyArg result_ty, VarArg (Var prim_state_id), VarArg (Var unitDataCon)]
230 `thenDs` \ the_pair ->
233 the_alt = (stateDataCon, [prim_state_id], the_pair)
235 returnDs (realWorldStateTy,
236 \prim_app -> Case prim_app (AlgAlts [the_alt] NoDefault)
240 = pprPanic "boxResult: " (ppr result_ty)
242 maybe_data_type = splitAlgTyConApp_maybe result_ty
243 Just (tycon, tycon_arg_tys, data_cons) = maybe_data_type
244 (the_data_con : other_data_cons) = data_cons
246 data_con_arg_tys = dataConArgTys the_data_con tycon_arg_tys
247 (the_prim_result_ty : other_args_tys) = data_con_arg_tys
249 -- (state_and_prim_datacon, state_and_prim_ty) = getStatePairingConInfo the_prim_result_ty
251 -- wrap up an unboxed value.
252 wrapUnboxedValue :: Type -> DsM (Id, Type, Id, CoreExpr)
255 -- oops! can't see the data constructors
256 = can'tSeeDataConsPanic "result" ty
257 -- Data types with a single constructor, which has a single, primitive-typed arg
258 | (maybeToBool maybe_data_type) && -- Data type
259 (null other_data_cons) && -- Just one constr
260 not (null data_con_arg_tys) && null other_args_tys && -- Just one arg
261 isUnpointedType the_prim_result_ty -- of primitive type
263 newSysLocalDs the_prim_result_ty `thenDs` \ prim_result_id ->
264 mkConDs the_data_con (map TyArg tycon_arg_tys ++
265 [VarArg (Var prim_result_id)]) `thenDs` \ the_result ->
266 returnDs (state_and_prim_datacon, state_and_prim_ty, prim_result_id, the_result)
268 -- Data types with a single nullary constructor
269 | (maybeToBool maybe_data_type) && -- Data type
270 (null other_data_cons) && -- Just one constr
271 (null data_con_arg_tys)
273 let unit = unitDataCon in
274 returnDs (stateDataCon, realWorldStateTy, unit, Var unit)
276 = pprPanic "boxResult: " (ppr ty)
278 maybe_data_type = splitAlgTyConApp_maybe ty
279 Just (tycon, tycon_arg_tys, data_cons) = maybe_data_type
280 (the_data_con : other_data_cons) = data_cons
282 data_con_arg_tys = dataConArgTys the_data_con tycon_arg_tys
283 (the_prim_result_ty : other_args_tys) = data_con_arg_tys
284 (state_and_prim_datacon, state_and_prim_ty) = getStatePairingConInfo the_prim_result_ty
288 This grimy bit of code is for digging out the IOok constructor from an
289 application of the the IO type. The constructor is needed for
290 wrapping the result of a _ccall_. The alternative is to wire-in IO,
291 which brings a whole heap of junk with it.
293 If the representation of IO changes, this will probably have to be
294 brought in line with the new definition.
296 newtype IO a = IO (State# RealWorld -> IOResult a)
298 the constructor IO has type (State# RealWorld -> IOResult a) -> IO a
301 getIoOkDataCon :: Type -- IO t
302 -> (Id, Id, Type) -- Returns (IOok, IO, t)
306 Just (ioTyCon, [t]) = splitTyConApp_maybe io_ty
307 [ioDataCon] = tyConDataCons ioTyCon
308 ioDataConTy = idType ioDataCon
309 (_, ioDataConTy') = splitForAllTys ioDataConTy
310 ([arg_ty], _) = splitFunTys ioDataConTy'
311 (_, io_result_ty) = splitFunTys arg_ty
312 Just (io_result_tycon, _) = splitTyConApp_maybe io_result_ty
313 [ioOkDataCon,ioFailDataCon] = tyConDataCons io_result_tycon
315 (ioOkDataCon, ioDataCon, t)
318 Another way to do it, more sensitive:
321 ForAll _ (FunTy (FunTy _ (AppTy (TyConTy ioResultTyCon _) _)) _) ->
322 let [ioOkDataCon,ioFailDataCon] = tyConDataCons ioResultTyCon
324 (ioOkDataCon, result_ty)
325 _ -> pprPanic "getIoOkDataCon: " (ppr PprDebug ioDataConTy)