Skip to content

Implement SPV_KHR_abort extension#3691

Merged
michalpaszkowski merged 8 commits into
KhronosGroup:mainfrom
vmustya:spv-khr-abort
May 4, 2026
Merged

Implement SPV_KHR_abort extension#3691
michalpaszkowski merged 8 commits into
KhronosGroup:mainfrom
vmustya:spv-khr-abort

Conversation

@vmustya

@vmustya vmustya commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

The SPV_KHR_abort extension introduces the OpAbortKHR instruction,
allowing shaders to terminate execution early.

Assisted-by: Claude Opus 4.7 noreply@anthropic.com

The SPV_KHR_abort extension introduces the `OpAbortKHR` instruction,
allowing shaders to terminate execution early.

Assisted-by: Claude Opus 4.7 <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Apr 20, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@michalpaszkowski michalpaszkowski left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM from my side!

@vmaksimo vmaksimo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SPV_KHR_constant_data is listed as a dependency, but I don't see it used anywhere in the code - maybe spirv-val will catch this as well.
Please also address clang-tidy failure

Comment thread lib/SPIRV/SPIRVWriter.cpp Outdated
Comment thread test/extensions/KHR/SPV_KHR_abort/abort.ll
Comment thread lib/SPIRV/SPIRVWriter.cpp Outdated
Comment thread lib/SPIRV/SPIRVWriter.cpp
Comment thread lib/SPIRV/libSPIRV/SPIRVInstruction.h Outdated
@vmustya

vmustya commented Apr 22, 2026

Copy link
Copy Markdown
Contributor Author

Please also address clang-tidy failure

The clang-tidy fails as follows:

/home/runner/work/SPIRV-LLVM-Translator/SPIRV-LLVM-Translator/lib/SPIRV/libSPIRV/SPIRVInstruction.h:903:3: error: visibility of function 'decode' is changed from public in class 'SPIRVEntry' to protected [misc-override-with-different-visibility,-warnings-as-errors]
  903 |   _SPIRV_DEF_ENCDEC2(MessageTypeId, MessageId)
      |   ^
/home/runner/work/SPIRV-LLVM-Translator/SPIRV-LLVM-Translator/lib/SPIRV/libSPIRV/SPIRVEntry.h:151:8: note: expanded from macro '_SPIRV_DEF_ENCDEC2'
  151 |   void decode(std::istream &I) override { getDecoder(I) >> (x) >> (y); }
      |        ^
/home/runner/work/SPIRV-LLVM-Translator/SPIRV-LLVM-Translator/lib/SPIRV/libSPIRV/SPIRVEntry.h:402:16: note: function declared here as public
  402 |   virtual void decode(std::istream &I);
      |                ^

The reported issue is that the encode and decode methods generated by the _SPIRV_DEF_ENCDEC2 macro are protected. However, the base SPIRVEntry class defines these methods as public. I've checked other instruction implementations, like OpReturn and OpUnreachable, and they also define the encode and decode methods as protected. So, this clang-tidy issue is applicable to the whole translator code.

I don't really want to deviate the style other instructions are implemented. So, I believe, that either all the instructions should be changed by a separate commit, or the clang-tidy error should be suppressed. @vmaksimo, what would you suggest?

@maarquitos14 maarquitos14 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at SPV_KHR_abort separately, but @MrSidims brought this PR to my attention. I have a few extra tests that I'm more than happy to share if you're interested @vmustya.

Comment thread lib/SPIRV/SPIRVWriter.cpp
// llvm.trap and llvm.debugtrap intrinsics are not implemented. But for now
// don't crash. This change is pending the trap/abort intrinsic
// implementation.
// TODO: lower llvm.trap / llvm.ubsantrap / llvm.debugtrap to OpAbortKHR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do this in this patch too? Seems very related.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maarquitos14 Maybe not to overload this PR, we can follow-up in a separate one (together with Reader part update for default/non-friendly IR path). What do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't block this PR for this. If you want to follow-up in a separate PR, go for it.

Comment thread lib/SPIRV/libSPIRV/SPIRVInstruction.h Outdated
Comment thread lib/SPIRV/libSPIRV/SPIRVInstruction.h Outdated
Comment thread lib/SPIRV/SPIRVWriter.cpp Outdated
Comment on lines +2336 to +2356
if (isa<UnreachableInst>(V)) {
// SPV_KHR_abort: OpAbortKHR is itself a block terminator. If the LLVM IR
// appends a trailing 'unreachable' after the abort call (the canonical
// pattern for noreturn calls), do not emit a second SPIR-V terminator.
if (auto *Last = BB->getTerminateInstr())
if (Last->getOpCode() == OpAbortKHR)
return mapValue(V, const_cast<SPIRVInstruction *>(Last));
return mapValue(V, BM->addUnreachableInst(BB));
}

if (auto *RI = dyn_cast<ReturnInst>(V)) {
// SPV_KHR_abort: OpAbortKHR is itself a SPIR-V block terminator. If the
// LLVM IR appends a trailing `ret void` after the abort call, do not emit
// a second SPIR-V terminator. We deliberately limit this suppression to
// `ret void`: if a non-void function ends with `ret <value>` after
// OpAbortKHR, fall through so that the value is still translated and the
// user sees a normal SPIR-V validation error rather than silently
// dropping the return value.
if (auto *Last = BB->getTerminateInstr();
!RI->getReturnValue() && Last && Last->getOpCode() == OpAbortKHR)
return mapValue(V, const_cast<SPIRVInstruction *>(Last));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure this is enough to handle all the cases. For example:

call void @llvm.trap()/__spirv_AbortKHR
cal void @llvm.lifetime.end()
ret void

This would be invalid, because we would have an instruction after a terminator. As far as I can tell, nothing would prevent translating the call to @llvm.lifetime.end() after the OpAbortKHR, which is a terminator. Am I right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maarquitos14, I've moved the tests you've shared from the llvm.trap intrinsic to the SPIR-V friendly IR, and adjusted the writer code. Now all the instructions in the basic block, that follow the __spirv_AbortKHR function call, are ignored by the writer. Could you please provide your feedback?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks :)

Comment thread lib/SPIRV/SPIRVReader.cpp
}

case OpAbortKHR: {
// OpAbortKHR is a SPIR-V block terminator. In LLVM IR, model it as a call

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we split in two paths? This one for spirv-friendly IR, and another one for non-friendly which would translate into... llvm.trap maybe?

@vmustya

vmustya commented Apr 24, 2026

Copy link
Copy Markdown
Contributor Author

I have a few extra tests that I'm more than happy to share if you're interested @vmustya.

@maarquitos14, sure! I'd really appreciate that.

@maarquitos14

Copy link
Copy Markdown
Contributor

I have a few extra tests that I'm more than happy to share if you're interested @vmustya.

@maarquitos14, sure! I'd really appreciate that.

You can find them in maarquitos14@fe51642. I think all of them assume llvm.trap gets translated to OpAbortKHR and back, but still I think they can be useful.

@vmaksimo

Copy link
Copy Markdown
Contributor

I don't really want to deviate the style other instructions are implemented. So, I believe, that either all the instructions should be changed by a separate commit, or the clang-tidy error should be suppressed.

@vmustya If can - we should not introduce new errors, and I believe this is the case. So please just put encode/decode to public - we'll take a look at other instructions separately.

@maarquitos14 maarquitos14 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

The CI environment does not provide the split-file utility, causing the
abort-invalid-arg-count.ll test to fail. Split it into two standalone
tests that exercise the no-args and two-args negative cases
independently, removing the split-file requirement.

@vmaksimo vmaksimo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change with the test coverege looks great, thanks for the work done!

I have the nits about the tests that'd better to be addressed, after that I guess we're perfectly good to go 🙂

Comment thread test/extensions/KHR/SPV_KHR_abort/abort.ll Outdated
Comment thread lib/SPIRV/SPIRVReader.cpp Outdated
Comment thread test/extensions/KHR/SPV_KHR_abort/no-abort-unaffected.ll Outdated
Comment thread test/extensions/KHR/SPV_KHR_abort/abort-multiple-blocks.ll
Comment thread test/extensions/KHR/SPV_KHR_abort/abort-in-kernel.ll Outdated
@vmaksimo vmaksimo requested a review from svenvh April 30, 2026 12:55

@vmaksimo vmaksimo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vmaksimo

vmaksimo commented May 4, 2026

Copy link
Copy Markdown
Contributor

@svenvh would you like to review this one prior merging?

@michalpaszkowski michalpaszkowski merged commit c5dbe56 into KhronosGroup:main May 4, 2026
9 checks passed
@vmustya vmustya deleted the spv-khr-abort branch May 4, 2026 19:47
@vmustya

vmustya commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

/backport llvm_release_220

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Attempting to create backport to llvm_release_220...

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Success. Backport PR created: #3730

@vmustya

vmustya commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

/backport llvm_release_210

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Attempting to create backport to llvm_release_210...

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Success. Backport PR created: #3733

@vmustya

vmustya commented May 4, 2026

Copy link
Copy Markdown
Contributor Author

/backport llvm_release_200

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Attempting to create backport to llvm_release_200...

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown

Backport to llvm_release_200 failed due to conflicts on commit c5dbe5662a56e57c6592e4f84ac5e087e9306580. Please backport manually.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants