[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