Skip to content

Commit 4f5d67b

Browse files
[AArch64] "Support" debug info for SVE types on Windows. (#147865)
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 cffe7cb commit 4f5d67b

File tree

6 files changed

+185
-4
lines changed

6 files changed

+185
-4
lines changed

llvm/include/llvm/CodeGen/TargetRegisterInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,10 @@ class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
12431243
getVRegFlagsOfReg(Register Reg, const MachineFunction &MF) const {
12441244
return {};
12451245
}
1246+
1247+
// Whether this register should be ignored when generating CodeView debug
1248+
// info, because it's a known there is no mapping available.
1249+
virtual bool isIgnoredCVReg(MCRegister LLVMReg) const { return false; }
12461250
};
12471251

12481252
//===----------------------------------------------------------------------===//

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
@@ -3043,9 +3043,11 @@ StackOffset AArch64FrameLowering::resolveFrameOffsetReference(
30433043
StackOffset::get(MFI.getStackSize() - AFI->getCalleeSavedStackSize(),
30443044
ObjectOffset);
30453045
if (FPAfterSVECalleeSaves) {
3046-
assert(-ObjectOffset > (int64_t)AFI->getSVECalleeSavedStackSize() &&
3047-
"Math isn't correct for CSRs with FPAfterSVECalleeSaves");
30483046
FPOffset += StackOffset::getScalable(AFI->getSVECalleeSavedStackSize());
3047+
if (-ObjectOffset <= (int64_t)AFI->getSVECalleeSavedStackSize()) {
3048+
FPOffset += StackOffset::getFixed(AFI->getCalleeSavedStackSize());
3049+
SPOffset += StackOffset::getFixed(AFI->getCalleeSavedStackSize());
3050+
}
30493051
}
30503052
// Always use the FP for SVE spills if available and beneficial.
30513053
if (hasFP(MF) && (SPOffset.getFixed() ||

llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,3 +1370,8 @@ bool AArch64RegisterInfo::shouldAnalyzePhysregInMachineLoopInfo(
13701370
MCRegister R) const {
13711371
return R == AArch64::VG;
13721372
}
1373+
1374+
bool AArch64RegisterInfo::isIgnoredCVReg(MCRegister LLVMReg) const {
1375+
return (LLVMReg >= AArch64::Z0 && LLVMReg <= AArch64::Z31) ||
1376+
(LLVMReg >= AArch64::P0 && LLVMReg <= AArch64::P15);
1377+
}

llvm/lib/Target/AArch64/AArch64RegisterInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class AArch64RegisterInfo final : public AArch64GenRegisterInfo {
154154
SmallVectorImpl<uint64_t> &Ops) const override;
155155

156156
bool shouldAnalyzePhysregInMachineLoopInfo(MCRegister R) const override;
157+
158+
virtual bool isIgnoredCVReg(MCRegister LLVMReg) const override;
157159
};
158160

159161
} // end namespace llvm
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)