1 %---------------------------------------------------------------*
3 \section{Executable code for arithmetic primitives}
5 %---------------------------------------------------------------*
8 /* basic definitions, just as if this were a module */
11 Sigh, ieee-flpt.h (which we need here) uses
12 __GLASGOW_HASKELL__ in a place or two to check
13 whether it is being included in a Haskell source file
14 or not. This is no longer the case! __GLASGOW_HASKELL__
15 is also defined when compiling .c files (C code that
16 depend on the RTS API needs to know this).
18 An unfortunate state of affairs, but since this is
19 the only place where the two uses of __GLASGOW_HASKELL__
20 clash, we hack around and undefine it before including
21 the header file. -- sof 8/98
23 #ifdef __GLASGOW_HASKELL__
24 #undef __GLASGOW_HASKELL__
30 %************************************************************************
32 \subsection[rts-prims-int]{Things for Int}
34 %************************************************************************
36 Well, really just one little devil:
44 if (a >= 0) { return( a / b ); }
45 else { return( ((a+1) / b) - 1 ); }
47 if (a > 0) { return( ((a-1) / b) - 1 ); }
48 else { return( a / b ); }
49 /* ToDo: something for division by zero? */
54 %************************************************************************
56 \subsection[rts-prims-float]{Things for floating-point}
58 %************************************************************************
60 %************************************************************************
62 \subsubsection[rts-mving-float]{Moving floatish things around}
64 %************************************************************************
66 See \tr{imports/StgMacros.h} for more about these things.
68 #if defined(FLOAT_ALIGNMENT_TROUBLES) && ! defined(__STG_GCC_REGS__)
69 /* Not all machines suffer from these (e.g., m68k). */
70 /* If we are registerizing, we must *not* have this code! */
74 ASSIGN_DBL(W_ p_dest[], StgDouble src)
94 ASSIGN_FLT(W_ p_dest[], StgFloat src)
110 #endif /* FLOAT_ALIGNMENT_TROUBLES and not registerizing */
113 %************************************************************************
115 \subsubsection[rts-coding-floats]{Encoding/decoding float-ish things}
117 %************************************************************************
119 Encoding and decoding Doubles. Code based on the HBC code
123 #define GMP_BASE 4294967296.0
124 #if alpha_TARGET_ARCH
125 #define DNBIGIT 1 /* mantissa of a double will fit in one long */
127 #define DNBIGIT 2 /* mantissa of a double will fit in two longs */
129 #define FNBIGIT 1 /* for float, one long */
131 #if IEEE_FLOATING_POINT
132 #define MY_DMINEXP ((DBL_MIN_EXP) - (DBL_MANT_DIG) - 1)
133 /* DMINEXP is defined in values.h on Linux (for example) */
134 #define DHIGHBIT 0x00100000
135 #define DMSBIT 0x80000000
137 #define MY_FMINEXP ((FLT_MIN_EXP) - (FLT_MANT_DIG) - 1)
138 #define FHIGHBIT 0x00800000
139 #define FMSBIT 0x80000000
153 __encodeDouble (MP_INT *s, I_ e) /* result = s * 2^e */
159 /* Convert MP_INT to a double; knows a lot about internal rep! */
160 i = __abs(s->size)-1;
164 for(r = s->d[i], i--; i >= 0; i--)
165 r = r * GMP_BASE + s->d[i];
168 /* Now raise to the exponent */
169 if ( r != 0.0 ) /* Lennart suggests this avoids a bug in MIPS's ldexp */
172 /* sign is encoded in the size */
177 temp = stgMallocBytes(mpz_sizeinbase(s,10)+2);
178 fprintf(stderr, "__encodeDouble(%s, %ld) => %g\n", mpz_get_str(temp,10,s), e, r);
184 #if ! alpha_TARGET_ARCH
185 /* On the alpha, Stg{Floats,Doubles} are the same */
187 __encodeFloat (MP_INT *s, I_ e) /* result = s * 2^e */
192 /* Convert MP_INT to a float; knows a lot about internal rep! */
193 for(r = 0.0, i = __abs(s->size)-1; i >= 0; i--)
194 r = (r * GMP_BASE) + s->d[i];
196 /* Now raise to the exponent */
197 if ( r != 0.0 ) /* Lennart suggests this avoids a bug in MIPS's ldexp */
200 /* sign is encoded in the size */
209 __decodeDouble (MP_INT *man, I_ *exp, StgDouble dbl)
211 #if ! IEEE_FLOATING_POINT
212 fprintf(stderr, "__decodeDouble: non-IEEE not yet supported\n");
215 #else /* IEEE fl-pt */
216 /* Do some bit fiddling on IEEE */
217 unsigned int low, high; /* assuming 32 bit ints */
219 union { double d; int i[2]; } u; /* assuming 32 bit ints, 64 bit double */
222 u.d = dbl; /* grab chunks of the double */
226 /* we know the MP_INT* passed in has size zero, so we realloc
229 man->alloc = DNBIGIT;
231 if (low == 0 && (high & ~DMSBIT) == 0) {
236 iexp = ((high >> 20) & 0x7ff) + MY_DMINEXP;
238 /* fprintf(stderr, "decode %g %08x %08x %d\n", u.d, high, low, iexp); */
241 if (iexp != MY_DMINEXP) /* don't add hidden bit to denorms */
245 /* A denorm, normalize the mantissa */
246 while (! (high & DHIGHBIT)) {
260 man->d[0] = ((unsigned long)high) << 32 | (unsigned long)low;
262 error : error : error : Cannae cope with DNBIGIT
266 man->size = -man->size;
270 temp = stgMallocBytes(mpz_sizeinbase(man,10)+2);
271 fprintf(stderr, "__decodeDouble(%g) => %s, %ld\n", dbl, mpz_get_str(temp,10,man), *exp);
274 #endif /* IEEE fl-pt */
277 #if ! alpha_TARGET_ARCH
278 /* Again, on the alpha we do not have separate "StgFloat" routines */
280 __decodeFloat (MP_INT *man, I_ *exp, StgFloat flt)
282 #if ! IEEE_FLOATING_POINT
283 fprintf(stderr, "__decodeFloat: non-IEEE not yet supported\n");
286 #else /* IEEE fl-pt */
287 /* Do some bit fiddling on IEEE */
288 int high, sign; /* assuming 32 bit ints */
289 union { float f; int i; } u; /* assuming 32 bit float and int */
291 u.f = flt; /* grab the float */
294 /* we know the MP_INT* passed in has size zero, so we realloc
297 man->alloc = FNBIGIT;
299 if ((high & ~FMSBIT) == 0) {
304 *exp = ((high >> 23) & 0xff) + MY_FMINEXP;
308 if (*exp != MY_FMINEXP) /* don't add hidden bit to denorms */
312 /* A denorm, normalize the mantissa */
313 while (! (high & FHIGHBIT)) {
321 error : error : error : Cannae cope with FNBIGIT
324 man->size = -man->size;
327 #endif /* IEEE fl-pt */
332 %************************************************************************
334 \subsection[rts-prims-integer]{Things for Integers (using GNU MP pkg)}
336 %************************************************************************
338 See ghc/compiler/prelude/TyInteger.lhs for the comment on this stuff.
340 %************************************************************************
342 \subsubsection[rts-gmp-alloc]{Our custom memory allocation routines}
344 %************************************************************************
346 The GMP documentation says what these must do.
350 StgInt DEBUG_GMPAllocBudget = 0;
351 /* # of _words_ known to be available for stgAllocForGMP */
355 stgAllocForGMP (size_in_bytes)
356 size_t size_in_bytes;
359 I_ data_size_in_words, total_size_in_words;
361 /* the new object will be "DATA_HS + BYTES_TO_STGWORDS(size_in_bytes)" words
363 data_size_in_words = BYTES_TO_STGWORDS(size_in_bytes);
364 total_size_in_words = DATA_HS + data_size_in_words;
366 /* Check that we are within the current budget */
367 if (DEBUG_GMPAllocBudget < total_size_in_words) {
368 fprintf(stderr, "stgAllocForGMP: budget error: %ld %ld\n",
369 DEBUG_GMPAllocBudget, total_size_in_words);
373 DEBUG_GMPAllocBudget -= total_size_in_words;
377 /* if it's a DATA thingy, we'd better fill it in.
379 SET_DATA_HDR(SAVE_Hp+1,ArrayOfData_info,CCC,DATA_VHS+data_size_in_words,0);
381 /* we're gonna return a pointer to the non-hdr part of the beast
383 stuff_ptr = (void *) (SAVE_Hp + 1 + DATA_HS);
385 /* move the heap pointer right along...
386 (tell [ticky-ticky and regular] profiling about it, too)
388 SAVE_Hp += total_size_in_words;
390 ALLOC_HEAP(total_size_in_words); /* ticky-ticky profiling */
391 /* ALLOC_CON(DATA_HS,data_size_in_words,0); */
392 ALLOC_PRIM(DATA_HS,data_size_in_words,0,total_size_in_words);
394 CC_ALLOC(CCC,total_size_in_words,CON_K); /* cc profiling */
395 /* NB: HACK WARNING: The above line will do The WRONG THING
396 if the CurrCostCentre reg is ever put in a Real Machine Register (TM).
399 /* and return what we said we would */
404 stgReallocForGMP (ptr, old_size, new_size)
406 size_t old_size, new_size;
408 void *new_stuff_ptr = stgAllocForGMP(new_size);
410 char *p = (char *) ptr;
411 char *q = (char *) new_stuff_ptr;
413 for (; i < old_size; i++, p++, q++) {
417 return(new_stuff_ptr);
421 stgDeallocForGMP (ptr, size)
425 /* easy for us: the garbage collector does the dealloc'n */