|
| 1 | +//===- DebugInfoCacheTest.cpp - DebugInfoCache unit tests -----------------===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#include "llvm/Analysis/DebugInfoCache.h" |
| 10 | +#include "llvm/AsmParser/Parser.h" |
| 11 | +#include "llvm/IR/Module.h" |
| 12 | +#include "llvm/IR/Verifier.h" |
| 13 | +#include "llvm/Support/SourceMgr.h" |
| 14 | +#include "llvm/Support/raw_ostream.h" |
| 15 | +#include "gtest/gtest.h" |
| 16 | + |
| 17 | +namespace llvm { |
| 18 | +namespace { |
| 19 | + |
| 20 | +// Forward declare the assembly |
| 21 | +extern StringRef MultiCUModule; |
| 22 | + |
| 23 | +const DICompileUnit *findCU(const Module &M, StringRef FileName) { |
| 24 | + for (const auto CU : M.debug_compile_units()) { |
| 25 | + if (CU->getFilename() == FileName) |
| 26 | + return CU; |
| 27 | + } |
| 28 | + |
| 29 | + return nullptr; |
| 30 | +} |
| 31 | + |
| 32 | +class DebugInfoCacheTest : public testing::Test { |
| 33 | +protected: |
| 34 | + LLVMContext C; |
| 35 | + |
| 36 | + std::unique_ptr<Module> makeModule(StringRef Assembly) { |
| 37 | + SMDiagnostic Err; |
| 38 | + auto M = parseAssemblyString(Assembly, Err, C); |
| 39 | + if (!M) |
| 40 | + Err.print("DebugInfoCacheTest", errs()); |
| 41 | + |
| 42 | + verifyModule(*M, &errs()); |
| 43 | + return M; |
| 44 | + } |
| 45 | +}; |
| 46 | + |
| 47 | +TEST_F(DebugInfoCacheTest, TestEmpty) { |
| 48 | + auto M = makeModule(""); |
| 49 | + DebugInfoCache DIC{*M}; |
| 50 | + EXPECT_EQ(DIC.Result.size(), 0u); |
| 51 | +} |
| 52 | + |
| 53 | +TEST_F(DebugInfoCacheTest, TestMultiCU) { |
| 54 | + auto M = makeModule(MultiCUModule); |
| 55 | + DebugInfoCache DIC{*M}; |
| 56 | + EXPECT_EQ(DIC.Result.size(), 2u); |
| 57 | + |
| 58 | + auto *File1CU = findCU(*M, "file1.cpp"); |
| 59 | + EXPECT_NE(File1CU, nullptr); |
| 60 | + |
| 61 | + auto File1DIFinder = DIC.Result.find(File1CU); |
| 62 | + EXPECT_NE(File1DIFinder, DIC.Result.end()); |
| 63 | + |
| 64 | + EXPECT_EQ(File1DIFinder->getSecond().compile_unit_count(), 1u); |
| 65 | + EXPECT_EQ(File1DIFinder->getSecond().type_count(), 6u); |
| 66 | + EXPECT_EQ(File1DIFinder->getSecond().subprogram_count(), 0u); |
| 67 | + EXPECT_EQ(File1DIFinder->getSecond().scope_count(), 1u); |
| 68 | + |
| 69 | + auto *File2CU = findCU(*M, "file2.cpp"); |
| 70 | + EXPECT_NE(File1CU, nullptr); |
| 71 | + |
| 72 | + auto File2DIFinder = DIC.Result.find(File2CU); |
| 73 | + EXPECT_NE(File2DIFinder, DIC.Result.end()); |
| 74 | + |
| 75 | + EXPECT_EQ(File2DIFinder->getSecond().compile_unit_count(), 1u); |
| 76 | + EXPECT_EQ(File2DIFinder->getSecond().type_count(), 2u); |
| 77 | + EXPECT_EQ(File2DIFinder->getSecond().subprogram_count(), 0u); |
| 78 | + EXPECT_EQ(File2DIFinder->getSecond().scope_count(), 2u); |
| 79 | +} |
| 80 | + |
| 81 | +/* Generated roughly by |
| 82 | +file1.cpp: |
| 83 | +struct file1_extern_type1; |
| 84 | +struct file1_extern_type2; |
| 85 | +
|
| 86 | +namespace file1 { |
| 87 | +typedef struct file1_type1 { int x; float y; } file1_type1; |
| 88 | +file1_type1 global{0, 1.}; |
| 89 | +} // file1 |
| 90 | +
|
| 91 | +extern struct file1_extern_type1 *file1_extern_func1(struct |
| 92 | +file1_extern_type2*); |
| 93 | +
|
| 94 | +file1::file1_type1 file1_func1(file1::file1_type1 x) { return x; } |
| 95 | +-------- |
| 96 | +file2.cpp: |
| 97 | +struct file2_extern_type1; |
| 98 | +struct file2_extern_type2; |
| 99 | +
|
| 100 | +namespace file2 { |
| 101 | +typedef struct file2_type1 { float x; float y; } file2_type1; |
| 102 | +enum class file2_type2 { opt1, opt2 }; |
| 103 | +
|
| 104 | +namespace inner { |
| 105 | +file2_type2 inner_global{file2_type2::opt2}; |
| 106 | +} // inner |
| 107 | +} // file2 |
| 108 | +
|
| 109 | +extern struct file2_extern_type1 *file2_extern_func1(struct |
| 110 | +file2_extern_type2*); |
| 111 | +
|
| 112 | +file2::file2_type1 file2_func1(file2::file2_type1 x, file2::file2_type2 y) { |
| 113 | +return x; } |
| 114 | +-------- |
| 115 | +$ clang -S -emit-llvm file*.cpp |
| 116 | +$ llvm-link -S -o single.ll file*.ll |
| 117 | +*/ |
| 118 | +StringRef MultiCUModule = R"""( |
| 119 | +%"struct.file1::file1_type1" = type { i32, float } |
| 120 | +%"struct.file2::file2_type1" = type { float, float } |
| 121 | +
|
| 122 | +@_ZN5file16globalE = dso_local global %"struct.file1::file1_type1" { i32 0, float 1.000000e+00 }, align 4, !dbg !0 |
| 123 | +@_ZN5file25inner12inner_globalE = dso_local global i32 1, align 4, !dbg !11 |
| 124 | +
|
| 125 | +define dso_local i64 @_Z11file1_func1N5file111file1_type1E(i64 %0) !dbg !33 { |
| 126 | + %2 = alloca %"struct.file1::file1_type1", align 4 |
| 127 | + %3 = alloca %"struct.file1::file1_type1", align 4 |
| 128 | + store i64 %0, ptr %3, align 4 |
| 129 | + #dbg_declare(ptr %3, !37, !DIExpression(), !38) |
| 130 | + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %2, ptr align 4 %3, i64 8, i1 false), !dbg !39 |
| 131 | + %4 = load i64, ptr %2, align 4, !dbg !40 |
| 132 | + ret i64 %4, !dbg !40 |
| 133 | +} |
| 134 | +
|
| 135 | +declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) |
| 136 | +
|
| 137 | +define dso_local <2 x float> @_Z11file2_func1N5file211file2_type1ENS_11file2_type2E(<2 x float> %0, i32 noundef %1) !dbg !41 { |
| 138 | + %3 = alloca %"struct.file2::file2_type1", align 4 |
| 139 | + %4 = alloca %"struct.file2::file2_type1", align 4 |
| 140 | + %5 = alloca i32, align 4 |
| 141 | + store <2 x float> %0, ptr %4, align 4 |
| 142 | + #dbg_declare(ptr %4, !49, !DIExpression(), !50) |
| 143 | + store i32 %1, ptr %5, align 4 |
| 144 | + #dbg_declare(ptr %5, !51, !DIExpression(), !52) |
| 145 | + call void @llvm.memcpy.p0.p0.i64(ptr align 4 %3, ptr align 4 %4, i64 8, i1 false), !dbg !53 |
| 146 | + %6 = load <2 x float>, ptr %3, align 4, !dbg !54 |
| 147 | + ret <2 x float> %6, !dbg !54 |
| 148 | +} |
| 149 | +
|
| 150 | +!llvm.dbg.cu = !{!20, !22} |
| 151 | +!llvm.ident = !{!25, !25} |
| 152 | +!llvm.module.flags = !{!26, !27, !28, !29, !30, !31, !32} |
| 153 | +
|
| 154 | +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) |
| 155 | +!1 = distinct !DIGlobalVariable(name: "global", linkageName: "_ZN5file16globalE", scope: !2, file: !3, line: 6, type: !4, isLocal: false, isDefinition: true) |
| 156 | +!2 = !DINamespace(name: "file1", scope: null) |
| 157 | +!3 = !DIFile(filename: "file1.cpp", directory: "") |
| 158 | +!4 = !DIDerivedType(tag: DW_TAG_typedef, name: "file1_type1", scope: !2, file: !3, line: 5, baseType: !5) |
| 159 | +!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "file1_type1", scope: !2, file: !3, line: 5, size: 64, flags: DIFlagTypePassByValue, elements: !6, identifier: "_ZTSN5file111file1_type1E") |
| 160 | +!6 = !{!7, !9} |
| 161 | +!7 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !5, file: !3, line: 5, baseType: !8, size: 32) |
| 162 | +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) |
| 163 | +!9 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !5, file: !3, line: 5, baseType: !10, size: 32, offset: 32) |
| 164 | +!10 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) |
| 165 | +!11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression()) |
| 166 | +!12 = distinct !DIGlobalVariable(name: "inner_global", linkageName: "_ZN5file25inner12inner_globalE", scope: !13, file: !15, line: 9, type: !16, isLocal: false, isDefinition: true) |
| 167 | +!13 = !DINamespace(name: "inner", scope: !14) |
| 168 | +!14 = !DINamespace(name: "file2", scope: null) |
| 169 | +!15 = !DIFile(filename: "file2.cpp", directory: "") |
| 170 | +!16 = distinct !DICompositeType(tag: DW_TAG_enumeration_type, name: "file2_type2", scope: !14, file: !15, line: 6, baseType: !8, size: 32, flags: DIFlagEnumClass, elements: !17, identifier: "_ZTSN5file211file2_type2E") |
| 171 | +!17 = !{!18, !19} |
| 172 | +!18 = !DIEnumerator(name: "opt1", value: 0) |
| 173 | +!19 = !DIEnumerator(name: "opt2", value: 1) |
| 174 | +!20 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !21, splitDebugInlining: false, nameTableKind: None) |
| 175 | +!21 = !{!0} |
| 176 | +!22 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !15, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !23, globals: !24, splitDebugInlining: false, nameTableKind: None) |
| 177 | +!23 = !{!16} |
| 178 | +!24 = !{!11} |
| 179 | +!25 = !{!"clang"} |
| 180 | +!26 = !{i32 7, !"Dwarf Version", i32 5} |
| 181 | +!27 = !{i32 2, !"Debug Info Version", i32 3} |
| 182 | +!28 = !{i32 1, !"wchar_size", i32 4} |
| 183 | +!29 = !{i32 8, !"PIC Level", i32 2} |
| 184 | +!30 = !{i32 7, !"PIE Level", i32 2} |
| 185 | +!31 = !{i32 7, !"uwtable", i32 2} |
| 186 | +!32 = !{i32 7, !"frame-pointer", i32 2} |
| 187 | +!33 = distinct !DISubprogram(name: "file1_func1", linkageName: "_Z11file1_func1N5file111file1_type1E", scope: !3, file: !3, line: 11, type: !34, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !20, retainedNodes: !36) |
| 188 | +!34 = !DISubroutineType(types: !35) |
| 189 | +!35 = !{!4, !4} |
| 190 | +!36 = !{} |
| 191 | +!37 = !DILocalVariable(name: "x", arg: 1, scope: !33, file: !3, line: 11, type: !4) |
| 192 | +!38 = !DILocation(line: 11, column: 51, scope: !33) |
| 193 | +!39 = !DILocation(line: 11, column: 63, scope: !33) |
| 194 | +!40 = !DILocation(line: 11, column: 56, scope: !33) |
| 195 | +!41 = distinct !DISubprogram(name: "file2_func1", linkageName: "_Z11file2_func1N5file211file2_type1ENS_11file2_type2E", scope: !15, file: !15, line: 15, type: !42, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !22, retainedNodes: !36) |
| 196 | +!42 = !DISubroutineType(types: !43) |
| 197 | +!43 = !{!44, !44, !16} |
| 198 | +!44 = !DIDerivedType(tag: DW_TAG_typedef, name: "file2_type1", scope: !14, file: !15, line: 5, baseType: !45) |
| 199 | +!45 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "file2_type1", scope: !14, file: !15, line: 5, size: 64, flags: DIFlagTypePassByValue, elements: !46, identifier: "_ZTSN5file211file2_type1E") |
| 200 | +!46 = !{!47, !48} |
| 201 | +!47 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !45, file: !15, line: 5, baseType: !10, size: 32) |
| 202 | +!48 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !45, file: !15, line: 5, baseType: !10, size: 32, offset: 32) |
| 203 | +!49 = !DILocalVariable(name: "x", arg: 1, scope: !41, file: !15, line: 15, type: !44) |
| 204 | +!50 = !DILocation(line: 15, column: 51, scope: !41) |
| 205 | +!51 = !DILocalVariable(name: "y", arg: 2, scope: !41, file: !15, line: 15, type: !16) |
| 206 | +!52 = !DILocation(line: 15, column: 73, scope: !41) |
| 207 | +!53 = !DILocation(line: 15, column: 85, scope: !41) |
| 208 | +!54 = !DILocation(line: 15, column: 78, scope: !41) |
| 209 | +)"""; |
| 210 | +} // namespace |
| 211 | +} // namespace llvm |
0 commit comments