Bug 22127 - [3.4 Regression] register window not preserved after getcontext call
Summary: [3.4 Regression] register window not preserved after getcontext call
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 4.0.1
: P1 normal
Target Milestone: 4.0.3
Assignee: Eric Botcazou
URL:
Keywords: wrong-code
: 21957 (view as bug list)
Depends on:
Blocks:
 
Reported: 2005-06-20 16:34 UTC by akr
Modified: 2005-11-10 17:05 UTC (History)
3 users (show)

See Also:
Host: sparc-sun-solaris2.8
Target: sparc-sun-solaris2.8
Build: sparc-sun-solaris2.8
Known to work: 2.95.3
Known to fail: 3.3.2 3.4.4 4.0.0 4.0.1
Last reconfirmed: 2005-11-01 22:15:04


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description akr 2005-06-20 16:34:18 UTC
I found that following program loops infinitely on SPARC if it is optimized.

% uname -a
SunOS mule 5.8 Generic_108528-29 sun4u sparc SUNW,Ultra-80
% cat tst.i 
typedef unsigned int size_t;
extern int printf(const char *, ...);
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
typedef unsigned int uint_t;
typedef char *caddr_t;
typedef int greg_t;
typedef greg_t gregset_t[19];
struct rwindow {
 greg_t rw_local[8];
 greg_t rw_in[8];
};
typedef struct gwindows {
 int wbcnt;
 greg_t *spbuf[31];
 struct rwindow wbuf[31];
} gwindows_t;
struct fpu {
 union {
  uint32_t fpu_regs[32];
  double fpu_dregs[16];
 } fpu_fr;
 struct fq *fpu_q;
 uint32_t fpu_fsr;
 uint8_t fpu_qcnt;
 uint8_t fpu_q_entrysize;
 uint8_t fpu_en;
};
typedef struct fpu fpregset_t;
typedef struct {
 unsigned int xrs_id;
 caddr_t xrs_ptr;
} xrs_t;
typedef struct {
 gregset_t gregs;
 gwindows_t *gwins;
 fpregset_t fpregs;
 xrs_t xrs;
 long filler[19];
} mcontext_t;
typedef struct {
 unsigned int __sigbits[4];
} sigset_t;
typedef struct sigaltstack {
 void *ss_sp;
 size_t ss_size;
 int ss_flags;
} stack_t;
typedef struct ucontext ucontext_t;
struct ucontext {
 uint_t uc_flags;
 ucontext_t *uc_link;
 sigset_t uc_sigmask;
 stack_t uc_stack;
 mcontext_t uc_mcontext;
 long uc_filler[23];
};
extern int getcontext(ucontext_t *);
extern int setcontext(const ucontext_t *);

int flag;
ucontext_t cont;
int pad[100];
typedef void (*fun_t)(int);
fun_t p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12;

void h(int v)
{
  printf("%d\n", v);
}

void f(void)
{
  flag = 1;
  setcontext(&cont);
}

static int
g(void)
{
  int ret;

  flag = 0;
  getcontext(&cont);
  ret = flag;
  if (ret == 0) {
    printf("first flag=%d\n", flag);
    p0 = p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = h;
    f();
    p0(ret); p1(ret); p2(ret); p3(ret); p4(ret); p5(ret); p6(ret); p7(ret); p8(ret);
  }
  else {
    printf("second flag=%d\n", flag);
  }
  return ret;
}

int main(int argc, char **argv)
{
  g();
  return 0;
}
% gcc-4.0 -v -g -O1 tst.i
Using built-in specs.
Target: sparc-sun-solaris2.8
Configured with: ../gcc/configure --prefix=/home/akr/g/gcc-4.0
--enable-languages=c --disable-nls
Thread model: posix
gcc version 4.0.1 20050618 (prerelease)
 /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/cc1 -fpreprocessed
tst.i -quiet -dumpbase tst.i -mcpu=v7 -auxbase tst -g -O1 -version -o
/var/tmp//ccINkNlP.s
GNU C version 4.0.1 20050618 (prerelease) (sparc-sun-solaris2.8)
        compiled by GNU C version 4.0.1 20050618 (prerelease).
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 /usr/ccs/bin/as -V -Qy -s -xarch=v8 -o /var/tmp//ccwL3YLE.o /var/tmp//ccINkNlP.s
/usr/ccs/bin/as: Sun WorkShop 6 2003/12/18 Compiler Common 6.0 Patch 114802-02
 /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/collect2 -V -Y
P,/usr/ccs/lib:/usr/lib -Qy
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crt1.o
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crti.o
/usr/ccs/lib/values-Xa.o
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtbegin.o
-L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1 -L/usr/ccs/bin
-L/usr/ccs/lib -L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/../../..
/var/tmp//ccwL3YLE.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh -lc
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtend.o
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtn.o
ld: Software Generation Utilities - Solaris Link Editors: 5.8-1.285
% ./a.out
first flag=0
first flag=0
first flag=0
first flag=0
first flag=0
first flag=0
first flag=0
first flag=0
first flag=0
first flag=0
...

But it terminates as follows if it is not optimized.

% gcc-4.0 -v -g -o a.out.nonopt tst.i 
Using built-in specs.
Target: sparc-sun-solaris2.8
Configured with: ../gcc/configure --prefix=/home/akr/g/gcc-4.0
--enable-languages=c --disable-nls
Thread model: posix
gcc version 4.0.1 20050618 (prerelease)
 /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/cc1 -fpreprocessed
tst.i -quiet -dumpbase tst.i -mcpu=v7 -auxbase tst -g -version -o
/var/tmp//ccbUpN08.s
GNU C version 4.0.1 20050618 (prerelease) (sparc-sun-solaris2.8)
        compiled by GNU C version 4.0.1 20050618 (prerelease).
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 /usr/ccs/bin/as -V -Qy -s -xarch=v8 -o /var/tmp//ccMsWIyd.o /var/tmp//ccbUpN08.s
/usr/ccs/bin/as: Sun WorkShop 6 2003/12/18 Compiler Common 6.0 Patch 114802-02
 /home/akr/g/gcc-4.0/libexec/gcc/sparc-sun-solaris2.8/4.0.1/collect2 -V -Y
P,/usr/ccs/lib:/usr/lib -Qy -o a.out.nonopt
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crt1.o
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crti.o
/usr/ccs/lib/values-Xa.o
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtbegin.o
-L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1 -L/usr/ccs/bin
-L/usr/ccs/lib -L/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/../../..
/var/tmp//ccMsWIyd.o -lgcc -lgcc_eh -lc -lgcc -lgcc_eh -lc
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtend.o
/home/akr/g/gcc-4.0/lib/gcc/sparc-sun-solaris2.8/4.0.1/crtn.o
ld: Software Generation Utilities - Solaris Link Editors: 5.8-1.285
% ./a.out.nonopt 
first flag=0
second flag=1

-------------------------------------------------------------------------------
I investigated the problem as follows.

| % gdb a.out
| GNU gdb 6.3
| Copyright 2004 Free Software Foundation, Inc.
| GDB is free software, covered by the GNU General Public License, and you are
| welcome to change it and/or distribute copies of it under certain conditions.
| Type "show copying" to see the conditions.
| There is absolutely no warranty for GDB.  Type "show warranty" for details.
| This GDB was configured as "sparc-sun-solaris2.8"...
| (gdb) disassemble g
| Dump of assembler code for function g:
| 0x000108ec <g+0>:       save  %sp, -112, %sp
| 0x000108f0 <g+4>:       sethi  %hi(0x20c00), %l0
| 0x000108f4 <g+8>:       clr  [ %l0 + 0x228 ]    ! 0x20e28 <flag>
| 0x000108f8 <g+12>:      sethi  %hi(0x20c00), %o0
| 0x000108fc <g+16>:      call  0x20b84 <getcontext>
| 0x00010900 <g+20>:      or  %o0, 0x240, %o0     ! 0x20e40 <cont>
| 0x00010904 <g+24>:      ld  [ %l0 + 0x228 ], %i0

It seems that the code assumes %l0 is preserved across the call to getcontext.

| 0x00010908 <g+28>:      cmp  %i0, 0
| 0x0001090c <g+32>:      bne,a   0x109ec <g+256>
| 0x00010910 <g+36>:      sethi  %hi(0x10800), %o0
| 0x00010914 <g+40>:      sethi  %hi(0x10800), %o0
| 0x00010918 <g+44>:      or  %o0, 0x2b8, %o0     ! 0x10ab8 <_lib_version+16>
| 0x0001091c <g+48>:      call  0x20b6c <printf>
| 0x00010920 <g+52>:      clr  %o1
| 0x00010924 <g+56>:      sethi  %hi(0x21000), %i5
| 0x00010928 <g+60>:      sethi  %hi(0x10800), %g1
| 0x0001092c <g+64>:      or  %g1, 0xac, %g1      ! 0x108ac <h>
| 0x00010930 <g+68>:      st  %g1, [ %i5 + 0x20 ]
| 0x00010934 <g+72>:      sethi  %hi(0x21000), %l7
| 0x00010938 <g+76>:      st  %g1, [ %l7 + 0x1c ] ! 0x2101c <p7>
| 0x0001093c <g+80>:      sethi  %hi(0x21000), %l6
| 0x00010940 <g+84>:      st  %g1, [ %l6 + 0x18 ] ! 0x21018 <p6>
| 0x00010944 <g+88>:      sethi  %hi(0x21000), %l5
| 0x00010948 <g+92>:      st  %g1, [ %l5 + 0x14 ] ! 0x21014 <p5>
| 0x0001094c <g+96>:      sethi  %hi(0x21000), %l4
| 0x00010950 <g+100>:     st  %g1, [ %l4 + 0x10 ] ! 0x21010 <p4>
| 0x00010954 <g+104>:     sethi  %hi(0x21000), %l3
| 0x00010958 <g+108>:     st  %g1, [ %l3 + 0xc ]  ! 0x2100c <p3>
| 0x0001095c <g+112>:     sethi  %hi(0x21000), %l2
| 0x00010960 <g+116>:     st  %g1, [ %l2 + 8 ]    ! 0x21008 <p2>
| 0x00010964 <g+120>:     sethi  %hi(0x21000), %l1
| 0x00010968 <g+124>:     st  %g1, [ %l1 + 4 ]    ! 0x21004 <p1>
| 0x0001096c <g+128>:     sethi  %hi(0x21000), %l0
| 0x00010970 <g+132>:     call  0x108c8 <f>
| 0x00010974 <g+136>:     st  %g1, [ %l0 ]
| 0x00010978 <g+140>:     ld  [ %l0 ], %g1
| 0x0001097c <g+144>:     call  %g1
| 0x00010980 <g+148>:     clr  %o0
| ---Type <return> to continue, or q <return> to quit--- 
| 0x00010984 <g+152>:     ld  [ %l1 + 4 ], %g1
| 0x00010988 <g+156>:     call  %g1
| 0x0001098c <g+160>:     clr  %o0
| 0x00010990 <g+164>:     ld  [ %l2 + 8 ], %g1
| 0x00010994 <g+168>:     call  %g1
| 0x00010998 <g+172>:     clr  %o0
| 0x0001099c <g+176>:     ld  [ %l3 + 0xc ], %g1
| 0x000109a0 <g+180>:     call  %g1
| 0x000109a4 <g+184>:     clr  %o0
| 0x000109a8 <g+188>:     ld  [ %l4 + 0x10 ], %g1
| 0x000109ac <g+192>:     call  %g1
| 0x000109b0 <g+196>:     clr  %o0
| 0x000109b4 <g+200>:     ld  [ %l5 + 0x14 ], %g1
| 0x000109b8 <g+204>:     call  %g1
| 0x000109bc <g+208>:     clr  %o0
| 0x000109c0 <g+212>:     ld  [ %l6 + 0x18 ], %g1
| 0x000109c4 <g+216>:     call  %g1
| 0x000109c8 <g+220>:     clr  %o0
| 0x000109cc <g+224>:     ld  [ %l7 + 0x1c ], %g1
| 0x000109d0 <g+228>:     call  %g1
| 0x000109d4 <g+232>:     clr  %o0
| 0x000109d8 <g+236>:     ld  [ %i5 + 0x20 ], %g1
| 0x000109dc <g+240>:     call  %g1
| 0x000109e0 <g+244>:     clr  %o0
| 0x000109e4 <g+248>:     ret 
| 0x000109e8 <g+252>:     restore 
| 0x000109ec <g+256>:     or  %o0, 0x2c8, %o0
| 0x000109f0 <g+260>:     call  0x20b6c <printf>
| 0x000109f4 <g+264>:     mov  %i0, %o1
| 0x000109f8 <g+268>:     ret 
| 0x000109fc <g+272>:     restore 
| End of assembler dump.
| (gdb) break *0x000108f4 
| Breakpoint 1 at 0x108f4: file tst.i, line 83.
| (gdb) break *0x00010904
| Breakpoint 2 at 0x10904: file tst.i, line 85.

Two breakpoints are set before and after getcontext call.

| (gdb) display/i $pc
| (gdb) run
| Starting program: /home/akr/z/a.out 
| 
| Breakpoint 1, 0x000108f4 in g () at tst.i:83
| 83        flag = 0;
| 1: x/i $pc  0x108f4 <g+8>:      clr  [ %l0 + 0x228 ]    ! 0x20e28 <flag>
| (gdb) p $l0
| $1 = 134144
| (gdb) x $l0 + 0x228
| 0x20e28 <flag>: 0x00000000

%l0 is 134144 before getcontext is called.
It is hi bits of the address of flag.
It is used to clear flag.

| (gdb) c
| Continuing.
| 
| Breakpoint 2, g () at tst.i:85
| 85        ret = flag;
| 1: x/i $pc  0x10904 <g+24>:     ld  [ %l0 + 0x228 ], %i0
| (gdb) p $l0
| $2 = 134144
| (gdb) x $l0 + 0x228
| 0x20e28 <flag>: 0x00000000

%l0 is still 134144 after first return from getcontext.
It is used to reference flag.

| (gdb) c
| Continuing.
| first flag=0
| 
| Breakpoint 2, g () at tst.i:85
| 85        ret = flag;
| 1: x/i $pc  0x10904 <g+24>:     ld  [ %l0 + 0x228 ], %i0
| (gdb) p $l0
| $3 = 135168
| (gdb) x $l0 + 0x228
| 0x21228:        0x00000000

%l0 is changed to 135168 after second return from getcontext.
It is intended to reference flag but actually reference other address.
The address accessed is 135168 + 0x228 which value is zero.

| (gdb) x 134144 + 0x228
| 0x20e28 <flag>: 0x00000001

The value of flag is one.

| (gdb) p $i0
| $4 = 0
| (gdb) si
| 86        if (ret == 0) {
| 1: x/i $pc  0x10908 <g+28>:     cmp  %i0, 0
| (gdb) p $i0
| $5 = 0
| (gdb) 

The condition doesn't work as intended because the compared value is different
from flag.

I think this is similar to GCC Bug 21957.

Note that the source program is follows.

| % cat tst.c 
| #include <stdlib.h>
| #include <stdio.h>
| #include <ucontext.h>
| 
| int flag;
| ucontext_t cont;
| int pad[100];
| typedef void (*fun_t)(int);
| fun_t p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12;
| 
| void h(int v)
| {
|   printf("%d\n", v);
| }
| 
| void f(void)
| {
|   flag = 1;
|   setcontext(&cont);
| }
| 
| static int
| g(void)
| {
|   int ret;
| 
|   flag = 0;
|   getcontext(&cont);
|   ret = flag;
|   if (ret == 0) {
|     printf("first flag=%d\n", flag);
|     p0 = p1 = p2 = p3 = p4 = p5 = p6 = p7 = p8 = h;
|     f();
|     p0(ret); p1(ret); p2(ret); p3(ret); p4(ret); p5(ret); p6(ret); p7(ret);
p8(ret); 
|   }
|   else {
|     printf("second flag=%d\n", flag);
|   }
|   return ret;
| }
| 
| int main(int argc, char **argv)
| {
|   g();
|   return 0;
| }
Comment 1 Andrew Pinski 2005-06-20 17:05:13 UTC
GCC is emmitting correct asm for a normal function, why should getcontext be different?
Comment 2 akr 2005-06-20 17:22:13 UTC
It's because getcontext is similar to setjmp.

Since setjmp/getcontext doesn't save registers in register window, modifications
to the registers between first setjmp/getcontext return and longjmp/setcontext
call is retained for second return from setjmp/getcontext via  longjmp/setcontext.

It seems that gcc knows setjmp is special but doesn't know about getcontext.

Note that getcontext is defined by Single Unix Specification.
Comment 3 Andrew Pinski 2005-06-20 17:27:02 UTC
Does this work correctly with say Sun's compiler?
Comment 4 Eric Botcazou 2005-06-20 17:31:06 UTC
Confirmed.  This happens to work with 2.95.3 so we have a regression.
Comment 5 Eric Botcazou 2005-06-20 17:32:52 UTC
> Does this work correctly with say Sun's compiler?

Yes it does.
Comment 6 akr 2005-06-20 17:36:29 UTC
Although I have no Sun's Compiler, I found some pragmas about header file in SunOS:

#pragma unknown_control_flow(setjmp)
#pragma unknown_control_flow(_setjmp)
#pragma unknown_control_flow(sigsetjmp)
#pragma unknown_control_flow(getcontext)

So I guess Sun's Compiler can know getcontext is special. 
Comment 7 Andrew Pinski 2005-06-20 17:36:54 UTC
This is not a front-end bug.  But I still think it accidentally worked in 2.95.3 or any compiler really 
because why do we have to treat function special.
Comment 8 Eric Botcazou 2005-06-20 17:46:05 UTC
> This is not a front-end bug.

I disagree, the front-end should automatically recognize the function.
Comment 9 Andrew Pinski 2005-06-20 17:48:44 UTC
Subject: Re:  [3.4/4.0/4.1 Regression] register window not preserved after getcontext call


On Jun 20, 2005, at 1:46 PM, ebotcazou at gcc dot gnu dot org wrote:

>
> ------- Additional Comments From ebotcazou at gcc dot gnu dot org  
> 2005-06-20 17:46 -------
>> This is not a front-end bug.
>
> I disagree, the front-end should automatically recognize the function.

But the place where setjmp is recognized is not in the front-end.

-- Pinski

Comment 10 Mark Mitchell 2005-10-31 03:49:57 UTC
Regardless of *where* getcontext() should be recognized, it's clear that the compiler should be aware that it has special behavior.  

This is a wrong-code regression on a primary platform with no non-default options in use; upgraded to P1.
Comment 11 Eric Botcazou 2005-11-01 22:15:04 UTC
> Regardless of *where* getcontext() should be recognized, it's clear that the
> compiler should be aware that it has special behavior.  

All right, I'll try to do something along these lines.
Comment 12 Eric Botcazou 2005-11-09 12:08:32 UTC
*** Bug 21957 has been marked as a duplicate of this bug. ***
Comment 13 Eric Botcazou 2005-11-10 16:58:59 UTC
Subject: Bug 22127

Author: ebotcazou
Date: Thu Nov 10 16:58:56 2005
New Revision: 106739

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=106739
Log:
	PR middle-end/22127
	* calls.c (special_function_p): Set ECF_RETURNS_TWICE for getcontext.


Added:
    trunk/gcc/testsuite/gcc.dg/sparc-getcontext-1.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/calls.c
    trunk/gcc/testsuite/ChangeLog

Comment 14 Eric Botcazou 2005-11-10 17:00:46 UTC
Subject: Bug 22127

Author: ebotcazou
Date: Thu Nov 10 17:00:41 2005
New Revision: 106740

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=106740
Log:
	PR middle-end/22127
	* calls.c (special_function_p): Set ECF_RETURNS_TWICE for getcontext.


Added:
    branches/gcc-4_0-branch/gcc/testsuite/gcc.dg/sparc-getcontext-1.c
Modified:
    branches/gcc-4_0-branch/gcc/ChangeLog
    branches/gcc-4_0-branch/gcc/calls.c
    branches/gcc-4_0-branch/gcc/testsuite/ChangeLog

Comment 15 Eric Botcazou 2005-11-10 17:05:46 UTC
See http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00663.html.

Fixed in 4.0.3 and up.