This instruction describes a dynamic array, mostly for Fortran 90.
Unlike DebugTypeArray it has Data Location, Associated, Allocated
and Rank parameters. If the appropriate metadata parameters
appear in LLVM IR in DW_TAG_array_type metadata, then such
debug type becomes treated as dynamic array by the translator
(of course if the appropriate extended instruction set is enabled).
Spec:
https://github.com/KhronosGroup/SPIRV-Registry/pull/186
Signed-off-by: Sidorov, Dmitry <dmitry.sidorov@intel.com>
Gbp-Pq: Name 0022-Backport-to-15-DebugInfo-Add-DebugTypeArrayDynamic-t.patch
return Flags;
}
+// Fortran dynamic arrays can have following 'dataLocation', 'associated'
+// 'allocated' and 'rank' debug metadata. Such arrays are being mapped on
+// DebugTypeArrayDynamic from NonSemantic.Kernel.100 debug spec
+inline bool isFortranArrayDynamic(const DICompositeType *AT) {
+ return (AT->getRawDataLocation() || AT->getRawAssociated() ||
+ AT->getRawAllocated() || AT->getRawRank());
+}
+
/// The following methods (till the end of the file) implement translation of
/// debug instrtuctions described in the spec.
}
SPIRVEntry *LLVMToSPIRVDbgTran::transDbgArrayType(const DICompositeType *AT) {
- if (BM->getDebugInfoEIS() == SPIRVEIS_NonSemantic_Kernel_DebugInfo_100)
+ if (BM->getDebugInfoEIS() == SPIRVEIS_NonSemantic_Kernel_DebugInfo_100) {
+ if (isFortranArrayDynamic(AT))
+ return transDbgArrayTypeDynamic(AT);
return transDbgArrayTypeNonSemantic(AT);
+ }
return transDbgArrayTypeOpenCL(AT);
}
LLVMToSPIRVDbgTran::transDbgArrayTypeOpenCL(const DICompositeType *AT) {
using namespace SPIRVDebug::Operand::TypeArray;
SPIRVWordVec Ops(MinOperandCount);
- SPIRVEntry *Base = transDbgEntry(AT->getBaseType());
- Ops[BaseTypeIdx] = Base->getId();
+ Ops[BaseTypeIdx] = transDbgEntry(AT->getBaseType())->getId();
DINodeArray AR(AT->getElements());
// For N-dimensianal arrays AR.getNumElements() == N
LLVMToSPIRVDbgTran::transDbgArrayTypeNonSemantic(const DICompositeType *AT) {
using namespace SPIRVDebug::Operand::TypeArray;
SPIRVWordVec Ops(MinOperandCount);
- SPIRVEntry *Base = transDbgEntry(AT->getBaseType());
- Ops[BaseTypeIdx] = Base->getId();
+ Ops[BaseTypeIdx] = transDbgEntry(AT->getBaseType())->getId();
DINodeArray AR(AT->getElements());
// For N-dimensianal arrays AR.getNumElements() == N
return BM->addDebugInfo(SPIRVDebug::TypeArray, getVoidTy(), Ops);
}
+// The function is used to translate Fortran's dynamic arrays
+SPIRVEntry *
+LLVMToSPIRVDbgTran::transDbgArrayTypeDynamic(const DICompositeType *AT) {
+ using namespace SPIRVDebug::Operand::TypeArrayDynamic;
+ SPIRVWordVec Ops(MinOperandCount);
+ Ops[BaseTypeIdx] = transDbgEntry(AT->getBaseType())->getId();
+
+ // DataLocation, Associated, Allocated and Rank can be either DIExpression
+ // metadata or DIVariable
+ auto TransOperand = [&](llvm::Metadata *DIMD) -> SPIRVWord {
+ if (auto *DIExpr = dyn_cast_or_null<DIExpression>(DIMD))
+ return transDbgExpression(DIExpr)->getId();
+ if (auto *DIVar = dyn_cast_or_null<DIVariable>(DIMD)) {
+ if (const DILocalVariable *LV = dyn_cast<DILocalVariable>(DIVar))
+ return transDbgLocalVariable(LV)->getId();
+ if (const DIGlobalVariable *GV = dyn_cast<DIGlobalVariable>(DIVar))
+ return transDbgGlobalVariable(GV)->getId();
+ }
+ return getDebugInfoNoneId();
+ };
+
+ Ops[DataLocationIdx] = TransOperand(AT->getRawDataLocation());
+ Ops[AssociatedIdx] = TransOperand(AT->getRawAssociated());
+ Ops[AllocatedIdx] = TransOperand(AT->getRawAllocated());
+ Ops[RankIdx] = TransOperand(AT->getRawRank());
+
+ DINodeArray AR(AT->getElements());
+ // For N-dimensianal arrays AR.getNumElements() == N
+ const unsigned N = AR.size();
+ Ops.resize(SubrangesIdx + N);
+ for (unsigned I = 0; I < N; ++I) {
+ DISubrange *SR = cast<DISubrange>(AR[I]);
+ Ops[SubrangesIdx + I] = transDbgEntry(SR)->getId();
+ }
+ return BM->addDebugInfo(SPIRVDebug::TypeArrayDynamic, getVoidTy(), Ops);
+}
+
SPIRVEntry *LLVMToSPIRVDbgTran::transDbgSubrangeType(const DISubrange *ST) {
using namespace SPIRVDebug::Operand::TypeSubrange;
SPIRVWordVec Ops(OperandCount);
SPIRVEntry *transDbgArrayType(const DICompositeType *AT);
SPIRVEntry *transDbgArrayTypeOpenCL(const DICompositeType *AT);
SPIRVEntry *transDbgArrayTypeNonSemantic(const DICompositeType *AT);
+ SPIRVEntry *transDbgArrayTypeDynamic(const DICompositeType *AT);
SPIRVEntry *transDbgSubrangeType(const DISubrange *ST);
SPIRVEntry *transDbgTypeDef(const DIDerivedType *D);
SPIRVEntry *transDbgSubroutineType(const DISubroutineType *FT);
for (size_t I = SubrangesIdx; I < Ops.size(); ++I) {
auto *SR = transDebugInst<DISubrange>(BM->get<SPIRVExtInst>(Ops[I]));
if (auto *Count = SR->getCount().get<ConstantInt *>())
- TotalCount *= Count->getZExtValue() > 0 ? Count->getZExtValue() : 0;
+ TotalCount *= Count->getSExtValue() > 0 ? Count->getSExtValue() : 0;
Subscripts.push_back(SR);
}
}
return Builder.createArrayType(Size, 0 /*align*/, BaseTy, SubscriptArray);
}
+DICompositeType *
+SPIRVToLLVMDbgTran::transTypeArrayDynamic(const SPIRVExtInst *DebugInst) {
+ using namespace SPIRVDebug::Operand::TypeArrayDynamic;
+ const SPIRVWordVec &Ops = DebugInst->getArguments();
+ assert(Ops.size() >= MinOperandCount && "Invalid number of operands");
+ DIType *BaseTy =
+ transDebugInst<DIType>(BM->get<SPIRVExtInst>(Ops[BaseTypeIdx]));
+ size_t TotalCount = 1;
+ SmallVector<llvm::Metadata *, 8> Subscripts;
+ for (size_t I = SubrangesIdx; I < Ops.size(); ++I) {
+ auto *SR = transDebugInst<DISubrange>(BM->get<SPIRVExtInst>(Ops[I]));
+ if (auto *Count = SR->getCount().get<ConstantInt *>())
+ TotalCount *= Count->getSExtValue() > 0 ? Count->getSExtValue() : 0;
+ Subscripts.push_back(SR);
+ }
+ DINodeArray SubscriptArray = Builder.getOrCreateArray(Subscripts);
+ size_t Size = getDerivedSizeInBits(BaseTy) * TotalCount;
+
+ auto TransOperand = [&](SPIRVWord Idx) -> PointerUnion<DIExpression *,
+ DIVariable *> {
+ if (!getDbgInst<SPIRVDebug::DebugInfoNone>(Ops[Idx])) {
+ if (const auto *GV = getDbgInst<SPIRVDebug::GlobalVariable>(Ops[Idx]))
+ return transDebugInst<DIGlobalVariable>(GV);
+ if (const auto *LV = getDbgInst<SPIRVDebug::LocalVariable>(Ops[Idx]))
+ return transDebugInst<DILocalVariable>(LV);
+ if (const auto *DIExpr = getDbgInst<SPIRVDebug::Expression>(Ops[Idx]))
+ return transDebugInst<DIExpression>(DIExpr);
+ }
+ return nullptr;
+ };
+ PointerUnion<DIExpression *, DIVariable *> DataLocation =
+ TransOperand(DataLocationIdx);
+ PointerUnion<DIExpression *, DIVariable *> Associated =
+ TransOperand(AssociatedIdx);
+ PointerUnion<DIExpression *, DIVariable *> Allocated =
+ TransOperand(AllocatedIdx);
+ PointerUnion<DIExpression *, DIVariable *> Rank = TransOperand(RankIdx);
+ return Builder.createArrayType(Size, 0 /*align*/, BaseTy, SubscriptArray,
+ DataLocation, Associated, Allocated, Rank);
+}
+
DICompositeType *
SPIRVToLLVMDbgTran::transTypeVector(const SPIRVExtInst *DebugInst) {
using namespace SPIRVDebug::Operand::TypeVector;
case SPIRVDebug::Expression:
return transExpression(DebugInst);
+ case SPIRVDebug::TypeArrayDynamic:
+ return transTypeArrayDynamic(DebugInst);
+
default:
llvm_unreachable("Not implemented SPIR-V debug instruction!");
}
DICompositeType *transTypeArray(const SPIRVExtInst *DebugInst);
DICompositeType *transTypeArrayOpenCL(const SPIRVExtInst *DebugInst);
DICompositeType *transTypeArrayNonSemantic(const SPIRVExtInst *DebugInst);
+ DICompositeType *transTypeArrayDynamic(const SPIRVExtInst *DebugInst);
DICompositeType *transTypeVector(const SPIRVExtInst *DebugInst);
Source = 35,
ModuleINTEL = 36,
InstCount = 37,
- TypeSubrange = 110
+ TypeSubrange = 110,
+ TypeArrayDynamic = 202
};
enum Flag {
};
}
+namespace TypeArrayDynamic {
+enum {
+ BaseTypeIdx = 0,
+ DataLocationIdx = 1,
+ AssociatedIdx = 2,
+ AllocatedIdx = 3,
+ RankIdx = 4,
+ SubrangesIdx = 5,
+ MinOperandCount = 6
+};
+}
+
namespace TypeVector = TypeArray;
namespace TypeSubrange {
add(SPIRVDebug::TypeBasic, "DebugTypeBasic");
add(SPIRVDebug::TypePointer, "DebugTypePointer");
add(SPIRVDebug::TypeArray, "DebugTypeArray");
+ add(SPIRVDebug::TypeArrayDynamic, "DebugTypeArrayDynamic");
add(SPIRVDebug::TypeVector, "DebugTypeVector");
add(SPIRVDebug::TypeQualifier, "DebugTypeQualifier");
add(SPIRVDebug::TypeFunction, "DebugTypeFunction");
; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefix=CHECK-LLVM
; CHECK-LLVM: !DICompileUnit(language: DW_LANG_Fortran95
-; CHECK-LLVM: !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref, DW_OP_push_object_address, DW_OP_plus_uconst, 48, DW_OP_deref, DW_OP_plus, DW_OP_constu, 1, DW_OP_minus), stride: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 56, DW_OP_deref))
+; CHECK-LLVM: !DICompositeType(tag: DW_TAG_array_type, baseType: ![[#BaseT:]], size: 32, elements: ![[#Elements:]], dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref), associated: !DIExpression(DW_OP_push_object_address, DW_OP_deref, DW_OP_constu, 0, DW_OP_or))
+; CHECK-LLVM: ![[#BaseT:]] = !DIBasicType(name: "INTEGER*4", size: 32, encoding: DW_ATE_signed)
+; CHECK-LLVM: ![[#Elements]] = !{![[#SubRange:]]}
+; CHECK-LLVM: ![[#SubRange]] = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref, DW_OP_push_object_address, DW_OP_plus_uconst, 48, DW_OP_deref, DW_OP_plus, DW_OP_constu, 1, DW_OP_minus), stride: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 56, DW_OP_deref))
source_filename = "llvm-link"
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
--- /dev/null
+;; The test checks, that Fortran dynamic arrays are being correctly represented
+;; by SPIR-V debug information
+;; Unlike 'static' arrays dynamic can have following parameters of
+;; DICompositeType metadata with DW_TAG_array_type tag:
+;; Data Location, Associated, Allocated and Rank which can be represented
+;; by either DIExpression or DIVariable (both local and global).
+;; This test if for expression representation.
+;; FortranDynamicArrayVar.ll is for variable representation.
+
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-spirv %t.bc -spirv-text --spirv-debug-info-version=nonsemantic-kernel-100 -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llvm-spirv %t.bc -o %t.spv --spirv-debug-info-version=nonsemantic-kernel-100
+; RUN: llvm-spirv -r -emit-opaque-pointers %t.spv -o %t.rev.bc
+; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefix=CHECK-LLVM
+
+; CHECK-SPIRV-DAG: ExtInstImport [[#Import:]] "NonSemantic.Kernel.DebugInfo.100"
+; CHECK-SPIRV-DAG: String [[#BasicTName:]] "INTEGER*4"
+; CHECK-SPIRV-DAG: TypeInt [[#Int32T:]] 32 0
+; CHECK-SPIRV-DAG: Constant [[#Int32T]] [[#IntConst:]] 32
+; CHECK-SPIRV-DAG: TypeVoid [[#VoidT:]]
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgInfoNone:]] [[#Import]] DebugInfoNone
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#ArrayBasicT:]] [[#Import]] DebugTypeBasic [[#BasicTName]] [[#IntConst]] 4
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgExprLocation:]] [[#Import]] DebugExpression [[#]] [[#]] {{$}}
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgExprAssociated:]] [[#Import]] DebugExpression [[#]] [[#]] [[#]] [[#]] {{$}}
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgExprLowerBound:]] [[#Import]] DebugExpression [[#]] [[#]] [[#]] {{$}}
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgExprUpperBound:]] [[#Import]] DebugExpression [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] {{$}}
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgExprCount:]] [[#Import]] DebugExpression [[#]] [[#]] [[#]] {{$}}
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgSubRangeId:]] [[#Import]] DebugTypeSubrange [[#DbgInfoNone]] [[#DbgExprLowerBound]] [[#DbgExprUpperBound]] [[#DbgExprCount]]
+; CHECK-SPIRV: ExtInst [[#VoidT]] [[#DbgArrayId:]] [[#Import]] DebugTypeArrayDynamic [[#ArrayBasicT]] [[#DbgExprLocation]] [[#DbgExprAssociated]] [[#DbgInfoNone]] [[#DbgInfoNone]] [[#DbgSubRangeId]]
+
+; CHECK-LLVM: %[[#Array:]] = alloca
+; CHECK-LLVM: call void @llvm.dbg.value(metadata ptr %[[#Array]], metadata ![[#DbgLVar:]]
+; CHECK-LLVM: ![[#DbgLVar]] = !DILocalVariable(name: "pint", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[#DbgLVarT:]])
+; CHECK-LLVM: ![[#DbgLVarT]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#DbgArrayT:]], size: 64)
+; CHECK-LLVM: ![[#DbgArrayT]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[#DbgArrayBaseT:]], size: 32, elements: ![[#Elements:]], dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref), associated: !DIExpression(DW_OP_push_object_address, DW_OP_deref, DW_OP_constu, 0, DW_OP_or))
+; CHECK-LLVM: ![[#DbgArrayBaseT]] = !DIBasicType(name: "INTEGER*4", size: 32, encoding: DW_ATE_signed)
+; CHECK-LLVM: ![[#Elements]] = !{![[#SubRange:]]}
+; CHECK-LLVM: ![[#SubRange]] = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref, DW_OP_push_object_address, DW_OP_plus_uconst, 48, DW_OP_deref, DW_OP_plus, DW_OP_constu, 1, DW_OP_minus), stride: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 56, DW_OP_deref))
+
+
+; ModuleID = 'reproducer.ll'
+source_filename = "test.f90"
+target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
+target triple = "spir64"
+
+%qnca = type { i32 addrspace(4)*, i64, i64, i64, i64, i64, [1 x { i64, i64, i64 }] }
+
+; Function Attrs: noinline nounwind optnone
+define weak dso_local spir_kernel void @TEST() #0 !dbg !5 {
+newFuncRoot:
+ %0 = alloca %qnca, align 8
+ call void @llvm.dbg.value(metadata %qnca* %0, metadata !8, metadata !DIExpression()), !dbg !14
+ ret void
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+attributes #0 = { noinline nounwind optnone }
+attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.dbg.cu = !{!2}
+!spirv.Source = !{!4}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{i32 2, !"Dwarf Version", i32 4}
+!2 = distinct !DICompileUnit(language: DW_LANG_Fortran95, file: !3, producer: "fortran", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+!3 = !DIFile(filename: "test.f90", directory: "/path/to")
+!4 = !{i32 4, i32 200000}
+!5 = distinct !DISubprogram(name: "test", linkageName: "MAIN__", scope: !3, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2)
+!6 = !DISubroutineType(types: !7)
+!7 = !{null}
+!8 = !DILocalVariable(name: "pint", scope: !5, file: !3, line: 3, type: !9)
+!9 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
+!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, elements: !12, dataLocation: !DIExpression(DW_OP_push_object_address, DW_OP_deref), associated: !DIExpression(DW_OP_push_object_address, DW_OP_deref, DW_OP_constu, 0, DW_OP_or))
+!11 = !DIBasicType(name: "INTEGER*4", size: 32, encoding: DW_ATE_signed)
+!12 = !{!13}
+!13 = !DISubrange(lowerBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref), upperBound: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 64, DW_OP_deref, DW_OP_push_object_address, DW_OP_plus_uconst, 48, DW_OP_deref, DW_OP_plus, DW_OP_constu, 1, DW_OP_minus), stride: !DIExpression(DW_OP_push_object_address, DW_OP_plus_uconst, 56, DW_OP_deref))
+!14 = !DILocation(line: 1, scope: !5)
+
--- /dev/null
+;; DebugInfo/dwarfdump-dataLocationVar.ll from llvm.org is used as base for this test
+;; The test checks, that Fortran dynamic arrays are being correctly represented
+;; by SPIR-V debug information
+;; Unlike 'static' arrays dynamic can have following parameters of
+;; DICompositeType metadata with DW_TAG_array_type tag:
+;; Data Location, Associated, Allocated and Rank which can be represented
+;; by either DIExpression or DIVariable (both local and global).
+;; This test if for variable representation.
+;; FortranDynamicArrayVar.ll is for expression representation.
+
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-spirv %t.bc -spirv-text --spirv-debug-info-version=nonsemantic-kernel-100 -o - | FileCheck %s --check-prefix=CHECK-SPIRV
+; RUN: llvm-spirv %t.bc -o %t.spv --spirv-debug-info-version=nonsemantic-kernel-100
+; RUN: llvm-spirv -r -emit-opaque-pointers %t.spv -o %t.rev.bc
+; RUN: llvm-dis %t.rev.bc -o - | FileCheck %s --check-prefix=CHECK-LLVM
+
+;; Major SPIR-V checks are done in FortranDynamicArrayExpr.ll
+; CHECK-SPIRV: ExtInst [[#]] [[#DbgLVarId:]] [[#]] DebugLocalVariable [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] [[#]] {{$}}
+; CHECK-SPIRV: ExtInst [[#]] [[#]] [[#]] DebugTypeArrayDynamic [[#]] [[#DbgLVarId]] [[#]] [[#]] [[#]] [[#]]
+
+; CHECK-LLVM: %[[#Ptr:]] = alloca ptr
+; CHECK-LLVM: %[[#Array:]] = alloca [16 x i64]
+; CHECK-LLVM: call void @llvm.dbg.declare(metadata ptr %[[#Array]], metadata ![[#DbgLVarArray:]]
+; CHECK-LLVM: call void @llvm.dbg.declare(metadata ptr %[[#Ptr]], metadata ![[#DbgLVarPtr:]]
+
+; CHECK-LLVM: ![[#DbgLVarPtr:]] = !DILocalVariable(scope: ![[#]], file: ![[#]], type: ![[#DbgPtrT:]], flags: DIFlagArtificial)
+; CHECK-LLVM: ![[#DbgPtrT:]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[#DbgBasicT:]], size: 64)
+; CHECK-LLVM: ![[#DbgBasicT]] = !DIBasicType(name: "integer", size: 32, encoding: DW_ATE_signed)
+; CHECK-LLVM: ![[#DbgLVarArray]] = !DILocalVariable(name: "arr", scope: ![[#]], file: ![[#]], type: ![[#DbgArrayT:]])
+; CHECK-LLVM: ![[#DbgArrayT]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[#DbgBasicT]], size: 608, elements: ![[#Elements:]], dataLocation: ![[#DbgLVarPtr]])
+; CHECK-LLVM: ![[#Elements]] = !{![[#SubRange:]]}
+; CHECK-LLVM: ![[#SubRange]] = !DISubrange(count: 19, lowerBound: 2)
+
+; ModuleID = 'fortsubrange.ll'
+source_filename = "fortsubrange.ll"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "spir64-unknown-unknown"
+
+define spir_func void @foo() !dbg !5 {
+L.entry:
+ %0 = alloca ptr, align 8
+ %1 = alloca [16 x i64], align 8
+ call void @llvm.dbg.declare(metadata ptr %1, metadata !8, metadata !DIExpression()), !dbg !16
+ call void @llvm.dbg.declare(metadata ptr %0, metadata !14, metadata !DIExpression()), !dbg !16
+ ret void, !dbg !17
+}
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.declare(metadata, metadata, metadata)
+
+; Function Attrs: nounwind readnone speculatable willreturn
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+
+!llvm.module.flags = !{!0, !1}
+!llvm.dbg.cu = !{!2}
+
+!0 = !{i32 2, !"Dwarf Version", i32 4}
+!1 = !{i32 2, !"Debug Info Version", i32 3}
+!2 = distinct !DICompileUnit(language: DW_LANG_Fortran90, file: !3, producer: " F90 Flang - 1.5 2017-05-01", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !4, globals: !4, imports: !4)
+!3 = !DIFile(filename: "fortsubrange.f90", directory: "/dir")
+!4 = !{}
+!5 = distinct !DISubprogram(name: "main", scope: !2, file: !3, line: 1, type: !6, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagMainSubprogram, unit: !2)
+!6 = !DISubroutineType(cc: DW_CC_program, types: !7)
+!7 = !{null}
+!8 = !DILocalVariable(name: "arr", scope: !9, file: !3, type: !10)
+!9 = !DILexicalBlock(scope: !5, file: !3, line: 1, column: 1)
+!10 = !DICompositeType(tag: DW_TAG_array_type, baseType: !11, size: 32, align: 32, elements: !12, dataLocation: !14)
+!11 = !DIBasicType(name: "integer", size: 32, align: 32, encoding: DW_ATE_signed)
+!12 = !{!13}
+!13 = !DISubrange(count: 19, lowerBound: 2)
+!14 = distinct !DILocalVariable(scope: !9, file: !3, type: !15, flags: DIFlagArtificial)
+!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 32, align: 32)
+!16 = !DILocation(line: 0, scope: !9)
+!17 = !DILocation(line: 6, column: 1, scope: !9)