6d488c44e7c06fc07b32ac2902bef9a5f10815ff
[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         , resultWrapper
13         ) where
14
15 #include "HsVersions.h"
16
17 import CoreSyn
18
19 import DsMonad
20 import DsUtils
21
22 import CoreUtils        ( exprType, mkCoerce )
23 import Id               ( Id, mkWildId )
24 import MkId             ( mkCCallOpId, realWorldPrimId )
25 import Maybes           ( maybeToBool )
26 import PrimOp           ( PrimOp(..), CCall(..), CCallTarget(..) )
27 import DataCon          ( DataCon, splitProductType_maybe, dataConSourceArity, dataConWrapId )
28 import CallConv
29 import Type             ( isUnLiftedType, splitAlgTyConApp_maybe, mkFunTys,
30                           splitTyConApp_maybe, tyVarsOfType, mkForAllTys, 
31                           isNewType, repType, isUnLiftedType, mkFunTy, mkTyConApp,
32                           Type
33                         )
34 import PprType          ( {- instance Outputable Type -} )
35 import TysPrim          ( byteArrayPrimTy, realWorldStatePrimTy,
36                           byteArrayPrimTyCon, mutableByteArrayPrimTyCon, intPrimTy
37                         )
38 import TysWiredIn       ( unitDataConId, stringTy,
39                           unboxedSingletonDataCon, unboxedPairDataCon,
40                           unboxedSingletonTyCon, unboxedPairTyCon,
41                           mkTupleTy, tupleCon,
42                           boolTy, trueDataCon, falseDataCon, trueDataConId, falseDataConId,
43                           unitTy
44                         )
45 import Literal          ( mkMachInt )
46 import CStrings         ( CLabelString )
47 import Unique           ( Unique, Uniquable(..), hasKey, ioTyConKey )
48 import VarSet           ( varSetElems )
49 import Outputable
50 \end{code}
51
52 Desugaring of @ccall@s consists of adding some state manipulation,
53 unboxing any boxed primitive arguments and boxing the result if
54 desired.
55
56 The state stuff just consists of adding in
57 @PrimIO (\ s -> case s of { S# s# -> ... })@ in an appropriate place.
58
59 The unboxing is straightforward, as all information needed to unbox is
60 available from the type.  For each boxed-primitive argument, we
61 transform:
62 \begin{verbatim}
63    _ccall_ foo [ r, t1, ... tm ] e1 ... em
64    |
65    |
66    V
67    case e1 of { T1# x1# ->
68    ...
69    case em of { Tm# xm# -> xm#
70    ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
71    } ... }
72 \end{verbatim}
73
74 The reboxing of a @_ccall_@ result is a bit tricker: the types don't
75 contain information about the state-pairing functions so we have to
76 keep a list of \tr{(type, s-p-function)} pairs.  We transform as
77 follows:
78 \begin{verbatim}
79    ccall# foo [ r, t1#, ... tm# ] e1# ... em#
80    |
81    |
82    V
83    \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
84           (StateAnd<r># result# state#) -> (R# result#, realWorld#)
85 \end{verbatim}
86
87 \begin{code}
88 dsCCall :: CLabelString -- C routine to invoke
89         -> [CoreExpr]   -- Arguments (desugared)
90         -> Bool         -- True <=> might cause Haskell GC
91         -> Bool         -- True <=> really a "_casm_"
92         -> Type         -- Type of the result: IO t
93         -> DsM CoreExpr
94
95 dsCCall lbl args may_gc is_asm result_ty
96   = mapAndUnzipDs unboxArg args `thenDs` \ (unboxed_args, arg_wrappers) ->
97     boxResult result_ty         `thenDs` \ (ccall_result_ty, res_wrapper) ->
98     getUniqueDs                 `thenDs` \ uniq ->
99     let
100         the_ccall    = CCall (StaticTarget lbl) is_asm may_gc cCallConv
101         the_prim_app = mkCCall uniq the_ccall unboxed_args ccall_result_ty
102     in
103     returnDs (foldr ($) (res_wrapper the_prim_app) arg_wrappers)
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 -- Example: if the arg is e::Int, unboxArg will return
134 --      (x#::Int#, \W. case x of I# x# -> W)
135 -- where W is a CoreExpr that probably mentions x#
136
137 unboxArg arg
138   -- Unlifted types: nothing to unbox
139   | isUnLiftedType arg_ty
140   = returnDs (arg, \body -> body)
141
142   -- Newtypes
143   | isNewType arg_ty
144   = unboxArg (mkCoerce (repType arg_ty) arg_ty arg)
145       
146   -- Booleans
147   | arg_ty == boolTy
148   = newSysLocalDs intPrimTy             `thenDs` \ prim_arg ->
149     returnDs (Var prim_arg,
150               \ body -> Case (Case arg (mkWildId arg_ty)
151                                        [(DataAlt falseDataCon,[],mkIntLit 0),
152                                         (DataAlt trueDataCon, [],mkIntLit 1)])
153                              prim_arg 
154                              [(DEFAULT,[],body)])
155
156   -- Data types with a single constructor, which has a single, primitive-typed arg
157   -- This deals with Int, Float etc
158   | is_product_type && data_con_arity == 1 
159   = ASSERT(isUnLiftedType data_con_arg_ty1 )    -- Typechecker ensures this
160     newSysLocalDs arg_ty                `thenDs` \ case_bndr ->
161     newSysLocalDs data_con_arg_ty1      `thenDs` \ prim_arg ->
162     returnDs (Var prim_arg,
163               \ body -> Case arg case_bndr [(DataAlt data_con,[prim_arg],body)]
164     )
165
166   -- Byte-arrays, both mutable and otherwise; hack warning
167   | is_product_type &&
168     data_con_arity == 3 &&
169     maybeToBool maybe_arg3_tycon &&
170     (arg3_tycon ==  byteArrayPrimTyCon ||
171      arg3_tycon ==  mutableByteArrayPrimTyCon)
172     -- and, of course, it is an instance of CCallable
173   = newSysLocalDs arg_ty                `thenDs` \ case_bndr ->
174     newSysLocalsDs data_con_arg_tys     `thenDs` \ vars@[l_var, r_var, arr_cts_var] ->
175     returnDs (Var arr_cts_var,
176               \ body -> Case arg case_bndr [(DataAlt data_con,vars,body)]
177     )
178
179   | otherwise
180   = getSrcLocDs `thenDs` \ l ->
181     pprPanic "unboxArg: " (ppr l <+> ppr arg_ty)
182   where
183     arg_ty     = exprType arg
184     arg_rep_ty = repType 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_arity                                = dataConSourceArity data_con
190     (data_con_arg_ty1 : _)                        = data_con_arg_tys
191
192     (_ : _ : data_con_arg_ty3 : _) = data_con_arg_tys
193     maybe_arg3_tycon               = splitTyConApp_maybe data_con_arg_ty3
194     Just (arg3_tycon,_)            = maybe_arg3_tycon
195 \end{code}
196
197
198 \begin{code}
199 boxResult :: Type -> DsM (Type, CoreExpr -> CoreExpr)
200
201 -- Takes the result of the user-level ccall: 
202 --      either (IO t), 
203 --      or maybe just t for an side-effect-free call
204 -- Returns a wrapper for the primitive ccall itself, along with the
205 -- type of the result of the primitive ccall.  This result type
206 -- will be of the form  
207 --      State# RealWorld -> (# State# RealWorld, t' #)
208 -- where t' is the unwrapped form of t.  If t is simply (), then
209 -- the result type will be 
210 --      State# RealWorld -> (# State# RealWorld #)
211
212 boxResult result_ty
213   = case splitAlgTyConApp_maybe result_ty of
214
215         -- The result is IO t, so wrap the result in an IO constructor
216         Just (io_tycon, [io_res_ty], [io_data_con]) | io_tycon `hasKey` ioTyConKey
217                 -> mk_alt return_result 
218                           (resultWrapper io_res_ty)     `thenDs` \ (ccall_res_ty, the_alt) ->
219                    newSysLocalDs realWorldStatePrimTy    `thenDs` \ state_id ->
220                    let
221                         wrap = \ the_call -> mkApps (Var (dataConWrapId io_data_con))
222                                                     [Type io_res_ty, Lam state_id $
223                                                                      Case (App the_call (Var state_id))
224                                                                           (mkWildId ccall_res_ty)
225                                                                           [the_alt]]
226                    in
227                    returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
228                 where
229                    return_result state ans = mkConApp unboxedPairDataCon 
230                                                       [Type realWorldStatePrimTy, Type io_res_ty, 
231                                                        state, ans]
232
233         -- It isn't, so do unsafePerformIO
234         -- It's not conveniently available, so we inline it
235         other -> mk_alt return_result
236                         (resultWrapper result_ty)       `thenDs` \ (ccall_res_ty, the_alt) ->
237                  let
238                     wrap = \ the_call -> Case (App the_call (Var realWorldPrimId)) 
239                                               (mkWildId ccall_res_ty)
240                                               [the_alt]
241                  in
242                  returnDs (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)
243               where
244                  return_result state ans = ans
245   where
246     mk_alt return_result (Nothing, wrap_result)
247         =       -- The ccall returns ()
248           newSysLocalDs realWorldStatePrimTy    `thenDs` \ state_id ->
249           let
250                 the_rhs      = return_result (Var state_id) (wrap_result (panic "boxResult"))
251                 ccall_res_ty = mkTyConApp unboxedSingletonTyCon [realWorldStatePrimTy]
252                 the_alt      = (DataAlt unboxedSingletonDataCon, [state_id], the_rhs)
253           in
254           returnDs (ccall_res_ty, the_alt)
255
256     mk_alt return_result (Just prim_res_ty, wrap_result)
257         =       -- The ccall returns a non-() value
258           newSysLocalDs realWorldStatePrimTy    `thenDs` \ state_id ->
259           newSysLocalDs prim_res_ty             `thenDs` \ result_id ->
260           let
261                 the_rhs      = return_result (Var state_id) (wrap_result (Var result_id))
262                 ccall_res_ty = mkTyConApp unboxedPairTyCon [realWorldStatePrimTy, prim_res_ty]
263                 the_alt      = (DataAlt unboxedPairDataCon, [state_id, result_id], the_rhs)
264           in
265           returnDs (ccall_res_ty, the_alt)
266
267
268 resultWrapper :: Type
269               -> (Maybe Type,           -- Type of the expected result, if any
270                   CoreExpr -> CoreExpr) -- Wrapper for the result 
271 resultWrapper result_ty
272   -- Base case 1: primitive types
273   | isUnLiftedType result_ty
274   = (Just result_ty, \e -> e)
275
276   -- Base case 1: the unit type ()
277   | result_ty == unitTy
278   = (Nothing, \e -> Var unitDataConId)
279
280   | result_ty == boolTy
281   = (Just intPrimTy, \e -> Case e (mkWildId intPrimTy)
282                                   [(LitAlt (mkMachInt 0),[],Var falseDataConId),
283                                    (DEFAULT             ,[],Var trueDataConId )])
284
285   -- Data types with a single constructor, which has a single arg
286   | is_product_type && data_con_arity == 1
287   = let
288         (maybe_ty, wrapper)    = resultWrapper unwrapped_res_ty
289         (unwrapped_res_ty : _) = data_con_arg_tys
290     in
291     (maybe_ty, \e -> mkApps (Var (dataConWrapId data_con)) 
292                             (map Type tycon_arg_tys ++ [wrapper e]))
293
294   -- newtypes
295   | isNewType result_ty
296   = let
297         rep_ty              = repType result_ty
298         (maybe_ty, wrapper) = resultWrapper rep_ty
299     in
300     (maybe_ty, \e -> mkCoerce result_ty rep_ty (wrapper e))
301
302   | otherwise
303   = pprPanic "resultWrapper" (ppr result_ty)
304   where
305     maybe_product_type                                      = splitProductType_maybe result_ty
306     is_product_type                                         = maybeToBool maybe_product_type
307     Just (tycon, tycon_arg_tys, data_con, data_con_arg_tys) = maybe_product_type
308     data_con_arity                                          = dataConSourceArity data_con
309 \end{code}