This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
c/6833: gcse mishandles global register variables
- From: Bruno Haible <bruno at clisp dot org>
- To: gcc-gnats at gcc dot gnu dot org
- Cc: clisp-devel at lists dot sourceforge dot net
- Date: Mon, 27 May 2002 13:26:23 +0200 (CEST)
- Subject: c/6833: gcse mishandles global register variables
>Number: 6833
>Category: c
>Synopsis: gcse generates wrong code with regard to global register variables
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: unassigned
>State: open
>Class: wrong-code
>Submitter-Id: net
>Arrival-Date: Mon May 27 04:36:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: Bruno Haible
>Release: 3.1
>Organization:
GNU hackers
>Environment:
System: Linux linuix 2.4.18-4GB #1 Wed Mar 27 13:57:05 UTC 2002 i686 unknown
Architecture: i686
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: /packages2/gcc-3.1/configure --prefix=/packages/gnu-snapshot --enable-shared --enable-version-specific-runtime-libs --enable-nls
>Description:
The GCSE pass recognizes expressions as being "common" subexpressions
even if they refer to the values of global register variables and
there are function calls in between. This is wrong because function
calls can modify any global register variable.
>How-To-Repeat:
In the following program the function C_make_instance is miscompiled.
============================ bu.c =====================================
typedef void * object;
register object* STACK __asm__("%ebx");
unsigned int mv_count;
object mv_space [127];
void funcall (object fun, unsigned int argcount)
{
STACK -= argcount;
}
void C_make_instance (unsigned int argcount, object fun)
{
STACK[0] = mv_space[0], STACK += 1;
if (argcount>0) {
object* ptr = &STACK[-1];
unsigned int count = 2*argcount;
do { *ptr = *(ptr - 1); ptr -= 1; } while (!(--count==0));
*ptr = mv_space[0];
}
funcall(fun,2*argcount+1);
mv_space[0] = (STACK -= 1, STACK[0]); mv_count = 1;
}
int main ()
{
int A;
object a = &A;
int B;
object b = &B;
int C;
object c = &C;
int D;
object d = &D;
int F;
object f = &F;
object STACK_SPACE[5] = { a, b, c, 0, 0 };
object* saved_STACK;
int exitcode;
saved_STACK = STACK;
STACK = &STACK_SPACE[3];
mv_space[0] = d;
C_make_instance(1,f);
exitcode = (STACK == &STACK_SPACE[0] && mv_space[0] == a ? 0 : 1);
STACK = saved_STACK;
return exitcode;
}
======================================================================
$ gcc -Wall bu.c
$ ./a.out ; echo $?
0
$ gcc -O2 -Wall bu.c
$ ./a.out ; echo $?
1
$ gcc -O2 -fno-gcse -Wall bu.c
$ ./a.out ; echo $?
0
Now look at the code generated by "gcc -O2 -S -g bu.c", Search for
".loc 1 19 0". You can see
movl -12(%ebp), %ebx
movl (%ebx), %eax
movl %eax, mv_space
You can see that here, instead of computing STACK-1 [= %ebx - 4],
the instruction fetches the saved earlier value of STACK-1 from
-12(%ebp). But this is wrong because there is a call to funcall()
in between which has modified STACK.
Please add this sample program to your testsuite.
>Fix:
Teach GCSE to look at global register variables with more care.
>Release-Note:
>Audit-Trail:
>Unformatted: