From c68f895702958dda96bfc297a3bc491082c5269d Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Tue, 20 Nov 2018 22:13:43 +0000 Subject: [PATCH] [CodeView] Add support for ref-qualified member functions. When you have a member function with a ref-qualifier, for example: struct Foo { void Func() &; void Func2() &&; }; clang-cl was not emitting this information. Doing so is a bit awkward, because it's not a property of the LF_MFUNCTION type, which is what you'd expect. Instead, it's a property of the this pointer which is actually an LF_POINTER. This record has an attributes bitmask on it, and our handling of this bitmask was all wrong. We had some parts of the bitmask defined incorrectly, but importantly for this bug, we didn't know about these extra 2 bits that represent the ref qualifier at all. Differential Revision: https://reviews.llvm.org/D54667 llvm-svn: 347354 --- llvm/include/llvm/DebugInfo/CodeView/CodeView.h | 4 +- llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h | 16 +- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 66 ++++--- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h | 4 + llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp | 2 + .../DebugInfo/COFF/types-method-ref-qualifiers.ll | 205 +++++++++++++++++++++ 6 files changed, 273 insertions(+), 24 deletions(-) create mode 100644 llvm/test/DebugInfo/COFF/types-method-ref-qualifiers.ll diff --git a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h index 4b96bc1..8e0d9f6 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/llvm/include/llvm/DebugInfo/CodeView/CodeView.h @@ -358,7 +358,9 @@ enum class PointerOptions : uint32_t { Const = 0x00000400, Unaligned = 0x00000800, Restrict = 0x00001000, - WinRTSmartPointer = 0x00080000 + WinRTSmartPointer = 0x00080000, + LValueRefThisPointer = 0x00100000, + RValueRefThisPointer = 0x00200000 }; CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(PointerOptions) diff --git a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h index 8cd8f87..15f6434 100644 --- a/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ b/llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -264,14 +264,18 @@ public: // LF_POINTER class PointerRecord : public TypeRecord { public: + // ---------------------------XXXXX static const uint32_t PointerKindShift = 0; static const uint32_t PointerKindMask = 0x1F; + // ------------------------XXX----- static const uint32_t PointerModeShift = 5; static const uint32_t PointerModeMask = 0x07; - static const uint32_t PointerOptionMask = 0xFF; + // ----------XXX------XXXXX------- + static const uint32_t PointerOptionMask = 0x1C0F80; + // -------------XXXXXX------------ static const uint32_t PointerSizeShift = 13; static const uint32_t PointerSizeMask = 0xFF; @@ -305,7 +309,7 @@ public: } PointerOptions getOptions() const { - return static_cast(Attrs); + return static_cast(Attrs & PointerOptionMask); } uint8_t getSize() const { @@ -334,6 +338,14 @@ public: return !!(Attrs & uint32_t(PointerOptions::Restrict)); } + bool isLValueReferenceThisPtr() const { + return !!(Attrs & uint32_t(PointerOptions::LValueRefThisPointer)); + } + + bool isRValueReferenceThisPtr() const { + return !!(Attrs & uint32_t(PointerOptions::RValueRefThisPointer)); + } + TypeIndex ReferentType; uint32_t Attrs; Optional MemberInfo; diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 59056b0..6d43143 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -1882,27 +1882,22 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty, // Lower the containing class type. TypeIndex ClassType = getTypeIndex(ClassTy); - SmallVector ReturnAndArgTypeIndices; - for (DITypeRef ArgTypeRef : Ty->getTypeArray()) - ReturnAndArgTypeIndices.push_back(getTypeIndex(ArgTypeRef)); + DITypeRefArray ReturnAndArgs = Ty->getTypeArray(); + + unsigned Index = 0; + SmallVector ArgTypeIndices; + TypeIndex ReturnTypeIndex = getTypeIndex(ReturnAndArgs[Index++]); - // MSVC uses type none for variadic argument. - if (ReturnAndArgTypeIndices.size() > 1 && - ReturnAndArgTypeIndices.back() == TypeIndex::Void()) { - ReturnAndArgTypeIndices.back() = TypeIndex::None(); - } - TypeIndex ReturnTypeIndex = TypeIndex::Void(); - ArrayRef ArgTypeIndices = None; - if (!ReturnAndArgTypeIndices.empty()) { - auto ReturnAndArgTypesRef = makeArrayRef(ReturnAndArgTypeIndices); - ReturnTypeIndex = ReturnAndArgTypesRef.front(); - ArgTypeIndices = ReturnAndArgTypesRef.drop_front(); - } TypeIndex ThisTypeIndex; - if (!IsStaticMethod && !ArgTypeIndices.empty()) { - ThisTypeIndex = ArgTypeIndices.front(); - ArgTypeIndices = ArgTypeIndices.drop_front(); - } + if (!IsStaticMethod && ReturnAndArgs.size() > 1) + ThisTypeIndex = getTypeIndexForThisPtr(ReturnAndArgs[Index++], Ty); + + while (Index < ReturnAndArgs.size()) + ArgTypeIndices.push_back(getTypeIndex(ReturnAndArgs[Index++])); + + // MSVC uses type none for variadic argument. + if (!ArgTypeIndices.empty() && ArgTypeIndices.back() == TypeIndex::Void()) + ArgTypeIndices.back() = TypeIndex::None(); ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices); TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec); @@ -1992,8 +1987,8 @@ static ClassOptions getCommonClassOptions(const DICompositeType *Ty) { CO |= ClassOptions::Nested; // Put the Scoped flag on function-local types. MSVC puts this flag for enum - // type only when it has an immediate function scope. Clang never puts enums - // inside DILexicalBlock scopes. Enum types, as generated by clang, are + // type only when it has an immediate function scope. Clang never puts enums + // inside DILexicalBlock scopes. Enum types, as generated by clang, are // always in function, class, or file scopes. if (Ty->getTag() == dwarf::DW_TAG_enumeration_type) { if (ImmediateScope && isa(ImmediateScope)) @@ -2449,6 +2444,35 @@ TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) { return recordTypeIndexForDINode(Ty, TI, ClassTy); } +codeview::TypeIndex +CodeViewDebug::getTypeIndexForThisPtr(DITypeRef TypeRef, + const DISubroutineType *SubroutineTy) { + const DIType *Ty = TypeRef.resolve(); + + PointerOptions Options = PointerOptions::None; + if (SubroutineTy->getFlags() & DINode::DIFlags::FlagLValueReference) + Options = PointerOptions::LValueRefThisPointer; + else if (SubroutineTy->getFlags() & DINode::DIFlags::FlagRValueReference) + Options = PointerOptions::RValueRefThisPointer; + + // Check if we've already translated this type. If there is no ref qualifier + // on the function then we look up this pointer type with no associated class + // so that the TypeIndex for the this pointer can be shared with the type + // index for other pointers to this class type. If there is a ref qualifier + // then we lookup the pointer using the subroutine as the parent type. + const DIType *ParentTy = nullptr; + if (Options != PointerOptions::None) + ParentTy = SubroutineTy; + + auto I = TypeIndices.find({Ty, SubroutineTy}); + if (I != TypeIndices.end()) + return I->second; + + TypeLoweringScope S(*this); + TypeIndex TI = lowerTypePointer(cast(Ty), Options); + return recordTypeIndexForDINode(Ty, TI, SubroutineTy); +} + TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) { DIType *Ty = TypeRef.resolve(); PointerRecord PR(getTypeIndex(Ty), diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index e85de52..e64197a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -346,6 +346,10 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { codeview::TypeIndex getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef = DITypeRef()); + codeview::TypeIndex + getTypeIndexForThisPtr(DITypeRef TypeRef, + const DISubroutineType *SubroutineTy); + codeview::TypeIndex getTypeIndexForReferenceTo(DITypeRef TypeRef); codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP, diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp index f7afc06..f5d3bea 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -370,6 +370,8 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { W->printNumber("IsVolatile", Ptr.isVolatile()); W->printNumber("IsUnaligned", Ptr.isUnaligned()); W->printNumber("IsRestrict", Ptr.isRestrict()); + W->printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr()); + W->printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr()); W->printNumber("SizeOf", Ptr.getSize()); if (Ptr.isPointerToMember()) { diff --git a/llvm/test/DebugInfo/COFF/types-method-ref-qualifiers.ll b/llvm/test/DebugInfo/COFF/types-method-ref-qualifiers.ll new file mode 100644 index 0000000..305eeeb --- /dev/null +++ b/llvm/test/DebugInfo/COFF/types-method-ref-qualifiers.ll @@ -0,0 +1,205 @@ +; RUN: llc < %s -filetype=obj | llvm-readobj - -codeview | FileCheck %s + +; C++ source to regenerate: +; struct A { +; int NoRefQual(); +; +; int RefQual() &; +; int RefQual() &&; +; +; int LValueRef() &; +; +; int RValueRef() &&; +; }; +; +; void foo() { +; A *GenericPtr = nullptr; +; A a; +; } + + +; ModuleID = 'foo.cpp' +source_filename = "foo.cpp" +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.15.26732" + +%struct.A = type { i8 } + +; Function Attrs: noinline nounwind optnone uwtable +define dso_local void @"?foo@@YAXXZ"() #0 !dbg !10 { +entry: + %GenericPtr = alloca %struct.A*, align 8 + %a = alloca %struct.A, align 1 + call void @llvm.dbg.declare(metadata %struct.A** %GenericPtr, metadata !13, metadata !DIExpression()), !dbg !28 + store %struct.A* null, %struct.A** %GenericPtr, align 8, !dbg !28 + call void @llvm.dbg.declare(metadata %struct.A* %a, metadata !29, metadata !DIExpression()), !dbg !30 + ret void, !dbg !31 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!0} +!llvm.linker.options = !{!3, !4} +!llvm.module.flags = !{!5, !6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 8.0.0 ", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, nameTableKind: None) +!1 = !DIFile(filename: "foo.cpp", directory: "D:\5C\5Csrc\5C\5Cllvmbuild\5C\5Cninja-x64", checksumkind: CSK_MD5, checksum: "d1b6ae9dc9ab85ca0a41c8b8c79a0b6a") +!2 = !{} +!3 = !{!"/DEFAULTLIB:libcmt.lib"} +!4 = !{!"/DEFAULTLIB:oldnames.lib"} +!5 = !{i32 2, !"CodeView", i32 1} +!6 = !{i32 2, !"Debug Info Version", i32 3} +!7 = !{i32 1, !"wchar_size", i32 2} +!8 = !{i32 7, !"PIC Level", i32 2} +!9 = !{!"clang version 8.0.0 "} +!10 = distinct !DISubprogram(name: "foo", linkageName: "?foo@@YAXXZ", scope: !1, file: !1, line: 12, type: !11, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2) +!11 = !DISubroutineType(types: !12) +!12 = !{null} +!13 = !DILocalVariable(name: "GenericPtr", scope: !10, file: !1, line: 13, type: !14) +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!15 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !1, line: 1, size: 8, flags: DIFlagTypePassByValue | DIFlagTrivial, elements: !16, identifier: ".?AUA@@") +!16 = !{!17, !22, !24, !26, !27} +!17 = !DISubprogram(name: "NoRefQual", linkageName: "?NoRefQual@A@@QEAAHXZ", scope: !15, file: !1, line: 2, type: !18, isLocal: false, isDefinition: false, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false) +!18 = !DISubroutineType(types: !19) +!19 = !{!20, !21} +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!22 = !DISubprogram(name: "RefQual", linkageName: "?RefQual@A@@QEGAAHXZ", scope: !15, file: !1, line: 4, type: !23, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped | DIFlagLValueReference, isOptimized: false) +!23 = !DISubroutineType(flags: DIFlagLValueReference, types: !19) +!24 = !DISubprogram(name: "RefQual", linkageName: "?RefQual@A@@QEHAAHXZ", scope: !15, file: !1, line: 5, type: !25, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped | DIFlagRValueReference, isOptimized: false) +!25 = !DISubroutineType(flags: DIFlagRValueReference, types: !19) +!26 = !DISubprogram(name: "LValueRef", linkageName: "?LValueRef@A@@QEGAAHXZ", scope: !15, file: !1, line: 7, type: !23, isLocal: false, isDefinition: false, scopeLine: 7, flags: DIFlagPrototyped | DIFlagLValueReference, isOptimized: false) +!27 = !DISubprogram(name: "RValueRef", linkageName: "?RValueRef@A@@QEHAAHXZ", scope: !15, file: !1, line: 9, type: !25, isLocal: false, isDefinition: false, scopeLine: 9, flags: DIFlagPrototyped | DIFlagRValueReference, isOptimized: false) +!28 = !DILocation(line: 13, scope: !10) +!29 = !DILocalVariable(name: "a", scope: !10, file: !1, line: 14, type: !15) +!30 = !DILocation(line: 14, scope: !10) +!31 = !DILocation(line: 15, scope: !10) + + + + +; CHECK: CodeViewTypes [ +; CHECK: Section: .debug$T (7) +; CHECK: Magic: 0x4 +; CHECK: Pointer (0x1005) { +; CHECK: TypeLeafKind: LF_POINTER (0x1002) +; CHECK: PointeeType: A (0x1003) +; CHECK: PtrType: Near64 (0xC) +; CHECK: PtrMode: Pointer (0x0) +; CHECK: IsFlat: 0 +; CHECK: IsConst: 1 +; CHECK: IsVolatile: 0 +; CHECK: IsUnaligned: 0 +; CHECK: IsRestrict: 0 +; CHECK: IsThisPtr&: 0 +; CHECK: IsThisPtr&&: 0 +; CHECK: SizeOf: 8 +; CHECK: } +; CHECK: MemberFunction (0x1006) { +; CHECK: TypeLeafKind: LF_MFUNCTION (0x1009) +; CHECK: ReturnType: int (0x74) +; CHECK: ClassType: A (0x1003) +; CHECK: ThisType: A* const (0x1005) +; CHECK: CallingConvention: NearC (0x0) +; CHECK: FunctionOptions [ (0x0) +; CHECK: ] +; CHECK: NumParameters: 0 +; CHECK: ArgListType: () (0x1000) +; CHECK: ThisAdjustment: 0 +; CHECK: } +; CHECK: Pointer (0x1007) { +; CHECK: TypeLeafKind: LF_POINTER (0x1002) +; CHECK: PointeeType: A (0x1003) +; CHECK: PtrType: Near64 (0xC) +; CHECK: PtrMode: Pointer (0x0) +; CHECK: IsFlat: 0 +; CHECK: IsConst: 1 +; CHECK: IsVolatile: 0 +; CHECK: IsUnaligned: 0 +; CHECK: IsRestrict: 0 +; CHECK: IsThisPtr&: 1 +; CHECK: IsThisPtr&&: 0 +; CHECK: SizeOf: 136 +; CHECK: } +; CHECK: MemberFunction (0x1008) { +; CHECK: TypeLeafKind: LF_MFUNCTION (0x1009) +; CHECK: ReturnType: int (0x74) +; CHECK: ClassType: A (0x1003) +; CHECK: ThisType: A* const (0x1007) +; CHECK: CallingConvention: NearC (0x0) +; CHECK: FunctionOptions [ (0x0) +; CHECK: ] +; CHECK: NumParameters: 0 +; CHECK: ArgListType: () (0x1000) +; CHECK: ThisAdjustment: 0 +; CHECK: } +; CHECK: Pointer (0x1009) { +; CHECK: TypeLeafKind: LF_POINTER (0x1002) +; CHECK: PointeeType: A (0x1003) +; CHECK: PtrType: Near64 (0xC) +; CHECK: PtrMode: Pointer (0x0) +; CHECK: IsFlat: 0 +; CHECK: IsConst: 1 +; CHECK: IsVolatile: 0 +; CHECK: IsUnaligned: 0 +; CHECK: IsRestrict: 0 +; CHECK: IsThisPtr&: 0 +; CHECK: IsThisPtr&&: 1 +; CHECK: SizeOf: 8 +; CHECK: } +; CHECK: MemberFunction (0x100A) { +; CHECK: TypeLeafKind: LF_MFUNCTION (0x1009) +; CHECK: ReturnType: int (0x74) +; CHECK: ClassType: A (0x1003) +; CHECK: ThisType: A* const (0x1009) +; CHECK: CallingConvention: NearC (0x0) +; CHECK: FunctionOptions [ (0x0) +; CHECK: ] +; CHECK: NumParameters: 0 +; CHECK: ArgListType: () (0x1000) +; CHECK: ThisAdjustment: 0 +; CHECK: } +; CHECK: MethodOverloadList (0x100B) { +; CHECK: TypeLeafKind: LF_METHODLIST (0x1206) +; CHECK: Method [ +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: int A::() (0x1008) +; CHECK: ] +; CHECK: Method [ +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: int A::() (0x100A) +; CHECK: ] +; CHECK: } +; CHECK: FieldList (0x100C) { +; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203) +; CHECK: OneMethod { +; CHECK: TypeLeafKind: LF_ONEMETHOD (0x1511) +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: int A::() (0x1006) +; CHECK: Name: NoRefQual +; CHECK: } +; CHECK: OverloadedMethod { +; CHECK: TypeLeafKind: LF_METHOD (0x150F) +; CHECK: MethodCount: 0x2 +; CHECK: MethodListIndex: 0x100B +; CHECK: Name: RefQual +; CHECK: } +; CHECK: OneMethod { +; CHECK: TypeLeafKind: LF_ONEMETHOD (0x1511) +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: int A::() (0x1008) +; CHECK: Name: LValueRef +; CHECK: } +; CHECK: OneMethod { +; CHECK: TypeLeafKind: LF_ONEMETHOD (0x1511) +; CHECK: AccessSpecifier: Public (0x3) +; CHECK: Type: int A::() (0x100A) +; CHECK: Name: RValueRef +; CHECK: } +; CHECK: } +; CHECK: ] -- 2.7.4