[llvm] r346532 - [Hexagon] Implement noreturn optimization

Brendon Cahoon via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 9 10:16:25 PST 2018


Author: bcahoon
Date: Fri Nov  9 10:16:24 2018
New Revision: 346532

URL: http://llvm.org/viewvc/llvm-project?rev=346532&view=rev
Log:
[Hexagon] Implement noreturn optimization

Eliminate the stack frame in functions with the noreturn nounwind
attributes, and when the noreturn-stack-elim target feature is
enabled. This reduces the code and stack space needed for noreturn
functions.

Differential Revision: https://reviews.llvm.org/D54210


Added:
    llvm/trunk/test/CodeGen/Hexagon/noreturn-stack-elim.ll
Modified:
    llvm/trunk/lib/Target/Hexagon/Hexagon.td
    llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp
    llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h
    llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.h

Modified: llvm/trunk/lib/Target/Hexagon/Hexagon.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/Hexagon.td?rev=346532&r1=346531&r2=346532&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/Hexagon.td (original)
+++ llvm/trunk/lib/Target/Hexagon/Hexagon.td Fri Nov  9 10:16:24 2018
@@ -60,6 +60,9 @@ def FeatureDuplex: SubtargetFeature<"dup
       "Enable generation of duplex instruction">;
 def FeatureReservedR19: SubtargetFeature<"reserved-r19", "ReservedR19",
       "true", "Reserve register R19">;
+def FeatureNoreturnStackElim: SubtargetFeature<"noreturn-stack-elim",
+      "NoreturnStackElim", "true",
+      "Eliminate stack allocation in a noreturn function when possible">;
 
 //===----------------------------------------------------------------------===//
 // Hexagon Instruction Predicate Definitions.

Modified: llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp?rev=346532&r1=346531&r2=346532&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.cpp Fri Nov  9 10:16:24 2018
@@ -550,6 +550,36 @@ void HexagonFrameLowering::emitPrologue(
   }
 }
 
+/// Returns true if the target can safely skip saving callee-saved registers
+/// for noreturn nounwind functions.
+bool HexagonFrameLowering::enableCalleeSaveSkip(
+    const MachineFunction &MF) const {
+  const auto &F = MF.getFunction();
+  assert(F.hasFnAttribute(Attribute::NoReturn) &&
+         F.getFunction().hasFnAttribute(Attribute::NoUnwind) &&
+         !F.getFunction().hasFnAttribute(Attribute::UWTable));
+
+  // No need to save callee saved registers if the function does not return.
+  return MF.getSubtarget<HexagonSubtarget>().noreturnStackElim();
+}
+
+// Helper function used to determine when to eliminate the stack frame for
+// functions marked as noreturn and when the noreturn-stack-elim options are
+// specified. When both these conditions are true, then a FP may not be needed
+// if the function makes a call. It is very similar to enableCalleeSaveSkip,
+// but it used to check if the allocframe can be eliminated as well.
+static bool enableAllocFrameElim(const MachineFunction &MF) {
+  const auto &F = MF.getFunction();
+  const auto &MFI = MF.getFrameInfo();
+  const auto &HST = MF.getSubtarget<HexagonSubtarget>();
+  assert(!MFI.hasVarSizedObjects() &&
+         !HST.getRegisterInfo()->needsStackRealignment(MF));
+  return F.hasFnAttribute(Attribute::NoReturn) &&
+    F.hasFnAttribute(Attribute::NoUnwind) &&
+    !F.hasFnAttribute(Attribute::UWTable) && HST.noreturnStackElim() &&
+    MFI.getStackSize() == 0;
+}
+
 void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB,
       bool PrologueStubs) const {
   MachineFunction &MF = *MBB.getParent();
@@ -994,7 +1024,7 @@ bool HexagonFrameLowering::hasFP(const M
   }
 
   const auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
-  if (MFI.hasCalls() || HMFI.hasClobberLR())
+  if ((MFI.hasCalls() && !enableAllocFrameElim(MF)) || HMFI.hasClobberLR())
     return true;
 
   return false;

Modified: llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h?rev=346532&r1=346531&r2=346532&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonFrameLowering.h Fri Nov  9 10:16:24 2018
@@ -41,6 +41,8 @@ public:
   void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const
       override {}
 
+  bool enableCalleeSaveSkip(const MachineFunction &MF) const override;
+
   bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
       MachineBasicBlock::iterator MI, const std::vector<CalleeSavedInfo> &CSI,
       const TargetRegisterInfo *TRI) const override {

Modified: llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.h?rev=346532&r1=346531&r2=346532&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.h (original)
+++ llvm/trunk/lib/Target/Hexagon/HexagonSubtarget.h Fri Nov  9 10:16:24 2018
@@ -56,6 +56,7 @@ class HexagonSubtarget : public HexagonG
   bool HasMemNoShuf = false;
   bool EnableDuplex = false;
   bool ReservedR19 = false;
+  bool NoreturnStackElim = false;
 
 public:
   Hexagon::ArchEnum HexagonArchVersion;
@@ -168,6 +169,8 @@ public:
   bool hasReservedR19() const { return ReservedR19; }
   bool usePredicatedCalls() const;
 
+  bool noreturnStackElim() const { return NoreturnStackElim; }
+
   bool useBSBScheduling() const { return UseBSBScheduling; }
   bool enableMachineScheduler() const override;
 

Added: llvm/trunk/test/CodeGen/Hexagon/noreturn-stack-elim.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Hexagon/noreturn-stack-elim.ll?rev=346532&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Hexagon/noreturn-stack-elim.ll (added)
+++ llvm/trunk/test/CodeGen/Hexagon/noreturn-stack-elim.ll Fri Nov  9 10:16:24 2018
@@ -0,0 +1,94 @@
+; RUN: llc -mtriple=hexagon-unknown--elf -hexagon-initial-cfg-cleanup=false < %s | FileCheck %s
+; RUN: llc -mtriple=hexagon-unknown--elf -hexagon-initial-cfg-cleanup=false -mattr=+noreturn-stack-elim < %s | FileCheck %s --check-prefix=CHECK-FLAG
+
+; Test the noreturn stack elimination feature. We've added a new flag/feature
+; that attempts to eliminate the local stack for noreturn nounwind functions.
+; The optimization eliminates the need to save callee saved registers, and
+; eliminates the allocframe, when no local stack space is needed.
+
+%struct.A = type { i32, i32 }
+
+; Test the case when noreturn-stack-elim determins that both callee saved
+; register do not need to be saved, and the allocframe can be eliminated.
+
+; CHECK-LABEL: test1
+; CHECK: memd(r29+#-16) = r17:16
+; CHECK: allocframe
+
+; CHECK-FLAG-LABEL: test1
+; CHECK-FLAG-NOT: memd(r29+#-16) = r17:16
+; CHECK-FLAG-NOT: allocframe
+
+define dso_local void @test1(i32 %a, %struct.A* %b) local_unnamed_addr #0 {
+entry:
+  %n = getelementptr inbounds %struct.A, %struct.A* %b, i32 0, i32 0
+  store i32 %a, i32* %n, align 4
+  tail call void @f1() #3
+  tail call void @nrf1(%struct.A* %b) #4
+  unreachable
+}
+
+; Test that noreturn-stack-elim doesn't eliminate the local stack, when
+; a function needs to allocate a local variable.
+
+; CHECK-LABEL: test2
+; CHECK: allocframe
+
+; CHECK-FLAG-LABEL: test2
+; CHECK-FLAG: allocframe
+
+define dso_local void @test2() local_unnamed_addr #0 {
+entry:
+  %a = alloca i32, align 4
+  %0 = bitcast i32* %a to i8*
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) #4
+  call void @f3(i32* nonnull %a) #4
+  unreachable
+}
+
+; Test that noreturn-stack-elim can elimnate the allocframe when no locals
+; are allocated on the stack.
+
+; CHECK-LABEL: test3
+; CHECK: allocframe
+
+; CHECK-FLAG-LABEL: test3
+; CHECK-FLAG-NOT: allocframe
+
+define dso_local void @test3(i32 %a) local_unnamed_addr #0 {
+entry:
+  %add = add nsw i32 %a, 5
+  call void @f2(i32 %add)
+  unreachable
+}
+
+; Test that nothing is optimized when an alloca is needed for local stack.
+
+; CHECK-LABEL: test4
+; CHECK: allocframe
+
+; CHECK-FLAG-LABEL: test4
+; CHECK-FLAG: allocframe
+
+define dso_local void @test4(i32 %n) local_unnamed_addr #0 {
+entry:
+  %vla = alloca i32, i32 %n, align 8
+  call void @f3(i32* nonnull %vla) #4
+  unreachable
+}
+
+
+declare dso_local void @f1() local_unnamed_addr
+declare dso_local void @f2(i32) local_unnamed_addr
+declare dso_local void @f3(i32*) local_unnamed_addr
+
+declare dso_local void @nrf1(%struct.A*) local_unnamed_addr #2
+
+declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #5
+
+attributes #0 = { noreturn nounwind }
+attributes #2 = { noreturn }
+attributes #3 = { nounwind }
+attributes #4 = { noreturn nounwind }
+attributes #5 = { argmemonly nounwind }
+




More information about the llvm-commits mailing list