Index: llvm/trunk/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86ISelLowering.cpp +++ llvm/trunk/lib/Target/X86/X86ISelLowering.cpp @@ -2780,6 +2780,24 @@ 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(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 @@ -2964,8 +2982,8 @@ // Note: The actual moving to ECX is done further down. GlobalAddressSDNode *G = dyn_cast(Callee); - if (G && !G->getGlobal()->hasHiddenVisibility() && - !G->getGlobal()->hasProtectedVisibility()) + if (G && !G->getGlobal()->hasLocalLinkage() && + G->getGlobal()->hasDefaultVisibility()) Callee = LowerGlobalAddress(Callee, DAG); else if (isa(Callee)) Callee = LowerExternalSymbol(Callee, DAG); Index: llvm/trunk/test/CodeGen/X86/pic.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/pic.ll +++ llvm/trunk/test/CodeGen/X86/pic.ll @@ -196,9 +196,11 @@ ; 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(...) Index: llvm/trunk/test/CodeGen/X86/tail-call-got.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/tail-call-got.ll +++ llvm/trunk/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 } @@ -15,10 +17,18 @@ 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 Index: llvm/trunk/test/CodeGen/X86/tailcallpic1.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/tailcallpic1.ll +++ llvm/trunk/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 Index: llvm/trunk/test/CodeGen/X86/tailcallpic3.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/tailcallpic3.ll +++ llvm/trunk/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