[project @ 2000-04-04 13:40:27 by panne]
[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         , mkCCall
10         , unboxArg
11         , boxResult
12         ,  wrapUnboxedValue
13         , can'tSeeDataConsPanic
14         
15         ) where
16
17 #include "HsVersions.h"
18
19 import CoreSyn
20
21 import DsMonad
22 import DsUtils
23
24 import TcHsSyn          ( maybeBoxedPrimType )
25 import CoreUtils        ( exprType )
26 import Id               ( Id, mkWildId )
27 import MkId             ( mkCCallOpId )
28 import Maybes           ( maybeToBool )
29 import PrelInfo         ( packStringForCId )
30 import PrimOp           ( PrimOp(..), CCall(..), CCallTarget(..) )
31 import DataCon          ( DataCon, splitProductType_maybe )
32 import CallConv
33 import Type             ( isUnLiftedType, splitAlgTyConApp_maybe, mkFunTys,
34                           splitTyConApp_maybe, tyVarsOfType, mkForAllTys, Type
35                         )
36 import TysPrim          ( byteArrayPrimTy, realWorldStatePrimTy,
37                           byteArrayPrimTyCon, mutableByteArrayPrimTyCon,
38                           intPrimTy
39                         )
40 import TysWiredIn       ( unitDataConId, stringTy, boolTy,
41                           falseDataCon, falseDataConId,
42                           trueDataCon, trueDataConId,
43                           unboxedPairDataCon,
44                           mkUnboxedTupleTy, unboxedTupleCon
45                         )
46 import Literal          ( mkMachInt )
47 import CStrings         ( CLabelString )
48 import Unique           ( Unique )
49 import VarSet           ( varSetElems )
50 import Outputable
51 \end{code}
52
53 Desugaring of @ccall@s consists of adding some state manipulation,
54 unboxing any boxed primitive arguments and boxing the result if
55 desired.
56
57 The state stuff just consists of adding in
58 @PrimIO (\ s -> case s of { S# s# -> ... })@ in an appropriate place.
59
60 The unboxing is straightforward, as all information needed to unbox is
61 available from the type.  For each boxed-primitive argument, we
62 transform:
63 \begin{verbatim}
64    _ccall_ foo [ r, t1, ... tm ] e1 ... em
65    |
66    |
67    V
68    case e1 of { T1# x1# ->
69    ...
70    case em of { Tm# xm# -> xm#
71    ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
72    } ... }
73 \end{verbatim}
74
75 The reboxing of a @_ccall_@ result is a bit tricker: the types don't
76 contain information about the state-pairing functions so we have to
77 keep a list of \tr{(type, s-p-function)} pairs.  We transform as
78 follows:
79 \begin{verbatim}
80    ccall# foo [ r, t1#, ... tm# ] e1# ... em#
81    |
82    |
83    V
84    \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
85           (StateAnd<r># result# state#) -> (R# result#, realWorld#)
86 \end{verbatim}
87
88 \begin{code}
89 dsCCall :: CLabelString -- C routine to invoke
90         -> [CoreExpr]   -- Arguments (desugared)
91         -> Bool         -- True <=> might cause Haskell GC
92         -> Bool         -- True <=> really a "_casm_"
93         -> Type         -- Type of the result (a boxed-prim IO type)
94         -> DsM CoreExpr
95
96 dsCCall lbl args may_gc is_asm result_ty
97   = newSysLocalDs realWorldStatePrimTy  `thenDs` \ old_s ->
98
99     mapAndUnzipDs unboxArg args `thenDs` \ (unboxed_args, arg_wrappers) ->
100     boxResult result_ty         `thenDs` \ (final_result_ty, res_wrapper) ->
101     getUniqueDs                 `thenDs` \ uniq ->
102     let
103         val_args     = Var old_s : unboxed_args
104         the_ccall    = CCall (StaticTarget lbl) is_asm may_gc cCallConv
105         the_prim_app = mkCCall uniq the_ccall val_args final_result_ty
106         the_body     = foldr ($) (res_wrapper the_prim_app) arg_wrappers
107     in
108     returnDs (Lam old_s the_body)
109
110 mkCCall :: Unique -> CCall 
111         -> [CoreExpr]   -- Args
112         -> Type         -- Result type
113         -> CoreExpr
114 -- Construct the ccall.  The only tricky bit is that the ccall Id should have
115 -- no free vars, so if any of the arg tys do we must give it a polymorphic type.
116 --      [I forget *why* it should have no free vars!]
117 -- For example:
118 --      mkCCall ... [s::StablePtr (a->b), x::Addr, c::Char]
119 --
120 -- Here we build a ccall thus
121 --      (ccallid::(forall a b.  StablePtr (a -> b) -> Addr -> Char -> IO Addr))
122 --                      a b s x c
123 mkCCall uniq the_ccall val_args res_ty
124   = mkApps (mkVarApps (Var the_ccall_id) tyvars) val_args
125   where
126     arg_tys = map exprType val_args
127     body_ty = (mkFunTys arg_tys res_ty)
128     tyvars  = varSetElems (tyVarsOfType body_ty)
129     ty      = mkForAllTys tyvars body_ty
130     the_ccall_id = mkCCallOpId uniq the_ccall ty
131 \end{code}
132
133 \begin{code}
134 unboxArg :: CoreExpr                    -- The supplied argument
135          -> DsM (CoreExpr,              -- To pass as the actual argument
136                  CoreExpr -> CoreExpr   -- Wrapper to unbox the arg
137                 )
138 unboxArg arg
139
140   -- Primitive types
141   -- ADR Question: can this ever be used?  None of the PrimTypes are
142   -- instances of the CCallable class.
143   --
144   -- SOF response:
145   --    Oh yes they are, I've just added them :-) Having _ccall_ and _casm_
146   --  that accept unboxed arguments is a Good Thing if you have a stub generator
147   --  which generates the boiler-plate box-unbox code for you, i.e., it may help
148   --  us nuke this very module :-)
149   --
150   | isUnLiftedType arg_ty
151   = returnDs (arg, \body -> body)
152
153   -- Strings
154   | arg_ty == stringTy
155   -- ToDo (ADR): - allow synonyms of Strings too?
156   = newSysLocalDs byteArrayPrimTy               `thenDs` \ prim_arg ->
157     returnDs (Var prim_arg,
158               \body -> Case (App (Var packStringForCId) arg) 
159                             prim_arg [(DEFAULT,[],body)])
160
161   -- Byte-arrays, both mutable and otherwise; hack warning
162   | is_product_type &&
163     length data_con_arg_tys == 3 &&
164     maybeToBool maybe_arg3_tycon &&
165     (arg3_tycon ==  byteArrayPrimTyCon ||
166      arg3_tycon ==  mutableByteArrayPrimTyCon)
167     -- and, of course, it is an instance of CCallable
168   = newSysLocalDs arg_ty                `thenDs` \ case_bndr ->
169     newSysLocalsDs data_con_arg_tys     `thenDs` \ vars@[l_var, r_var, arr_cts_var] ->
170     returnDs (Var arr_cts_var,
171               \ body -> Case arg case_bndr [(DataAlt data_con,vars,body)]
172     )
173
174   -- Data types with a single constructor, which has a single, primitive-typed arg
175   | maybeToBool maybe_boxed_prim_arg_ty
176   = newSysLocalDs arg_ty                `thenDs` \ case_bndr ->
177     newSysLocalDs the_prim_arg_ty       `thenDs` \ prim_arg ->
178     returnDs (Var prim_arg,
179               \ body -> Case arg case_bndr [(DataAlt box_data_con,[prim_arg],body)]
180     )
181
182   -- Booleans; Hacking alert: the 0/1 literals should match the HsFalse/HsTrue constants
183   | arg_ty == boolTy
184   = newSysLocalDs intPrimTy             `thenDs` \ prim_arg ->
185     returnDs (Var prim_arg,
186               \ body -> Case (Case arg (mkWildId arg_ty) [
187                                 (DataAlt falseDataCon,[],mkIntLit 0),
188                                 (DataAlt trueDataCon, [],mkIntLit 1)])
189                              prim_arg [(DEFAULT,[],body)]
190     )
191
192   | otherwise
193   = getSrcLocDs `thenDs` \ l ->
194     pprPanic "unboxArg: " (ppr l <+> ppr arg_ty)
195   where
196     arg_ty = exprType arg
197
198     maybe_boxed_prim_arg_ty = maybeBoxedPrimType arg_ty
199     (Just (box_data_con, the_prim_arg_ty)) = maybe_boxed_prim_arg_ty
200
201     maybe_product_type                            = splitProductType_maybe arg_ty
202     is_product_type                               = maybeToBool maybe_product_type
203     Just (tycon, _, data_con, data_con_arg_tys)   = maybe_product_type
204     (data_con_arg_ty1 : data_con_arg_ty2 : data_con_arg_ty3 :_)
205           = data_con_arg_tys
206
207     maybe_arg3_tycon = splitTyConApp_maybe data_con_arg_ty3
208     Just (arg3_tycon,_) = maybe_arg3_tycon
209
210 can'tSeeDataConsPanic thing ty
211   = pprPanic
212      "ERROR: Can't see the data constructor(s) for _ccall_/_casm_/foreign declaration"
213      (hcat [ text thing, text "; type: ", ppr ty
214            , text "(try compiling with -fno-prune-tydecls ..)\n"])
215 \end{code}
216
217
218 \begin{code}
219 boxResult :: Type                       -- Type of desired result
220           -> DsM (Type,                 -- Type of the result of the ccall itself
221                   CoreExpr -> CoreExpr) -- Wrapper for the ccall
222                                         -- to box the result
223 boxResult result_ty
224   -- Data types with a single nullary constructor
225   | (maybeToBool maybe_product_type) &&                         -- Data type
226     (null data_con_arg_tys)
227   =
228     newSysLocalDs realWorldStatePrimTy          `thenDs` \ prim_state_id ->
229 {-
230     wrapUnboxedValue result_ty                  `thenDs` \ (state_and_prim_datacon,
231                                                             state_and_prim_ty, prim_result_id, the_result) ->
232     mkConDs ioOkDataCon
233             [TyArg result_ty, VarArg (Var prim_state_id), VarArg the_result]
234                                                         `thenDs` \ the_pair ->
235 -}
236     let
237         the_pair = mkConApp unboxedPairDataCon
238                             [Type realWorldStatePrimTy, Type result_ty, 
239                              Var prim_state_id, 
240                              Var unitDataConId]
241         the_alt  = (DataAlt (unboxedTupleCon 1), [prim_state_id], the_pair)
242         scrut_ty = mkUnboxedTupleTy 1 [realWorldStatePrimTy]
243     in
244     returnDs (scrut_ty, \prim_app -> Case prim_app (mkWildId scrut_ty) [the_alt]
245     )
246
247   -- Data types with a single constructor, which has a single, primitive-typed arg
248   | (maybeToBool maybe_product_type) &&                         -- Data type
249     not (null data_con_arg_tys) && null other_args_tys  &&      -- Just one arg
250     isUnLiftedType the_prim_result_ty                           -- of primitive type
251   =
252     newSysLocalDs realWorldStatePrimTy          `thenDs` \ prim_state_id ->
253     newSysLocalDs the_prim_result_ty            `thenDs` \ prim_result_id ->
254     newSysLocalDs ccall_res_type                `thenDs` \ case_bndr ->
255
256     let
257         the_result = mkConApp data_con (map Type tycon_arg_tys ++ [Var prim_result_id])
258         the_pair   = mkConApp unboxedPairDataCon
259                                 [Type realWorldStatePrimTy, Type result_ty, 
260                                  Var prim_state_id, the_result]
261         the_alt    = (DataAlt unboxedPairDataCon, [prim_state_id, prim_result_id], the_pair)
262     in
263     returnDs (ccall_res_type, \prim_app -> Case prim_app case_bndr [the_alt]
264     )
265
266   -- Booleans
267   | result_ty == boolTy
268   = returnDs (mkUnboxedTupleTy 2 [realWorldStatePrimTy, intPrimTy],
269               \ prim_app -> Case prim_app (mkWildId intPrimTy) [
270                                (LitAlt (mkMachInt 0),[],Var falseDataConId),
271                                (DEFAULT             ,[],Var trueDataConId )])
272
273   | otherwise
274   = pprPanic "boxResult: " (ppr result_ty)
275   where
276     maybe_product_type                                      = splitProductType_maybe result_ty
277     Just (tycon, tycon_arg_tys, data_con, data_con_arg_tys) = maybe_product_type
278     (the_prim_result_ty : other_args_tys)                   = data_con_arg_tys
279
280     ccall_res_type = mkUnboxedTupleTy 2 [realWorldStatePrimTy, the_prim_result_ty]
281
282 -- wrap up an unboxed value.
283 wrapUnboxedValue :: Type -> DsM (Type, Id, CoreExpr)
284 wrapUnboxedValue ty
285   | (maybeToBool maybe_product_type) &&                         -- Data type
286     not (null data_con_arg_tys) && null other_args_tys  &&      -- Just one arg
287     isUnLiftedType the_prim_result_ty                           -- of primitive type
288   =
289     newSysLocalDs the_prim_result_ty                     `thenDs` \ prim_result_id ->
290     let
291         the_result = mkConApp data_con (map Type tycon_arg_tys ++ [Var prim_result_id])
292     in
293     returnDs (ccall_res_type, prim_result_id, the_result)
294
295   -- Data types with a single nullary constructor
296   | (maybeToBool maybe_product_type) &&                         -- Data type
297     (null data_con_arg_tys)
298   =
299     let 
300         scrut_ty = mkUnboxedTupleTy 1 [realWorldStatePrimTy]
301     in
302     returnDs (scrut_ty, unitDataConId, Var unitDataConId)
303
304   | otherwise
305   = pprPanic "boxResult: " (ppr ty)
306  where
307    maybe_product_type                                      = splitProductType_maybe ty
308    Just (tycon, tycon_arg_tys, data_con, data_con_arg_tys) = maybe_product_type
309    (the_prim_result_ty : other_args_tys)                   = data_con_arg_tys
310    ccall_res_type = mkUnboxedTupleTy 2 [realWorldStatePrimTy, the_prim_result_ty]
311 \end{code}