blob: 326a6ea3e25eece430f7b8f18bc36dc62491c5e8 [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the declaration of the AArch64PrologueEmitter and
/// AArch64EpilogueEmitter classes, which are is used to emit the prologue and
/// epilogue on AArch64.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64PROLOGUEEPILOGUE_H
#define LLVM_LIB_TARGET_AARCH64_AARCH64PROLOGUEEPILOGUE_H
#include "AArch64RegisterInfo.h"
#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineFunction.h"
namespace llvm {
class AArch64FunctionInfo;
class AArch64FrameLowering;
class AArch64InstrInfo;
class AArch64Subtarget;
class TargetLowering;
struct SVEFrameSizes {
struct {
StackOffset CalleeSavesSize, LocalsSize;
} PPR, ZPR;
};
struct SVEStackAllocations {
StackOffset BeforePPRs, AfterPPRs, AfterZPRs;
StackOffset totalSize() const { return BeforePPRs + AfterPPRs + AfterZPRs; }
};
class AArch64PrologueEpilogueCommon {
public:
AArch64PrologueEpilogueCommon(MachineFunction &MF, MachineBasicBlock &MBB,
const AArch64FrameLowering &AFL);
enum class SVEStackLayout {
Default,
Split,
CalleeSavesAboveFrameRecord,
};
protected:
bool requiresGetVGCall() const;
bool isVGInstruction(MachineBasicBlock::iterator MBBI,
const TargetLowering &TLI) const;
// Convert callee-save register save/restore instruction to do stack pointer
// decrement/increment to allocate/deallocate the callee-save stack area by
// converting store/load to use pre/post increment version.
MachineBasicBlock::iterator convertCalleeSaveRestoreToSPPrePostIncDec(
MachineBasicBlock::iterator MBBI, const DebugLoc &DL, int CSStackSizeInc,
bool EmitCFI, MachineInstr::MIFlag FrameFlag = MachineInstr::FrameSetup,
int CFAOffset = 0) const;
// Fixup callee-save register save/restore instructions to take into account
// combined SP bump by adding the local stack size to the stack offsets.
void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI,
uint64_t LocalStackSize) const;
bool shouldCombineCSRLocalStackBump(uint64_t StackBumpBytes) const;
SVEFrameSizes getSVEStackFrameSizes() const;
SVEStackAllocations getSVEStackAllocations(SVEFrameSizes const &);
MachineFunction &MF;
MachineBasicBlock &MBB;
const MachineFrameInfo &MFI;
const AArch64Subtarget &Subtarget;
const AArch64FrameLowering &AFL;
const AArch64RegisterInfo &RegInfo;
// Common flags. These generally should not change outside of the (possibly
// derived) constructor.
bool HasFP = false;
bool EmitCFI = false; // Note: Set in derived constructors.
bool IsFunclet = false; // Note: Set in derived constructors.
bool NeedsWinCFI = false; // Note: Can be changed in emitFramePointerSetup.
bool HomPrologEpilog = false; // Note: Set in derived constructors.
SVEStackLayout SVELayout = SVEStackLayout::Default;
// Note: "HasWinCFI" is mutable as it can change in any "emit" function.
mutable bool HasWinCFI = false;
const AArch64InstrInfo *TII = nullptr;
AArch64FunctionInfo *AFI = nullptr;
};
/// A helper class for emitting the prologue. Substantial new functionality
/// should be factored into a new method. Where possible "emit*" methods should
/// be const, and any flags that change how the prologue is emitted should be
/// set in the constructor.
class AArch64PrologueEmitter final : public AArch64PrologueEpilogueCommon {
public:
AArch64PrologueEmitter(MachineFunction &MF, MachineBasicBlock &MBB,
const AArch64FrameLowering &AFL);
/// Emit the prologue.
void emitPrologue();
~AArch64PrologueEmitter() {
MF.setHasWinCFI(HasWinCFI);
#ifndef NDEBUG
verifyPrologueClobbers();
#endif
}
private:
void allocateStackSpace(MachineBasicBlock::iterator MBBI,
int64_t RealignmentPadding, StackOffset AllocSize,
bool EmitCFI, StackOffset InitialOffset,
bool FollowupAllocs);
void emitShadowCallStackPrologue(MachineBasicBlock::iterator MBBI,
const DebugLoc &DL) const;
void emitSwiftAsyncContextFramePointer(MachineBasicBlock::iterator MBBI,
const DebugLoc &DL) const;
void emitEmptyStackFramePrologue(int64_t NumBytes,
MachineBasicBlock::iterator MBBI,
const DebugLoc &DL) const;
void emitFramePointerSetup(MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, unsigned FixedObject);
void emitDefineCFAWithFP(MachineBasicBlock::iterator MBBI,
unsigned FixedObject) const;
void emitWindowsStackProbe(MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, int64_t &NumBytes,
int64_t RealignmentPadding) const;
void emitCalleeSavedGPRLocations(MachineBasicBlock::iterator MBBI) const;
void emitCalleeSavedSVELocations(MachineBasicBlock::iterator MBBI) const;
void determineLocalsStackSize(uint64_t StackSize, uint64_t PrologueSaveSize);
const Function &F;
#ifndef NDEBUG
mutable LivePhysRegs LiveRegs{RegInfo};
MachineBasicBlock::iterator PrologueEndI;
void collectBlockLiveins();
void verifyPrologueClobbers() const;
#endif
// Prologue flags. These generally should not change outside of the
// constructor.
bool EmitAsyncCFI = false;
bool CombineSPBump = false; // Note: This is set in determineLocalsStackSize.
};
/// A helper class for emitting the epilogue. Substantial new functionality
/// should be factored into a new method. Where possible "emit*" methods should
/// be const, and any flags that change how the epilogue is emitted should be
/// set in the constructor.
class AArch64EpilogueEmitter final : public AArch64PrologueEpilogueCommon {
public:
AArch64EpilogueEmitter(MachineFunction &MF, MachineBasicBlock &MBB,
const AArch64FrameLowering &AFL);
/// Emit the epilogue.
void emitEpilogue();
~AArch64EpilogueEmitter() { finalizeEpilogue(); }
private:
bool shouldCombineCSRLocalStackBump(uint64_t StackBumpBytes) const;
/// A helper for moving the SP to a negative offset from the FP, without
/// deallocating any stack in the range FP to FP + Offset.
void moveSPBelowFP(MachineBasicBlock::iterator MBBI, StackOffset Offset);
void emitSwiftAsyncContextFramePointer(MachineBasicBlock::iterator MBBI,
const DebugLoc &DL) const;
void emitShadowCallStackEpilogue(MachineBasicBlock::iterator MBBI,
const DebugLoc &DL) const;
void emitCalleeSavedRestores(MachineBasicBlock::iterator MBBI,
bool SVE) const;
void emitCalleeSavedGPRRestores(MachineBasicBlock::iterator MBBI) const {
emitCalleeSavedRestores(MBBI, /*SVE=*/false);
}
void emitCalleeSavedSVERestores(MachineBasicBlock::iterator MBBI) const {
emitCalleeSavedRestores(MBBI, /*SVE=*/true);
}
void finalizeEpilogue() const;
MachineBasicBlock::iterator SEHEpilogueStartI;
DebugLoc DL;
};
} // namespace llvm
#endif