KhronosGroup / KhronosGroup/SPIRV-LLVM-Translator
Translation of NonSemantic.Shader.DebugInfo DebugLocalVariable ArgNumber does not correctly wrap/unwrap in OpConstant
- Dominant language
- LLVM
- Stars
- 625
- Forks
- 279
- Avg merge
- 3d 5h
- Merged PRs (30d)
- 34
Description
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](https://github.khronos.org/SPIRV-Registry/nonsemantic/NonSemantic.Shader.DebugInfo.html#DebugLocalVariable), 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](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/lib/SPIRV/LLVMToSPIRVDbgTran.cpp#L1609):
```
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](https://github.com/KhronosGroup/SPIRV-LLVM-Translator/blob/main/lib/SPIRV/SPIRVToLLVMDbgTran.cpp#L1208):
```
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](https://github.com/llvm/llvm-project/blob/92b01a1bac4d01bb548c625a464840e32dea6c13/llvm/lib/IR/DebugInfoMetadata.cpp#L1657).
---
Attached is a test for the SPIRV -> LLVM pipeline: [big_kernel.spvasm.txt](https://github.com/user-attachments/files/28473730/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.
Contributor guide
Research direction
Start with the cited DebugLocalVariable handling in lib/SPIRV/LLVMToSPIRVDbgTran.cpp and lib/SPIRV/SPIRVToLLVMDbgTran.cpp, then read the NonSemantic.Shader.DebugInfo specification for ArgNumber. Use big_kernel.spvasm.txt to reproduce the SPIRV-to-LLVM failure; done means both translation directions preserve ArgNumber as the specified 32-bit integer OpConstant operand without overflow or assertion.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 52/100