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. ]
Confirmed. Only after early inlining we know enough to do this, but the decision is already made before it seems. Honza?
This is fixed now by ipa-reference code. I will commit the testcase.
Author: hubicka Date: Wed Nov 10 20:38:15 2010 New Revision: 166557 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=166557 Log: PR tree-optimize/33172 PR tree-optimize/43411 * gcc.dg/tree-ssa/pr33172.c: New testcase. * g++.dg/tree-ssa/pr43411.C: New testcase. Added: trunk/gcc/testsuite/g++.dg/tree-ssa/pr43411.C trunk/gcc/testsuite/gcc.dg/tree-ssa/pr33172.c Modified: trunk/gcc/testsuite/ChangeLog