[flang-commits] [flang] a73eccc - [flang][debuginfo] Emit DW_AT_type for DW_TAG_string_type DIEs [3/3] (#231960)

via flang-commits flang-commits at lists.llvm.org
Wed Oct 21 14:50:01 PDT 2026


Author: Tim
Date: 2026-10-21T16:49:56-05:00
New Revision: a73eccc328658b352bef955ba225853f36f47542

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

LOG: [flang][debuginfo] Emit DW_AT_type for DW_TAG_string_type DIEs [3/3] (#231960)

Use the new DIStringType type field to emit the DW_AT_type attribute on
DW_TAG_string_type DIEs generated by Flang's debug type generator,
enabling debuggers to identify the character type of Fortran strings.

Fixes #95440

Added: 
    

Modified: 
    flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
    flang/test/Integration/debug-bounds-stack-slot.f90
    flang/test/Integration/debug-char-type-1.f90
    flang/test/Integration/debug-module-constant.f90
    flang/test/Transforms/debug-107988.fir
    flang/test/Transforms/debug-char-type-1.fir
    flang/test/Transforms/debug-char-type-2.fir
    flang/test/Transforms/debug-variable-char-len.fir

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
index c9c9794d6913f..037feae7058dd 100644
--- a/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
+++ b/flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp
@@ -704,6 +704,13 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertCharacterType(
     };
     addOp(llvm::dwarf::DW_OP_push_object_address, {});
     addOp(llvm::dwarf::DW_OP_plus_uconst, {lenOffset});
+    uint64_t charBytes = kindMapping.getCharacterBitsize(charTy.getFKind()) / 8;
+    if (charBytes != 1) {
+      addOp(llvm::dwarf::DW_OP_deref, {});
+      addOp(llvm::dwarf::DW_OP_constu, {charBytes});
+      addOp(llvm::dwarf::DW_OP_div, {});
+      addOp(llvm::dwarf::DW_OP_stack_value, {});
+    }
     lenExpr = mlir::LLVM::DIExpressionAttr::get(context, ops);
     ops.clear();
 
@@ -730,12 +737,19 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertCharacterType(
     }
   }
 
-  // TODO: Populate the charType field to represent strings with non-default
-  // character types. Please see issue #95440 for more details.
+  // Set type of the underlying characters in the string
+  unsigned charBitSize = kindMapping.getCharacterBitsize(charTy.getFKind());
+  mlir::LLVM::DITypeAttr charTypeAttr = genBasicType(
+      context,
+      mlir::StringAttr::get(
+          context,
+          getBasicTypeName(context, "character", charTy.getFKind()).getValue()),
+      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, nullptr);
+      /*stringLength=*/varAttr, lenExpr, locExpr, encoding, charTypeAttr);
 }
 
 mlir::LLVM::DITypeAttr DebugTypeGenerator::convertPointerLikeType(

diff  --git a/flang/test/Integration/debug-bounds-stack-slot.f90 b/flang/test/Integration/debug-bounds-stack-slot.f90
index 3bb1743adf6fc..575f02745a247 100644
--- a/flang/test/Integration/debug-bounds-stack-slot.f90
+++ b/flang/test/Integration/debug-bounds-stack-slot.f90
@@ -42,7 +42,7 @@ subroutine char_len(c)
 ! CHECK-DAG: ![[SUBRANGE]] = !DISubrange(count: ![[COUNT]], lowerBound: ![[LB]])
 ! CHECK-DAG: ![[LEN]] = !DILocalVariable(name: "._QFchar_lenEc1"{{.*}}flags: DIFlagArtificial)
 ! CHECK-DAG: !DILocalVariable(name: "c"{{.*}}type: ![[CTY:[0-9]+]])
-! CHECK-DAG: ![[CTY]] = !DIStringType(stringLength: ![[LEN]], encoding: DW_ATE_ASCII)
+! CHECK-DAG: ![[CTY]] = !DIStringType(stringLength: ![[LEN]], encoding: DW_ATE_ASCII, charType: !{{.*}})
 
 ! The slots are only made at -O0. Above it a bound is described by its value,
 ! as it was before, so a debugger has to find that value in a register.

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/Integration/debug-module-constant.f90 b/flang/test/Integration/debug-module-constant.f90
index 37ae40e94f14e..2a3b574d595d3 100644
--- a/flang/test/Integration/debug-module-constant.f90
+++ b/flang/test/Integration/debug-module-constant.f90
@@ -29,7 +29,7 @@ module helper
   integer, parameter :: primes(3) = [2, 3, 5]
 
 ! CHECK-DAG: ![[TAG:.*]] = distinct !DIGlobalVariable(name: "tag", linkageName: "_QMhelperECtag", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+3]], type: ![[STR:.*]], isLocal: false, isDefinition: true)
-! CHECK-DAG: ![[STR]] = !DIStringType(size: 40, encoding: DW_ATE_ASCII)
+! CHECK-DAG: ![[STR]] = !DIStringType(size: 40, encoding: DW_ATE_ASCII, charType: !{{.*}})
 ! CHECK-DAG: !DIGlobalVariableExpression(var: ![[TAG]], expr: !DIExpression())
   character(len=5), parameter :: tag = "hello"
 end module helper

diff  --git a/flang/test/Transforms/debug-107988.fir b/flang/test/Transforms/debug-107988.fir
index e8b0a1147f4da..da3bcee1c885f 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..e66d9b61ba6b0 100644
--- a/flang/test/Transforms/debug-char-type-1.fir
+++ b/flang/test/Transforms/debug-char-type-1.fir
@@ -15,12 +15,28 @@ module {
     %1 = fir.embox %0 typeparams %c0 : (!fir.heap<!fir.char<1,?>>, index) -> !fir.box<!fir.heap<!fir.char<1,?>>>
     fir.has_value %1 : !fir.box<!fir.heap<!fir.char<1,?>>>
   } loc(#loc1)
+  fir.global @_QMhelperEstr4 : !fir.box<!fir.heap<!fir.char<4,?>>> {
+    %c0 = arith.constant 0 : index
+    %0 = fir.zero_bits !fir.heap<!fir.char<4,?>>
+    %1 = fir.embox %0 typeparams %c0 : (!fir.heap<!fir.char<4,?>>, index) -> !fir.box<!fir.heap<!fir.char<4,?>>>
+    fir.has_value %1 : !fir.box<!fir.heap<!fir.char<4,?>>>
+  } loc(#loc1)
 }
 #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>
+
+// str3: descriptor-based deferred-length character(kind=1). The length is read
+// from the descriptor (elem_len in bytes). Since kind=1 characters are a single
+// byte, no division is needed to convert the byte length to a character count.
+// 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]]{{.*}}>
+
+// str4: descriptor-based deferred-length character(kind=4). The length is read
+// from the descriptor (elem_len in bytes) and divided by the kind (4 bytes per
+// character) to recover the character count.
+// CHECK-DAG: #[[TY4:.*]] = #llvm.di_string_type<tag = DW_TAG_string_type{{.*}}stringLengthExp = <[DW_OP_push_object_address, DW_OP_plus_uconst(8), DW_OP_deref, DW_OP_constu(4), DW_OP_div, DW_OP_stack_value]>, stringLocationExp = <[DW_OP_push_object_address, DW_OP_deref]>, encoding = DW_ATE_UCS, charType = #{{.*}}>
+// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "str4"{{.*}}type = #[[TY4]]{{.*}}>

diff  --git a/flang/test/Transforms/debug-char-type-2.fir b/flang/test/Transforms/debug-char-type-2.fir
index d3726a2d8484e..ee126842ee44b 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 9ea2e9ca078d4..1acb8babf6cd6 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]]>
 


        


More information about the flang-commits mailing list