RS/6000 Optimizer breaks code -- suggestions?

jar@florida.eng.ileaf.com (Jim Roskind x5570)
Tue, 21 Aug 90 14:01:11 GMT

          From comp.compilers

Related articles
RS/6000 Optimizer breaks code -- suggestions? banshee@ucscb.ucsc.edu (1990-08-18)
RS/6000 Optimizer breaks code -- suggestions? jar@florida.eng.ileaf.com (1990-08-21)
Re: RS/6000 Optimizer breaks code -- suggestions? worley@compass.com (1990-08-24)
Re: RS/6000 Optimizer breaks code -- suggestions? daveg@near.cs.caltech.edu (1990-08-25)
Re: RS/6000 Optimizer breaks code -- suggestions? johnv@metaware.uucp (1990-08-27)
Re: RS/6000 Optimizer breaks code -- suggestions? johnv@metaware.com (1990-08-27)
Re: RS/6000 Optimizer breaks code -- suggestions? worley@compass.com (1990-08-29)
| List of all articles for this month |

Newsgroups: comp.compilers,comp.lang.c
From: jar@florida.eng.ileaf.com (Jim Roskind x5570)
In-Reply-To: banshee@ucscb.ucsc.edu's message of 18 Aug 90 05:41:50 GMT
Followup-To: comp.lang.c
Keywords: C, optimize, code, debug
Organization: Compilers Central
Date: Tue, 21 Aug 90 14:01:11 GMT

> This fragment of code breaks when the following function is inlined and
> the code is compiled with -O on a RS/6000. Question, why? Note that
> without -O everything works fine, even with the function inlined.


As with many optimizer related problems, you were simply lucky it worked
without optimization! You were slightly justified in your expectation,
but still luck was key!


> But -O kills it.
>
> tradd(b)
> union g {long xx; struct half yy;} *b;


Note that you define a tag "g" here. Note that any other union or struct
that "happens" to look like it does not have to *really* be implemented
identically, *UNLESS* you reuse the tag! (I assume you have defined
"half" somewhere else). If you have severely different expectations, you
should take them up with the ANSI C Committee, as I believe this is in
keeping with the standard.


> {
> b->yy.high &= 077777; /* WHY CAN'T I INLINE THIS? */
> }
>
> m_mult(a,b,c)
> struct mint *a,*b,*c;
> {
> long x;
> union {long xx; struct half yy;} sum;


Here you define another union, but you did *NOT* use the tag "g". As a
result, the compiler has the freedom to "optimize" the layout of these
distinct unions. *IF* you had simply said "union g sum;" you probably
would be safe (unless there was a real bug in the compiler). In the form
given here, all bets are off in terms of guarantees of compatibility of
the two union types. My guess is that the optimizing compiler realized
that you had declared a local union, and placed the elements individually
in a convenient place on the stack or in registers. A lot of folks use
unions to sneakily cast from one data type to another, but there are very
few guarantees that such attempts will work!


> int carry;
> int i,j;
> c->val=xalloc(a->len+b->len,"m_mult");
> sum.xx=0;
> for(i=0;i<b->len;i++)
> { carry=0;
> for(j=0;j<i+1;j++)
> {
> sum.xx += (a->val[j])*(b->val[i-j]);
> if (sum.yy.high & 0100000) {
> tradd(&sum);


The above statement could have given you a warning that the type of
the argument that you passed to "tradd" was different from the
"expected" type for an argument. However, since you did *NOT*
prototype the function (and the above old style definition for "tradd"
does *NOT* constitute a prototype) the compiler simply looked the
other way. In fact, you could have said "tradd(3.14259)" and it would
not have complained :-(.


> /* sum.yy.high &= 077777; */
> carry += 1;
> }
> c->val[i]=sum.yy.low & 077777;
> sum.xx=sum.xx >> 15;
> sum.yy.high=carry;
> etc etc etc




Moral of the story:


1) Use function prototypes and the compiler would have given you an
error message, rather than a subtle bug.


2) Avoid the use of casts. Avoid the use of unions to hide the
fact that you were wanted to use casts.


3) Optimizers are pretty clever.


4) If you define the same value twice in a program, you are asking for
trouble. Generally such redefinitions get out of sync. Even if they
"look the same", they might not be. It is better to work to reuse a
single definition. This was an interesting extreme example of two
definitions "looking the same".


5) This was really a comp.lang.c question, but it shows just how far
good optimizers can go. It is their job to assume as much as the law
(standard) allows, and not one bit more. In this case, they followed
the law, and your code, which lived outside the law, broke.




Jim Roskind
Independent Consultant
(407)729-4348 or (617)577-9813 x5570
jar@hq.ileaf.com or ...!uunet!leafusa!jar
[Actually, my reading of the standard implies pretty strongly that all
similar definitions of a union be equivalent, but it explicitly says that
the behavior when you store one element in a union and read back another is
in almost all cases undefined. Jim's point that an optimizer often breaks
programs that depend on semantics not guaranteed by the language is a good
one. -John]
--


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.