Index: lib/Target/X86/X86ISelLowering.cpp =================================================================== --- lib/Target/X86/X86ISelLowering.cpp +++ lib/Target/X86/X86ISelLowering.cpp @@ -2752,11 +2752,21 @@ if (MF.getTarget().Options.DisableTailCalls) isTailCall = false; + if (Subtarget->isPICStyleGOT()) { + // Cannot jump to address through GOT, see https://llvm.org/bugs/show_bug.cgi?id=15086 + GlobalAddressSDNode *G = dyn_cast(Callee); + // Only assume local binding, not through GOT, for protected and hidden symbols. + // For special symbols like "sin", see tail-call-got.ll test case, G is null. + if (!(G && (G->getGlobal()->hasHiddenVisibility() || + G->getGlobal()->hasProtectedVisibility()))) + isTailCall = false; + } + bool IsMustTail = CLI.CS && CLI.CS->isMustTailCall(); if (IsMustTail) { // Force this to be a tail call. The verifier rules are enough to ensure // that we can lower this successfully without moving the return address - // around. + // around. User should be aware of lazy dynamic linking issue in bug 15086. isTailCall = true; } else if (isTailCall) { // Check if it's really possible to do a tail call. Index: test/CodeGen/X86/pic.ll =================================================================== --- test/CodeGen/X86/pic.ll +++ 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: test/CodeGen/X86/tail-call-got.ll =================================================================== --- test/CodeGen/X86/tail-call-got.ll +++ test/CodeGen/X86/tail-call-got.ll @@ -5,20 +5,28 @@ 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 } declare double @foo(double) readnone +; "sin2" is global but not "sin"? 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: test/CodeGen/X86/tailcallpic1.ll =================================================================== --- test/CodeGen/X86/tailcallpic1.ll +++ test/CodeGen/X86/tailcallpic1.ll @@ -11,3 +11,39 @@ ret i32 %tmp11 ; CHECK: jmp tailcallee } + +define hidden fastcc i32 @tailcallee2(i32 %a1, i32 %a2, i32 %a3, i32 %a4) { +entry: + ret i32 %a3 +} + +define fastcc i32 @tailcaller2(i32 %in1, i32 %in2) { +entry: + %tmp11 = tail call fastcc i32 @tailcallee2( i32 %in1, i32 %in2, i32 %in1, i32 %in2 ) ; [#uses=1] + ret i32 %tmp11 +; CHECK: jmp tailcallee2 +} + +define default fastcc i32 @tailcallee3(i32 %a1, i32 %a2, i32 %a3, i32 %a4) { +entry: + ret i32 %a3 +} + +define fastcc i32 @tailcaller3(i32 %in1, i32 %in2) { +entry: + %tmp11 = tail call fastcc i32 @tailcallee3( i32 %in1, i32 %in2, i32 %in1, i32 %in2 ) ; [#uses=1] + ret i32 %tmp11 +; CHECK: calll tailcallee3@PLT +} + +define fastcc i32 @tailcallee4(i32 %a1, i32 %a2, i32 %a3, i32 %a4) { +entry: + ret i32 %a3 +} + +define fastcc i32 @tailcaller4(i32 %in1, i32 %in2) { +entry: + %tmp11 = tail call fastcc i32 @tailcallee4( i32 %in1, i32 %in2, i32 %in1, i32 %in2 ) ; [#uses=1] + ret i32 %tmp11 +; CHECK: calll tailcallee4@PLT +} Index: test/CodeGen/X86/tailcallpic2.ll =================================================================== --- test/CodeGen/X86/tailcallpic2.ll +++ test/CodeGen/X86/tailcallpic2.ll @@ -9,7 +9,6 @@ entry: %tmp11 = tail call fastcc i32 @tailcallee( i32 %in1, i32 %in2, i32 %in1, i32 %in2 ) ; [#uses=1] ret i32 %tmp11 -; CHECK: movl tailcallee@GOT -; CHECK: jmpl +; CHECK: calll tailcallee@PLT }