[PATCH] D40706: Fix function pointer tail calls in armv8-M.base

Pablo Barrio via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 1 02:34:44 PST 2017


pbarrio created this revision.
Herald added subscribers: kristof.beyls, javed.absar, aemerson.

The compiler fails with the following error message:

fatal error: error in backend: ran out of registers during
register allocation

Tail call optimization for Armv8-M.base fails to meet all the required
constraints when handling calls to function pointers where the
arguments take up r0-r3. This is because the pointer to the
function to be called can only be stored in r0-r3, but these are
all occupied by arguments. This patch makes sure that tail call
optimization does not try to handle this type of calls.


https://reviews.llvm.org/D40706

Files:
  lib/Target/ARM/ARMISelLowering.cpp
  test/CodeGen/ARM/v8m-tail-call.ll


Index: test/CodeGen/ARM/v8m-tail-call.ll
===================================================================
--- test/CodeGen/ARM/v8m-tail-call.ll
+++ test/CodeGen/ARM/v8m-tail-call.ll
@@ -45,3 +45,46 @@
 ; CHECK-NEXT: add     sp, #4
 ; CHECK-NEXT: b       h2
 }
+
+; Make sure that tail calls to function pointers that require r0-r3 for argument
+; passing do not break the compiler.
+ at fnptr = global i32 (i32, i32, i32, i32)* null
+define i32 @test3() {
+; CHECK-LABEL: test3:
+  %1 = load i32 (i32, i32, i32, i32)*, i32 (i32, i32, i32, i32)** @fnptr
+  %2 = tail call i32 %1(i32 1, i32 2, i32 3, i32 4)
+  ret i32 %2
+}
+
+ at fnptr2 = global i32 (i32, i32, i64)* null
+define i32 @test4() {
+; CHECK-LABEL: test4:
+  %1 = load i32 (i32, i32, i64)*, i32 (i32, i32, i64)** @fnptr2
+  %2 = tail call i32 %1(i32 1, i32 2, i64 3)
+  ret i32 %2
+}
+
+; Check that tail calls to function pointers where not all of r0-r3 are used for
+; parameter passing are tail-call optimized.
+ at fnptr3 = global i32 (i32, i32)* null
+define i32 @test5() {
+; CHECK-LABEL: test5:
+; CHECK: ldr [[REG:r[0-9]+]]
+; CHECK: bx [[REG]]
+; CHECK-NOT: blx [[REG]]
+  %1 = load i32 (i32, i32)*, i32 (i32, i32)** @fnptr3
+  %2 = tail call i32 %1(i32 1, i32 2)
+  ret i32 %2
+}
+
+; Check that tail calls to functions other than function pointers are
+; tail-call optimized.
+define i32 @test6() {
+; CHECK-LABEL: test6:
+; CHECK: b bar
+; CHECK-NOT: bl bar
+  %tail = tail call i32 @bar(i32 1, i32 2, i32 3, i32 4)
+  ret i32 %tail
+}
+
+declare i32 @bar(i32, i32, i32, i32)
Index: lib/Target/ARM/ARMISelLowering.cpp
===================================================================
--- lib/Target/ARM/ARMISelLowering.cpp
+++ lib/Target/ARM/ARMISelLowering.cpp
@@ -2282,6 +2282,13 @@
 
   assert(Subtarget->supportsTailCall());
 
+  // Tail calls to function pointers cannot be optimized for Thumb1 if the args
+  // to the call take up r0-r3. The reason is that there are no legal registers
+  // left to hold the pointer to the function to be called.
+  if (Subtarget->isThumb1Only() && Outs.size() >= 4 &&
+      isa<LoadSDNode>(Callee.getNode()))
+      return false;
+
   // Look for obvious safe cases to perform tail call optimization that do not
   // require ABI changes. This is what gcc calls sibcall.
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D40706.125089.patch
Type: text/x-patch
Size: 2286 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20171201/d899802c/attachment.bin>


More information about the llvm-commits mailing list