Skip to content

Commit fd6584a

Browse files
committed
[AArch64][SVE] Fix CFA calculation in presence of SVE objects.
The CFA is calculated as (SP/FP + offset), but when there are SVE objects on the stack the SP offset is partly scalable and should instead be expressed as the DWARF expression: SP + offset + scalable_offset * VG where VG is the Vector Granule register, containing the number of 64bits 'granules' in a scalable vector. Reviewed By: efriedma Differential Revision: https://reviews.llvm.org/D84043
1 parent 79b44a4 commit fd6584a

File tree

8 files changed

+267
-33
lines changed

8 files changed

+267
-33
lines changed

llvm/include/llvm/MC/MCDwarf.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -467,10 +467,12 @@ class MCCFIInstruction {
467467
unsigned Register2;
468468
};
469469
std::vector<char> Values;
470+
std::string Comment;
470471

471-
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, StringRef V)
472+
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, StringRef V,
473+
StringRef Comment = "")
472474
: Operation(Op), Label(L), Register(R), Offset(O),
473-
Values(V.begin(), V.end()) {
475+
Values(V.begin(), V.end()), Comment(Comment) {
474476
assert(Op != OpRegister);
475477
}
476478

@@ -570,8 +572,9 @@ class MCCFIInstruction {
570572

571573
/// .cfi_escape Allows the user to add arbitrary bytes to the unwind
572574
/// info.
573-
static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals) {
574-
return MCCFIInstruction(OpEscape, L, 0, 0, Vals);
575+
static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals,
576+
StringRef Comment = "") {
577+
return MCCFIInstruction(OpEscape, L, 0, 0, Vals, Comment);
575578
}
576579

577580
/// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
@@ -606,6 +609,10 @@ class MCCFIInstruction {
606609
assert(Operation == OpEscape);
607610
return StringRef(&Values[0], Values.size());
608611
}
612+
613+
StringRef getComment() const {
614+
return Comment;
615+
}
609616
};
610617

611618
struct MCDwarfFrameInfo {

llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
241241
OutStreamer->emitCFIGnuArgsSize(Inst.getOffset());
242242
break;
243243
case MCCFIInstruction::OpEscape:
244+
OutStreamer->AddComment(Inst.getComment());
244245
OutStreamer->emitCFIEscape(Inst.getValues());
245246
break;
246247
case MCCFIInstruction::OpRestore:

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
#include "llvm/Support/CommandLine.h"
149149
#include "llvm/Support/Debug.h"
150150
#include "llvm/Support/ErrorHandling.h"
151+
#include "llvm/Support/LEB128.h"
151152
#include "llvm/Support/MathExtras.h"
152153
#include "llvm/Support/raw_ostream.h"
153154
#include "llvm/Target/TargetMachine.h"
@@ -399,6 +400,64 @@ static bool ShouldSignReturnAddress(MachineFunction &MF) {
399400
return false;
400401
}
401402

403+
// Convenience function to create a DWARF expression for
404+
// Expr + NumBytes + NumVGScaledBytes * AArch64::VG
405+
static void appendVGScaledOffsetExpr(SmallVectorImpl<char> &Expr,
406+
int NumBytes, int NumVGScaledBytes, unsigned VG,
407+
llvm::raw_string_ostream &Comment) {
408+
uint8_t buffer[16];
409+
410+
if (NumBytes) {
411+
Expr.push_back(dwarf::DW_OP_consts);
412+
Expr.append(buffer, buffer + encodeSLEB128(NumBytes, buffer));
413+
Expr.push_back((uint8_t)dwarf::DW_OP_plus);
414+
Comment << (NumBytes < 0 ? " - " : " + ") << std::abs(NumBytes);
415+
}
416+
417+
if (NumVGScaledBytes) {
418+
Expr.push_back((uint8_t)dwarf::DW_OP_consts);
419+
Expr.append(buffer, buffer + encodeSLEB128(NumVGScaledBytes, buffer));
420+
421+
Expr.push_back((uint8_t)dwarf::DW_OP_bregx);
422+
Expr.append(buffer, buffer + encodeULEB128(VG, buffer));
423+
Expr.push_back(0);
424+
425+
Expr.push_back((uint8_t)dwarf::DW_OP_mul);
426+
Expr.push_back((uint8_t)dwarf::DW_OP_plus);
427+
428+
Comment << (NumVGScaledBytes < 0 ? " - " : " + ")
429+
<< std::abs(NumVGScaledBytes) << " * VG";
430+
}
431+
}
432+
433+
// Creates an MCCFIInstruction:
434+
// { DW_CFA_def_cfa_expression, ULEB128 (sizeof expr), expr }
435+
MCCFIInstruction AArch64FrameLowering::createDefCFAExpressionFromSP(
436+
const TargetRegisterInfo &TRI, const StackOffset &OffsetFromSP) const {
437+
int64_t NumBytes, NumVGScaledBytes;
438+
OffsetFromSP.getForDwarfOffset(NumBytes, NumVGScaledBytes);
439+
440+
std::string CommentBuffer = "sp";
441+
llvm::raw_string_ostream Comment(CommentBuffer);
442+
443+
// Build up the expression (SP + NumBytes + NumVGScaledBytes * AArch64::VG)
444+
SmallString<64> Expr;
445+
Expr.push_back(dwarf::DW_OP_breg0 + /*SP*/ 31);
446+
Expr.push_back(0);
447+
appendVGScaledOffsetExpr(Expr, NumBytes, NumVGScaledBytes,
448+
TRI.getDwarfRegNum(AArch64::VG, true), Comment);
449+
450+
// Wrap this into DW_CFA_def_cfa.
451+
SmallString<64> DefCfaExpr;
452+
DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression);
453+
uint8_t buffer[16];
454+
DefCfaExpr.append(buffer,
455+
buffer + encodeULEB128(Expr.size(), buffer));
456+
DefCfaExpr.append(Expr.str());
457+
return MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str(),
458+
Comment.str());
459+
}
460+
402461
void AArch64FrameLowering::emitCalleeSavedFrameMoves(
403462
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const {
404463
MachineFunction &MF = *MBB.getParent();
@@ -1383,9 +1442,18 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
13831442
.addCFIIndex(CFIIndex)
13841443
.setMIFlags(MachineInstr::FrameSetup);
13851444
} else {
1386-
// Encode the stack size of the leaf function.
1387-
unsigned CFIIndex = MF.addFrameInst(
1388-
MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
1445+
unsigned CFIIndex;
1446+
if (SVEStackSize) {
1447+
const TargetSubtargetInfo &STI = MF.getSubtarget();
1448+
const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
1449+
StackOffset TotalSize =
1450+
SVEStackSize + StackOffset((int64_t)MFI.getStackSize(), MVT::i8);
1451+
CFIIndex = MF.addFrameInst(createDefCFAExpressionFromSP(TRI, TotalSize));
1452+
} else {
1453+
// Encode the stack size of the leaf function.
1454+
CFIIndex = MF.addFrameInst(
1455+
MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
1456+
}
13891457
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
13901458
.addCFIIndex(CFIIndex)
13911459
.setMIFlags(MachineInstr::FrameSetup);

llvm/lib/Target/AArch64/AArch64FrameLowering.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
namespace llvm {
2020

21+
class MCCFIInstruction;
22+
2123
class AArch64FrameLowering : public TargetFrameLowering {
2224
public:
2325
explicit AArch64FrameLowering()
@@ -119,6 +121,11 @@ class AArch64FrameLowering : public TargetFrameLowering {
119121
int64_t assignSVEStackObjectOffsets(MachineFrameInfo &MF,
120122
int &MinCSFrameIndex,
121123
int &MaxCSFrameIndex) const;
124+
MCCFIInstruction
125+
createDefCFAExpressionFromSP(const TargetRegisterInfo &TRI,
126+
const StackOffset &OffsetFromSP) const;
127+
MCCFIInstruction createCfaOffset(const MCRegisterInfo &MRI, unsigned DwarfReg,
128+
const StackOffset &OffsetFromDefCFA) const;
122129
bool shouldCombineCSRLocalStackBumpInEpilogue(MachineBasicBlock &MBB,
123130
unsigned StackBumpBytes) const;
124131
};

llvm/lib/Target/AArch64/AArch64RegisterInfo.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ def NZCV : AArch64Reg<0, "nzcv">;
133133
// First fault status register
134134
def FFR : AArch64Reg<0, "ffr">, DwarfRegNum<[47]>;
135135

136+
// Purely virtual Vector Granule (VG) Dwarf register
137+
def VG : AArch64Reg<0, "vg">, DwarfRegNum<[46]>;
138+
136139
// GPR register classes with the intersections of GPR32/GPR32sp and
137140
// GPR64/GPR64sp for use by the coalescer.
138141
def GPR32common : RegisterClass<"AArch64", [i32], 32, (sequence "W%u", 0, 30)> {

llvm/lib/Target/AArch64/AArch64StackOffset.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ class StackOffset {
123123
}
124124
}
125125

126+
void getForDwarfOffset(int64_t &ByteSized, int64_t &VGSized) const {
127+
assert(isValid() && "Invalid frame offset");
128+
129+
// VGSized offsets are divided by '2', because the VG register is the
130+
// the number of 64bit granules as opposed to 128bit vector chunks,
131+
// which is how the 'n' in e.g. MVT::nxv1i8 is modelled.
132+
// So, for a stack offset of 16 MVT::nxv1i8's, the size is n x 16 bytes.
133+
// VG = n * 2 and the dwarf offset must be VG * 8 bytes.
134+
ByteSized = Bytes;
135+
VGSized = ScalableBytes / 2;
136+
}
137+
126138
/// Returns whether the offset is known zero.
127139
explicit operator bool() const { return Bytes || ScalableBytes; }
128140

0 commit comments

Comments
 (0)