[comp.lang.c] Using distributive property to optimize.

clp@altos86.Altos.COM (Chuck L. Peterson) (02/03/90)

We just noticed that this old 286 XENIX compiler we have floating
around changes the statement:
	n = a - (b + c);
To this:
	n = a - b - c;

Anyone know if it is valid for a C Compiler to do this?
The two will most certainly give different results when
dealing with overflow/underflow conditions.

Chuck L. Peterson
clp@altos.com

henry@utzoo.uucp (Henry Spencer) (02/06/90)

In article <229@altos86.Altos.COM> clp@altos86.Altos.COM (Chuck L. Peterson) writes:
>We just noticed that this old 286 XENIX compiler we have floating
>around changes the statement:
>	n = a - (b + c);
>To this:
>	n = a - b - c;
>
>Anyone know if it is valid for a C Compiler to do this?
>The two will most certainly give different results when
>dealing with overflow/underflow conditions.

The slightly fuzzy definition of overflow behavior in K&R1 could be read
to permit this.  Old C compilers usually just ignored the possibility of
overflow entirely, and rearranged expressions whenever they felt like it.
They got away with this, usually, because most C implementations didn't
do anything about overflow anyway, and 2's-complement arithmetic gives
the same answer either way.  (I assume we are talking about integers, not
floating point!)

ANSI C has tightened the rules a little.  Overflow behavior must not change
as the result of optimization.  Mind you, if the code you generate ignores
overflows, and if your machine's arithmetic is such that the result is the
same, then that isn't an issue and the rearrangement is still kosher.

(Note a very subtle fine point:  compilers that ignore the possibility of
overflow do not necessarily generate code that ignores overflows!  If
the machine remembers overflows (e.g. with an overflow condition-code bit),
tests on computed values can be sensitive to whether an overflow occurred
in the computation.  I found an example that did this with the original
pdp11 C compiler.  Generating code that truly ignores overflows on such
a machine requires that the compiler be aware of the issue.)
-- 
SVR4:  every feature you ever |     Henry Spencer at U of Toronto Zoology
wanted, and plenty you didn't.| uunet!attcan!utzoo!henry henry@zoo.toronto.edu

bengsig@oracle.nl (Bjorn Engsig) (02/06/90)

Article <229@altos86.Altos.COM> by clp@altos86.Altos.COM (Chuck L. Peterson) says:
[is it valid to change]
|	n = a - (b + c);
|To this:
|	n = a - b - c;
It was valid according to K&R 1.  It's not in ANSI.
-- 
Bjorn Engsig,	Domain:		bengsig@oracle.nl, bengsig@oracle.com
		Path:		uunet!{mcsun!orcenl,oracle}!bengsig

bs@linus.UUCP (Robert D. Silverman) (02/07/90)

In article <1020.nlhp3@oracle.nl> bengsig@oracle.nl (Bjorn Engsig) writes:
:Article <229@altos86.Altos.COM> by clp@altos86.Altos.COM (Chuck L. Peterson) says:
:[is it valid to change]
:|	n = a - (b + c);
:|To this:
:|	n = a - b - c;
:It was valid according to K&R 1.  It's not in ANSI.
 
Nor should it be. Floating point addition is NOT associative. Presumably
the programmer has a reason to group the computation the way he did.

Note also that even with integer arithmetic, the rearrangement is not
safe. If (say) b is a large negative number and c a large positive
number a - (b+c) may not overflow. However, a-b most certainly can.

Compilers should NEVER rearrange computations.

-- 
Bob Silverman
#include <std.disclaimer>
Internet: bs@linus.mitre.org; UUCP: {decvax,philabs}!linus!bs
Mitre Corporation, Bedford, MA 01730

karl@haddock.ima.isc.com (Karl Heuer) (02/08/90)

In article <94348@linus.UUCP> bs@linus.UUCP writes:
>[is it valid to change "n = a - (b + c);" to "n = a - b - c;"]
>
>Note also that even with integer arithmetic, the rearrangement is not
>safe. If (say) b is a large negative number and c a large positive
>number a - (b+c) may not overflow. However, a-b most certainly can.

But if, as is common, the implementation chooses to handle signed integer
overflow by producing the unique representable value which is congruent modulo
UINT_MAX+1 to the true answer, then (a-b)-c will yield the same value as
a-(b+c).  (And if the variables are unsigned integers, then the rewrite is
valid on *all* implementations, because that's how unsigned arithmetic is
defined in C.)

>Compilers should NEVER rearrange computations.

As long as they get the right answer, they may; as long as it's a desirable
performance improvement, they should.

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint

chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) (02/13/90)

On 7 Feb 90 20:25:41 GMT,
karl@haddock.ima.isc.com (Karl Heuer) said:
I forget who> Compilers should NEVER rearrange computations.

Karl> As long as they get the right answer, they may; as long as it's a
Karl> desirable performance improvement, they should.


Agreed.  In the spirit of C, the compiler _should_, by default, have the
freedom to rearrange an expression (take advantage of distributivity, etc.).
However, there are times when you _really need_ to explicitly control the
order and means of evaluation.

Serious:
Anyone for casting an evaluation critical expressions to type "volatile"?
It's too late for ANSI C.  ISO C, perhaps?

Un-serious:
Then again, how about: extern "forth" ?  :-)

Just kidding!  See the smilies? -> :-) :-) :-) :-) :-) :-) :-) :-) :-) 
--
		Chuck Phillips -- chuckp%ncr-fc.FtCollins.NCR.COM
		                  uunet!ncrlnk!ncr-sd!chuckp%ncr-fc

karl@haddock.ima.isc.com (Karl Heuer) (02/15/90)

In article <CHUCKP.90Feb13065634@halley.ncr-fc.FtCollins.NCR.com> chuckp@ncr-fc.FtCollins.NCR.com (Chuck Phillips) writes:
>Agreed.  In the spirit of C, the compiler _should_, by default, have the
>freedom to rearrange an expression (take advantage of distributivity, etc.).
>However, there are times when you _really need_ to explicitly control the
>order and means of evaluation.

Please describe such a circumstance.  I believe that all such are covered by
the new ANSI C rules%, and hence there is no need for extensions like your
proposed "cast-to-volatile".

Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint
Followups to comp.lang.c only; this isn't really C++ related.
________
% Briefly, the rule is that the implementation is permitted to rearrange only
  through the grace of the as-if rule: i.e., only if the result obtained is
  indistinguishable from that of the abstract machine.  Lvalues with the
  "volatile" attribute must be loaded and stored as per the abstract machine.