[llvm] 61fac2c - Incomplete attempt to pull DWARFTypePrinter into its own file for reuse

David Blaikie via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 16 15:29:01 PDT 2022


Author: David Blaikie
Date: 2022-06-16T22:28:28Z
New Revision: 61fac2c370b92cb77e6441abe2237e7112cd1a9a

URL: https://github.com/llvm/llvm-project/commit/61fac2c370b92cb77e6441abe2237e7112cd1a9a
DIFF: https://github.com/llvm/llvm-project/commit/61fac2c370b92cb77e6441abe2237e7112cd1a9a.diff

LOG: Incomplete attempt to pull DWARFTypePrinter into its own file for reuse
from lldb

Added: 
    llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
    llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp

Modified: 
    llvm/lib/DebugInfo/DWARF/CMakeLists.txt
    llvm/lib/DebugInfo/DWARF/DWARFDie.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
new file mode 100644
index 0000000000000..e05271740e615
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFTypePrinter.h
@@ -0,0 +1,67 @@
+//===- DWARFTypePrinter.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
+#define LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+
+#include <string>
+
+namespace llvm {
+
+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 {
+  raw_ostream &OS;
+  bool Word = true;
+  bool EndedWithTemplate = false;
+
+  DWARFTypePrinter(raw_ostream &OS) : OS(OS) {}
+
+  /// Dump the name encoded in the type tag.
+  void appendTypeTagName(dwarf::Tag T);
+
+  void appendArrayType(const DWARFDie &D);
+
+  DWARFDie skipQualifiers(DWARFDie D);
+
+  bool needsParens(DWARFDie D);
+
+  void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr);
+
+  DWARFDie appendUnqualifiedNameBefore(DWARFDie D,
+                                       std::string *OriginalFullName = nullptr);
+
+  void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie 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);
+
+  /// Recursively append the DIE type name when applicable.
+  void appendUnqualifiedName(DWARFDie D,
+                             std::string *OriginalFullName = nullptr);
+
+  void appendSubroutineNameAfter(DWARFDie D, DWARFDie Inner,
+                                 bool SkipFirstParamIfArtificial, bool Const,
+                                 bool Volatile);
+  void appendScopes(DWARFDie D);
+};
+
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_DWARF_DWARFTYPEPRINTER_H

diff  --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
index 4bcc0d5ad513a..5ff72add9faf9 100644
--- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt
@@ -10,6 +10,7 @@ add_llvm_component_library(LLVMDebugInfoDWARF
   DWARFDebugArangeSet.cpp
   DWARFDebugAranges.cpp
   DWARFDebugFrame.cpp
+  DWARFTypePrinter.cpp
   DWARFDebugInfoEntry.cpp
   DWARFDebugLine.cpp
   DWARFDebugLoc.cpp

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index b375fc5ecbe07..9bbe09fccfe69 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -18,6 +18,7 @@
 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
 #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
 #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
 #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
 #include "llvm/Object/ObjectFile.h"
@@ -107,623 +108,10 @@ static void dumpLocationExpr(raw_ostream &OS, const DWARFFormValue &FormValue,
       .print(OS, DumpOpts, MRI, U);
 }
 
-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();
 }
 
-namespace {
-
-// 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 {
-  raw_ostream &OS;
-  bool Word = true;
-  bool EndedWithTemplate = false;
-
-  DWARFTypePrinter(raw_ostream &OS) : OS(OS) {}
-
-  /// Dump the name encoded in the type tag.
-  void appendTypeTagName(dwarf::Tag T) {
-    StringRef TagStr = TagString(T);
-    static constexpr StringRef Prefix = "DW_TAG_";
-    static constexpr StringRef Suffix = "_type";
-    if (!TagStr.startswith(Prefix) || !TagStr.endswith(Suffix))
-      return;
-    OS << TagStr.substr(Prefix.size(),
-                        TagStr.size() - (Prefix.size() + Suffix.size()))
-       << " ";
-  }
-
-  void appendArrayType(const DWARFDie &D) {
-    for (const DWARFDie &C : D.children()) {
-      if (C.getTag() != DW_TAG_subrange_type)
-        continue;
-      Optional<uint64_t> LB;
-      Optional<uint64_t> Count;
-      Optional<uint64_t> UB;
-      Optional<unsigned> DefaultLB;
-      if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
-        LB = L->getAsUnsignedConstant();
-      if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
-        Count = CountV->getAsUnsignedConstant();
-      if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
-        UB = UpperV->getAsUnsignedConstant();
-      if (Optional<DWARFFormValue> LV =
-              D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
-        if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
-          if ((DefaultLB =
-                   LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
-            if (LB && *LB == *DefaultLB)
-              LB = None;
-      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;
-  }
-
-  DWARFDie skipQualifiers(DWARFDie D) {
-    while (D && (D.getTag() == DW_TAG_const_type ||
-                 D.getTag() == DW_TAG_volatile_type))
-      D = resolveReferencedType(D);
-    return D;
-  }
-
-  bool needsParens(DWARFDie D) {
-    D = skipQualifiers(D);
-    return D && (D.getTag() == DW_TAG_subroutine_type || D.getTag() == DW_TAG_array_type);
-  }
-
-  void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr) {
-    appendQualifiedNameBefore(Inner);
-    if (Word)
-      OS << ' ';
-    if (needsParens(Inner))
-      OS << '(';
-    OS << Ptr;
-    Word = false;
-    EndedWithTemplate = false;
-  }
-
-  DWARFDie
-  appendUnqualifiedNameBefore(DWARFDie D,
-                              std::string *OriginalFullName = nullptr) {
-    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_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.startswith(MangledPrefix)) {
-        Name = Name.drop_front(MangledPrefix.size());
-        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.endswith(">");
-      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.endswith(">"))
-        break;
-      if (!appendTemplateParameters(D))
-        break;
-
-      if (EndedWithTemplate)
-        OS << ' ';
-      OS << '>';
-      EndedWithTemplate = true;
-      Word = true;
-      break;
-    }
-    }
-    return InnerDIE;
-  }
-
-  void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie Inner,
-                                  bool SkipFirstParamIfArtificial = false) {
-    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_structure_type:
-    case DW_TAG_class_type:
-    case DW_TAG_enumeration_type:
-    case DW_TAG_base_type:
-    case DW_TAG_namespace:
-    */
-    default:
-      break;
-    }
-  }
-
-  void appendQualifiedName(DWARFDie D) {
-    if (D)
-      appendScopes(D.getParent());
-    appendUnqualifiedName(D);
-  }
-  DWARFDie appendQualifiedNameBefore(DWARFDie D) {
-    if (D)
-      appendScopes(D.getParent());
-    return appendUnqualifiedNameBefore(D);
-  }
-  bool appendTemplateParameters(DWARFDie D, bool *FirstParameter = nullptr) {
-    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 << 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 << to_string(*V->getAsSignedConstant());
-        } else if (Name == "unsigned short") {
-          OS << "(unsigned short)";
-          OS << to_string(*V->getAsSignedConstant());
-        } else if (Name == "int")
-          OS << to_string(*V->getAsSignedConstant());
-        else if (Name == "long") {
-          OS << to_string(*V->getAsSignedConstant());
-          OS << "L";
-        } else if (Name == "long long") {
-          OS << to_string(*V->getAsSignedConstant());
-          OS << "LL";
-        } else if (Name == "unsigned int") {
-          OS << to_string(*V->getAsUnsignedConstant());
-          OS << "U";
-        } else if (Name == "unsigned long") {
-          OS << to_string(*V->getAsUnsignedConstant());
-          OS << "UL";
-        } else if (Name == "unsigned long long") {
-          OS << 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 
diff erent 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 
diff erent 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 << to_string(llvm::format("'\\x%02x'", Val));
-            else if (Val <= 0xFFFF)
-              OS << to_string(llvm::format("'\\u%04x'", Val));
-            else
-              OS << to_string(llvm::format("'\\U%08x'", 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 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 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 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";
-      }
-    }
-  }
-
-  /// Recursively append the DIE type name when applicable.
-  void appendUnqualifiedName(DWARFDie D,
-                             std::string *OriginalFullName = nullptr) {
-    // 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 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_X86RegCall:
-        OS << " __attribute__((regcall))";
-        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 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 << "::";
-  }
-};
-} // anonymous namespace
-
 static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
                           const DWARFAttribute &AttrValue, unsigned Indent,
                           DIDumpOptions DumpOpts) {

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
new file mode 100644
index 0000000000000..86cc07b0d0f29
--- /dev/null
+++ b/llvm/lib/DebugInfo/DWARF/DWARFTypePrinter.cpp
@@ -0,0 +1,608 @@
+#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.startswith(Prefix) || !TagStr.endswith(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;
+    Optional<uint64_t> LB;
+    Optional<uint64_t> Count;
+    Optional<uint64_t> UB;
+    Optional<unsigned> DefaultLB;
+    if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
+      LB = L->getAsUnsignedConstant();
+    if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
+      Count = CountV->getAsUnsignedConstant();
+    if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
+      UB = UpperV->getAsUnsignedConstant();
+    if (Optional<DWARFFormValue> LV =
+            D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
+      if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
+        if ((DefaultLB =
+                 LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
+          if (LB && *LB == *DefaultLB)
+            LB = None;
+    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_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.startswith(MangledPrefix)) {
+      Name = Name.drop_front(MangledPrefix.size());
+      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.endswith(">");
+    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.endswith(">"))
+      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_structure_type:
+  case DW_TAG_class_type:
+  case DW_TAG_enumeration_type:
+  case DW_TAG_base_type:
+  case DW_TAG_namespace:
+  */
+  default:
+    break;
+  }
+}
+
+void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
+  if (D)
+    appendScopes(D.getParent());
+  appendUnqualifiedName(D);
+}
+DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
+  if (D)
+    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 
diff erent 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 
diff erent 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 << to_string(llvm::format("'\\x%02x'", Val));
+          else if (Val <= 0xFFFF)
+            OS << to_string(llvm::format("'\\u%04x'", Val));
+          else
+            OS << to_string(llvm::format("'\\U%08x'", 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_X86RegCall:
+      OS << " __attribute__((regcall))";
+      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