From ac945e27dd73525ec0beddfb200049cf0f9bbfce Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Fri, 17 Jun 2016 16:11:20 +0000 Subject: [PATCH] [codeview] Make function names more consistent with MSVC Names in function id records don't include nested name specifiers or template arguments, but names in the symbol stream include both. For the symbol stream, instead of having Clang put the fully qualified name in the subprogram display name, recreate it from the subprogram scope chain. For the type stream, take the unqualified name and chop of any template arguments. This makes it so that CodeView DI metadata is more similar to DWARF DI metadata. llvm-svn: 273009 --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 67 ++++++----- llvm/test/DebugInfo/COFF/cpp-mangling.ll | 104 +++++++++++------- 2 files changed, 104 insertions(+), 67 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 5ba76823a9b6..47adfc731fd5 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -135,7 +135,9 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) { return I->second; TypeIndex ParentScope = TypeIndex(0); - StringRef DisplayName = SP->getDisplayName(); + // The display name includes function template arguments. Drop them to match + // MSVC. + StringRef DisplayName = SP->getDisplayName().split('<').first; FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName); TypeIndex TI = TypeTable.writeFuncId(FuncId); @@ -453,6 +455,31 @@ void CodeViewDebug::switchToDebugSectionForSymbol(const MCSymbol *GVSym) { emitCodeViewMagicVersion(); } +static const DISubprogram *getQualifiedNameComponents( + const DIScope *Scope, SmallVectorImpl &QualifiedNameComponents) { + const DISubprogram *ClosestSubprogram = nullptr; + while (Scope != nullptr) { + if (ClosestSubprogram == nullptr) + ClosestSubprogram = dyn_cast(Scope); + StringRef ScopeName = Scope->getName(); + if (!ScopeName.empty()) + QualifiedNameComponents.push_back(ScopeName); + Scope = Scope->getScope().resolve(); + } + return ClosestSubprogram; +} + +static std::string getQualifiedName(ArrayRef QualifiedNameComponents, + StringRef TypeName) { + std::string FullyQualifiedName; + for (StringRef QualifiedNameComponent : reverse(QualifiedNameComponents)) { + FullyQualifiedName.append(QualifiedNameComponent); + FullyQualifiedName.append("::"); + } + FullyQualifiedName.append(TypeName); + return FullyQualifiedName; +} + void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, FunctionInfo &FI) { // For each function there is a separate subsection @@ -463,11 +490,18 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV, // Switch to the to a comdat section, if appropriate. switchToDebugSectionForSymbol(Fn); - StringRef FuncName; + std::string FuncName; auto *SP = GV->getSubprogram(); setCurrentSubprogram(SP); - if (SP != nullptr) - FuncName = SP->getDisplayName(); + + // If we have a display name, build the fully qualified name by walking the + // chain of scopes. + if (SP != nullptr && !SP->getDisplayName().empty()) { + SmallVector QualifiedNameComponents; + getQualifiedNameComponents(SP->getScope().resolve(), + QualifiedNameComponents); + FuncName = getQualifiedName(QualifiedNameComponents, SP->getDisplayName()); + } // If our DISubprogram name is empty, use the mangled name. if (FuncName.empty()) @@ -769,31 +803,6 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty) { } } -static const DISubprogram *getQualifiedNameComponents( - const DIScope *Scope, SmallVectorImpl &QualifiedNameComponents) { - const DISubprogram *ClosestSubprogram = nullptr; - while (Scope != nullptr) { - if (ClosestSubprogram == nullptr) - ClosestSubprogram = dyn_cast(Scope); - StringRef ScopeName = Scope->getName(); - if (!ScopeName.empty()) - QualifiedNameComponents.push_back(ScopeName); - Scope = Scope->getScope().resolve(); - } - return ClosestSubprogram; -} - -static std::string getQualifiedName(ArrayRef QualifiedNameComponents, - StringRef TypeName) { - std::string FullyQualifiedName; - for (StringRef QualifiedNameComponent : reverse(QualifiedNameComponents)) { - FullyQualifiedName.append(QualifiedNameComponent); - FullyQualifiedName.append("::"); - } - FullyQualifiedName.append(TypeName); - return FullyQualifiedName; -} - TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) { DITypeRef UnderlyingTypeRef = Ty->getBaseType(); TypeIndex UnderlyingTypeIndex = getTypeIndex(UnderlyingTypeRef); diff --git a/llvm/test/DebugInfo/COFF/cpp-mangling.ll b/llvm/test/DebugInfo/COFF/cpp-mangling.ll index c0eec6c6eb60..a75720f18128 100644 --- a/llvm/test/DebugInfo/COFF/cpp-mangling.ll +++ b/llvm/test/DebugInfo/COFF/cpp-mangling.ll @@ -1,55 +1,83 @@ -; RUN: llc -mcpu=core2 -mtriple=i686-pc-win32 -o - -O0 < %s \ -; RUN: | llvm-mc -triple=i686-pc-win32 -filetype=obj \ -; RUN: | llvm-readobj -s -sr -codeview -section-symbols | FileCheck %s +; RUN: llc -mcpu=core2 -mtriple=i686-pc-win32 -o - -O0 -filetype=obj < %s \ +; RUN: | llvm-readobj -codeview | FileCheck %s -; This LL file was generated by running clang on the following code: -; D:\src.cpp: -; 1 namespace foo { -; 2 int bar(int x) { -; 3 return x * 2; -; 4 } -; 5 } +; C++ source to regenerate: +; namespace foo { +; int bar(int x) { return x * 2; } +; } +; template +; void fn_tmpl() {} +; template void fn_tmpl(); +; void f() { +; fn_tmpl(); +; } ; CHECK: ProcStart { -; CHECK: DisplayName: foo::bar -; CHECK-NEXT: LinkageName: ?bar@foo@@YAHH@Z +; CHECK: FunctionType: bar ({{.*}}) +; CHECK: DisplayName: foo::bar{{$}} +; CHECK-NEXT: LinkageName: ?bar@foo@@YAHH@Z -; Function Attrs: nounwind uwtable -define i32 @"\01?bar@foo@@YAHH@Z"(i32 %x) #0 !dbg !4 { +; CHECK: ProcStart { +; CHECK: FunctionType: fn_tmpl ({{.*}}) +; CHECK: DisplayName: foo::fn_tmpl +; CHECK-NEXT: LinkageName: ??$fn_tmpl@H$1?bar@foo@@YAHH@Z@foo@@YAXXZ + +; ModuleID = 't.cpp' +source_filename = "t.cpp" +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i386-pc-windows-msvc19.0.23918" + +$"\01??$fn_tmpl@H$1?bar@foo@@YAHH@Z@foo@@YAXXZ" = comdat any + +; Function Attrs: nounwind +define i32 @"\01?bar@foo@@YAHH@Z"(i32 %x) #0 !dbg !6 { entry: %x.addr = alloca i32, align 4 store i32 %x, i32* %x.addr, align 4 - call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !13, metadata !14), !dbg !15 - %0 = load i32, i32* %x.addr, align 4, !dbg !16 - %mul = mul nsw i32 %0, 2, !dbg !17 - ret i32 %mul, !dbg !18 + call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !11, metadata !12), !dbg !13 + %0 = load i32, i32* %x.addr, align 4, !dbg !14 + %mul = mul nsw i32 %0, 2, !dbg !15 + ret i32 %mul, !dbg !16 } ; Function Attrs: nounwind readnone declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 -attributes #0 = { nounwind uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2" "unsafe-fp-math"="false" "use-soft-float"="false" } +; Function Attrs: nounwind +define weak_odr void @"\01??$fn_tmpl@H$1?bar@foo@@YAHH@Z@foo@@YAXXZ"() #0 comdat !dbg !17 { +entry: + ret void, !dbg !24 +} + +attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="pentium4" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { nounwind readnone } !llvm.dbg.cu = !{!0} -!llvm.module.flags = !{!9, !10, !11} -!llvm.ident = !{!12} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!5} -!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 (trunk 257652)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) -!1 = !DIFile(filename: "t2.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild") +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.9.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "t.cpp", directory: "D:\5Csrc\5Cllvm\5Cbuild") !2 = !{} -!4 = distinct !DISubprogram(name: "foo::bar", linkageName: "\01?bar@foo@@YAHH@Z", scope: !5, file: !1, line: 2, type: !6, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) -!5 = !DINamespace(name: "foo", scope: null, file: !1, line: 1) -!6 = !DISubroutineType(types: !7) -!7 = !{!8, !8} -!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) -!9 = !{i32 2, !"CodeView", i32 1} -!10 = !{i32 2, !"Debug Info Version", i32 3} -!11 = !{i32 1, !"PIC Level", i32 2} -!12 = !{!"clang version 3.9.0 (trunk 257652)"} -!13 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !1, line: 2, type: !8) -!14 = !DIExpression() -!15 = !DILocation(line: 2, column: 13, scope: !4) -!16 = !DILocation(line: 3, column: 10, scope: !4) -!17 = !DILocation(line: 3, column: 12, scope: !4) -!18 = !DILocation(line: 3, column: 3, scope: !4) +!3 = !{i32 2, !"CodeView", i32 1} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{!"clang version 3.9.0 "} +!6 = distinct !DISubprogram(name: "bar", linkageName: "\01?bar@foo@@YAHH@Z", scope: !7, file: !1, line: 2, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!7 = !DINamespace(name: "foo", scope: null, file: !1, line: 1) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!11 = !DILocalVariable(name: "x", arg: 1, scope: !6, file: !1, line: 2, type: !10) +!12 = !DIExpression() +!13 = !DILocation(line: 2, column: 13, scope: !6) +!14 = !DILocation(line: 2, column: 25, scope: !6) +!15 = !DILocation(line: 2, column: 27, scope: !6) +!16 = !DILocation(line: 2, column: 18, scope: !6) +!17 = distinct !DISubprogram(name: "fn_tmpl", linkageName: "\01??$fn_tmpl@H$1?bar@foo@@YAHH@Z@foo@@YAXXZ", scope: !7, file: !1, line: 4, type: !18, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, unit: !0, templateParams: !20, variables: !2) +!18 = !DISubroutineType(types: !19) +!19 = !{null} +!20 = !{!21, !22} +!21 = !DITemplateTypeParameter(name: "T", type: !10) +!22 = !DITemplateValueParameter(type: !23, value: i32 (i32)* @"\01?bar@foo@@YAHH@Z") +!23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 32, align: 32) +!24 = !DILocation(line: 4, column: 17, scope: !17)