Builtin bzero? Please don't.
David Holland
dholland@eecs.harvard.edu
Thu Jan 10 13:54:00 GMT 2002
I discovered just now that gcc 3.0.3, with -O1 or higher, and without
-ansi, converts calls to bzero() into calls to memset(), entirely on
its own, without being told to.
There are three reasons why this is incorrect:
1. bzero() is not a standard function. It is inappropriate to
assume that an arbitrary call to a function called bzero can be
correctly transformed into a call to memset, even if -ansi is
not specified. Whether it is formally incorrect is debatable,
but it certainly violates the principle of least surprise, since
it happens without any request to the compiler. (If I wanted
bzero calls to be transformed into memset calls, I would put an
inline definition into string.h.)
2. This transformation does not accomplish anything. There is
nothing to be saved from converting bzero calls into memset
calls, except perhaps a few bytes in the C library image which
probably need to be retained for compatibility anyway. Such
savings are not worth the potential problems.
3. Worse, this transformation is an anti-optimization. On many
platforms, the fact that bzero is known to be filling with zeros
can be exploited to make it faster and simpler than memset. And
on some platforms, there are MMU or cache features that allow
direct zeroing of blocks of memory. These features can be used
in a bzero implementation, but not in a memset implementation.
It would be more useful for the compiler to make the
transformation the other way around: detect calls to memset with
a zero fill-byte argument, which, when present, is almost always
constant, and convert them to calls to bzero.
In general, I think, gcc needs to offer more control over builtin
functions to C library implementors. This sort of transformation is
fine, and in fact possibly quite useful, *if* it is only performed
when explicitly requested. If it's necessary to have these
transformations work even on source that doesn't include appropriate
headers, which it might be, it seems to me that the solution is to
have a special header file that's automatically processed with cpp
-include.
The above diagnosis was made with stock gcc 3.0.3 configured for
mips-linux on i386-netbsd:
Reading specs from ../usr/bin/../lib/gcc-lib/mips-linux/3.0.3/specs
Configured with: ../../option2/gcc-3.0.3/configure --target=mips-linux
--nfp --disable-shared --prefix=/usr/tmp/tools02/test2/usr
Thread model: single
gcc version 3.0.3
(I should note that it didn't build without --disable-shared; I didn't
take enough notes to file a proper bug report, though.)
Sample code follows:
/*
* Demonstration code.
* Compile this with: mips-linux-gcc -S -O2 test.c
* Examine the resulting .s file, which calls memset instead of bzero.
*/
typedef unsigned size_t;
void bzero(void *, size_t);
void foo(void) {
long array[12];
bzero(array, sizeof(array));
/* prevent array from being optimized away */
(void)(volatile long *)array;
}
--
- David A. Holland | VINO project home page:
dholland@eecs.harvard.edu | http://www.eecs.harvard.edu/vino
More information about the Gcc-bugs
mailing list