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