[llvm] r329494 - Reapply ARM: Do not spill CSR to stack on entry to noreturn functions

Tim Northover via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 7 03:57:03 PDT 2018


Author: tnorthover
Date: Sat Apr  7 03:57:03 2018
New Revision: 329494

URL: http://llvm.org/viewvc/llvm-project?rev=329494&view=rev
Log:
Reapply ARM: Do not spill CSR to stack on entry to noreturn functions

Should fix UBSan bot by also checking there's no "uwtable" attribute
before skipping. Otherwise the unwind table will be useless since its
moves expect CSRs to actually be preserved.

A noreturn nounwind function can be expected to never return in any way, and by
never returning it will also never have to restore any callee-saved registers
for its caller. This makes it possible to skip spills of those registers during
function entry, saving some stack space and time in the process. This is rather
useful for embedded targets with limited stack space.

Should fix PR9970.

Patch mostly by myeisha (pmb).

Added:
    llvm/trunk/test/CodeGen/ARM/noreturn-csr-skip.mir
Modified:
    llvm/trunk/include/llvm/CodeGen/TargetFrameLowering.h
    llvm/trunk/lib/CodeGen/TargetFrameLoweringImpl.cpp
    llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp
    llvm/trunk/lib/Target/ARM/ARMFrameLowering.h
    llvm/trunk/test/CodeGen/AArch64/arm64-shrink-wrapping.ll
    llvm/trunk/test/CodeGen/ARM/arm-shrink-wrapping.ll
    llvm/trunk/test/CodeGen/PowerPC/ppc-shrink-wrapping.ll
    llvm/trunk/test/CodeGen/Thumb/thumb-shrink-wrapping.ll
    llvm/trunk/test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll
    llvm/trunk/test/CodeGen/X86/x86-shrink-wrapping.ll

Modified: llvm/trunk/include/llvm/CodeGen/TargetFrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/TargetFrameLowering.h?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/TargetFrameLowering.h (original)
+++ llvm/trunk/include/llvm/CodeGen/TargetFrameLowering.h Sat Apr  7 03:57:03 2018
@@ -158,6 +158,10 @@ public:
     return false;
   }
 
+  /// Returns true if the target can safely skip saving callee-saved registers
+  /// for noreturn nounwind functions.
+  virtual bool enableCalleeSaveSkip(const MachineFunction &MF) const;
+
   /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
   /// the function.
   virtual void emitPrologue(MachineFunction &MF,

Modified: llvm/trunk/lib/CodeGen/TargetFrameLoweringImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetFrameLoweringImpl.cpp?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/TargetFrameLoweringImpl.cpp (original)
+++ llvm/trunk/lib/CodeGen/TargetFrameLoweringImpl.cpp Sat Apr  7 03:57:03 2018
@@ -36,6 +36,13 @@ bool TargetFrameLowering::noFramePointer
   return Attr.getValueAsString() == "true";
 }
 
+bool TargetFrameLowering::enableCalleeSaveSkip(const MachineFunction &MF) const {
+  assert(MF.getFunction().hasFnAttribute(Attribute::NoReturn) &&
+         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
+         !MF.getFunction().hasFnAttribute(Attribute::UWTable));
+  return false;
+}
+
 /// Returns the displacement from the frame register to the stack
 /// frame of the specified index, along with the frame register used
 /// (in output arg FrameReg). This is the default implementation which
@@ -85,6 +92,19 @@ void TargetFrameLowering::determineCalle
   if (MF.getFunction().hasFnAttribute(Attribute::Naked))
     return;
 
+  // Noreturn+nounwind functions never restore CSR, so no saves are needed.
+  // Purely noreturn functions may still return through throws, so those must
+  // save CSR for caller exception handlers.
+  //
+  // If the function uses longjmp to break out of its current path of
+  // execution we do not need the CSR spills either: setjmp stores all CSRs
+  // it was called with into the jmp_buf, which longjmp then restores.
+  if (MF.getFunction().hasFnAttribute(Attribute::NoReturn) &&
+        MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
+        !MF.getFunction().hasFnAttribute(Attribute::UWTable) &&
+        enableCalleeSaveSkip(MF))
+    return;
+
   // Functions which call __builtin_unwind_init get all their registers saved.
   bool CallsUnwindInit = MF.callsUnwindInit();
   const MachineRegisterInfo &MRI = MF.getRegInfo();

Modified: llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMFrameLowering.cpp Sat Apr  7 03:57:03 2018
@@ -87,6 +87,18 @@ bool ARMFrameLowering::noFramePointerEli
          MF.getSubtarget<ARMSubtarget>().useFastISel();
 }
 
+/// Returns true if the target can safely skip saving callee-saved registers
+/// for noreturn nounwind functions.
+bool ARMFrameLowering::enableCalleeSaveSkip(const MachineFunction &MF) const {
+  assert(MF.getFunction().hasFnAttribute(Attribute::NoReturn) &&
+         MF.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
+         !MF.getFunction().hasFnAttribute(Attribute::UWTable));
+
+  // Frame pointer and link register are not treated as normal CSR, thus we
+  // can always skip CSR saves for nonreturning functions.
+  return true;
+}
+
 /// hasFP - Return true if the specified function should have a dedicated frame
 /// pointer register.  This is true if the function has variable sized allocas
 /// or if frame pointer elimination is disabled.

Modified: llvm/trunk/lib/Target/ARM/ARMFrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMFrameLowering.h?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMFrameLowering.h (original)
+++ llvm/trunk/lib/Target/ARM/ARMFrameLowering.h Sat Apr  7 03:57:03 2018
@@ -44,6 +44,8 @@ public:
 
   bool noFramePointerElim(const MachineFunction &MF) const override;
 
+  bool enableCalleeSaveSkip(const MachineFunction &MF) const override;
+
   bool hasFP(const MachineFunction &MF) const override;
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
   bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;

Modified: llvm/trunk/test/CodeGen/AArch64/arm64-shrink-wrapping.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/arm64-shrink-wrapping.ll?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/arm64-shrink-wrapping.ll (original)
+++ llvm/trunk/test/CodeGen/AArch64/arm64-shrink-wrapping.ll Sat Apr  7 03:57:03 2018
@@ -281,7 +281,7 @@ declare void @somethingElse(...)
 ; Shift second argument by one and store into returned register.
 ; ENABLE: lsl w0, w1, #1
 ; ENABLE: ret
-define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
+define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind {
 entry:
   %tobool = icmp eq i32 %cond, 0
   br i1 %tobool, label %if.else, label %if.then
@@ -355,7 +355,7 @@ entry:
 ; CHECK-NEXT: lsl w0, w1, #1
 ; DISABLE-NEXT: add sp, sp, #16
 ; CHECK-NEXT: ret
-define i32 @variadicFunc(i32 %cond, i32 %count, ...) #0 {
+define i32 @variadicFunc(i32 %cond, i32 %count, ...) nounwind {
 entry:
   %ap = alloca i8*, align 8
   %tobool = icmp eq i32 %cond, 0

Modified: llvm/trunk/test/CodeGen/ARM/arm-shrink-wrapping.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/arm-shrink-wrapping.ll?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/arm-shrink-wrapping.ll (original)
+++ llvm/trunk/test/CodeGen/ARM/arm-shrink-wrapping.ll Sat Apr  7 03:57:03 2018
@@ -327,7 +327,7 @@ declare void @somethingElse(...)
 ; DISABLE-NEXT: pop {r4, r7, pc}
 ;
 ; ENABLE-NEXT: bx lr
-define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) "no-frame-pointer-elim"="true" #0 {
+define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) "no-frame-pointer-elim"="true" nounwind {
 entry:
   %tobool = icmp eq i32 %cond, 0
   br i1 %tobool, label %if.else, label %if.then

Added: llvm/trunk/test/CodeGen/ARM/noreturn-csr-skip.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/noreturn-csr-skip.mir?rev=329494&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/ARM/noreturn-csr-skip.mir (added)
+++ llvm/trunk/test/CodeGen/ARM/noreturn-csr-skip.mir Sat Apr  7 03:57:03 2018
@@ -0,0 +1,65 @@
+# RUN: llc -mtriple thumbv7m-none-eabi -run-pass prologepilog %s -o - | FileCheck %s
+
+--- |
+  define void @throw() noreturn { unreachable }
+
+  define void @ret() nounwind { ret void }
+
+  define void @tables() nounwind noreturn uwtable { ret void }
+
+  define void @noret() noreturn nounwind {
+  start:
+    %p = alloca i32
+    store i32 42, i32* %p
+    unreachable
+  }
+...
+---
+# This function may return by exception. Check that $r4 is saved and restored.
+# CHECK-LABEL: name: throw
+# CHECK: killed $r4
+# CHECK: def $r4
+name: throw
+body: |
+  bb.0:
+    $r4 = IMPLICIT_DEF
+    tBX_RET 14, $noreg
+---
+---
+# This function may return. Check that $r4 is saved and restored.
+# CHECK-LABEL: name: ret
+# CHECK: killed $r4
+# CHECK: def $r4
+name: ret
+body: |
+  bb.0:
+    $r4 = IMPLICIT_DEF
+    tBX_RET 14, $noreg
+---
+---
+# This function needs correct unwind tables anyway. Check that $r4 is saved and
+# restored.
+# CHECK-LABEL: name: tables
+# CHECK: killed $r4
+# CHECK: def $r4
+name: tables
+body: |
+  bb.0:
+    $r4 = IMPLICIT_DEF
+    tBX_RET 14, $noreg
+---
+---
+# This function does not return. We need not save any CSR, but
+# other stack adjustments in the prologue are still necessary.
+# CHECK-LABEL: name: noret
+# CHECK-NOT: killed $r4
+# CHECK-NOT: def $r4
+# CHECK: $sp = frame-setup
+name: noret
+stack:
+  - { id: 0, name: p, offset: 0, size: 4, alignment: 4, local-offset: -4 }
+body: |
+  bb.0:
+    $r4 = IMPLICIT_DEF
+    tBX_RET 14, $noreg
+---

Modified: llvm/trunk/test/CodeGen/PowerPC/ppc-shrink-wrapping.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/PowerPC/ppc-shrink-wrapping.ll?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/PowerPC/ppc-shrink-wrapping.ll (original)
+++ llvm/trunk/test/CodeGen/PowerPC/ppc-shrink-wrapping.ll Sat Apr  7 03:57:03 2018
@@ -328,7 +328,7 @@ declare void @somethingElse(...)
 ; Shift second argument by one and store into returned register.
 ; ENABLE: slwi 3, 4, 1
 ; ENABLE-NEXT: blr
-define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
+define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind {
 entry:
   %tobool = icmp eq i32 %cond, 0
   br i1 %tobool, label %if.else, label %if.then

Modified: llvm/trunk/test/CodeGen/Thumb/thumb-shrink-wrapping.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Thumb/thumb-shrink-wrapping.ll?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/Thumb/thumb-shrink-wrapping.ll (original)
+++ llvm/trunk/test/CodeGen/Thumb/thumb-shrink-wrapping.ll Sat Apr  7 03:57:03 2018
@@ -374,7 +374,7 @@ declare void @somethingElse(...)
 ;
 ; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
 ; ENABLE-NEXT: bx lr
-define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
+define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind {
 entry:
   %tobool = icmp eq i32 %cond, 0
   br i1 %tobool, label %if.else, label %if.then

Modified: llvm/trunk/test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll (original)
+++ llvm/trunk/test/CodeGen/X86/2010-02-19-TailCallRetAddrBug.ll Sat Apr  7 03:57:03 2018
@@ -17,10 +17,10 @@
 
 %tupl = type [9 x i32]
 
-declare fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) noreturn nounwind
-declare fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) noreturn nounwind
+declare fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) nounwind
+declare fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) nounwind
 
-define fastcc void @l186(%tupl* %r1) noreturn nounwind {
+define fastcc void @l186(%tupl* %r1) nounwind {
 entry:
   %ptr1 = getelementptr %tupl, %tupl* %r1, i32 0, i32 0
   %r2 = load i32, i32* %ptr1
@@ -44,10 +44,10 @@ entry:
   br i1 %cond, label %true, label %false
 
 true:
-  tail call fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) noreturn nounwind
+  tail call fastcc void @l297(i32 %r10, i32 %r9, i32 %r8, i32 %r7, i32 %r6, i32 %r5, i32 %r3, i32 %r2) nounwind
   ret void
 
 false:
-  tail call fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) noreturn nounwind
+  tail call fastcc void @l298(i32 %r10, i32 %r9, i32 %r4) nounwind
   ret void
 }

Modified: llvm/trunk/test/CodeGen/X86/x86-shrink-wrapping.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/x86-shrink-wrapping.ll?rev=329494&r1=329493&r2=329494&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/x86-shrink-wrapping.ll (original)
+++ llvm/trunk/test/CodeGen/X86/x86-shrink-wrapping.ll Sat Apr  7 03:57:03 2018
@@ -314,7 +314,7 @@ if.end:
 ; ENABLE: addl %esi, %esi
 ; ENABLE-NEXT: movl %esi, %eax
 ; ENABLE-NEXT: retq
-define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
+define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) nounwind {
 entry:
   %tobool = icmp eq i32 %cond, 0
   br i1 %tobool, label %if.else, label %if.then




More information about the llvm-commits mailing list