Bug 12108 - gcc tries to skip asm() with comiclr
Summary: gcc tries to skip asm() with comiclr
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 3.3.2
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2003-08-30 09:57 UTC by anton
Modified: 2005-07-23 22:49 UTC (History)
1 user (show)

See Also:
Host: hppa-linux
Target: hppa-linux
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description anton 2003-08-30 09:57:49 UTC
The 3.3.2 version is the one distributed with Debian.

Also shows up on gcc-3.2 on hppa2.0n-hp-hpux11.00, but not on
gcc-2.95.2 on hppa2.0n-hp-hpux11.00, nor on a number of non-hppa
platforms.

Command line:

gcc -o conftest -g -O2 conftest.c -L/lib/pa1.1/

conftest.c is:

int foo(int);
main()
{
  exit(foo(0)!=16);
}
int foo(int x)
{
  if (x) {
  label1:
    asm(".skip 16"); /* or ".space 16" or somesuch */
  label2:
  }
  return (&&label2)-(&&label1);
}

(The purpose of this program is a test for autoconf: test if .skip
works as we expect).

This program crashes, because the code in the asm statement is
executed even though x is 0.

A small variation is to insert some code before label1:

int foo(int);
main()
{
  exit(foo(0)!=16);
}
int y;
int foo(int x)
{
  if (x) {
    y++;
  label1:
    asm(".skip 16"); /* or ".space 16" or somesuch */
  label2:
  }
  return (&&label2)-(&&label1);
}

This time the program finishes, but produces the wrong result, because
(interpreting the disassembled code) "&&label1" is computed as if it was
placed before the "y++":

(gdb) disass foo
Dump of assembler code for function foo:
;;; File: conftest.c
;;;   if (x) {
0x2648 <foo>:   cmpib,= 0,%r26,0x266c <foo+36>
0x264c <foo+4>: addil L'0,%dp,%r1
;;;     y++;
0x2650 <foo+8>: ldw 0x20(%r1),%r19
0x2654 <foo+12>:        ldo 1(%r19),%r19
0x2658 <foo+16>:        stw %r19,0x20(%r1)
;;;     asm(".skip 16"); /* or ".space 16" or somesuch */
0x265c <foo+20>:        break 0,0
0x2660 <foo+24>:        break 0,0
0x2664 <foo+28>:        break 0,0
0x2668 <foo+32>:        break 0,0
;;;   return (&&label2)-(&&label1);
0x266c <foo+36>:        ldil L'0x2000,%ret0
0x2670 <foo+40>:        ldil L'0x2000,%r19
0x2674 <foo+44>:        ldo 0x650(%r19),%r19
0x2678 <foo+48>:        ldo 0x66c(%ret0),%ret0
;;; }
0x267c <foo+52>:        bv %r0(%rp)
0x2680 <foo+56>:        sub %ret0,%r19,%ret0
0x2684 <foo+60>:        break 0,0

I.e., &&label1 (%r19 at the end) is computed as 0x2650, but it should
be 0x265c.
Comment 1 Andrew Pinski 2003-08-30 13:47:44 UTC
I think the code is wrong because the asm is not marked as volatile so the schedular is free to 
move it around.
Can you try this:
int foo(int);
main()
{
  if(foo(0)!=16)
    abort();
}
int y;
int foo(int x)
{
  if (x) {
  label1:
    asm volatile (".skip 16"); /* or ".space 16" or somesuch */
  label2:
;
  }
  return (&&label2)-(&&label1);
}
Comment 2 anton 2003-08-30 17:20:51 UTC
Subject: Re:  wrong code generated in the presence of asm("...")

pinskia at gcc dot gnu dot org wrote:
> I think the code is wrong because the asm is not marked as volatile so the schedular is free to 
> move it around.

No: from the gcc manual (node Extended asm):

|   An `asm' instruction without any operands or clobbers (an "old
|style" `asm') will be treated identically to a volatile `asm'
|instruction.

> Can you try this:
> int foo(int);
> main()
> {
>   if(foo(0)!=16)
>     abort();
> }
> int y;
> int foo(int x)
> {
>   if (x) {
>   label1:
>     asm volatile (".skip 16"); /* or ".space 16" or somesuch */
>   label2:
> ;
>   }
>   return (&&label2)-(&&label1);
> }

Same result.

- anton
Comment 3 Andrew Pinski 2003-08-30 23:22:34 UTC
Marking as invalid to mark it as ...
Comment 4 Andrew Pinski 2003-08-30 23:23:44 UTC
unconfirmed.  I think this might have been fixed on the mainline though.  I also think this is the 
wrong way to test for an as feature.
Comment 5 Andrew Pinski 2003-08-30 23:24:01 UTC
unconfirmed.  I think this might have been fixed on the mainline though.  I also think this is the 
wrong way to test for an as feature.
Comment 6 Falk Hueffner 2003-09-11 20:45:18 UTC
I don't think gcc does, or should guarantee anything about the value of labels
except that jumping to them works. Can you provide a test case where a goto hits
the wrong place? Otherwise I don't think this is a bug.
Comment 7 anton 2003-09-12 11:37:50 UTC
Subject: Re:  wrong code generated in the presence of asm("...")

falk at debian dot org wrote:
> I don't think gcc does, or should guarantee anything about the value of labels
> except that jumping to them works. Can you provide a test case where a goto hits
> the wrong place? Otherwise I don't think this is a bug.

This bug exists independent of the labels stuff.  Even if I remove the
labels and all references to them, the faulting code is still the
same.  I.e., a conftest.c like this:

int foo(int);
main()
{
  exit(foo(0)!=16);
}
int foo(int x)
{
  if (x) {
    asm(".skip 16"); /* or ".space 16" or somesuch */
  }
  return 0;
}

still produces a SIGILL and the assembly code for foo looks like this:

foo
        .PROC
        .CALLINFO FRAME=0,NO_CALLS
        .ENTRY
        comiclr,= 0,%r26,%r0
        .skip 16
L$0003
        bv %r0(%r2)
        ldi 0,%r28
        .EXIT
        .PROCEND

Concerning a test case where the goto hits the wrong place: I have
played around with the second example (with "y++") a little, and it
seems that as soon as I insert a goto, the label corresponding to
label1 is produced in the right place.  This might be so by design,
but also by accident, so I feel a little nervous about relying on it.
In any case, a version that works (around the bug on hppa) is:

int foo(int,int,int);
main()
{
  exit(foo(0,0,0)!=16);
}
int y;
int foo(int x, int y, int z)
{
  static void *labels[]={&&label1,&&label2};
  if (x) {
    y++;
  label1:
    asm(".skip 16"); /* or ".space 16" or somesuch */
  label2: ;
  }
  {
  if (y) goto *labels[z];
  return labels[1]-labels[0];
  }
}

Whether gcc should guarantee something about the values of labels
beyond being able to goto there: There are a number of systems that
work by copying code between two labels (as-values) at run-time; e.g.,
Gforth, qemu and Tempo.  These systems require more than just being
able to goto labels.  gcc-2.95 provides for this on all platforms I
have tested.  I think future gccs should provide for it, too (maybe
requiring special flags like -fno-reorder-blocks, but certainly in one
way or the other).

- anton
Comment 8 Falk Hueffner 2003-09-12 12:48:52 UTC
I can reproduce this with the same compiler version on hppa. This seems to be
target specific; gcc thinks it can skip an asm with comiclr, but it can't,
because an asm might be more than one instruction. I have no current 3.4 or 3.3,
so I'll leave it unconfirmed for now.
Comment 9 Andrew Pinski 2003-10-05 17:07:27 UTC
This is documented as correct behavior now, see <http://gcc.gnu.org/onlinedocs/gcc/
Extended-Asm.html#Extended%20Asm>, Size of an asm, there is a new patch to say that 
it might create silent bad code that has not been commited yet.