[net.bugs.4bsd] integer op= floating evaluated incorrectly by C compiler

edhall@randvax.ARPA (Ed Hall) (01/11/84)

------------------------------------
This bug may affect all pre-5.0USG C compilers, and perhaps earlier
5.0USG compilers as well.  The below fix only works for PCC-derived
compilers (such as the BSD VAX C compiler).

Index:  usr.lib/ccom 4.2BSD 4.1BSD 3.0USG

Description:
	When assignement operators such as *= are used with an integer
	Left-Hand Side and a floating-point expression on the Right-
	Hand Side, results are incorrect.  For example:

		int i = 6;
		i *= .5;

	leaves a value of 0 in i, rather than 3.  The +=, -=, and /=
	operators are similarly affected.

Caused by:
	Conversion of RHS of assignment to type of LHS before application
	of the operator.

Fixed by:
	The fix is in two parts.  First, the automatic forcing of type
	conversion to the LHS of an assignment op must be shut off in
	appropriate circumstances.  This requires a change to tymatch()
	in mip/trees.c:

1031c1031,1035
< 	if( t != t2 || o==CAST ) p->in.right = makety( p->in.right, tu, 0, (int)tu );
---
> 	if( o==CAST || (t != t2
> 	  && ( (dope[o]&(FLOFLG|ASGOPFLG)) != (FLOFLG|ASGOPFLG)
> 	  || t != INT || (t2 != DOUBLE && t2 != FLOAT) )) ) {
> 		p->in.right = makety( p->in.right, tu, 0, (int)tu );
> 		}

	This causes certain assignment ops (+=, -=, *=, /=, i.e. the ones
	appropriate in floating-point) to remain in the parse tree without
	`balanced' operand types.  When these get to code-generation the
	compiler would break unless the template table had the proper pieces
	added to it.  Thus, in pcc/table.c:

712a713,729
>
> /* begin new stuff */
>
> ASG OPFLOAT,    INAREG|FOREFF|FORCC,
>       SAREG|AWD,      TWORD|TCHAR|TSHORT,
>       SAREG|AWD,      TDOUBLE,
>               NAREG,  RLEFT|RESCC,
>               "       cvtZLd  AL,A1\n OD2     AR,A1\n cvtdZL  A1,AL\n",
>
> ASG OPFLOAT,    INAREG|FOREFF|FORCC,
>       SAREG|AWD,      TWORD|TCHAR|TSHORT,
>       SAREG|AWD,      TFLOAT,
>               NAREG,  RLEFT|RESCC,
>               "       cvtZLf  AL,A1\n OF2     AR,A1\n cvtfZL  A1,AL\n",
>
> /* end new stuff */
>

	-Ed Hall
	Rand Corporation
	Santa Monica, CA
	decvax!randvax!edhall   (UUCP)
	edhall@rand-unix        (ARPA)

myunive@nsc.UUCP (Jay Zelitzky) (01/14/84)

..........
   Everyone has been missing another case where there is a problem:
   int /= unsigned; will do an integer divide instead of the correct
   unsigned divide.  This will result in a different value in some cases.
   For example:  (2^32-1)/2 will equal some large number if the division is
   done unsigned and 0 if the division is signed.  

   A slight variation of the previously posted fix will also fix this case.

					Jay Zelitzky
					{menlo70,fortune}!nsc!myunive

msc@qubix.UUCP (Mark Callow) (01/17/84)

Can we please close this seemingly endless discussion.  God (dmr) spoke
some weeks ago confirming that it is indeed a bug for x *= y to differ
from x = x * y.  What more is there to discuss except actual fixes
for various compilers?
-- 
From the Tardis of Mark Callow
msc@qubix.UUCP,  decwrl!qubix!msc@Berkeley.ARPA
...{decvax,ucbvax,ihnp4}!decwrl!qubix!msc, ...{ittvax,amd70}!qubix!msc