[comp.sys.mips] compiler bug

dwl@mercury.udev.cdc.com (Daren W Latham) (03/06/90)

I have just run across what I believe is a bug in the C compiler.  It doesn't
matter if optimization is turned on or not.  This program works correctly with
other C compilers.  Does anybody (mips perhaps) know if this bug is documented,
or just what the status of this is.  I am running on:

  RC2030: MIPS R2000A Processor Chip, Revision 2.0
          MIPS R2010A VLSI Floating Point Chip Revision: 2.0
          RISC/os Release 4.10 mips Version UMIPS

and on a

  M2000: MIPS R3000 Processor Chip, Revision 2.0
         MIPS R3010 VLSI Floating Point Chip Revision: 2.0
         RISC/os Release 4_0 mips Version UMIPS

--
Daren W. Latham                        | <dwl@udev.cdc.com>
Control Data Corporation               | (612)482-3457
Arden Hills, MN                        |

/*  sample program to show compiler bug
 *
 *  Note that the first printf displays a value of 10 and the second
 *  printf correctly displays a value of 13 for 5+8.
 *
 *  It doesn't make a difference if optimization is turned on or off.
 *
 */

#include <stdio.h>

#define  PushArg(n)              argStack[argStackP++] = n
#define  PopArg()                argStack[--argStackP]

main()
{
  int  argStack[10];
  int  argStackP = 0;
  int  temp;

  PushArg(5);
  PushArg(8);

  temp = PopArg() + PopArg();

  printf ("temp = %d \n", temp);

  PushArg(5);
  PushArg(8);

  temp = PopArg();

  temp += PopArg();

  printf ("temp = %d \n", temp);
}

rex@mips.COM (Rex Di Bona) (03/06/90)

In article <18302@shamash.cdc.com> dwl@mercury.udev.cdc.com (Daren W Latham) writes:
>I have just run across what I believe is a bug in the C compiler.  It doesn't
>matter if optimization is turned on or not.  This program works correctly with
>other C compilers.  Does anybody (mips perhaps) know if this bug is documented,
>or just what the status of this is.  I am running on:

This is not a "bug". What you have done is illegal under `standard' C.
You have two side effects in the one line that refer to the same variable.
This usually gives "undefined" results, and is a common source of errors.
This is because the order in which the side effects are done in relation
to the rest of the code is undefined.

Reference:
	"K&R Section 2.12" (Both first, and second (ansi) editions)

>#define  PushArg(n)              argStack[argStackP++] = n
>#define  PopArg()                argStack[--argStackP]
>
>main()
>{
>  int  argStack[10];
>  int  argStackP = 0;
>  int  temp;
>
>  PushArg(5);
>  PushArg(8);
>
>  temp = PopArg() + PopArg();

This is the line in question.

This is it after the preprocessor is done with it.

   temp = argStack[--argStackP] + argStack[--argStackP]

The compiler produces the following for this line:
(non optimised)

 #  24    temp = PopArg() + PopArg();
        addu    $13, $12, -1
        sw      $13, 28($sp)
        addu    $14, $13, -1
        sw      $14, 28($sp)
        mul     $15, $14, 4
        addu    $24, $sp, $15
        lw      $24, 32($24)
        addu    $25, $24, $24
        sw      $25, 24($sp)

The compiler has decided to do the two decrements first
(this is legal) and has then removed the second lookup
in the array to save a multiply. It has finally done the addition.

>
>  printf ("temp = %d \n", temp);
>
>  PushArg(5);
>  PushArg(8);
>
>  temp = PopArg();
>
>  temp += PopArg();
>
>  printf ("temp = %d \n", temp);
>}

The second version forces the two decrements to be done in
the order you expected. The side effects have to be completed
before the next line is executed, and so you get both elements.

I hope this helps.

				Rex.
-- 
Rex di Bona		Penguin Lust is NOT immoral!
rex@mips.com		apply STD disclaimers here.

rogerk@servitude.mips.com (Roger B.A. Klorese) (03/10/90)

(I've been asked by Frank Yellin to post this reply, since his followup
hasn't made it off Lucid's machines.)
-----
Newsgroups: comp.sys.mips
Subject: Re: compiler bug
Summary: 
Expires: 
References: <18302@shamash.cdc.com> <36721@mips.mips.COM>
Sender: 
Reply-To: fy@sunvalleymall.UUCP (Frank Yellin)
Followup-To: 
Distribution: 
Organization: Lucid, Inc., Menlo Park, CA
Keywords: 

In article <18302@shamash.cdc.com> dwl@mercury.udev.cdc.com (Daren W Latham)
writes that the following doesn't compile correctly.
>#define  PushArg(n)              argStack[argStackP++] = n
>#define  PopArg()                argStack[--argStackP]
>
>main()
>{
>  int  argStack[10];
>  int  argStackP = 0;
>  int  temp;
>
>  PushArg(5);
>  PushArg(8);
>
>  temp = PopArg() + PopArg();
> }

and in article <36721@mips.mips.COM> rex@mips.COM (Rex Di Bona) replies


> The compiler has decided to do the two decrements first
> (this is legal) and has then removed the second lookup
> in the array to save a multiply. It has finally done the addition.

In the Second Edition of "C: A Reference Manual" by Harbison and Steele,
they write (p. 190), 

    When evaluating the actual arguments in a function call, the order in
    which the arguments are evaluated is not specified; but the program
    must behave as if it chose one argument, evaluated it fully, then chose
    another argument, evaluated it fully, and so on. . . .

    A similar restring holds for binary operators:  The two operands may be
    evaluated in either order, but the program must behave as if one of the
    two operands were evaluated completely before commencement of the 
    evaluation of the second operand.

    [In] the original description of C. . . . the matter of interleaving
    was not discussed. . . .  We advise implementors to adhere rigidly to
    the restrictions outlined here (which actually are quite sensible and
    not terribly restrictive).   We also advice programmers not to exploit
    these restrictions too cleverly. . . .  The entire purpose of the
    restrictions is to make the behavior of the program more understandable.

I don't know whether Harbison and Steele is considered authoritative, but
they certainly would consider the MIPS implementation to be incorrect.

-- Frank Yellin
   fy@lucid.com
   
  
---
ROGER B.A. KLORESE      MIPS Computer Systems, Inc.      phone: +1 408 720-2939
MS 4-02    928 E. Arques Ave.  Sunnyvale, CA  94086             rogerk@mips.COM
{ames,decwrl,pyramid}!mips!rogerk                                 "I'm the NLA"
"Two guys, one cart, fresh pasta... *you* figure it out." -- Suzanne Sugarbaker

chris@mimsy.umd.edu (Chris Torek) (03/10/90)

In article <36884@mips.mips.COM> rogerk@servitude.mips.com
(Roger B.A. Klorese) writes for fy@sunvalleymall.UUCP (Frank Yellin):
>... the Second Edition of "C: A Reference Manual" by Harbison and Steele

[recommends against `interleaving' expression evaluation the way the MIPS
compiler did for `result = a[--i] + a[--i]'], then:

>I don't know whether Harbison and Steele is considered authoritative, but
>they certainly would consider the MIPS implementation to be incorrect.

The new authority is the ANSI standard (X3.159); it allows the MIPS
implementation.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

davecb@yunexus.UUCP (David Collier-Brown) (03/11/90)

>In article <18302@shamash.cdc.com> dwl@mercury.udev.cdc.com (Daren W Latham)
>writes that the following doesn't compile correctly.
>>#define  PushArg(n)              argStack[argStackP++] = n
>>#define  PopArg()                argStack[--argStackP]
>>
[...]
>>  temp = PopArg() + PopArg();
>> }

  Erk!  That expands to 
	temp = argStack[--argStackP] + argStack[--argStackP];
for which a legal archaic (K&R) interpretation is
	(argStackP -= 2, temp = argStack[argStackP] + argStack[argStackP]);

  In other words, because there are no ";"s in the expression, it's subject
to having the addressing operations either pulled to the front (unusual,
admittedly) or delayed to the end of the expression (common if they're
postfix ++'s). The old rule-of-the-thumb was "anything that doesn't contain
a semicolon can be reordered", and several compilers happily did so, typically
to avoid generating **horrible** sequences for b[a++] that looked like
	load a,R1
	increment R1
	store R1,a
	decrement R1
	load address b,R2
(I'll give you three guesses about who's machine needed this optimization).

  The ANSI interpretation is substantially similar, if stated and reasoned
about quite differently...


--dave
-- 
David Collier-Brown,  | davecb@yunexus, ...!yunexus!davecb or
72 Abitibi Ave.,      | {toronto area...}lethe!dave 
Willowdale, Ontario,  | Joyce C-B:
CANADA. 416-223-8968  |    He's so smart he's dumb.

seanf@sco.COM (Sean Fagan) (03/14/90)

In article <36884@mips.mips.COM> rogerk@servitude.mips.com (Roger B.A. Klorese) writes:
>>#define  PushArg(n)              argStack[argStackP++] = n
>>#define  PopArg()                argStack[--argStackP]
>>  temp = PopArg() + PopArg();
>    When evaluating the actual arguments in a function call, the order in
>    which the arguments are evaluated is not specified; but the program
>    must behave as if it chose one argument, evaluated it fully, then chose
>    another argument, evaluated it fully, and so on. . . .

Uhm, I don't see a function call there.  I see to macros which are expanded.

If you are going to continue this, please move it to comp.lang.c, where it
belongs.  Please note that Chris Torek has already replied to this, and he
is considered a comp.lang.c.deity (right up there with Doug Gwyn and Henry
Spencer, right below Dennis Ritchie 8-)).

-- 

-----------------+
Sean Eric Fagan  | "Time has little to do with infinity and jelly donuts."
seanf@sco.COM    |    -- Thomas Magnum (Tom Selleck), _Magnum, P.I._
(408) 458-1422   | Any opinions expressed are my own, not my employers'.

diamond@jit345.swstokyo.dec.com (Norman Diamond) (01/23/91)

In article <1685@svin02.info.win.tue.nl> debra@svin02.info.win.tue.nl (Paul de Bra) writes:

>struct a { int b, int c } d , e ;
      should be  ;
>main()
>{
>  int f;
>  f = (d=e).b;
>}

After correcting your bug, I saw the same error message that you saw.
Actually it's inherited from BSD's pcc, which is probably inherited
from System III's pcc (because the last time I touched a System V
machine, its pcc-based compiler accepted this usage of ".").

In ANSI C, (d=e) is a perfectly legal non-lvalue value, therefore (d=e).b
is also a perfectly legal non-lvalue value.  (I would say rvalue but ANSI C
doesn't use this word, except for a dangling reference in the index.)

(d=e),d.b  also yields a perfectly legal non-lvalue value, so I would
agree with your suggestion that it should be equivalent.

In K&R-I, the left operand of "." had to be an lvalue.  Therefore, if your
vendor does not claim ANSI conformance, it might not be a compiler bug.
--
Norman Diamond       diamond@tkov50.enet.dec.com
If this were the company's opinion, I wouldn't be allowed to post it.

rogerk@mips.COM (Roger B.A. Klorese) (01/24/91)

In article <1991Jan23.031214.544@tkou02.enet.dec.com> diamond@jit345.enet@tkou02.enet.dec.com (Norman Diamond) writes:
>In ANSI C, (d=e) is a perfectly legal non-lvalue value, therefore (d=e).b
>is also a perfectly legal non-lvalue value.
>(d=e),d.b  also yields a perfectly legal non-lvalue value, so I would
>agree with your suggestion that it should be equivalent.
>
>In K&R-I, the left operand of "." had to be an lvalue.  Therefore, if your
>vendor does not claim ANSI conformance, it might not be a compiler bug.

And, of course, MIPS-C claims K&R-I compliance only.  This reference is
accepted in the new ANSI C compiler which is in beta test.  (Sorry, we
have a full complement of test sites, and are not accepting any more.)
It is accepted in the K&R mode of the 2.20 compilers as well, as of now;
we will check if this should be rejected.
-- 
ROGER B.A. KLORESE                                  MIPS Computer Systems, Inc.
MS 6-05    930 DeGuigne Dr.   Sunnyvale, CA  94086              +1 408 524-7421
rogerk@mips.COM         {ames,decwrl,pyramid}!mips!rogerk         "I'm the NLA"
"WAR: been there, done that... hated it."  -- QueerPeace/DAGGER chant