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

Reply via email to