This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

bug-report



/*  Dear member of the GCC society,
* 
*  compiling this code on a i386-compatible linux with
* 
*   gcc --version = 2.95
* 
* and simple (-O2) optimization
* 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.
*
*
* I would be glad if you could send me a fix.
*	A. Salathe
*/


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

#include <math.h>
#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 ipowl( 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 ipowl( 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 first call 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!
*/



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]