Skip to content

Commit 360df81

Browse files
hazzlimllvmbot
authored andcommitted
[StackFrameLayoutAnalysis] Use target-specific hook for SP offsets (llvm#100386)
StackFrameLayoutAnalysis currently calculates SP-relative offsets in a target-independent way via MachineFrameInfo offsets. This is incorrect for some Targets, e.g. AArch64, when there are scalable vector stack slots. This patch adds a virtual function to TargetFrameLowering to provide offsets from SP, with a default implementation matching what is currently used in StackFrameLayoutAnalysis, and refactors StackFrameLayoutAnalysis to use this function. Only non-zero scalable offsets are output by the analysis pass. An implementation of this function is added for AArch64 targets, which aims to provide correct SP offsets in most cases. (cherry picked from commit dc1c00f)
1 parent a8b7c80 commit 360df81

File tree

6 files changed

+563
-26
lines changed

6 files changed

+563
-26
lines changed

llvm/include/llvm/CodeGen/TargetFrameLowering.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,13 @@ class TargetFrameLowering {
343343
return getFrameIndexReference(MF, FI, FrameReg);
344344
}
345345

346+
/// getFrameIndexReferenceFromSP - This method returns the offset from the
347+
/// stack pointer to the slot of the specified index. This function serves to
348+
/// provide a comparable offset from a single reference point (the value of
349+
/// the stack-pointer at function entry) that can be used for analysis.
350+
virtual StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
351+
int FI) const;
352+
346353
/// Returns the callee-saved registers as computed by determineCalleeSaves
347354
/// in the BitVector \p SavedRegs.
348355
virtual void getCalleeSaves(const MachineFunction &MF,

llvm/lib/CodeGen/StackFrameLayoutAnalysisPass.cpp

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
6060
int Slot;
6161
int Size;
6262
int Align;
63-
int Offset;
63+
StackOffset Offset;
6464
SlotType SlotTy;
6565
bool Scalable;
6666

67-
SlotData(const MachineFrameInfo &MFI, const int ValOffset, const int Idx)
67+
SlotData(const MachineFrameInfo &MFI, const StackOffset Offset,
68+
const int Idx)
6869
: Slot(Idx), Size(MFI.getObjectSize(Idx)),
69-
Align(MFI.getObjectAlign(Idx).value()),
70-
Offset(MFI.getObjectOffset(Idx) - ValOffset), SlotTy(Invalid),
71-
Scalable(false) {
70+
Align(MFI.getObjectAlign(Idx).value()), Offset(Offset),
71+
SlotTy(Invalid), Scalable(false) {
7272
Scalable = MFI.getStackID(Idx) == TargetStackID::ScalableVector;
7373
if (MFI.isSpillSlotObjectIndex(Idx))
7474
SlotTy = SlotType::Spill;
@@ -79,10 +79,10 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
7979
}
8080

8181
// We use this to sort in reverse order, so that the layout is displayed
82-
// correctly. Scalable slots are sorted to the end of the list.
82+
// correctly.
8383
bool operator<(const SlotData &Rhs) const {
84-
return std::make_tuple(!Scalable, Offset) >
85-
std::make_tuple(!Rhs.Scalable, Rhs.Offset);
84+
return (Offset.getFixed() + Offset.getScalable()) >
85+
(Rhs.Offset.getFixed() + Rhs.Offset.getScalable());
8686
}
8787
};
8888

@@ -149,15 +149,27 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
149149
// For example we store the Offset in YAML as:
150150
// ...
151151
// - Offset: -8
152+
// - ScalableOffset: -16
153+
// Note: the ScalableOffset entries are added only for slots with non-zero
154+
// scalable offsets.
152155
//
153-
// But we print it to the CLI as
156+
// But we print it to the CLI as:
154157
// Offset: [SP-8]
158+
//
159+
// Or with non-zero scalable offset:
160+
// Offset: [SP-8-16 x vscale]
155161

156162
// Negative offsets will print a leading `-`, so only add `+`
157163
std::string Prefix =
158-
formatv("\nOffset: [SP{0}", (D.Offset < 0) ? "" : "+").str();
159-
Rem << Prefix << ore::NV("Offset", D.Offset)
160-
<< "], Type: " << ore::NV("Type", getTypeString(D.SlotTy))
164+
formatv("\nOffset: [SP{0}", (D.Offset.getFixed() < 0) ? "" : "+").str();
165+
Rem << Prefix << ore::NV("Offset", D.Offset.getFixed());
166+
167+
if (D.Offset.getScalable()) {
168+
Rem << ((D.Offset.getScalable() < 0) ? "" : "+")
169+
<< ore::NV("ScalableOffset", D.Offset.getScalable()) << " x vscale";
170+
}
171+
172+
Rem << "], Type: " << ore::NV("Type", getTypeString(D.SlotTy))
161173
<< ", Align: " << ore::NV("Align", D.Align)
162174
<< ", Size: " << ore::NV("Size", ElementCount::get(D.Size, D.Scalable));
163175
}
@@ -170,17 +182,22 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
170182
Rem << "\n " << ore::NV("DataLoc", Loc);
171183
}
172184

185+
StackOffset getStackOffset(const MachineFunction &MF,
186+
const MachineFrameInfo &MFI,
187+
const TargetFrameLowering *FI, int FrameIdx) {
188+
if (!FI)
189+
return StackOffset::getFixed(MFI.getObjectOffset(FrameIdx));
190+
191+
return FI->getFrameIndexReferenceFromSP(MF, FrameIdx);
192+
}
193+
173194
void emitStackFrameLayoutRemarks(MachineFunction &MF,
174195
MachineOptimizationRemarkAnalysis &Rem) {
175196
const MachineFrameInfo &MFI = MF.getFrameInfo();
176197
if (!MFI.hasStackObjects())
177198
return;
178199

179-
// ValOffset is the offset to the local area from the SP at function entry.
180-
// To display the true offset from SP, we need to subtract ValOffset from
181-
// MFI's ObjectOffset.
182200
const TargetFrameLowering *FI = MF.getSubtarget().getFrameLowering();
183-
const int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0);
184201

185202
LLVM_DEBUG(dbgs() << "getStackProtectorIndex =="
186203
<< MFI.getStackProtectorIndex() << "\n");
@@ -194,7 +211,7 @@ struct StackFrameLayoutAnalysisPass : public MachineFunctionPass {
194211
Idx != EndIdx; ++Idx) {
195212
if (MFI.isDeadObjectIndex(Idx))
196213
continue;
197-
SlotInfo.emplace_back(MFI, ValOffset, Idx);
214+
SlotInfo.emplace_back(MFI, getStackOffset(MF, MFI, FI, Idx), Idx);
198215
}
199216

200217
// sort the ordering, to match the actual layout in memory

llvm/lib/CodeGen/TargetFrameLoweringImpl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ TargetFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
6161
MFI.getOffsetAdjustment());
6262
}
6363

64+
/// Returns the offset from the stack pointer to the slot of the specified
65+
/// index. This function serves to provide a comparable offset from a single
66+
/// reference point (the value of the stack-pointer at function entry) that can
67+
/// be used for analysis. This is the default implementation using
68+
/// MachineFrameInfo offsets.
69+
StackOffset
70+
TargetFrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF,
71+
int FI) const {
72+
// To display the true offset from SP, we need to subtract the offset to the
73+
// local area from MFI's ObjectOffset.
74+
return StackOffset::getFixed(MF.getFrameInfo().getObjectOffset(FI) -
75+
getOffsetOfLocalArea());
76+
}
77+
6478
bool TargetFrameLowering::needsFrameIndexResolution(
6579
const MachineFunction &MF) const {
6680
return MF.getFrameInfo().hasStackObjects();

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2603,6 +2603,41 @@ AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI,
26032603
/*ForSimm=*/false);
26042604
}
26052605

2606+
StackOffset
2607+
AArch64FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF,
2608+
int FI) const {
2609+
// This function serves to provide a comparable offset from a single reference
2610+
// point (the value of SP at function entry) that can be used for analysis,
2611+
// e.g. the stack-frame-layout analysis pass. It is not guaranteed to be
2612+
// correct for all objects in the presence of VLA-area objects or dynamic
2613+
// stack re-alignment.
2614+
2615+
const auto &MFI = MF.getFrameInfo();
2616+
2617+
int64_t ObjectOffset = MFI.getObjectOffset(FI);
2618+
2619+
// This is correct in the absence of any SVE stack objects.
2620+
StackOffset SVEStackSize = getSVEStackSize(MF);
2621+
if (!SVEStackSize)
2622+
return StackOffset::getFixed(ObjectOffset - getOffsetOfLocalArea());
2623+
2624+
const auto *AFI = MF.getInfo<AArch64FunctionInfo>();
2625+
if (MFI.getStackID(FI) == TargetStackID::ScalableVector) {
2626+
return StackOffset::get(-((int64_t)AFI->getCalleeSavedStackSize()),
2627+
ObjectOffset);
2628+
}
2629+
2630+
bool IsFixed = MFI.isFixedObjectIndex(FI);
2631+
bool IsCSR =
2632+
!IsFixed && ObjectOffset >= -((int)AFI->getCalleeSavedStackSize(MFI));
2633+
2634+
StackOffset ScalableOffset = {};
2635+
if (!IsFixed && !IsCSR)
2636+
ScalableOffset = -SVEStackSize;
2637+
2638+
return StackOffset::getFixed(ObjectOffset) + ScalableOffset;
2639+
}
2640+
26062641
StackOffset
26072642
AArch64FrameLowering::getNonLocalFrameIndexReference(const MachineFunction &MF,
26082643
int FI) const {

llvm/lib/Target/AArch64/AArch64FrameLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ class AArch64FrameLowering : public TargetFrameLowering {
4141

4242
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
4343
Register &FrameReg) const override;
44+
StackOffset getFrameIndexReferenceFromSP(const MachineFunction &MF,
45+
int FI) const override;
4446
StackOffset resolveFrameIndexReference(const MachineFunction &MF, int FI,
4547
Register &FrameReg, bool PreferFP,
4648
bool ForSimm) const;

0 commit comments

Comments
 (0)