[gnu.g++.bug] Optimisation problems when using const

T.Day@ucl-cs.UUCP (12/19/89)

From: Tim Day <T.Day@uk.ac.ucl.cs>


+-----------------------------------------------------------------------------+
Tim Day                           | Meet every second in life as challenge;
Department of Photogrammetry      | Respond fully to whatever happens
UCL, Gower St., London  WC1E 6BT  |  without anxiety, or complaint, or clinging
+-----------------------------------------------------------------------------+
// Hope you can handle this... I like it       W            I                D               E
//
// I recently got around to putting some consts in my Vector3 class
// .. which promply broke.  This used to work fine before
// I added the consts.  Am I using them right ?  I get no errors from compiler
//
// Compiled with g++ (-v gcc version 1.36.1 (based on GCC 1.36)) on Sun3, OS4.something>0
// g++ -m68020 -m68881 -O -fdefault-inline -finline-functions -fstrength-reduce -fomit-frame-pointer vector.cc -o vector
// Problem described in main() at end
// g++ -m68020 -m68881 -g vector.cc -o vector works OK... some kinda optimisation bug
// Also works fine if you #define const /* */

#include <stream.h>


	typedef void Void;
	typedef char Char;
	typedef short Short;
	typedef int Int;
	typedef long Long;
	typedef float Float;
	typedef double Double;

	typedef unsigned char UnsignedChar;
	typedef unsigned short UnsignedShort;
	typedef unsigned int UnsignedInt;
	typedef unsigned long UnsignedLong;

	typedef Int Boolean;

	typedef ostream Ostream;
	typedef istream Istream;

class Vector3
{
	Double component[3];
public:
	Void x(Double x)					{component[0]=x;}
	Void y(Double y)					{component[1]=y;}
	Void z(Double z)					{component[2]=z;}
	Void c(Int c,Double m)					{component[c]=m;}
	Double x() const 					{return component[0];}
	Double y() const 					{return component[1];}
	Double z() const					{return component[2];}
	Double c(Int n)	const					{return component[n];}

	Vector3(Double a=0.0,Double b=0.0,Double c=0.0)		{x(a);y(b);z(c);}
	Vector3(const Vector3 &p)				{x(p.x());y(p.y());z(p.z());}

	Void operator+=(const Vector3 &p)			{x(x()+p.x());y(y()+p.y());z(z()+p.z());}
	Void operator-=(const Vector3 &p)			{x(x()-p.x());y(y()-p.y());z(z()-p.z());}
	Void operator*=(Double a)				{x(a*x());y(a*y());z(a*z());}	// Problem in here
													
	Void operator/=(Double a) 				{(*this)*=(1.0/a);}

	Double magnitude2() const				{return x()*x()+y()*y()+z()*z();}		
	Double magnitude() const				{return sqrt(magnitude2());}
	Void normalise()					{(*this)*=(1.0/magnitude());}
	Vector3 normalised() const;

};

inline Vector3 Vector3::normalised() const			return r(*this);{r.normalise();}

inline Vector3 operator+(const Vector3 &p,const Vector3 &q)	return r(p);{r+=q;}
inline Vector3 operator-(const Vector3 &p,const Vector3 &q)	return r(p);{r-=q;}
inline Vector3 operator-(const Vector3 &p)			{return Vector3(-p.x(),-p.y(),-p.z());}
inline Vector3 operator*(Double a,const Vector3 &p)		return r(p);{r*=a;}
inline Vector3 operator*(const Vector3 &p,Double a)		return r(p);{r*=a;}
inline Vector3 operator/(const Vector3 &p,Double a)		return r(p);{r/=a;}
inline Boolean operator==(const Vector3 &p,const Vector3 &q)	{return (p.x()==q.x() && p.y()==q.y() && p.z()==q.z());}
inline Boolean operator!=(const Vector3 &p,const Vector3 &q)	{return (p.x()!=q.x() || p.y()!=q.y() || p.z()==q.z());}

inline Double operator&(const Vector3 &p,const Vector3 &q)	{return p.x()*q.x()+p.y()*q.y()+p.z()*q.z();}	/* Dot product */
inline Vector3 operator*(const Vector3 &p,const Vector3 &q)	{return Vector3(p.y()*q.z()-p.z()*q.y(),	/* Cross product */
										p.z()*q.x()-p.x()*q.z(),
										p.x()*q.y()-p.y()*q.x()
										);
								}

Istream& operator>>(Istream &i,Vector3 &v)			{Double x,y,z;if (i>>x && i>>y && i>>z) v=Vector3(x,y,z);return i;}
Ostream& operator<<(Ostream &o,const Vector3 &v)		{o << v.x() << " " << v.y() << " " << v.z();return o;}

Void foo(const Vector3 &t)	{cout << t << "\n";}

main()
{	Vector3 t(1.0,1.0,1.0);
	t*=10.0;		
	cout << t << "\n";	// Outputs 10 1 10 on Sun3, (OK on Sun4)
	foo(t);			// But foo output 10 10 10 !
	exit(0);
}

// Looking at the assembler output reveals...
// That the first ``cout<<'' is all mixed up with the multiplies, whereas the call to foo
// operates on the finished result.  I can't follow the inlined cout<< stuff enough to work out what's happening.
// The constructors are inline, but don't call inline versions of x(), y() (irrelevant  to this problem)

// Putting some cerr<<s into operator*= seems to indicate that y() has the right value
// after y(a*y()), but then gets clobbered by z()... but something more subtle
// must be going on as it contains the right value for the call to foo.