forked from OSchip/llvm-project
[AArch64] NFC: Add generic StackOffset to describe scalable offsets.
To support spilling/filling of scalable vectors we need a more generic representation of a stack offset than simply 'int'. For this we introduce the StackOffset struct, which comprises multiple offsets sized by their respective MVTs. Byte-offsets will thus be a simple tuple such as { offset, MVT::i8 }. Adding two byte-offsets will result in a byte offset { offsetA + offsetB, MVT::i8 }. When two offsets have different types, we can canonicalise them to use the same MVT, as long as their runtime sizes are guaranteed to have the same size-ratio as they would have at compile-time. When we have both scalable- and fixed-size objects on the stack, we can create an offset that is: ({ offset_fixed, MVT::i8 } + { offset_scalable, MVT::nxv1i8 }) The struct also contains a getForFrameOffset() method that is specific to AArch64 and decomposes the frame-offset to be used directly in instructions that operate on the stack or index into the stack. Note: This patch adds StackOffset as an AArch64-only concept, but we would like to make this a generic concept/struct that is supported by all interfaces that take or return stack offsets (currently as 'int'). Since that would be a bigger change that is currently pending on D32530 landing, we thought it makes sense to first show/prove the concept in the AArch64 target before proposing to roll this out further. Reviewers: thegameg, rovka, t.p.northover, efriedma, greened Reviewed By: rovka, greened Differential Revision: https://reviews.llvm.org/D61435 llvm-svn: 368024
This commit is contained in:
parent
2fbf58c6e6
commit
612b038966
|
@ -659,11 +659,12 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
|
||||||
// instruction sequence.
|
// instruction sequence.
|
||||||
int BaseOffset = -AFI->getTaggedBasePointerOffset();
|
int BaseOffset = -AFI->getTaggedBasePointerOffset();
|
||||||
unsigned FrameReg;
|
unsigned FrameReg;
|
||||||
int FrameRegOffset = TFI->resolveFrameOffsetReference(
|
StackOffset FrameRegOffset = TFI->resolveFrameOffsetReference(
|
||||||
MF, BaseOffset, false /*isFixed*/, FrameReg, /*PreferFP=*/false,
|
MF, BaseOffset, false /*isFixed*/, FrameReg,
|
||||||
|
/*PreferFP=*/false,
|
||||||
/*ForSimm=*/true);
|
/*ForSimm=*/true);
|
||||||
Register SrcReg = FrameReg;
|
Register SrcReg = FrameReg;
|
||||||
if (FrameRegOffset != 0) {
|
if (FrameRegOffset) {
|
||||||
// Use output register as temporary.
|
// Use output register as temporary.
|
||||||
SrcReg = MI.getOperand(0).getReg();
|
SrcReg = MI.getOperand(0).getReg();
|
||||||
emitFrameOffset(MBB, &MI, MI.getDebugLoc(), SrcReg, FrameReg,
|
emitFrameOffset(MBB, &MI, MI.getDebugLoc(), SrcReg, FrameReg,
|
||||||
|
|
|
@ -94,6 +94,7 @@
|
||||||
#include "AArch64InstrInfo.h"
|
#include "AArch64InstrInfo.h"
|
||||||
#include "AArch64MachineFunctionInfo.h"
|
#include "AArch64MachineFunctionInfo.h"
|
||||||
#include "AArch64RegisterInfo.h"
|
#include "AArch64RegisterInfo.h"
|
||||||
|
#include "AArch64StackOffset.h"
|
||||||
#include "AArch64Subtarget.h"
|
#include "AArch64Subtarget.h"
|
||||||
#include "AArch64TargetMachine.h"
|
#include "AArch64TargetMachine.h"
|
||||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||||
|
@ -173,7 +174,7 @@ static unsigned estimateRSStackSizeLimit(MachineFunction &MF) {
|
||||||
if (!MO.isFI())
|
if (!MO.isFI())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int Offset = 0;
|
StackOffset Offset;
|
||||||
if (isAArch64FrameOffsetLegal(MI, Offset, nullptr, nullptr, nullptr) ==
|
if (isAArch64FrameOffsetLegal(MI, Offset, nullptr, nullptr, nullptr) ==
|
||||||
AArch64FrameOffsetCannotUpdate)
|
AArch64FrameOffsetCannotUpdate)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -273,14 +274,15 @@ MachineBasicBlock::iterator AArch64FrameLowering::eliminateCallFramePseudoInstr(
|
||||||
// Most call frames will be allocated at the start of a function so
|
// Most call frames will be allocated at the start of a function so
|
||||||
// this is OK, but it is a limitation that needs dealing with.
|
// this is OK, but it is a limitation that needs dealing with.
|
||||||
assert(Amount > -0xffffff && Amount < 0xffffff && "call frame too large");
|
assert(Amount > -0xffffff && Amount < 0xffffff && "call frame too large");
|
||||||
emitFrameOffset(MBB, I, DL, AArch64::SP, AArch64::SP, Amount, TII);
|
emitFrameOffset(MBB, I, DL, AArch64::SP, AArch64::SP, {Amount, MVT::i8},
|
||||||
|
TII);
|
||||||
}
|
}
|
||||||
} else if (CalleePopAmount != 0) {
|
} else if (CalleePopAmount != 0) {
|
||||||
// If the calling convention demands that the callee pops arguments from the
|
// If the calling convention demands that the callee pops arguments from the
|
||||||
// stack, we want to add it back if we have a reserved call frame.
|
// stack, we want to add it back if we have a reserved call frame.
|
||||||
assert(CalleePopAmount < 0xffffff && "call frame too large");
|
assert(CalleePopAmount < 0xffffff && "call frame too large");
|
||||||
emitFrameOffset(MBB, I, DL, AArch64::SP, AArch64::SP, -CalleePopAmount,
|
emitFrameOffset(MBB, I, DL, AArch64::SP, AArch64::SP,
|
||||||
TII);
|
{-(int64_t)CalleePopAmount, MVT::i8}, TII);
|
||||||
}
|
}
|
||||||
return MBB.erase(I);
|
return MBB.erase(I);
|
||||||
}
|
}
|
||||||
|
@ -866,8 +868,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||||
AFI->setHasRedZone(true);
|
AFI->setHasRedZone(true);
|
||||||
++NumRedZoneFunctions;
|
++NumRedZoneFunctions;
|
||||||
} else {
|
} else {
|
||||||
emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP, -NumBytes, TII,
|
emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP,
|
||||||
MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI);
|
{-NumBytes, MVT::i8}, TII, MachineInstr::FrameSetup,
|
||||||
|
false, NeedsWinCFI, &HasWinCFI);
|
||||||
if (!NeedsWinCFI) {
|
if (!NeedsWinCFI) {
|
||||||
// Label used to tie together the PROLOG_LABEL and the MachineMoves.
|
// Label used to tie together the PROLOG_LABEL and the MachineMoves.
|
||||||
MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
|
MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
|
||||||
|
@ -901,8 +904,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||||
AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
|
AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
|
||||||
bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes);
|
bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes);
|
||||||
if (CombineSPBump) {
|
if (CombineSPBump) {
|
||||||
emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP, -NumBytes, TII,
|
emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP,
|
||||||
MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI);
|
{-NumBytes, MVT::i8}, TII, MachineInstr::FrameSetup, false,
|
||||||
|
NeedsWinCFI, &HasWinCFI);
|
||||||
NumBytes = 0;
|
NumBytes = 0;
|
||||||
} else if (PrologueSaveSize != 0) {
|
} else if (PrologueSaveSize != 0) {
|
||||||
MBBI = convertCalleeSaveRestoreToSPPrePostIncDec(
|
MBBI = convertCalleeSaveRestoreToSPPrePostIncDec(
|
||||||
|
@ -958,8 +962,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||||
// mov fp,sp when FPOffset is zero.
|
// mov fp,sp when FPOffset is zero.
|
||||||
// Note: All stores of callee-saved registers are marked as "FrameSetup".
|
// Note: All stores of callee-saved registers are marked as "FrameSetup".
|
||||||
// This code marks the instruction(s) that set the FP also.
|
// This code marks the instruction(s) that set the FP also.
|
||||||
emitFrameOffset(MBB, MBBI, DL, AArch64::FP, AArch64::SP, FPOffset, TII,
|
emitFrameOffset(MBB, MBBI, DL, AArch64::FP, AArch64::SP,
|
||||||
MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI);
|
{FPOffset, MVT::i8}, TII, MachineInstr::FrameSetup, false,
|
||||||
|
NeedsWinCFI, &HasWinCFI);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (windowsRequiresStackProbe(MF, NumBytes)) {
|
if (windowsRequiresStackProbe(MF, NumBytes)) {
|
||||||
|
@ -1071,8 +1076,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
|
||||||
// FIXME: in the case of dynamic re-alignment, NumBytes doesn't have
|
// FIXME: in the case of dynamic re-alignment, NumBytes doesn't have
|
||||||
// the correct value here, as NumBytes also includes padding bytes,
|
// the correct value here, as NumBytes also includes padding bytes,
|
||||||
// which shouldn't be counted here.
|
// which shouldn't be counted here.
|
||||||
emitFrameOffset(MBB, MBBI, DL, scratchSPReg, AArch64::SP, -NumBytes, TII,
|
emitFrameOffset(MBB, MBBI, DL, scratchSPReg, AArch64::SP,
|
||||||
MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI);
|
{-NumBytes, MVT::i8}, TII, MachineInstr::FrameSetup,
|
||||||
|
false, NeedsWinCFI, &HasWinCFI);
|
||||||
|
|
||||||
if (NeedsRealignment) {
|
if (NeedsRealignment) {
|
||||||
const unsigned Alignment = MFI.getMaxAlignment();
|
const unsigned Alignment = MFI.getMaxAlignment();
|
||||||
|
@ -1404,8 +1410,8 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||||
// If there is a single SP update, insert it before the ret and we're done.
|
// If there is a single SP update, insert it before the ret and we're done.
|
||||||
if (CombineSPBump) {
|
if (CombineSPBump) {
|
||||||
emitFrameOffset(MBB, MBB.getFirstTerminator(), DL, AArch64::SP, AArch64::SP,
|
emitFrameOffset(MBB, MBB.getFirstTerminator(), DL, AArch64::SP, AArch64::SP,
|
||||||
NumBytes + AfterCSRPopSize, TII, MachineInstr::FrameDestroy,
|
{NumBytes + (int64_t)AfterCSRPopSize, MVT::i8}, TII,
|
||||||
false, NeedsWinCFI, &HasWinCFI);
|
MachineInstr::FrameDestroy, false, NeedsWinCFI, &HasWinCFI);
|
||||||
if (NeedsWinCFI && HasWinCFI)
|
if (NeedsWinCFI && HasWinCFI)
|
||||||
BuildMI(MBB, MBB.getFirstTerminator(), DL,
|
BuildMI(MBB, MBB.getFirstTerminator(), DL,
|
||||||
TII->get(AArch64::SEH_EpilogEnd))
|
TII->get(AArch64::SEH_EpilogEnd))
|
||||||
|
@ -1437,8 +1443,8 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||||
adaptForLdStOpt(MBB, MBB.getFirstTerminator(), LastPopI);
|
adaptForLdStOpt(MBB, MBB.getFirstTerminator(), LastPopI);
|
||||||
|
|
||||||
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::SP,
|
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::SP,
|
||||||
StackRestoreBytes, TII, MachineInstr::FrameDestroy, false,
|
{StackRestoreBytes, MVT::i8}, TII,
|
||||||
NeedsWinCFI, &HasWinCFI);
|
MachineInstr::FrameDestroy, false, NeedsWinCFI, &HasWinCFI);
|
||||||
if (Done) {
|
if (Done) {
|
||||||
if (NeedsWinCFI) {
|
if (NeedsWinCFI) {
|
||||||
HasWinCFI = true;
|
HasWinCFI = true;
|
||||||
|
@ -1458,11 +1464,12 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||||
// be able to save any instructions.
|
// be able to save any instructions.
|
||||||
if (!IsFunclet && (MFI.hasVarSizedObjects() || AFI->isStackRealigned()))
|
if (!IsFunclet && (MFI.hasVarSizedObjects() || AFI->isStackRealigned()))
|
||||||
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::FP,
|
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::FP,
|
||||||
-AFI->getCalleeSavedStackSize() + 16, TII,
|
{-(int64_t)AFI->getCalleeSavedStackSize() + 16, MVT::i8},
|
||||||
MachineInstr::FrameDestroy, false, NeedsWinCFI);
|
TII, MachineInstr::FrameDestroy, false, NeedsWinCFI);
|
||||||
else if (NumBytes)
|
else if (NumBytes)
|
||||||
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::SP, NumBytes, TII,
|
emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::SP,
|
||||||
MachineInstr::FrameDestroy, false, NeedsWinCFI);
|
{NumBytes, MVT::i8}, TII, MachineInstr::FrameDestroy, false,
|
||||||
|
NeedsWinCFI);
|
||||||
|
|
||||||
// This must be placed after the callee-save restore code because that code
|
// This must be placed after the callee-save restore code because that code
|
||||||
// assumes the SP is at the same location as it was after the callee-save save
|
// assumes the SP is at the same location as it was after the callee-save save
|
||||||
|
@ -1483,8 +1490,8 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
|
||||||
adaptForLdStOpt(MBB, FirstSPPopI, LastPopI);
|
adaptForLdStOpt(MBB, FirstSPPopI, LastPopI);
|
||||||
|
|
||||||
emitFrameOffset(MBB, FirstSPPopI, DL, AArch64::SP, AArch64::SP,
|
emitFrameOffset(MBB, FirstSPPopI, DL, AArch64::SP, AArch64::SP,
|
||||||
AfterCSRPopSize, TII, MachineInstr::FrameDestroy, false,
|
{(int64_t)AfterCSRPopSize, MVT::i8}, TII,
|
||||||
NeedsWinCFI, &HasWinCFI);
|
MachineInstr::FrameDestroy, false, NeedsWinCFI, &HasWinCFI);
|
||||||
}
|
}
|
||||||
if (NeedsWinCFI && HasWinCFI)
|
if (NeedsWinCFI && HasWinCFI)
|
||||||
BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::SEH_EpilogEnd))
|
BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::SEH_EpilogEnd))
|
||||||
|
@ -1504,7 +1511,8 @@ int AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF,
|
||||||
MF, FI, FrameReg,
|
MF, FI, FrameReg,
|
||||||
/*PreferFP=*/
|
/*PreferFP=*/
|
||||||
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress),
|
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress),
|
||||||
/*ForSimm=*/false);
|
/*ForSimm=*/false)
|
||||||
|
.getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AArch64FrameLowering::getNonLocalFrameIndexReference(
|
int AArch64FrameLowering::getNonLocalFrameIndexReference(
|
||||||
|
@ -1512,18 +1520,18 @@ int AArch64FrameLowering::getNonLocalFrameIndexReference(
|
||||||
return getSEHFrameIndexOffset(MF, FI);
|
return getSEHFrameIndexOffset(MF, FI);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getFPOffset(const MachineFunction &MF, int ObjectOffset) {
|
static StackOffset getFPOffset(const MachineFunction &MF, int ObjectOffset) {
|
||||||
const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
|
const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||||
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
|
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
|
||||||
bool IsWin64 =
|
bool IsWin64 =
|
||||||
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
|
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
|
||||||
unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
|
unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
|
||||||
return ObjectOffset + FixedObject + 16;
|
return {ObjectOffset + FixedObject + 16, MVT::i8};
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getStackOffset(const MachineFunction &MF, int ObjectOffset) {
|
static StackOffset getStackOffset(const MachineFunction &MF, int ObjectOffset) {
|
||||||
const auto &MFI = MF.getFrameInfo();
|
const auto &MFI = MF.getFrameInfo();
|
||||||
return ObjectOffset + MFI.getStackSize();
|
return {ObjectOffset + (int)MFI.getStackSize(), MVT::i8};
|
||||||
}
|
}
|
||||||
|
|
||||||
int AArch64FrameLowering::getSEHFrameIndexOffset(const MachineFunction &MF,
|
int AArch64FrameLowering::getSEHFrameIndexOffset(const MachineFunction &MF,
|
||||||
|
@ -1532,13 +1540,12 @@ int AArch64FrameLowering::getSEHFrameIndexOffset(const MachineFunction &MF,
|
||||||
MF.getSubtarget().getRegisterInfo());
|
MF.getSubtarget().getRegisterInfo());
|
||||||
int ObjectOffset = MF.getFrameInfo().getObjectOffset(FI);
|
int ObjectOffset = MF.getFrameInfo().getObjectOffset(FI);
|
||||||
return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
|
return RegInfo->getLocalAddressRegister(MF) == AArch64::FP
|
||||||
? getFPOffset(MF, ObjectOffset)
|
? getFPOffset(MF, ObjectOffset).getBytes()
|
||||||
: getStackOffset(MF, ObjectOffset);
|
: getStackOffset(MF, ObjectOffset).getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AArch64FrameLowering::resolveFrameIndexReference(const MachineFunction &MF,
|
StackOffset AArch64FrameLowering::resolveFrameIndexReference(
|
||||||
int FI, unsigned &FrameReg,
|
const MachineFunction &MF, int FI, unsigned &FrameReg, bool PreferFP,
|
||||||
bool PreferFP,
|
|
||||||
bool ForSimm) const {
|
bool ForSimm) const {
|
||||||
const auto &MFI = MF.getFrameInfo();
|
const auto &MFI = MF.getFrameInfo();
|
||||||
int ObjectOffset = MFI.getObjectOffset(FI);
|
int ObjectOffset = MFI.getObjectOffset(FI);
|
||||||
|
@ -1547,7 +1554,7 @@ int AArch64FrameLowering::resolveFrameIndexReference(const MachineFunction &MF,
|
||||||
PreferFP, ForSimm);
|
PreferFP, ForSimm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AArch64FrameLowering::resolveFrameOffsetReference(
|
StackOffset AArch64FrameLowering::resolveFrameOffsetReference(
|
||||||
const MachineFunction &MF, int ObjectOffset, bool isFixed,
|
const MachineFunction &MF, int ObjectOffset, bool isFixed,
|
||||||
unsigned &FrameReg, bool PreferFP, bool ForSimm) const {
|
unsigned &FrameReg, bool PreferFP, bool ForSimm) const {
|
||||||
const auto &MFI = MF.getFrameInfo();
|
const auto &MFI = MF.getFrameInfo();
|
||||||
|
@ -1556,8 +1563,8 @@ int AArch64FrameLowering::resolveFrameOffsetReference(
|
||||||
const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
|
const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||||
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
|
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
|
||||||
|
|
||||||
int FPOffset = getFPOffset(MF, ObjectOffset);
|
int FPOffset = getFPOffset(MF, ObjectOffset).getBytes();
|
||||||
int Offset = getStackOffset(MF, ObjectOffset);
|
int Offset = getStackOffset(MF, ObjectOffset).getBytes();
|
||||||
bool isCSR =
|
bool isCSR =
|
||||||
!isFixed && ObjectOffset >= -((int)AFI->getCalleeSavedStackSize());
|
!isFixed && ObjectOffset >= -((int)AFI->getCalleeSavedStackSize());
|
||||||
|
|
||||||
|
@ -1627,7 +1634,7 @@ int AArch64FrameLowering::resolveFrameOffsetReference(
|
||||||
|
|
||||||
if (UseFP) {
|
if (UseFP) {
|
||||||
FrameReg = RegInfo->getFrameRegister(MF);
|
FrameReg = RegInfo->getFrameRegister(MF);
|
||||||
return FPOffset;
|
return StackOffset(FPOffset, MVT::i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the base pointer if we have one.
|
// Use the base pointer if we have one.
|
||||||
|
@ -1644,7 +1651,7 @@ int AArch64FrameLowering::resolveFrameOffsetReference(
|
||||||
Offset -= AFI->getLocalStackSize();
|
Offset -= AFI->getLocalStackSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Offset;
|
return StackOffset(Offset, MVT::i8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned getPrologueDeath(MachineFunction &MF, unsigned Reg) {
|
static unsigned getPrologueDeath(MachineFunction &MF, unsigned Reg) {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
|
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
|
||||||
#define LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
|
#define LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
|
||||||
|
|
||||||
|
#include "AArch64StackOffset.h"
|
||||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
@ -39,12 +40,13 @@ public:
|
||||||
|
|
||||||
int getFrameIndexReference(const MachineFunction &MF, int FI,
|
int getFrameIndexReference(const MachineFunction &MF, int FI,
|
||||||
unsigned &FrameReg) const override;
|
unsigned &FrameReg) const override;
|
||||||
int resolveFrameIndexReference(const MachineFunction &MF, int FI,
|
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI,
|
||||||
|
unsigned &FrameReg, bool PreferFP,
|
||||||
|
bool ForSimm) const;
|
||||||
|
StackOffset resolveFrameOffsetReference(const MachineFunction &MF,
|
||||||
|
int ObjectOffset, bool isFixed,
|
||||||
unsigned &FrameReg, bool PreferFP,
|
unsigned &FrameReg, bool PreferFP,
|
||||||
bool ForSimm) const;
|
bool ForSimm) const;
|
||||||
int resolveFrameOffsetReference(const MachineFunction &MF, int ObjectOffset,
|
|
||||||
bool isFixed, unsigned &FrameReg,
|
|
||||||
bool PreferFP, bool ForSimm) const;
|
|
||||||
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||||
MachineBasicBlock::iterator MI,
|
MachineBasicBlock::iterator MI,
|
||||||
const std::vector<CalleeSavedInfo> &CSI,
|
const std::vector<CalleeSavedInfo> &CSI,
|
||||||
|
|
|
@ -2974,10 +2974,12 @@ void AArch64InstrInfo::loadRegFromStackSlot(
|
||||||
|
|
||||||
void llvm::emitFrameOffset(MachineBasicBlock &MBB,
|
void llvm::emitFrameOffset(MachineBasicBlock &MBB,
|
||||||
MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
|
MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
|
||||||
unsigned DestReg, unsigned SrcReg, int Offset,
|
unsigned DestReg, unsigned SrcReg,
|
||||||
const TargetInstrInfo *TII,
|
StackOffset SOffset, const TargetInstrInfo *TII,
|
||||||
MachineInstr::MIFlag Flag, bool SetNZCV,
|
MachineInstr::MIFlag Flag, bool SetNZCV,
|
||||||
bool NeedsWinCFI, bool *HasWinCFI) {
|
bool NeedsWinCFI, bool *HasWinCFI) {
|
||||||
|
int64_t Offset;
|
||||||
|
SOffset.getForFrameOffset(Offset);
|
||||||
if (DestReg == SrcReg && Offset == 0)
|
if (DestReg == SrcReg && Offset == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -3239,7 +3241,8 @@ MachineInstr *AArch64InstrInfo::foldMemoryOperandImpl(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int llvm::isAArch64FrameOffsetLegal(const MachineInstr &MI, int &Offset,
|
int llvm::isAArch64FrameOffsetLegal(const MachineInstr &MI,
|
||||||
|
StackOffset &SOffset,
|
||||||
bool *OutUseUnscaledOp,
|
bool *OutUseUnscaledOp,
|
||||||
unsigned *OutUnscaledOp,
|
unsigned *OutUnscaledOp,
|
||||||
int *EmittableOffset) {
|
int *EmittableOffset) {
|
||||||
|
@ -3283,7 +3286,7 @@ int llvm::isAArch64FrameOffsetLegal(const MachineInstr &MI, int &Offset,
|
||||||
// Construct the complete offset.
|
// Construct the complete offset.
|
||||||
const MachineOperand &ImmOpnd =
|
const MachineOperand &ImmOpnd =
|
||||||
MI.getOperand(AArch64InstrInfo::getLoadStoreImmIdx(MI.getOpcode()));
|
MI.getOperand(AArch64InstrInfo::getLoadStoreImmIdx(MI.getOpcode()));
|
||||||
Offset += ImmOpnd.getImm() * Scale;
|
int Offset = SOffset.getBytes() + ImmOpnd.getImm() * Scale;
|
||||||
|
|
||||||
// If the offset doesn't match the scale, we rewrite the instruction to
|
// If the offset doesn't match the scale, we rewrite the instruction to
|
||||||
// use the unscaled instruction instead. Likewise, if we have a negative
|
// use the unscaled instruction instead. Likewise, if we have a negative
|
||||||
|
@ -3315,23 +3318,24 @@ int llvm::isAArch64FrameOffsetLegal(const MachineInstr &MI, int &Offset,
|
||||||
if (OutUnscaledOp && UnscaledOp)
|
if (OutUnscaledOp && UnscaledOp)
|
||||||
*OutUnscaledOp = *UnscaledOp;
|
*OutUnscaledOp = *UnscaledOp;
|
||||||
|
|
||||||
|
SOffset = StackOffset(Offset, MVT::i8);
|
||||||
return AArch64FrameOffsetCanUpdate |
|
return AArch64FrameOffsetCanUpdate |
|
||||||
(Offset == 0 ? AArch64FrameOffsetIsLegal : 0);
|
(Offset == 0 ? AArch64FrameOffsetIsLegal : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool llvm::rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
bool llvm::rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||||
unsigned FrameReg, int &Offset,
|
unsigned FrameReg, StackOffset &Offset,
|
||||||
const AArch64InstrInfo *TII) {
|
const AArch64InstrInfo *TII) {
|
||||||
unsigned Opcode = MI.getOpcode();
|
unsigned Opcode = MI.getOpcode();
|
||||||
unsigned ImmIdx = FrameRegIdx + 1;
|
unsigned ImmIdx = FrameRegIdx + 1;
|
||||||
|
|
||||||
if (Opcode == AArch64::ADDSXri || Opcode == AArch64::ADDXri) {
|
if (Opcode == AArch64::ADDSXri || Opcode == AArch64::ADDXri) {
|
||||||
Offset += MI.getOperand(ImmIdx).getImm();
|
Offset += StackOffset(MI.getOperand(ImmIdx).getImm(), MVT::i8);
|
||||||
emitFrameOffset(*MI.getParent(), MI, MI.getDebugLoc(),
|
emitFrameOffset(*MI.getParent(), MI, MI.getDebugLoc(),
|
||||||
MI.getOperand(0).getReg(), FrameReg, Offset, TII,
|
MI.getOperand(0).getReg(), FrameReg, Offset, TII,
|
||||||
MachineInstr::NoFlags, (Opcode == AArch64::ADDSXri));
|
MachineInstr::NoFlags, (Opcode == AArch64::ADDSXri));
|
||||||
MI.eraseFromParent();
|
MI.eraseFromParent();
|
||||||
Offset = 0;
|
Offset = StackOffset();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3348,7 +3352,7 @@ bool llvm::rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||||
MI.setDesc(TII->get(UnscaledOp));
|
MI.setDesc(TII->get(UnscaledOp));
|
||||||
|
|
||||||
MI.getOperand(ImmIdx).ChangeToImmediate(NewOffset);
|
MI.getOperand(ImmIdx).ChangeToImmediate(NewOffset);
|
||||||
return Offset == 0;
|
return !Offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "AArch64.h"
|
#include "AArch64.h"
|
||||||
#include "AArch64RegisterInfo.h"
|
#include "AArch64RegisterInfo.h"
|
||||||
|
#include "AArch64StackOffset.h"
|
||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
#include "llvm/CodeGen/MachineCombinerPattern.h"
|
#include "llvm/CodeGen/MachineCombinerPattern.h"
|
||||||
#include "llvm/CodeGen/TargetInstrInfo.h"
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
||||||
|
@ -299,7 +300,7 @@ private:
|
||||||
/// if necessary, to be replaced by the scavenger at the end of PEI.
|
/// if necessary, to be replaced by the scavenger at the end of PEI.
|
||||||
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||||
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
|
const DebugLoc &DL, unsigned DestReg, unsigned SrcReg,
|
||||||
int Offset, const TargetInstrInfo *TII,
|
StackOffset Offset, const TargetInstrInfo *TII,
|
||||||
MachineInstr::MIFlag = MachineInstr::NoFlags,
|
MachineInstr::MIFlag = MachineInstr::NoFlags,
|
||||||
bool SetNZCV = false, bool NeedsWinCFI = false,
|
bool SetNZCV = false, bool NeedsWinCFI = false,
|
||||||
bool *HasWinCFI = nullptr);
|
bool *HasWinCFI = nullptr);
|
||||||
|
@ -308,7 +309,7 @@ void emitFrameOffset(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||||
/// FP. Return false if the offset could not be handled directly in MI, and
|
/// FP. Return false if the offset could not be handled directly in MI, and
|
||||||
/// return the left-over portion by reference.
|
/// return the left-over portion by reference.
|
||||||
bool rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
bool rewriteAArch64FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
|
||||||
unsigned FrameReg, int &Offset,
|
unsigned FrameReg, StackOffset &Offset,
|
||||||
const AArch64InstrInfo *TII);
|
const AArch64InstrInfo *TII);
|
||||||
|
|
||||||
/// Use to report the frame offset status in isAArch64FrameOffsetLegal.
|
/// Use to report the frame offset status in isAArch64FrameOffsetLegal.
|
||||||
|
@ -332,7 +333,7 @@ enum AArch64FrameOffsetStatus {
|
||||||
/// If set, @p EmittableOffset contains the amount that can be set in @p MI
|
/// If set, @p EmittableOffset contains the amount that can be set in @p MI
|
||||||
/// (possibly with @p OutUnscaledOp if OutUseUnscaledOp is true) and that
|
/// (possibly with @p OutUnscaledOp if OutUseUnscaledOp is true) and that
|
||||||
/// is a legal offset.
|
/// is a legal offset.
|
||||||
int isAArch64FrameOffsetLegal(const MachineInstr &MI, int &Offset,
|
int isAArch64FrameOffsetLegal(const MachineInstr &MI, StackOffset &Offset,
|
||||||
bool *OutUseUnscaledOp = nullptr,
|
bool *OutUseUnscaledOp = nullptr,
|
||||||
unsigned *OutUnscaledOp = nullptr,
|
unsigned *OutUnscaledOp = nullptr,
|
||||||
int *EmittableOffset = nullptr);
|
int *EmittableOffset = nullptr);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "AArch64FrameLowering.h"
|
#include "AArch64FrameLowering.h"
|
||||||
#include "AArch64InstrInfo.h"
|
#include "AArch64InstrInfo.h"
|
||||||
#include "AArch64MachineFunctionInfo.h"
|
#include "AArch64MachineFunctionInfo.h"
|
||||||
|
#include "AArch64StackOffset.h"
|
||||||
#include "AArch64Subtarget.h"
|
#include "AArch64Subtarget.h"
|
||||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||||
#include "llvm/ADT/BitVector.h"
|
#include "llvm/ADT/BitVector.h"
|
||||||
|
@ -23,10 +24,10 @@
|
||||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||||
#include "llvm/IR/Function.h"
|
|
||||||
#include "llvm/IR/DiagnosticInfo.h"
|
|
||||||
#include "llvm/Support/raw_ostream.h"
|
|
||||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||||
|
#include "llvm/IR/DiagnosticInfo.h"
|
||||||
|
#include "llvm/IR/Function.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
#include "llvm/Target/TargetOptions.h"
|
#include "llvm/Target/TargetOptions.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
@ -390,7 +391,7 @@ bool AArch64RegisterInfo::isFrameOffsetLegal(const MachineInstr *MI,
|
||||||
int64_t Offset) const {
|
int64_t Offset) const {
|
||||||
assert(Offset <= INT_MAX && "Offset too big to fit in int.");
|
assert(Offset <= INT_MAX && "Offset too big to fit in int.");
|
||||||
assert(MI && "Unable to get the legal offset for nil instruction.");
|
assert(MI && "Unable to get the legal offset for nil instruction.");
|
||||||
int SaveOffset = Offset;
|
StackOffset SaveOffset(Offset, MVT::i8);
|
||||||
return isAArch64FrameOffsetLegal(*MI, SaveOffset) & AArch64FrameOffsetIsLegal;
|
return isAArch64FrameOffsetLegal(*MI, SaveOffset) & AArch64FrameOffsetIsLegal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +421,9 @@ void AArch64RegisterInfo::materializeFrameBaseRegister(MachineBasicBlock *MBB,
|
||||||
|
|
||||||
void AArch64RegisterInfo::resolveFrameIndex(MachineInstr &MI, unsigned BaseReg,
|
void AArch64RegisterInfo::resolveFrameIndex(MachineInstr &MI, unsigned BaseReg,
|
||||||
int64_t Offset) const {
|
int64_t Offset) const {
|
||||||
int Off = Offset; // ARM doesn't need the general 64-bit offsets
|
// ARM doesn't need the general 64-bit offsets
|
||||||
|
StackOffset Off(Offset, MVT::i8);
|
||||||
|
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
|
||||||
while (!MI.getOperand(i).isFI()) {
|
while (!MI.getOperand(i).isFI()) {
|
||||||
|
@ -449,34 +452,36 @@ void AArch64RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||||
|
|
||||||
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
|
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
|
||||||
unsigned FrameReg;
|
unsigned FrameReg;
|
||||||
int Offset;
|
|
||||||
|
|
||||||
// Special handling of dbg_value, stackmap and patchpoint instructions.
|
// Special handling of dbg_value, stackmap and patchpoint instructions.
|
||||||
if (MI.isDebugValue() || MI.getOpcode() == TargetOpcode::STACKMAP ||
|
if (MI.isDebugValue() || MI.getOpcode() == TargetOpcode::STACKMAP ||
|
||||||
MI.getOpcode() == TargetOpcode::PATCHPOINT) {
|
MI.getOpcode() == TargetOpcode::PATCHPOINT) {
|
||||||
Offset = TFI->resolveFrameIndexReference(MF, FrameIndex, FrameReg,
|
StackOffset Offset =
|
||||||
|
TFI->resolveFrameIndexReference(MF, FrameIndex, FrameReg,
|
||||||
/*PreferFP=*/true,
|
/*PreferFP=*/true,
|
||||||
/*ForSimm=*/false);
|
/*ForSimm=*/false);
|
||||||
Offset += MI.getOperand(FIOperandNum + 1).getImm();
|
Offset += StackOffset(MI.getOperand(FIOperandNum + 1).getImm(), MVT::i8);
|
||||||
MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false /*isDef*/);
|
MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false /*isDef*/);
|
||||||
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
|
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset.getBytes());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE) {
|
if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE) {
|
||||||
MachineOperand &FI = MI.getOperand(FIOperandNum);
|
MachineOperand &FI = MI.getOperand(FIOperandNum);
|
||||||
Offset = TFI->getNonLocalFrameIndexReference(MF, FrameIndex);
|
int Offset = TFI->getNonLocalFrameIndexReference(MF, FrameIndex);
|
||||||
FI.ChangeToImmediate(Offset);
|
FI.ChangeToImmediate(Offset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StackOffset Offset;
|
||||||
if (MI.getOpcode() == AArch64::TAGPstack) {
|
if (MI.getOpcode() == AArch64::TAGPstack) {
|
||||||
// TAGPstack must use the virtual frame register in its 3rd operand.
|
// TAGPstack must use the virtual frame register in its 3rd operand.
|
||||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||||
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
|
||||||
FrameReg = MI.getOperand(3).getReg();
|
FrameReg = MI.getOperand(3).getReg();
|
||||||
Offset =
|
Offset = {MFI.getObjectOffset(FrameIndex) +
|
||||||
MFI.getObjectOffset(FrameIndex) + AFI->getTaggedBasePointerOffset();
|
AFI->getTaggedBasePointerOffset(),
|
||||||
|
MVT::i8};
|
||||||
} else {
|
} else {
|
||||||
Offset = TFI->resolveFrameIndexReference(
|
Offset = TFI->resolveFrameIndexReference(
|
||||||
MF, FrameIndex, FrameReg, /*PreferFP=*/false, /*ForSimm=*/true);
|
MF, FrameIndex, FrameReg, /*PreferFP=*/false, /*ForSimm=*/true);
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
//==--AArch64StackOffset.h ---------------------------------------*- 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This file contains the declaration of the StackOffset class, which is used to
|
||||||
|
// describe scalable and non-scalable offsets during frame lowering.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64STACKOFFSET_H
|
||||||
|
#define LLVM_LIB_TARGET_AARCH64_AARCH64STACKOFFSET_H
|
||||||
|
|
||||||
|
#include "llvm/Support/MachineValueType.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
/// StackOffset is a wrapper around scalable and non-scalable offsets and is
|
||||||
|
/// used in several functions such as 'isAArch64FrameOffsetLegal' and
|
||||||
|
/// 'emitFrameOffset()'. StackOffsets are described by MVTs, e.g.
|
||||||
|
//
|
||||||
|
/// StackOffset(1, MVT::nxv16i8)
|
||||||
|
//
|
||||||
|
/// would describe an offset as being the size of a single SVE vector.
|
||||||
|
///
|
||||||
|
/// The class also implements simple arithmetic (addition/subtraction) on these
|
||||||
|
/// offsets, e.g.
|
||||||
|
//
|
||||||
|
/// StackOffset(1, MVT::nxv16i8) + StackOffset(1, MVT::i64)
|
||||||
|
//
|
||||||
|
/// describes an offset that spans the combined storage required for an SVE
|
||||||
|
/// vector and a 64bit GPR.
|
||||||
|
class StackOffset {
|
||||||
|
int64_t Bytes;
|
||||||
|
|
||||||
|
explicit operator int() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Part = std::pair<int64_t, MVT>;
|
||||||
|
|
||||||
|
StackOffset() : Bytes(0) {}
|
||||||
|
|
||||||
|
StackOffset(int64_t Offset, MVT::SimpleValueType T) : StackOffset() {
|
||||||
|
assert(!MVT(T).isScalableVector() && "Scalable types not supported");
|
||||||
|
*this += Part(Offset, T);
|
||||||
|
}
|
||||||
|
|
||||||
|
StackOffset(const StackOffset &Other) : Bytes(Other.Bytes) {}
|
||||||
|
|
||||||
|
StackOffset &operator=(const StackOffset &) = default;
|
||||||
|
|
||||||
|
StackOffset &operator+=(const StackOffset::Part &Other) {
|
||||||
|
assert(Other.second.getSizeInBits() % 8 == 0 &&
|
||||||
|
"Offset type is not a multiple of bytes");
|
||||||
|
Bytes += Other.first * (Other.second.getSizeInBits() / 8);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackOffset &operator+=(const StackOffset &Other) {
|
||||||
|
Bytes += Other.Bytes;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackOffset operator+(const StackOffset &Other) const {
|
||||||
|
StackOffset Res(*this);
|
||||||
|
Res += Other;
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackOffset &operator-=(const StackOffset &Other) {
|
||||||
|
Bytes -= Other.Bytes;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackOffset operator-(const StackOffset &Other) const {
|
||||||
|
StackOffset Res(*this);
|
||||||
|
Res -= Other;
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
StackOffset operator-() const {
|
||||||
|
StackOffset Res = {};
|
||||||
|
const StackOffset Other(*this);
|
||||||
|
Res -= Other;
|
||||||
|
return Res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the non-scalable part of the offset in bytes.
|
||||||
|
int64_t getBytes() const { return Bytes; }
|
||||||
|
|
||||||
|
/// Returns the offset in parts to which this frame offset can be
|
||||||
|
/// decomposed for the purpose of describing a frame offset.
|
||||||
|
/// For non-scalable offsets this is simply its byte size.
|
||||||
|
void getForFrameOffset(int64_t &ByteSized) const { ByteSized = Bytes; }
|
||||||
|
|
||||||
|
/// Returns whether the offset is known zero.
|
||||||
|
explicit operator bool() const { return Bytes; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end namespace llvm
|
||||||
|
|
||||||
|
#endif
|
|
@ -19,4 +19,5 @@ set(LLVM_LINK_COMPONENTS
|
||||||
|
|
||||||
add_llvm_unittest(AArch64Tests
|
add_llvm_unittest(AArch64Tests
|
||||||
InstSizes.cpp
|
InstSizes.cpp
|
||||||
|
TestStackOffset.cpp
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
//===- TestStackOffset.cpp - StackOffset unit tests------------------------===//
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "AArch64StackOffset.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
TEST(StackOffset, MixedSize) {
|
||||||
|
StackOffset A(1, MVT::i8);
|
||||||
|
EXPECT_EQ(1, A.getBytes());
|
||||||
|
|
||||||
|
StackOffset B(2, MVT::i32);
|
||||||
|
EXPECT_EQ(8, B.getBytes());
|
||||||
|
|
||||||
|
StackOffset C(2, MVT::v4i64);
|
||||||
|
EXPECT_EQ(64, C.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackOffset, Add) {
|
||||||
|
StackOffset A(1, MVT::i64);
|
||||||
|
StackOffset B(1, MVT::i32);
|
||||||
|
StackOffset C = A + B;
|
||||||
|
EXPECT_EQ(12, C.getBytes());
|
||||||
|
|
||||||
|
StackOffset D(1, MVT::i32);
|
||||||
|
D += A;
|
||||||
|
EXPECT_EQ(12, D.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackOffset, Sub) {
|
||||||
|
StackOffset A(1, MVT::i64);
|
||||||
|
StackOffset B(1, MVT::i32);
|
||||||
|
StackOffset C = A - B;
|
||||||
|
EXPECT_EQ(4, C.getBytes());
|
||||||
|
|
||||||
|
StackOffset D(1, MVT::i64);
|
||||||
|
D -= A;
|
||||||
|
EXPECT_EQ(0, D.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackOffset, isZero) {
|
||||||
|
StackOffset A(0, MVT::i64);
|
||||||
|
StackOffset B(0, MVT::i32);
|
||||||
|
EXPECT_TRUE(!A);
|
||||||
|
EXPECT_TRUE(!(A + B));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackOffset, getForFrameOffset) {
|
||||||
|
StackOffset A(1, MVT::i64);
|
||||||
|
StackOffset B(1, MVT::i32);
|
||||||
|
int64_t ByteSized;
|
||||||
|
(A + B).getForFrameOffset(ByteSized);
|
||||||
|
EXPECT_EQ(12, ByteSized);
|
||||||
|
}
|
Loading…
Reference in New Issue