Skip to content

Commit

Permalink
[DebugInfo] Add DebugTypeArrayDynamic translation (#1871)
Browse files Browse the repository at this point in the history
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:
KhronosGroup/SPIRV-Registry#186

Signed-off-by: Sidorov, Dmitry <dmitry.sidorov@intel.com>
  • Loading branch information
MrSidims authored Mar 8, 2023
1 parent a9f4f25 commit 7906823
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 8 deletions.
56 changes: 51 additions & 5 deletions lib/SPIRV/LLVMToSPIRVDbgTran.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,14 @@ SPIRVWord adjustAccessFlags(DIScope *Scope, SPIRVWord Flags) {
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.

Expand Down Expand Up @@ -561,8 +569,11 @@ SPIRVEntry *LLVMToSPIRVDbgTran::transDbgQualifiedType(const DIDerivedType *QT) {
}

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);
}
Expand All @@ -571,8 +582,7 @@ SPIRVEntry *
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
Expand Down Expand Up @@ -615,8 +625,7 @@ SPIRVEntry *
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
Expand All @@ -635,6 +644,43 @@ LLVMToSPIRVDbgTran::transDbgArrayTypeNonSemantic(const DICompositeType *AT) {
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);
Expand Down
1 change: 1 addition & 0 deletions lib/SPIRV/LLVMToSPIRVDbgTran.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class LLVMToSPIRVDbgTran {
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);
Expand Down
46 changes: 45 additions & 1 deletion lib/SPIRV/SPIRVToLLVMDbgTran.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ SPIRVToLLVMDbgTran::transTypeArrayNonSemantic(const SPIRVExtInst *DebugInst) {
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);
}
}
Expand All @@ -282,6 +282,47 @@ SPIRVToLLVMDbgTran::transTypeArrayNonSemantic(const SPIRVExtInst *DebugInst) {
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;
Expand Down Expand Up @@ -1037,6 +1078,9 @@ MDNode *SPIRVToLLVMDbgTran::transDebugInstImpl(const SPIRVExtInst *DebugInst) {
case SPIRVDebug::Expression:
return transExpression(DebugInst);

case SPIRVDebug::TypeArrayDynamic:
return transTypeArrayDynamic(DebugInst);

default:
llvm_unreachable("Not implemented SPIR-V debug instruction!");
}
Expand Down
1 change: 1 addition & 0 deletions lib/SPIRV/SPIRVToLLVMDbgTran.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class SPIRVToLLVMDbgTran {
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);

Expand Down
15 changes: 14 additions & 1 deletion lib/SPIRV/libSPIRV/SPIRV.debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ enum Instruction {
Source = 35,
ModuleINTEL = 36,
InstCount = 37,
TypeSubrange = 110
TypeSubrange = 110,
TypeArrayDynamic = 202
};

enum Flag {
Expand Down Expand Up @@ -330,6 +331,18 @@ enum {
};
}

namespace TypeArrayDynamic {
enum {
BaseTypeIdx = 0,
DataLocationIdx = 1,
AssociatedIdx = 2,
AllocatedIdx = 3,
RankIdx = 4,
SubrangesIdx = 5,
MinOperandCount = 6
};
}

namespace TypeVector = TypeArray;

namespace TypeSubrange {
Expand Down
1 change: 1 addition & 0 deletions lib/SPIRV/libSPIRV/SPIRVExtInst.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ template <> inline void SPIRVMap<SPIRVDebugExtOpKind, std::string>::init() {
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");
Expand Down
5 changes: 4 additions & 1 deletion test/DebugInfo/NonSemanticKernel100/FortranArray.ll
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
; 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"
Expand Down
81 changes: 81 additions & 0 deletions test/DebugInfo/NonSemanticKernel100/FortranDynamicArrayExpr.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
;; 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)

Loading

0 comments on commit 7906823

Please sign in to comment.