This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Bug in register allocation for long longÆ?ü^¹¥¨?
- To: <gcc-bugs at gcc dot gnu dot org>
- Subject: Bug in register allocation for long longÆ?ü^¹¥¨?
- From: asal at freesurf dot ch
- Date: Sat, 23 Oct 1999 00:41:25 +0100
- Cc: <asal at freesurf dot ch>
/* 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 ?
*/