[llvm] ad4a582 - [llvm] Consistently respect `naked` fn attribute in `TargetFrameLowering::hasFP()` (#106014)

via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 17 22:35:46 PDT 2024


Author: Alex Rønne Petersen
Date: 2024-10-18T09:35:42+04:00
New Revision: ad4a582fd938c933e784f0052bd773676b37b690

URL: https://github.com/llvm/llvm-project/commit/ad4a582fd938c933e784f0052bd773676b37b690
DIFF: https://github.com/llvm/llvm-project/commit/ad4a582fd938c933e784f0052bd773676b37b690.diff

LOG: [llvm] Consistently respect `naked` fn attribute in `TargetFrameLowering::hasFP()` (#106014)

Some targets (e.g. PPC and Hexagon) already did this. I think it's best
to do this consistently so that frontend authors don't run into
inconsistent results when they emit `naked` functions. For example, in
Zig, we had to change our emit code to also set `frame-pointer=none` to
get reliable results across targets.

Note: I don't have commit access.

Added: 
    llvm/test/CodeGen/AArch64/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/AMDGPU/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/ARM/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/AVR/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/CSKY/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/Hexagon/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/Lanai/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/LoongArch/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/M68k/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/MSP430/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/Mips/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/NVPTX/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/PowerPC/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/RISCV/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/SPARC/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/SystemZ/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/VE/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/X86/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/XCore/naked-fn-with-frame-pointer.ll
    llvm/test/CodeGen/Xtensa/naked-fn-with-frame-pointer.ll

Modified: 
    llvm/include/llvm/CodeGen/TargetFrameLowering.h
    llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
    llvm/lib/Target/AArch64/AArch64FrameLowering.h
    llvm/lib/Target/AMDGPU/R600FrameLowering.h
    llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
    llvm/lib/Target/AMDGPU/SIFrameLowering.h
    llvm/lib/Target/ARC/ARCFrameLowering.cpp
    llvm/lib/Target/ARC/ARCFrameLowering.h
    llvm/lib/Target/ARM/ARMFrameLowering.cpp
    llvm/lib/Target/ARM/ARMFrameLowering.h
    llvm/lib/Target/AVR/AVRFrameLowering.cpp
    llvm/lib/Target/AVR/AVRFrameLowering.h
    llvm/lib/Target/BPF/BPFFrameLowering.cpp
    llvm/lib/Target/BPF/BPFFrameLowering.h
    llvm/lib/Target/CSKY/CSKYFrameLowering.cpp
    llvm/lib/Target/CSKY/CSKYFrameLowering.h
    llvm/lib/Target/DirectX/DirectXFrameLowering.h
    llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
    llvm/lib/Target/Hexagon/HexagonFrameLowering.h
    llvm/lib/Target/Lanai/LanaiFrameLowering.h
    llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
    llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
    llvm/lib/Target/M68k/M68kFrameLowering.cpp
    llvm/lib/Target/M68k/M68kFrameLowering.h
    llvm/lib/Target/MSP430/MSP430FrameLowering.cpp
    llvm/lib/Target/MSP430/MSP430FrameLowering.h
    llvm/lib/Target/Mips/MipsFrameLowering.cpp
    llvm/lib/Target/Mips/MipsFrameLowering.h
    llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp
    llvm/lib/Target/NVPTX/NVPTXFrameLowering.h
    llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
    llvm/lib/Target/PowerPC/PPCFrameLowering.h
    llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
    llvm/lib/Target/RISCV/RISCVFrameLowering.h
    llvm/lib/Target/SPIRV/SPIRVFrameLowering.h
    llvm/lib/Target/Sparc/SparcFrameLowering.cpp
    llvm/lib/Target/Sparc/SparcFrameLowering.h
    llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
    llvm/lib/Target/SystemZ/SystemZFrameLowering.h
    llvm/lib/Target/VE/VEFrameLowering.cpp
    llvm/lib/Target/VE/VEFrameLowering.h
    llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
    llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
    llvm/lib/Target/X86/X86FrameLowering.cpp
    llvm/lib/Target/X86/X86FrameLowering.h
    llvm/lib/Target/XCore/XCoreFrameLowering.cpp
    llvm/lib/Target/XCore/XCoreFrameLowering.h
    llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
    llvm/lib/Target/Xtensa/XtensaFrameLowering.h
    llvm/unittests/CodeGen/MFCommon.inc

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/TargetFrameLowering.h b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
index 9882d851187578..97de0197da9b40 100644
--- a/llvm/include/llvm/CodeGen/TargetFrameLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetFrameLowering.h
@@ -280,7 +280,11 @@ class TargetFrameLowering {
   /// hasFP - Return true if the specified function should have a dedicated
   /// frame pointer register. For most targets this is true only if the function
   /// has variable sized allocas or if frame pointer elimination is disabled.
-  virtual bool hasFP(const MachineFunction &MF) const = 0;
+  /// For all targets, this is false if the function has the naked attribute
+  /// since there is no prologue to set up the frame pointer.
+  bool hasFP(const MachineFunction &MF) const {
+    return !MF.getFunction().hasFnAttribute(Attribute::Naked) && hasFPImpl(MF);
+  }
 
   /// hasReservedCallFrame - Under normal circumstances, when a frame pointer is
   /// not required, we reserve argument space for call sites in the function
@@ -477,6 +481,9 @@ class TargetFrameLowering {
   /// targets can emit remarks based on the final frame layout.
   virtual void emitRemarks(const MachineFunction &MF,
                            MachineOptimizationRemarkEmitter *ORE) const {};
+
+protected:
+  virtual bool hasFPImpl(const MachineFunction &MF) const = 0;
 };
 
 } // End llvm namespace

diff  --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 1b8eac7fac21f7..bbf2f267795457 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -480,9 +480,9 @@ bool AArch64FrameLowering::canUseRedZone(const MachineFunction &MF) const {
            getSVEStackSize(MF) || LowerQRegCopyThroughMem);
 }
 
-/// hasFP - Return true if the specified function should have a dedicated frame
-/// pointer register.
-bool AArch64FrameLowering::hasFP(const MachineFunction &MF) const {
+/// hasFPImpl - Return true if the specified function should have a dedicated
+/// frame pointer register.
+bool AArch64FrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 

diff  --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.h b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
index c1973124962085..20445e63bcb13e 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.h
@@ -65,7 +65,6 @@ class AArch64FrameLowering : public TargetFrameLowering {
   /// Can this function use the red zone for local allocations.
   bool canUseRedZone(const MachineFunction &MF) const;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
 
   bool assignCalleeSavedSpillSlots(MachineFunction &MF,
@@ -125,6 +124,9 @@ class AArch64FrameLowering : public TargetFrameLowering {
   orderFrameObjects(const MachineFunction &MF,
                     SmallVectorImpl<int> &ObjectsToAllocate) const override;
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   /// Returns true if a homogeneous prolog or epilog code can be emitted
   /// for the size optimization. If so, HOM_Prolog/HOM_Epilog pseudo

diff  --git a/llvm/lib/Target/AMDGPU/R600FrameLowering.h b/llvm/lib/Target/AMDGPU/R600FrameLowering.h
index f171bc4fea781f..c4621174acaba1 100644
--- a/llvm/lib/Target/AMDGPU/R600FrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/R600FrameLowering.h
@@ -27,9 +27,8 @@ class R600FrameLowering : public AMDGPUFrameLowering {
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  bool hasFP(const MachineFunction &MF) const override {
-    return false;
-  }
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override { return false; }
 };
 
 } // end namespace llvm

diff  --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
index bc162b0953a7be..13a2db7a87b437 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp
@@ -1805,7 +1805,7 @@ static bool frameTriviallyRequiresSP(const MachineFrameInfo &MFI) {
 // The FP for kernels is always known 0, so we never really need to setup an
 // explicit register for it. However, DisableFramePointerElim will force us to
 // use a register for it.
-bool SIFrameLowering::hasFP(const MachineFunction &MF) const {
+bool SIFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
 
   // For entry & chain functions we can use an immediate offset in most cases,

diff  --git a/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
index b3feb759ed811f..938c75099a3bc3 100644
--- a/llvm/lib/Target/AMDGPU/SIFrameLowering.h
+++ b/llvm/lib/Target/AMDGPU/SIFrameLowering.h
@@ -66,6 +66,9 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
                                 MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator MI) const override;
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   void emitEntryFunctionFlatScratchInit(MachineFunction &MF,
                                         MachineBasicBlock &MBB,
@@ -82,8 +85,6 @@ class SIFrameLowering final : public AMDGPUFrameLowering {
       Register ScratchWaveOffsetReg) const;
 
 public:
-  bool hasFP(const MachineFunction &MF) const override;
-
   bool requiresStackPointerReference(const MachineFunction &MF) const;
 };
 

diff  --git a/llvm/lib/Target/ARC/ARCFrameLowering.cpp b/llvm/lib/Target/ARC/ARCFrameLowering.cpp
index 1227fae13211a8..472f1c13f362e5 100644
--- a/llvm/lib/Target/ARC/ARCFrameLowering.cpp
+++ b/llvm/lib/Target/ARC/ARCFrameLowering.cpp
@@ -487,7 +487,7 @@ MachineBasicBlock::iterator ARCFrameLowering::eliminateCallFramePseudoInstr(
   return MBB.erase(I);
 }
 
-bool ARCFrameLowering::hasFP(const MachineFunction &MF) const {
+bool ARCFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
   bool HasFP = MF.getTarget().Options.DisableFramePointerElim(MF) ||
                MF.getFrameInfo().hasVarSizedObjects() ||

diff  --git a/llvm/lib/Target/ARC/ARCFrameLowering.h b/llvm/lib/Target/ARC/ARCFrameLowering.h
index 9951a09842c57f..089326fe32057e 100644
--- a/llvm/lib/Target/ARC/ARCFrameLowering.h
+++ b/llvm/lib/Target/ARC/ARCFrameLowering.h
@@ -54,8 +54,6 @@ class ARCFrameLowering : public TargetFrameLowering {
   void processFunctionBeforeFrameFinalized(MachineFunction &MF,
                                            RegScavenger *RS) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
-
   MachineBasicBlock::iterator
   eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator I) const override;
@@ -64,6 +62,9 @@ class ARCFrameLowering : public TargetFrameLowering {
       llvm::MachineFunction &, const llvm::TargetRegisterInfo *,
       std::vector<llvm::CalleeSavedInfo> &) const override;
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   void adjustStackToMatchRecords(MachineBasicBlock &MBB,
                                  MachineBasicBlock::iterator MI,

diff  --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
index 2706efa83fc3f1..82b6f808688eb0 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
@@ -323,10 +323,10 @@ bool ARMFrameLowering::enableCalleeSaveSkip(const MachineFunction &MF) const {
   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.
-bool ARMFrameLowering::hasFP(const MachineFunction &MF) const {
+/// hasFPImpl - 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.
+bool ARMFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
   const MachineFrameInfo &MFI = MF.getFrameInfo();
 

diff  --git a/llvm/lib/Target/ARM/ARMFrameLowering.h b/llvm/lib/Target/ARM/ARMFrameLowering.h
index 3c5bc00cb449f1..ff51f1a7af0229 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.h
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.h
@@ -45,7 +45,6 @@ class ARMFrameLowering : public TargetFrameLowering {
 
   bool enableCalleeSaveSkip(const MachineFunction &MF) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool isFPReserved(const MachineFunction &MF) const;
   bool requiresAAPCSFrameRecord(const MachineFunction &MF) const;
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
@@ -87,6 +86,9 @@ class ARMFrameLowering : public TargetFrameLowering {
   const SpillSlot *
   getCalleeSavedSpillSlots(unsigned &NumEntries) const override;
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   void emitPushInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
                     ArrayRef<CalleeSavedInfo> CSI, unsigned StmOpc,

diff  --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
index 64dd0338bf60ed..91b0f8c6b2df48 100644
--- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp
@@ -232,7 +232,7 @@ void AVRFrameLowering::emitEpilogue(MachineFunction &MF,
 //
 // Notice that strictly this is not a frame pointer because it contains SP after
 // frame allocation instead of having the original SP in function entry.
-bool AVRFrameLowering::hasFP(const MachineFunction &MF) const {
+bool AVRFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
 
   return (FuncInfo->getHasSpills() || FuncInfo->getHasAllocas() ||

diff  --git a/llvm/lib/Target/AVR/AVRFrameLowering.h b/llvm/lib/Target/AVR/AVRFrameLowering.h
index a550c0efbb8ef7..7baa5e9d62f60b 100644
--- a/llvm/lib/Target/AVR/AVRFrameLowering.h
+++ b/llvm/lib/Target/AVR/AVRFrameLowering.h
@@ -21,7 +21,6 @@ class AVRFrameLowering : public TargetFrameLowering {
 public:
   void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
   void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
-  bool hasFP(const MachineFunction &MF) const override;
   bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
                                  MachineBasicBlock::iterator MI,
                                  ArrayRef<CalleeSavedInfo> CSI,
@@ -38,6 +37,9 @@ class AVRFrameLowering : public TargetFrameLowering {
   MachineBasicBlock::iterator
   eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator MI) const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 
 } // end namespace llvm

diff  --git a/llvm/lib/Target/BPF/BPFFrameLowering.cpp b/llvm/lib/Target/BPF/BPFFrameLowering.cpp
index 8812cfdd86da43..123b99f254234d 100644
--- a/llvm/lib/Target/BPF/BPFFrameLowering.cpp
+++ b/llvm/lib/Target/BPF/BPFFrameLowering.cpp
@@ -20,7 +20,9 @@
 
 using namespace llvm;
 
-bool BPFFrameLowering::hasFP(const MachineFunction &MF) const { return true; }
+bool BPFFrameLowering::hasFPImpl(const MachineFunction &MF) const {
+  return true;
+}
 
 void BPFFrameLowering::emitPrologue(MachineFunction &MF,
                                     MachineBasicBlock &MBB) const {}

diff  --git a/llvm/lib/Target/BPF/BPFFrameLowering.h b/llvm/lib/Target/BPF/BPFFrameLowering.h
index a546351ec6cbbf..6beffcbe69dd0b 100644
--- a/llvm/lib/Target/BPF/BPFFrameLowering.h
+++ b/llvm/lib/Target/BPF/BPFFrameLowering.h
@@ -26,7 +26,6 @@ class BPFFrameLowering : public TargetFrameLowering {
   void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
   void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                             RegScavenger *RS) const override;
 
@@ -35,6 +34,9 @@ class BPFFrameLowering : public TargetFrameLowering {
                                 MachineBasicBlock::iterator MI) const override {
     return MBB.erase(MI);
   }
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 }
 #endif

diff  --git a/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp b/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp
index cedcbff1db24fc..c023b5a0de5ad5 100644
--- a/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp
+++ b/llvm/lib/Target/CSKY/CSKYFrameLowering.cpp
@@ -33,7 +33,7 @@ static Register getFPReg(const CSKYSubtarget &STI) { return CSKY::R8; }
 // callee saved register to save the value.
 static Register getBPReg(const CSKYSubtarget &STI) { return CSKY::R7; }
 
-bool CSKYFrameLowering::hasFP(const MachineFunction &MF) const {
+bool CSKYFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
   const MachineFrameInfo &MFI = MF.getFrameInfo();

diff  --git a/llvm/lib/Target/CSKY/CSKYFrameLowering.h b/llvm/lib/Target/CSKY/CSKYFrameLowering.h
index 69bf01cf1801e5..0b3b287bb6a55b 100644
--- a/llvm/lib/Target/CSKY/CSKYFrameLowering.h
+++ b/llvm/lib/Target/CSKY/CSKYFrameLowering.h
@@ -61,7 +61,6 @@ class CSKYFrameLowering : public TargetFrameLowering {
                               MutableArrayRef<CalleeSavedInfo> CSI,
                               const TargetRegisterInfo *TRI) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool hasBP(const MachineFunction &MF) const;
 
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
@@ -69,6 +68,9 @@ class CSKYFrameLowering : public TargetFrameLowering {
   MachineBasicBlock::iterator
   eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator MI) const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 } // namespace llvm
 #endif

diff  --git a/llvm/lib/Target/DirectX/DirectXFrameLowering.h b/llvm/lib/Target/DirectX/DirectXFrameLowering.h
index 76a1450054be81..85823556d55504 100644
--- a/llvm/lib/Target/DirectX/DirectXFrameLowering.h
+++ b/llvm/lib/Target/DirectX/DirectXFrameLowering.h
@@ -29,7 +29,8 @@ class DirectXFrameLowering : public TargetFrameLowering {
   void emitPrologue(MachineFunction &, MachineBasicBlock &) const override {}
   void emitEpilogue(MachineFunction &, MachineBasicBlock &) const override {}
 
-  bool hasFP(const MachineFunction &) const override { return false; }
+protected:
+  bool hasFPImpl(const MachineFunction &) const override { return false; }
 };
 } // namespace llvm
 #endif // LLVM_DIRECTX_DIRECTXFRAMELOWERING_H

diff  --git a/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp b/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
index 7c82f5e9f9a604..48acd9da9587fe 100644
--- a/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp
@@ -1144,10 +1144,7 @@ void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
   }
 }
 
-bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
-  if (MF.getFunction().hasFnAttribute(Attribute::Naked))
-    return false;
-
+bool HexagonFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   auto &MFI = MF.getFrameInfo();
   auto &HRI = *MF.getSubtarget<HexagonSubtarget>().getRegisterInfo();
   bool HasExtraAlign = HRI.hasStackRealignment(MF);

diff  --git a/llvm/lib/Target/Hexagon/HexagonFrameLowering.h b/llvm/lib/Target/Hexagon/HexagonFrameLowering.h
index 98e69dcc4b3915..926aadb01f50e5 100644
--- a/llvm/lib/Target/Hexagon/HexagonFrameLowering.h
+++ b/llvm/lib/Target/Hexagon/HexagonFrameLowering.h
@@ -89,7 +89,6 @@ class HexagonFrameLowering : public TargetFrameLowering {
 
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
-  bool hasFP(const MachineFunction &MF) const override;
 
   const SpillSlot *getCalleeSavedSpillSlots(unsigned &NumEntries)
       const override {
@@ -114,6 +113,9 @@ class HexagonFrameLowering : public TargetFrameLowering {
 
   void insertCFIInstructions(MachineFunction &MF) const;
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   using CSIVect = std::vector<CalleeSavedInfo>;
 

diff  --git a/llvm/lib/Target/Lanai/LanaiFrameLowering.h b/llvm/lib/Target/Lanai/LanaiFrameLowering.h
index 380d63df7301ef..9bd78d008f77e3 100644
--- a/llvm/lib/Target/Lanai/LanaiFrameLowering.h
+++ b/llvm/lib/Target/Lanai/LanaiFrameLowering.h
@@ -44,10 +44,11 @@ class LanaiFrameLowering : public TargetFrameLowering {
   eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator I) const override;
 
-  bool hasFP(const MachineFunction & /*MF*/) const override { return true; }
-
   void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                             RegScavenger *RS = nullptr) const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction & /*MF*/) const override { return true; }
 };
 
 } // namespace llvm

diff  --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
index 4e504729b23e2d..1a787c63c6241b 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
@@ -31,7 +31,7 @@ using namespace llvm;
 // pointer register.  This is true if frame pointer elimination is
 // disabled, if it needs dynamic stack realignment, if the function has
 // variable sized allocas, or if the frame address is taken.
-bool LoongArchFrameLowering::hasFP(const MachineFunction &MF) const {
+bool LoongArchFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
   const MachineFrameInfo &MFI = MF.getFrameInfo();

diff  --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
index bc2ac02c91f814..6cbfcf665f6a93 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
@@ -49,13 +49,15 @@ class LoongArchFrameLowering : public TargetFrameLowering {
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool hasBP(const MachineFunction &MF) const;
 
   uint64_t getFirstSPAdjustAmount(const MachineFunction &MF) const;
 
   bool enableShrinkWrapping(const MachineFunction &MF) const override;
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   void determineFrameLayout(MachineFunction &MF) const;
   void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,

diff  --git a/llvm/lib/Target/M68k/M68kFrameLowering.cpp b/llvm/lib/Target/M68k/M68kFrameLowering.cpp
index 1445bac0b92e85..4245061f0ae749 100644
--- a/llvm/lib/Target/M68k/M68kFrameLowering.cpp
+++ b/llvm/lib/Target/M68k/M68kFrameLowering.cpp
@@ -40,7 +40,7 @@ M68kFrameLowering::M68kFrameLowering(const M68kSubtarget &STI, Align Alignment)
   StackPtr = TRI->getStackRegister();
 }
 
-bool M68kFrameLowering::hasFP(const MachineFunction &MF) const {
+bool M68kFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
 

diff  --git a/llvm/lib/Target/M68k/M68kFrameLowering.h b/llvm/lib/Target/M68k/M68kFrameLowering.h
index a5349377232eb6..ed2bfb605ff13a 100644
--- a/llvm/lib/Target/M68k/M68kFrameLowering.h
+++ b/llvm/lib/Target/M68k/M68kFrameLowering.h
@@ -121,12 +121,6 @@ class M68kFrameLowering : public TargetFrameLowering {
                               MutableArrayRef<CalleeSavedInfo> CSI,
                               const TargetRegisterInfo *TRI) const override;
 
-  /// Return true if the specified function should have a dedicated frame
-  /// pointer register.  This is true if the function has variable sized
-  /// allocas, if it needs dynamic stack realignment, if frame pointer
-  /// elimination is disabled, or if the frame address is taken.
-  bool hasFP(const MachineFunction &MF) const override;
-
   /// Under normal circumstances, when a frame pointer is not required, we
   /// reserve argument space for call sites in the function immediately on
   /// entry to the current function. This eliminates the need for add/sub sp
@@ -166,6 +160,13 @@ class M68kFrameLowering : public TargetFrameLowering {
   /// pointer by a constant value.
   void emitSPUpdate(MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI,
                     int64_t NumBytes, bool InEpilogue) const;
+
+protected:
+  /// Return true if the specified function should have a dedicated frame
+  /// pointer register.  This is true if the function has variable sized
+  /// allocas, if it needs dynamic stack realignment, if frame pointer
+  /// elimination is disabled, or if the frame address is taken.
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 } // namespace llvm
 

diff  --git a/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp b/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp
index d0dc6dd146efdb..045dedfb385385 100644
--- a/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp
+++ b/llvm/lib/Target/MSP430/MSP430FrameLowering.cpp
@@ -30,7 +30,7 @@ MSP430FrameLowering::MSP430FrameLowering(const MSP430Subtarget &STI)
                           Align(2)),
       STI(STI), TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
 
-bool MSP430FrameLowering::hasFP(const MachineFunction &MF) const {
+bool MSP430FrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
 
   return (MF.getTarget().Options.DisableFramePointerElim(MF) ||

diff  --git a/llvm/lib/Target/MSP430/MSP430FrameLowering.h b/llvm/lib/Target/MSP430/MSP430FrameLowering.h
index 5227d3e731edb3..daa4eec998ee87 100644
--- a/llvm/lib/Target/MSP430/MSP430FrameLowering.h
+++ b/llvm/lib/Target/MSP430/MSP430FrameLowering.h
@@ -24,6 +24,7 @@ class MSP430RegisterInfo;
 
 class MSP430FrameLowering : public TargetFrameLowering {
 protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 
 public:
   MSP430FrameLowering(const MSP430Subtarget &STI);
@@ -51,7 +52,6 @@ class MSP430FrameLowering : public TargetFrameLowering {
                               MutableArrayRef<CalleeSavedInfo> CSI,
                               const TargetRegisterInfo *TRI) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
   void processFunctionBeforeFrameFinalized(MachineFunction &MF,
                                      RegScavenger *RS = nullptr) const override;

diff  --git a/llvm/lib/Target/Mips/MipsFrameLowering.cpp b/llvm/lib/Target/Mips/MipsFrameLowering.cpp
index 99d225f9abfe89..9b3edcd61ae1e2 100644
--- a/llvm/lib/Target/Mips/MipsFrameLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsFrameLowering.cpp
@@ -86,11 +86,11 @@ const MipsFrameLowering *MipsFrameLowering::create(const MipsSubtarget &ST) {
   return llvm::createMipsSEFrameLowering(ST);
 }
 
-// hasFP - Return true if the specified function should have a dedicated frame
-// pointer register.  This is true if the function has variable sized allocas,
-// if it needs dynamic stack realignment, if frame pointer elimination is
-// disabled, or if the frame address is taken.
-bool MipsFrameLowering::hasFP(const MachineFunction &MF) const {
+// hasFPImpl - Return true if the specified function should have a dedicated
+// frame pointer register.  This is true if the function has variable sized
+// allocas, if it needs dynamic stack realignment, if frame pointer elimination
+// is disabled, or if the frame address is taken.
+bool MipsFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   const TargetRegisterInfo *TRI = STI.getRegisterInfo();
 

diff  --git a/llvm/lib/Target/Mips/MipsFrameLowering.h b/llvm/lib/Target/Mips/MipsFrameLowering.h
index 710a3d40c38efc..25adc33fbf5cab 100644
--- a/llvm/lib/Target/Mips/MipsFrameLowering.h
+++ b/llvm/lib/Target/Mips/MipsFrameLowering.h
@@ -23,6 +23,8 @@ class MipsFrameLowering : public TargetFrameLowering {
 protected:
   const MipsSubtarget &STI;
 
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 public:
   explicit MipsFrameLowering(const MipsSubtarget &sti, Align Alignment)
       : TargetFrameLowering(StackGrowsDown, Alignment, 0, Alignment), STI(sti) {
@@ -30,8 +32,6 @@ class MipsFrameLowering : public TargetFrameLowering {
 
   static const MipsFrameLowering *create(const MipsSubtarget &ST);
 
-  bool hasFP(const MachineFunction &MF) const override;
-
   bool hasBP(const MachineFunction &MF) const;
 
   bool allocateScavengingFrameIndexesNearIncomingSP(

diff  --git a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp
index 9abe0e3186f200..a5f6cab421fb7e 100644
--- a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.cpp
@@ -27,7 +27,9 @@ using namespace llvm;
 NVPTXFrameLowering::NVPTXFrameLowering()
     : TargetFrameLowering(TargetFrameLowering::StackGrowsUp, Align(8), 0) {}
 
-bool NVPTXFrameLowering::hasFP(const MachineFunction &MF) const { return true; }
+bool NVPTXFrameLowering::hasFPImpl(const MachineFunction &MF) const {
+  return true;
+}
 
 void NVPTXFrameLowering::emitPrologue(MachineFunction &MF,
                                       MachineBasicBlock &MBB) const {

diff  --git a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h
index a5d49ac3ab2930..f8d1f978327bc0 100644
--- a/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h
+++ b/llvm/lib/Target/NVPTX/NVPTXFrameLowering.h
@@ -22,7 +22,6 @@ class NVPTXFrameLowering : public TargetFrameLowering {
 public:
   explicit NVPTXFrameLowering();
 
-  bool hasFP(const MachineFunction &MF) const override;
   void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
   void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
@@ -32,6 +31,9 @@ class NVPTXFrameLowering : public TargetFrameLowering {
   eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator I) const override;
   DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 
 } // End llvm namespace

diff  --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
index f7188b856461b7..1083febc5f8520 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp
@@ -355,9 +355,9 @@ PPCFrameLowering::determineFrameLayout(const MachineFunction &MF,
   return FrameSize;
 }
 
-// hasFP - Return true if the specified function actually has a dedicated frame
-// pointer register.
-bool PPCFrameLowering::hasFP(const MachineFunction &MF) const {
+// hasFPImpl - Return true if the specified function actually has a dedicated
+// frame pointer register.
+bool PPCFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   // FIXME: This is pretty much broken by design: hasFP() might be called really
   // early, before the stack layout was calculated and thus hasFP() might return

diff  --git a/llvm/lib/Target/PowerPC/PPCFrameLowering.h b/llvm/lib/Target/PowerPC/PPCFrameLowering.h
index d74c87428326ca..47f249862946f3 100644
--- a/llvm/lib/Target/PowerPC/PPCFrameLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCFrameLowering.h
@@ -107,7 +107,6 @@ class PPCFrameLowering: public TargetFrameLowering {
   void inlineStackProbe(MachineFunction &MF,
                         MachineBasicBlock &PrologMBB) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool needsFP(const MachineFunction &MF) const;
   void replaceFPWithRealFP(MachineFunction &MF) const;
 
@@ -176,6 +175,9 @@ class PPCFrameLowering: public TargetFrameLowering {
   void updateCalleeSaves(const MachineFunction &MF, BitVector &SavedRegs) const;
 
   uint64_t getStackThreshold() const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 } // End llvm namespace
 

diff  --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index f388376c12c943..b49cbab1876d79 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -309,7 +309,7 @@ static Register getMaxPushPopReg(const MachineFunction &MF,
 // pointer register.  This is true if frame pointer elimination is
 // disabled, if it needs dynamic stack realignment, if the function has
 // variable sized allocas, or if the frame address is taken.
-bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const {
+bool RISCVFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
   const MachineFrameInfo &MFI = MF.getFrameInfo();

diff  --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index d660f3ad67c968..f45fcdb0acd6bc 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
@@ -37,8 +37,6 @@ class RISCVFrameLowering : public TargetFrameLowering {
   void processFunctionBeforeFrameFinalized(MachineFunction &MF,
                                            RegScavenger *RS) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
-
   bool hasBP(const MachineFunction &MF) const;
 
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
@@ -83,6 +81,8 @@ class RISCVFrameLowering : public TargetFrameLowering {
 protected:
   const RISCVSubtarget &STI;
 
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   void determineFrameLayout(MachineFunction &MF) const;
   void adjustStackForRVV(MachineFunction &MF, MachineBasicBlock &MBB,

diff  --git a/llvm/lib/Target/SPIRV/SPIRVFrameLowering.h b/llvm/lib/Target/SPIRV/SPIRVFrameLowering.h
index b98f8d0928e5b7..c7522554166a7e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVFrameLowering.h
+++ b/llvm/lib/Target/SPIRV/SPIRVFrameLowering.h
@@ -33,7 +33,8 @@ class SPIRVFrameLowering : public TargetFrameLowering {
   void emitEpilogue(MachineFunction &MF,
                     MachineBasicBlock &MBB) const override {}
 
-  bool hasFP(const MachineFunction &MF) const override { return false; }
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override { return false; }
 };
 } // namespace llvm
 #endif // LLVM_LIB_TARGET_SPIRV_SPIRVFRAMELOWERING_H

diff  --git a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
index 000418be9a9e33..fa38c6cbb6ebbf 100644
--- a/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
@@ -249,10 +249,10 @@ bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
   return !MF.getFrameInfo().hasVarSizedObjects();
 }
 
-// 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.
-bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
+// hasFPImpl - 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.
+bool SparcFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
   const MachineFrameInfo &MFI = MF.getFrameInfo();

diff  --git a/llvm/lib/Target/Sparc/SparcFrameLowering.h b/llvm/lib/Target/Sparc/SparcFrameLowering.h
index ab0ceb6591c63c..803856811969b2 100644
--- a/llvm/lib/Target/Sparc/SparcFrameLowering.h
+++ b/llvm/lib/Target/Sparc/SparcFrameLowering.h
@@ -35,7 +35,6 @@ class SparcFrameLowering : public TargetFrameLowering {
                                 MachineBasicBlock::iterator I) const override;
 
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
-  bool hasFP(const MachineFunction &MF) const override;
   void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                             RegScavenger *RS = nullptr) const override;
 
@@ -47,6 +46,9 @@ class SparcFrameLowering : public TargetFrameLowering {
   /// time).
   bool targetHandlesStackFrameRounding() const override { return true; }
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   // Remap input registers to output registers for leaf procedure.
   void remapRegsForLeafProc(MachineFunction &MF) const;

diff  --git a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
index 8c53b8dffc2fa6..8fbd05eab5f6ee 100644
--- a/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp
@@ -832,7 +832,7 @@ void SystemZELFFrameLowering::inlineStackProbe(
   }
 }
 
-bool SystemZELFFrameLowering::hasFP(const MachineFunction &MF) const {
+bool SystemZELFFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
           MF.getFrameInfo().hasVarSizedObjects());
 }
@@ -1449,7 +1449,12 @@ void SystemZXPLINKFrameLowering::inlineStackProbe(
   fullyRecomputeLiveIns({StackExtMBB, NextMBB});
 }
 
-bool SystemZXPLINKFrameLowering::hasFP(const MachineFunction &MF) const {
+bool SystemZXPLINKFrameLowering::hasFPImpl(const MachineFunction &MF) const {
+  // Naked functions have no stack frame pushed, so we don't have a frame
+  // pointer.
+  if (MF.getFunction().hasFnAttribute(Attribute::Naked))
+    return false;
+
   return (MF.getFrameInfo().hasVarSizedObjects());
 }
 

diff  --git a/llvm/lib/Target/SystemZ/SystemZFrameLowering.h b/llvm/lib/Target/SystemZ/SystemZFrameLowering.h
index c4367b491f99ef..57fc73b78bbf7c 100644
--- a/llvm/lib/Target/SystemZ/SystemZFrameLowering.h
+++ b/llvm/lib/Target/SystemZ/SystemZFrameLowering.h
@@ -86,7 +86,6 @@ class SystemZELFFrameLowering : public SystemZFrameLowering {
   void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
   void inlineStackProbe(MachineFunction &MF,
                         MachineBasicBlock &PrologMBB) const override;
-  bool hasFP(const MachineFunction &MF) const override;
   StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
                                      Register &FrameReg) const override;
   void
@@ -113,6 +112,9 @@ class SystemZELFFrameLowering : public SystemZFrameLowering {
 
   // Get or create the frame index of where the old frame pointer is stored.
   int getOrCreateFramePointerSaveIndex(MachineFunction &MF) const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 
 class SystemZXPLINKFrameLowering : public SystemZFrameLowering {
@@ -147,8 +149,6 @@ class SystemZXPLINKFrameLowering : public SystemZFrameLowering {
   void inlineStackProbe(MachineFunction &MF,
                         MachineBasicBlock &PrologMBB) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
-
   void processFunctionBeforeFrameFinalized(MachineFunction &MF,
                                            RegScavenger *RS) const override;
 
@@ -167,6 +167,9 @@ class SystemZXPLINKFrameLowering : public SystemZFrameLowering {
 
   // Get or create the frame index of where the old frame pointer is stored.
   int getOrCreateFramePointerSaveIndex(MachineFunction &MF) const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 } // end namespace llvm
 

diff  --git a/llvm/lib/Target/VE/VEFrameLowering.cpp b/llvm/lib/Target/VE/VEFrameLowering.cpp
index 195bd4e6c3aee7..10e94c28072fda 100644
--- a/llvm/lib/Target/VE/VEFrameLowering.cpp
+++ b/llvm/lib/Target/VE/VEFrameLowering.cpp
@@ -415,10 +415,10 @@ void VEFrameLowering::emitEpilogue(MachineFunction &MF,
   emitEpilogueInsns(MF, MBB, MBBI, NumBytes, 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.
-bool VEFrameLowering::hasFP(const MachineFunction &MF) const {
+// hasFPImpl - 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.
+bool VEFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
   const MachineFrameInfo &MFI = MF.getFrameInfo();

diff  --git a/llvm/lib/Target/VE/VEFrameLowering.h b/llvm/lib/Target/VE/VEFrameLowering.h
index 36fc8b201b648c..be9cdc01d6f446 100644
--- a/llvm/lib/Target/VE/VEFrameLowering.h
+++ b/llvm/lib/Target/VE/VEFrameLowering.h
@@ -39,7 +39,6 @@ class VEFrameLowering : public TargetFrameLowering {
   eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator I) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool hasBP(const MachineFunction &MF) const;
   bool hasGOT(const MachineFunction &MF) const;
 
@@ -69,6 +68,8 @@ class VEFrameLowering : public TargetFrameLowering {
 protected:
   const VESubtarget &STI;
 
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   // Returns true if MF is a leaf procedure.
   bool isLeafProc(MachineFunction &MF) const;

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
index 8f3ad167ae41fc..f0334ccb3afcb5 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
@@ -98,7 +98,7 @@ bool WebAssemblyFrameLowering::hasBP(const MachineFunction &MF) const {
 
 /// Return true if the specified function should have a dedicated frame pointer
 /// register.
-bool WebAssemblyFrameLowering::hasFP(const MachineFunction &MF) const {
+bool WebAssemblyFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
 
   // When we have var-sized objects, we move the stack pointer by an unknown

diff  --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
index 528b33e34beeef..710d5173d64dba 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.h
@@ -41,7 +41,6 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering {
   void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
   void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
 
-  bool hasFP(const MachineFunction &MF) const override;
   bool hasReservedCallFrame(const MachineFunction &MF) const override;
   bool isSupportedStackID(TargetStackID::Value ID) const override;
   DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const override;
@@ -68,6 +67,9 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering {
   static unsigned getOpcGlobGet(const MachineFunction &MF);
   static unsigned getOpcGlobSet(const MachineFunction &MF);
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   bool hasBP(const MachineFunction &MF) const;
   bool needsSPForLocalFrame(const MachineFunction &MF) const;

diff  --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index 4f83267c999e4a..a35b04606e595d 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -91,10 +91,10 @@ bool X86FrameLowering::needsFrameIndexResolution(
          MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences();
 }
 
-/// 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.
-bool X86FrameLowering::hasFP(const MachineFunction &MF) const {
+/// hasFPImpl - 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.
+bool X86FrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   return (MF.getTarget().Options.DisableFramePointerElim(MF) ||
           TRI->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||

diff  --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h
index 78217911dacadf..02fe8ee02a7e45 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.h
+++ b/llvm/lib/Target/X86/X86FrameLowering.h
@@ -105,7 +105,6 @@ class X86FrameLowering : public TargetFrameLowering {
 
   void spillFPBP(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;
   bool needsFrameIndexResolution(const MachineFunction &MF) const override;
@@ -201,6 +200,9 @@ class X86FrameLowering : public TargetFrameLowering {
   /// frame of the top of stack function) as part of it's ABI.
   bool has128ByteRedZone(const MachineFunction& MF) const;
 
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
+
 private:
   bool isWin64Prologue(const MachineFunction &MF) const;
 

diff  --git a/llvm/lib/Target/XCore/XCoreFrameLowering.cpp b/llvm/lib/Target/XCore/XCoreFrameLowering.cpp
index b3753692ac2a05..ec18eca82b52d1 100644
--- a/llvm/lib/Target/XCore/XCoreFrameLowering.cpp
+++ b/llvm/lib/Target/XCore/XCoreFrameLowering.cpp
@@ -215,7 +215,7 @@ XCoreFrameLowering::XCoreFrameLowering(const XCoreSubtarget &sti)
   // Do nothing
 }
 
-bool XCoreFrameLowering::hasFP(const MachineFunction &MF) const {
+bool XCoreFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
          MF.getFrameInfo().hasVarSizedObjects();
 }

diff  --git a/llvm/lib/Target/XCore/XCoreFrameLowering.h b/llvm/lib/Target/XCore/XCoreFrameLowering.h
index a914d82e198947..b06a6f922cdde0 100644
--- a/llvm/lib/Target/XCore/XCoreFrameLowering.h
+++ b/llvm/lib/Target/XCore/XCoreFrameLowering.h
@@ -46,8 +46,6 @@ namespace llvm {
     eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                                   MachineBasicBlock::iterator I) const override;
 
-    bool hasFP(const MachineFunction &MF) const override;
-
     void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                               RegScavenger *RS = nullptr) const override;
 
@@ -58,6 +56,9 @@ namespace llvm {
     static int stackSlotSize() {
       return 4;
     }
+
+  protected:
+    bool hasFPImpl(const MachineFunction &MF) const override;
   };
 }
 

diff  --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
index e24cb7714d3646..f46d386c9186aa 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.cpp
@@ -27,7 +27,7 @@ XtensaFrameLowering::XtensaFrameLowering(const XtensaSubtarget &STI)
                           Align(4)),
       TII(*STI.getInstrInfo()), TRI(STI.getRegisterInfo()) {}
 
-bool XtensaFrameLowering::hasFP(const MachineFunction &MF) const {
+bool XtensaFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   return MF.getTarget().Options.DisableFramePointerElim(MF) ||
          MFI.hasVarSizedObjects();

diff  --git a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
index 9120215af08b52..3f946e1ea730f9 100644
--- a/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaFrameLowering.h
@@ -24,8 +24,6 @@ class XtensaFrameLowering : public TargetFrameLowering {
 public:
   XtensaFrameLowering(const XtensaSubtarget &STI);
 
-  bool hasFP(const MachineFunction &MF) const override;
-
   /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
   /// the function.
   void emitPrologue(MachineFunction &, MachineBasicBlock &) const override;
@@ -50,6 +48,9 @@ class XtensaFrameLowering : public TargetFrameLowering {
 
   void processFunctionBeforeFrameFinalized(MachineFunction &MF,
                                            RegScavenger *RS) const override;
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override;
 };
 
 } // namespace llvm

diff  --git a/llvm/test/CodeGen/AArch64/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/AArch64/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..fb559867a2d47b
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple aarch64 | FileCheck %s -check-prefixes=CHECK-LE
+; RUN: llc < %s -mtriple aarch64_be | FileCheck %s -check-prefixes=CHECK-BE
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LE-LABEL: naked:
+; CHECK-LE:       // %bb.0:
+; CHECK-LE-NEXT:    bl main
+;
+; CHECK-BE-LABEL: naked:
+; CHECK-BE:       // %bb.0:
+; CHECK-BE-NEXT:    bl main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LE-LABEL: normal:
+; CHECK-LE:       // %bb.0:
+; CHECK-LE-NEXT:    stp x29, x30, [sp, #-16]! // 16-byte Folded Spill
+; CHECK-LE-NEXT:    mov x29, sp
+; CHECK-LE-NEXT:    .cfi_def_cfa w29, 16
+; CHECK-LE-NEXT:    .cfi_offset w30, -8
+; CHECK-LE-NEXT:    .cfi_offset w29, -16
+; CHECK-LE-NEXT:    bl main
+;
+; CHECK-BE-LABEL: normal:
+; CHECK-BE:       // %bb.0:
+; CHECK-BE-NEXT:    stp x29, x30, [sp, #-16]! // 16-byte Folded Spill
+; CHECK-BE-NEXT:    mov x29, sp
+; CHECK-BE-NEXT:    .cfi_def_cfa w29, 16
+; CHECK-BE-NEXT:    .cfi_offset w30, -8
+; CHECK-BE-NEXT:    .cfi_offset w29, -16
+; CHECK-BE-NEXT:    bl main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/AMDGPU/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/AMDGPU/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..5ff2d82c1464f2
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple amdgcn | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       naked$local:
+; CHECK-NEXT:    .type naked$local, at function
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_getpc_b64 s[16:17]
+; CHECK-NEXT:    s_add_u32 s16, s16, main at rel32@lo+4
+; CHECK-NEXT:    s_addc_u32 s17, s17, main at rel32@hi+12
+; CHECK-NEXT:    s_swappc_b64 s[30:31], s[16:17]
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       normal$local:
+; CHECK-NEXT:    .type normal$local, at function
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; CHECK-NEXT:    s_mov_b32 s16, s33
+; CHECK-NEXT:    s_mov_b32 s33, s32
+; CHECK-NEXT:    s_or_saveexec_b64 s[18:19], -1
+; CHECK-NEXT:    buffer_store_dword v40, off, s[0:3], s33 ; 4-byte Folded Spill
+; CHECK-NEXT:    s_mov_b64 exec, s[18:19]
+; CHECK-NEXT:    s_waitcnt expcnt(0)
+; CHECK-NEXT:    v_writelane_b32 v40, s16, 2
+; CHECK-NEXT:    s_addk_i32 s32, 0x400
+; CHECK-NEXT:    v_writelane_b32 v40, s30, 0
+; CHECK-NEXT:    v_writelane_b32 v40, s31, 1
+; CHECK-NEXT:    s_getpc_b64 s[16:17]
+; CHECK-NEXT:    s_add_u32 s16, s16, main at rel32@lo+4
+; CHECK-NEXT:    s_addc_u32 s17, s17, main at rel32@hi+12
+; CHECK-NEXT:    s_swappc_b64 s[30:31], s[16:17]
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/ARM/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/ARM/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..2bdc7d3e29b981
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,55 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple arm | FileCheck %s -check-prefixes=CHECK-ALE
+; RUN: llc < %s -mtriple armeb | FileCheck %s -check-prefixes=CHECK-ABE
+; RUN: llc < %s -mtriple thumb | FileCheck %s -check-prefixes=CHECK-TLE
+; RUN: llc < %s -mtriple thumbeb | FileCheck %s -check-prefixes=CHECK-TBE
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-ALE-LABEL: naked:
+; CHECK-ALE:       @ %bb.0:
+; CHECK-ALE-NEXT:    bl main
+;
+; CHECK-ABE-LABEL: naked:
+; CHECK-ABE:       @ %bb.0:
+; CHECK-ABE-NEXT:    bl main
+;
+; CHECK-TLE-LABEL: naked:
+; CHECK-TLE:       @ %bb.0:
+; CHECK-TLE-NEXT:    bl main
+;
+; CHECK-TBE-LABEL: naked:
+; CHECK-TBE:       @ %bb.0:
+; CHECK-TBE-NEXT:    bl main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-ALE-LABEL: normal:
+; CHECK-ALE:       @ %bb.0:
+; CHECK-ALE-NEXT:    push {r11, lr}
+; CHECK-ALE-NEXT:    mov r11, sp
+; CHECK-ALE-NEXT:    bl main
+;
+; CHECK-ABE-LABEL: normal:
+; CHECK-ABE:       @ %bb.0:
+; CHECK-ABE-NEXT:    push {r11, lr}
+; CHECK-ABE-NEXT:    mov r11, sp
+; CHECK-ABE-NEXT:    bl main
+;
+; CHECK-TLE-LABEL: normal:
+; CHECK-TLE:       @ %bb.0:
+; CHECK-TLE-NEXT:    push {r7, lr}
+; CHECK-TLE-NEXT:    add r7, sp, #0
+; CHECK-TLE-NEXT:    bl main
+;
+; CHECK-TBE-LABEL: normal:
+; CHECK-TBE:       @ %bb.0:
+; CHECK-TBE-NEXT:    push {r7, lr}
+; CHECK-TBE-NEXT:    add r7, sp, #0
+; CHECK-TBE-NEXT:    bl main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/AVR/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/AVR/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..18ea60906bd0cd
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,20 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple avr | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    rcall main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    rcall main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..4e4436296f3b56
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple bpfel | FileCheck %s -check-prefixes=CHECK-LE
+; RUN: llc < %s -mtriple bpfeb | FileCheck %s -check-prefixes=CHECK-BE
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LE-LABEL: naked:
+; CHECK-LE:       .Lnaked$local:
+; CHECK-LE-NEXT:    .type .Lnaked$local, at function
+; CHECK-LE-NEXT:    .cfi_startproc
+; CHECK-LE-NEXT:  # %bb.0:
+; CHECK-LE-NEXT:    call main
+;
+; CHECK-BE-LABEL: naked:
+; CHECK-BE:       .Lnaked$local:
+; CHECK-BE-NEXT:    .type .Lnaked$local, at function
+; CHECK-BE-NEXT:    .cfi_startproc
+; CHECK-BE-NEXT:  # %bb.0:
+; CHECK-BE-NEXT:    call main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LE-LABEL: normal:
+; CHECK-LE:       .Lnormal$local:
+; CHECK-LE-NEXT:    .type .Lnormal$local, at function
+; CHECK-LE-NEXT:    .cfi_startproc
+; CHECK-LE-NEXT:  # %bb.0:
+; CHECK-LE-NEXT:    call main
+;
+; CHECK-BE-LABEL: normal:
+; CHECK-BE:       .Lnormal$local:
+; CHECK-BE-NEXT:    .type .Lnormal$local, at function
+; CHECK-BE-NEXT:    .cfi_startproc
+; CHECK-BE-NEXT:  # %bb.0:
+; CHECK-BE-NEXT:    call main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/CSKY/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/CSKY/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..e897127eb31cdd
--- /dev/null
+++ b/llvm/test/CodeGen/CSKY/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple csky | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lrw a0, [.LCPI0_0]
+; CHECK-NEXT:    jsr16 a0
+; CHECK-NEXT:    .p2align 1
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    .p2align 2, 0x0
+; CHECK-NEXT:  .LCPI0_0:
+; CHECK-NEXT:    .long main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    subi16 sp, sp, 8
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    st32.w lr, (sp, 4) # 4-byte Folded Spill
+; CHECK-NEXT:    st32.w l4, (sp, 0) # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset lr, -4
+; CHECK-NEXT:    .cfi_offset l4, -8
+; CHECK-NEXT:    mov16 l4, sp
+; CHECK-NEXT:    .cfi_def_cfa_register l4
+; CHECK-NEXT:    subi16 sp, sp, 4
+; CHECK-NEXT:    lrw a0, [.LCPI1_0]
+; CHECK-NEXT:    jsr16 a0
+; CHECK-NEXT:    .p2align 1
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    .p2align 2, 0x0
+; CHECK-NEXT:  .LCPI1_0:
+; CHECK-NEXT:    .long main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/Hexagon/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/Hexagon/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..c53f2d4df9b62c
--- /dev/null
+++ b/llvm/test/CodeGen/Hexagon/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,30 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple hexagon | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    {
+; CHECK-NEXT:     call main
+; CHECK-NEXT:    }
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  // %bb.0:
+; CHECK-NEXT:    .cfi_def_cfa r30, 8
+; CHECK-NEXT:    .cfi_offset r31, -4
+; CHECK-NEXT:    .cfi_offset r30, -8
+; CHECK-NEXT:    {
+; CHECK-NEXT:     call main
+; CHECK-NEXT:     allocframe(r29,#0):raw
+; CHECK-NEXT:    }
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/Lanai/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/Lanai/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..4e148764e478b7
--- /dev/null
+++ b/llvm/test/CodeGen/Lanai/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,35 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple lanai | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       .Lnaked$local:
+; CHECK-NEXT:    .type .Lnaked$local, at function
+; CHECK-NEXT:    .cfi_startproc
+; CHECK-NEXT:  ! %bb.0:
+; CHECK-NEXT:    add %pc, 0x10, %rca
+; CHECK-NEXT:    st %rca, [--%sp]
+; CHECK-NEXT:    bt main
+; CHECK-NEXT:    nop
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       .Lnormal$local:
+; CHECK-NEXT:    .type .Lnormal$local, at function
+; CHECK-NEXT:    .cfi_startproc
+; CHECK-NEXT:  ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    add %pc, 0x10, %rca
+; CHECK-NEXT:    st %rca, [--%sp]
+; CHECK-NEXT:    bt main
+; CHECK-NEXT:    nop
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/LoongArch/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/LoongArch/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..9bb449101683d6
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple loongarch32 -mattr +d | FileCheck %s -check-prefixes=CHECK-32
+; RUN: llc < %s -mtriple loongarch64 -mattr +d | FileCheck %s -check-prefixes=CHECK-64
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-LABEL: naked:
+; CHECK-32:       # %bb.0:
+; CHECK-32-NEXT:    bl main
+;
+; CHECK-64-LABEL: naked:
+; CHECK-64:       # %bb.0:
+; CHECK-64-NEXT:    bl main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-LABEL: normal:
+; CHECK-32:       # %bb.0:
+; CHECK-32-NEXT:    addi.w $sp, $sp, -16
+; CHECK-32-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-32-NEXT:    st.w $ra, $sp, 12 # 4-byte Folded Spill
+; CHECK-32-NEXT:    st.w $fp, $sp, 8 # 4-byte Folded Spill
+; CHECK-32-NEXT:    .cfi_offset 1, -4
+; CHECK-32-NEXT:    .cfi_offset 22, -8
+; CHECK-32-NEXT:    addi.w $fp, $sp, 16
+; CHECK-32-NEXT:    .cfi_def_cfa 22, 0
+; CHECK-32-NEXT:    bl main
+;
+; CHECK-64-LABEL: normal:
+; CHECK-64:       # %bb.0:
+; CHECK-64-NEXT:    addi.d $sp, $sp, -16
+; CHECK-64-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-64-NEXT:    st.d $ra, $sp, 8 # 8-byte Folded Spill
+; CHECK-64-NEXT:    st.d $fp, $sp, 0 # 8-byte Folded Spill
+; CHECK-64-NEXT:    .cfi_offset 1, -8
+; CHECK-64-NEXT:    .cfi_offset 22, -16
+; CHECK-64-NEXT:    addi.d $fp, $sp, 16
+; CHECK-64-NEXT:    .cfi_def_cfa 22, 0
+; CHECK-64-NEXT:    bl main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/M68k/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/M68k/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..807c52c39b6e6a
--- /dev/null
+++ b/llvm/test/CodeGen/M68k/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,26 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple m68k | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    jsr main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    link.w %a6, #0
+; CHECK-NEXT:    .cfi_def_cfa_offset -8
+; CHECK-NEXT:    .cfi_offset %a6, -8
+; CHECK-NEXT:    .cfi_def_cfa_register %a6
+; CHECK-NEXT:    jsr main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/MSP430/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/MSP430/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..2fdb01005bb280
--- /dev/null
+++ b/llvm/test/CodeGen/MSP430/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,27 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple msp430 | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    call #main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:         .cfi_startproc
+; CHECK-NEXT:  ; %bb.0:
+; CHECK-NEXT:    push r4
+; CHECK-NEXT:    .cfi_def_cfa_offset 4
+; CHECK-NEXT:    .cfi_offset r4, -4
+; CHECK-NEXT:    mov r1, r4
+; CHECK-NEXT:    .cfi_def_cfa_register r4
+; CHECK-NEXT:    call #main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/Mips/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/Mips/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..a3820da8b221c9
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,87 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple mips | FileCheck %s -check-prefixes=CHECK-32-BE
+; RUN: llc < %s -mtriple mipsel | FileCheck %s -check-prefixes=CHECK-32-LE
+; RUN: llc < %s -mtriple mips64 | FileCheck %s -check-prefixes=CHECK-64-BE
+; RUN: llc < %s -mtriple mips64el | FileCheck %s -check-prefixes=CHECK-64-LE
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-BE-LABEL: naked:
+; CHECK-32-BE:       # %bb.0:
+; CHECK-32-BE-NEXT:    jal main
+; CHECK-32-BE-NEXT:    nop
+;
+; CHECK-32-LE-LABEL: naked:
+; CHECK-32-LE:       # %bb.0:
+; CHECK-32-LE-NEXT:    jal main
+; CHECK-32-LE-NEXT:    nop
+;
+; CHECK-64-BE-LABEL: naked:
+; CHECK-64-BE:       # %bb.0:
+; CHECK-64-BE-NEXT:    jal main
+; CHECK-64-BE-NEXT:    nop
+;
+; CHECK-64-LE-LABEL: naked:
+; CHECK-64-LE:       # %bb.0:
+; CHECK-64-LE-NEXT:    jal main
+; CHECK-64-LE-NEXT:    nop
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-BE-LABEL: normal:
+; CHECK-32-BE:       # %bb.0:
+; CHECK-32-BE-NEXT:    addiu $sp, $sp, -24
+; CHECK-32-BE-NEXT:    .cfi_def_cfa_offset 24
+; CHECK-32-BE-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill
+; CHECK-32-BE-NEXT:    sw $fp, 16($sp) # 4-byte Folded Spill
+; CHECK-32-BE-NEXT:    .cfi_offset 31, -4
+; CHECK-32-BE-NEXT:    .cfi_offset 30, -8
+; CHECK-32-BE-NEXT:    move $fp, $sp
+; CHECK-32-BE-NEXT:    .cfi_def_cfa_register 30
+; CHECK-32-BE-NEXT:    jal main
+; CHECK-32-BE-NEXT:    nop
+;
+; CHECK-32-LE-LABEL: normal:
+; CHECK-32-LE:       # %bb.0:
+; CHECK-32-LE-NEXT:    addiu $sp, $sp, -24
+; CHECK-32-LE-NEXT:    .cfi_def_cfa_offset 24
+; CHECK-32-LE-NEXT:    sw $ra, 20($sp) # 4-byte Folded Spill
+; CHECK-32-LE-NEXT:    sw $fp, 16($sp) # 4-byte Folded Spill
+; CHECK-32-LE-NEXT:    .cfi_offset 31, -4
+; CHECK-32-LE-NEXT:    .cfi_offset 30, -8
+; CHECK-32-LE-NEXT:    move $fp, $sp
+; CHECK-32-LE-NEXT:    .cfi_def_cfa_register 30
+; CHECK-32-LE-NEXT:    jal main
+; CHECK-32-LE-NEXT:    nop
+;
+; CHECK-64-BE-LABEL: normal:
+; CHECK-64-BE:       # %bb.0:
+; CHECK-64-BE-NEXT:    daddiu $sp, $sp, -16
+; CHECK-64-BE-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-64-BE-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill
+; CHECK-64-BE-NEXT:    sd $fp, 0($sp) # 8-byte Folded Spill
+; CHECK-64-BE-NEXT:    .cfi_offset 31, -8
+; CHECK-64-BE-NEXT:    .cfi_offset 30, -16
+; CHECK-64-BE-NEXT:    move $fp, $sp
+; CHECK-64-BE-NEXT:    .cfi_def_cfa_register 30
+; CHECK-64-BE-NEXT:    jal main
+; CHECK-64-BE-NEXT:    nop
+;
+; CHECK-64-LE-LABEL: normal:
+; CHECK-64-LE:       # %bb.0:
+; CHECK-64-LE-NEXT:    daddiu $sp, $sp, -16
+; CHECK-64-LE-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-64-LE-NEXT:    sd $ra, 8($sp) # 8-byte Folded Spill
+; CHECK-64-LE-NEXT:    sd $fp, 0($sp) # 8-byte Folded Spill
+; CHECK-64-LE-NEXT:    .cfi_offset 31, -8
+; CHECK-64-LE-NEXT:    .cfi_offset 30, -16
+; CHECK-64-LE-NEXT:    move $fp, $sp
+; CHECK-64-LE-NEXT:    .cfi_def_cfa_register 30
+; CHECK-64-LE-NEXT:    jal main
+; CHECK-64-LE-NEXT:    nop
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/NVPTX/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/NVPTX/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..a1f0577c2218bd
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,73 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple nvptx | FileCheck %s -check-prefixes=CHECK-32
+; RUN: llc < %s -mtriple nvptx64 | FileCheck %s -check-prefixes=CHECK-64
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-LABEL: naked(
+; CHECK-32:       {
+; CHECK-32-EMPTY:
+; CHECK-32-EMPTY:
+; CHECK-32-NEXT:  // %bb.0:
+; CHECK-32-NEXT:    { // callseq 0, 0
+; CHECK-32-NEXT:    call.uni
+; CHECK-32-NEXT:    main,
+; CHECK-32-NEXT:    (
+; CHECK-32-NEXT:    );
+; CHECK-32-NEXT:    } // callseq 0
+; CHECK-32-NEXT:    // begin inline asm
+; CHECK-32-NEXT:    exit;
+; CHECK-32-NEXT:    // end inline asm
+;
+; CHECK-64-LABEL: naked(
+; CHECK-64:       {
+; CHECK-64-EMPTY:
+; CHECK-64-EMPTY:
+; CHECK-64-NEXT:  // %bb.0:
+; CHECK-64-NEXT:    { // callseq 0, 0
+; CHECK-64-NEXT:    call.uni
+; CHECK-64-NEXT:    main,
+; CHECK-64-NEXT:    (
+; CHECK-64-NEXT:    );
+; CHECK-64-NEXT:    } // callseq 0
+; CHECK-64-NEXT:    // begin inline asm
+; CHECK-64-NEXT:    exit;
+; CHECK-64-NEXT:    // end inline asm
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-LABEL: normal(
+; CHECK-32:       {
+; CHECK-32-EMPTY:
+; CHECK-32-EMPTY:
+; CHECK-32-NEXT:  // %bb.0:
+; CHECK-32-NEXT:    { // callseq 1, 0
+; CHECK-32-NEXT:    call.uni
+; CHECK-32-NEXT:    main,
+; CHECK-32-NEXT:    (
+; CHECK-32-NEXT:    );
+; CHECK-32-NEXT:    } // callseq 1
+; CHECK-32-NEXT:    // begin inline asm
+; CHECK-32-NEXT:    exit;
+; CHECK-32-NEXT:    // end inline asm
+;
+; CHECK-64-LABEL: normal(
+; CHECK-64:       {
+; CHECK-64-EMPTY:
+; CHECK-64-EMPTY:
+; CHECK-64-NEXT:  // %bb.0:
+; CHECK-64-NEXT:    { // callseq 1, 0
+; CHECK-64-NEXT:    call.uni
+; CHECK-64-NEXT:    main,
+; CHECK-64-NEXT:    (
+; CHECK-64-NEXT:    );
+; CHECK-64-NEXT:    } // callseq 1
+; CHECK-64-NEXT:    // begin inline asm
+; CHECK-64-NEXT:    exit;
+; CHECK-64-NEXT:    // end inline asm
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/PowerPC/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/PowerPC/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..59b1044084c645
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,87 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple powerpc | FileCheck %s -check-prefixes=CHECK-32-BE
+; RUN: llc < %s -mtriple powerpcle | FileCheck %s -check-prefixes=CHECK-32-LE
+; RUN: llc < %s -mtriple powerpc64 | FileCheck %s -check-prefixes=CHECK-64-BE
+; RUN: llc < %s -mtriple powerpc64le | FileCheck %s -check-prefixes=CHECK-64-LE
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-BE-LABEL: naked:
+; CHECK-32-BE:       # %bb.0:
+; CHECK-32-BE-NEXT:    bl main
+;
+; CHECK-32-LE-LABEL: naked:
+; CHECK-32-LE:       # %bb.0:
+; CHECK-32-LE-NEXT:    bl main
+;
+; CHECK-64-BE-LABEL: naked:
+; CHECK-64-BE:       # %bb.0:
+; CHECK-64-BE-NEXT:    bl main
+; CHECK-64-BE-NEXT:    nop
+;
+; CHECK-64-LE-LABEL: naked:
+; CHECK-64-LE:       # %bb.0:
+; CHECK-64-LE-NEXT:    bl main
+; CHECK-64-LE-NEXT:    nop
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-BE-LABEL: normal:
+; CHECK-32-BE:       # %bb.0:
+; CHECK-32-BE-NEXT:    mflr 0
+; CHECK-32-BE-NEXT:    stwu 1, -16(1)
+; CHECK-32-BE-NEXT:    stw 31, 12(1)
+; CHECK-32-BE-NEXT:    stw 0, 20(1)
+; CHECK-32-BE-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-32-BE-NEXT:    .cfi_offset r31, -4
+; CHECK-32-BE-NEXT:    .cfi_offset lr, 4
+; CHECK-32-BE-NEXT:    mr 31, 1
+; CHECK-32-BE-NEXT:    .cfi_def_cfa_register r31
+; CHECK-32-BE-NEXT:    bl main
+;
+; CHECK-32-LE-LABEL: normal:
+; CHECK-32-LE:       # %bb.0:
+; CHECK-32-LE-NEXT:    mflr 0
+; CHECK-32-LE-NEXT:    stwu 1, -16(1)
+; CHECK-32-LE-NEXT:    stw 31, 12(1)
+; CHECK-32-LE-NEXT:    stw 0, 20(1)
+; CHECK-32-LE-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-32-LE-NEXT:    .cfi_offset r31, -4
+; CHECK-32-LE-NEXT:    .cfi_offset lr, 4
+; CHECK-32-LE-NEXT:    mr 31, 1
+; CHECK-32-LE-NEXT:    .cfi_def_cfa_register r31
+; CHECK-32-LE-NEXT:    bl main
+;
+; CHECK-64-BE-LABEL: normal:
+; CHECK-64-BE:       # %bb.0:
+; CHECK-64-BE-NEXT:    mflr 0
+; CHECK-64-BE-NEXT:    std 31, -8(1)
+; CHECK-64-BE-NEXT:    stdu 1, -128(1)
+; CHECK-64-BE-NEXT:    std 0, 144(1)
+; CHECK-64-BE-NEXT:    .cfi_def_cfa_offset 128
+; CHECK-64-BE-NEXT:    .cfi_offset r31, -8
+; CHECK-64-BE-NEXT:    .cfi_offset lr, 16
+; CHECK-64-BE-NEXT:    mr 31, 1
+; CHECK-64-BE-NEXT:    .cfi_def_cfa_register r31
+; CHECK-64-BE-NEXT:    bl main
+; CHECK-64-BE-NEXT:    nop
+;
+; CHECK-64-LE-LABEL: normal:
+; CHECK-64-LE:       # %bb.0:
+; CHECK-64-LE-NEXT:    mflr 0
+; CHECK-64-LE-NEXT:    std 31, -8(1)
+; CHECK-64-LE-NEXT:    stdu 1, -48(1)
+; CHECK-64-LE-NEXT:    std 0, 64(1)
+; CHECK-64-LE-NEXT:    .cfi_def_cfa_offset 48
+; CHECK-64-LE-NEXT:    .cfi_offset r31, -8
+; CHECK-64-LE-NEXT:    .cfi_offset lr, 16
+; CHECK-64-LE-NEXT:    mr 31, 1
+; CHECK-64-LE-NEXT:    .cfi_def_cfa_register r31
+; CHECK-64-LE-NEXT:    bl main
+; CHECK-64-LE-NEXT:    nop
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/RISCV/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/RISCV/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..de87b10d387338
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple riscv32 | FileCheck %s -check-prefixes=CHECK-32
+; RUN: llc < %s -mtriple riscv64 | FileCheck %s -check-prefixes=CHECK-64
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-LABEL: naked:
+; CHECK-32:       # %bb.0:
+; CHECK-32-NEXT:    call main
+;
+; CHECK-64-LABEL: naked:
+; CHECK-64:       # %bb.0:
+; CHECK-64-NEXT:    call main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-LABEL: normal:
+; CHECK-32:       # %bb.0:
+; CHECK-32-NEXT:    addi sp, sp, -16
+; CHECK-32-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-32-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; CHECK-32-NEXT:    sw s0, 8(sp) # 4-byte Folded Spill
+; CHECK-32-NEXT:    .cfi_offset ra, -4
+; CHECK-32-NEXT:    .cfi_offset s0, -8
+; CHECK-32-NEXT:    addi s0, sp, 16
+; CHECK-32-NEXT:    .cfi_def_cfa s0, 0
+; CHECK-32-NEXT:    call main
+;
+; CHECK-64-LABEL: normal:
+; CHECK-64:       # %bb.0:
+; CHECK-64-NEXT:    addi sp, sp, -16
+; CHECK-64-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-64-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-64-NEXT:    sd s0, 0(sp) # 8-byte Folded Spill
+; CHECK-64-NEXT:    .cfi_offset ra, -8
+; CHECK-64-NEXT:    .cfi_offset s0, -16
+; CHECK-64-NEXT:    addi s0, sp, 16
+; CHECK-64-NEXT:    .cfi_def_cfa s0, 0
+; CHECK-64-NEXT:    call main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/SPARC/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/SPARC/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..af97c573625b52
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple sparc | FileCheck %s -check-prefixes=CHECK-32
+; RUN: llc < %s -mtriple sparc64 | FileCheck %s -check-prefixes=CHECK-64
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-LABEL: naked:
+; CHECK-32:         .cfi_startproc
+; CHECK-32-NEXT:  ! %bb.0:
+; CHECK-32-NEXT:    call main
+; CHECK-32-NEXT:    nop
+;
+; CHECK-64-LABEL: naked:
+; CHECK-64:         .cfi_startproc
+; CHECK-64-NEXT:  ! %bb.0:
+; CHECK-64-NEXT:    call main
+; CHECK-64-NEXT:    nop
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-LABEL: normal:
+; CHECK-32:         .cfi_startproc
+; CHECK-32-NEXT:  ! %bb.0:
+; CHECK-32-NEXT:    save %sp, -96, %sp
+; CHECK-32-NEXT:    .cfi_def_cfa_register %fp
+; CHECK-32-NEXT:    .cfi_window_save
+; CHECK-32-NEXT:    .cfi_register %o7, %i7
+; CHECK-32-NEXT:    call main
+; CHECK-32-NEXT:    nop
+;
+; CHECK-64-LABEL: normal:
+; CHECK-64:         .cfi_startproc
+; CHECK-64-NEXT:  ! %bb.0:
+; CHECK-64-NEXT:    save %sp, -176, %sp
+; CHECK-64-NEXT:    .cfi_def_cfa_register %fp
+; CHECK-64-NEXT:    .cfi_window_save
+; CHECK-64-NEXT:    .cfi_register %o7, %i7
+; CHECK-64-NEXT:    call main
+; CHECK-64-NEXT:    nop
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/SystemZ/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/SystemZ/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..3eb396e4044206
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,28 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple s390x | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    brasl %r14, main at PLT
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    stmg %r11, %r15, 88(%r15)
+; CHECK-NEXT:    .cfi_offset %r11, -72
+; CHECK-NEXT:    .cfi_offset %r14, -48
+; CHECK-NEXT:    .cfi_offset %r15, -40
+; CHECK-NEXT:    aghi %r15, -160
+; CHECK-NEXT:    .cfi_def_cfa_offset 320
+; CHECK-NEXT:    lgr %r11, %r15
+; CHECK-NEXT:    .cfi_def_cfa_register %r11
+; CHECK-NEXT:    brasl %r14, main at PLT
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/VE/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/VE/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..3b88bea46c4dd0
--- /dev/null
+++ b/llvm/test/CodeGen/VE/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple ve | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lea %s0, main at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, main at hi(, %s0)
+; CHECK-NEXT:    bsic %s10, (, %s12)
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    st %s9, (, %s11)
+; CHECK-NEXT:    st %s10, 8(, %s11)
+; CHECK-NEXT:    or %s9, 0, %s11
+; CHECK-NEXT:    lea %s11, -240(, %s11)
+; CHECK-NEXT:    brge.l.t %s11, %s8, .LBB1_2
+; CHECK-NEXT:  # %bb.1:
+; CHECK-NEXT:    ld %s61, 24(, %s14)
+; CHECK-NEXT:    or %s62, 0, %s0
+; CHECK-NEXT:    lea %s63, 315
+; CHECK-NEXT:    shm.l %s63, (%s61)
+; CHECK-NEXT:    shm.l %s8, 8(%s61)
+; CHECK-NEXT:    shm.l %s11, 16(%s61)
+; CHECK-NEXT:    monc
+; CHECK-NEXT:    or %s0, 0, %s62
+; CHECK-NEXT:  .LBB1_2:
+; CHECK-NEXT:    lea %s0, main at lo
+; CHECK-NEXT:    and %s0, %s0, (32)0
+; CHECK-NEXT:    lea.sl %s12, main at hi(, %s0)
+; CHECK-NEXT:    bsic %s10, (, %s12)
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..fcd42e8cbfb9f5
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,37 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple wasm32 | FileCheck %s -check-prefixes=CHECK-32
+; RUN: llc < %s -mtriple wasm64 | FileCheck %s -check-prefixes=CHECK-64
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-LABEL: naked:
+; CHECK-32:         .functype naked () -> ()
+; CHECK-32-NEXT:  # %bb.0:
+; CHECK-32-NEXT:    call main
+; CHECK-32-NEXT:    unreachable
+;
+; CHECK-64-LABEL: naked:
+; CHECK-64:         .functype naked () -> ()
+; CHECK-64-NEXT:  # %bb.0:
+; CHECK-64-NEXT:    call main
+; CHECK-64-NEXT:    unreachable
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-LABEL: normal:
+; CHECK-32:         .functype normal () -> ()
+; CHECK-32-NEXT:  # %bb.0:
+; CHECK-32-NEXT:    call main
+; CHECK-32-NEXT:    unreachable
+;
+; CHECK-64-LABEL: normal:
+; CHECK-64:         .functype normal () -> ()
+; CHECK-64-NEXT:  # %bb.0:
+; CHECK-64-NEXT:    call main
+; CHECK-64-NEXT:    unreachable
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/X86/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/X86/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..37756009fa7d86
--- /dev/null
+++ b/llvm/test/CodeGen/X86/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,39 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple i386 | FileCheck %s -check-prefixes=CHECK-32
+; RUN: llc < %s -mtriple x86_64 | FileCheck %s -check-prefixes=CHECK-64
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-32-LABEL: naked:
+; CHECK-32:       # %bb.0:
+; CHECK-32-NEXT:    calll main
+;
+; CHECK-64-LABEL: naked:
+; CHECK-64:       # %bb.0:
+; CHECK-64-NEXT:    callq main
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-32-LABEL: normal:
+; CHECK-32:       # %bb.0:
+; CHECK-32-NEXT:    pushl %ebp
+; CHECK-32-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-32-NEXT:    .cfi_offset %ebp, -8
+; CHECK-32-NEXT:    movl %esp, %ebp
+; CHECK-32-NEXT:    .cfi_def_cfa_register %ebp
+; CHECK-32-NEXT:    calll main
+;
+; CHECK-64-LABEL: normal:
+; CHECK-64:       # %bb.0:
+; CHECK-64-NEXT:    pushq %rbp
+; CHECK-64-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-64-NEXT:    .cfi_offset %rbp, -16
+; CHECK-64-NEXT:    movq %rsp, %rbp
+; CHECK-64-NEXT:    .cfi_def_cfa_register %rbp
+; CHECK-64-NEXT:    callq main
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/XCore/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/XCore/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..429a78108a7bac
--- /dev/null
+++ b/llvm/test/CodeGen/XCore/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -march xcore | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    bl main
+; CHECK-NEXT:    .cc_bottom naked.function
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    entsp 2
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    .cfi_offset 15, 0
+; CHECK-NEXT:    stw r10, sp[1] # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset 10, -4
+; CHECK-NEXT:    ldaw r10, sp[0]
+; CHECK-NEXT:    .cfi_def_cfa_register 10
+; CHECK-NEXT:    extsp 1
+; CHECK-NEXT:    bl main
+; CHECK-NEXT:    ldaw sp, sp[1]
+; CHECK-NEXT:    .cc_bottom normal.function
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/test/CodeGen/Xtensa/naked-fn-with-frame-pointer.ll b/llvm/test/CodeGen/Xtensa/naked-fn-with-frame-pointer.ll
new file mode 100644
index 00000000000000..020fcc4f6dae6d
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/naked-fn-with-frame-pointer.ll
@@ -0,0 +1,31 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -march xtensa | FileCheck %s -check-prefixes=CHECK
+
+declare dso_local void @main()
+
+define dso_local void @naked() naked "frame-pointer"="all" {
+; CHECK-LABEL: naked:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    l32r a8, {{\.?LCPI[0-9]+_[0-9]+}}
+; CHECK-NEXT:    callx0 a8
+  call void @main()
+  unreachable
+}
+
+define dso_local void @normal() "frame-pointer"="all" {
+; CHECK-LABEL: normal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    addi a8, a1, -16
+; CHECK-NEXT:    or a1, a8, a8
+; CHECK-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-NEXT:    s32i a0, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT:    s32i a15, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset a0, -4
+; CHECK-NEXT:    .cfi_offset a15, -8
+; CHECK-NEXT:    or a15, a1, a1
+; CHECK-NEXT:    .cfi_def_cfa_register a15
+; CHECK-NEXT:    l32r a8, {{\.?LCPI[0-9]+_[0-9]+}}
+; CHECK-NEXT:    callx0 a8
+  call void @main()
+  unreachable
+}

diff  --git a/llvm/unittests/CodeGen/MFCommon.inc b/llvm/unittests/CodeGen/MFCommon.inc
index 5d5720c3162da9..749c5780fbac3d 100644
--- a/llvm/unittests/CodeGen/MFCommon.inc
+++ b/llvm/unittests/CodeGen/MFCommon.inc
@@ -14,7 +14,9 @@ public:
                     MachineBasicBlock &MBB) const override {}
   void emitEpilogue(MachineFunction &MF,
                     MachineBasicBlock &MBB) const override {}
-  bool hasFP(const MachineFunction &MF) const override { return false; }
+
+protected:
+  bool hasFPImpl(const MachineFunction &MF) const override { return false; }
 };
 
 static TargetRegisterClass *const BogusRegisterClasses[] = {nullptr};


        


More information about the llvm-commits mailing list