summaryrefslogtreecommitdiff
path: root/ghc/compiler/deSugar/DsCCall.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/compiler/deSugar/DsCCall.lhs')
-rw-r--r--ghc/compiler/deSugar/DsCCall.lhs295
1 files changed, 295 insertions, 0 deletions
diff --git a/ghc/compiler/deSugar/DsCCall.lhs b/ghc/compiler/deSugar/DsCCall.lhs
new file mode 100644
index 0000000000..87a834e07d
--- /dev/null
+++ b/ghc/compiler/deSugar/DsCCall.lhs
@@ -0,0 +1,295 @@
+%
+% (c) The AQUA Project, Glasgow University, 1994-1995
+%
+\section[DsCCall]{Desugaring \tr{_ccall_}s and \tr{_casm_}s}
+
+\begin{code}
+#include "HsVersions.h"
+
+module DsCCall ( dsCCall ) where
+
+IMPORT_Trace
+
+import AbsSyn -- the stuff being desugared
+import PlainCore -- the output of desugaring
+import DsMonad -- the monadery used in the desugarer
+
+import AbsPrel
+import TysPrim -- ****** ToDo: PROPERLY
+import TysWiredIn
+import AbsUniType
+import DsUtils
+import Id ( getInstantiatedDataConSig, mkTupleCon, DataCon(..) )
+import Maybes ( maybeToBool, Maybe(..) )
+import Pretty
+#if USE_ATTACK_PRAGMAS
+import Unique
+#endif
+import Util
+\end{code}
+
+Desugaring of @ccall@s consists of adding some state manipulation,
+unboxing any boxed primitive arguments and boxing the result if
+desired.
+
+The state stuff just consists of adding in
+@\ s -> case s of { S# s# -> ... }@ in an appropriate place.
+
+The unboxing is straightforward, as all information needed to unbox is
+available from the type. For each boxed-primitive argument, we
+transform:
+\begin{verbatim}
+ _ccall_ foo [ r, t1, ... tm ] e1 ... em
+ |
+ |
+ V
+ case e1 of { T1# x1# ->
+ ...
+ case em of { Tm# xm# -> xm#
+ ccall# foo [ r, t1#, ... tm# ] x1# ... xm#
+ } ... }
+\end{verbatim}
+
+The reboxing of a @_ccall_@ result is a bit tricker: the types don't
+contain information about the state-pairing functions so we have to
+keep a list of \tr{(type, s-p-function)} pairs. We transform as
+follows:
+\begin{verbatim}
+ ccall# foo [ r, t1#, ... tm# ] e1# ... em#
+ |
+ |
+ V
+ \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of
+ (StateAnd<r># result# state#) -> (R# result#, realWorld#)
+\end{verbatim}
+
+\begin{code}
+dsCCall :: FAST_STRING -- C routine to invoke
+ -> [PlainCoreExpr] -- Arguments (desugared)
+ -> Bool -- True <=> might cause Haskell GC
+ -> Bool -- True <=> really a "_casm_"
+ -> UniType -- Type of the result (a boxed-prim type)
+ -> DsM PlainCoreExpr
+
+dsCCall label args may_gc is_asm result_ty
+ = newSysLocalDs realWorldStateTy `thenDs` \ old_s ->
+
+ mapAndUnzipDs unboxArg (CoVar old_s : args) `thenDs` \ (final_args, arg_wrappers) ->
+
+ boxResult result_ty `thenDs` \ (final_result_ty, res_wrapper) ->
+
+ let
+ the_ccall_op = CCallOp label is_asm may_gc
+ (map typeOfCoreExpr final_args)
+ final_result_ty
+ in
+ mkCoPrimDs the_ccall_op
+ [] -- ***NOTE*** no ty apps; the types are inside the_ccall_op.
+ final_args `thenDs` \ the_prim_app ->
+ let
+ the_body = foldr apply (res_wrapper the_prim_app) arg_wrappers
+ in
+ returnDs (CoLam [old_s] the_body)
+ where
+ apply f x = f x
+\end{code}
+
+\begin{code}
+unboxArg :: PlainCoreExpr -- The supplied argument
+ -> DsM (PlainCoreExpr, -- To pass as the actual argument
+ PlainCoreExpr -> PlainCoreExpr -- Wrapper to unbox the arg
+ )
+unboxArg arg
+
+ -- Primitive types
+ -- ADR Question: can this ever be used? None of the PrimTypes are
+ -- instances of the _CCallable class.
+ | isPrimType arg_ty
+ = returnDs (arg, \body -> body)
+
+ -- Strings
+ | arg_ty == stringTy
+ -- ToDo (ADR): - allow synonyms of Strings too?
+ = newSysLocalDs byteArrayPrimTy `thenDs` \ prim_arg ->
+ mkCoAppDs (CoVar packStringForCId) arg `thenDs` \ pack_appn ->
+ returnDs (CoVar prim_arg,
+ \body -> CoCase pack_appn (CoPrimAlts []
+ (CoBindDefault prim_arg body))
+ )
+
+ | null data_cons
+ -- oops: we can't see the data constructors!!!
+ = can't_see_datacons_error "argument" arg_ty
+
+ -- Byte-arrays, both mutable and otherwise
+ -- (HACKy method -- but we really don't want the TyCons wired-in...) [WDP 94/10]
+ | is_data_type &&
+ length data_con_arg_tys == 2 &&
+ not (isPrimType data_con_arg_ty1) &&
+ isPrimType data_con_arg_ty2
+ -- and, of course, it is an instance of _CCallable
+-- ( tycon == byteArrayTyCon ||
+-- tycon == mutableByteArrayTyCon )
+ = newSysLocalsDs data_con_arg_tys `thenDs` \ vars@[ixs_var, arr_cts_var] ->
+ returnDs (CoVar arr_cts_var,
+ \ body -> CoCase arg (CoAlgAlts [(the_data_con,vars,body)]
+ CoNoDefault)
+ )
+
+ -- Data types with a single constructor, which has a single, primitive-typed arg
+ | maybeToBool maybe_boxed_prim_arg_ty
+ = newSysLocalDs the_prim_arg_ty `thenDs` \ prim_arg ->
+ returnDs (CoVar prim_arg,
+ \ body -> CoCase arg (CoAlgAlts [(box_data_con,[prim_arg],body)]
+ CoNoDefault)
+ )
+ -- ... continued below ....
+\end{code}
+
+As an experiment, I'm going to unpack any "acceptably small"
+enumeration. This code will never get used in the main version
+because enumerations would have triggered type errors but I've
+disabled type-checking in my version. ADR
+
+To Will: It might be worth leaving this in (but commented out) until
+we decide what's happening with enumerations. ADR
+
+\begin{code}
+#if 0
+ -- MAYBE LATER:
+ -- Data types with a nullary constructors (enumeration)
+ | isEnumerationType arg_ty && -- enumeration
+ (length data_cons) <= 5 -- "acceptably short"
+ = newSysLocalDs the_prim_arg_ty `thenDs` \ prim_arg ->
+
+ let
+ alts = [ (con, [], mkMachInt i) | (con,i) <- data_cons `zip` [0..] ]
+ arg_tag = CoCase arg (CoAlgAlts alts) CoNoDefault
+ in
+
+ returnDs (CoVar prim_arg,
+ \ body -> CoCase arg_tag (CoPrimAlts [(prim_arg, body)] CoNoDefault)
+ )
+#endif
+\end{code}
+
+\begin{code}
+ -- ... continued from above ....
+ | otherwise
+ = pprPanic "unboxArg: " (ppr PprDebug arg_ty)
+ where
+ arg_ty = typeOfCoreExpr arg
+
+ maybe_boxed_prim_arg_ty = maybeBoxedPrimType arg_ty
+ (Just (box_data_con, the_prim_arg_ty)) = maybe_boxed_prim_arg_ty
+
+ maybe_data_type = getUniDataTyCon_maybe arg_ty
+ is_data_type = maybeToBool maybe_data_type
+ (Just (tycon, tycon_arg_tys, data_cons)) = maybe_data_type
+ (the_data_con : other_data_cons) = data_cons
+
+ (_, data_con_arg_tys, _) = getInstantiatedDataConSig the_data_con tycon_arg_tys
+ (data_con_arg_ty1 : data_con_arg_ty2 : _) = data_con_arg_tys
+
+can't_see_datacons_error thing ty
+ = error (ppShow 100 (ppBesides [ppStr "ERROR: Can't see the data constructor(s) for _ccall_/_casm_ ", ppStr thing, ppStr "; type: ", ppr PprForUser ty]))
+\end{code}
+
+
+\begin{code}
+tuple_con_2 = mkTupleCon 2 -- out here to avoid CAF (sigh)
+covar_tuple_con_0 = CoVar (mkTupleCon 0) -- ditto
+
+boxResult :: UniType -- Type of desired result
+ -> DsM (UniType, -- Type of the result of the ccall itself
+ PlainCoreExpr -> PlainCoreExpr) -- Wrapper for the ccall
+ -- to box the result
+boxResult result_ty
+ | null data_cons
+ -- oops! can't see the data constructors
+ = can't_see_datacons_error "result" result_ty
+
+ -- Data types with a single constructor, which has a single, primitive-typed arg
+ | (maybeToBool maybe_data_type) && -- Data type
+ (null other_data_cons) && -- Just one constr
+ not (null data_con_arg_tys) && null other_args_tys && -- Just one arg
+ isPrimType the_prim_result_ty -- of primitive type
+ =
+ newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
+ newSysLocalDs the_prim_result_ty `thenDs` \ prim_result_id ->
+
+ mkCoConDs stateDataCon [realWorldTy] [CoVar prim_state_id] `thenDs` \ new_state ->
+ mkCoConDs the_data_con tycon_arg_tys [CoVar prim_result_id] `thenDs` \ the_result ->
+
+ mkCoConDs tuple_con_2
+ [result_ty, realWorldStateTy]
+ [the_result, new_state] `thenDs` \ the_pair ->
+ let
+ the_alt = (state_and_prim_datacon, [prim_state_id, prim_result_id], the_pair)
+ in
+ returnDs (state_and_prim_ty,
+ \prim_app -> CoCase prim_app (CoAlgAlts [the_alt] CoNoDefault)
+ )
+
+ -- Data types with a single nullary constructor
+ | (maybeToBool maybe_data_type) && -- Data type
+ (null other_data_cons) && -- Just one constr
+ (null data_con_arg_tys)
+ =
+ newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
+
+ mkCoConDs stateDataCon [realWorldTy] [CoVar prim_state_id] `thenDs` \ new_state ->
+
+ mkCoConDs tuple_con_2
+ [result_ty, realWorldStateTy]
+ [covar_tuple_con_0, new_state] `thenDs` \ the_pair ->
+
+ let
+ the_alt = (stateDataCon, [prim_state_id], the_pair)
+ in
+ returnDs (realWorldStateTy,
+ \prim_app -> CoCase prim_app (CoAlgAlts [the_alt] CoNoDefault)
+ )
+
+#if 0
+ -- MAYBE LATER???
+
+ -- Data types with several nullary constructors (Enumerated types)
+ | isEnumerationType result_ty && -- Enumeration
+ (length data_cons) <= 5 -- fairly short
+ =
+ newSysLocalDs realWorldStatePrimTy `thenDs` \ prim_state_id ->
+ newSysLocalDs intPrimTy `thenDs` \ prim_result_id ->
+
+ mkCoConDs stateDataCon [realWorldTy] [CoVar prim_state_id] `thenDs` \ new_state ->
+
+ let
+ alts = [ (mkMachInt i, con) | (i, con) <- [0..] `zip` data_cons ]
+ the_result = CoCase prim_result_id (CoPrimAlts alts) CoNoDefault
+ in
+
+ mkCoConDs (mkTupleCon 2)
+ [result_ty, realWorldStateTy]
+ [the_result, new_state] `thenDs` \ the_pair ->
+ let
+ the_alt = (state_and_prim_datacon, [prim_state_id, prim_result_id], the_pair)
+ in
+ returnDs (state_and_prim_ty,
+ \prim_app -> CoCase prim_app (CoAlgAlts [the_alt] CoNoDefault)
+ )
+#endif
+
+ | otherwise
+ = pprPanic "boxResult: " (ppr PprDebug result_ty)
+
+ where
+ maybe_data_type = getUniDataTyCon_maybe result_ty
+ Just (tycon, tycon_arg_tys, data_cons) = maybe_data_type
+ (the_data_con : other_data_cons) = data_cons
+
+ (_, data_con_arg_tys, _) = getInstantiatedDataConSig the_data_con tycon_arg_tys
+ (the_prim_result_ty : other_args_tys) = data_con_arg_tys
+
+ (state_and_prim_datacon, state_and_prim_ty) = getStatePairingConInfo the_prim_result_ty
+\end{code}
+