Skip to content

Commit

Permalink
Disable x86 tail call optimizations that jump through GOT
Browse files Browse the repository at this point in the history
For x86 targets, do not do sibling call optimization when materializing
the callee's address would require a GOT relocation. We can still do
tail calls to internal functions, hidden functions, and protected
functions, because they do not require this kind of relocation. It is
still possible to get GOT relocations when the user explicitly asks for
it with musttail or -tailcallopt, both of which are supposed to
guarantee TCO.

Based on a patch by Chih-hung Hsieh.

Reviewers: srhines, timmurray, danalbert, enh, void, nadav, rnk

Subscribers: joerg, davidxl, llvm-commits

Differential Revision: http://reviews.llvm.org/D9799

llvm-svn: 238487
  • Loading branch information
rnk committed May 28, 2015
1 parent 322b2c4 commit 80956a0
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 9 deletions.
22 changes: 20 additions & 2 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Expand Up @@ -2780,6 +2780,24 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
if (MF.getTarget().Options.DisableTailCalls)
isTailCall = false;

if (Subtarget->isPICStyleGOT() &&
!MF.getTarget().Options.GuaranteedTailCallOpt) {
// If we are using a GOT, disable tail calls to external symbols with
// default visibility. Tail calling such a symbol requires using a GOT
// relocation, which forces early binding of the symbol. This breaks code
// that require lazy function symbol resolution. Using musttail or
// GuaranteedTailCallOpt will override this.
GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee);
if (!G || (!G->getGlobal()->hasLocalLinkage() &&
G->getGlobal()->hasDefaultVisibility())) {
isTailCall = false;
if (G) {
llvm::errs() << "disabling tail call for default visibility symbol\n";
G->getGlobal()->dump();
}
}
}

bool IsMustTail = CLI.CS && CLI.CS->isMustTailCall();
if (IsMustTail) {
// Force this to be a tail call. The verifier rules are enough to ensure
Expand Down Expand Up @@ -2964,8 +2982,8 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,

// Note: The actual moving to ECX is done further down.
GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee);
if (G && !G->getGlobal()->hasHiddenVisibility() &&
!G->getGlobal()->hasProtectedVisibility())
if (G && !G->getGlobal()->hasLocalLinkage() &&
G->getGlobal()->hasDefaultVisibility())
Callee = LowerGlobalAddress(Callee, DAG);
else if (isa<ExternalSymbolSDNode>(Callee))
Callee = LowerExternalSymbol(Callee, DAG);
Expand Down
8 changes: 5 additions & 3 deletions llvm/test/CodeGen/X86/pic.ll
Expand Up @@ -196,9 +196,11 @@ bb12:
; LINUX-NEXT: .LJTI7_0:
; LINUX: .long .LBB7_2@GOTOFF
; LINUX: .long .LBB7_8@GOTOFF
; LINUX: .long .LBB7_14@GOTOFF
; LINUX: .long .LBB7_9@GOTOFF
; LINUX: .long .LBB7_10@GOTOFF
; LINUX: .long .LBB7_4@GOTOFF
; LINUX: .long .LBB7_6@GOTOFF
; LINUX: .long .LBB7_5@GOTOFF
; LINUX: .long .LBB7_8@GOTOFF
; LINUX: .long .LBB7_7@GOTOFF
}

declare void @foo1(...)
Expand Down
18 changes: 14 additions & 4 deletions llvm/test/CodeGen/X86/tail-call-got.ll
@@ -1,12 +1,14 @@
; RUN: llc < %s -relocation-model=pic -mattr=+sse2 | FileCheck %s

; We used to do tail calls through the GOT for these symbols, but it was
; disabled due to PR15086.

target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
target triple = "i386-unknown-freebsd9.0"

define double @test1(double %x) nounwind readnone {
; CHECK-LABEL: test1:
; CHECK: movl foo@GOT
; CHECK-NEXT: jmpl
; CHECK: calll foo@PLT
%1 = tail call double @foo(double %x) nounwind readnone
ret double %1
}
Expand All @@ -15,10 +17,18 @@ declare double @foo(double) readnone

define double @test2(double %x) nounwind readnone {
; CHECK-LABEL: test2:
; CHECK: movl sin@GOT
; CHECK-NEXT: jmpl
; CHECK: calll sin@PLT
%1 = tail call double @sin(double %x) nounwind readnone
ret double %1
}

declare double @sin(double) readnone

define double @test3(double %x) nounwind readnone {
; CHECK-LABEL: test3:
; CHECK: calll sin2@PLT
%1 = tail call double @sin2(double %x) nounwind readnone
ret double %1
}

declare double @sin2(double) readnone
3 changes: 3 additions & 0 deletions llvm/test/CodeGen/X86/tailcallpic1.ll
@@ -1,5 +1,8 @@
; RUN: llc < %s -tailcallopt -mtriple=i686-pc-linux-gnu -relocation-model=pic | FileCheck %s

; This test uses guaranteed TCO so these will be tail calls, despite the early
; binding issues.

define protected fastcc i32 @tailcallee(i32 %a1, i32 %a2, i32 %a3, i32 %a4) {
entry:
ret i32 %a3
Expand Down
73 changes: 73 additions & 0 deletions llvm/test/CodeGen/X86/tailcallpic3.ll
@@ -0,0 +1,73 @@
; RUN: llc < %s -mtriple=i686-pc-linux-gnu -relocation-model=pic | FileCheck %s

; While many of these could be tail called, we don't do it because it forces
; early binding.

declare void @external()

define hidden void @tailcallee_hidden() {
entry:
ret void
}

define void @tailcall_hidden() {
entry:
tail call void @tailcallee_hidden()
ret void
}
; CHECK: tailcall_hidden:
; CHECK: jmp tailcallee_hidden

define internal void @tailcallee_internal() {
entry:
ret void
}

define void @tailcall_internal() {
entry:
tail call void @tailcallee_internal()
ret void
}
; CHECK: tailcall_internal:
; CHECK: jmp tailcallee_internal

define default void @tailcallee_default() {
entry:
ret void
}

define void @tailcall_default() {
entry:
tail call void @tailcallee_default()
ret void
}
; CHECK: tailcall_default:
; CHECK: calll tailcallee_default@PLT

define void @tailcallee_default_implicit() {
entry:
ret void
}

define void @tailcall_default_implicit() {
entry:
tail call void @tailcallee_default_implicit()
ret void
}
; CHECK: tailcall_default_implicit:
; CHECK: calll tailcallee_default_implicit@PLT

define void @tailcall_external() {
tail call void @external()
ret void
}
; CHECK: tailcall_external:
; CHECK: calll external@PLT

define void @musttail_external() {
musttail call void @external()
ret void
}
; CHECK: musttail_external:
; CHECK: movl external@GOT
; CHECK: jmpl

0 comments on commit 80956a0

Please sign in to comment.