1 %---------------------------------------------------------------*
3 \section{Executable code for arithmetic primitives}
5 %---------------------------------------------------------------*
8 /* basic definitions, just as if this were a module */
13 %************************************************************************
15 \subsection[rts-prims-int]{Things for Int}
17 %************************************************************************
19 Well, really just one little devil:
27 if (a >= 0) { return( a / b ); }
28 else { return( ((a+1) / b) - 1 ); }
30 if (a > 0) { return( ((a-1) / b) - 1 ); }
31 else { return( a / b ); }
32 /* ToDo: something for division by zero? */
37 %************************************************************************
39 \subsection[rts-prims-float]{Things for floating-point}
41 %************************************************************************
43 %************************************************************************
45 \subsubsection[rts-mving-float]{Moving floatish things around}
47 %************************************************************************
49 See \tr{imports/StgMacros.h} for more about these things.
51 #if defined(FLOAT_ALIGNMENT_TROUBLES) && ! defined(__STG_GCC_REGS__)
52 /* Not all machines suffer from these (e.g., m68k). */
53 /* If we are registerizing, we must *not* have this code! */
58 ASSIGN_DBL(W_ p_dest[], StgDouble src)
60 ASSIGN_DBL(p_dest, src)
61 W_ p_dest[]; StgDouble src;
88 ASSIGN_FLT(W_ p_dest[], StgFloat src)
90 ASSIGN_FLT(p_dest, src)
91 W_ p_dest[]; StgFloat src;
113 #endif /* FLOAT_ALIGNMENT_TROUBLES and not registerizing */
116 %************************************************************************
118 \subsubsection[rts-coding-floats]{Encoding/decoding float-ish things}
120 %************************************************************************
122 Encoding and decoding Doubles. Code based on the HBC code
126 #define GMP_BASE 4294967296.0
127 #if alpha_TARGET_ARCH
128 #define DNBIGIT 1 /* mantissa of a double will fit in one long */
130 #define DNBIGIT 2 /* mantissa of a double will fit in two longs */
132 #define FNBIGIT 1 /* for float, one long */
134 #if IEEE_FLOATING_POINT
135 #define MY_DMINEXP ((DBL_MIN_EXP) - (DBL_MANT_DIG) - 1)
136 /* DMINEXP is defined in values.h on Linux (for example) */
137 #define DHIGHBIT 0x00100000
138 #define DMSBIT 0x80000000
140 #define MY_FMINEXP ((FLT_MIN_EXP) - (FLT_MANT_DIG) - 1)
141 #define FHIGHBIT 0x00800000
142 #define FMSBIT 0x80000000
157 __encodeDouble (MP_INT *s, I_ e) /* result = s * 2^e */
159 __encodeDouble (s, e)
161 #endif /* ! __STDC__ */
167 /* Convert MP_INT to a double; knows a lot about internal rep! */
168 i = __abs(s->size)-1;
172 for(r = s->d[i], i--; i >= 0; i--)
173 r = r * GMP_BASE + s->d[i];
176 /* Now raise to the exponent */
177 if ( r != 0.0 ) /* Lennart suggests this avoids a bug in MIPS's ldexp */
180 /* sign is encoded in the size */
185 temp = xmalloc(mpz_sizeinbase(s,10)+2);
186 fprintf(stderr, "__encodeDouble(%s, %ld) => %g\n", mpz_get_str(temp,10,s), e, r);
192 #if ! alpha_TARGET_ARCH
193 /* On the alpha, Stg{Floats,Doubles} are the same */
196 __encodeFloat (MP_INT *s, I_ e) /* result = s * 2^e */
200 #endif /* ! __STDC__ */
205 /* Convert MP_INT to a float; knows a lot about internal rep! */
206 for(r = 0.0, i = __abs(s->size)-1; i >= 0; i--)
207 r = (r * GMP_BASE) + s->d[i];
209 /* Now raise to the exponent */
210 if ( r != 0.0 ) /* Lennart suggests this avoids a bug in MIPS's ldexp */
213 /* sign is encoded in the size */
223 __decodeDouble (MP_INT *man, I_ *exp, StgDouble dbl)
225 __decodeDouble (man, exp, dbl)
229 #endif /* ! __STDC__ */
231 #if ! IEEE_FLOATING_POINT
232 fprintf(stderr, "__decodeDouble: non-IEEE not yet supported\n");
235 #else /* IEEE fl-pt */
236 /* Do some bit fiddling on IEEE */
237 unsigned int low, high; /* assuming 32 bit ints */
239 union { double d; int i[2]; } u; /* assuming 32 bit ints, 64 bit double */
242 u.d = dbl; /* grab chunks of the double */
246 /* we know the MP_INT* passed in has size zero, so we realloc
249 man->alloc = DNBIGIT;
251 if (low == 0 && (high & ~DMSBIT) == 0) {
256 iexp = ((high >> 20) & 0x7ff) + MY_DMINEXP;
258 /* fprintf(stderr, "decode %g %08x %08x %d\n", u.d, high, low, iexp); */
261 if (iexp != MY_DMINEXP) /* don't add hidden bit to denorms */
265 /* A denorm, normalize the mantissa */
266 while (! (high & DHIGHBIT)) {
280 man->d[0] = ((unsigned long)high) << 32 | (unsigned long)low;
282 error : error : error : Cannae cope with DNBIGIT
286 man->size = -man->size;
290 temp = xmalloc(mpz_sizeinbase(man,10)+2);
291 fprintf(stderr, "__decodeDouble(%g) => %s, %ld\n", dbl, mpz_get_str(temp,10,man), *exp);
294 #endif /* IEEE fl-pt */
297 #if ! alpha_TARGET_ARCH
298 /* Again, on the alpha we do not have separate "StgFloat" routines */
301 __decodeFloat (MP_INT *man, I_ *exp, StgFloat flt)
303 __decodeFloat (man, exp, flt)
307 #endif /* ! __STDC__ */
309 #if ! IEEE_FLOATING_POINT
310 fprintf(stderr, "__decodeFloat: non-IEEE not yet supported\n");
313 #else /* IEEE fl-pt */
314 /* Do some bit fiddling on IEEE */
315 int high, sign; /* assuming 32 bit ints */
316 union { float f; int i; } u; /* assuming 32 bit float and int */
318 u.f = flt; /* grab the float */
321 /* we know the MP_INT* passed in has size zero, so we realloc
324 man->alloc = FNBIGIT;
326 if ((high & ~FMSBIT) == 0) {
331 *exp = ((high >> 23) & 0xff) + MY_FMINEXP;
335 if (*exp != MY_FMINEXP) /* don't add hidden bit to denorms */
339 /* A denorm, normalize the mantissa */
340 while (! (high & FHIGHBIT)) {
348 error : error : error : Cannae cope with FNBIGIT
351 man->size = -man->size;
354 #endif /* IEEE fl-pt */
359 %************************************************************************
361 \subsection[rts-prims-integer]{Things for Integers (using GNU MP pkg)}
363 %************************************************************************
365 See ghc/compiler/prelude/TyInteger.lhs for the comment on this stuff.
367 %************************************************************************
369 \subsubsection[rts-gmp-alloc]{Our custom memory allocation routines}
371 %************************************************************************
373 The GMP documentation says what these must do.
377 StgInt DEBUG_GMPAllocBudget = 0;
378 /* # of _words_ known to be available for stgAllocForGMP */
382 stgAllocForGMP (size_in_bytes)
383 size_t size_in_bytes;
386 I_ data_size_in_words, total_size_in_words;
388 /* the new object will be "DATA_HS + BYTES_TO_STGWORDS(size_in_bytes)" words
390 data_size_in_words = BYTES_TO_STGWORDS(size_in_bytes);
391 total_size_in_words = DATA_HS + data_size_in_words;
394 /* Check that we are within the current budget */
395 if (DEBUG_GMPAllocBudget < total_size_in_words) {
396 fprintf(stderr, "stgAllocForGMP: budget error: %ld %ld\n",
397 DEBUG_GMPAllocBudget, total_size_in_words);
401 DEBUG_GMPAllocBudget -= total_size_in_words;
404 /* if it's a DATA thingy, we'd better fill it in.
406 SET_DATA_HDR(SAVE_Hp+1,ArrayOfData_info,CCC,DATA_VHS+data_size_in_words,0);
408 /* we're gonna return a pointer to the non-hdr part of the beast
410 stuff_ptr = (void *) (SAVE_Hp + 1 + DATA_HS);
412 /* move the heap pointer right along...
413 (tell [ticky-ticky and regular] profiling about it, too)
415 SAVE_Hp += total_size_in_words;
417 #if ! defined(DO_SPAT_PROFILING)
418 /* Note: ActivityReg is not defined in this .lc file */
420 ALLOC_HEAP(total_size_in_words); /* ticky-ticky profiling */
421 /* ALLOC_CON(DATA_HS,data_size_in_words,0); */
422 ALLOC_PRIM(DATA_HS,data_size_in_words,0,total_size_in_words);
423 #endif /* ! DO_SPAT_PROFILING */
424 CC_ALLOC(CCC,total_size_in_words,CON_K); /* cc profiling */
425 /* NB: HACK WARNING: The above line will do The WRONG THING
426 if the CurrCostCentre reg is ever put in a Real Machine Register (TM).
429 #if defined(LIFE_PROFILE) /* HACK warning -- Bump HpLim (see also StgMacros.lh)*/
430 SAVE_HpLim += 1; /* SET_DATA_HDR attempted HpLim++ in wrong window */
433 /* and return what we said we would */
438 stgReallocForGMP (ptr, old_size, new_size)
440 size_t old_size, new_size;
442 void *new_stuff_ptr = stgAllocForGMP(new_size);
444 char *p = (char *) ptr;
445 char *q = (char *) new_stuff_ptr;
447 for (; i < old_size; i++, p++, q++) {
451 return(new_stuff_ptr);
455 stgDeallocForGMP (ptr, size)
459 /* easy for us: the garbage collector does the dealloc'n */