CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
275 lines
12 KiB
C++
275 lines
12 KiB
C++
//==-- AArch64FrameLowering.h - TargetFrameLowering for AArch64 --*- 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_AARCH64_AARCH64FRAMELOWERING_H
|
|
#define LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
|
|
|
|
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
|
#include "llvm/Support/TypeSize.h"
|
|
|
|
namespace llvm {
|
|
|
|
class TargetLowering;
|
|
class AArch64FunctionInfo;
|
|
class AArch64InstrInfo;
|
|
class AArch64PrologueEmitter;
|
|
class AArch64EpilogueEmitter;
|
|
|
|
struct SVEStackSizes {
|
|
uint64_t ZPRStackSize{0};
|
|
uint64_t PPRStackSize{0};
|
|
};
|
|
|
|
class AArch64FrameLowering : public TargetFrameLowering {
|
|
public:
|
|
explicit AArch64FrameLowering()
|
|
: TargetFrameLowering(StackGrowsDown, Align(16), 0, Align(16),
|
|
true /*StackRealignable*/) {}
|
|
|
|
void resetCFIToInitialState(MachineBasicBlock &MBB) const override;
|
|
|
|
MachineBasicBlock::iterator
|
|
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
|
MachineBasicBlock::iterator I) const override;
|
|
|
|
/// 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;
|
|
|
|
/// Harden the entire function with pac-ret.
|
|
///
|
|
/// If pac-ret+leaf is requested, we want to harden as much code as possible.
|
|
/// This function inserts pac-ret hardening at the points where prologue and
|
|
/// epilogue are traditionally inserted, ignoring possible shrink-wrapping
|
|
/// optimization.
|
|
void emitPacRetPlusLeafHardening(MachineFunction &MF) const;
|
|
|
|
bool enableCFIFixup(const MachineFunction &MF) const override;
|
|
|
|
bool enableFullCFIFixup(const MachineFunction &MF) const override;
|
|
|
|
bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;
|
|
|
|
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
|
|
Register &FrameReg) const override;
|
|
StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
|
|
int FI) const override;
|
|
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI,
|
|
Register &FrameReg, bool PreferFP,
|
|
bool ForSimm) const;
|
|
StackOffset resolveFrameOffsetReference(const MachineFunction &MF,
|
|
int64_t ObjectOffset, bool isFixed,
|
|
TargetStackID::Value StackID,
|
|
Register &FrameReg, bool PreferFP,
|
|
bool ForSimm) const;
|
|
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;
|
|
|
|
/// Can this function use the red zone for local allocations.
|
|
bool canUseRedZone(const MachineFunction &MF) const;
|
|
|
|
/// Returns how much of the incoming argument stack area (in bytes) we should
|
|
/// clean up in an epilogue. For the C calling convention this will be 0, for
|
|
/// guaranteed tail call conventions it can be positive (a normal return or a
|
|
/// tail call to a function that uses less stack space for arguments) or
|
|
/// negative (for a tail call to a function that needs more stack space than
|
|
/// us for arguments).
|
|
int64_t getArgumentStackToRestore(MachineFunction &MF,
|
|
MachineBasicBlock &MBB) const;
|
|
|
|
bool hasReservedCallFrame(const MachineFunction &MF) const override;
|
|
|
|
bool
|
|
assignCalleeSavedSpillSlots(MachineFunction &MF,
|
|
const TargetRegisterInfo *TRI,
|
|
std::vector<CalleeSavedInfo> &CSI) const override;
|
|
|
|
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
|
RegScavenger *RS) const override;
|
|
|
|
/// Returns true if the target will correctly handle shrink wrapping.
|
|
bool enableShrinkWrapping(const MachineFunction &MF) const override {
|
|
return true;
|
|
}
|
|
|
|
bool enableStackSlotScavenging(const MachineFunction &MF) const override;
|
|
TargetStackID::Value getStackIDForScalableVectors() const override;
|
|
|
|
void processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
|
RegScavenger *RS) const override;
|
|
|
|
void
|
|
processFunctionBeforeFrameIndicesReplaced(MachineFunction &MF,
|
|
RegScavenger *RS) const override;
|
|
|
|
unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override;
|
|
|
|
unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;
|
|
|
|
StackOffset
|
|
getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
|
|
Register &FrameReg,
|
|
bool IgnoreSPUpdates) const override;
|
|
StackOffset getNonLocalFrameIndexReference(const MachineFunction &MF,
|
|
int FI) const override;
|
|
int getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const;
|
|
|
|
bool isSupportedStackID(TargetStackID::Value ID) const override {
|
|
switch (ID) {
|
|
default:
|
|
return false;
|
|
case TargetStackID::Default:
|
|
case TargetStackID::ScalableVector:
|
|
case TargetStackID::ScalablePredicateVector:
|
|
case TargetStackID::NoAlloc:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool isStackIdSafeForLocalArea(unsigned StackId) const override {
|
|
// We don't support putting SVE objects into the pre-allocated local
|
|
// frame block at the moment.
|
|
return (StackId != TargetStackID::ScalableVector &&
|
|
StackId != TargetStackID::ScalablePredicateVector);
|
|
}
|
|
|
|
void
|
|
orderFrameObjects(const MachineFunction &MF,
|
|
SmallVectorImpl<int> &ObjectsToAllocate) const override;
|
|
|
|
bool isFPReserved(const MachineFunction &MF) const;
|
|
|
|
bool needsWinCFI(const MachineFunction &MF) const;
|
|
|
|
bool requiresSaveVG(const MachineFunction &MF) const;
|
|
|
|
/// Returns the size of the entire ZPR stackframe (calleesaves + spills).
|
|
StackOffset getZPRStackSize(const MachineFunction &MF) const;
|
|
|
|
/// Returns the size of the entire PPR stackframe (calleesaves + spills +
|
|
/// hazard padding).
|
|
StackOffset getPPRStackSize(const MachineFunction &MF) const;
|
|
|
|
/// Returns the size of the entire SVE stackframe (PPRs + ZPRs).
|
|
StackOffset getSVEStackSize(const MachineFunction &MF) const {
|
|
return getZPRStackSize(MF) + getPPRStackSize(MF);
|
|
}
|
|
|
|
friend class AArch64PrologueEpilogueCommon;
|
|
friend class AArch64PrologueEmitter;
|
|
friend class AArch64EpilogueEmitter;
|
|
|
|
// Windows unwind can't represent the required stack adjustments if we have
|
|
// both SVE callee-saves and dynamic stack allocations, and the frame
|
|
// pointer is before the SVE spills. The allocation of the frame pointer
|
|
// must be the last instruction in the prologue so the unwinder can restore
|
|
// the stack pointer correctly. (And there isn't any unwind opcode for
|
|
// `addvl sp, x29, -17`.)
|
|
//
|
|
// Because of this, we do spills in the opposite order on Windows: first SVE,
|
|
// then GPRs. The main side-effect of this is that it makes accessing
|
|
// parameters passed on the stack more expensive.
|
|
//
|
|
// We could consider rearranging the spills for simpler cases.
|
|
bool hasSVECalleeSavesAboveFrameRecord(const MachineFunction &MF) const;
|
|
|
|
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
|
|
/// instructions are emitted in place. When Exit block is given, this check is
|
|
/// for epilog.
|
|
bool homogeneousPrologEpilog(MachineFunction &MF,
|
|
MachineBasicBlock *Exit = nullptr) const;
|
|
|
|
/// Returns true if CSRs should be paired.
|
|
bool producePairRegisters(MachineFunction &MF) const;
|
|
|
|
/// Make a determination whether a Hazard slot is used and create it if
|
|
/// needed.
|
|
void determineStackHazardSlot(MachineFunction &MF,
|
|
BitVector &SavedRegs) const;
|
|
|
|
/// Emit target zero call-used regs.
|
|
void emitZeroCallUsedRegs(BitVector RegsToZero,
|
|
MachineBasicBlock &MBB) const override;
|
|
|
|
/// Replace a StackProbe stub (if any) with the actual probe code inline
|
|
void inlineStackProbe(MachineFunction &MF,
|
|
MachineBasicBlock &PrologueMBB) const override;
|
|
|
|
void inlineStackProbeFixed(MachineBasicBlock::iterator MBBI,
|
|
Register ScratchReg, int64_t FrameSize,
|
|
StackOffset CFAOffset) const;
|
|
|
|
MachineBasicBlock::iterator
|
|
inlineStackProbeLoopExactMultiple(MachineBasicBlock::iterator MBBI,
|
|
int64_t NegProbeSize,
|
|
Register TargetReg) const;
|
|
|
|
void emitRemarks(const MachineFunction &MF,
|
|
MachineOptimizationRemarkEmitter *ORE) const override;
|
|
|
|
bool windowsRequiresStackProbe(const MachineFunction &MF,
|
|
uint64_t StackSizeInBytes) const;
|
|
|
|
bool shouldSignReturnAddressEverywhere(const MachineFunction &MF) const;
|
|
|
|
StackOffset getFPOffset(const MachineFunction &MF,
|
|
int64_t ObjectOffset) const;
|
|
|
|
StackOffset getStackOffset(const MachineFunction &MF,
|
|
int64_t ObjectOffset) const;
|
|
|
|
// Given a load or a store instruction, generate an appropriate unwinding SEH
|
|
// code on Windows.
|
|
MachineBasicBlock::iterator insertSEH(MachineBasicBlock::iterator MBBI,
|
|
const AArch64InstrInfo &TII,
|
|
MachineInstr::MIFlag Flag) const;
|
|
|
|
// Find a scratch register that we can use at the start of the prologue to
|
|
// re-align the stack pointer. We avoid using callee-save registers since
|
|
// they may appear to be free when this is called from canUseAsPrologue
|
|
// (during shrink wrapping), but then no longer be free when this is called
|
|
// from emitPrologue.
|
|
//
|
|
// FIXME: This is a bit conservative, since in the above case we could use one
|
|
// of the callee-save registers as a scratch temp to re-align the stack
|
|
// pointer, but we would then have to make sure that we were in fact saving at
|
|
// least one callee-save register in the prologue, which is additional
|
|
// complexity that doesn't seem worth the benefit.
|
|
Register findScratchNonCalleeSaveRegister(MachineBasicBlock *MBB,
|
|
bool HasCall = false) const;
|
|
|
|
/// Returns the size of the fixed object area (allocated next to sp on entry)
|
|
/// On Win64 this may include a var args area and an UnwindHelp object for EH.
|
|
unsigned getFixedObjectSize(const MachineFunction &MF,
|
|
const AArch64FunctionInfo *AFI, bool IsWin64,
|
|
bool IsFunclet) const;
|
|
};
|
|
|
|
} // End llvm namespace
|
|
|
|
#endif
|