[comp.std.c] Unary plus

michi@ptcburp.ptcbu.oz.au (Michael Henning) (03/26/91)

In my copy of Harbison & Steele (1987) is a section about the unary plus
operator in ANSI-C.
It basically states that the unary plus operator may be used to force
a particular order of evaluation. H & S quote an example:

If x and y are floating point variables, the expressions

	((x+y)-x)-y
and
	(x+y)-(x+y)

do not necessarily give the same result (or zero, for that matter) because
the order of evaluation is undefined. The go on to say that to force
evaluation order as indicated by the brackets in the first expression,
one may write

	+((+(x+y))-x)-y

In my copy of the ANSI-C standard (X3J11/90-013, Feb 14th, 1990), I could
not find any mention of this behaviour, so I assume that it was dropped from
the standard after H & S published the book. Is this correct ?

Which brings me to my next question...

If I want to enforce evaluation order by assigning to temporary variables, e.g.

	tmp = x + y;
	tmp -= x;
	tmp -= y;
	result = tmp;

is it necessary to declare tmp as volatile to prevent the optimizer from
optimizing tmp out of existence ?  Or are there some rules that say that the
optimizer should not get rid of tmp in this case ?

Similar problems occur if union fields of different sizes and/or types
are to be assigned to each other. For example, given

	union {
		int	i;
		double	d;
	} u;

the behaviour of the assignment

	u.i = (int) u.d;

is undefined, because the storage area for i and d overlap, and i and d have
different types. If I instead write

	tmp = (int) u.d;
	u.i = tmp;

is it necessary to declare tmp as volatile to tell the optimizer not to
get rid of it ?

					Any help greatly appreciated,

						Michi.
-- 
      -m------- Michael Henning			+61 75 950255
    ---mmm----- Pyramid Technology		+61 75 522475 FAX
  -----mmmmm--- Research Park, Bond University	michi@ptcburp.ptcbu.oz.au
-------mmmmmmm- Gold Coast, Q 4229, AUSTRALIA	uunet!munnari!ptcburp.oz!michi

henry@zoo.toronto.edu (Henry Spencer) (03/27/91)

In article <370@ptcburp.ptcbu.oz.au> michi@ptcburp.ptcbu.oz.au (Michael Henning) writes:
>In my copy of Harbison & Steele (1987) is a section about the unary plus
>operator in ANSI-C.
>It basically states that the unary plus operator may be used to force
>a particular order of evaluation...

That was based on an obsolete ANSI draft.  Unary plus no longer does
any such thing.

>If I want to enforce evaluation order by assigning to temporary variables...

No longer necessary, actually.  ANSI C says that order of evaluation is as
written in the expression, unless the compiler can be sure that changing
it will have no visible effect.

>	u.i = (int) u.d;

Now, on this one you do have to go via a temporary.

>	tmp = (int) u.d;
>	u.i = tmp;
>
>is it necessary to declare tmp as volatile to tell the optimizer not to
>get rid of it ?

No need; you don't care whether the optimizer gets rid of it.  You have
satisfied the language rules, and the optimizer should not be making
changes unless it knows it is safe.
-- 
"[Some people] positively *wish* to     | Henry Spencer @ U of Toronto Zoology
believe ill of the modern world."-R.Peto|  henry@zoo.toronto.edu  utzoo!henry

keie@cs.vu.nl (Keizer E G) (03/27/91)

michi@ptcburp.ptcbu.oz.au (Michael Henning) writes:

>In my copy of Harbison & Steele (1987) is a section about the unary plus
>operator in ANSI-C.
>It basically states that the unary plus operator may be used to force
>a particular order of evaluation. H & S quote an example:

>If x and y are floating point variables, the expressions

>	((x+y)-x)-y
>and
>	(x+y)-(x+y)

>do not necessarily give the same result (or zero, for that matter) because
>the order of evaluation is undefined. The go on to say that to force
>evaluation order as indicated by the brackets in the first expression,
>one may write

>	+((+(x+y))-x)-y

>In my copy of the ANSI-C standard (X3J11/90-013, Feb 14th, 1990), I could
>not find any mention of this behaviour, so I assume that it was dropped from
>the standard after H & S published the book. Is this correct ?

Yes. The `special' effect that a unary plus enforced evaluation order has
disappeared. You have to make a difference between evaluation order
and the re-ordering of the expression. The current Standard allows
any evaluation order but restricts re-ordering with the as-if rule.
To illustrate the point:
	( x1 + y1 ) * ( x2 + y2 )
The Standard does not state in which order the additions "x1+y1" and
"x2+y2" have to be done. The only way in which this could affect
the result is when one of x1, x2, y1 and y2 produce side effects.
The best way to see this is by viewing the expression as a tree.
The compiler is allowed to compute the leaves and perform the operations
in any order as long as the expression tree itself is not changed.
That is you have to evaluate x1 and y1 before adding them, x2 and y2
before adding them and perform the multiplication only after the result
from additions is known.
To confuse the matter a bit I have to state that the compiler can
actually use any which way to calculate the expression, as long as the result
(including possible overflow) is a result that is possible under the
rules stated above. The reason for this is that nobody could tell
the difference (as long as they are not reading the code produced).
For floating point expressions all this means that the programmer can
assume the a conforming compiler will not fiddle with his expressions.

>Which brings me to my next question...

>If I want to enforce evaluation order by assigning to temporary variables, e.g.

>	tmp = x + y;
>	tmp -= x;
>	tmp -= y;
>	result = tmp;

>is it necessary to declare tmp as volatile to prevent the optimizer from
>optimizing tmp out of existence ?  Or are there some rules that say that the
>optimizer should not get rid of tmp in this case ?

No, it is not necessary to declare tmp as volatile. In fact as stated
above this way of calculating the result only makes sense if x or y
produce side-effects.

I refrain from giving an answer to your third question.

Ed Keizer

bhoughto@hopi.intel.com (Blair P. Houghton) (03/27/91)

In article <370@ptcburp.ptcbu.oz.au> michi@ptcburp.ptcbu.oz.au (Michael Henning) writes:
>If I want to enforce evaluation order by assigning to temporary variables, e.g.
>
>	tmp = x + y;
>	tmp -= x;
>	tmp -= y;
>	result = tmp;
>
>is it necessary to declare tmp as volatile to prevent the optimizer from
>optimizing tmp out of existence ?  Or are there some rules that say that the
>optimizer should not get rid of tmp in this case ?

Yes.  The result has to be the one expressed.  The optimizer
would be broken if it produced a result different from the
one obtained with `tmp' intact.

Optimization is moot, always, when the Standard is concerned.
The only time things are undefined is when the Standard says
they are undefined.  If your optimizer produces code that
operates otherwise, then your implementor is not telling you
the truth about conforming to the Standard.

				--Blair
				  "Moot."

P.S. However, if it can guarantee, through correct order of evaluation,
that this would give the same result:

	copy x to result;
	add y to result;
	subtract x from result;
	subtract y from result

then it's free never to allocate storage for tmp.

In fact, if it's capable of guaranteeing that the types
you've selected for x, y, result, _and_ tmp mean that the
result _is_ guaranteed to be zero (e.g., unsigned short
x,y; signed long tmp,result; enough bits in long to hold
short*short), then it may simply do

	result = 0;

or even nothing, if it can further determine that result==0
produces no effect that just 0 couldn't produce.

I.e., if you use the temporary variable, the answer
has to be the one the syntax implies, not the one that
possible optimizations might imply.

Orders of evaluation are often undefined; so optimization
is moot.  It's the syntax which says you're not being
explicit.

I know this P.S. is longer than the body, but I like muddling
around in the moot; you meet an interesting class of moot-monster
in here...

gwyn@smoke.brl.mil (Doug Gwyn) (03/28/91)

In article <370@ptcburp.ptcbu.oz.au> michi@ptcburp.ptcbu.oz.au (Michael Henning) writes:
>It basically states that the unary plus operator may be used to force
>a particular order of evaluation.

No, that was proposed in early drafts of the standard, but was dropped in
favor of requiring "honoring of parentheses" (a la Fortran) instead.

>If I want to enforce evaluation order by assigning to temporary variables, ...

Don't do that, use parentheses instead.
For finer-grained control you can use volatile, but that should not be
used merely to control subexpression evaluation order.