% % (c) The GRASP/AQUA Project, Glasgow University, 1992-1994 % %************************************************************************ %* * \section{How data is handled, especially floats and doubles} %* * %************************************************************************ \begin{code} #ifndef STGTYPES_H #define STGTYPES_H \end{code} Some variables (eg the A stack, the stack pointers, floating point registers) can only contain data of a particular (machine type). %partain:\begin{center} \begin{tabular}{|l|l|} \hline What we call it & The C type which represents it \\ \hline & \\ StgInt & long \\ StgFloat & float \\ StgDouble & double \\ StgChar & unsigned char \\\hline StgStablePtr & long \\ StgForeignObj & (long *) \\ \end{tabular} %partain:\end{center} Others, notably the heap itself and the B stack, can contain various kinds of data; pointers, floats, doubles, chars and so on. These structures are given C type @StgWord@, meaning ``I don't know''. %partain:\begin{center} \begin{tabular}{|l|l|} \hline StgWord & long \\\hline \end{tabular} %partain:\end{center} % @StgWord@s only live in {\em memory locations}; there are no registers % of type @StgWord@. When we load/store things in the heap, or on the B stack, we therefore have to coerce data in and out of the @StgWord@ type. For @StgInt@ and @StgChar@ that's no problem; we just use a C cast. Now here's the rub: we can't cast a @StgFloat@ to @StgWord@ because C performs numeric conversions if you do! Worse, we obviously can't cast a @StgDouble@ to @StgWord@, because it's the wrong size. The solution we adopt is to provide functions/macros with the following prototypes \begin{pseudocode} StgFloat PK_FLT( StgWord * ) void ASSIGN_FLT( StgWord [], StgFloat ) StgDouble PK_DBL( StgWord * ) void ASSIGN_DBL( StgWord [], StgDouble ) \end{pseudocode} The @PK@ functions create a suitable float/double given a pointer to some @StgWord@ memory locations; the @ASSIGN@ functions do the reverse. Notice that it is a private matter between @PK_DBL@ and @ASSIGN_DBL@ how the words are acutally used to store the double (the high word could go in the upper or lower memory location). We implement these operations as inlined C functions; much better than macros because they need a local variable which macros don't give you. There is probably more than one way to implement them; we have cheated the type system using a union type. \begin{code} typedef unsigned long StgWord; /* used for heap- and Bstk- words, which can be of various types */ /* macro to round a number-of-bytes up to a sufficient number of words: */ #define BYTES_TO_STGWORDS(no_bytes) (((no_bytes)+sizeof(W_)-1)/sizeof(W_)) typedef unsigned long *StgPtr; /* StgPtr is a ptr to a heap object or into the B stack */ typedef StgPtr *StgPtrPtr; /* used for A stack pointer */ typedef long StgInt; /* seven shorthand forms: StgChar, StgWord, StgPtr, StgPtrPtr, StgInt, StgAddr, const StgPtr */ typedef unsigned char C_; typedef unsigned long W_; typedef unsigned long *P_; typedef P_ *PP_; typedef long I_; typedef void *A_; typedef const unsigned long *D_; typedef unsigned char StgChar; typedef void *StgAddr; #if alpha_TARGET_ARCH typedef double StgFloat; typedef double StgDouble; #else typedef float StgFloat; typedef double StgDouble; #endif typedef StgPtr StgArray; typedef StgChar *StgByteArray; typedef StgByteArray B_; typedef I_ StgStablePtr; /* Index into Stable Pointer Table */ typedef P_ StgForeignObj; /* (Probably) Pointer to object in C Heap */ /* On any architecture, StgForeignObj should be big enough to hold the largest possible pointer. */ /* These are used to pass the do_full_collection flag to RealPerformGC and collectHeap. (Is there a standard name for them?) [ADR] Why longs? --JSM No good reason (bad reason: same as StgInt) -- ADR An abomination! Death to StgBool! --JSM */ #define StgFalse 0 #define StgTrue 1 typedef long StgBool; typedef long StgTag; typedef StgWord StgInfoEntry; typedef StgWord *StgInfoPtr; \end{code} Types for the generated C functions take no arguments return a pointer to the next function to be called use: Ptr to Fun that returns a Ptr to Fun which returns Ptr to void \begin{code} typedef void *(*(*StgFunPtr)(STG_NO_ARGS))(STG_NO_ARGS); typedef StgFunPtr (StgFun)(STG_NO_ARGS); typedef StgFunPtr sfp; /* shorthand, for less typing while debugging */ typedef StgFunPtr (*StgFunPtrFunPtr)(STG_NO_ARGS); typedef StgFunPtr F_; typedef StgFunPtrFunPtr *FP_; typedef D_ StgRetAddr; /* for now ... */ #if 0 typedef union { StgFunPtr d; /* direct return */ D_ v; /* vectored return */ } StgRetAddr; #endif /* new union type, to eventually replace StgWord */ typedef union word { B_ b; /* pointer to byte array */ W_ c; /* (unsigned) character; *not* StgChar type */ D_ d; /* read-only data pointer */ StgFloat f; /* single-precision float */ StgFunPtr fp; /* function (code) pointer */ I_ i; /* integer */ P_ p; /* basic pointer */ StgRetAddr r; /* return address or vector */ W_ w; /* arbitrary word (needed?) */ void *v; /* ??? (AddrKind) */ } StgUnion; /* If a BitWord is anything other than an StgWord, you may have some problems. In particular, be sure that the dynamic allocation of a BitWord array from the heap is done properly. */ typedef StgWord BitWord; /* Bit marking words */ /* Stuff for hashing */ typedef StgWord hash_t; #define UNHASHED (~0L) /* ullong (64|128-bit) type: only include if needed (not ANSI) */ #if defined(__GNUC__) typedef unsigned long long ullong; /* need prototypes */ #define LL(x) CAT2(x,LL) #else typedef unsigned long ullong; #define LL(x) CAT2(x,L) #endif \end{code} Stuff for packed shorts; used in @StgMacros.h@. \begin{code} typedef struct __uw { unsigned short s1; unsigned short s2; } unpacked_word; typedef union __ps { unsigned int u; unpacked_word wu; } packed_shorts; \end{code} Stuff for floats/doubles; used in @StgMacros.h@. ToDo: looks pretty 64-bit unfriendly to me! [WDP] \begin{code} typedef struct __ud { StgWord dhi; StgWord dlo; } unpacked_double; typedef union __dt { StgDouble d; unpacked_double du; } double_thing; typedef StgWord unpacked_float; typedef union __ft { StgFloat f; unpacked_float fu; } float_thing; \end{code} Also include the RTS types for the runtime system modules. \begin{code} #include "RtsTypes.h" #endif /* ! STGTYPES_H */ \end{code}