
FPSCR and FPEXC will be stored in FPStatusRegs, after GPRCS2 has been saved. - GPRCS1 - GPRCS2 - FPStatusRegs (new) - DPRCS - GPRCS3 - DPRCS2 FPSCR is present on all targets with a VFP, but the FPEXC register is not present on Cortex-M devices, so different amounts of bytes are being pushed onto the stack depending on our target, which would affect alignment for subsequent saves. DPRCS1 will sum up all previous bytes that were saved, and will emit extra instructions to ensure that its alignment is correct. My assumption is that if DPRCS1 is able to correct its alignment to be correct, then all subsequent saves will also have correct alignment. Avoid annotating the saving of FPSCR and FPEXC for functions marked with the interrupt_save_fp attribute, even though this is done as part of frame setup. Since these are status registers, there really is no viable way of annotating this. Since these aren't GPRs or DPRs, they can't be used with .save or .vsave directives. Instead, just record that the intermediate registers r4 and r5 are saved to the stack again. Co-authored-by: Jake Vossen <jake@vossen.dev> Co-authored-by: Alan Phipps <a-phipps@ti.com>
120 lines
4.8 KiB
C++
120 lines
4.8 KiB
C++
//===- ARMTargetFrameLowering.h - Define frame lowering for ARM -*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_TARGET_ARM_ARMFRAMELOWERING_H
|
|
#define LLVM_LIB_TARGET_ARM_ARMFRAMELOWERING_H
|
|
|
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
|
#include "llvm/Support/TypeSize.h"
|
|
|
|
namespace llvm {
|
|
|
|
class ARMSubtarget;
|
|
class CalleeSavedInfo;
|
|
class MachineFunction;
|
|
|
|
class ARMFrameLowering : public TargetFrameLowering {
|
|
protected:
|
|
const ARMSubtarget &STI;
|
|
|
|
public:
|
|
explicit ARMFrameLowering(const ARMSubtarget &sti);
|
|
|
|
/// emitProlog/emitEpilog - These methods insert prolog and epilog code into
|
|
/// the function.
|
|
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
|
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
|
|
|
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
|
MachineBasicBlock::iterator MI,
|
|
ArrayRef<CalleeSavedInfo> CSI,
|
|
const TargetRegisterInfo *TRI) const override;
|
|
|
|
bool
|
|
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
|
|
MachineBasicBlock::iterator MI,
|
|
MutableArrayRef<CalleeSavedInfo> CSI,
|
|
const TargetRegisterInfo *TRI) const override;
|
|
|
|
bool keepFramePointer(const MachineFunction &MF) const;
|
|
|
|
bool enableCalleeSaveSkip(const MachineFunction &MF) const override;
|
|
|
|
bool isFPReserved(const MachineFunction &MF) const;
|
|
bool requiresAAPCSFrameRecord(const MachineFunction &MF) const;
|
|
bool hasReservedCallFrame(const MachineFunction &MF) const override;
|
|
bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;
|
|
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
|
|
Register &FrameReg) const override;
|
|
int ResolveFrameIndexReference(const MachineFunction &MF, int FI,
|
|
Register &FrameReg, int SPAdj) const;
|
|
|
|
void getCalleeSaves(const MachineFunction &MF,
|
|
BitVector &SavedRegs) const override;
|
|
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
|
RegScavenger *RS) const override;
|
|
|
|
/// Update the IsRestored flag on LR if it is spilled, based on the return
|
|
/// instructions.
|
|
static void updateLRRestored(MachineFunction &MF);
|
|
|
|
void processFunctionBeforeFrameFinalized(
|
|
MachineFunction &MF, RegScavenger *RS = nullptr) const override;
|
|
|
|
void adjustForSegmentedStacks(MachineFunction &MF,
|
|
MachineBasicBlock &MBB) const override;
|
|
|
|
/// Returns true if the target will correctly handle shrink wrapping.
|
|
bool enableShrinkWrapping(const MachineFunction &MF) const override;
|
|
|
|
bool isProfitableForNoCSROpt(const Function &F) const override {
|
|
// The no-CSR optimisation is bad for code size on ARM, because we can save
|
|
// many registers with a single PUSH/POP pair.
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
assignCalleeSavedSpillSlots(MachineFunction &MF,
|
|
const TargetRegisterInfo *TRI,
|
|
std::vector<CalleeSavedInfo> &CSI) const override;
|
|
|
|
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,
|
|
unsigned StrOpc, bool NoGap,
|
|
function_ref<bool(unsigned)> Func) const;
|
|
void emitPopInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
|
MutableArrayRef<CalleeSavedInfo> CSI, unsigned LdmOpc,
|
|
unsigned LdrOpc, bool isVarArg, bool NoGap,
|
|
function_ref<bool(unsigned)> Func) const;
|
|
|
|
void emitFPStatusSaves(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
|
ArrayRef<CalleeSavedInfo> CSI,
|
|
unsigned PushOneOpc) const;
|
|
|
|
void emitFPStatusRestores(MachineBasicBlock &MBB,
|
|
MachineBasicBlock::iterator MI,
|
|
MutableArrayRef<CalleeSavedInfo> CSI,
|
|
unsigned LdrOpc) const;
|
|
|
|
MachineBasicBlock::iterator
|
|
eliminateCallFramePseudoInstr(MachineFunction &MF,
|
|
MachineBasicBlock &MBB,
|
|
MachineBasicBlock::iterator MI) const override;
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_LIB_TARGET_ARM_ARMFRAMELOWERING_H
|