Skip to content

Commit 909e307

Browse files
committed
[AArch64] "Support" debug info for SVE types on Windows.
There isn't any way to encode a variable in an SVE register, and there isn't any way to encode a scalable offset, and as far as I know that's unlikely to change in the near future. So suppress any debug info which would require those encodings. This isn't ideal, but we need to ship something which doesn't crash. Alternatively, for Z registers, we could emit debug info assuming the vector length is 128 bits, but that seems like it would lead to unintuitive results. The change to AArch64FrameLowering is needed to avoid a crash. But we can't actually test that the returned offset is correct: LiveDebugValues performs the query, then discards the result.
1 parent 6a99326 commit 909e307

File tree

5 files changed

+196
-4
lines changed

5 files changed

+196
-4
lines changed

llvm/include/llvm/MC/MCRegisterInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define LLVM_MC_MCREGISTERINFO_H
1717

1818
#include "llvm/ADT/DenseMap.h"
19+
#include "llvm/ADT/DenseSet.h"
1920
#include "llvm/ADT/iterator.h"
2021
#include "llvm/ADT/iterator_range.h"
2122
#include "llvm/MC/LaneBitmask.h"
@@ -190,6 +191,7 @@ class LLVM_ABI MCRegisterInfo {
190191
const DwarfLLVMRegPair *EHDwarf2LRegs; // Dwarf to LLVM regs mapping EH
191192
DenseMap<MCRegister, int> L2SEHRegs; // LLVM to SEH regs mapping
192193
DenseMap<MCRegister, int> L2CVRegs; // LLVM to CV regs mapping
194+
DenseSet<MCRegister> IgnoredCVRegs;
193195

194196
mutable std::vector<std::vector<MCPhysReg>> RegAliasesCache;
195197
ArrayRef<MCPhysReg> getCachedAliasesOf(MCRegister R) const;
@@ -353,6 +355,12 @@ class LLVM_ABI MCRegisterInfo {
353355
L2CVRegs[LLVMReg] = CVReg;
354356
}
355357

358+
void ignoreCVReg(MCRegister LLVMReg) { IgnoredCVRegs.insert(LLVMReg); }
359+
360+
bool isIgnoredCVReg(MCRegister LLVMReg) const {
361+
return IgnoredCVRegs.contains(LLVMReg);
362+
}
363+
356364
/// This method should return the register where the return
357365
/// address can be found.
358366
MCRegister getRARegister() const {

llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1318,8 +1318,10 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
13181318
TFI->getFrameIndexReference(*Asm->MF, VI.getStackSlot(), FrameReg);
13191319
uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg);
13201320

1321-
assert(!FrameOffset.getScalable() &&
1322-
"Frame offsets with a scalable component are not supported");
1321+
if (FrameOffset.getScalable()) {
1322+
// No encoding currently exists for scalable offsets; bail out.
1323+
continue;
1324+
}
13231325

13241326
// Calculate the label ranges.
13251327
LocalVarDef DefRange =
@@ -1410,6 +1412,11 @@ void CodeViewDebug::calculateRanges(
14101412
if (Location->FragmentInfo->OffsetInBits % 8)
14111413
continue;
14121414

1415+
if (TRI->isIgnoredCVReg(Location->Register)) {
1416+
// No encoding currently exists for this register; bail out.
1417+
continue;
1418+
}
1419+
14131420
LocalVarDef DR;
14141421
DR.CVRegister = TRI->getCodeViewRegNum(Location->Register);
14151422
DR.InMemory = !Location->LoadChain.empty();

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,9 +2958,11 @@ StackOffset AArch64FrameLowering::resolveFrameOffsetReference(
29582958
StackOffset::get(MFI.getStackSize() - AFI->getCalleeSavedStackSize(),
29592959
ObjectOffset);
29602960
if (FPAfterSVECalleeSaves) {
2961-
assert(-ObjectOffset > (int64_t)AFI->getSVECalleeSavedStackSize() &&
2962-
"Math isn't correct for CSRs with FPAfterSVECalleeSaves");
29632961
FPOffset += StackOffset::getScalable(AFI->getSVECalleeSavedStackSize());
2962+
if (-ObjectOffset <= (int64_t)AFI->getSVECalleeSavedStackSize()) {
2963+
FPOffset += StackOffset::getFixed(AFI->getCalleeSavedStackSize());
2964+
SPOffset += StackOffset::getFixed(AFI->getCalleeSavedStackSize());
2965+
}
29642966
}
29652967
// Always use the FP for SVE spills if available and beneficial.
29662968
if (hasFP(MF) && (SPOffset.getFixed() ||

llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCTargetDesc.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,20 @@ void AArch64_MC::initLLVMToCVRegMapping(MCRegisterInfo *MRI) {
302302
};
303303
for (const auto &I : RegMap)
304304
MRI->mapLLVMRegToCVReg(I.Reg, static_cast<int>(I.CVReg));
305+
static constexpr MCRegister IgnoredRegs[] = {
306+
AArch64::Z0, AArch64::Z1, AArch64::Z2, AArch64::Z3, AArch64::Z4,
307+
AArch64::Z5, AArch64::Z6, AArch64::Z7, AArch64::Z8, AArch64::Z9,
308+
AArch64::Z10, AArch64::Z11, AArch64::Z12, AArch64::Z13, AArch64::Z14,
309+
AArch64::Z15, AArch64::Z16, AArch64::Z17, AArch64::Z18, AArch64::Z19,
310+
AArch64::Z20, AArch64::Z21, AArch64::Z22, AArch64::Z23, AArch64::Z24,
311+
AArch64::Z25, AArch64::Z26, AArch64::Z27, AArch64::Z28, AArch64::Z29,
312+
AArch64::Z30, AArch64::Z31, AArch64::P0, AArch64::P1, AArch64::P2,
313+
AArch64::P3, AArch64::P4, AArch64::P5, AArch64::P6, AArch64::P7,
314+
AArch64::P8, AArch64::P9, AArch64::P10, AArch64::P11, AArch64::P12,
315+
AArch64::P13, AArch64::P14, AArch64::P15,
316+
};
317+
for (const auto &R : IgnoredRegs)
318+
MRI->ignoreCVReg(R);
305319
}
306320

307321
bool AArch64_MC::isHForm(const MCInst &MI, const MCInstrInfo *MCII) {
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
; RUN: llc < %s -filetype=obj | llvm-readobj --codeview - | FileCheck %s
2+
3+
; The point of this is mostly just to avoid crashing... there isn't any way
4+
; to encode most of the information we want to encode. But we try to do what
5+
; we can.
6+
;
7+
; Generated from:
8+
;
9+
; #include <arm_sve.h>
10+
; void g();
11+
; svint32_t f(svint32_t aaa, svint32_t bbb, svint32_t *ccc) {
12+
; asm("":::"z0", "z1", "z2", "z3", "z4", "z5", "z6", "z7", "z8", "z9",
13+
; "z10", "z11", "z12", "z13", "z14", "z15", "z16", "z17", "z18",
14+
; "z19", "z20", "z21", "z22", "z23", "z24", "z25", "z26", "z27",
15+
; "z28", "z29", "z30", "z31");
16+
; return aaa**ccc+bbb;
17+
;}
18+
19+
; Emit the SVE type. We represent this as an array with unknown bound.
20+
21+
; CHECK: Array (0x1000) {
22+
; CHECK-NEXT: TypeLeafKind: LF_ARRAY (0x1503)
23+
; CHECK-NEXT: ElementType: int (0x74)
24+
; CHECK-NEXT: IndexType: unsigned __int64 (0x23)
25+
; CHECK-NEXT: SizeOf: 0
26+
; CHECK-NEXT: Name:
27+
; CHECK-NEXT: }
28+
29+
; Emit frame information. This is missing the size of the SVE
30+
; variables, but we can't really do anything about that.
31+
32+
; CHECK: FrameProcSym {
33+
; CHECK-NEXT: Kind: S_FRAMEPROC (0x1012)
34+
; CHECK-NEXT: TotalFrameBytes: 0x10
35+
; CHECK-NEXT: PaddingFrameBytes: 0x0
36+
; CHECK-NEXT: OffsetToPadding: 0x0
37+
; CHECK-NEXT: BytesOfCalleeSavedRegisters: 0x0
38+
; CHECK-NEXT: OffsetOfExceptionHandler: 0x0
39+
; CHECK-NEXT: SectionIdOfExceptionHandler: 0x0
40+
; CHECK-NEXT: Flags [ (0x116008)
41+
; CHECK-NEXT: HasInlineAssembly (0x8)
42+
; CHECK-NEXT: OptimizedForSpeed (0x100000)
43+
; CHECK-NEXT: SafeBuffers (0x2000)
44+
; CHECK-NEXT: ]
45+
; CHECK-NEXT: LocalFramePtrReg: ARM64_NOREG (0x0)
46+
; CHECK-NEXT: ParamFramePtrReg: ARM64_NOREG (0x0)
47+
; CHECK-NEXT: }
48+
49+
; Emit the symbols for the local variables.
50+
;
51+
; ccc is a normal pointer.
52+
;
53+
; We can't represent bbb anywhere in its range; there's no way to name Z
54+
; registers, and no way to express its location on the stack relative
55+
; to the stack pointer when it's spilled.
56+
;
57+
; In the middle of the range, aaa happens to have a scalable offset of zero,
58+
; so we can represent it while it's on the stack.
59+
60+
; CHECK-NEXT: LocalSym {
61+
; CHECK-NEXT: Kind: S_LOCAL (0x113E)
62+
; CHECK-NEXT: Type: 0x1000
63+
; CHECK-NEXT: Flags [ (0x1)
64+
; CHECK-NEXT: IsParameter (0x1)
65+
; CHECK-NEXT: ]
66+
; CHECK-NEXT: VarName: aaa
67+
; CHECK-NEXT: }
68+
; CHECK-NEXT: DefRangeRegisterRelSym {
69+
; CHECK-NEXT: Kind: S_DEFRANGE_REGISTER_REL (0x1145)
70+
; CHECK-NEXT: BaseRegister: ARM64_SP (0x51)
71+
; CHECK-NEXT: HasSpilledUDTMember: No
72+
; CHECK-NEXT: OffsetInParent: 0
73+
; CHECK-NEXT: BasePointerOffset: 0
74+
; CHECK-NEXT: LocalVariableAddrRange {
75+
; CHECK-NEXT: OffsetStart: .text+0x58
76+
; CHECK-NEXT: ISectStart: 0x0
77+
; CHECK-NEXT: Range: 0xC
78+
; CHECK-NEXT: }
79+
; CHECK-NEXT: }
80+
; CHECK-NEXT: LocalSym {
81+
; CHECK-NEXT: Kind: S_LOCAL (0x113E)
82+
; CHECK-NEXT: Type: 0x1000
83+
; CHECK-NEXT: Flags [ (0x101)
84+
; CHECK-NEXT: IsOptimizedOut (0x100)
85+
; CHECK-NEXT: IsParameter (0x1)
86+
; CHECK-NEXT: ]
87+
; CHECK-NEXT: VarName: bbb
88+
; CHECK-NEXT: }
89+
; CHECK-NEXT: LocalSym {
90+
; CHECK-NEXT: Kind: S_LOCAL (0x113E)
91+
; CHECK-NEXT: Type: * (0x1001)
92+
; CHECK-NEXT: Flags [ (0x1)
93+
; CHECK-NEXT: IsParameter (0x1)
94+
; CHECK-NEXT: ]
95+
; CHECK-NEXT: VarName: ccc
96+
; CHECK-NEXT: }
97+
; CHECK-NEXT: DefRangeRegisterSym {
98+
; CHECK-NEXT: Kind: S_DEFRANGE_REGISTER (0x1141)
99+
; CHECK-NEXT: Register: ARM64_X0 (0x32)
100+
; CHECK-NEXT: MayHaveNoName: 0
101+
; CHECK-NEXT: LocalVariableAddrRange {
102+
; CHECK-NEXT: OffsetStart: .text+0x0
103+
; CHECK-NEXT: ISectStart: 0x0
104+
; CHECK-NEXT: Range: 0xBC
105+
; CHECK-NEXT: }
106+
; CHECK-NEXT: }
107+
; CHECK-NEXT: ProcEnd {
108+
; CHECK-NEXT: Kind: S_PROC_ID_END (0x114F)
109+
; CHECK-NEXT: }
110+
111+
target triple = "aarch64-unknown-windows-msvc19.33.0"
112+
113+
; Function Attrs: mustprogress nounwind uwtable vscale_range(1,16)
114+
define dso_local <vscale x 4 x i32> @"?f@@YAU__SVInt32_t@__clang@@U12@0PEAU12@@Z"(<vscale x 4 x i32> %aaa, <vscale x 4 x i32> %bbb, ptr noundef readonly captures(none) %ccc) local_unnamed_addr #0 !dbg !10 {
115+
entry:
116+
#dbg_value(ptr %ccc, !23, !DIExpression(), !26)
117+
#dbg_value(<vscale x 4 x i32> %bbb, !24, !DIExpression(), !26)
118+
#dbg_value(<vscale x 4 x i32> %aaa, !25, !DIExpression(), !26)
119+
tail call void asm sideeffect "", "~{z0},~{z1},~{z2},~{z3},~{z4},~{z5},~{z6},~{z7},~{z8},~{z9},~{z10},~{z11},~{z12},~{z13},~{z14},~{z15},~{z16},~{z17},~{z18},~{z19},~{z20},~{z21},~{z22},~{z23},~{z24},~{z25},~{z26},~{z27},~{z28},~{z29},~{z30},~{z31}"() #1, !dbg !27, !srcloc !28
120+
%0 = load <vscale x 4 x i32>, ptr %ccc, align 16, !dbg !27
121+
%mul = mul <vscale x 4 x i32> %0, %aaa, !dbg !27
122+
%add = add <vscale x 4 x i32> %mul, %bbb, !dbg !27
123+
ret <vscale x 4 x i32> %add, !dbg !27
124+
}
125+
126+
attributes #0 = { mustprogress nounwind uwtable vscale_range(1,16) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+fullfp16,+neon,+sve,+v8a,-fmv" }
127+
attributes #1 = { nounwind }
128+
129+
!llvm.dbg.cu = !{!0}
130+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
131+
!llvm.ident = !{!9}
132+
133+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 21.0.0git", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
134+
!1 = !DIFile(filename: "-", directory: "", checksumkind: CSK_MD5, checksum: "e54fc2ba768e4a43f64b8a9d03a374d6")
135+
!2 = !{i32 2, !"CodeView", i32 1}
136+
!3 = !{i32 2, !"Debug Info Version", i32 3}
137+
!4 = !{i32 1, !"wchar_size", i32 2}
138+
!5 = !{i32 8, !"PIC Level", i32 2}
139+
!6 = !{i32 7, !"uwtable", i32 2}
140+
!7 = !{i32 7, !"frame-pointer", i32 1}
141+
!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
142+
!9 = !{!"clang version 21.0.0git"}
143+
!10 = distinct !DISubprogram(name: "f", linkageName: "?f@@YAU__SVInt32_t@__clang@@U12@0PEAU12@@Z", scope: !11, file: !11, line: 2, type: !12, scopeLine: 2, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !22)
144+
!11 = !DIFile(filename: "<stdin>", directory: "", checksumkind: CSK_MD5, checksum: "e54fc2ba768e4a43f64b8a9d03a374d6")
145+
!12 = !DISubroutineType(types: !13)
146+
!13 = !{!14, !14, !14, !21}
147+
!14 = !DIDerivedType(tag: DW_TAG_typedef, name: "svint32_t", file: !15, line: 30, baseType: !16)
148+
!15 = !DIFile(filename: "arm_sve.h", directory: "", checksumkind: CSK_MD5, checksum: "34027e9d24f4b03c6e5370869d5cc907")
149+
!16 = !DIDerivedType(tag: DW_TAG_typedef, name: "__SVInt32_t", file: !1, baseType: !17)
150+
!17 = !DICompositeType(tag: DW_TAG_array_type, baseType: !18, flags: DIFlagVector, elements: !19)
151+
!18 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
152+
!19 = !{!20}
153+
!20 = !DISubrange(lowerBound: 0, upperBound: !DIExpression(DW_OP_constu, 2, DW_OP_bregx, 46, 0, DW_OP_mul, DW_OP_constu, 1, DW_OP_minus))
154+
!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64)
155+
!22 = !{!23, !24, !25}
156+
!23 = !DILocalVariable(name: "ccc", arg: 3, scope: !10, file: !11, line: 2, type: !21)
157+
!24 = !DILocalVariable(name: "bbb", arg: 2, scope: !10, file: !11, line: 2, type: !14)
158+
!25 = !DILocalVariable(name: "aaa", arg: 1, scope: !10, file: !11, line: 2, type: !14)
159+
!26 = !DILocation(line: 0, scope: !10)
160+
!27 = !DILocation(line: 2, scope: !10)
161+
!28 = !{i64 98}

0 commit comments

Comments
 (0)