[llvm] [SPIR-V] Emit 64-bit OpConstant for wide debug sizes and offsets (PR #223678)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 07:06:26 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/223678
>From a9334bf7e017e94432b87a34d7a38922b92f55ed Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 15 Sep 2026 14:36:47 +0200
Subject: [PATCH 1/2] [SPIR-V] Emit 64-bit OpConstant for wide debug sizes and
offsets
A size or offset above 4 GiB was truncated to 32 bits
---
.../SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp | 2 +-
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 111 ++++++++++++++----
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 29 ++++-
.../SPIRV/debug-info/debug-type-composite.ll | 29 ++++-
4 files changed, 138 insertions(+), 33 deletions(-)
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index 8a2618b5309a9..a0fd1187143b6 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -81,7 +81,7 @@ void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
// Handle 64 bit literals.
if (NumVarOps == 2) {
- Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32);
+ Imm = Make_64(MI->getOperand(StartIndex + 1).getImm(), Imm);
}
// Format and print float values.
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index 55ea4bc365d8d..f41a528853dfc 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -338,6 +338,7 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
DebugSourceRegByFileStr.clear();
OpStringContentCache.clear();
I32ConstantCache.clear();
+ I64ConstantCache.clear();
DebugTypeFunctionCache.clear();
DebugOperationCache.clear();
DebugExpressionCache.clear();
@@ -350,7 +351,7 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
CachedDebugInfoNoneReg = MCRegister();
CachedEmptyStringReg = MCRegister();
CachedOpTypeVoidReg = MCRegister();
- CachedOpTypeInt32Reg = MCRegister();
+ CachedOpTypeIntRegs.clear();
// Collect compile-unit info: file paths and source languages.
for (const DICompileUnit *CU : M->debug_compile_units()) {
@@ -441,6 +442,30 @@ void SPIRVNonSemanticDebugHandler::prepareModuleOutput(
// fresh result ID for it now; the same ID is used in emitExtInst() operands.
if (!MAI.ExtInstSetMap.count(NSSet))
MAI.ExtInstSetMap[NSSet] = MAI.getNextIDRegister();
+
+ // Capabilities are output before the debug info, so settle Int64 here.
+ if (needsI64SizeOrOffsetConstants())
+ MAI.Reqs.addCapability(SPIRV::Capability::Int64);
+}
+
+bool SPIRVNonSemanticDebugHandler::needsI64SizeOrOffsetConstants() const {
+ for (const DIBasicType *BT : BasicTypes)
+ if (!isUInt<32>(BT->getSizeInBits()))
+ return true;
+
+ for (const DICompositeType *CT : CompositeTypes) {
+ if (!CT->isForwardDecl() && !isUInt<32>(CT->getSizeInBits()))
+ return true;
+ for (const DINode *Element : CT->getElements()) {
+ const auto *M = dyn_cast<DIDerivedType>(Element);
+ if (!M || M->getTag() != dwarf::DW_TAG_member)
+ continue;
+ if (!isUInt<32>(M->getOffsetInBits()) || !isUInt<32>(M->getSizeInBits()))
+ return true;
+ }
+ }
+
+ return false;
}
void SPIRVNonSemanticDebugHandler::emitMCInst(MCInst &Inst) {
@@ -526,6 +551,34 @@ MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
return Reg;
}
+MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI64(
+ uint64_t Value, SPIRV::ModuleAnalysisInfo &MAI) {
+ MCRegister I64TypeReg = getOrEmitOpTypeIntReg(64, MAI);
+
+ auto [It, Inserted] = I64ConstantCache.try_emplace(Value);
+ if (!Inserted)
+ return It->second;
+
+ MCRegister Reg = MAI.getNextIDRegister();
+ It->second = Reg;
+ MCInst Inst;
+ Inst.setOpcode(SPIRV::OpConstantI);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createReg(I64TypeReg));
+ // SPIR-V encodes a 64-bit literal as two 32-bit words, low word first.
+ Inst.addOperand(MCOperand::createImm(Lo_32(Value)));
+ Inst.addOperand(MCOperand::createImm(Hi_32(Value)));
+ emitMCInst(Inst);
+ return Reg;
+}
+
+MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantSizeOrOffset(
+ uint64_t Value, MCRegister I32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
+ if (isUInt<32>(Value))
+ return emitOpConstantI32(static_cast<uint32_t>(Value), I32TypeReg, MAI);
+ return emitOpConstantI64(Value, MAI);
+}
+
MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
@@ -564,11 +617,18 @@ MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
return CachedOpTypeVoidReg;
}
-MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
- SPIRV::ModuleAnalysisInfo &MAI) {
- if (!CachedOpTypeInt32Reg.isValid())
- CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
- return CachedOpTypeInt32Reg;
+MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeIntReg(
+ unsigned Width, SPIRV::ModuleAnalysisInfo &MAI) {
+ assert((Width == 32 || llvm::is_contained(MAI.Reqs.getMinimalCapabilities(),
+ SPIRV::Capability::Int64)) &&
+ "OpTypeInt emitted for a width whose capability was not requested in "
+ "prepareModuleOutput()");
+ MCRegister Reg = CachedOpTypeIntRegs.lookup(Width);
+ if (!Reg.isValid()) {
+ Reg = findOrEmitOpTypeInt(Width, MAI);
+ CachedOpTypeIntRegs[Width] = Reg;
+ }
+ return Reg;
}
MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
@@ -585,19 +645,19 @@ MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
return Reg;
}
-MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
- SPIRV::ModuleAnalysisInfo &MAI) {
+MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt(
+ unsigned Width, SPIRV::ModuleAnalysisInfo &MAI) {
for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars)) {
if (MI->getOpcode() == SPIRV::OpTypeInt &&
- MI->getOperand(1).getImm() == 32 && MI->getOperand(2).getImm() == 0)
+ MI->getOperand(1).getImm() == Width && MI->getOperand(2).getImm() == 0)
return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
}
MCRegister Reg = MAI.getNextIDRegister();
MCInst Inst;
Inst.setOpcode(SPIRV::OpTypeInt);
Inst.addOperand(MCOperand::createReg(Reg));
- Inst.addOperand(MCOperand::createImm(32)); // width
- Inst.addOperand(MCOperand::createImm(0)); // signedness (unsigned)
+ Inst.addOperand(MCOperand::createImm(Width));
+ Inst.addOperand(MCOperand::createImm(0)); // signedness (unsigned)
emitMCInst(Inst);
return Reg;
}
@@ -611,7 +671,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
return std::nullopt;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
MCRegister DebugTypePointerFlagsReg =
emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
@@ -646,7 +706,7 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
const DISubroutineType *ST, MCRegister ExtInstSetReg,
SPIRV::ModuleAnalysisInfo &MAI) {
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
MCRegister DebugTypeFunctionFlagsReg =
emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
DITypeArray TA = ST->getTypeArray();
@@ -1081,11 +1141,13 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
return std::nullopt;
const auto *SR = cast<DISubrange>(Elements[0]);
const auto *CI = dyn_cast_if_present<ConstantInt *>(SR->getCount());
- if (!CI)
+ // Component Count is a 32-bit OpConstant, so a wider count cannot be
+ // encoded. Truncating it would silently describe a different vector.
+ if (!CI || CI->getValue().getActiveBits() > 32)
return std::nullopt;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
MCRegister CountReg = emitOpConstantI32(
static_cast<uint32_t>(CI->getZExtValue()), I32TypeReg, MAI);
return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
@@ -1102,7 +1164,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
return std::nullopt;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
SmallVector<MCRegister> Ops;
Ops.push_back(*BaseRegOpt);
@@ -1150,10 +1212,10 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
// DIDerivedType members carry no column, so emit 0.
MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
- MCRegister OffsetReg = emitOpConstantI32(
- static_cast<uint32_t>(M->getOffsetInBits()), I32TypeReg, MAI);
- MCRegister SizeReg = emitOpConstantI32(
- static_cast<uint32_t>(M->getSizeInBits()), I32TypeReg, MAI);
+ MCRegister OffsetReg =
+ emitOpConstantSizeOrOffset(M->getOffsetInBits(), I32TypeReg, MAI);
+ MCRegister SizeReg =
+ emitOpConstantSizeOrOffset(M->getSizeInBits(), I32TypeReg, MAI);
MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(M), I32TypeReg, MAI);
// In NonSemantic.Shader.DebugInfo a DebugTypeMember has no Parent operand:
@@ -1196,8 +1258,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
// A forward declaration has no known size or members: Size is DebugInfoNone.
MCRegister SizeReg = CachedDebugInfoNoneReg;
if (!CT->isForwardDecl())
- SizeReg = emitOpConstantI32(static_cast<uint32_t>(CT->getSizeInBits()),
- I32TypeReg, MAI);
+ SizeReg = emitOpConstantSizeOrOffset(CT->getSizeInBits(), I32TypeReg, MAI);
MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI);
@@ -1737,7 +1798,7 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
CurrentMAI = &MAI;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
VoidTypeReg, ExtInstSetReg, {}, MAI);
@@ -1785,8 +1846,8 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
for (const DIBasicType *BT : BasicTypes) {
MCRegister NameReg = getCachedOpStringReg(BT->getName());
- MCRegister SizeReg = emitOpConstantI32(
- static_cast<uint32_t>(BT->getSizeInBits()), I32TypeReg, MAI);
+ MCRegister SizeReg =
+ emitOpConstantSizeOrOffset(BT->getSizeInBits(), I32TypeReg, MAI);
// Map DWARF base type encodings to NSDI encoding codes per
// NonSemantic.Shader.DebugInfo.100 specification, section 4.5.
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index 16e4dd3cb8e3b..44006f76117ff 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -152,12 +152,16 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
MCRegister CachedOpTypeVoidReg;
- MCRegister CachedOpTypeInt32Reg;
+ // OpTypeInt <width> 0 ids for this module.
+ SmallDenseMap<unsigned, MCRegister, 2> CachedOpTypeIntRegs;
// Cache of already-emitted i32 constants, keyed by value. Prevents
// duplicate OpConstant instructions for the same integer value.
DenseMap<uint32_t, MCRegister> I32ConstantCache;
+ // Same, for size and offset operands that do not fit in 32 bits.
+ DenseMap<uint64_t, MCRegister> I64ConstantCache;
+
// Cache of already-emitted DebugTypeFunction instructions, keyed by operand
// ids (flags, return type, parameters).
DenseMap<SmallVector<MCRegister, 8>, MCRegister> DebugTypeFunctionCache;
@@ -306,6 +310,12 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
bool UseEmptyPathIfNullScope = false);
MCRegister emitOpConstantI32(uint32_t Value, MCRegister I32TypeReg,
SPIRV::ModuleAnalysisInfo &MAI);
+
+ MCRegister emitOpConstantI64(uint64_t Value, SPIRV::ModuleAnalysisInfo &MAI);
+
+ /// Size and offset operands accept a 32-bit or a 64-bit integer OpConstant.
+ MCRegister emitOpConstantSizeOrOffset(uint64_t Value, MCRegister I32TypeReg,
+ SPIRV::ModuleAnalysisInfo &MAI);
MCRegister emitExtInst(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
ArrayRef<MCRegister> Operands,
@@ -321,16 +331,23 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
/// Return OpTypeVoid id for this module (lazy lookup / emit, then cache).
MCRegister getOrEmitOpTypeVoidReg(SPIRV::ModuleAnalysisInfo &MAI);
- /// Return OpTypeInt 32 0 id for this module (lazy lookup / emit, then cache).
- MCRegister getOrEmitOpTypeInt32Reg(SPIRV::ModuleAnalysisInfo &MAI);
+ /// Return OpTypeInt \p Width 0 id for this module (lazy lookup / emit, then
+ /// cache). Only widths whose capability is already required are valid.
+ MCRegister getOrEmitOpTypeIntReg(unsigned Width,
+ SPIRV::ModuleAnalysisInfo &MAI);
+
+ /// Whether any size or offset operand needs a 64-bit OpConstant. Must stay in
+ /// sync with the emitOpConstantSizeOrOffset() call sites.
+ bool needsI64SizeOrOffsetConstants() const;
/// Find OpTypeVoid in the already-emitted TypeConstVars section, or emit one
/// if the module does not contain it (e.g. no void-returning functions).
MCRegister findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI);
- /// Find OpTypeInt 32 0 in the already-emitted TypeConstVars section, or emit
- /// one if the module does not contain it.
- MCRegister findOrEmitOpTypeInt32(SPIRV::ModuleAnalysisInfo &MAI);
+ /// Find OpTypeInt \p Width 0 in the already-emitted TypeConstVars section,
+ /// or emit one if absent.
+ MCRegister findOrEmitOpTypeInt(unsigned Width,
+ SPIRV::ModuleAnalysisInfo &MAI);
/// Emit \c DebugTypePointer for pointer metadata \p PT.
///
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll
index 0fc545f09fd73..4e52887d5e471 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll
@@ -6,15 +6,23 @@
; emitted before the composite that lists them. A forward-declared composite
; emits DebugInfoNone for Size and no members. Tag is 1 for a structure.
+; CHECK-SPIRV: OpCapability Int64
; CHECK-SPIRV: [[ext:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
; CHECK-SPIRV-DAG: [[void:%[0-9]+]] = OpTypeVoid
; CHECK-SPIRV-DAG: [[i32:%[0-9]+]] = OpTypeInt 32 0
+; CHECK-SPIRV-DAG: [[i64:%[0-9]+]] = OpTypeInt 64 0
; CHECK-SPIRV-DAG: [[str_int:%[0-9]+]] = OpString "int"
; CHECK-SPIRV-DAG: [[str_float:%[0-9]+]] = OpString "float"
; CHECK-SPIRV-DAG: [[str_S:%[0-9]+]] = OpString "S"
; CHECK-SPIRV-DAG: [[str_a:%[0-9]+]] = OpString "a"
; CHECK-SPIRV-DAG: [[str_b:%[0-9]+]] = OpString "b"
; CHECK-SPIRV-DAG: [[str_Fwd:%[0-9]+]] = OpString "Fwd"
+; CHECK-SPIRV-DAG: [[str_Wide:%[0-9]+]] = OpString "Wide"
+; CHECK-SPIRV-DAG: [[str_wide:%[0-9]+]] = OpString "wide"
+; CHECK-SPIRV-DAG: [[str_pad:%[0-9]+]] = OpString "pad"
+; CHECK-SPIRV-DAG: [[str_tail:%[0-9]+]] = OpString "tail"
+; CHECK-SPIRV-DAG: [[str_u32max:%[0-9]+]] = OpString "u32max"
+; CHECK-SPIRV-DAG: [[str_edge:%[0-9]+]] = OpString "edge"
; CHECK-SPIRV-DAG: [[c0:%[0-9]+]] = OpConstant [[i32]] 0{{$}}
; CHECK-SPIRV-DAG: [[c1:%[0-9]+]] = OpConstant [[i32]] 1{{$}}
; CHECK-SPIRV-DAG: [[c32:%[0-9]+]] = OpConstant [[i32]] 32{{$}}
@@ -31,6 +39,18 @@
; A forward declaration carries FlagFwdDecl (16) in its Flags operand.
; CHECK-SPIRV-DAG: OpExtInst [[void]] [[ext]] DebugTypeComposite [[str_Fwd]] [[c1]] [[ds]] {{%[0-9]+}} [[c0]] [[cu]] {{%[0-9]+}} [[dbgnone]] [[c16]]{{$}}
+; CHECK-SPIRV-DAG: [[big:%[0-9]+]] = OpConstant [[i64]] 8589934592{{$}}
+; CHECK-SPIRV-DAG: [[bigsum:%[0-9]+]] = OpConstant [[i64]] 8589934624{{$}}
+; CHECK-SPIRV-DAG: [[basic_wide:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeBasic [[str_wide]] [[big]] {{%[0-9]+}} [[c0]]{{$}}
+; CHECK-SPIRV-DAG: [[member_pad:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeMember [[str_pad]] [[basic_wide]] [[ds]] {{%[0-9]+}} [[c0]] [[c0]] [[big]] [[c0]]{{$}}
+; CHECK-SPIRV-DAG: [[member_tail:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeMember [[str_tail]] [[basic_int]] [[ds]] {{%[0-9]+}} [[c0]] [[big]] [[c32]] [[c0]]{{$}}
+
+; CHECK-SPIRV-DAG: [[cu32max:%[0-9]+]] = OpConstant [[i32]] 4294967295{{$}}
+; CHECK-SPIRV-DAG: [[bigtotal:%[0-9]+]] = OpConstant [[i64]] 12884901919{{$}}
+; CHECK-SPIRV-DAG: [[basic_u32max:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeBasic [[str_u32max]] [[cu32max]] {{%[0-9]+}} [[c0]]{{$}}
+; CHECK-SPIRV-DAG: [[member_edge:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeMember [[str_edge]] [[basic_u32max]] [[ds]] {{%[0-9]+}} [[c0]] [[bigsum]] [[cu32max]] [[c0]]{{$}}
+; CHECK-SPIRV-DAG: OpExtInst [[void]] [[ext]] DebugTypeComposite [[str_Wide]] [[c1]] [[ds]] {{%[0-9]+}} [[c0]] [[cu]] {{%[0-9]+}} [[bigtotal]] [[c0]] [[member_pad]] [[member_tail]] [[member_edge]]{{$}}
+
define spir_func void @test() !dbg !13 {
entry:
ret void
@@ -43,7 +63,7 @@ entry:
!1 = !{i32 7, !"Dwarf Version", i32 5}
!2 = !{i32 2, !"Debug Info Version", i32 3}
!3 = !DIFile(filename: "composite.hlsl", directory: "/src")
-!4 = !{!5, !12}
+!4 = !{!5, !12, !16}
!5 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !3, line: 1, size: 64, elements: !6)
!6 = !{!7, !9}
!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", file: !3, line: 2, baseType: !8, size: 32)
@@ -54,3 +74,10 @@ entry:
!13 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 10, type: !14, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
!14 = !DISubroutineType(types: !15)
!15 = !{null}
+!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "Wide", file: !3, line: 7, size: 12884901919, elements: !17)
+!17 = !{!18, !20, !21}
+!18 = !DIDerivedType(tag: DW_TAG_member, name: "pad", file: !3, line: 8, baseType: !19, size: 8589934592)
+!19 = !DIBasicType(name: "wide", size: 8589934592, encoding: DW_ATE_unsigned)
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "tail", file: !3, line: 9, baseType: !8, size: 32, offset: 8589934592)
+!21 = !DIDerivedType(tag: DW_TAG_member, name: "edge", file: !3, line: 10, baseType: !22, size: 4294967295, offset: 8589934624)
+!22 = !DIBasicType(name: "u32max", size: 4294967295, encoding: DW_ATE_unsigned)
>From bd1e2f563192f6d48813e1ff6486f8d9bf6e268d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 15 Sep 2026 16:06:13 +0200
Subject: [PATCH 2/2] error
---
.../SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp | 2 +-
.../SPIRV/SPIRVNonSemanticDebugHandler.cpp | 121 ++++++------------
.../SPIRV/SPIRVNonSemanticDebugHandler.h | 35 ++---
.../SPIRV/debug-info/debug-type-composite.ll | 29 +----
.../SPIRV/debug-info/wide-size-error.ll | 27 ++++
5 files changed, 80 insertions(+), 134 deletions(-)
create mode 100644 llvm/test/CodeGen/SPIRV/debug-info/wide-size-error.ll
diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
index a0fd1187143b6..8a2618b5309a9 100644
--- a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
+++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp
@@ -81,7 +81,7 @@ void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
// Handle 64 bit literals.
if (NumVarOps == 2) {
- Imm = Make_64(MI->getOperand(StartIndex + 1).getImm(), Imm);
+ Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32);
}
// Format and print float values.
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
index f41a528853dfc..dea9a2f288592 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.cpp
@@ -338,7 +338,6 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
DebugSourceRegByFileStr.clear();
OpStringContentCache.clear();
I32ConstantCache.clear();
- I64ConstantCache.clear();
DebugTypeFunctionCache.clear();
DebugOperationCache.clear();
DebugExpressionCache.clear();
@@ -351,7 +350,7 @@ void SPIRVNonSemanticDebugHandler::beginModule(Module *M) {
CachedDebugInfoNoneReg = MCRegister();
CachedEmptyStringReg = MCRegister();
CachedOpTypeVoidReg = MCRegister();
- CachedOpTypeIntRegs.clear();
+ CachedOpTypeInt32Reg = MCRegister();
// Collect compile-unit info: file paths and source languages.
for (const DICompileUnit *CU : M->debug_compile_units()) {
@@ -442,30 +441,6 @@ void SPIRVNonSemanticDebugHandler::prepareModuleOutput(
// fresh result ID for it now; the same ID is used in emitExtInst() operands.
if (!MAI.ExtInstSetMap.count(NSSet))
MAI.ExtInstSetMap[NSSet] = MAI.getNextIDRegister();
-
- // Capabilities are output before the debug info, so settle Int64 here.
- if (needsI64SizeOrOffsetConstants())
- MAI.Reqs.addCapability(SPIRV::Capability::Int64);
-}
-
-bool SPIRVNonSemanticDebugHandler::needsI64SizeOrOffsetConstants() const {
- for (const DIBasicType *BT : BasicTypes)
- if (!isUInt<32>(BT->getSizeInBits()))
- return true;
-
- for (const DICompositeType *CT : CompositeTypes) {
- if (!CT->isForwardDecl() && !isUInt<32>(CT->getSizeInBits()))
- return true;
- for (const DINode *Element : CT->getElements()) {
- const auto *M = dyn_cast<DIDerivedType>(Element);
- if (!M || M->getTag() != dwarf::DW_TAG_member)
- continue;
- if (!isUInt<32>(M->getOffsetInBits()) || !isUInt<32>(M->getSizeInBits()))
- return true;
- }
- }
-
- return false;
}
void SPIRVNonSemanticDebugHandler::emitMCInst(MCInst &Inst) {
@@ -551,32 +526,14 @@ MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32(
return Reg;
}
-MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI64(
- uint64_t Value, SPIRV::ModuleAnalysisInfo &MAI) {
- MCRegister I64TypeReg = getOrEmitOpTypeIntReg(64, MAI);
-
- auto [It, Inserted] = I64ConstantCache.try_emplace(Value);
- if (!Inserted)
- return It->second;
-
- MCRegister Reg = MAI.getNextIDRegister();
- It->second = Reg;
- MCInst Inst;
- Inst.setOpcode(SPIRV::OpConstantI);
- Inst.addOperand(MCOperand::createReg(Reg));
- Inst.addOperand(MCOperand::createReg(I64TypeReg));
- // SPIR-V encodes a 64-bit literal as two 32-bit words, low word first.
- Inst.addOperand(MCOperand::createImm(Lo_32(Value)));
- Inst.addOperand(MCOperand::createImm(Hi_32(Value)));
- emitMCInst(Inst);
- return Reg;
-}
-
-MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantSizeOrOffset(
- uint64_t Value, MCRegister I32TypeReg, SPIRV::ModuleAnalysisInfo &MAI) {
- if (isUInt<32>(Value))
- return emitOpConstantI32(static_cast<uint32_t>(Value), I32TypeReg, MAI);
- return emitOpConstantI64(Value, MAI);
+MCRegister SPIRVNonSemanticDebugHandler::emitOpConstantI32Checked(
+ uint64_t Value, const Twine &OperandName, MCRegister I32TypeReg,
+ SPIRV::ModuleAnalysisInfo &MAI) {
+ if (!isUInt<32>(Value))
+ report_fatal_error("SPIR-V debug info: " + OperandName +
+ " does not fit in 32 bits: " + Twine(Value),
+ /*GenCrashDiag=*/false);
+ return emitOpConstantI32(static_cast<uint32_t>(Value), I32TypeReg, MAI);
}
MCRegister SPIRVNonSemanticDebugHandler::emitExtInst(
@@ -617,18 +574,11 @@ MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeVoidReg(
return CachedOpTypeVoidReg;
}
-MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeIntReg(
- unsigned Width, SPIRV::ModuleAnalysisInfo &MAI) {
- assert((Width == 32 || llvm::is_contained(MAI.Reqs.getMinimalCapabilities(),
- SPIRV::Capability::Int64)) &&
- "OpTypeInt emitted for a width whose capability was not requested in "
- "prepareModuleOutput()");
- MCRegister Reg = CachedOpTypeIntRegs.lookup(Width);
- if (!Reg.isValid()) {
- Reg = findOrEmitOpTypeInt(Width, MAI);
- CachedOpTypeIntRegs[Width] = Reg;
- }
- return Reg;
+MCRegister SPIRVNonSemanticDebugHandler::getOrEmitOpTypeInt32Reg(
+ SPIRV::ModuleAnalysisInfo &MAI) {
+ if (!CachedOpTypeInt32Reg.isValid())
+ CachedOpTypeInt32Reg = findOrEmitOpTypeInt32(MAI);
+ return CachedOpTypeInt32Reg;
}
MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
@@ -645,19 +595,19 @@ MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeVoid(
return Reg;
}
-MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt(
- unsigned Width, SPIRV::ModuleAnalysisInfo &MAI) {
+MCRegister SPIRVNonSemanticDebugHandler::findOrEmitOpTypeInt32(
+ SPIRV::ModuleAnalysisInfo &MAI) {
for (const MachineInstr *MI : MAI.getMSInstrs(SPIRV::MB_TypeConstVars)) {
if (MI->getOpcode() == SPIRV::OpTypeInt &&
- MI->getOperand(1).getImm() == Width && MI->getOperand(2).getImm() == 0)
+ MI->getOperand(1).getImm() == 32 && MI->getOperand(2).getImm() == 0)
return MAI.getRegisterAlias(MI->getMF(), MI->getOperand(0).getReg());
}
MCRegister Reg = MAI.getNextIDRegister();
MCInst Inst;
Inst.setOpcode(SPIRV::OpTypeInt);
Inst.addOperand(MCOperand::createReg(Reg));
- Inst.addOperand(MCOperand::createImm(Width));
- Inst.addOperand(MCOperand::createImm(0)); // signedness (unsigned)
+ Inst.addOperand(MCOperand::createImm(32)); // width
+ Inst.addOperand(MCOperand::createImm(0)); // signedness (unsigned)
emitMCInst(Inst);
return Reg;
}
@@ -671,7 +621,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypePointer(
return std::nullopt;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
MCRegister DebugTypePointerFlagsReg =
emitOpConstantI32(transDebugFlags(PT), I32TypeReg, MAI);
@@ -706,7 +656,7 @@ SPIRVNonSemanticDebugHandler::emitDebugTypeFunctionForSubroutineType(
const DISubroutineType *ST, MCRegister ExtInstSetReg,
SPIRV::ModuleAnalysisInfo &MAI) {
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
MCRegister DebugTypeFunctionFlagsReg =
emitOpConstantI32(transDebugFlags(ST), I32TypeReg, MAI);
DITypeArray TA = ST->getTypeArray();
@@ -1141,13 +1091,11 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeVector(
return std::nullopt;
const auto *SR = cast<DISubrange>(Elements[0]);
const auto *CI = dyn_cast_if_present<ConstantInt *>(SR->getCount());
- // Component Count is a 32-bit OpConstant, so a wider count cannot be
- // encoded. Truncating it would silently describe a different vector.
- if (!CI || CI->getValue().getActiveBits() > 32)
+ if (!CI)
return std::nullopt;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
MCRegister CountReg = emitOpConstantI32(
static_cast<uint32_t>(CI->getZExtValue()), I32TypeReg, MAI);
return emitExtInst(SPIRV::NonSemanticExtInst::DebugTypeVector, VoidTypeReg,
@@ -1164,7 +1112,7 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeArray(
return std::nullopt;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
SmallVector<MCRegister> Ops;
Ops.push_back(*BaseRegOpt);
@@ -1212,10 +1160,12 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeMember(
// DIDerivedType members carry no column, so emit 0.
MCRegister ColReg = emitOpConstantI32(0, I32TypeReg, MAI);
- MCRegister OffsetReg =
- emitOpConstantSizeOrOffset(M->getOffsetInBits(), I32TypeReg, MAI);
- MCRegister SizeReg =
- emitOpConstantSizeOrOffset(M->getSizeInBits(), I32TypeReg, MAI);
+ MCRegister OffsetReg = emitOpConstantI32Checked(
+ M->getOffsetInBits(), "offset of member '" + M->getName() + "'",
+ I32TypeReg, MAI);
+ MCRegister SizeReg = emitOpConstantI32Checked(
+ M->getSizeInBits(), "size of member '" + M->getName() + "'", I32TypeReg,
+ MAI);
MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(M), I32TypeReg, MAI);
// In NonSemantic.Shader.DebugInfo a DebugTypeMember has no Parent operand:
@@ -1258,7 +1208,9 @@ std::optional<MCRegister> SPIRVNonSemanticDebugHandler::emitDebugTypeComposite(
// A forward declaration has no known size or members: Size is DebugInfoNone.
MCRegister SizeReg = CachedDebugInfoNoneReg;
if (!CT->isForwardDecl())
- SizeReg = emitOpConstantSizeOrOffset(CT->getSizeInBits(), I32TypeReg, MAI);
+ SizeReg = emitOpConstantI32Checked(
+ CT->getSizeInBits(), "size of composite type '" + CT->getName() + "'",
+ I32TypeReg, MAI);
MCRegister FlagsReg = emitOpConstantI32(transDebugFlags(CT), I32TypeReg, MAI);
@@ -1798,7 +1750,7 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
CurrentMAI = &MAI;
MCRegister VoidTypeReg = getOrEmitOpTypeVoidReg(MAI);
- MCRegister I32TypeReg = getOrEmitOpTypeIntReg(32, MAI);
+ MCRegister I32TypeReg = getOrEmitOpTypeInt32Reg(MAI);
CachedDebugInfoNoneReg = emitExtInst(SPIRV::NonSemanticExtInst::DebugInfoNone,
VoidTypeReg, ExtInstSetReg, {}, MAI);
@@ -1846,8 +1798,9 @@ void SPIRVNonSemanticDebugHandler::emitNonSemanticGlobalDebugInfo(
for (const DIBasicType *BT : BasicTypes) {
MCRegister NameReg = getCachedOpStringReg(BT->getName());
- MCRegister SizeReg =
- emitOpConstantSizeOrOffset(BT->getSizeInBits(), I32TypeReg, MAI);
+ MCRegister SizeReg = emitOpConstantI32Checked(
+ BT->getSizeInBits(), "size of basic type '" + BT->getName() + "'",
+ I32TypeReg, MAI);
// Map DWARF base type encodings to NSDI encoding codes per
// NonSemantic.Shader.DebugInfo.100 specification, section 4.5.
diff --git a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
index 44006f76117ff..e846620eb5339 100644
--- a/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
+++ b/llvm/lib/Target/SPIRV/SPIRVNonSemanticDebugHandler.h
@@ -25,6 +25,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/CodeGen/DebugHandlerBase.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/MC/MCInst.h"
@@ -152,16 +153,12 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
MCRegister CachedOpTypeVoidReg;
- // OpTypeInt <width> 0 ids for this module.
- SmallDenseMap<unsigned, MCRegister, 2> CachedOpTypeIntRegs;
+ MCRegister CachedOpTypeInt32Reg;
// Cache of already-emitted i32 constants, keyed by value. Prevents
// duplicate OpConstant instructions for the same integer value.
DenseMap<uint32_t, MCRegister> I32ConstantCache;
- // Same, for size and offset operands that do not fit in 32 bits.
- DenseMap<uint64_t, MCRegister> I64ConstantCache;
-
// Cache of already-emitted DebugTypeFunction instructions, keyed by operand
// ids (flags, return type, parameters).
DenseMap<SmallVector<MCRegister, 8>, MCRegister> DebugTypeFunctionCache;
@@ -311,11 +308,14 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
MCRegister emitOpConstantI32(uint32_t Value, MCRegister I32TypeReg,
SPIRV::ModuleAnalysisInfo &MAI);
- MCRegister emitOpConstantI64(uint64_t Value, SPIRV::ModuleAnalysisInfo &MAI);
+ /// Same, for a value that is naturally 64-bit in the IR. Sizes and offsets
+ /// are 32-bit OpConstants in NonSemantic.Shader.DebugInfo, so report a fatal
+ /// error rather than silently truncating. \p OperandName names the operand in
+ /// that message.
+ MCRegister emitOpConstantI32Checked(uint64_t Value, const Twine &OperandName,
+ MCRegister I32TypeReg,
+ SPIRV::ModuleAnalysisInfo &MAI);
- /// Size and offset operands accept a 32-bit or a 64-bit integer OpConstant.
- MCRegister emitOpConstantSizeOrOffset(uint64_t Value, MCRegister I32TypeReg,
- SPIRV::ModuleAnalysisInfo &MAI);
MCRegister emitExtInst(SPIRV::NonSemanticExtInst::NonSemanticExtInst Opcode,
MCRegister VoidTypeReg, MCRegister ExtInstSetReg,
ArrayRef<MCRegister> Operands,
@@ -331,23 +331,16 @@ class SPIRVNonSemanticDebugHandler : public DebugHandlerBase {
/// Return OpTypeVoid id for this module (lazy lookup / emit, then cache).
MCRegister getOrEmitOpTypeVoidReg(SPIRV::ModuleAnalysisInfo &MAI);
- /// Return OpTypeInt \p Width 0 id for this module (lazy lookup / emit, then
- /// cache). Only widths whose capability is already required are valid.
- MCRegister getOrEmitOpTypeIntReg(unsigned Width,
- SPIRV::ModuleAnalysisInfo &MAI);
-
- /// Whether any size or offset operand needs a 64-bit OpConstant. Must stay in
- /// sync with the emitOpConstantSizeOrOffset() call sites.
- bool needsI64SizeOrOffsetConstants() const;
+ /// Return OpTypeInt 32 0 id for this module (lazy lookup / emit, then cache).
+ MCRegister getOrEmitOpTypeInt32Reg(SPIRV::ModuleAnalysisInfo &MAI);
/// Find OpTypeVoid in the already-emitted TypeConstVars section, or emit one
/// if the module does not contain it (e.g. no void-returning functions).
MCRegister findOrEmitOpTypeVoid(SPIRV::ModuleAnalysisInfo &MAI);
- /// Find OpTypeInt \p Width 0 in the already-emitted TypeConstVars section,
- /// or emit one if absent.
- MCRegister findOrEmitOpTypeInt(unsigned Width,
- SPIRV::ModuleAnalysisInfo &MAI);
+ /// Find OpTypeInt 32 0 in the already-emitted TypeConstVars section, or emit
+ /// one if the module does not contain it.
+ MCRegister findOrEmitOpTypeInt32(SPIRV::ModuleAnalysisInfo &MAI);
/// Emit \c DebugTypePointer for pointer metadata \p PT.
///
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll
index 4e52887d5e471..0fc545f09fd73 100644
--- a/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll
+++ b/llvm/test/CodeGen/SPIRV/debug-info/debug-type-composite.ll
@@ -6,23 +6,15 @@
; emitted before the composite that lists them. A forward-declared composite
; emits DebugInfoNone for Size and no members. Tag is 1 for a structure.
-; CHECK-SPIRV: OpCapability Int64
; CHECK-SPIRV: [[ext:%[0-9]+]] = OpExtInstImport "NonSemantic.Shader.DebugInfo.100"
; CHECK-SPIRV-DAG: [[void:%[0-9]+]] = OpTypeVoid
; CHECK-SPIRV-DAG: [[i32:%[0-9]+]] = OpTypeInt 32 0
-; CHECK-SPIRV-DAG: [[i64:%[0-9]+]] = OpTypeInt 64 0
; CHECK-SPIRV-DAG: [[str_int:%[0-9]+]] = OpString "int"
; CHECK-SPIRV-DAG: [[str_float:%[0-9]+]] = OpString "float"
; CHECK-SPIRV-DAG: [[str_S:%[0-9]+]] = OpString "S"
; CHECK-SPIRV-DAG: [[str_a:%[0-9]+]] = OpString "a"
; CHECK-SPIRV-DAG: [[str_b:%[0-9]+]] = OpString "b"
; CHECK-SPIRV-DAG: [[str_Fwd:%[0-9]+]] = OpString "Fwd"
-; CHECK-SPIRV-DAG: [[str_Wide:%[0-9]+]] = OpString "Wide"
-; CHECK-SPIRV-DAG: [[str_wide:%[0-9]+]] = OpString "wide"
-; CHECK-SPIRV-DAG: [[str_pad:%[0-9]+]] = OpString "pad"
-; CHECK-SPIRV-DAG: [[str_tail:%[0-9]+]] = OpString "tail"
-; CHECK-SPIRV-DAG: [[str_u32max:%[0-9]+]] = OpString "u32max"
-; CHECK-SPIRV-DAG: [[str_edge:%[0-9]+]] = OpString "edge"
; CHECK-SPIRV-DAG: [[c0:%[0-9]+]] = OpConstant [[i32]] 0{{$}}
; CHECK-SPIRV-DAG: [[c1:%[0-9]+]] = OpConstant [[i32]] 1{{$}}
; CHECK-SPIRV-DAG: [[c32:%[0-9]+]] = OpConstant [[i32]] 32{{$}}
@@ -39,18 +31,6 @@
; A forward declaration carries FlagFwdDecl (16) in its Flags operand.
; CHECK-SPIRV-DAG: OpExtInst [[void]] [[ext]] DebugTypeComposite [[str_Fwd]] [[c1]] [[ds]] {{%[0-9]+}} [[c0]] [[cu]] {{%[0-9]+}} [[dbgnone]] [[c16]]{{$}}
-; CHECK-SPIRV-DAG: [[big:%[0-9]+]] = OpConstant [[i64]] 8589934592{{$}}
-; CHECK-SPIRV-DAG: [[bigsum:%[0-9]+]] = OpConstant [[i64]] 8589934624{{$}}
-; CHECK-SPIRV-DAG: [[basic_wide:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeBasic [[str_wide]] [[big]] {{%[0-9]+}} [[c0]]{{$}}
-; CHECK-SPIRV-DAG: [[member_pad:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeMember [[str_pad]] [[basic_wide]] [[ds]] {{%[0-9]+}} [[c0]] [[c0]] [[big]] [[c0]]{{$}}
-; CHECK-SPIRV-DAG: [[member_tail:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeMember [[str_tail]] [[basic_int]] [[ds]] {{%[0-9]+}} [[c0]] [[big]] [[c32]] [[c0]]{{$}}
-
-; CHECK-SPIRV-DAG: [[cu32max:%[0-9]+]] = OpConstant [[i32]] 4294967295{{$}}
-; CHECK-SPIRV-DAG: [[bigtotal:%[0-9]+]] = OpConstant [[i64]] 12884901919{{$}}
-; CHECK-SPIRV-DAG: [[basic_u32max:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeBasic [[str_u32max]] [[cu32max]] {{%[0-9]+}} [[c0]]{{$}}
-; CHECK-SPIRV-DAG: [[member_edge:%[0-9]+]] = OpExtInst [[void]] [[ext]] DebugTypeMember [[str_edge]] [[basic_u32max]] [[ds]] {{%[0-9]+}} [[c0]] [[bigsum]] [[cu32max]] [[c0]]{{$}}
-; CHECK-SPIRV-DAG: OpExtInst [[void]] [[ext]] DebugTypeComposite [[str_Wide]] [[c1]] [[ds]] {{%[0-9]+}} [[c0]] [[cu]] {{%[0-9]+}} [[bigtotal]] [[c0]] [[member_pad]] [[member_tail]] [[member_edge]]{{$}}
-
define spir_func void @test() !dbg !13 {
entry:
ret void
@@ -63,7 +43,7 @@ entry:
!1 = !{i32 7, !"Dwarf Version", i32 5}
!2 = !{i32 2, !"Debug Info Version", i32 3}
!3 = !DIFile(filename: "composite.hlsl", directory: "/src")
-!4 = !{!5, !12, !16}
+!4 = !{!5, !12}
!5 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !3, line: 1, size: 64, elements: !6)
!6 = !{!7, !9}
!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", file: !3, line: 2, baseType: !8, size: 32)
@@ -74,10 +54,3 @@ entry:
!13 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 10, type: !14, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
!14 = !DISubroutineType(types: !15)
!15 = !{null}
-!16 = !DICompositeType(tag: DW_TAG_structure_type, name: "Wide", file: !3, line: 7, size: 12884901919, elements: !17)
-!17 = !{!18, !20, !21}
-!18 = !DIDerivedType(tag: DW_TAG_member, name: "pad", file: !3, line: 8, baseType: !19, size: 8589934592)
-!19 = !DIBasicType(name: "wide", size: 8589934592, encoding: DW_ATE_unsigned)
-!20 = !DIDerivedType(tag: DW_TAG_member, name: "tail", file: !3, line: 9, baseType: !8, size: 32, offset: 8589934592)
-!21 = !DIDerivedType(tag: DW_TAG_member, name: "edge", file: !3, line: 10, baseType: !22, size: 4294967295, offset: 8589934624)
-!22 = !DIBasicType(name: "u32max", size: 4294967295, encoding: DW_ATE_unsigned)
diff --git a/llvm/test/CodeGen/SPIRV/debug-info/wide-size-error.ll b/llvm/test/CodeGen/SPIRV/debug-info/wide-size-error.ll
new file mode 100644
index 0000000000000..ba1605a531057
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/debug-info/wide-size-error.ll
@@ -0,0 +1,27 @@
+; RUN: not llc --verify-machineinstrs --spirv-ext=+SPV_KHR_non_semantic_info -O0 -mtriple=spirv64-unknown-unknown %s -o - 2>&1 | FileCheck %s
+
+; NonSemantic.Shader.DebugInfo encodes Size and Offset as 32-bit OpConstants,
+; so a wider value is rejected instead of silently truncated.
+
+; CHECK: SPIR-V debug info: size of composite type 'Wide' does not fit in 32 bits: 8589934592
+
+define spir_func void @test() !dbg !9 {
+entry:
+ ret void
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!1, !2}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, retainedTypes: !4)
+!1 = !{i32 7, !"Dwarf Version", i32 5}
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = !DIFile(filename: "wide.hlsl", directory: "/src")
+!4 = !{!5}
+!5 = !DICompositeType(tag: DW_TAG_structure_type, name: "Wide", file: !3, line: 1, size: 8589934592, elements: !6)
+!6 = !{!7}
+!7 = !DIDerivedType(tag: DW_TAG_member, name: "a", file: !3, line: 2, baseType: !8, size: 32)
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = distinct !DISubprogram(name: "test", scope: !3, file: !3, line: 10, type: !10, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0)
+!10 = !DISubroutineType(types: !11)
+!11 = !{null}
More information about the llvm-commits
mailing list