Subject: Error in gcc version 2.96 20000731

From: Kjeld Borch Egevang <[email-masked]>
Date: Thu, 13 Sep 2001 16:15:10 +0200

Hi all.

I discovered an optimization error in the current gcc for MIPS.

When I compile the code below with -O2 it clears the code-field just 
after setting it. The instructions are mixed up. It works fine with -O1 
and -O0.

If the "//" is removed in front of the first printf, it works too.

/Kjeld

--------------- cut here -----------------
#include <stdio.h>

typedef struct rtx_def
{
 short code;
 int dummy;
} rtx;

void put_code (rtx *rt, short code)
{
 register int length;

 length = 1;
 for (; length >= 0; length--)
   ((int *) rt)[length] = 0;

 // printf("put_code before\n");
 rt->code = code;
 printf("put_code after, code=%d %d\n", code, rt->code);
}

int main()
{
 rtx rt;

 put_code(&rt, 5);
 printf("gen_rtx, code=%d\n", rt.code);
}
--------------- cut here -----------------

The assembler looks like:

       .rdata
       .align  2
$LC0:
       .ascii  "put_code after, code=%d %d\n\000"
       .text
       .align  2
       .globl  put_code
       .ent    put_code
       .type    put_code,@function
put_code:
       .frame  $sp,32,$31              # vars= 0, regs= 2/0, args= 16, 
extra= 8
       .mask   0x90000000,-4
       .fmask  0x00000000,0
       .set    noreorder
       .cpload $25
       .set    reorder
       subu    $sp,$sp,32
       .cprestore 16
       move    $2,$5
       sll     $2,$2,16
       sra     $2,$2,16
       move    $5,$2
       la      $3,$LC0
       sw      $31,28($sp)
       sw      $28,24($sp)
       move    $6,$5
       sh      $2,0($4)     <----- sets code field
       sw      $0,4($4)     <----- clears structure
       sw      $0,0($4)     <----- clears structure
       move    $4,$3
       la      $25,printf
       jal     $31,$25
       lw      $31,28($sp)
       #nop
       .set    noreorder
       .set    nomacro
       j       $31
       addu    $sp,$sp,32
       .set    macro
       .set    reorder

       .end    put_code

---

From: "H . J . Lu" <[email-masked]>
Date: Thu, 13 Sep 2001 08:10:40 -0700

> If the "//" is removed in front of the first printf, it works too.

The code isn't ISO C. You cannot declare something as short and then
access it as int. On x86:

# gcc alias.c -O
put_code after, code=5 5
gen_rtx, code=5
# gcc alias.c -O2
put_code after, code=5 0
gen_rtx, code=0

On mips,

# gcc alias.c -O
put_code after, code=5 5
gen_rtx, code=5
# gcc alias.c -O2
put_code after, code=5 5
gen_rtx, code=0

You can fix the code or add -fno-strict-aliasing

# gcc alias.c -O2 -fno-strict-aliasing
put_code after, code=5 5
gen_rtx, code=5

H.J.

---

From: "Maciej W. Rozycki" <[email-masked]>
Date: Thu, 13 Sep 2001 17:14:45 +0200 (MET DST)

> I discovered an optimization error in the current gcc for MIPS.

 Is 2.96 20000731 current?  I thought 3.0.1 is.

> after setting it. The instructions are mixed up. It works fine with -O1 

 Use "-fno-strict-aliasing"?

> If the "//" is removed in front of the first printf, it works too.

 Why don't you use memset() to clear the struct in the first place?

-- 
+  Maciej W. Rozycki, Technical University of Gdansk, Poland   +
+--------------------------------------------------------------+
+        e-mail: [email-masked], PGP key available        +

---

From: "H . J . Lu" <[email-masked]>
Date: Thu, 13 Sep 2001 08:16:45 -0700

>  Is 2.96 20000731 current?  I thought 3.0.1 is.

gcc 3.0.1 lacks many patches in my gcc 2.96 and gcc 3.x. I am trying to
get them backported to 3.0.x.

H.J.

---

From: "Kjeld Borch Egevang" <[email-masked]>
Date: Thu, 13 Sep 2001 22:47:25 +0200

Thanks for your reply.

I was trying to port SPEC CPU 2000 (benchmarks), and one of the tests
failed. I boiled it down to the attached program. For performance reasons it
could be perfectly valid not to use memset(), but I agree that the code
looks a bit odd.

/Kjeld

---

From: "Kjeld Borch Egevang" <[email-masked]>
Date: Thu, 13 Sep 2001 23:09:04 +0200

Perhaps I don't get you point, but I get the same with:

int main()
{
  rtx rt;

  put_code(&rt, (short)5);
  printf("gen_rtx, code=%d\n", (int)rt.code);
}

/Kjeld

-----Original Message-----
From: [email-masked]
[mailto:[email-masked]]On Behalf Of H . J . Lu
Sent: 13. september 2001 17:11
To: Kjeld Borch Egevang
Cc: [email-masked]
Subject: Re: Error in gcc version 2.96 20000731

# gcc alias.c -O
put_code after, code=5 5
gen_rtx, code=5
# gcc alias.c -O2
put_code after, code=5 0
gen_rtx, code=0

On mips,

# gcc alias.c -O
put_code after, code=5 5
gen_rtx, code=5
# gcc alias.c -O2
put_code after, code=5 5
gen_rtx, code=0

H.J.

---

From: "H . J . Lu" <[email-masked]>
Date: Thu, 13 Sep 2001 14:14:54 -0700

>   printf("gen_rtx, code=%d\n", (int)rt.code);

That is not what I meant. You have

typedef struct rtx_def
{
  short code;
  int dummy;
} rtx;
 
The first field of rtx_def is short.

But you access it as int. If you do

  for (; length >= 0; length--)
    ((short *) rt)[length] = 0;

It will be ok.

H.J.

---

From: "Kjeld Borch Egevang" <[email-masked]>
Date: Thu, 13 Sep 2001 23:22:46 +0200

I get your point. A bit suprising though. Do you consider it a bug?

/Kjeld

-----Original Message-----
Sent: 13. september 2001 23:15

typedef struct rtx_def
{
  short code;
  int dummy;
} rtx;

It will be ok.

H.J.

---

From: "H . J . Lu" <[email-masked]>
Date: Thu, 13 Sep 2001 14:26:00 -0700

> I get your point. A bit suprising though. Do you consider it a bug?

It is an alias bug in your example.

H.J.

---

From: "Maciej W. Rozycki" <[email-masked]>
Date: Fri, 14 Sep 2001 16:42:46 +0200 (MET DST)

> could be perfectly valid not to use memset(), but I agree that the code

 With a high optimization level and a constant size of the area to set
(you'd likely use sizeof here, which is constant) gcc will happily inline
a memset() yielding no worse performance but no bugs and better
readability.  You may have no loop at all as the result.  Check yourself!