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