This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: noalias macro bug [was: Linux and aliasing?]
- To: pommnitz at darmstadt dot gmd dot de
- Subject: Re: noalias macro bug [was: Linux and aliasing?]
- From: mark at codesourcery dot com
- Date: Tue, 08 Jun 1999 10:42:29 -0700
- Cc: egcs at egcs dot cygnus dot com
- Organization: CodeSourcery, LLC
- References: <375D2731.5EDE3C6@darmstadt.gmd.de>
>>>>> "Joerg" == Joerg Pommnitz <pommnitz@darmstadt.gmd.de> writes:
You included the following program:
#include <stdio.h>
#define noalias(type, ptr) \
(((union { type __x__; __typeof__(*(ptr)) __y__;} *)(ptr))->__x__)
int
main ()
{
int a = 0x12345678;
unsigned short *b = &noalias(unsigned short, &a);
printf ("%x\n", a);
b[1] = 0;
printf ("%x\n", a);
return 0;
}
and noted that:
pommnitz ~>gcc -O2 -o alias alias.c
pommnitz ~>./alias
12345678
12345678
You correctly concluded that this means the "noalias" macro didn't
work and asked:
Is this an egcs bug, is the macro at fault or am I doing something
stupid?
None of the above. It's not a GCC bug. From the manual section on
-fstrict-aliasing:
Pay special attention to code like this:
union a_union {
int i;
double d;
};
int f() {
a_union t;
t.d = 3.0;
return t.i;
}
The practice of reading from a different union member than the one
most recently written to (called "type-punning") is common. Even
with `-fstrict-aliasing', type-punning is allowed, provided the
memory is accessed through the union type. So, the code above
will work as expected. However, this code might not:
int f() {
a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}
In other words, as in Linus' proposal, the "union trick" works only
when accessing directly through the union. You squirelled the pointer
away, and then used it later, thereby losing the effects of the
noalias macro. The following variant of your program works as you
expect:
extern void printf(const char*, ...);
#define noalias(type, ptr) \
(((union { type __x__; __typeof__(*(ptr)) __y__;} *)(ptr))->__x__)
typedef unsigned short usa[2];
int
main ()
{
int a = 0x12345678;
printf ("%x\n", a);
noalias(usa, &a)[1] = 0;
printf ("%x\n", a);
return 0;
}
Here's what I get:
linux1.codesourcery.com% ./a.out
12345678
5678
which is I think what you expected.
Kernel people: is the use of the self-documenting noalias macro, as
demonstrated here, really so hard?
--
Mark Mitchell mark@codesourcery.com
CodeSourcery, LLC http://www.codesourcery.com