[flang-commits] [flang] [llvm] [mlir] Add DW_AT_type attribute to DW_TAG_string_type DWARF DIEs (PR #215365)

via flang-commits flang-commits at lists.llvm.org
Mon Aug 10 11:49:02 PDT 2026


https://github.com/timsmith78 created https://github.com/llvm/llvm-project/pull/215365

The DWARF spec allows for the DW_TAG_string_type DIE to contain a DW_AT_type attribute which can be helpful for supporting non-ASCII character types in a debugger.  This requires adding a DIType member to DIStringType in the FIR and LLVM layers which is then propagated to the DWARF generator in the backend. (Issue #95440)

Co-authored with Claude Opus 4.6

>From 71fbdf0c6339451a9856436b7bdccc58f699d014 Mon Sep 17 00:00:00 2001
From: Timothy Smith <timothy.smith at hpe.com>
Date: Fri, 7 Aug 2026 14:36:34 -0500
Subject: [PATCH] Add DW_AT_type attribute to DW_TAG_string_type DWARF DIEs

The DWARF spec allows for the DW_TAG_string_type DIE to contain a
DW_AT_type attribute which can be helpful for supporting non-ASCII
character types in a debugger.  This requires adding a DIType member
to DIStringType in the FIR and LLVM layers which is then propagated to
the DWARF generator in the backend. (Issue #95440)

Co-authored with Claude Opus 4.6
---
 .../Transforms/DebugTypeGenerator.cpp         |  9 ++++-
 flang/test/Integration/debug-char-type-1.f90  | 10 +++--
 flang/test/Transforms/debug-107988.fir        |  2 +-
 flang/test/Transforms/debug-char-type-1.fir   |  6 +--
 flang/test/Transforms/debug-char-type-2.fir   |  2 +-
 .../Transforms/debug-variable-char-len.fir    |  2 +-
 llvm/include/llvm/IR/DebugInfoMetadata.h      | 37 +++++++++++--------
 llvm/lib/AsmParser/LLParser.cpp               |  5 ++-
 llvm/lib/Bitcode/Reader/MetadataLoader.cpp    |  7 +++-
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp     |  1 +
 llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp     |  3 ++
 llvm/lib/IR/AsmWriter.cpp                     |  1 +
 llvm/lib/IR/DebugInfoMetadata.cpp             | 16 ++++----
 llvm/lib/IR/LLVMContextImpl.h                 | 11 ++++--
 llvm/test/DebugInfo/fortran-string-type.ll    |  6 ++-
 mlir/include/mlir-c/Dialect/LLVM.h            |  2 +-
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       |  3 +-
 mlir/lib/CAPI/Dialect/LLVM.cpp                |  5 ++-
 mlir/lib/Target/LLVMIR/DebugImporter.cpp      |  3 +-
 mlir/lib/Target/LLVMIR/DebugTranslation.cpp   |  3 +-
 mlir/test/CAPI/llvm.c                         |  6 +--
 21 files changed, 88 insertions(+), 52 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index b6f3b6e1d4d67..386b7c15a0751 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -682,10 +682,17 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertCharacterType(
   // type of the underlying character. This restricts out ability to represent
   // string with non-default characters. Please see issue #95440 for more
   // details.
+  unsigned charBitSize = kindMapping.getCharacterBitsize(charTy.getFKind());
+  mlir::LLVM::DITypeAttr charTypeAttr = genBasicType(
+      context,
+      mlir::StringAttr::get(
+          context, "character(kind=" + llvm::Twine(charTy.getFKind()) + ")"),
+      charBitSize, encoding);
+
   return mlir::LLVM::DIStringTypeAttr::get(
       context, llvm::dwarf::DW_TAG_string_type,
       mlir::StringAttr::get(context, ""), sizeInBits, /*alignInBits=*/0,
-      /*stringLength=*/varAttr, lenExpr, locExpr, encoding);
+      /*stringLength=*/varAttr, lenExpr, locExpr, encoding, charTypeAttr);
 }
 
 mlir::LLVM::DITypeAttr DebugTypeGenerator::convertPointerLikeType(
diff --git a/flang/test/Integration/debug-char-type-1.f90 b/flang/test/Integration/debug-char-type-1.f90
index 5068663aa9e28..262d439d47538 100644
--- a/flang/test/Integration/debug-char-type-1.f90
+++ b/flang/test/Integration/debug-char-type-1.f90
@@ -16,10 +16,12 @@ program test
 end program test
 
 ! CHECK-DAG: !DIGlobalVariable(name: "str"{{.*}}type: ![[TY40:[0-9]+]]{{.*}})
-! CHECK-DAG: ![[TY40]] = !DIStringType(size: 320, encoding: DW_ATE_ASCII)
+! CHECK-DAG: ![[TY40]] = !DIStringType(size: 320, encoding: DW_ATE_ASCII, charType: ![[CHAR1:[0-9]+]])
+! CHECK-DAG: ![[CHAR1]] = !DIBasicType(name: "character(kind=1)", size: 8, encoding: DW_ATE_ASCII)
 ! CHECK-DAG: !DIGlobalVariable(name: "str2"{{.*}}type: ![[TY:[0-9]+]]{{.*}})
-! CHECK-DAG: ![[TY]] = !DIStringType(stringLengthExpression: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8), stringLocationExpression: !DIExpression(DW_OP_push_object_address, DW_OP_deref), encoding: DW_ATE_ASCII)
+! CHECK-DAG: ![[TY]] = !DIStringType(stringLengthExpression: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8), stringLocationExpression: !DIExpression(DW_OP_push_object_address, DW_OP_deref), encoding: DW_ATE_ASCII, charType: ![[CHAR1]])
 ! CHECK-DAG: !DILocalVariable(name: "first"{{.*}}type: ![[TY8:[0-9]+]])
-! CHECK-DAG: ![[TY8]] = !DIStringType(size: 256, encoding: DW_ATE_UCS)
+! CHECK-DAG: ![[TY8]] = !DIStringType(size: 256, encoding: DW_ATE_UCS, charType: ![[CHAR4:[0-9]+]])
+! CHECK-DAG: ![[CHAR4]] = !DIBasicType(name: "character(kind=4)", size: 32, encoding: DW_ATE_UCS)
 ! CHECK-DAG: !DILocalVariable(name: "second"{{.*}}type: ![[TY10:[0-9]+]])
-! CHECK-DAG: ![[TY10]] = !DIStringType(size: 80, encoding: DW_ATE_ASCII)
+! CHECK-DAG: ![[TY10]] = !DIStringType(size: 80, encoding: DW_ATE_ASCII, charType: ![[CHAR1]])
diff --git a/flang/test/Transforms/debug-107988.fir b/flang/test/Transforms/debug-107988.fir
index 674ce287a29ec..d04bd8939af38 100644
--- a/flang/test/Transforms/debug-107988.fir
+++ b/flang/test/Transforms/debug-107988.fir
@@ -18,6 +18,6 @@ module {
 // CHECK: %[[V1:.*]]:2 = fir.unboxchar{{.*}}
 // CHECK: %[[V2:.*]] = fir.convert %[[V1]]#1 : (index) -> i64
 // CHECK: llvm.intr.dbg.value #[[VAR]] = %[[V2]] : i64
-// CHECK: #[[STR_TY:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", stringLength = #[[VAR]], encoding = DW_ATE_ASCII>
+// CHECK: #[[STR_TY:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", stringLength = #[[VAR]], encoding = DW_ATE_ASCII, charType = #{{.*}}>
 // CHECK: #llvm.di_local_variable<{{.*}}name = "str"{{.*}}type = #[[STR_TY]]>
 
diff --git a/flang/test/Transforms/debug-char-type-1.fir b/flang/test/Transforms/debug-char-type-1.fir
index 49f230f7307fa..ebda329fe2d47 100644
--- a/flang/test/Transforms/debug-char-type-1.fir
+++ b/flang/test/Transforms/debug-char-type-1.fir
@@ -18,9 +18,9 @@ module {
 }
 #loc1 = loc("string.f90":1:1)
 
-// CHECK-DAG: #[[TY1:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", sizeInBits = 320, encoding = DW_ATE_ASCII>
+// CHECK-DAG: #[[TY1:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", sizeInBits = 320, encoding = DW_ATE_ASCII, charType = #{{.*}}>
 // CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "str1"{{.*}}type = #[[TY1]]{{.*}}>
-// CHECK-DAG: #[[TY2:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", sizeInBits = 640, encoding = DW_ATE_UCS>
+// CHECK-DAG: #[[TY2:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", sizeInBits = 640, encoding = DW_ATE_UCS, charType = #{{.*}}>
 // CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "str2"{{.*}}type = #[[TY2]]{{.*}}>
-// CHECK-DAG: #[[TY3:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type{{.*}}stringLengthExp = <[DW_OP_push_object_address, DW_OP_plus_uconst(8)]>, stringLocationExp = <[DW_OP_push_object_address, DW_OP_deref]>, encoding = DW_ATE_ASCII>
+// CHECK-DAG: #[[TY3:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type{{.*}}stringLengthExp = <[DW_OP_push_object_address, DW_OP_plus_uconst(8)]>, stringLocationExp = <[DW_OP_push_object_address, DW_OP_deref]>, encoding = DW_ATE_ASCII, charType = #{{.*}}>
 // CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "str3"{{.*}}type = #[[TY3]]{{.*}}>
diff --git a/flang/test/Transforms/debug-char-type-2.fir b/flang/test/Transforms/debug-char-type-2.fir
index 7be81224d8a04..7f78b74a5c6fb 100644
--- a/flang/test/Transforms/debug-char-type-2.fir
+++ b/flang/test/Transforms/debug-char-type-2.fir
@@ -13,7 +13,7 @@ module {
 #loc1 = loc("string.f90":16:1)
 #loc2 = loc("string.f90":15:1)
 
-// CHECK: #[[STR:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", stringLengthExp = <[DW_OP_push_object_address, DW_OP_plus_uconst(8)]>, encoding = DW_ATE_ASCII>
+// CHECK: #[[STR:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", stringLengthExp = <[DW_OP_push_object_address, DW_OP_plus_uconst(8)]>, encoding = DW_ATE_ASCII, charType = #{{.*}}>
 // CHECK: #[[ARR:.*]] = #llvm.di_composite_type<tag = DW_TAG_array_type, {{.*}}baseType = #[[STR]]
 // CHECK-SAME: dataLocation = <[DW_OP_push_object_address, DW_OP_deref]>
 // CHECK: #llvm.di_local_variable<{{.*}}name = "akeys"{{.*}}type = #[[ARR]]>
diff --git a/flang/test/Transforms/debug-variable-char-len.fir b/flang/test/Transforms/debug-variable-char-len.fir
index 907b65a4c6d4f..1a52c10fce2c9 100644
--- a/flang/test/Transforms/debug-variable-char-len.fir
+++ b/flang/test/Transforms/debug-variable-char-len.fir
@@ -26,6 +26,6 @@ module {
 // CHECK: func.func @foo
 // CHECK: llvm.intr.dbg.value #[[VAR]]
 // CHECK: return
-// CHECK: #[[STR_TY:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", stringLength = #[[VAR]], encoding = DW_ATE_ASCII>
+// CHECK: #[[STR_TY:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type, name = "", stringLength = #[[VAR]], encoding = DW_ATE_ASCII, charType = #{{.*}}>
 // CHECK: #llvm.di_local_variable<{{.*}}name = "str1"{{.*}}type = #[[STR_TY]]>
 
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index 33a1a6e482555..4d3b54a76662a 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -1174,37 +1174,37 @@ class DIStringType : public DIType {
                                StringRef Name, Metadata *StringLength,
                                Metadata *StrLenExp, Metadata *StrLocationExp,
                                uint64_t SizeInBits, uint32_t AlignInBits,
-                               unsigned Encoding, StorageType Storage,
-                               bool ShouldCreate = true) {
+                               unsigned Encoding, Metadata *CharType,
+                               StorageType Storage, bool ShouldCreate = true) {
     auto *SizeInBitsNode = ConstantAsMetadata::get(
         ConstantInt::get(Type::getInt64Ty(Context), SizeInBits));
     return getImpl(Context, Tag, getCanonicalMDString(Context, Name),
                    StringLength, StrLenExp, StrLocationExp, SizeInBitsNode,
-                   AlignInBits, Encoding, Storage, ShouldCreate);
+                   AlignInBits, Encoding, CharType, Storage, ShouldCreate);
   }
   static DIStringType *getImpl(LLVMContext &Context, unsigned Tag,
                                MDString *Name, Metadata *StringLength,
                                Metadata *StrLenExp, Metadata *StrLocationExp,
                                uint64_t SizeInBits, uint32_t AlignInBits,
-                               unsigned Encoding, StorageType Storage,
-                               bool ShouldCreate = true) {
+                               unsigned Encoding, Metadata *CharType,
+                               StorageType Storage, bool ShouldCreate = true) {
     auto *SizeInBitsNode = ConstantAsMetadata::get(
         ConstantInt::get(Type::getInt64Ty(Context), SizeInBits));
     return getImpl(Context, Tag, Name, StringLength, StrLenExp, StrLocationExp,
-                   SizeInBitsNode, AlignInBits, Encoding, Storage,
+                   SizeInBitsNode, AlignInBits, Encoding, CharType, Storage,
                    ShouldCreate);
   }
   LLVM_ABI static DIStringType *
   getImpl(LLVMContext &Context, unsigned Tag, MDString *Name,
           Metadata *StringLength, Metadata *StrLenExp, Metadata *StrLocationExp,
           Metadata *SizeInBits, uint32_t AlignInBits, unsigned Encoding,
-          StorageType Storage, bool ShouldCreate = true);
+          Metadata *CharType, StorageType Storage, bool ShouldCreate = true);
 
   TempDIStringType cloneImpl() const {
     return getTemporary(getContext(), getTag(), getRawName(),
                         getRawStringLength(), getRawStringLengthExp(),
                         getRawStringLocationExp(), getRawSizeInBits(),
-                        getAlignInBits(), getEncoding());
+                        getAlignInBits(), getEncoding(), getRawCharType());
   }
 
 public:
@@ -1212,28 +1212,31 @@ class DIStringType : public DIType {
                     (unsigned Tag, StringRef Name, uint64_t SizeInBits,
                      uint32_t AlignInBits),
                     (Tag, Name, nullptr, nullptr, nullptr, SizeInBits,
-                     AlignInBits, 0))
+                     AlignInBits, 0, nullptr))
   DEFINE_MDNODE_GET(DIStringType,
                     (unsigned Tag, MDString *Name, Metadata *StringLength,
                      Metadata *StringLengthExp, Metadata *StringLocationExp,
                      uint64_t SizeInBits, uint32_t AlignInBits,
-                     unsigned Encoding),
+                     unsigned Encoding, Metadata *CharType = nullptr),
                     (Tag, Name, StringLength, StringLengthExp,
-                     StringLocationExp, SizeInBits, AlignInBits, Encoding))
+                     StringLocationExp, SizeInBits, AlignInBits, Encoding,
+                     CharType))
   DEFINE_MDNODE_GET(DIStringType,
                     (unsigned Tag, StringRef Name, Metadata *StringLength,
                      Metadata *StringLengthExp, Metadata *StringLocationExp,
                      uint64_t SizeInBits, uint32_t AlignInBits,
-                     unsigned Encoding),
+                     unsigned Encoding, Metadata *CharType = nullptr),
                     (Tag, Name, StringLength, StringLengthExp,
-                     StringLocationExp, SizeInBits, AlignInBits, Encoding))
+                     StringLocationExp, SizeInBits, AlignInBits, Encoding,
+                     CharType))
   DEFINE_MDNODE_GET(DIStringType,
                     (unsigned Tag, MDString *Name, Metadata *StringLength,
                      Metadata *StringLengthExp, Metadata *StringLocationExp,
                      Metadata *SizeInBits, uint32_t AlignInBits,
-                     unsigned Encoding),
+                     unsigned Encoding, Metadata *CharType = nullptr),
                     (Tag, Name, StringLength, StringLengthExp,
-                     StringLocationExp, SizeInBits, AlignInBits, Encoding))
+                     StringLocationExp, SizeInBits, AlignInBits, Encoding,
+                     CharType))
 
   TempDIStringType clone() const { return cloneImpl(); }
 
@@ -1255,6 +1258,8 @@ class DIStringType : public DIType {
 
   unsigned getEncoding() const { return Encoding; }
 
+  DIType *getCharType() const { return cast_or_null<DIType>(getRawCharType()); }
+
   Metadata *getRawStringLength() const { return getOperand(MY_FIRST_OPERAND); }
 
   Metadata *getRawStringLengthExp() const {
@@ -1264,6 +1269,8 @@ class DIStringType : public DIType {
   Metadata *getRawStringLocationExp() const {
     return getOperand(MY_FIRST_OPERAND + 2);
   }
+
+  Metadata *getRawCharType() const { return getOperand(MY_FIRST_OPERAND + 3); }
 };
 
 /// Derived types.
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index edff818b3b152..aa8f0623a3178 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -6035,7 +6035,8 @@ bool LLParser::parseDIStringType(MDNode *&Result, bool IsDistinct) {
   OPTIONAL(stringLocationExpression, MDField, );                               \
   OPTIONAL(size, MDUnsignedOrMDField, (0, UINT64_MAX));                        \
   OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX));                           \
-  OPTIONAL(encoding, DwarfAttEncodingField, );
+  OPTIONAL(encoding, DwarfAttEncodingField, );                                 \
+  OPTIONAL(charType, MDField, );
   PARSE_MD_FIELDS();
 #undef VISIT_MD_FIELDS
 
@@ -6043,7 +6044,7 @@ bool LLParser::parseDIStringType(MDNode *&Result, bool IsDistinct) {
       DIStringType,
       (Context, tag.Val, name.Val, stringLength.Val, stringLengthExpression.Val,
        stringLocationExpression.Val, size.getValueAsMetadata(Context),
-       align.Val, encoding.Val));
+       align.Val, encoding.Val, charType.Val));
   return false;
 }
 
diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
index 8b7beb1a8ff9e..21150835bebea 100644
--- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
+++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp
@@ -1654,7 +1654,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
     break;
   }
   case bitc::METADATA_STRING_TYPE: {
-    if (Record.size() > 9 || Record.size() < 8)
+    if (Record.size() > 10 || Record.size() < 8)
       return error("Invalid record");
 
     IsDistinct = Record[0] & 1;
@@ -1666,13 +1666,16 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
     unsigned Offset = SizeIs8 ? 5 : 6;
     Metadata *SizeInBits =
         getMetadataOrConstant(SizeIsMetadata, Record[Offset]);
+    Metadata *CharType = (Record.size() > Offset + 3)
+                             ? getMDOrNull(Record[Offset + 3])
+                             : nullptr;
 
     MetadataList.assignValue(
         GET_OR_DISTINCT(DIStringType,
                         (Context, Record[1], getMDString(Record[2]),
                          getMDOrNull(Record[3]), getMDOrNull(Record[4]),
                          StringLocationExp, SizeInBits, Record[Offset + 1],
-                         Record[Offset + 2])),
+                         Record[Offset + 2], CharType)),
         NextMetadataNo);
     NextMetadataNo++;
     break;
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 571336c217797..ca2df28ee2772 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -2058,6 +2058,7 @@ void ModuleBitcodeWriter::writeDIStringType(const DIStringType *N,
   Record.push_back(VE.getMetadataOrNullID(N->getRawSizeInBits()));
   Record.push_back(N->getAlignInBits());
   Record.push_back(N->getEncoding());
+  Record.push_back(VE.getMetadataOrNullID(N->getRawCharType()));
 
   Stream.EmitRecord(bitc::METADATA_STRING_TYPE, Record, Abbrev);
   Record.clear();
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index dd16095f0e823..80bdcca010f2d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -859,6 +859,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) {
     addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
             STy->getEncoding());
   }
+
+  if (STy->getCharType())
+    addType(Buffer, STy->getCharType());
 }
 
 void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index cad4f17b0db91..0980e3d1d4b1f 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -2278,6 +2278,7 @@ static void writeDIStringType(raw_ostream &Out, const DIStringType *N,
   Printer.printInt("align", N->getAlignInBits());
   Printer.printDwarfEnum("encoding", N->getEncoding(),
                          dwarf::AttributeEncodingString);
+  Printer.printMetadata("charType", N->getRawCharType());
   Out << ")";
 }
 
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 5e9e0e4e81c6e..00a17f4607951 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -954,15 +954,15 @@ DIStringType *DIStringType::getImpl(LLVMContext &Context, unsigned Tag,
                                     Metadata *StringLengthExp,
                                     Metadata *StringLocationExp,
                                     Metadata *SizeInBits, uint32_t AlignInBits,
-                                    unsigned Encoding, StorageType Storage,
-                                    bool ShouldCreate) {
+                                    unsigned Encoding, Metadata *CharType,
+                                    StorageType Storage, bool ShouldCreate) {
   assert(isCanonical(Name) && "Expected canonical MDString");
-  DEFINE_GETIMPL_LOOKUP(DIStringType,
-                        (Tag, Name, StringLength, StringLengthExp,
-                         StringLocationExp, SizeInBits, AlignInBits, Encoding));
-  Metadata *Ops[] = {nullptr,         nullptr,          Name,
-                     SizeInBits,      nullptr,          StringLength,
-                     StringLengthExp, StringLocationExp};
+  DEFINE_GETIMPL_LOOKUP(DIStringType, (Tag, Name, StringLength, StringLengthExp,
+                                       StringLocationExp, SizeInBits,
+                                       AlignInBits, Encoding, CharType));
+  Metadata *Ops[] = {nullptr,         nullptr,           Name,
+                     SizeInBits,      nullptr,           StringLength,
+                     StringLengthExp, StringLocationExp, CharType};
   DEFINE_GETIMPL_STORE(DIStringType, (Tag, AlignInBits, Encoding), Ops);
 }
 DIType *DIDerivedType::getClassType() const {
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 41c8a92c56eda..9b27eb1997792 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -543,20 +543,23 @@ template <> struct MDNodeKeyImpl<DIStringType> {
   Metadata *SizeInBits;
   uint32_t AlignInBits;
   unsigned Encoding;
+  Metadata *CharType;
 
   MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *StringLength,
                 Metadata *StringLengthExp, Metadata *StringLocationExp,
-                Metadata *SizeInBits, uint32_t AlignInBits, unsigned Encoding)
+                Metadata *SizeInBits, uint32_t AlignInBits, unsigned Encoding,
+                Metadata *CharType)
       : Tag(Tag), Name(Name), StringLength(StringLength),
         StringLengthExp(StringLengthExp), StringLocationExp(StringLocationExp),
-        SizeInBits(SizeInBits), AlignInBits(AlignInBits), Encoding(Encoding) {}
+        SizeInBits(SizeInBits), AlignInBits(AlignInBits), Encoding(Encoding),
+        CharType(CharType) {}
   MDNodeKeyImpl(const DIStringType *N)
       : Tag(N->getTag()), Name(N->getRawName()),
         StringLength(N->getRawStringLength()),
         StringLengthExp(N->getRawStringLengthExp()),
         StringLocationExp(N->getRawStringLocationExp()),
         SizeInBits(N->getRawSizeInBits()), AlignInBits(N->getAlignInBits()),
-        Encoding(N->getEncoding()) {}
+        Encoding(N->getEncoding()), CharType(N->getRawCharType()) {}
 
   bool isKeyOf(const DIStringType *RHS) const {
     return Tag == RHS->getTag() && Name == RHS->getRawName() &&
@@ -565,7 +568,7 @@ template <> struct MDNodeKeyImpl<DIStringType> {
            StringLocationExp == RHS->getRawStringLocationExp() &&
            SizeInBits == RHS->getRawSizeInBits() &&
            AlignInBits == RHS->getAlignInBits() &&
-           Encoding == RHS->getEncoding();
+           Encoding == RHS->getEncoding() && CharType == RHS->getRawCharType();
   }
   unsigned getHashValue() const {
     // Intentionally computes the hash on a subset of the operands for
diff --git a/llvm/test/DebugInfo/fortran-string-type.ll b/llvm/test/DebugInfo/fortran-string-type.ll
index e6fe3c5096d34..ac8bb96e64f91 100644
--- a/llvm/test/DebugInfo/fortran-string-type.ll
+++ b/llvm/test/DebugInfo/fortran-string-type.ll
@@ -8,6 +8,8 @@
 ; CHECK: !DIStringType(name: "character(10)", size: 80, align: 8)
 ; CHECK: !DIBasicType(tag: DW_TAG_string_type
 ; CHECK: !DIStringType(name: ".str.DEFERRED", stringLengthExpression: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8), stringLocationExpression: !DIExpression(DW_OP_push_object_address, DW_OP_deref))
+; CHECK: !DIStringType(name: "character(10)_typed", size: 80, align: 8, charType: ![[CHARTYPE:[0-9]+]])
+; CHECK: ![[CHARTYPE]] = !DIBasicType(name: "character", size: 8, encoding: DW_ATE_unsigned_char)
 
 !llvm.module.flags = !{!0, !1}
 !llvm.dbg.cu = !{!2}
@@ -17,7 +19,7 @@
 !2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: "Flang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !4, imports: !4)
 !3 = !DIFile(filename: "fortran-string-type.f", directory: "/")
 !4 = !{}
-!5 = !{!6, !9, !12, !13, !14}
+!5 = !{!6, !9, !12, !13, !14, !15}
 !6 = !DIStringType(name: "character(*)", stringLength: !7, stringLengthExpression: !DIExpression(), size: 32)
 !7 = !DILocalVariable(arg: 2, scope: !8, file: !3, line: 256, type: !11, flags: DIFlagArtificial)
 !8 = distinct !DISubprogram(name: "subprgm", scope: !2, file: !3, line: 256, type: !9, isLocal: false, isDefinition: true, scopeLine: 256, isOptimized: false, unit: !2)
@@ -27,3 +29,5 @@
 !12 = !DIStringType(name: "character(10)", size: 80, align: 8)
 !13 = !DIBasicType(tag: DW_TAG_string_type, name: "character")
 !14 = !DIStringType(name: ".str.DEFERRED", stringLengthExpression: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 8), stringLocationExpression: !DIExpression(DW_OP_push_object_address, DW_OP_deref))
+!15 = !DIStringType(name: "character(10)_typed", size: 80, align: 8, charType: !16)
+!16 = !DIBasicType(name: "character", size: 8, encoding: DW_ATE_unsigned_char)
diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h
index 30137faaaa8d8..8d94f7eb787de 100644
--- a/mlir/include/mlir-c/Dialect/LLVM.h
+++ b/mlir/include/mlir-c/Dialect/LLVM.h
@@ -327,7 +327,7 @@ MLIR_CAPI_EXPORTED MlirAttribute mlirLLVMDIStringTypeAttrGet(
     MlirContext ctx, unsigned int tag, MlirAttribute name, uint64_t sizeInBits,
     uint32_t alignInBits, MlirAttribute stringLength,
     MlirAttribute stringLengthExp, MlirAttribute stringLocationExp,
-    MlirLLVMTypeEncoding encoding);
+    MlirLLVMTypeEncoding encoding, MlirAttribute charType);
 
 MLIR_CAPI_EXPORTED MlirStringRef mlirLLVMDIStringTypeAttrGetName(void);
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index a5e4bc52c84a6..a33bda22e22bc 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -994,7 +994,8 @@ def LLVM_DIStringTypeAttr : LLVM_Attr<"DIStringType", "di_string_type",
     OptionalParameter<"DIVariableAttr">:$stringLength,
     OptionalParameter<"DIExpressionAttr">:$stringLengthExp,
     OptionalParameter<"DIExpressionAttr">:$stringLocationExp,
-    LLVM_DIEncodingParameter:$encoding
+    LLVM_DIEncodingParameter:$encoding,
+    OptionalParameter<"DITypeAttr">:$charType
   );
   let assemblyFormat = "`<` struct(params) `>`";
 
diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp
index 9885ae7b2b77f..a35172cb525d4 100644
--- a/mlir/lib/CAPI/Dialect/LLVM.cpp
+++ b/mlir/lib/CAPI/Dialect/LLVM.cpp
@@ -300,12 +300,13 @@ MlirAttribute mlirLLVMDIStringTypeAttrGet(
     MlirContext ctx, unsigned int tag, MlirAttribute name, uint64_t sizeInBits,
     uint32_t alignInBits, MlirAttribute stringLength,
     MlirAttribute stringLengthExp, MlirAttribute stringLocationExp,
-    MlirLLVMTypeEncoding encoding) {
+    MlirLLVMTypeEncoding encoding, MlirAttribute charType) {
   return wrap(DIStringTypeAttr::get(
       unwrap(ctx), tag, cast<StringAttr>(unwrap(name)), sizeInBits, alignInBits,
       cast<DIVariableAttr>(unwrap(stringLength)),
       cast<DIExpressionAttr>(unwrap(stringLengthExp)),
-      cast<DIExpressionAttr>(unwrap(stringLocationExp)), encoding));
+      cast<DIExpressionAttr>(unwrap(stringLocationExp)), encoding,
+      cast<DITypeAttr>(unwrap(charType))));
 }
 
 MlirStringRef mlirLLVMDIStringTypeAttrGetName(void) {
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
index 82beb2984b043..e293baf66394f 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -139,7 +139,8 @@ DIStringTypeAttr DebugImporter::translateImpl(llvm::DIStringType *node) {
       node->getSizeInBits(), node->getAlignInBits(),
       translate(node->getStringLength()),
       translateExpression(node->getStringLengthExp()),
-      translateExpression(node->getStringLocationExp()), node->getEncoding());
+      translateExpression(node->getStringLocationExp()), node->getEncoding(),
+      translate(node->getCharType()));
 }
 
 DIFileAttr DebugImporter::translateImpl(llvm::DIFile *node) {
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index 4dc9e91b4e1c2..97ff48925ac45 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -289,7 +289,8 @@ llvm::DIStringType *DebugTranslation::translateImpl(DIStringTypeAttr attr) {
       translate(attr.getStringLength()),
       getExpressionAttrOrNull(attr.getStringLengthExp()),
       getExpressionAttrOrNull(attr.getStringLocationExp()),
-      attr.getSizeInBits(), attr.getAlignInBits(), attr.getEncoding());
+      attr.getSizeInBits(), attr.getAlignInBits(), attr.getEncoding(),
+      translate(attr.getCharType()));
 }
 
 llvm::DIFile *DebugTranslation::translateImpl(DIFileAttr attr) {
diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c
index 692a846d3b3c9..5d06386ecb2e5 100644
--- a/mlir/test/CAPI/llvm.c
+++ b/mlir/test/CAPI/llvm.c
@@ -374,9 +374,9 @@ static void testDebugInfoAttributes(MlirContext ctx) {
   // CHECK: #llvm.di_expression<[(1)]>
   mlirAttributeDump(expression);
 
-  MlirAttribute string_type =
-      mlirLLVMDIStringTypeAttrGet(ctx, 0x0, foo, 16, 0, local_var, expression,
-                                  expression, MlirLLVMTypeEncodingSigned);
+  MlirAttribute string_type = mlirLLVMDIStringTypeAttrGet(
+      ctx, 0x0, foo, 16, 0, local_var, expression, expression,
+      MlirLLVMTypeEncodingSigned, basic_type);
   // CHECK: #llvm.di_string_type<{{.*}}>
   mlirAttributeDump(string_type);
 



More information about the flang-commits mailing list