Skip to content

Adapt NVPTX target-feature handling for LLVM 22 and 23 - #157868

Open
kulst wants to merge 1 commit into
rust-lang:mainfrom
kulst:nvptx-fixup-target-features
Open

kulst wants to merge 1 commit into
rust-lang:mainfrom
kulst:nvptx-fixup-target-features

Conversation

@kulst

@kulst kulst commented Jun 13, 2026 •

Copy link
Copy Markdown
Contributor

Previously, we did not explicitly enable a PTX version target-feature, because LLVM implied one from the selected CPU.

Starting with LLVM 22, the NVPTX backend still infers the minimum required PTX version from the selected CPU when none is selected explicitly, but no longer reflects that version in the enabled subtarget features. As a result, cfg could miss the PTX version of the emitted PTX. Also, if a PTX version below the required minimum is selected explicitly, LLVM errors.
We missed this because the corresponding NVPTX target-feature test was mistakenly disabled.

With this patch we always select a PTX version explicitly, whichever is higher between

  • Rust's minimum required PTX version, and
  • the CPU's minimum required PTX version.

The patch also re-enables the NVPTX target-feature test to catch such changes in the future.
It additionally forbids PTX and sm versions below Rust's minimum required versions by marking the corresponding target-features as InternalOnly.
Lastly it adds PTX and sm versions present in LLVM 22 or LLVM 23 but missing as Rust target-features.

This will not prevent all issues. In fact, the following combinations might still miscompile:

-Ctarget-cpu=sm_101 -Ctarget-feature=+ptx90 // sm_101 was renamed starting with ptx90
-Ctarget-cpu=sm_70 -Ctarget-feature=+sm_80,+ptx81 // .target directive is sm_70 but instructions are selected from sm_80

cc: @kjetilkjeka
r? @ZuseZ4
@rustbot label +O-NVPTX

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. O-NVPTX Target: the NVPTX LLVM backend for running rust on GPUs, https://llvm.org/docs/NVPTXUsage.html labels Jun 13, 2026
@rust-log-analyzer

This comment has been minimized.

@kulst
kulst force-pushed the nvptx-fixup-target-features branch 2 times, most recently from 7b7a043 to abd0003 Compare June 13, 2026 19:50
@rust-log-analyzer

This comment has been minimized.

@kulst
kulst force-pushed the nvptx-fixup-target-features branch from abd0003 to 8ec03af Compare June 13, 2026 21:14
@rustbot rustbot added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label Jun 13, 2026
@rust-bors

This comment has been minimized.

@apiraino

Copy link
Copy Markdown
Contributor

@rustbot reroll

@rustbot rustbot assigned davidtwco and unassigned ZuseZ4 Aug 19, 2026
@davidtwco

Copy link
Copy Markdown
Member

Can approve after rebasing

@kulst
kulst force-pushed the nvptx-fixup-target-features branch from 8ec03af to ada34f5 Compare October 11, 2026 11:40
@rustbot

rustbot commented Oct 11, 2026

Copy link
Copy Markdown
Collaborator

Target features are being changed; ensure all ABI effects are being accounted for

cc @RalfJung

@rustbot

This comment has been minimized.

@kulst kulst changed the title Adapt NVPTX target-feature handling for LLVM 22 Adapt NVPTX target-feature handling for LLVM 22 and 23 Oct 11, 2026
}
}

pub fn additional_features_for_cpu(&self, cpu: &str) -> &'static [&'static str] {

@RalfJung RalfJung Oct 11, 2026 •

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.

Thanks for moving this logic into a more suitable place.

Please add a doc comment explaining the point of this function and what it should be used for.

It is still surprising and concerning to me that we need this at all. We have usually relied on LLVM to convert target-cpu into target-features. Why does LLVM not do this any more?

View changes since the review

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.

Ideally, we could just add ptx70 to NVPTX' default features as this is the minimum required PTX version by Rust.
However, starting from LLVM 22 this would result in LLVM errors, if the SM version requires a higher PTX version and the user does not enable a compliant one explicitely.
The logic here should prevent these errors for LLVM 22, 23 and the current LLVM main branch.

For reference:
Between LLVM 22 and the current LLVM main branch, NVPTX' subtarget feature handling underwent some changes. For example, in LLVM 22 and 23, if no PTX subtarget feature is enabled explicitely, LLVM would just emit PTX using the minimum required PTX version by the SM version. However, it would not imply the corresponding PTX subtarget feature.

In the current LLVM main branch on the other hand, the corresponding PTX subtarget feature is implied by LLVM. But LLVM would still error if the highest explicitely enabled PTX subtarget feature would not be compliant to the SM version.

Additionally, in the current LLVM main branch higher PTX subtarget features imply lower ones. So
ptx91 implies ptx90 and so on.

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.

In the current LLVM main branch on the other hand, the corresponding PTX subtarget feature is implied by LLVM.

That sounds reasonable. So this function here that manually implements "sm_X target-cpu implies ptxY target-feature" can be removed once we require LLVM 24?

But LLVM would still error if the highest explicitely enabled PTX subtarget feature would not be compliant to the SM version.

So the PTX subtarget feature is implied but also it's not implied and we have to still enable it manually? 😵

Comment on lines +642 to +653
("sm_20", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_21", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_30", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_32", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_35", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_37", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_50", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_52", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_53", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_60", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_61", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),
("sm_62", InternalOnly { reason: "unsupported compute capability", hard_error: true }, &[]),

@RalfJung RalfJung Oct 11, 2026 •

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.

Can these be removed once we make unknown target features a hard error even on nightly? Or is there some other reason they must be listed here?

View changes since the review

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.

Yes, if that is the case, these features can be removed.

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.

In that case please add a comment explaining that.
(Other InternalOnly features will remain because we really need to track them internally in the compiler.)

@RalfJung

RalfJung commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

This will not prevent all issues. In fact, the following combinations might still miscompile:

-Ctarget-cpu=sm_101 -Ctarget-feature=+ptx90 // sm_101 was renamed starting with ptx90
-Ctarget-cpu=sm_70 -Ctarget-feature=+sm_80,+ptx81 // .target directive is sm_70 but instructions are selected from sm_80

That 2nd example sounds to me like we should forbid the sm_* target features entirely and only allow them to be set via -Ctarget-cpu?

I don't understand the first example.

@kulst

kulst commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

That 2nd example sounds to me like we should forbid the sm_* target features entirely and only allow them to be set via -Ctarget-cpu?

That example is to my understanding a bug: llvm/llvm-project#202323

I don't understand the first example.

If a PTX file using PTX version 9.0 and later contains a .target sm_101 directive, ptxas (NVIDIAS assembler) will reject this PTX file. Starting with PTX 9.0 NVIDIA renamed the compute capabilities sm_101, sm_101a and sm_101f into sm_110 and the like.

@RalfJung

RalfJung commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

If a PTX file using PTX version 9.0 and later contains a .target sm_101 directive, ptxas (NVIDIAS assembler) will reject this PTX file.

So... some newer ptx declarations are incompatible with some older sm_ declarations?
That's fundamentally breaking the usual contract of target features. I am beginning to think that none of these should be allowed with -Ctarget-features, we need a completely different UI for this. Someone made this a total mess and now we have to figure out how to clean it up.

@kjetilkjeka

Copy link
Copy Markdown
Contributor

So... some newer ptx declarations are incompatible with some older sm_ declarations?
That's fundamentally breaking the usual contract of target features. I am beginning to think that none of these should be allowed with -Ctarget-features, we need a completely different UI for this. Someone made this a total mess and now we have to figure out how to clean it up.

While setting -Ctarget-feature=+sm_80 is problematic, we still want to use these target features for conditional compilation with #[cfg(target_feature = "ptx80"). This comment describes how that was previously not possible, but I'm not sure that limitation is still in place?

On the ptx ISA side of the feature problem something like the flag described here would also need to be in place. I never got around to making an MCP, but I will do that next week.

When disallowing them with -Ctarget-features we should also disallow them with #[target_feature(enable = <...>)]


Thanks a lot for removing my mess in codegen_ssa and thanks to Ralf for pointing it out.

Previously, Rust did not explicitly enable a PTX version target-feature,
because LLVM implied one from the selected CPU.

Starting with LLVM 22, the NVPTX backend still infers the minimum required
PTX version from the selected CPU when none is selected explicitly, but no
longer reflects that version in the enabled subtarget features. As a result,
cfg could miss the PTX version of the emitted PTX. Also, if a PTX version
below the required minimum is selected explicitly, LLVM errors.

We missed this because the corresponding NVPTX target-feature test was
mistakenly disabled.

To keep cfg evaluation consistent and avoid LLVM errors, always select an
explicit PTX version: whichever is higher between
 - Rust's minimum required PTX version, and
 - the CPU's minimum required PTX version.

Re-enable the NVPTX target-feature test and adapt it to Rust's minimum
required PTX and sm versions.

Forbid PTX and sm versions below Rust's minimum required versions by marking
the corresponding target-features as `InternalOnly`.

Add PTX and sm versions present in LLVM 22 or 23 but missing as Rust
target-features.
@kulst
kulst force-pushed the nvptx-fixup-target-features branch from ada34f5 to 74394da Compare October 15, 2026 07:36
@rustbot

rustbot commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@RalfJung

RalfJung commented Oct 15, 2026 via email

Copy link
Copy Markdown
Member

@kulst

kulst commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

I've rebased the PR and addressed the comments. From my perspective the PR should be mergable at this point.
While it does not resolve all issues with the NVPTX target features, it is an interim solution until a better one is in place.

This branch has not been deployed

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

Labels

A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. O-NVPTX Target: the NVPTX LLVM backend for running rust on GPUs, https://llvm.org/docs/NVPTXUsage.html S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants