-
Notifications
You must be signed in to change notification settings - Fork 15.3k
Allow DIDerivedType as a bound in DISubrangeType #165880
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Consider this Ada type:
```
type Array_Type is array (Natural range <>) of Integer;
type Record_Type (L1, L2 : Natural) is record
I1 : Integer;
A1 : Array_Type (1 .. L1);
I2 : Integer;
A2 : Array_Type (1 .. L2);
I3 : Integer;
end record;
```
Here, the array fields have lengths that depend on the discriminants
of the record type. However, in this case the array lengths cannot be
expressed as DWARF location expressions, with the issue being that
"A2" has a non-constant offset, but an expression involving
DW_OP_push_object_address will push the address of the field -- with
no way to find the location of "L2".
In a case like this, I believe the correct DWARF is to emit the array
ranges using a direct reference to the discriminant, like:
```
<3><1156>: Abbrev Number: 1 (DW_TAG_member)
<1157> DW_AT_name : l1
...
<3><1177>: Abbrev Number: 6 (DW_TAG_array_type)
<1178> DW_AT_name : (indirect string, offset: 0x1a0b): vla__record_type__T4b
<117c> DW_AT_type : <0x1287>
<1180> DW_AT_sibling : <0x118e>
<4><1184>: Abbrev Number: 7 (DW_TAG_subrange_type)
<1185> DW_AT_type : <0x1280>
<1189> DW_AT_upper_bound : <0x1156>
```
(FWIW this is what GCC has done for years.)
This patch makes this possible in LLVM, by letting a DISubrangeType
refer to a DIDerivedType. gnat-llvm can then arrange for the DIE
reference to be correct by setting the array type's scope to be the
record.
|
@llvm/pr-subscribers-llvm-ir Author: Tom Tromey (tromey) ChangesConsider this Ada type: Here, the array fields have lengths that depend on the discriminants of the record type. However, in this case the array lengths cannot be expressed as DWARF location expressions, with the issue being that "A2" has a non-constant offset, but an expression involving DW_OP_push_object_address will push the address of the field -- with no way to find the location of "L2". In a case like this, I believe the correct DWARF is to emit the array ranges using a direct reference to the discriminant, like: (FWIW this is what GCC has done for years.) This patch makes this possible in LLVM, by letting a DISubrangeType refer to a DIDerivedType. gnat-llvm can then arrange for the DIE reference to be correct by setting the array type's scope to be the record. Full diff: https://github.com/llvm/llvm-project/pull/165880.diff 5 Files Affected:
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index 7ade6b8e13308..cde15e05b3782 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -1520,7 +1520,9 @@ inline bool operator!=(DIDerivedType::PtrAuthData Lhs,
/// is also a DIType.
class DISubrangeType : public DIType {
public:
- typedef PointerUnion<ConstantInt *, DIVariable *, DIExpression *> BoundType;
+ typedef PointerUnion<ConstantInt *, DIVariable *, DIExpression *,
+ DIDerivedType *>
+ BoundType;
private:
friend class LLVMContextImpl;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index b16e131529ac3..698e804f7419e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1607,6 +1607,9 @@ void DwarfUnit::constructSubrangeDIE(DIE &DW_Subrange, const DISubrangeType *SR,
if (auto *BV = dyn_cast_if_present<DIVariable *>(Bound)) {
if (auto *VarDIE = getDIE(BV))
addDIEEntry(DW_Subrange, Attr, *VarDIE);
+ } else if (auto *DT = dyn_cast_if_present<DIDerivedType *>(Bound)) {
+ if (auto *DTDIE = getDIE(DT))
+ addDIEEntry(DW_Subrange, Attr, *DTDIE);
} else if (auto *BE = dyn_cast_if_present<DIExpression *>(Bound)) {
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc);
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index fafc3254120de..17c8432338cf8 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -839,7 +839,7 @@ DISubrangeType::convertRawToBound(Metadata *IN) const {
return BoundType();
assert(isa<ConstantAsMetadata>(IN) || isa<DIVariable>(IN) ||
- isa<DIExpression>(IN));
+ isa<DIExpression>(IN) || isa<DIDerivedType>(IN));
if (auto *MD = dyn_cast<ConstantAsMetadata>(IN))
return BoundType(cast<ConstantInt>(MD->getValue()));
@@ -850,6 +850,9 @@ DISubrangeType::convertRawToBound(Metadata *IN) const {
if (auto *MD = dyn_cast<DIExpression>(IN))
return BoundType(MD);
+ if (auto *DT = dyn_cast<DIDerivedType>(IN))
+ return BoundType(DT);
+
return BoundType();
}
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 7917712846990..9ca4025b3214a 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1187,13 +1187,17 @@ void Verifier::visitDISubrangeType(const DISubrangeType &N) {
CheckDI(!BaseType || isType(BaseType), "BaseType must be a type");
auto *LBound = N.getRawLowerBound();
CheckDI(!LBound || isa<ConstantAsMetadata>(LBound) ||
- isa<DIVariable>(LBound) || isa<DIExpression>(LBound),
- "LowerBound must be signed constant or DIVariable or DIExpression",
+ isa<DIVariable>(LBound) || isa<DIExpression>(LBound) ||
+ isa<DIDerivedType>(LBound),
+ "LowerBound must be signed constant or DIVariable or DIExpression or "
+ "DIDerivedType",
&N);
auto *UBound = N.getRawUpperBound();
CheckDI(!UBound || isa<ConstantAsMetadata>(UBound) ||
- isa<DIVariable>(UBound) || isa<DIExpression>(UBound),
- "UpperBound must be signed constant or DIVariable or DIExpression",
+ isa<DIVariable>(UBound) || isa<DIExpression>(UBound) ||
+ isa<DIDerivedType>(UBound),
+ "UpperBound must be signed constant or DIVariable or DIExpression or "
+ "DIDerivedType",
&N);
auto *Stride = N.getRawStride();
CheckDI(!Stride || isa<ConstantAsMetadata>(Stride) ||
diff --git a/llvm/test/DebugInfo/X86/derived-in-subrange.ll b/llvm/test/DebugInfo/X86/derived-in-subrange.ll
new file mode 100644
index 0000000000000..fb4c1d4745feb
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/derived-in-subrange.ll
@@ -0,0 +1,88 @@
+; RUN: llvm-as < %s | llvm-dis | llc -mtriple=x86_64 -O0 -filetype=obj -o - | llvm-dwarfdump -v -debug-info - | FileCheck %s
+
+; A test to verify the use of a DIDerivedType as a bound of a
+; DISubrangeType.
+
+; CHECK: DW_TAG_array_type
+; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}
+; CHECK: DW_TAG_subrange_type {{.*}}
+; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}
+; CHECK-NEXT: DW_AT_upper_bound [DW_FORM_ref4] {{.*}}
+
+; ModuleID = 'vla.ads'
+source_filename = "vla.ads"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%vla__array_type_FP = type { ptr, ptr }
+%vla__record_type_I = type <{ i32 }>
+
+@vla_E = dso_local global i16 0, align 2, !dbg !0
+
+; Function Attrs: inlinehint
+define dso_local void @vla__array_typeIP(%vla__array_type_FP %_init) #0 !dbg !10 {
+entry:
+ %0 = extractvalue %vla__array_type_FP %_init, 1, !dbg !15
+ %1 = call ptr @llvm.invariant.start.p0(i64 8, ptr %0), !dbg !15
+ ret void, !dbg !15
+}
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare ptr @llvm.invariant.start.p0(i64 immarg, ptr nocapture) #1
+
+; Function Attrs: inlinehint
+define dso_local void @vla__record_typeIP(ptr noalias nocapture nonnull %_init, i32 %l1) #0 !dbg !16 {
+entry:
+ #dbg_declare(ptr %_init, !31, !DIExpression(), !32)
+ #dbg_value(i32 %l1, !33, !DIExpression(), !34)
+ %0 = getelementptr inbounds %vla__record_type_I, ptr %_init, i32 0, i32 0, !dbg !32
+ store i32 %l1, ptr %0, align 4, !dbg !32, !tbaa !35
+ ret void, !dbg !32
+}
+
+attributes #0 = { inlinehint }
+attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+
+!llvm.module.flags = !{!6, !7, !8, !9}
+!llvm.dbg.cu = !{!2}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "vla_E", scope: !2, file: !3, line: 16, type: !5, isLocal: false, isDefinition: true, align: 16)
+!2 = distinct !DICompileUnit(language: DW_LANG_Ada95, file: !3, producer: "GNAT/LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false)
+!3 = !DIFile(filename: "vla.ads", directory: "")
+!4 = !{!0}
+!5 = !DIBasicType(name: "short_integer", size: 16, encoding: DW_ATE_signed)
+!6 = !{i32 8, !"PIC Level", i32 2}
+!7 = !{i32 7, !"PIE Level", i32 2}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 2, !"Dwarf Version", i32 4}
+!10 = distinct !DISubprogram(name: "vla__array_typeIP", scope: !3, file: !3, line: 17, type: !11, scopeLine: 17, spFlags: DISPFlagDefinition, unit: !2)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64, align: 64, dwarfAddressSpace: 0)
+!14 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "vla__array_type")
+!15 = !DILocation(line: 17, column: 9, scope: !10)
+!16 = distinct !DISubprogram(name: "vla__record_typeIP", scope: !3, file: !3, line: 18, type: !17, scopeLine: 18, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !30)
+!17 = !DISubroutineType(types: !18)
+!18 = !{null, !19, !23}
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64, align: 64, dwarfAddressSpace: 0)
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "vla__record_type", file: !3, line: 18, size: !DIExpression(DW_OP_push_object_address, DW_OP_deref_size, 4, DW_OP_constu, 32, DW_OP_mul, DW_OP_constu, 32, DW_OP_plus), align: 32, elements: !21, identifier: "vla__record_type")
+!21 = !{!22, !26}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "l1", file: !3, line: 18, baseType: !23)
+!23 = !DISubrangeType(name: "natural", file: !24, line: 1, size: 32, align: 32, baseType: !25, lowerBound: i64 0, upperBound: i64 2147483647)
+!24 = !DIFile(filename: "system.ads", directory: "/home/tromey/AdaCore/gnat-llvm/llvm-interface//lib/gnat-llvm/x86_64-unknown-linux-gnu/rts-native/adainclude/")
+!25 = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a1", file: !3, line: 19, baseType: !27, offset: 32)
+!27 = !DICompositeType(tag: DW_TAG_array_type, scope: !20, file: !3, line: 19, baseType: !25, align: 32, elements: !28)
+!28 = !{!29}
+!29 = !DISubrangeType(baseType: !25, lowerBound: i64 1, upperBound: !22)
+!30 = !{}
+!31 = !DILocalVariable(name: "_init", arg: 1, scope: !16, file: !3, line: 18, type: !20, flags: DIFlagArtificial)
+!32 = !DILocation(line: 18, column: 9, scope: !16)
+!33 = !DILocalVariable(name: "l1", arg: 2, scope: !16, file: !3, line: 18, type: !23, flags: DIFlagArtificial)
+!34 = !DILocation(line: 18, column: 22, scope: !16)
+!35 = !{!36, !36, i64 0, i64 4}
+!36 = !{!37, i64 4, !"natural#T5"}
+!37 = !{!38, i64 4, !"natural#TN"}
+!38 = !{!39, i64 4, !"integerB#TN"}
+!39 = !{!"Ada Root"}
|
|
@llvm/pr-subscribers-debuginfo Author: Tom Tromey (tromey) ChangesConsider this Ada type: Here, the array fields have lengths that depend on the discriminants of the record type. However, in this case the array lengths cannot be expressed as DWARF location expressions, with the issue being that "A2" has a non-constant offset, but an expression involving DW_OP_push_object_address will push the address of the field -- with no way to find the location of "L2". In a case like this, I believe the correct DWARF is to emit the array ranges using a direct reference to the discriminant, like: (FWIW this is what GCC has done for years.) This patch makes this possible in LLVM, by letting a DISubrangeType refer to a DIDerivedType. gnat-llvm can then arrange for the DIE reference to be correct by setting the array type's scope to be the record. Full diff: https://github.com/llvm/llvm-project/pull/165880.diff 5 Files Affected:
diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h
index 7ade6b8e13308..cde15e05b3782 100644
--- a/llvm/include/llvm/IR/DebugInfoMetadata.h
+++ b/llvm/include/llvm/IR/DebugInfoMetadata.h
@@ -1520,7 +1520,9 @@ inline bool operator!=(DIDerivedType::PtrAuthData Lhs,
/// is also a DIType.
class DISubrangeType : public DIType {
public:
- typedef PointerUnion<ConstantInt *, DIVariable *, DIExpression *> BoundType;
+ typedef PointerUnion<ConstantInt *, DIVariable *, DIExpression *,
+ DIDerivedType *>
+ BoundType;
private:
friend class LLVMContextImpl;
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index b16e131529ac3..698e804f7419e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -1607,6 +1607,9 @@ void DwarfUnit::constructSubrangeDIE(DIE &DW_Subrange, const DISubrangeType *SR,
if (auto *BV = dyn_cast_if_present<DIVariable *>(Bound)) {
if (auto *VarDIE = getDIE(BV))
addDIEEntry(DW_Subrange, Attr, *VarDIE);
+ } else if (auto *DT = dyn_cast_if_present<DIDerivedType *>(Bound)) {
+ if (auto *DTDIE = getDIE(DT))
+ addDIEEntry(DW_Subrange, Attr, *DTDIE);
} else if (auto *BE = dyn_cast_if_present<DIExpression *>(Bound)) {
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc);
diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index fafc3254120de..17c8432338cf8 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -839,7 +839,7 @@ DISubrangeType::convertRawToBound(Metadata *IN) const {
return BoundType();
assert(isa<ConstantAsMetadata>(IN) || isa<DIVariable>(IN) ||
- isa<DIExpression>(IN));
+ isa<DIExpression>(IN) || isa<DIDerivedType>(IN));
if (auto *MD = dyn_cast<ConstantAsMetadata>(IN))
return BoundType(cast<ConstantInt>(MD->getValue()));
@@ -850,6 +850,9 @@ DISubrangeType::convertRawToBound(Metadata *IN) const {
if (auto *MD = dyn_cast<DIExpression>(IN))
return BoundType(MD);
+ if (auto *DT = dyn_cast<DIDerivedType>(IN))
+ return BoundType(DT);
+
return BoundType();
}
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 7917712846990..9ca4025b3214a 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -1187,13 +1187,17 @@ void Verifier::visitDISubrangeType(const DISubrangeType &N) {
CheckDI(!BaseType || isType(BaseType), "BaseType must be a type");
auto *LBound = N.getRawLowerBound();
CheckDI(!LBound || isa<ConstantAsMetadata>(LBound) ||
- isa<DIVariable>(LBound) || isa<DIExpression>(LBound),
- "LowerBound must be signed constant or DIVariable or DIExpression",
+ isa<DIVariable>(LBound) || isa<DIExpression>(LBound) ||
+ isa<DIDerivedType>(LBound),
+ "LowerBound must be signed constant or DIVariable or DIExpression or "
+ "DIDerivedType",
&N);
auto *UBound = N.getRawUpperBound();
CheckDI(!UBound || isa<ConstantAsMetadata>(UBound) ||
- isa<DIVariable>(UBound) || isa<DIExpression>(UBound),
- "UpperBound must be signed constant or DIVariable or DIExpression",
+ isa<DIVariable>(UBound) || isa<DIExpression>(UBound) ||
+ isa<DIDerivedType>(UBound),
+ "UpperBound must be signed constant or DIVariable or DIExpression or "
+ "DIDerivedType",
&N);
auto *Stride = N.getRawStride();
CheckDI(!Stride || isa<ConstantAsMetadata>(Stride) ||
diff --git a/llvm/test/DebugInfo/X86/derived-in-subrange.ll b/llvm/test/DebugInfo/X86/derived-in-subrange.ll
new file mode 100644
index 0000000000000..fb4c1d4745feb
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/derived-in-subrange.ll
@@ -0,0 +1,88 @@
+; RUN: llvm-as < %s | llvm-dis | llc -mtriple=x86_64 -O0 -filetype=obj -o - | llvm-dwarfdump -v -debug-info - | FileCheck %s
+
+; A test to verify the use of a DIDerivedType as a bound of a
+; DISubrangeType.
+
+; CHECK: DW_TAG_array_type
+; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}
+; CHECK: DW_TAG_subrange_type {{.*}}
+; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] {{.*}}
+; CHECK-NEXT: DW_AT_upper_bound [DW_FORM_ref4] {{.*}}
+
+; ModuleID = 'vla.ads'
+source_filename = "vla.ads"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+%vla__array_type_FP = type { ptr, ptr }
+%vla__record_type_I = type <{ i32 }>
+
+@vla_E = dso_local global i16 0, align 2, !dbg !0
+
+; Function Attrs: inlinehint
+define dso_local void @vla__array_typeIP(%vla__array_type_FP %_init) #0 !dbg !10 {
+entry:
+ %0 = extractvalue %vla__array_type_FP %_init, 1, !dbg !15
+ %1 = call ptr @llvm.invariant.start.p0(i64 8, ptr %0), !dbg !15
+ ret void, !dbg !15
+}
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare ptr @llvm.invariant.start.p0(i64 immarg, ptr nocapture) #1
+
+; Function Attrs: inlinehint
+define dso_local void @vla__record_typeIP(ptr noalias nocapture nonnull %_init, i32 %l1) #0 !dbg !16 {
+entry:
+ #dbg_declare(ptr %_init, !31, !DIExpression(), !32)
+ #dbg_value(i32 %l1, !33, !DIExpression(), !34)
+ %0 = getelementptr inbounds %vla__record_type_I, ptr %_init, i32 0, i32 0, !dbg !32
+ store i32 %l1, ptr %0, align 4, !dbg !32, !tbaa !35
+ ret void, !dbg !32
+}
+
+attributes #0 = { inlinehint }
+attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+
+!llvm.module.flags = !{!6, !7, !8, !9}
+!llvm.dbg.cu = !{!2}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "vla_E", scope: !2, file: !3, line: 16, type: !5, isLocal: false, isDefinition: true, align: 16)
+!2 = distinct !DICompileUnit(language: DW_LANG_Ada95, file: !3, producer: "GNAT/LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false)
+!3 = !DIFile(filename: "vla.ads", directory: "")
+!4 = !{!0}
+!5 = !DIBasicType(name: "short_integer", size: 16, encoding: DW_ATE_signed)
+!6 = !{i32 8, !"PIC Level", i32 2}
+!7 = !{i32 7, !"PIE Level", i32 2}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{i32 2, !"Dwarf Version", i32 4}
+!10 = distinct !DISubprogram(name: "vla__array_typeIP", scope: !3, file: !3, line: 17, type: !11, scopeLine: 17, spFlags: DISPFlagDefinition, unit: !2)
+!11 = !DISubroutineType(types: !12)
+!12 = !{null, !13}
+!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64, align: 64, dwarfAddressSpace: 0)
+!14 = !DIBasicType(tag: DW_TAG_unspecified_type, name: "vla__array_type")
+!15 = !DILocation(line: 17, column: 9, scope: !10)
+!16 = distinct !DISubprogram(name: "vla__record_typeIP", scope: !3, file: !3, line: 18, type: !17, scopeLine: 18, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !30)
+!17 = !DISubroutineType(types: !18)
+!18 = !{null, !19, !23}
+!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64, align: 64, dwarfAddressSpace: 0)
+!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "vla__record_type", file: !3, line: 18, size: !DIExpression(DW_OP_push_object_address, DW_OP_deref_size, 4, DW_OP_constu, 32, DW_OP_mul, DW_OP_constu, 32, DW_OP_plus), align: 32, elements: !21, identifier: "vla__record_type")
+!21 = !{!22, !26}
+!22 = !DIDerivedType(tag: DW_TAG_member, name: "l1", file: !3, line: 18, baseType: !23)
+!23 = !DISubrangeType(name: "natural", file: !24, line: 1, size: 32, align: 32, baseType: !25, lowerBound: i64 0, upperBound: i64 2147483647)
+!24 = !DIFile(filename: "system.ads", directory: "/home/tromey/AdaCore/gnat-llvm/llvm-interface//lib/gnat-llvm/x86_64-unknown-linux-gnu/rts-native/adainclude/")
+!25 = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
+!26 = !DIDerivedType(tag: DW_TAG_member, name: "a1", file: !3, line: 19, baseType: !27, offset: 32)
+!27 = !DICompositeType(tag: DW_TAG_array_type, scope: !20, file: !3, line: 19, baseType: !25, align: 32, elements: !28)
+!28 = !{!29}
+!29 = !DISubrangeType(baseType: !25, lowerBound: i64 1, upperBound: !22)
+!30 = !{}
+!31 = !DILocalVariable(name: "_init", arg: 1, scope: !16, file: !3, line: 18, type: !20, flags: DIFlagArtificial)
+!32 = !DILocation(line: 18, column: 9, scope: !16)
+!33 = !DILocalVariable(name: "l1", arg: 2, scope: !16, file: !3, line: 18, type: !23, flags: DIFlagArtificial)
+!34 = !DILocation(line: 18, column: 22, scope: !16)
+!35 = !{!36, !36, i64 0, i64 4}
+!36 = !{!37, i64 4, !"natural#T5"}
+!37 = !{!38, i64 4, !"natural#TN"}
+!38 = !{!39, i64 4, !"integerB#TN"}
+!39 = !{!"Ada Root"}
|
|
Ping. |
Michael137
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For DW_TAG_subrange_types of VLAs we just emit a DW_AT_count which references a variable DIE, which holds the dynamic element count. But that's not helpful here because you have a non-zero lower bound (and the variable holding the bound is a member variable, which we never have for VLAs)? So you want the same for DW_AT_upper_bound but be able to refer to a member variable? That seems reasonable to me (especially if GCC does this too).
Could you briefly elaborate on this:
gnat-llvm can then arrange for the DIE reference to be correct by setting the array type's scope to be the record.
How does that help determine the dynamic length?
Yeah, basically. This particular change is about allowing an array bound to come from a "discriminant", which is a certain kind of field. In C terms it would be like if the In Ada, either or both bounds can be treated this way, because in Ada all array types specify the ranges of their indices.
This ensures that the member DIEs are written first, so that the array bounds can refer to them. |
Consider this Ada type:
Here, the array fields have lengths that depend on the discriminants of the record type. However, in this case the array lengths cannot be expressed as DWARF location expressions, with the issue being that "A2" has a non-constant offset, but an expression involving DW_OP_push_object_address will push the address of the field -- with no way to find the location of "L2".
In a case like this, I believe the correct DWARF is to emit the array ranges using a direct reference to the discriminant, like:
(FWIW this is what GCC has done for years.)
This patch makes this possible in LLVM, by letting a DISubrangeType refer to a DIDerivedType. gnat-llvm can then arrange for the DIE reference to be correct by setting the array type's scope to be the record.