I noticed that most of the attr-ifunc tests were failing on the PowerPC. I tracked it down to the fact that in varasm.c the indirect function is considered a local function. On the powerpc in 64-bit mode or 32-bit mode under AIX, a local function uses the same TOC value in r2 as the caller, so the compiler can just implmenet a BL instruction. For non-local functions, the compiler issues BL followed by a NOP, which might be modified by the linker to reload the TOC value into r2. In the case of the indirect functions, the linker needs to convert the call to always going through the PLT (procedure linkage table), and it won't do the optimization if the BL is not followed by a NOP.
This patch makes indirect functions always non-local, much like weak symbols are. Note, in the general case, the resolver function could potentially resolve to a non-local function, so I feel this patch is correct for all ports. I did a bootstrap and make check on the powerpc with no regressions, and the attr-ifunc tests are fixed. Is it ok to apply to the tree (and backport to 4.6)? 2011-12-08 Michael Meissner <meiss...@the-meissners.org> PR rtl-optimization/51469 * varasm.c (default_binds_local_p_1): If the symbol is a gnu indirect function, mark the symbol as non-local. Index: gcc/varasm.c =================================================================== --- gcc/varasm.c (revision 182092) +++ gcc/varasm.c (working copy) @@ -6911,11 +6911,14 @@ default_binds_local_p_1 (const_tree exp, /* A non-decl is an entry in the constant pool. */ if (!DECL_P (exp)) local_p = true; - /* Weakrefs may not bind locally, even though the weakref itself is - always static and therefore local. - FIXME: We can resolve this more curefuly by looking at the weakref - alias. */ - else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp))) + /* Weakrefs may not bind locally, even though the weakref itself is always + static and therefore local. Similarly, the resolver for ifunc functions + might resolve to a non-local function. + FIXME: We can resolve the weakref case more curefuly by looking at the + weakref alias. */ + else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)) + || (TREE_CODE (exp) == FUNCTION_DECL + && lookup_attribute ("ifunc", DECL_ATTRIBUTES (exp)))) local_p = false; /* Static variables are always local. */ else if (! TREE_PUBLIC (exp)) -- Michael Meissner, IBM 5 Technology Place Drive, M/S 2757, Westford, MA 01886-3141, USA meiss...@linux.vnet.ibm.com fax +1 (978) 399-6899