Michael137 created this revision. Michael137 added reviewers: dblaikie, aprantl. Herald added a project: All. Michael137 requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
**Summary** After this patch, any `AbiTagAttr` attribute on a constructor/destructor (like the ones for numerous types in libcxx) will be attached to the declaration `DW_TAG_subprogram` as a `DW_TAG_LLVM_annotation`. E.g., DW_TAG_subprogram DW_AT_name ("shared_ptr") DW_AT_decl_file ("./bin/../include/c++/v1/__memory/shared_ptr.h") DW_AT_decl_line (475) DW_AT_declaration (true) DW_AT_external (true) DW_AT_accessibility (DW_ACCESS_public) DW_TAG_LLVM_annotation DW_AT_name ("abi_tag") DW_AT_const_value ("v170000") We only emit these annotations for constructors/destructors declarations because those don't carry linkage names, which is where this information is usually encoded. **Motivation** ABI tags affect a function's linkage name, which LLDB uses to resolve function calls during expression evaluation. However, constructors/destructors are emitted as declarations and can have multiple definitions with different linkage names for a single declaration DIE. LLDB relies on Clang to mangle the function AST node into the correct linkage name. However, LLDB doesn't know about the `AbiTagAttr` that was attached to a constructor/destructor in the source, so there's no way to cleanly reconstruct the AST and resolve the function symbol. With this patch, LLDB can attach the ABI tag to the ctor/dtor decl and let clang determine which linkage name to pick. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D144181 Files: clang/lib/CodeGen/CGDebugInfo.cpp clang/lib/CodeGen/CGDebugInfo.h clang/test/CodeGen/attr-abi_tag-ctors-dtors.cpp
Index: clang/test/CodeGen/attr-abi_tag-ctors-dtors.cpp =================================================================== --- /dev/null +++ clang/test/CodeGen/attr-abi_tag-ctors-dtors.cpp @@ -0,0 +1,25 @@ +// RUN: %clang -g -S -emit-llvm -o - %s | FileCheck %s + +struct Foo { + [[gnu::abi_tag("Ctor")]] Foo() {} + [[gnu::abi_tag("Dtor")]] ~Foo() {} +}; + +Foo f; + +// CHECK: ![[#]] = !DISubprogram(name: "Foo", +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: [[#]], annotations: ![[CTOR_ANNOTS:[0-9]+]]) +// CHECK: ![[CTOR_ANNOTS]] = !{![[CTOR:[0-9]+]]} +// CHECK: ![[CTOR]] = !{!"abi_tag", !"Ctor"} +// CHECK: ![[#]] = !DISubprogram(name: "~Foo", +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: [[#]], annotations: ![[DTOR_ANNOTS:[0-9]+]]) +// CHECK: ![[DTOR_ANNOTS]] = !{![[DTOR:[0-9]+]]} +// CHECK: ![[DTOR]] = !{!"abi_tag", !"Dtor"} +// CHECK: ![[#]] = distinct !DISubprogram(name: "Foo", +// FCHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]], annotations: ![[CTOR_ANNOTS]]) +// FCHECK: ![[#]] = distinct !DISubprogram(name: "~Foo", +// FCHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]], annotations: ![[DTOR_ANNOTS]]) +// FCHECK: ![[#]] = distinct !DISubprogram(name: "Foo", +// FCHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]], annotations: ![[CTOR_ANNOTS]]) +// FCHECK: ![[#]] = distinct !DISubprogram(name: "~Foo", +// FCHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]], annotations: ![[DTOR_ANNOTS]]) Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -303,6 +303,10 @@ /// A helper function to collect debug info for btf_decl_tag annotations. llvm::DINodeArray CollectBTFDeclTagAnnotations(const Decl *D); + /// A helper function to collect debug info for abi_tag annotations. + /// Returns a null DINodeArray if 'D' doesn't have any 'clang::AbiTagAttr's. + llvm::DINodeArray CollectAbiTagAnnotations(const Decl *D); + llvm::DIType *createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -1350,6 +1350,8 @@ SourceLocation Loc = Ty->getDecl()->getLocation(); uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext()); + // TODO: need to account for tags on typedefs? Or would LLDB correctly + // call through typedefs of abi-tagged decls? // Typedefs are derived from some other type. llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(Ty->getDecl()); @@ -1842,11 +1844,19 @@ SPFlags |= llvm::DISubprogram::SPFlagDeleted; }; + llvm::DINodeArray AbiTagAnnotations = nullptr; + switch (Method->getKind()) { case Decl::CXXConstructor: case Decl::CXXDestructor: checkAttrDeleted(Method); + + // Add annotations for abi_tag's for constructors/destructors + // because their declarations don't carry linkage names (which + // encodes the existance of abi-tags). LLDB uses these annotations + // to resolve calls to abi-tagged constructors/destructors. + AbiTagAnnotations = CollectAbiTagAnnotations(Method); break; case Decl::CXXMethod: if (Method->isCopyAssignmentOperator() || @@ -1893,7 +1903,7 @@ llvm::DISubprogram *SP = DBuilder.createMethod( RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, MethodTy, VIndex, ThisAdjustment, ContainingType, Flags, SPFlags, - TParamsArray.get()); + TParamsArray.get(), nullptr, AbiTagAnnotations); SPCache[Method->getCanonicalDecl()].reset(SP); @@ -2195,6 +2205,21 @@ return DBuilder.getOrCreateArray(Annotations); } +llvm::DINodeArray CGDebugInfo::CollectAbiTagAnnotations(const Decl *D) { + if (!D->hasAttr<AbiTagAttr>()) + return nullptr; + + SmallVector<llvm::Metadata *, 4> Annotations; + auto const *Attr = D->getAttr<AbiTagAttr>(); + for (const auto Tag : Attr->tags()) { + llvm::Metadata *Ops[2] = { + llvm::MDString::get(CGM.getLLVMContext(), StringRef("abi_tag")), + llvm::MDString::get(CGM.getLLVMContext(), Tag)}; + Annotations.push_back(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); + } + return DBuilder.getOrCreateArray(Annotations); +} + llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { if (VTablePtrType) return VTablePtrType; @@ -4212,6 +4237,8 @@ if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + // No need to collect ABI tags on formal parameters because they + // don't affect name mangling. llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); llvm::DISubroutineType *STy = getOrCreateFunctionType(D, FnType, Unit); llvm::DISubprogram *SP = @@ -4564,6 +4591,7 @@ // Create the descriptor for the variable. llvm::DILocalVariable *D = nullptr; if (ArgNo) { + // TODO: need to collect ABI tags? probably not for parameters llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(VD); D = DBuilder.createParameterVariable(Scope, Name, *ArgNo, Unit, Line, Ty, CGM.getLangOpts().Optimize, Flags,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits