Bug in register allocation for long longÆ?ü^¹¥¨?

asal@freesurf.ch asal@freesurf.ch
Fri Oct 22 15:46:00 GMT 1999


/*  Dear member of the GCC society,
* 
*  compiling this code on a i386-compatible linux with
* 
*   gcc --version = 2.95
* 
* and simple (-O2) optimization
* 
*   gcc -O2 -S -o mathtest.asm mathtest.c
*  
* produces code which allocates registers badly.
* (simultaneous usage of the same integer register for 2 purposes)
*
* => it will (usually) lead to a segmentation-fault abort.
* 
* I actually deduced it from a library provided include file,
* which kept producing errors.
*
*/


#define __NO_MATH_INLINES 1
/* defined to prevent usage of any (erroneous) fancy math-inlines */

extern double exp(double x);
extern double log(double x);

#include <stdio.h>


typedef double float_type;
/* You can use whatever you like: (double) or (long double),
* the programme will fail!
*/


/* the library function "pow(doube x,double y)" must distinguish
* whether the exponent was an integer value (passed as float)
* or a "true" float.
* 
* here I focus on integer values only:
*/


inline float_type IPOW ( float_type x, long long int y) {
/* computes an integer power of a float_type,
* seems ok to me
*/

float_type result = 1.0;
if (y) {
if (y < 0) {
y = ~y;
result =  x = 1.0 / x; }

if (y & 1)
result *= x;

y >>= 1;

while (y) {
x *= x;
if (y & 1)
result *= x;
y >>= 1; }}
return result;
}



inline float_type POW (float_type x, float_type y) {

/******* this line produces eventually errors **********/
long long int y_trucd = (long long int) y; 

if (x == 0.0 && y > 0.0)
return 0.0;

if (y == (float_type) y_trucd) {
return IPOW( x, y_trucd ); }

/* else fall back to the standard expression */
return exp( y * log(x) ); 
}







int main() {
double X;
fscanf( stdin, "%lf", &X);
fprintf(stderr, "%f\n",  POW(X, -1.0002) ); // works ok.
fprintf(stderr, "%f\n",  POW(X, -1.0003) ); // now bad things 
happen in 
POW.
return 0; }



/* compiling this code on a i386-compatible linux with
* 
*   gcc --version = 2.95
* 
* and simple (-O2) optimization, yields the following assembler 
output,
* for the truncation at the first time (which is correct):
* 

fnstcw -22(%ebp)        
movw -22(%ebp),%ax
orw $3072,%ax
movw %ax,-24(%ebp)
fldcw -24(%ebp)
fistpll -32(%ebp)
movl -32(%ebp),%ebx
movl -28(%ebp),%esi
fldcw -22(%ebp)
movl %ebx,-32(%ebp)
movl %esi,-28(%ebp)

* 
*
* and at the second call :
*
* 
leal -52(%ebp),%esi
..
* here the firstcall to fprintf is processed
..
fnstcw -2(%esi)
movw -2(%esi),%ax
orw $3072,%ax
movw %ax,-4(%esi)
fldcw -4(%esi)
fistpll -12(%esi)
movl -12(%esi),%ebx
movl -8(%esi),%esi
* NOW %ESI HAS BEEN SPOILED WITH HIGH PART OF LONG LONG !
fldcw -2(%esi)
* AND THUS THE ABOVE INSTRUCTION ACCESSES RANDOM MEMORY
*  -> SEGMENTATION FAULT
movl %ebx,-64(%ebp)
movl %esi,-60(%ebp)


* 
* I can't figure out why (a) %esi is used as memory reference 
* for something
*  residing in the local frame...
* (b) the usage of a register for the higher part of a 64-bit int 
* doesn\'t
* always spill it for other operations (such as using it as a memory
* ref.)
*/
/*  Thank you

Has This Bug been fixed in 2.95.1 ?
*/




More information about the Gcc-bugs mailing list