[PATCH] ARM: Do not tail-call to an externally-defined function with weak linkage

Oliver Stannard oliver.stannard at arm.com
Fri Aug 15 06:02:37 PDT 2014


I originally stated that "we cannot rely on the linker replacing the tail call with a return", but after further thought I now realise that it is impossible for the linker to replace a tail-call with a return, as it may need to insert a stack pointer adjustment, but it does not know how big the adjustment must be.

Both armlink and arm-none-eabi-ld replace branch instructions to undefined weak symbols with a NOP, so this is not just an armlink problem.

The AAELF spec only states this for "platforms that do not support dynamic pre-emption of symbols", so I have modified the patch to only prevent the tail call for bare-metal systems.

http://reviews.llvm.org/D4906

Files:
  lib/Transforms/Scalar/TailRecursionElimination.cpp
  test/Transforms/TailCallElim/AArch64/lit.local.cfg
  test/Transforms/TailCallElim/AArch64/weak-linkage.ll
  test/Transforms/TailCallElim/ARM/lit.local.cfg
  test/Transforms/TailCallElim/ARM/weak-linkage.ll

Index: lib/Transforms/Scalar/TailRecursionElimination.cpp
===================================================================
--- lib/Transforms/Scalar/TailRecursionElimination.cpp
+++ lib/Transforms/Scalar/TailRecursionElimination.cpp
@@ -54,6 +54,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/Triple.h"
 #include "llvm/Analysis/CaptureTracking.h"
 #include "llvm/Analysis/CFG.h"
 #include "llvm/Analysis/InlineCost.h"
@@ -298,6 +299,22 @@
       if (!CI || CI->isTailCall())
         continue;
 
+      // Externally-defined functions with weak linkage should not be
+      // tail-called on ARM or 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.
+      GlobalValue *Callee = dyn_cast<GlobalValue>(CI->getCalledValue());
+      Triple T(F.getParent()->getTargetTriple());
+      if ((T.getArch() == Triple::arm || T.getArch() == Triple::armeb ||
+          T.getArch() == Triple::thumb || T.getArch() == Triple::thumbeb ||
+          T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_be)
+          && T.getOS() == Triple::UnknownOS
+          && Callee && Callee->hasExternalWeakLinkage())
+        continue;
+
       if (CI->doesNotAccessMemory()) {
         // A call to a readnone function whose arguments are all things computed
         // outside this function can be marked tail. Even if you stored the
Index: test/Transforms/TailCallElim/AArch64/lit.local.cfg
===================================================================
--- /dev/null
+++ test/Transforms/TailCallElim/AArch64/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'AArch64' in config.root.targets:
+    config.unsupported = True
+
Index: test/Transforms/TailCallElim/AArch64/weak-linkage.ll
===================================================================
--- /dev/null
+++ test/Transforms/TailCallElim/AArch64/weak-linkage.ll
@@ -0,0 +1,12 @@
+; RUN: opt -mtriple=aarch64--none-eabi  < %s -tailcallelim -S | FileCheck %s --check-prefix=NONE
+; RUN: opt -mtriple=aarch64--linux-eabi < %s -tailcallelim -S | FileCheck %s --check-prefix=LINUX
+
+declare extern_weak void @weak_function()
+
+; Don't tail call to a weak symbol on bare metal AArch64
+define void @func1() {
+; NONE-NOT: tail call
+; LINUX: tail call
+  call void @weak_function()
+  ret void
+}
Index: test/Transforms/TailCallElim/ARM/lit.local.cfg
===================================================================
--- /dev/null
+++ test/Transforms/TailCallElim/ARM/lit.local.cfg
@@ -0,0 +1,3 @@
+if not 'ARM' in config.root.targets:
+    config.unsupported = True
+
Index: test/Transforms/TailCallElim/ARM/weak-linkage.ll
===================================================================
--- /dev/null
+++ test/Transforms/TailCallElim/ARM/weak-linkage.ll
@@ -0,0 +1,12 @@
+; RUN: opt -mtriple=armv7a--none-eabi  < %s -tailcallelim -S | FileCheck %s --check-prefix=NONE
+; RUN: opt -mtriple=armv7a--linux-eabi < %s -tailcallelim -S | FileCheck %s --check-prefix=LINUX
+
+declare extern_weak void @weak_function()
+
+; Don't tail call to a weak symbol on bare metal ARM
+define void @func1() {
+; NONE-NOT: tail call
+; LINUX: tail call
+  call void @weak_function()
+  ret void
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D4906.12551.patch
Type: text/x-patch
Size: 3590 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140815/25d5af99/attachment.bin>


More information about the llvm-commits mailing list