This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug rtl-optimization/33172] New: Optimizer fails to elid away unreferenced static function
- From: "satyam at infradead dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 24 Aug 2007 12:04:40 -0000
- Subject: [Bug rtl-optimization/33172] New: Optimizer fails to elid away unreferenced static function
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
Background:
===========
In the Linux kernel one often sees the following idiom:
static void foo_func(void)
{
}
static struct foo_type foo_struct = {
.foo_call = foo_func,
};
some_init_func(...)
{
register_foo(&foo_struct);
}
some_exit_func(...)
{
unregister_foo(&foo_struct);
}
The point is that {un}register_foo() may be a configuration-dependent
functions that may either be externally-implemented-in-another-module
or, if that configuration item is turned off, resolve to empty stubs
defined in a header itself. [ The empty stubs may be do-nothing macros,
or often static inline functions with empty bodies. ]
The expectation is that, when defined as empty stubs, because there is
effectively no reference left to the static foo_struct and, transitively,
to the static foo_func, the optimizer must just optimize them away
completely.
Problem:
========
The expectation holds true, when the empty stubs are defined as empty
do {} while (0); macros, but not if defined as empty "static inline
int ... {return 0;}" functions.
Testcase:
=========
I think the below (with given commentary) is self-explanatory:
/* gcc -Wall -Os -S */
struct abc {
void (*abc_call)(void);
};
/*
* Use only any one of the three definitions below at a time:
*
* 1. nothing optimized away. Good.
* 2. call_func() _not_ optimized away, but struct xyz is. gcc disappoints.
* 3. both call_func() and struct xyz optimized away. Nice.
*/
/* 1 */
/*extern int do_register(struct abc *xyz);*/
/* 2 */
static inline int do_register(struct abc *xyz)
{
return 0;
}
/* 3 */
/*#define do_register(xyz) do { (void)(xyz); } while (0)*/
static void call_func(void)
{
}
static struct abc xyz = {
.abc_call = call_func,
};
void func(void)
{
do_register(&xyz);
}
Assembler for problematic case:
===============================
.file "xyz.c"
.text
.type call_func, @function
call_func:
pushl %ebp
movl %esp, %ebp
popl %ebp
ret
.size call_func, .-call_func
.globl func
.type func, @function
func:
pushl %ebp
movl %esp, %ebp
popl %ebp
ret
.size func, .-func
.ident "GCC: (GNU) 4.1.1 20070105 (Red Hat 4.1.1-51)"
.section .note.GNU-stack,"",@progbits
As you can see, there is nobody referencing the static call_func()
in this object file, and being static, there can be none in others
either. Why did we fail to just elid it away completely?
[ Interestingly, the equally-unreferenced static struct xyz _did_
get elided away. But not so the static function. ]
--
Summary: Optimizer fails to elid away unreferenced static
function
Product: gcc
Version: 4.1.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: satyam at infradead dot org
GCC host triplet: i386-redhat-linux
GCC target triplet: i386-redhat-linux
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33172