Skip to content

Commit

Permalink
[SVE] Return StackOffset for TargetFrameLowering::getFrameIndexRefere…
Browse files Browse the repository at this point in the history
…nce.

To accommodate frame layouts that have both fixed and scalable objects
on the stack, describing a stack location or offset using a pointer + uint64_t
is not sufficient. For this reason, we've introduced the StackOffset class,
which models both the fixed- and scalable sized offsets.

The TargetFrameLowering::getFrameIndexReference is made to return a StackOffset,
so that this can be used in other interfaces, such as to eliminate frame indices
in PEI or to emit Debug locations for variables on the stack.

This patch is purely mechanical and doesn't change the behaviour of how
the result of this function is used for fixed-sized offsets. The patch adds
various checks to assert that the offset has no scalable component, as frame
offsets with a scalable component are not yet supported in various places.

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D90018
  • Loading branch information
sdesmalen-arm committed Nov 5, 2020
1 parent b257657 commit d57bba7
Show file tree
Hide file tree
Showing 44 changed files with 231 additions and 168 deletions.
16 changes: 9 additions & 7 deletions llvm/include/llvm/CodeGen/TargetFrameLowering.h
Expand Up @@ -14,6 +14,7 @@
#define LLVM_CODEGEN_TARGETFRAMELOWERING_H

#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/Support/TypeSize.h"
#include <vector>

namespace llvm {
Expand Down Expand Up @@ -297,27 +298,28 @@ class TargetFrameLowering {
/// getFrameIndexReference - This method should return the base register
/// and offset used to reference a frame index location. The offset is
/// returned directly, and the base register is returned via FrameReg.
virtual int getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const;
virtual StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const;

/// Same as \c getFrameIndexReference, except that the stack pointer (as
/// opposed to the frame pointer) will be the preferred value for \p
/// FrameReg. This is generally used for emitting statepoint or EH tables that
/// use offsets from RSP. If \p IgnoreSPUpdates is true, the returned
/// offset is only guaranteed to be valid with respect to the value of SP at
/// the end of the prologue.
virtual int getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
Register &FrameReg,
bool IgnoreSPUpdates) const {
virtual StackOffset
getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
Register &FrameReg,
bool IgnoreSPUpdates) const {
// Always safe to dispatch to getFrameIndexReference.
return getFrameIndexReference(MF, FI, FrameReg);
}

/// getNonLocalFrameIndexReference - This method returns the offset used to
/// reference a frame index location. The offset can be from either FP/BP/SP
/// based on which base register is returned by llvm.localaddress.
virtual int getNonLocalFrameIndexReference(const MachineFunction &MF,
int FI) const {
virtual StackOffset getNonLocalFrameIndexReference(const MachineFunction &MF,
int FI) const {
// By default, dispatch to getFrameIndexReference. Interested targets can
// override this.
Register FrameReg;
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Expand Up @@ -884,7 +884,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {

// The second operand is only an offset if it's an immediate.
bool MemLoc = MI->isIndirectDebugValue();
int64_t Offset = MemLoc ? MI->getOperand(1).getImm() : 0;
auto Offset = StackOffset::getFixed(MemLoc ? MI->getOperand(1).getImm() : 0);
const DIExpression *Expr = MI->getDebugExpression();
if (Expr->getNumElements()) {
OS << '[';
Expand Down Expand Up @@ -948,7 +948,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
}

if (MemLoc)
OS << '+' << Offset << ']';
OS << '+' << Offset.getFixed() << ']';

// NOTE: Want this comment at start of line, don't emit with AddComment.
AP.OutStreamer->emitRawComment(OS.str());
Expand Down
7 changes: 5 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
Expand Up @@ -1186,12 +1186,15 @@ void CodeViewDebug::collectVariableInfoFromMFTable(

// Get the frame register used and the offset.
Register FrameReg;
int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg);
StackOffset FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg);
uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg);

assert(!FrameOffset.getScalable() &&
"Frame offsets with a scalable component are not supported");

// Calculate the label ranges.
LocalVarDefRange DefRange =
createDefRangeMem(CVReg, FrameOffset + ExprOffset);
createDefRangeMem(CVReg, FrameOffset.getFixed() + ExprOffset);

for (const InsnRange &Range : Scope->getRanges()) {
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Expand Up @@ -730,10 +730,15 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
Register FrameReg;
const DIExpression *Expr = Fragment.Expr;
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg);
StackOffset Offset =
TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg);
DwarfExpr.addFragmentOffset(Expr);

assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");

SmallVector<uint64_t, 8> Ops;
DIExpression::appendOffset(Ops, Offset);
DIExpression::appendOffset(Ops, Offset.getFixed());
// According to
// https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf
// cuda-gdb requires DW_AT_address_class for all variables to be able to
Expand Down
20 changes: 12 additions & 8 deletions llvm/lib/CodeGen/AsmPrinter/WinException.cpp
Expand Up @@ -330,22 +330,24 @@ int WinException::getFrameIndexOffset(int FrameIndex,
const TargetFrameLowering &TFI = *Asm->MF->getSubtarget().getFrameLowering();
Register UnusedReg;
if (Asm->MAI->usesWindowsCFI()) {
int Offset =
StackOffset Offset =
TFI.getFrameIndexReferencePreferSP(*Asm->MF, FrameIndex, UnusedReg,
/*IgnoreSPUpdates*/ true);
assert(UnusedReg ==
Asm->MF->getSubtarget()
.getTargetLowering()
->getStackPointerRegisterToSaveRestore());
return Offset;
return Offset.getFixed();
}

// For 32-bit, offsets should be relative to the end of the EH registration
// node. For 64-bit, it's relative to SP at the end of the prologue.
assert(FuncInfo.EHRegNodeEndOffset != INT_MAX);
int Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg);
Offset += FuncInfo.EHRegNodeEndOffset;
return Offset;
StackOffset Offset = TFI.getFrameIndexReference(*Asm->MF, FrameIndex, UnusedReg);
Offset += StackOffset::getFixed(FuncInfo.EHRegNodeEndOffset);
assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");
return Offset.getFixed();
}

namespace {
Expand Down Expand Up @@ -942,7 +944,7 @@ void WinException::emitEHRegistrationOffsetLabel(const WinEHFuncInfo &FuncInfo,
int FI = FuncInfo.EHRegNodeFrameIndex;
if (FI != INT_MAX) {
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI);
Offset = TFI->getNonLocalFrameIndexReference(*Asm->MF, FI).getFixed();
}

MCContext &Ctx = Asm->OutContext;
Expand Down Expand Up @@ -1006,7 +1008,8 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
Register UnusedReg;
const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
int SSPIdx = MFI.getStackProtectorIndex();
GSCookieOffset = TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg);
GSCookieOffset =
TFI->getFrameIndexReference(*MF, SSPIdx, UnusedReg).getFixed();
}

// Retrieve the EH Guard slot.
Expand All @@ -1016,7 +1019,8 @@ void WinException::emitExceptHandlerTable(const MachineFunction *MF) {
Register UnusedReg;
const TargetFrameLowering *TFI = MF->getSubtarget().getFrameLowering();
int EHGuardIdx = FuncInfo.EHGuardFrameIndex;
EHCookieOffset = TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg);
EHCookieOffset =
TFI->getFrameIndexReference(*MF, EHGuardIdx, UnusedReg).getFixed();
}

AddComment("GSCookieOffset");
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/CodeGen/GCRootLowering.cpp
Expand Up @@ -296,7 +296,10 @@ void GCMachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) {
} else {
Register FrameReg; // FIXME: surely GCRoot ought to store the
// register that the offset is from?
RI->StackOffset = TFI->getFrameIndexReference(MF, RI->Num, FrameReg);
auto FrameOffset = TFI->getFrameIndexReference(MF, RI->Num, FrameReg);
assert(!FrameOffset.getScalable() &&
"Frame offsets with a scalable component are not supported");
RI->StackOffset = FrameOffset.getFixed();
++RI;
}
}
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
Expand Up @@ -1576,8 +1576,10 @@ InstrRefBasedLDV::extractSpillBaseRegAndOffset(const MachineInstr &MI) {
int FI = cast<FixedStackPseudoSourceValue>(PVal)->getFrameIndex();
const MachineBasicBlock *MBB = MI.getParent();
Register Reg;
int Offset = TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg);
return {Reg, Offset};
StackOffset Offset = TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg);
assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");
return {Reg, static_cast<int>(Offset.getFixed())};
}

/// End all previous ranges related to @MI and start a new range from @MI
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/CodeGen/LiveDebugValues/VarLocBasedImpl.cpp
Expand Up @@ -983,8 +983,10 @@ VarLocBasedLDV::extractSpillBaseRegAndOffset(const MachineInstr &MI) {
int FI = cast<FixedStackPseudoSourceValue>(PVal)->getFrameIndex();
const MachineBasicBlock *MBB = MI.getParent();
Register Reg;
int Offset = TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg);
return {Reg, Offset};
StackOffset Offset = TFI->getFrameIndexReference(*MBB->getParent(), FI, Reg);
assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");
return {Reg, static_cast<int>(Offset.getFixed())};
}

/// Try to salvage the debug entry value if we encounter a new debug value
Expand Down
12 changes: 8 additions & 4 deletions llvm/lib/CodeGen/PrologEpilogInserter.cpp
Expand Up @@ -1209,8 +1209,10 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
unsigned FrameIdx = MI.getOperand(0).getIndex();
unsigned Size = MF.getFrameInfo().getObjectSize(FrameIdx);

int64_t Offset =
StackOffset Offset =
TFI->getFrameIndexReference(MF, FrameIdx, Reg);
assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");
MI.getOperand(0).ChangeToRegister(Reg, false /*isDef*/);
MI.getOperand(0).setIsDebug();

Expand All @@ -1236,7 +1238,7 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
// Make the DBG_VALUE direct.
MI.getDebugOffset().ChangeToRegister(0, false);
}
DIExpr = DIExpression::prepend(DIExpr, PrependFlags, Offset);
DIExpr = DIExpression::prepend(DIExpr, PrependFlags, Offset.getFixed());
MI.getDebugExpressionOp().setMetadata(DIExpr);
continue;
}
Expand All @@ -1252,9 +1254,11 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &MF,
"DBG_VALUE machine instruction");
Register Reg;
MachineOperand &Offset = MI.getOperand(i + 1);
int refOffset = TFI->getFrameIndexReferencePreferSP(
StackOffset refOffset = TFI->getFrameIndexReferencePreferSP(
MF, MI.getOperand(i).getIndex(), Reg, /*IgnoreSPUpdates*/ false);
Offset.setImm(Offset.getImm() + refOffset + SPAdj);
assert(!refOffset.getScalable() &&
"Frame offsets with a scalable component are not supported");
Offset.setImm(Offset.getImm() + refOffset.getFixed() + SPAdj);
MI.getOperand(i).ChangeToRegister(Reg, false /*isDef*/);
continue;
}
Expand Down
11 changes: 6 additions & 5 deletions llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp
Expand Up @@ -41,9 +41,9 @@ bool TargetFrameLowering::enableCalleeSaveSkip(const MachineFunction &MF) const
/// frame of the specified index, along with the frame register used
/// (in output arg FrameReg). This is the default implementation which
/// is overridden for some targets.
int TargetFrameLowering::getFrameIndexReference(const MachineFunction &MF,
int FI,
Register &FrameReg) const {
StackOffset
TargetFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();

Expand All @@ -52,8 +52,9 @@ int TargetFrameLowering::getFrameIndexReference(const MachineFunction &MF,
// something different.
FrameReg = RI->getFrameRegister(MF);

return MFI.getObjectOffset(FI) + MFI.getStackSize() -
getOffsetOfLocalArea() + MFI.getOffsetAdjustment();
return StackOffset::getFixed(MFI.getObjectOffset(FI) + MFI.getStackSize() -
getOffsetOfLocalArea() +
MFI.getOffsetAdjustment());
}

bool TargetFrameLowering::needsFrameIndexResolution(
Expand Down
27 changes: 14 additions & 13 deletions llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
Expand Up @@ -1803,20 +1803,20 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
/// debug info. It's the same as what we use for resolving the code-gen
/// references for now. FIXME: This can go wrong when references are
/// SP-relative and simple call frames aren't used.
int AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF,
int FI,
Register &FrameReg) const {
StackOffset
AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const {
return resolveFrameIndexReference(
MF, FI, FrameReg,
/*PreferFP=*/
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress),
/*ForSimm=*/false)
.getFixed();
MF, FI, FrameReg,
/*PreferFP=*/
MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress),
/*ForSimm=*/false);
}

int AArch64FrameLowering::getNonLocalFrameIndexReference(
const MachineFunction &MF, int FI) const {
return getSEHFrameIndexOffset(MF, FI);
StackOffset
AArch64FrameLowering::getNonLocalFrameIndexReference(const MachineFunction &MF,
int FI) const {
return StackOffset::getFixed(getSEHFrameIndexOffset(MF, FI));
}

static StackOffset getFPOffset(const MachineFunction &MF,
Expand All @@ -1839,6 +1839,7 @@ static StackOffset getStackOffset(const MachineFunction &MF,
return StackOffset::getFixed(ObjectOffset + (int64_t)MFI.getStackSize());
}

// TODO: This function currently does not work for scalable vectors.
int AArch64FrameLowering::getSEHFrameIndexOffset(const MachineFunction &MF,
int FI) const {
const auto *RegInfo = static_cast<const AArch64RegisterInfo *>(
Expand Down Expand Up @@ -3273,15 +3274,15 @@ void AArch64FrameLowering::processFunctionBeforeFrameIndicesReplaced(
/// For Win64 AArch64 EH, the offset to the Unwind object is from the SP
/// before the update. This is easily retrieved as it is exactly the offset
/// that is set in processFunctionBeforeFrameFinalized.
int AArch64FrameLowering::getFrameIndexReferencePreferSP(
StackOffset AArch64FrameLowering::getFrameIndexReferencePreferSP(
const MachineFunction &MF, int FI, Register &FrameReg,
bool IgnoreSPUpdates) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
if (IgnoreSPUpdates) {
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
<< MFI.getObjectOffset(FI) << "\n");
FrameReg = AArch64::SP;
return MFI.getObjectOffset(FI);
return StackOffset::getFixed(MFI.getObjectOffset(FI));
}

return getFrameIndexReference(MF, FI, FrameReg);
Expand Down
15 changes: 8 additions & 7 deletions llvm/lib/Target/AArch64/AArch64FrameLowering.h
Expand Up @@ -41,8 +41,8 @@ class AArch64FrameLowering : public TargetFrameLowering {

bool canUseAsPrologue(const MachineBasicBlock &MBB) const override;

int getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg, bool PreferFP,
bool ForSimm) const;
Expand Down Expand Up @@ -94,11 +94,12 @@ class AArch64FrameLowering : public TargetFrameLowering {

unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;

int getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
Register &FrameReg,
bool IgnoreSPUpdates) const override;
int getNonLocalFrameIndexReference(const MachineFunction &MF,
int FI) const override;
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 {
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
Expand Up @@ -626,8 +626,10 @@ void AArch64RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,

if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE) {
MachineOperand &FI = MI.getOperand(FIOperandNum);
int Offset = TFI->getNonLocalFrameIndexReference(MF, FrameIndex);
FI.ChangeToImmediate(Offset);
StackOffset Offset = TFI->getNonLocalFrameIndexReference(MF, FrameIndex);
assert(!Offset.getScalable() &&
"Frame offsets with a scalable component are not supported");
FI.ChangeToImmediate(Offset.getFixed());
return;
}

Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/AMDGPU/R600FrameLowering.cpp
Expand Up @@ -18,8 +18,9 @@ using namespace llvm;
R600FrameLowering::~R600FrameLowering() = default;

/// \returns The number of registers allocated for \p FI.
int R600FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const {
StackOffset
R600FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
const R600RegisterInfo *RI
= MF.getSubtarget<R600Subtarget>().getRegisterInfo();
Expand All @@ -44,5 +45,5 @@ int R600FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
if (FI != -1)
OffsetBytes = alignTo(OffsetBytes, MFI.getObjectAlign(FI));

return OffsetBytes / (getStackWidth(MF) * 4);
return StackOffset::getFixed(OffsetBytes / (getStackWidth(MF) * 4));
}
5 changes: 3 additions & 2 deletions llvm/lib/Target/AMDGPU/R600FrameLowering.h
Expand Up @@ -10,6 +10,7 @@
#define LLVM_LIB_TARGET_AMDGPU_R600FRAMELOWERING_H

#include "AMDGPUFrameLowering.h"
#include "llvm/Support/TypeSize.h"

namespace llvm {

Expand All @@ -24,8 +25,8 @@ class R600FrameLowering : public AMDGPUFrameLowering {
MachineBasicBlock &MBB) const override {}
void emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const override {}
int getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;

bool hasFP(const MachineFunction &MF) const override {
return false;
Expand Down

0 comments on commit d57bba7

Please sign in to comment.