KhronosGroup / KhronosGroup/SPIRV-LLVM-Translator

Translation of NonSemantic.Shader.DebugInfo DebugLocalVariable ArgNumber does not correctly wrap/unwrap in OpConstant

Open
#3,768 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.