[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