On Sun, 10 May 2015, Jan Hubicka wrote:
> You probably need to update comment here. I wonder what happens when we
> optimize
> indirect call to direct call to global function at RTL level? I suppose we are
> safe here, because at RTL level we explicitly represent if we refer to PLT
> entry
> or the functionaddress itself and we never optimize one to the other?
>
> Patch is OK if you make sure that this works and update the comment.
I think we are safe: to have things break we'd have to have a GOT-relative
memory load be combined with a branch on the RTL level, and GOT loads have
UNSPEC_GOT. I have used the following example to try to induce failure:
void foo(void);
void bar()
{
void (*p)(void) = foo;
p();
}
With the following options:
gcc -fPIC -m32 -O -foptimize-sibling-calls -fno-tree-ccp -fno-tree-copy-prop
-fno-tree-fre -fno-tree-dominator-opts -fno-tree-ter
GCC has indirect call after pass_expand. Without -fPIC it is transformed into
direct call in pass_combine, with -fPIC it is kept as is.
I've added a testcase. Below is what I'm checking in. Thanks!
Index: testsuite/gcc.target/i386/pr65753.c
===================================================================
--- testsuite/gcc.target/i386/pr65753.c (revision 0)
+++ testsuite/gcc.target/i386/pr65753.c (revision 0)
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-fPIC -O" } */
+/* { dg-final { scan-assembler-not "call" } } */
+
+void foo(void (*bar)(void))
+{
+ bar();
+}
Index: config/i386/i386.c
===================================================================
--- config/i386/i386.c (revision 223002)
+++ config/i386/i386.c (working copy)
@@ -5473,12 +5473,12 @@
rtx a, b;
/* If we are generating position-independent code, we cannot sibcall
- optimize any indirect call, or a direct call to a global function,
- as the PLT requires %ebx be live. (Darwin does not have a PLT.) */
+ optimize direct calls to global functions, as the PLT requires
+ %ebx be live. (Darwin does not have a PLT.) */
if (!TARGET_MACHO
&& !TARGET_64BIT
&& flag_pic
- && (!decl || !targetm.binds_local_p (decl)))
+ && decl && !targetm.binds_local_p (decl))
return false;