Skip to content

Commit 5d55839

Browse files
authored
[AssignmentTracking] Skip large types in redundant debug info pruning (#74329)
Fix #74189 (crash report). The pruning code uses a BitVector to track which parts of a variable have been defined in order to find redundant debug records. BitVector uses a u32 to track size; variable of types with a bit-size greater than max(u32) ish* can't be represented using a BitVector. Fix the assertion by introducing a limit on type size. Improve performance by bringing the limit down to a sensible number and tracking byte-sizes instead of bit-sizes. Skipping variables in this pruning code doesn't cause debug info correctness issues; it just means there may be some extra redundant debug records. (*) `max(u32) - 63` due to BitVector::NumBitWords implementation.
1 parent ae7bffd commit 5d55839

File tree

2 files changed

+75
-10
lines changed

2 files changed

+75
-10
lines changed

llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,14 +2269,14 @@ static bool
22692269
removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,
22702270
FunctionVarLocsBuilder &FnVarLocs) {
22712271
bool Changed = false;
2272-
SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBits;
2272+
SmallDenseMap<DebugAggregate, BitVector> VariableDefinedBytes;
22732273
// Scan over the entire block, not just over the instructions mapped by
22742274
// FnVarLocs, because wedges in FnVarLocs may only be seperated by debug
22752275
// instructions.
22762276
for (const Instruction &I : reverse(*BB)) {
22772277
if (!isa<DbgVariableIntrinsic>(I)) {
22782278
// Sequence of consecutive defs ended. Clear map for the next one.
2279-
VariableDefinedBits.clear();
2279+
VariableDefinedBytes.clear();
22802280
}
22812281

22822282
// Get the location defs that start just before this instruction.
@@ -2295,33 +2295,40 @@ removeRedundantDbgLocsUsingBackwardScan(const BasicBlock *BB,
22952295
DebugAggregate Aggr =
22962296
getAggregate(FnVarLocs.getVariable(RIt->VariableID));
22972297
uint64_t SizeInBits = Aggr.first->getSizeInBits().value_or(0);
2298+
uint64_t SizeInBytes = divideCeil(SizeInBits, 8);
22982299

2299-
if (SizeInBits == 0) {
2300+
// Cutoff for large variables to prevent expensive bitvector operations.
2301+
const uint64_t MaxSizeBytes = 2048;
2302+
2303+
if (SizeInBytes == 0 || SizeInBytes > MaxSizeBytes) {
23002304
// If the size is unknown (0) then keep this location def to be safe.
2305+
// Do the same for defs of large variables, which would be expensive
2306+
// to represent with a BitVector.
23012307
NewDefsReversed.push_back(*RIt);
23022308
continue;
23032309
}
23042310

23052311
// Only keep this location definition if it is not fully eclipsed by
23062312
// other definitions in this wedge that come after it
23072313

2308-
// Inert the bits the location definition defines.
2314+
// Inert the bytes the location definition defines.
23092315
auto InsertResult =
2310-
VariableDefinedBits.try_emplace(Aggr, BitVector(SizeInBits));
2316+
VariableDefinedBytes.try_emplace(Aggr, BitVector(SizeInBytes));
23112317
bool FirstDefinition = InsertResult.second;
2312-
BitVector &DefinedBits = InsertResult.first->second;
2318+
BitVector &DefinedBytes = InsertResult.first->second;
23132319

23142320
DIExpression::FragmentInfo Fragment =
23152321
RIt->Expr->getFragmentInfo().value_or(
23162322
DIExpression::FragmentInfo(SizeInBits, 0));
23172323
bool InvalidFragment = Fragment.endInBits() > SizeInBits;
2324+
uint64_t StartInBytes = Fragment.startInBits() / 8;
2325+
uint64_t EndInBytes = divideCeil(Fragment.endInBits(), 8);
23182326

2319-
// If this defines any previously undefined bits, keep it.
2327+
// If this defines any previously undefined bytes, keep it.
23202328
if (FirstDefinition || InvalidFragment ||
2321-
DefinedBits.find_first_unset_in(Fragment.startInBits(),
2322-
Fragment.endInBits()) != -1) {
2329+
DefinedBytes.find_first_unset_in(StartInBytes, EndInBytes) != -1) {
23232330
if (!InvalidFragment)
2324-
DefinedBits.set(Fragment.startInBits(), Fragment.endInBits());
2331+
DefinedBytes.set(StartInBytes, EndInBytes);
23252332
NewDefsReversed.push_back(*RIt);
23262333
continue;
23272334
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; RUN: llc %s -stop-after=finalize-isel -o - \
2+
; RUN: | FileCheck %s --implicit-check-not=DBG_
3+
4+
;; Based on optimized IR from C source:
5+
;; int main () {
6+
;; char a1[__INT_MAX__];
7+
;; a1[__INT_MAX__ - 1] = 5;
8+
;; return a1[__INT_MAX__ - 1];
9+
;; }
10+
;;
11+
;; Check extremely large types don't cause a crash.
12+
; CHECK: DBG_VALUE 5, $noreg, ![[#]], !DIExpression(DW_OP_LLVM_fragment, 4294967280, 8)
13+
; CHECK: DBG_VALUE 6, $noreg, ![[#]], !DIExpression(DW_OP_LLVM_fragment, 0, 8)
14+
; CHECK: DBG_VALUE 7, $noreg, ![[#]], !DIExpression(DW_OP_LLVM_fragment, 0, 8)
15+
16+
define dso_local i32 @main() local_unnamed_addr !dbg !10 {
17+
entry:
18+
;; FIXME: SROA currently creates incorrect fragments if bit_offset > max(u32),
19+
;; with and without assignment-tracking.
20+
tail call void @llvm.dbg.value(metadata i8 5, metadata !15, metadata !DIExpression(DW_OP_LLVM_fragment, 4294967280, 8)), !dbg !20
21+
;; These two were inserted by hand.
22+
tail call void @llvm.dbg.value(metadata i8 6, metadata !22, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 8)), !dbg !20
23+
tail call void @llvm.dbg.value(metadata i8 7, metadata !23, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 8)), !dbg !20
24+
ret i32 5, !dbg !21
25+
}
26+
27+
declare void @llvm.dbg.value(metadata, metadata, metadata)
28+
29+
!llvm.dbg.cu = !{!0}
30+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
31+
!llvm.ident = !{!9}
32+
33+
!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
34+
!1 = !DIFile(filename: "test.c", directory: "/")
35+
!2 = !{i32 7, !"Dwarf Version", i32 5}
36+
!3 = !{i32 2, !"Debug Info Version", i32 3}
37+
!4 = !{i32 1, !"wchar_size", i32 4}
38+
!5 = !{i32 8, !"PIC Level", i32 2}
39+
!6 = !{i32 7, !"PIE Level", i32 2}
40+
!7 = !{i32 7, !"uwtable", i32 2}
41+
!8 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
42+
!9 = !{!"clang version 18.0.0"}
43+
!10 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !11, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14)
44+
!11 = !DISubroutineType(types: !12)
45+
!12 = !{!13}
46+
!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
47+
!14 = !{!15}
48+
!15 = !DILocalVariable(name: "a1", scope: !10, file: !1, line: 5, type: !16)
49+
!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !17, size: 17179869176, elements: !18)
50+
!17 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
51+
!18 = !{!19}
52+
!19 = !DISubrange(count: 2147483647)
53+
!20 = !DILocation(line: 0, scope: !10)
54+
!21 = !DILocation(line: 7, column: 3, scope: !10)
55+
!22 = !DILocalVariable(name: "a2", scope: !10, file: !1, line: 5, type: !16)
56+
!23 = !DILocalVariable(name: "a3", scope: !10, file: !1, line: 5, type: !16)
57+
!24 = !DICompositeType(tag: DW_TAG_array_type, baseType: !17, size: 4294967232, elements: !18)
58+
!25 = !DICompositeType(tag: DW_TAG_array_type, baseType: !17, size: 4294967233, elements: !18)

0 commit comments

Comments
 (0)