Both directions of translation (i.e. LLVM -> SPIRV and SPIRV -> LLVM) of the NonSemantic.Shader.DebugInfo DebugLocalVariable op incorrectly translate the (optional) ArgNumber argument. As per the spec, the ArgNumber operand is the id of a 32-bit integer OpConstant.
However, neither "side" of the translator respect this. From the LLVM -> SPIRV side, the ArgNumber is written as a literal:
if (SPIRVWord ArgNumber = Var->getArg())
Ops.push_back(ArgNumber);
while on the SPIRV -> LLVM side, the ArgNumber (which should be an id) is read as a literal:
if (Ops.size() > ArgNumberIdx)
return getDIBuilder(DebugInst).createParameterVariable(
Scope, Name, Ops[ArgNumberIdx], File, LineNo, Ty, true, Flags);
This "works" to a certain extent, as the same bug exists on both sides of the translator (even if the debug information ends up being incorrect). However, issues occur when working with very large kernels which contain more than UINT64_MAX ids. This will overflow LLVM's internal16-bit integer that stores the arg number, or cause an assertion in debug builds.
Attached is a test for the SPIRV -> LLVM pipeline: big_kernel.spvasm.txt. The test consists of more than 65535 IDs, followed by a DebugLocalVariable call that uses an ID that is beyond that range. This triggers the assertion in LLVM. Full disclosure, it was created with the assistance of AI (specifically Claude Sonnet 4.6).
Writing a test for the LLVM -> SPIRV case is more difficult, as LLVM inherently cannot produce a value of greater than 65535 from its internal debug information. I have however observed this behaviour in the wild, in SPIRV generated by SYCL kernels, so it is somehow possible. If necessary, I can keep working on this until I have a test.
Both directions of translation (i.e. LLVM -> SPIRV and SPIRV -> LLVM) of the NonSemantic.Shader.DebugInfo
DebugLocalVariableop incorrectly translate the (optional)ArgNumberargument. As per the spec, theArgNumberoperand is the id of a 32-bit integer OpConstant.However, neither "side" of the translator respect this. From the LLVM -> SPIRV side, the ArgNumber is written as a literal:
while on the SPIRV -> LLVM side, the ArgNumber (which should be an id) is read as a literal:
This "works" to a certain extent, as the same bug exists on both sides of the translator (even if the debug information ends up being incorrect). However, issues occur when working with very large kernels which contain more than
UINT64_MAXids. This will overflow LLVM's internal16-bit integer that stores the arg number, or cause an assertion in debug builds.Attached is a test for the SPIRV -> LLVM pipeline: big_kernel.spvasm.txt. The test consists of more than 65535 IDs, followed by a DebugLocalVariable call that uses an ID that is beyond that range. This triggers the assertion in LLVM. Full disclosure, it was created with the assistance of AI (specifically Claude Sonnet 4.6).
Writing a test for the LLVM -> SPIRV case is more difficult, as LLVM inherently cannot produce a value of greater than 65535 from its internal debug information. I have however observed this behaviour in the wild, in SPIRV generated by SYCL kernels, so it is somehow possible. If necessary, I can keep working on this until I have a test.