From 802d420792769f789f372748a739aa10feccbb26 Mon Sep 17 00:00:00 2001 From: Oliver Stannard Date: Mon, 18 Aug 2014 12:42:15 +0000 Subject: [PATCH] [ARM,AArch64] Do not tail-call to an externally-defined function with weak linkage Externally-defined functions with weak linkage should not be tail-called on ARM or AArch64, as the AAELF spec requires normal calls to undefined weak functions to be replaced with a NOP or jump to the next instruction. The behaviour of branch instructions in this situation (as used for tail calls) is implementation-defined, so we cannot rely on the linker replacing the tail call with a return. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215890 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/AArch64/AArch64ISelLowering.cpp | 13 +++++++++++++ lib/Target/ARM/ARMISelLowering.cpp | 13 +++++++++++++ test/CodeGen/AArch64/tail-call.ll | 11 +++++++++++ test/CodeGen/ARM/tail-call.ll | 10 ++++++++++ 4 files changed, 47 insertions(+) diff --git a/lib/Target/AArch64/AArch64ISelLowering.cpp b/lib/Target/AArch64/AArch64ISelLowering.cpp index be9d8d67afd..e277a5e0780 100644 --- a/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -2016,6 +2016,19 @@ bool AArch64TargetLowering::isEligibleForTailCallOptimization( return false; } + // Externally-defined functions with weak linkage should not be + // tail-called on AArch64 when the OS does not support dynamic + // pre-emption of symbols, as the AAELF spec requires normal calls + // to undefined weak functions to be replaced with a NOP or jump to the + // next instruction. The behaviour of branch instructions in this + // situation (as used for tail calls) is implementation-defined, so we + // cannot rely on the linker replacing the tail call with a return. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + const GlobalValue *GV = G->getGlobal(); + if (GV->hasExternalWeakLinkage()) + return false; + } + // Now we search for cases where we can use a tail call without changing the // ABI. Sibcall is used in some places (particularly gcc) to refer to this // concept. diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 4349f291e50..e8cbada3447 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -1997,6 +1997,19 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, if (Subtarget->isThumb1Only()) return false; + // Externally-defined functions with weak linkage should not be + // tail-called on ARM when the OS does not support dynamic + // pre-emption of symbols, as the AAELF spec requires normal calls + // to undefined weak functions to be replaced with a NOP or jump to the + // next instruction. The behaviour of branch instructions in this + // situation (as used for tail calls) is implementation-defined, so we + // cannot rely on the linker replacing the tail call with a return. + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + const GlobalValue *GV = G->getGlobal(); + if (GV->hasExternalWeakLinkage()) + return false; + } + // If the calling conventions do not match, then we'd better make sure the // results are returned in the same way as what the caller expects. if (!CCMatch) { diff --git a/test/CodeGen/AArch64/tail-call.ll b/test/CodeGen/AArch64/tail-call.ll index 8aab8421526..7fb39545a32 100644 --- a/test/CodeGen/AArch64/tail-call.ll +++ b/test/CodeGen/AArch64/tail-call.ll @@ -3,6 +3,7 @@ declare fastcc void @callee_stack0() declare fastcc void @callee_stack8([8 x i32], i64) declare fastcc void @callee_stack16([8 x i32], i64, i64) +declare extern_weak fastcc void @callee_weak() define fastcc void @caller_to0_from0() nounwind { ; CHECK-LABEL: caller_to0_from0: @@ -92,3 +93,13 @@ define fastcc void @caller_to16_from16([8 x i32], i64 %a, i64 %b) { ; CHECK-NEXT: add sp, sp, #16 ; CHECK-NEXT: b callee_stack16 } + + +; Weakly-referenced extern functions cannot be tail-called, as AAELF does +; not define the behaviour of branch instructions to undefined weak symbols. +define fastcc void @caller_weak() { +; CHECK-LABEL: caller_weak: +; CHECK: bl callee_weak + tail call void @callee_weak() + ret void +} diff --git a/test/CodeGen/ARM/tail-call.ll b/test/CodeGen/ARM/tail-call.ll index 771158632ec..c3e79652c03 100644 --- a/test/CodeGen/ARM/tail-call.ll +++ b/test/CodeGen/ARM/tail-call.ll @@ -3,6 +3,7 @@ ; RUN: | FileCheck %s -check-prefix CHECK-NO-TAIL declare i32 @callee(i32 %i) +declare extern_weak fastcc void @callee_weak() define i32 @caller(i32 %i) { entry: @@ -19,3 +20,12 @@ entry: ; CHECK-NO-TAIL: pop {lr} ; CHECK-NO-TAIL: bx lr + +; Weakly-referenced extern functions cannot be tail-called, as AAELF does +; not define the behaviour of branch instructions to undefined weak symbols. +define fastcc void @caller_weak() { +; CHECK-LABEL: caller_weak: +; CHECK: bl callee_weak + tail call void @callee_weak() + ret void +} -- 2.11.0