[lldb] [llvm] lldb simplified template names rebuild without clang ast (PR #90008)

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 24 17:51:46 PDT 2024


https://github.com/dwblaikie created https://github.com/llvm/llvm-project/pull/90008

- DO NOT SUBMIT: lldb DWARF-Clang AST parsing tracing
- Fix scope operator ordering
- DO NOT SUBMIT: Really dodgy demonstration of DWARFTypePrinter reuse in lldb


>From 863343317c47602163d75c13b2687601740e8410 Mon Sep 17 00:00:00 2001
From: David Blaikie <dblaikie at gmail.com>
Date: Fri, 19 Apr 2024 03:34:27 +0000
Subject: [PATCH 1/3] DO NOT SUBMIT: lldb DWARF-Clang AST parsing tracing

---
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp        | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 54d06b1115a229..17445e0c3ad17d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include <cstdlib>
+#include <iostream>
 
 #include "DWARFASTParser.h"
 #include "DWARFASTParserClang.h"
@@ -1556,6 +1557,15 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) {
   const char *name = die.GetName();
   if (!name)
     return "";
+  static int indent = 0;
+  std::cerr << std::string(indent, ' ') << "starting qualified name for: " << name << '\n';
+  auto &FS = die.GetCU()->GetSymbolFileDWARF().GetObjectFile()->GetFileSpec();
+  std::string Directory = FS.GetDirectory().AsCString("");
+  std::cerr << std::string(indent, ' ')
+            << Directory.substr(std::min(59ul, Directory.size())) << '/'
+            << FS.GetFilename().AsCString("") << ':' << std::hex
+            << die.GetDIE()->GetOffset() << '\n';
+  ++indent;
   std::string qualified_name;
   DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE();
   // TODO: change this to get the correct decl context parent....
@@ -1601,6 +1611,9 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) {
   qualified_name.append(name);
   qualified_name.append(GetDIEClassTemplateParams(die).AsCString(""));
 
+  --indent;
+  std::cerr << std::string(indent, ' ') << "computed qualified name: " << qualified_name << '\n';
+
   return qualified_name;
 }
 

>From b2926499710b7bf673111aabc5be51597a46493c Mon Sep 17 00:00:00 2001
From: David Blaikie <dblaikie at gmail.com>
Date: Thu, 25 Apr 2024 00:28:57 +0000
Subject: [PATCH 2/3] Fix scope operator ordering

---
 lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 17445e0c3ad17d..ab181b482e4fbc 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -1590,9 +1590,9 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) {
     case DW_TAG_structure_type:
     case DW_TAG_union_type: {
       if (const char *class_union_struct_name = parent_decl_ctx_die.GetName()) {
+        qualified_name.insert(0, "::");
         qualified_name.insert(
             0, GetDIEClassTemplateParams(parent_decl_ctx_die).AsCString(""));
-        qualified_name.insert(0, "::");
         qualified_name.insert(0, class_union_struct_name);
       }
       parent_decl_ctx_die = parent_decl_ctx_die.GetParentDeclContextDIE();

>From 9a654b056d9c05c0aa4856db161c1f1b08b9dfe9 Mon Sep 17 00:00:00 2001
From: David Blaikie <dblaikie at gmail.com>
Date: Thu, 25 Apr 2024 00:46:48 +0000
Subject: [PATCH 3/3] DO NOT SUBMIT: Really dodgy demonstration of
 DWARFTypePrinter reuse in lldb

The hacks necessary to make lldb's DWARFDIE APIs sufficiently compatible
with LLVM's DWARFDie API aren't shippable, but maybe somewhere to start
the conversation.

With all these changes, an internal example that would crash expanding
too many types (computing the fully qualified name for 414671 types before
crashing due to running out of stack) - but with these patches applied,
it comes down to 856 expansions (compared to 848 for non-simplified
template names inputs)
---
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |  11 +
 .../Plugins/SymbolFile/DWARF/DWARFBaseDIE.h   |  10 +
 .../Plugins/SymbolFile/DWARF/DWARFDIE.cpp     |  21 +-
 .../Plugins/SymbolFile/DWARF/DWARFDIE.h       |  13 +
 .../Plugins/SymbolFile/DWARF/DWARFFormValue.h |  37 +
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      |  24 +-
 llvm/include/llvm-c/Error.h                   |   8 +
 llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h  |   2 +
 .../llvm/DebugInfo/DWARF/DWARFFormValue.h     |   7 +-
 .../llvm/DebugInfo/DWARF/DWARFTypePrinter.h   | 734 +++++++++++++++++-
 llvm/lib/DebugInfo/DWARF/DWARFDie.cpp         |   4 +-
 llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp | 674 ----------------
 12 files changed, 830 insertions(+), 715 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index ab181b482e4fbc..962844af286645 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -8,6 +8,7 @@
 
 #include <cstdlib>
 #include <iostream>
+#include <algorithm>
 
 #include "DWARFASTParser.h"
 #include "DWARFASTParserClang.h"
@@ -45,6 +46,8 @@
 #include "clang/AST/Type.h"
 #include "llvm/Demangle/Demangle.h"
 
+#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
+
 #include <map>
 #include <memory>
 #include <optional>
@@ -798,11 +801,19 @@ DWARFASTParserClang::GetDIEClassTemplateParams(const DWARFDIE &die) {
   if (llvm::StringRef(die.GetName()).contains("<"))
     return ConstString();
 
+#if 1
+  std::string R;
+  llvm::raw_string_ostream OS(R);
+  llvm::DWARFTypePrinter<DWARFDIE> p(OS);
+  p.appendAndTerminateTemplateParameters(die);
+  return ConstString(R);
+#else
   TypeSystemClang::TemplateParameterInfos template_param_infos;
   if (ParseTemplateParameterInfos(die, template_param_infos)) {
     return ConstString(m_ast.PrintTemplateParams(template_param_infos));
   }
   return ConstString();
+#endif
 }
 
 TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
index 75c822703cd80e..6a5ef1f83a478c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h
@@ -24,6 +24,7 @@ class DWARFUnit;
 class DWARFDebugInfoEntry;
 class DWARFDeclContext;
 class SymbolFileDWARF;
+class DWARFFormValue;
 
 class DWARFBaseDIE {
 public:
@@ -47,6 +48,8 @@ class DWARFBaseDIE {
 
   bool IsValid() const { return m_cu && m_die; }
 
+  bool isValid() const { return IsValid(); }
+
   bool HasChildren() const;
 
   bool Supports_DW_AT_APPLE_objc_complete_type() const;
@@ -84,6 +87,10 @@ class DWARFBaseDIE {
 
   // Accessing information about a DIE
   dw_tag_t Tag() const;
+  dw_tag_t getTag() const {
+    return Tag();
+  }
+  using DWARFFormValue = dwarf::DWARFFormValue;
 
   const char *GetTagAsCString() const;
 
@@ -96,6 +103,9 @@ class DWARFBaseDIE {
   lldb::user_id_t GetID() const;
 
   const char *GetName() const;
+  const char *getShortName() const {
+    return GetName();
+  }
 
   lldb::ModuleSP GetModule() const;
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
index 4884374ef94729..064c510eea9b09 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
@@ -116,7 +116,13 @@ DWARFDIE::GetReferencedDIE(const dw_attr_t attr) const {
 }
 
 DWARFDIE
-DWARFDIE::GetDIE(dw_offset_t die_offset) const {
+DWARFDIE::getAttributeValueAsReferencedDie(DWARFFormValue value) const {
+  if (IsValid())
+    return value.Reference();
+  return {};
+}
+
+DWARFDIE DWARFDIE::GetDIE(dw_offset_t die_offset) const {
   if (IsValid())
     return m_cu->GetDIE(die_offset);
   else
@@ -522,3 +528,16 @@ bool DWARFDIE::GetDIENamesAndRanges(
 llvm::iterator_range<DWARFDIE::child_iterator> DWARFDIE::children() const {
   return llvm::make_range(child_iterator(*this), child_iterator());
 }
+
+DWARFDIE::child_iterator DWARFDIE::begin() const {
+  return child_iterator(*this);
+}
+DWARFDIE::child_iterator DWARFDIE::end() const {
+  return child_iterator();
+}
+std::optional<DWARFFormValue> DWARFDIE::find(const dw_attr_t attr) const {
+  DWARFFormValue form_value;
+  if (m_die->GetAttributeValue(m_cu, attr, form_value, nullptr, false))
+    return form_value;
+  return std::nullopt;
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
index 511ca62d0197a8..e3e2f725cfdf69 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
@@ -47,6 +47,8 @@ class DWARFDIE : public DWARFBaseDIE {
   DWARFDIE
   GetParent() const;
 
+  DWARFDIE getParent() const { return GetParent(); }
+
   DWARFDIE
   GetFirstChild() const;
 
@@ -56,6 +58,12 @@ class DWARFDIE : public DWARFBaseDIE {
   DWARFDIE
   GetReferencedDIE(const dw_attr_t attr) const;
 
+  DWARFDIE getAttributeValueAsReferencedDie(const dw_attr_t attr) const {
+    return GetReferencedDIE(attr);
+  }
+
+  DWARFDIE getAttributeValueAsReferencedDie(DWARFFormValue) const;
+
   // Get a another DIE from the same DWARF file as this DIE. This will
   // check the current DIE's compile unit first to see if "die_offset" is
   // in the same compile unit, and fall back to checking the DWARF file.
@@ -97,6 +105,8 @@ class DWARFDIE : public DWARFBaseDIE {
   DWARFDIE
   GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const;
 
+  std::optional<DWARFFormValue> find(const dw_attr_t attr) const;
+
   bool GetDIENamesAndRanges(
       const char *&name, const char *&mangled, DWARFRangeList &ranges,
       std::optional<int> &decl_file, std::optional<int> &decl_line,
@@ -106,6 +116,9 @@ class DWARFDIE : public DWARFBaseDIE {
 
   /// The range of all the children of this DIE.
   llvm::iterator_range<child_iterator> children() const;
+
+  child_iterator begin() const;
+  child_iterator end() const;
 };
 
 class DWARFDIE::child_iterator
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
index fdd5b3c278a4e8..42a9b9e8e7f50f 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
@@ -69,6 +69,30 @@ class DWARFFormValue {
   uint64_t Reference(dw_offset_t offset) const;
   bool Boolean() const { return m_value.value.uval != 0; }
   uint64_t Unsigned() const { return m_value.value.uval; }
+  std::optional<uint64_t> getAsUnsignedConstant() const {
+    if ((!IsDataForm(m_form)) || m_form == lldb_private::dwarf::DW_FORM_sdata)
+      return std::nullopt;
+    return m_value.value.uval;
+  }
+  std::optional<int64_t> getAsSignedConstant() const {
+    if ((!IsDataForm(m_form)) ||
+        (m_form == lldb_private::dwarf::DW_FORM_udata &&
+         uint64_t(std::numeric_limits<int64_t>::max()) < m_value.value.uval))
+      return std::nullopt;
+    switch (m_form) {
+    case lldb_private::dwarf::DW_FORM_data4:
+      return int32_t(m_value.value.uval);
+    case lldb_private::dwarf::DW_FORM_data2:
+      return int16_t(m_value.value.uval);
+    case lldb_private::dwarf::DW_FORM_data1:
+      return int8_t(m_value.value.uval);
+    case lldb_private::dwarf::DW_FORM_sdata:
+    case lldb_private::dwarf::DW_FORM_data8:
+    default:
+      return m_value.value.sval;
+    }
+  }
+
   void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; }
   int64_t Signed() const { return m_value.value.sval; }
   void SetSigned(int64_t sval) { m_value.value.sval = sval; }
@@ -93,6 +117,19 @@ class DWARFFormValue {
   dw_form_t m_form = dw_form_t(0);   // Form for this value
   ValueType m_value;                 // Contains all data for the form
 };
+
+inline const char* toString(DWARFFormValue Value, const char* Default) {
+  if (const char* R = Value.AsCString())
+    return R;
+  return Default;
+}
+inline const char* toString(std::optional<DWARFFormValue> Value, const char* Default) {
+  if (!Value)
+    return Default;
+  if (const char* R = Value->AsCString())
+    return R;
+  return Default;
+}
 } // namespace dwarf
 } // namespace lldb_private::plugin
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 49f13d2c89e380..5d20d523345fc1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3203,31 +3203,21 @@ SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) {
             type_dwarf_decl_ctx.GetQualifiedName());
       }
 
-      Type *resolved_type = ResolveType(type_die, false);
-      if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED)
-        return true;
-
       // With -gsimple-template-names, the DIE name may not contain the template
       // parameters. If the declaration has template parameters but doesn't
       // contain '<', check that the child template parameters match.
       if (template_params) {
-        llvm::StringRef test_base_name =
-            GetTypeForDIE(type_die)->GetBaseName().GetStringRef();
-        auto i = test_base_name.find('<');
-
-        // Full name from clang AST doesn't contain '<' so this type_die isn't
-        // a template parameter, but we're expecting template parameters, so
-        // bail.
-        if (i == llvm::StringRef::npos)
-          return true;
-
-        llvm::StringRef test_template_params =
-            test_base_name.slice(i, test_base_name.size());
+        ConstString test_template_params =
+            type_system->GetDWARFParser()->GetDIEClassTemplateParams(type_die);
         // Bail if template parameters don't match.
-        if (test_template_params != template_params.GetStringRef())
+        if (test_template_params != template_params)
           return true;
       }
 
+      Type *resolved_type = ResolveType(type_die, false);
+      if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED)
+        return true;
+
       type_sp = resolved_type->shared_from_this();
       return false;
     });
diff --git a/llvm/include/llvm-c/Error.h b/llvm/include/llvm-c/Error.h
index c3baaf65186aac..81a30133d58352 100644
--- a/llvm/include/llvm-c/Error.h
+++ b/llvm/include/llvm-c/Error.h
@@ -51,6 +51,14 @@ LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err);
  */
 void LLVMConsumeError(LLVMErrorRef Err);
 
+/**
+ * Report a fatal error if Err is a failure value.
+ *
+ * This function can be used to wrap calls to fallible functions ONLY when it
+ * is known that the Error will always be a success value.
+ */
+void LLVMCantFail(LLVMErrorRef Err);
+
 /**
  * Returns the given string's error message. This operation consumes the error,
  * and the given LLVMErrorRef value is not usable once this call returns.
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
index 421b84d644db64..50eabdf6b05111 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
@@ -17,6 +17,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
 #include "llvm/DebugInfo/DWARF/DWARFAttribute.h"
 #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
 #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
 #include <cassert>
 #include <cstdint>
@@ -44,6 +45,7 @@ class DWARFDie {
   const DWARFDebugInfoEntry *Die = nullptr;
 
 public:
+  using DWARFFormValue = llvm::DWARFFormValue;
   DWARFDie() = default;
   DWARFDie(DWARFUnit *Unit, const DWARFDebugInfoEntry *D) : U(Unit), Die(D) {}
 
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
index 2dcd7805b6c96b..88d207d9847776 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h
@@ -168,8 +168,6 @@ class DWARFFormValue {
   void dumpString(raw_ostream &OS) const;
 };
 
-namespace dwarf {
-
 /// Take an optional DWARFFormValue and try to extract a string value from it.
 ///
 /// \param V and optional DWARFFormValue to attempt to extract the value from.
@@ -219,6 +217,11 @@ inline const char *toString(const std::optional<DWARFFormValue> &V,
   return Default;
 }
 
+namespace dwarf {
+
+using llvm::toString;
+using llvm::toStringRef;
+
 /// Take an optional DWARFFormValue and try to extract an unsigned constant.
 ///
 /// \param V and optional DWARFFormValue to attempt to extract the value from.
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
index e05271740e6157..abc0ab8e27976a 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -11,7 +11,6 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Dwarf.h"
-#include "llvm/DebugInfo/DWARF/DWARFDie.h"
 
 #include <string>
 
@@ -21,7 +20,7 @@ class raw_ostream;
 
 // FIXME: We should have pretty printers per language. Currently we print
 // everything as if it was C++ and fall back to the TAG type name.
-struct DWARFTypePrinter {
+template <typename DieType> struct DWARFTypePrinter {
   raw_ostream &OS;
   bool Word = true;
   bool EndedWithTemplate = false;
@@ -31,37 +30,734 @@ struct DWARFTypePrinter {
   /// Dump the name encoded in the type tag.
   void appendTypeTagName(dwarf::Tag T);
 
-  void appendArrayType(const DWARFDie &D);
+  void appendArrayType(const DieType &D);
 
-  DWARFDie skipQualifiers(DWARFDie D);
+  DieType skipQualifiers(DieType D);
 
-  bool needsParens(DWARFDie D);
+  bool needsParens(DieType D);
 
-  void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr);
+  void appendPointerLikeTypeBefore(DieType D, DieType Inner, StringRef Ptr);
 
-  DWARFDie appendUnqualifiedNameBefore(DWARFDie D,
-                                       std::string *OriginalFullName = nullptr);
+  DieType appendUnqualifiedNameBefore(DieType D,
+                                      std::string *OriginalFullName = nullptr);
 
-  void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie Inner,
+  void appendUnqualifiedNameAfter(DieType D, DieType Inner,
                                   bool SkipFirstParamIfArtificial = false);
-  void appendQualifiedName(DWARFDie D);
-  DWARFDie appendQualifiedNameBefore(DWARFDie D);
-  bool appendTemplateParameters(DWARFDie D, bool *FirstParameter = nullptr);
-  void decomposeConstVolatile(DWARFDie &N, DWARFDie &T, DWARFDie &C,
-                              DWARFDie &V);
-  void appendConstVolatileQualifierAfter(DWARFDie N);
-  void appendConstVolatileQualifierBefore(DWARFDie N);
+  void appendQualifiedName(DieType D);
+  DieType appendQualifiedNameBefore(DieType D);
+  bool appendTemplateParameters(DieType D, bool *FirstParameter = nullptr);
+  void appendAndTerminateTemplateParameters(DieType D);
+  void decomposeConstVolatile(DieType &N, DieType &T, DieType &C, DieType &V);
+  void appendConstVolatileQualifierAfter(DieType N);
+  void appendConstVolatileQualifierBefore(DieType N);
 
   /// Recursively append the DIE type name when applicable.
-  void appendUnqualifiedName(DWARFDie D,
+  void appendUnqualifiedName(DieType D,
                              std::string *OriginalFullName = nullptr);
 
-  void appendSubroutineNameAfter(DWARFDie D, DWARFDie Inner,
+  void appendSubroutineNameAfter(DieType D, DieType Inner,
                                  bool SkipFirstParamIfArtificial, bool Const,
                                  bool Volatile);
-  void appendScopes(DWARFDie D);
+  void appendScopes(DieType D);
 };
 
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendTypeTagName(dwarf::Tag T) {
+  StringRef TagStr = TagString(T);
+  static constexpr StringRef Prefix = "dwarf::DW_TAG_";
+  static constexpr StringRef Suffix = "_type";
+  if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix))
+    return;
+  OS << TagStr.substr(Prefix.size(),
+                      TagStr.size() - (Prefix.size() + Suffix.size()))
+     << " ";
+}
+
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendArrayType(const DieType &D) {
+  for (const DieType &C : D.children()) {
+    if (C.getTag() != dwarf::DW_TAG_subrange_type)
+      continue;
+    std::optional<uint64_t> LB;
+    std::optional<uint64_t> Count;
+    std::optional<uint64_t> UB;
+    std::optional<unsigned> DefaultLB;
+    if (std::optional<typename DieType::DWARFFormValue> L = C.find(dwarf::DW_AT_lower_bound))
+      LB = L->getAsUnsignedConstant();
+    if (std::optional<typename DieType::DWARFFormValue> CountV = C.find(dwarf::DW_AT_count))
+      Count = CountV->getAsUnsignedConstant();
+    if (std::optional<typename DieType::DWARFFormValue> UpperV = C.find(dwarf::DW_AT_upper_bound))
+      UB = UpperV->getAsUnsignedConstant();
+    /*
+    if (std::optional<typename DieType::DWARFFormValue> LV =
+            D.getDwarfUnit()->getUnitDIE().find(dwarf::DW_AT_language))
+      if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant())
+        if ((DefaultLB =
+                 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
+          if (LB && *LB == *DefaultLB)
+            LB = std::nullopt;
+            */
+    if (!LB && !Count && !UB)
+      OS << "[]";
+    else if (!LB && (Count || UB) && DefaultLB)
+      OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
+    else {
+      OS << "[[";
+      if (LB)
+        OS << *LB;
+      else
+        OS << '?';
+      OS << ", ";
+      if (Count)
+        if (LB)
+          OS << *LB + *Count;
+        else
+          OS << "? + " << *Count;
+      else if (UB)
+        OS << *UB + 1;
+      else
+        OS << '?';
+      OS << ")]";
+    }
+  }
+  EndedWithTemplate = false;
+}
+
+namespace detail {
+template<typename DieType>
+DieType resolveReferencedType(DieType D,
+                                     dwarf::Attribute Attr = dwarf::DW_AT_type) {
+  return D.getAttributeValueAsReferencedDie(Attr); // .resolveTypeUnitReference();
+}
+template <typename DieType>
+DieType resolveReferencedType(DieType D, typename DieType::DWARFFormValue F) {
+  return D.getAttributeValueAsReferencedDie(F); // .resolveTypeUnitReference();
+}
+} // namespace detail
+
+template <typename DieType>
+DieType DWARFTypePrinter<DieType>::skipQualifiers(DieType D) {
+  while (D && (D.getTag() == dwarf::DW_TAG_const_type ||
+               D.getTag() == dwarf::DW_TAG_volatile_type))
+    D = detail::resolveReferencedType(D);
+  return D;
+}
+
+template <typename DieType>
+bool DWARFTypePrinter<DieType>::needsParens(DieType D) {
+  D = skipQualifiers(D);
+  return D && (D.getTag() == dwarf::DW_TAG_subroutine_type ||
+               D.getTag() == dwarf::DW_TAG_array_type);
+}
+
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendPointerLikeTypeBefore(DieType D,
+                                                            DieType Inner,
+                                                            StringRef Ptr) {
+  appendQualifiedNameBefore(Inner);
+  if (Word)
+    OS << ' ';
+  if (needsParens(Inner))
+    OS << '(';
+  OS << Ptr;
+  Word = false;
+  EndedWithTemplate = false;
+}
+
+template <typename DieType>
+DieType DWARFTypePrinter<DieType>::appendUnqualifiedNameBefore(
+    DieType D, std::string *OriginalFullName) {
+  Word = true;
+  if (!D) {
+    OS << "void";
+    return DieType();
+  }
+  DieType InnerDIE;
+  auto Inner = [&] { return InnerDIE = detail::resolveReferencedType(D); };
+  const dwarf::Tag T = D.getTag();
+  switch (T) {
+  case dwarf::DW_TAG_pointer_type: {
+    appendPointerLikeTypeBefore(D, Inner(), "*");
+    break;
+  }
+  case dwarf::DW_TAG_subroutine_type: {
+    appendQualifiedNameBefore(Inner());
+    if (Word) {
+      OS << ' ';
+    }
+    Word = false;
+    break;
+  }
+  case dwarf::DW_TAG_array_type: {
+    appendQualifiedNameBefore(Inner());
+    break;
+  }
+  case dwarf::DW_TAG_reference_type:
+    appendPointerLikeTypeBefore(D, Inner(), "&");
+    break;
+  case dwarf::DW_TAG_rvalue_reference_type:
+    appendPointerLikeTypeBefore(D, Inner(), "&&");
+    break;
+  case dwarf::DW_TAG_ptr_to_member_type: {
+    appendQualifiedNameBefore(Inner());
+    if (needsParens(InnerDIE))
+      OS << '(';
+    else if (Word)
+      OS << ' ';
+    if (DieType Cont = detail::resolveReferencedType(D, dwarf::DW_AT_containing_type)) {
+      appendQualifiedName(Cont);
+      EndedWithTemplate = false;
+      OS << "::";
+    }
+    OS << "*";
+    Word = false;
+    break;
+  }
+  case dwarf::DW_TAG_LLVM_ptrauth_type:
+    appendQualifiedNameBefore(Inner());
+    break;
+  case dwarf::DW_TAG_const_type:
+  case dwarf::DW_TAG_volatile_type:
+    appendConstVolatileQualifierBefore(D);
+    break;
+  case dwarf::DW_TAG_namespace: {
+    if (const char *Name = toString(D.find(dwarf::DW_AT_name), nullptr))
+      OS << Name;
+    else
+      OS << "(anonymous namespace)";
+    break;
+  }
+  case dwarf::DW_TAG_unspecified_type: {
+    StringRef TypeName = D.getShortName();
+    if (TypeName == "decltype(nullptr)")
+      TypeName = "std::nullptr_t";
+    Word = true;
+    OS << TypeName;
+    EndedWithTemplate = false;
+    break;
+  }
+    /*
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_enumeration_type:
+  case dwarf::DW_TAG_base_type:
+  */
+  default: {
+    const char *NamePtr = toString(D.find(dwarf::DW_AT_name), nullptr);
+    if (!NamePtr) {
+      appendTypeTagName(D.getTag());
+      return DieType();
+    }
+    Word = true;
+    StringRef Name = NamePtr;
+    static constexpr StringRef MangledPrefix = "_STN|";
+    if (Name.consume_front(MangledPrefix)) {
+      auto Separator = Name.find('|');
+      assert(Separator != StringRef::npos);
+      StringRef BaseName = Name.substr(0, Separator);
+      StringRef TemplateArgs = Name.substr(Separator + 1);
+      if (OriginalFullName)
+        *OriginalFullName = (BaseName + TemplateArgs).str();
+      Name = BaseName;
+    } else
+      EndedWithTemplate = Name.ends_with(">");
+    OS << Name;
+    // This check would be insufficient for operator overloads like
+    // "operator>>" - but for now Clang doesn't try to simplify them, so this
+    // is OK. Add more nuanced operator overload handling here if/when needed.
+    if (Name.ends_with(">"))
+      break;
+    appendAndTerminateTemplateParameters(D);
+    break;
+  }
+  }
+  return InnerDIE;
+}
+
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendAndTerminateTemplateParameters(DieType D) {
+  if (!appendTemplateParameters(D))
+    return;
+
+  if (EndedWithTemplate)
+    OS << ' ';
+  OS << '>';
+  EndedWithTemplate = true;
+  Word = true;
+}
+
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendUnqualifiedNameAfter(
+    DieType D, DieType Inner, bool SkipFirstParamIfArtificial) {
+  if (!D)
+    return;
+  switch (D.getTag()) {
+  case dwarf::DW_TAG_subroutine_type: {
+    appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
+                              false);
+    break;
+  }
+  case dwarf::DW_TAG_array_type: {
+    appendArrayType(D);
+    break;
+  }
+  case dwarf::DW_TAG_const_type:
+  case dwarf::DW_TAG_volatile_type:
+    appendConstVolatileQualifierAfter(D);
+    break;
+  case dwarf::DW_TAG_ptr_to_member_type:
+  case dwarf::DW_TAG_reference_type:
+  case dwarf::DW_TAG_rvalue_reference_type:
+  case dwarf::DW_TAG_pointer_type: {
+    if (needsParens(Inner))
+      OS << ')';
+    appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner),
+                               /*SkipFirstParamIfArtificial=*/D.getTag() ==
+                                   dwarf::DW_TAG_ptr_to_member_type);
+    break;
+  }
+  case dwarf::DW_TAG_LLVM_ptrauth_type: {
+    auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
+      if (auto Form = D.find(Attr))
+        return *Form->getAsUnsignedConstant();
+      return 0;
+    };
+    SmallVector<const char *, 2> optionsVec;
+    if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_isa_pointer))
+      optionsVec.push_back("isa-pointer");
+    if (getValOrNull(dwarf::DW_AT_LLVM_ptrauth_authenticates_null_values))
+      optionsVec.push_back("authenticates-null-values");
+    if (auto AuthenticationMode =
+            D.find(dwarf::DW_AT_LLVM_ptrauth_authentication_mode)) {
+      switch (*AuthenticationMode->getAsUnsignedConstant()) {
+      case 0:
+      case 1:
+        optionsVec.push_back("strip");
+        break;
+      case 2:
+        optionsVec.push_back("sign-and-strip");
+        break;
+      default:
+        // Default authentication policy
+        break;
+      }
+    }
+    std::string options;
+    for (const auto *option : optionsVec) {
+      if (options.size())
+        options += ",";
+      options += option;
+    }
+    if (options.size())
+      options = ", \"" + options + "\"";
+    std::string PtrauthString;
+    llvm::raw_string_ostream PtrauthStream(PtrauthString);
+    PtrauthStream
+        << "__ptrauth(" << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_key) << ", "
+        << getValOrNull(dwarf::DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
+        << utohexstr(getValOrNull(dwarf::DW_AT_LLVM_ptrauth_extra_discriminator), true)
+        << options << ")";
+    OS << PtrauthStream.str();
+    break;
+  }
+    /*
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_enumeration_type:
+  case dwarf::DW_TAG_base_type:
+  case dwarf::DW_TAG_namespace:
+  */
+  default:
+    break;
+  }
+}
+
+namespace detail {
+/// Returns True if the DIE TAG is one of the ones that is scopped.
+inline bool scopedTAGs(dwarf::Tag Tag) {
+  switch (Tag) {
+  case dwarf::DW_TAG_structure_type:
+  case dwarf::DW_TAG_class_type:
+  case dwarf::DW_TAG_union_type:
+  case dwarf::DW_TAG_namespace:
+  case dwarf::DW_TAG_enumeration_type:
+    return true;
+  default:
+    break;
+  }
+  return false;
+}
+} // namespace detail
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendQualifiedName(DieType D) {
+  if (D && detail::scopedTAGs(D.getTag()))
+    appendScopes(D.getParent());
+  appendUnqualifiedName(D);
+}
+template <typename DieType>
+DieType DWARFTypePrinter<DieType>::appendQualifiedNameBefore(DieType D) {
+  if (D && detail::scopedTAGs(D.getTag()))
+    appendScopes(D.getParent());
+  return appendUnqualifiedNameBefore(D);
+}
+template <typename DieType>
+bool DWARFTypePrinter<DieType>::appendTemplateParameters(DieType D,
+                                                         bool *FirstParameter) {
+  bool FirstParameterValue = true;
+  bool IsTemplate = false;
+  if (!FirstParameter)
+    FirstParameter = &FirstParameterValue;
+  for (const DieType &C : D) {
+    auto Sep = [&] {
+      if (*FirstParameter)
+        OS << '<';
+      else
+        OS << ", ";
+      IsTemplate = true;
+      EndedWithTemplate = false;
+      *FirstParameter = false;
+    };
+    if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
+      IsTemplate = true;
+      appendTemplateParameters(C, FirstParameter);
+    }
+    if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
+      DieType T = detail::resolveReferencedType(C);
+      Sep();
+      if (T.getTag() == dwarf::DW_TAG_enumeration_type) {
+        OS << '(';
+        appendQualifiedName(T);
+        OS << ')';
+        auto V = C.find(dwarf::DW_AT_const_value);
+        OS << std::to_string(*V->getAsSignedConstant());
+        continue;
+      }
+      // /Maybe/ we could do pointer type parameters, looking for the
+      // symbol in the ELF symbol table to get back to the variable...
+      // but probably not worth it.
+      if (T.getTag() == dwarf::DW_TAG_pointer_type)
+        continue;
+      const char *RawName = toString(T.find(dwarf::DW_AT_name), nullptr);
+      assert(RawName);
+      StringRef Name = RawName;
+      auto V = C.find(dwarf::DW_AT_const_value);
+      bool IsQualifiedChar = false;
+      if (Name == "bool") {
+        OS << (*V->getAsUnsignedConstant() ? "true" : "false");
+      } else if (Name == "short") {
+        OS << "(short)";
+        OS << std::to_string(*V->getAsSignedConstant());
+      } else if (Name == "unsigned short") {
+        OS << "(unsigned short)";
+        OS << std::to_string(*V->getAsSignedConstant());
+      } else if (Name == "int")
+        OS << std::to_string(*V->getAsSignedConstant());
+      else if (Name == "long") {
+        OS << std::to_string(*V->getAsSignedConstant());
+        OS << "L";
+      } else if (Name == "long long") {
+        OS << std::to_string(*V->getAsSignedConstant());
+        OS << "LL";
+      } else if (Name == "unsigned int") {
+        OS << std::to_string(*V->getAsUnsignedConstant());
+        OS << "U";
+      } else if (Name == "unsigned long") {
+        OS << std::to_string(*V->getAsUnsignedConstant());
+        OS << "UL";
+      } else if (Name == "unsigned long long") {
+        OS << std::to_string(*V->getAsUnsignedConstant());
+        OS << "ULL";
+      } else if (Name == "char" ||
+                 (IsQualifiedChar =
+                      (Name == "unsigned char" || Name == "signed char"))) {
+        // FIXME: check T's dwarf::DW_AT_type to see if it's signed or not (since
+        // char signedness is implementation defined).
+        auto Val = *V->getAsSignedConstant();
+        // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
+        // (doesn't actually support different character types/widths, sign
+        // handling's not done, and doesn't correctly test if a character is
+        // printable or needs to use a numeric escape sequence instead)
+        if (IsQualifiedChar) {
+          OS << '(';
+          OS << Name;
+          OS << ')';
+        }
+        switch (Val) {
+        case '\\':
+          OS << "'\\\\'";
+          break;
+        case '\'':
+          OS << "'\\''";
+          break;
+        case '\a':
+          // TODO: K&R: the meaning of '\\a' is different in traditional C
+          OS << "'\\a'";
+          break;
+        case '\b':
+          OS << "'\\b'";
+          break;
+        case '\f':
+          OS << "'\\f'";
+          break;
+        case '\n':
+          OS << "'\\n'";
+          break;
+        case '\r':
+          OS << "'\\r'";
+          break;
+        case '\t':
+          OS << "'\\t'";
+          break;
+        case '\v':
+          OS << "'\\v'";
+          break;
+        default:
+          if ((Val & ~0xFFu) == ~0xFFu)
+            Val &= 0xFFu;
+          if (Val < 127 && Val >= 32) {
+            OS << "'";
+            OS << (char)Val;
+            OS << "'";
+          } else if (Val < 256)
+            OS << llvm::format("'\\x%02" PRIx64 "'", Val);
+          else if (Val <= 0xFFFF)
+            OS << llvm::format("'\\u%04" PRIx64 "'", Val);
+          else
+            OS << llvm::format("'\\U%08" PRIx64 "'", Val);
+        }
+      }
+      continue;
+    }
+    if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
+      const char *RawName =
+          toString(C.find(dwarf::DW_AT_GNU_template_name), nullptr);
+      assert(RawName);
+      StringRef Name = RawName;
+      Sep();
+      OS << Name;
+      continue;
+    }
+    if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
+      continue;
+    auto TypeAttr = C.find(dwarf::DW_AT_type);
+    Sep();
+    appendQualifiedName(TypeAttr ? detail::resolveReferencedType(C, *TypeAttr)
+                                 : DieType());
+  }
+  if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
+    OS << '<';
+    EndedWithTemplate = false;
+  }
+  return IsTemplate;
+}
+template <typename DieType>
+void DWARFTypePrinter<DieType>::decomposeConstVolatile(DieType &N, DieType &T,
+                                                       DieType &C, DieType &V) {
+  (N.getTag() == dwarf::DW_TAG_const_type ? C : V) = N;
+  T = detail::resolveReferencedType(N);
+  if (T) {
+    auto Tag = T.getTag();
+    if (Tag == dwarf::DW_TAG_const_type) {
+      C = T;
+      T = detail::resolveReferencedType(T);
+    } else if (Tag == dwarf::DW_TAG_volatile_type) {
+      V = T;
+      T = detail::resolveReferencedType(T);
+    }
+  }
+}
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendConstVolatileQualifierAfter(DieType N) {
+  DieType C;
+  DieType V;
+  DieType T;
+  decomposeConstVolatile(N, T, C, V);
+  if (T && T.getTag() == dwarf::DW_TAG_subroutine_type)
+    appendSubroutineNameAfter(T, detail::resolveReferencedType(T), false, C.isValid(),
+                              V.isValid());
+  else
+    appendUnqualifiedNameAfter(T, detail::resolveReferencedType(T));
+}
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendConstVolatileQualifierBefore(DieType N) {
+  DieType C;
+  DieType V;
+  DieType T;
+  decomposeConstVolatile(N, T, C, V);
+  bool Subroutine = T && T.getTag() == dwarf::DW_TAG_subroutine_type;
+  DieType A = T;
+  while (A && A.getTag() == dwarf::DW_TAG_array_type)
+    A = detail::resolveReferencedType(A);
+  bool Leading =
+      (!A || (A.getTag() != dwarf::DW_TAG_pointer_type &&
+              A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
+      !Subroutine;
+  if (Leading) {
+    if (C)
+      OS << "const ";
+    if (V)
+      OS << "volatile ";
+  }
+  appendQualifiedNameBefore(T);
+  if (!Leading && !Subroutine) {
+    Word = true;
+    if (C)
+      OS << "const";
+    if (V) {
+      if (C)
+        OS << ' ';
+      OS << "volatile";
+    }
+  }
+}
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendUnqualifiedName(
+    DieType D, std::string *OriginalFullName) {
+  // FIXME: We should have pretty printers per language. Currently we print
+  // everything as if it was C++ and fall back to the TAG type name.
+  DieType Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
+  appendUnqualifiedNameAfter(D, Inner);
+}
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendSubroutineNameAfter(
+    DieType D, DieType Inner, bool SkipFirstParamIfArtificial, bool Const,
+    bool Volatile) {
+  DieType FirstParamIfArtificial;
+  OS << '(';
+  EndedWithTemplate = false;
+  bool First = true;
+  bool RealFirst = true;
+  for (DieType P : D) {
+    if (P.getTag() != dwarf::DW_TAG_formal_parameter &&
+        P.getTag() != dwarf::DW_TAG_unspecified_parameters)
+      return;
+    DieType T = detail::resolveReferencedType(P);
+    if (SkipFirstParamIfArtificial && RealFirst && P.find(dwarf::DW_AT_artificial)) {
+      FirstParamIfArtificial = T;
+      RealFirst = false;
+      continue;
+    }
+    if (!First) {
+      OS << ", ";
+    }
+    First = false;
+    if (P.getTag() == dwarf::DW_TAG_unspecified_parameters)
+      OS << "...";
+    else
+      appendQualifiedName(T);
+  }
+  EndedWithTemplate = false;
+  OS << ')';
+  if (FirstParamIfArtificial) {
+    if (DieType P = FirstParamIfArtificial) {
+      if (P.getTag() == dwarf::DW_TAG_pointer_type) {
+        auto CVStep = [&](DieType CV) {
+          if (DieType U = detail::resolveReferencedType(CV)) {
+            Const |= U.getTag() == dwarf::DW_TAG_const_type;
+            Volatile |= U.getTag() == dwarf::DW_TAG_volatile_type;
+            return U;
+          }
+          return DieType();
+        };
+        if (DieType CV = CVStep(P)) {
+          CVStep(CV);
+        }
+      }
+    }
+  }
+
+  if (auto CC = D.find(dwarf::DW_AT_calling_convention)) {
+    switch (*CC->getAsUnsignedConstant()) {
+    case dwarf::CallingConvention::DW_CC_BORLAND_stdcall:
+      OS << " __attribute__((stdcall))";
+      break;
+    case dwarf::CallingConvention::DW_CC_BORLAND_msfastcall:
+      OS << " __attribute__((fastcall))";
+      break;
+    case dwarf::CallingConvention::DW_CC_BORLAND_thiscall:
+      OS << " __attribute__((thiscall))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_vectorcall:
+      OS << " __attribute__((vectorcall))";
+      break;
+    case dwarf::CallingConvention::DW_CC_BORLAND_pascal:
+      OS << " __attribute__((pascal))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_Win64:
+      OS << " __attribute__((ms_abi))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_X86_64SysV:
+      OS << " __attribute__((sysv_abi))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_AAPCS:
+      // AArch64VectorCall missing?
+      OS << " __attribute__((pcs(\"aapcs\")))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_AAPCS_VFP:
+      OS << " __attribute__((pcs(\"aapcs-vfp\")))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_IntelOclBicc:
+      OS << " __attribute__((intel_ocl_bicc))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_SpirFunction:
+    case dwarf::CallingConvention::DW_CC_LLVM_OpenCLKernel:
+      // These aren't available as attributes, but maybe we should still
+      // render them somehow? (Clang doesn't render them, but that's an issue
+      // for template names too - since then the DWARF names of templates
+      // instantiated with function types with these calling conventions won't
+      // have distinct names - so we'd need to fix that too)
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_Swift:
+      // SwiftAsync missing
+      OS << " __attribute__((swiftcall))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_PreserveMost:
+      OS << " __attribute__((preserve_most))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_PreserveAll:
+      OS << " __attribute__((preserve_all))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_PreserveNone:
+      OS << " __attribute__((preserve_none))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_X86RegCall:
+      OS << " __attribute__((regcall))";
+      break;
+    case dwarf::CallingConvention::DW_CC_LLVM_M68kRTD:
+      OS << " __attribute__((m68k_rtd))";
+      break;
+    }
+  }
+
+  if (Const)
+    OS << " const";
+  if (Volatile)
+    OS << " volatile";
+  if (D.find(dwarf::DW_AT_reference))
+    OS << " &";
+  if (D.find(dwarf::DW_AT_rvalue_reference))
+    OS << " &&";
+
+  appendUnqualifiedNameAfter(Inner, detail::resolveReferencedType(Inner));
+}
+template <typename DieType>
+void DWARFTypePrinter<DieType>::appendScopes(DieType D) {
+  if (D.getTag() == dwarf::DW_TAG_compile_unit)
+    return;
+  if (D.getTag() == dwarf::DW_TAG_type_unit)
+    return;
+  if (D.getTag() == dwarf::DW_TAG_skeleton_unit)
+    return;
+  if (D.getTag() == dwarf::DW_TAG_subprogram)
+    return;
+  if (D.getTag() == dwarf::DW_TAG_lexical_block)
+    return;
+  //D = D.resolveTypeUnitReference();
+  if (DieType P = D.getParent())
+    appendScopes(P);
+  appendUnqualifiedName(D);
+  OS << "::";
+}
 } // namespace llvm
 
 #endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index 410842a80b0151..8686717e9e9006 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -775,12 +775,12 @@ bool DWARFAttribute::mayHaveLocationExpr(dwarf::Attribute Attr) {
 namespace llvm {
 
 void dumpTypeQualifiedName(const DWARFDie &DIE, raw_ostream &OS) {
-  DWARFTypePrinter(OS).appendQualifiedName(DIE);
+  DWARFTypePrinter<DWARFDie>(OS).appendQualifiedName(DIE);
 }
 
 void dumpTypeUnqualifiedName(const DWARFDie &DIE, raw_ostream &OS,
                              std::string *OriginalFullName) {
-  DWARFTypePrinter(OS).appendUnqualifiedName(DIE, OriginalFullName);
+  DWARFTypePrinter<DWARFDie>(OS).appendUnqualifiedName(DIE, OriginalFullName);
 }
 
 } // namespace llvm
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
index 05dee8a3d71298..e69de29bb2d1d6 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
@@ -1,674 +0,0 @@
-#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
-#include "llvm/DebugInfo/DWARF/DWARFDie.h"
-#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
-#include "llvm/Support/ScopedPrinter.h"
-namespace llvm {
-using namespace dwarf;
-void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) {
-  StringRef TagStr = TagString(T);
-  static constexpr StringRef Prefix = "DW_TAG_";
-  static constexpr StringRef Suffix = "_type";
-  if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix))
-    return;
-  OS << TagStr.substr(Prefix.size(),
-                      TagStr.size() - (Prefix.size() + Suffix.size()))
-     << " ";
-}
-
-void DWARFTypePrinter::appendArrayType(const DWARFDie &D) {
-  for (const DWARFDie &C : D.children()) {
-    if (C.getTag() != DW_TAG_subrange_type)
-      continue;
-    std::optional<uint64_t> LB;
-    std::optional<uint64_t> Count;
-    std::optional<uint64_t> UB;
-    std::optional<unsigned> DefaultLB;
-    if (std::optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
-      LB = L->getAsUnsignedConstant();
-    if (std::optional<DWARFFormValue> CountV = C.find(DW_AT_count))
-      Count = CountV->getAsUnsignedConstant();
-    if (std::optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
-      UB = UpperV->getAsUnsignedConstant();
-    if (std::optional<DWARFFormValue> LV =
-            D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
-      if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant())
-        if ((DefaultLB =
-                 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
-          if (LB && *LB == *DefaultLB)
-            LB = std::nullopt;
-    if (!LB && !Count && !UB)
-      OS << "[]";
-    else if (!LB && (Count || UB) && DefaultLB)
-      OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
-    else {
-      OS << "[[";
-      if (LB)
-        OS << *LB;
-      else
-        OS << '?';
-      OS << ", ";
-      if (Count)
-        if (LB)
-          OS << *LB + *Count;
-        else
-          OS << "? + " << *Count;
-      else if (UB)
-        OS << *UB + 1;
-      else
-        OS << '?';
-      OS << ")]";
-    }
-  }
-  EndedWithTemplate = false;
-}
-
-static DWARFDie resolveReferencedType(DWARFDie D,
-                                      dwarf::Attribute Attr = DW_AT_type) {
-  return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
-}
-static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
-  return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
-}
-DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) {
-  while (D && (D.getTag() == DW_TAG_const_type ||
-               D.getTag() == DW_TAG_volatile_type))
-    D = resolveReferencedType(D);
-  return D;
-}
-
-bool DWARFTypePrinter::needsParens(DWARFDie D) {
-  D = skipQualifiers(D);
-  return D && (D.getTag() == DW_TAG_subroutine_type ||
-               D.getTag() == DW_TAG_array_type);
-}
-
-void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner,
-                                                   StringRef Ptr) {
-  appendQualifiedNameBefore(Inner);
-  if (Word)
-    OS << ' ';
-  if (needsParens(Inner))
-    OS << '(';
-  OS << Ptr;
-  Word = false;
-  EndedWithTemplate = false;
-}
-
-DWARFDie
-DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
-                                              std::string *OriginalFullName) {
-  Word = true;
-  if (!D) {
-    OS << "void";
-    return DWARFDie();
-  }
-  DWARFDie InnerDIE;
-  auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
-  const dwarf::Tag T = D.getTag();
-  switch (T) {
-  case DW_TAG_pointer_type: {
-    appendPointerLikeTypeBefore(D, Inner(), "*");
-    break;
-  }
-  case DW_TAG_subroutine_type: {
-    appendQualifiedNameBefore(Inner());
-    if (Word) {
-      OS << ' ';
-    }
-    Word = false;
-    break;
-  }
-  case DW_TAG_array_type: {
-    appendQualifiedNameBefore(Inner());
-    break;
-  }
-  case DW_TAG_reference_type:
-    appendPointerLikeTypeBefore(D, Inner(), "&");
-    break;
-  case DW_TAG_rvalue_reference_type:
-    appendPointerLikeTypeBefore(D, Inner(), "&&");
-    break;
-  case DW_TAG_ptr_to_member_type: {
-    appendQualifiedNameBefore(Inner());
-    if (needsParens(InnerDIE))
-      OS << '(';
-    else if (Word)
-      OS << ' ';
-    if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
-      appendQualifiedName(Cont);
-      EndedWithTemplate = false;
-      OS << "::";
-    }
-    OS << "*";
-    Word = false;
-    break;
-  }
-  case DW_TAG_LLVM_ptrauth_type:
-    appendQualifiedNameBefore(Inner());
-    break;
-  case DW_TAG_const_type:
-  case DW_TAG_volatile_type:
-    appendConstVolatileQualifierBefore(D);
-    break;
-  case DW_TAG_namespace: {
-    if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
-      OS << Name;
-    else
-      OS << "(anonymous namespace)";
-    break;
-  }
-  case DW_TAG_unspecified_type: {
-    StringRef TypeName = D.getShortName();
-    if (TypeName == "decltype(nullptr)")
-      TypeName = "std::nullptr_t";
-    Word = true;
-    OS << TypeName;
-    EndedWithTemplate = false;
-    break;
-  }
-    /*
-  case DW_TAG_structure_type:
-  case DW_TAG_class_type:
-  case DW_TAG_enumeration_type:
-  case DW_TAG_base_type:
-  */
-  default: {
-    const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
-    if (!NamePtr) {
-      appendTypeTagName(D.getTag());
-      return DWARFDie();
-    }
-    Word = true;
-    StringRef Name = NamePtr;
-    static constexpr StringRef MangledPrefix = "_STN|";
-    if (Name.consume_front(MangledPrefix)) {
-      auto Separator = Name.find('|');
-      assert(Separator != StringRef::npos);
-      StringRef BaseName = Name.substr(0, Separator);
-      StringRef TemplateArgs = Name.substr(Separator + 1);
-      if (OriginalFullName)
-        *OriginalFullName = (BaseName + TemplateArgs).str();
-      Name = BaseName;
-    } else
-      EndedWithTemplate = Name.ends_with(">");
-    OS << Name;
-    // This check would be insufficient for operator overloads like
-    // "operator>>" - but for now Clang doesn't try to simplify them, so this
-    // is OK. Add more nuanced operator overload handling here if/when needed.
-    if (Name.ends_with(">"))
-      break;
-    if (!appendTemplateParameters(D))
-      break;
-
-    if (EndedWithTemplate)
-      OS << ' ';
-    OS << '>';
-    EndedWithTemplate = true;
-    Word = true;
-    break;
-  }
-  }
-  return InnerDIE;
-}
-
-void DWARFTypePrinter::appendUnqualifiedNameAfter(
-    DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
-  if (!D)
-    return;
-  switch (D.getTag()) {
-  case DW_TAG_subroutine_type: {
-    appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
-                              false);
-    break;
-  }
-  case DW_TAG_array_type: {
-    appendArrayType(D);
-    break;
-  }
-  case DW_TAG_const_type:
-  case DW_TAG_volatile_type:
-    appendConstVolatileQualifierAfter(D);
-    break;
-  case DW_TAG_ptr_to_member_type:
-  case DW_TAG_reference_type:
-  case DW_TAG_rvalue_reference_type:
-  case DW_TAG_pointer_type: {
-    if (needsParens(Inner))
-      OS << ')';
-    appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
-                               /*SkipFirstParamIfArtificial=*/D.getTag() ==
-                                   DW_TAG_ptr_to_member_type);
-    break;
-  }
-  case DW_TAG_LLVM_ptrauth_type: {
-    auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
-      if (auto Form = D.find(Attr))
-        return *Form->getAsUnsignedConstant();
-      return 0;
-    };
-    SmallVector<const char *, 2> optionsVec;
-    if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer))
-      optionsVec.push_back("isa-pointer");
-    if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values))
-      optionsVec.push_back("authenticates-null-values");
-    if (auto AuthenticationMode =
-            D.find(DW_AT_LLVM_ptrauth_authentication_mode)) {
-      switch (*AuthenticationMode->getAsUnsignedConstant()) {
-      case 0:
-      case 1:
-        optionsVec.push_back("strip");
-        break;
-      case 2:
-        optionsVec.push_back("sign-and-strip");
-        break;
-      default:
-        // Default authentication policy
-        break;
-      }
-    }
-    std::string options;
-    for (const auto *option : optionsVec) {
-      if (options.size())
-        options += ",";
-      options += option;
-    }
-    if (options.size())
-      options = ", \"" + options + "\"";
-    std::string PtrauthString;
-    llvm::raw_string_ostream PtrauthStream(PtrauthString);
-    PtrauthStream
-        << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", "
-        << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
-        << utohexstr(getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), true)
-        << options << ")";
-    OS << PtrauthStream.str();
-    break;
-  }
-    /*
-  case DW_TAG_structure_type:
-  case DW_TAG_class_type:
-  case DW_TAG_enumeration_type:
-  case DW_TAG_base_type:
-  case DW_TAG_namespace:
-  */
-  default:
-    break;
-  }
-}
-
-/// Returns True if the DIE TAG is one of the ones that is scopped.
-static bool scopedTAGs(dwarf::Tag Tag) {
-  switch (Tag) {
-  case dwarf::DW_TAG_structure_type:
-  case dwarf::DW_TAG_class_type:
-  case dwarf::DW_TAG_union_type:
-  case dwarf::DW_TAG_namespace:
-  case dwarf::DW_TAG_enumeration_type:
-    return true;
-  default:
-    break;
-  }
-  return false;
-}
-void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
-  if (D && scopedTAGs(D.getTag()))
-    appendScopes(D.getParent());
-  appendUnqualifiedName(D);
-}
-DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
-  if (D && scopedTAGs(D.getTag()))
-    appendScopes(D.getParent());
-  return appendUnqualifiedNameBefore(D);
-}
-bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
-                                                bool *FirstParameter) {
-  bool FirstParameterValue = true;
-  bool IsTemplate = false;
-  if (!FirstParameter)
-    FirstParameter = &FirstParameterValue;
-  for (const DWARFDie &C : D) {
-    auto Sep = [&] {
-      if (*FirstParameter)
-        OS << '<';
-      else
-        OS << ", ";
-      IsTemplate = true;
-      EndedWithTemplate = false;
-      *FirstParameter = false;
-    };
-    if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
-      IsTemplate = true;
-      appendTemplateParameters(C, FirstParameter);
-    }
-    if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
-      DWARFDie T = resolveReferencedType(C);
-      Sep();
-      if (T.getTag() == DW_TAG_enumeration_type) {
-        OS << '(';
-        appendQualifiedName(T);
-        OS << ')';
-        auto V = C.find(DW_AT_const_value);
-        OS << std::to_string(*V->getAsSignedConstant());
-        continue;
-      }
-      // /Maybe/ we could do pointer type parameters, looking for the
-      // symbol in the ELF symbol table to get back to the variable...
-      // but probably not worth it.
-      if (T.getTag() == DW_TAG_pointer_type)
-        continue;
-      const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
-      assert(RawName);
-      StringRef Name = RawName;
-      auto V = C.find(DW_AT_const_value);
-      bool IsQualifiedChar = false;
-      if (Name == "bool") {
-        OS << (*V->getAsUnsignedConstant() ? "true" : "false");
-      } else if (Name == "short") {
-        OS << "(short)";
-        OS << std::to_string(*V->getAsSignedConstant());
-      } else if (Name == "unsigned short") {
-        OS << "(unsigned short)";
-        OS << std::to_string(*V->getAsSignedConstant());
-      } else if (Name == "int")
-        OS << std::to_string(*V->getAsSignedConstant());
-      else if (Name == "long") {
-        OS << std::to_string(*V->getAsSignedConstant());
-        OS << "L";
-      } else if (Name == "long long") {
-        OS << std::to_string(*V->getAsSignedConstant());
-        OS << "LL";
-      } else if (Name == "unsigned int") {
-        OS << std::to_string(*V->getAsUnsignedConstant());
-        OS << "U";
-      } else if (Name == "unsigned long") {
-        OS << std::to_string(*V->getAsUnsignedConstant());
-        OS << "UL";
-      } else if (Name == "unsigned long long") {
-        OS << std::to_string(*V->getAsUnsignedConstant());
-        OS << "ULL";
-      } else if (Name == "char" ||
-                 (IsQualifiedChar =
-                      (Name == "unsigned char" || Name == "signed char"))) {
-        // FIXME: check T's DW_AT_type to see if it's signed or not (since
-        // char signedness is implementation defined).
-        auto Val = *V->getAsSignedConstant();
-        // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
-        // (doesn't actually support different character types/widths, sign
-        // handling's not done, and doesn't correctly test if a character is
-        // printable or needs to use a numeric escape sequence instead)
-        if (IsQualifiedChar) {
-          OS << '(';
-          OS << Name;
-          OS << ')';
-        }
-        switch (Val) {
-        case '\\':
-          OS << "'\\\\'";
-          break;
-        case '\'':
-          OS << "'\\''";
-          break;
-        case '\a':
-          // TODO: K&R: the meaning of '\\a' is different in traditional C
-          OS << "'\\a'";
-          break;
-        case '\b':
-          OS << "'\\b'";
-          break;
-        case '\f':
-          OS << "'\\f'";
-          break;
-        case '\n':
-          OS << "'\\n'";
-          break;
-        case '\r':
-          OS << "'\\r'";
-          break;
-        case '\t':
-          OS << "'\\t'";
-          break;
-        case '\v':
-          OS << "'\\v'";
-          break;
-        default:
-          if ((Val & ~0xFFu) == ~0xFFu)
-            Val &= 0xFFu;
-          if (Val < 127 && Val >= 32) {
-            OS << "'";
-            OS << (char)Val;
-            OS << "'";
-          } else if (Val < 256)
-            OS << llvm::format("'\\x%02" PRIx64 "'", Val);
-          else if (Val <= 0xFFFF)
-            OS << llvm::format("'\\u%04" PRIx64 "'", Val);
-          else
-            OS << llvm::format("'\\U%08" PRIx64 "'", Val);
-        }
-      }
-      continue;
-    }
-    if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
-      const char *RawName =
-          dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
-      assert(RawName);
-      StringRef Name = RawName;
-      Sep();
-      OS << Name;
-      continue;
-    }
-    if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
-      continue;
-    auto TypeAttr = C.find(DW_AT_type);
-    Sep();
-    appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
-                                 : DWARFDie());
-  }
-  if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
-    OS << '<';
-    EndedWithTemplate = false;
-  }
-  return IsTemplate;
-}
-void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
-                                              DWARFDie &C, DWARFDie &V) {
-  (N.getTag() == DW_TAG_const_type ? C : V) = N;
-  T = resolveReferencedType(N);
-  if (T) {
-    auto Tag = T.getTag();
-    if (Tag == DW_TAG_const_type) {
-      C = T;
-      T = resolveReferencedType(T);
-    } else if (Tag == DW_TAG_volatile_type) {
-      V = T;
-      T = resolveReferencedType(T);
-    }
-  }
-}
-void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
-  DWARFDie C;
-  DWARFDie V;
-  DWARFDie T;
-  decomposeConstVolatile(N, T, C, V);
-  if (T && T.getTag() == DW_TAG_subroutine_type)
-    appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
-                              V.isValid());
-  else
-    appendUnqualifiedNameAfter(T, resolveReferencedType(T));
-}
-void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
-  DWARFDie C;
-  DWARFDie V;
-  DWARFDie T;
-  decomposeConstVolatile(N, T, C, V);
-  bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
-  DWARFDie A = T;
-  while (A && A.getTag() == DW_TAG_array_type)
-    A = resolveReferencedType(A);
-  bool Leading =
-      (!A || (A.getTag() != DW_TAG_pointer_type &&
-              A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
-      !Subroutine;
-  if (Leading) {
-    if (C)
-      OS << "const ";
-    if (V)
-      OS << "volatile ";
-  }
-  appendQualifiedNameBefore(T);
-  if (!Leading && !Subroutine) {
-    Word = true;
-    if (C)
-      OS << "const";
-    if (V) {
-      if (C)
-        OS << ' ';
-      OS << "volatile";
-    }
-  }
-}
-void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
-                                             std::string *OriginalFullName) {
-  // FIXME: We should have pretty printers per language. Currently we print
-  // everything as if it was C++ and fall back to the TAG type name.
-  DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
-  appendUnqualifiedNameAfter(D, Inner);
-}
-void DWARFTypePrinter::appendSubroutineNameAfter(
-    DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
-    bool Volatile) {
-  DWARFDie FirstParamIfArtificial;
-  OS << '(';
-  EndedWithTemplate = false;
-  bool First = true;
-  bool RealFirst = true;
-  for (DWARFDie P : D) {
-    if (P.getTag() != DW_TAG_formal_parameter &&
-        P.getTag() != DW_TAG_unspecified_parameters)
-      return;
-    DWARFDie T = resolveReferencedType(P);
-    if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
-      FirstParamIfArtificial = T;
-      RealFirst = false;
-      continue;
-    }
-    if (!First) {
-      OS << ", ";
-    }
-    First = false;
-    if (P.getTag() == DW_TAG_unspecified_parameters)
-      OS << "...";
-    else
-      appendQualifiedName(T);
-  }
-  EndedWithTemplate = false;
-  OS << ')';
-  if (FirstParamIfArtificial) {
-    if (DWARFDie P = FirstParamIfArtificial) {
-      if (P.getTag() == DW_TAG_pointer_type) {
-        auto CVStep = [&](DWARFDie CV) {
-          if (DWARFDie U = resolveReferencedType(CV)) {
-            Const |= U.getTag() == DW_TAG_const_type;
-            Volatile |= U.getTag() == DW_TAG_volatile_type;
-            return U;
-          }
-          return DWARFDie();
-        };
-        if (DWARFDie CV = CVStep(P)) {
-          CVStep(CV);
-        }
-      }
-    }
-  }
-
-  if (auto CC = D.find(DW_AT_calling_convention)) {
-    switch (*CC->getAsUnsignedConstant()) {
-    case CallingConvention::DW_CC_BORLAND_stdcall:
-      OS << " __attribute__((stdcall))";
-      break;
-    case CallingConvention::DW_CC_BORLAND_msfastcall:
-      OS << " __attribute__((fastcall))";
-      break;
-    case CallingConvention::DW_CC_BORLAND_thiscall:
-      OS << " __attribute__((thiscall))";
-      break;
-    case CallingConvention::DW_CC_LLVM_vectorcall:
-      OS << " __attribute__((vectorcall))";
-      break;
-    case CallingConvention::DW_CC_BORLAND_pascal:
-      OS << " __attribute__((pascal))";
-      break;
-    case CallingConvention::DW_CC_LLVM_Win64:
-      OS << " __attribute__((ms_abi))";
-      break;
-    case CallingConvention::DW_CC_LLVM_X86_64SysV:
-      OS << " __attribute__((sysv_abi))";
-      break;
-    case CallingConvention::DW_CC_LLVM_AAPCS:
-      // AArch64VectorCall missing?
-      OS << " __attribute__((pcs(\"aapcs\")))";
-      break;
-    case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
-      OS << " __attribute__((pcs(\"aapcs-vfp\")))";
-      break;
-    case CallingConvention::DW_CC_LLVM_IntelOclBicc:
-      OS << " __attribute__((intel_ocl_bicc))";
-      break;
-    case CallingConvention::DW_CC_LLVM_SpirFunction:
-    case CallingConvention::DW_CC_LLVM_OpenCLKernel:
-      // These aren't available as attributes, but maybe we should still
-      // render them somehow? (Clang doesn't render them, but that's an issue
-      // for template names too - since then the DWARF names of templates
-      // instantiated with function types with these calling conventions won't
-      // have distinct names - so we'd need to fix that too)
-      break;
-    case CallingConvention::DW_CC_LLVM_Swift:
-      // SwiftAsync missing
-      OS << " __attribute__((swiftcall))";
-      break;
-    case CallingConvention::DW_CC_LLVM_PreserveMost:
-      OS << " __attribute__((preserve_most))";
-      break;
-    case CallingConvention::DW_CC_LLVM_PreserveAll:
-      OS << " __attribute__((preserve_all))";
-      break;
-    case CallingConvention::DW_CC_LLVM_PreserveNone:
-      OS << " __attribute__((preserve_none))";
-      break;
-    case CallingConvention::DW_CC_LLVM_X86RegCall:
-      OS << " __attribute__((regcall))";
-      break;
-    case CallingConvention::DW_CC_LLVM_M68kRTD:
-      OS << " __attribute__((m68k_rtd))";
-      break;
-    }
-  }
-
-  if (Const)
-    OS << " const";
-  if (Volatile)
-    OS << " volatile";
-  if (D.find(DW_AT_reference))
-    OS << " &";
-  if (D.find(DW_AT_rvalue_reference))
-    OS << " &&";
-
-  appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
-}
-void DWARFTypePrinter::appendScopes(DWARFDie D) {
-  if (D.getTag() == DW_TAG_compile_unit)
-    return;
-  if (D.getTag() == DW_TAG_type_unit)
-    return;
-  if (D.getTag() == DW_TAG_skeleton_unit)
-    return;
-  if (D.getTag() == DW_TAG_subprogram)
-    return;
-  if (D.getTag() == DW_TAG_lexical_block)
-    return;
-  D = D.resolveTypeUnitReference();
-  if (DWARFDie P = D.getParent())
-    appendScopes(P);
-  appendUnqualifiedName(D);
-  OS << "::";
-}
-} // namespace llvm



More information about the llvm-commits mailing list