Bug 33172 - Optimizer fails to elid away unreferenced static function
Summary: Optimizer fails to elid away unreferenced static function
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 4.1.1
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization
Depends on:
Blocks:
 
Reported: 2007-08-24 12:04 UTC by Satyam Sharma
Modified: 2010-11-10 20:38 UTC (History)
2 users (show)

See Also:
Host: i386-redhat-linux
Target: i386-redhat-linux
Build:
Known to work:
Known to fail: 4.3.0
Last reconfirmed: 2007-08-24 14:13:09


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Satyam Sharma 2007-08-24 12:04:38 UTC
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. ]
Comment 1 Richard Biener 2007-08-24 14:13:09 UTC
Confirmed.  Only after early inlining we know enough to do this, but the decision
is already made before it seems.  Honza?
Comment 2 Jan Hubicka 2010-11-10 17:55:20 UTC
This is fixed now by ipa-reference code. I will commit the testcase.
Comment 3 Jan Hubicka 2010-11-10 20:38:26 UTC
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