Skip to content

Extract some shared code from codegen backend target feature handling #140920

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

RalfJung
Copy link
Member

@RalfJung RalfJung commented May 11, 2025

There's a bunch of code duplication between the GCC and LLVM backends in target feature handling. This moves that into new shared helper functions in rustc_codegen_ssa.

The first two commits should be purely refactoring. I am fairly sure the LLVM-side behavior stays the same; if the GCC side deliberately diverges from this then I may have missed that. I did account for one divergence, which I do not know is deliberate or not: GCC does not seem to use the -Ctarget-feature flag to populate cfg(target_feature). That seems odd, since the -Ctarget-feature flag is used to populate the return value of global_gcc_features which controls the target features actually used by GCC. @GuillaumeGomez @antoyo is there a reason target_config ignores -Ctarget-feature but global_gcc_features does not?

The third commit extracts some shared logic out of the functions that populate cfg(target_feature) and the backend target feature set, respectively. This one actually has some slight functional changes:

  • Before, with -Ctarget-feature=-feat, if there is some other feature x that implies feat we would not add -x to the backend target feature set. Now, we do. This fixes Target feature implications for negative features are handled inconsistently between codegen and cfg(target_feature) #134792.
  • The logic that removes x from cfg(target_feature) in this case also changed a bit, avoiding a large number of calls to the (uncached) sess.target.implied_target_features (if there were a large number of positive features listed before a negative feature) but instead constructing a full inverse implication map when encountering the first negative feature. Ideally this would be done with queries but the backend target feature logic runs before tcx so we can't use that...
  • Previously, if feature "a" implied "b" and "b" was unstable, then using -Ctarget-feature=+a would also emit a warning about b. I had to remove this since when accounting for negative implications, this emits a ton of warnings in a bunch of existing tests... I assume this was unintentional anyway.

The fourth commit increases consistency of the GCC backend with the LLVM backend.

@bjorn3 I did not touch the cranelift backend here, since AFAIK it doesn't really support target features. But if you ever do, please use the new helpers. :)

Cc @workingjubilee

@rustbot
Copy link
Collaborator

rustbot commented May 11, 2025

r? @compiler-errors

rustbot has assigned @compiler-errors.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added A-attributes Area: Attributes (`#[…]`, `#![…]`) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 11, 2025
@rustbot
Copy link
Collaborator

rustbot commented May 11, 2025

Some changes occurred in compiler/rustc_codegen_ssa

cc @WaffleLapkin

Some changes occurred in compiler/rustc_codegen_ssa/src/codegen_attrs.rs

cc @jdonszelmann

Some changes occurred in compiler/rustc_codegen_gcc

cc @antoyo, @GuillaumeGomez

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label May 11, 2025
Copy link
Member Author

Choose a reason for hiding this comment

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

There's a lot more logic in this file that seems like it should be shared across backends (almost all of fn codegen_fn_attrs), but I shied away from the huge refactor that would have been.

@rust-log-analyzer

This comment has been minimized.

@RalfJung RalfJung force-pushed the target-feature-unification branch from 8175ae7 to b0607f4 Compare May 11, 2025 10:07
@RalfJung
Copy link
Member Author

Turns out properly adding negative implications to the target_features we set for LLVM tends to add a lot of target features -- we have some quite extensive implication chains. Is that a problem? Cc @nikic @taiki-e

@rust-log-analyzer

This comment has been minimized.

@antoyo
Copy link
Contributor

antoyo commented May 11, 2025

if the GCC side deliberately diverges from this then I may have missed that. I did account for one divergence, which I do not know is deliberate or not: GCC does not seem to use the -Ctarget-feature flag to populate cfg(target_feature). That seems odd, since the -Ctarget-feature flag is used to populate the return value of global_gcc_features which controls the target features actually used by GCC. @GuillaumeGomez @antoyo is there a reason target_config ignores -Ctarget-feature but global_gcc_features does not?

There is no reason for that. I probably missed some stuff when I implemented this.
I'd be happy to have the same behavior as LLVM here.

@RalfJung RalfJung force-pushed the target-feature-unification branch from b0607f4 to e3f260f Compare May 11, 2025 10:51
@rust-log-analyzer

This comment has been minimized.

@RalfJung RalfJung force-pushed the target-feature-unification branch from e3f260f to e973da1 Compare May 11, 2025 11:28
@rust-log-analyzer

This comment has been minimized.

@RalfJung RalfJung force-pushed the target-feature-unification branch 2 times, most recently from c46d167 to 891f35e Compare May 11, 2025 12:09
@nikic
Copy link
Contributor

nikic commented May 11, 2025

Turns out properly adding negative implications to the target_features we set for LLVM tends to add a lot of target features -- we have some quite extensive implication chains. Is that a problem? Cc @nikic @taiki-e

Anything in particular you're concerned about? But generally, no, it shouldn't be a problem.

@RalfJung
Copy link
Member Author

I can imagine two concerns:

  • So many attributes cause some sort of perf issue?
  • We actually have more implications in rustc than LLVM recognizes, so now we're disabling more things than before. This is probably a bugfix but still it'd be good to know if there is such a case...

@bors
Copy link
Collaborator

bors commented May 19, 2025

☔ The latest upstream changes (presumably #141238) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung RalfJung force-pushed the target-feature-unification branch from 891f35e to 9fc38d1 Compare May 19, 2025 11:24
@compiler-errors
Copy link
Member

r? compiler

@bors
Copy link
Collaborator

bors commented May 23, 2025

☔ The latest upstream changes (presumably #135160) made this pull request unmergeable. Please resolve the merge conflicts.

@RalfJung RalfJung force-pushed the target-feature-unification branch from 9fc38d1 to 1a58c68 Compare May 23, 2025 06:20
@RalfJung
Copy link
Member Author

RalfJung commented May 23, 2025

This is somewhat bitrotty... and to my knowledge rather outside your typical review areas, @nnethercote.

@workingjubilee @bjorn3 @nikic maybe one of you could take this?

@RalfJung RalfJung force-pushed the target-feature-unification branch from 1a58c68 to 8915a90 Compare May 23, 2025 06:31
@nnethercote
Copy link
Contributor

There's a bunch of code duplication between the GCC and LLVM backends in target feature handling. This moves that into new shared helper functions.

That sounds reasonable.

I placed those in rustc_middle since I couldn't think of a better place to put them... I'm open for suggestions. :)

I think you've gotten off-track here.

rustc_codegen_ssa is the logical spot for stuff shared between backends, because all backends depend on it. The doc comment at the top of its lib.rs says //! This crate contains codegen code that is used by all codegen backends (LLVM and others).

Also, rustc_middle is already too big and shouldn't get anything added to it that doesn't need to be.

Here's part of the crate graph. You can see how rustc_codegen_llvm depends directly on rustc_codegen_ssa, while rustc_middle is several layers further down. rustc_codegen_gcc isn't included, I think because it's in a sub-repo, but it would sit next to rustc_codegen_llvm and also depend directly on rustc_codegen_ssa.

Screenshot from 2025-05-29 19-08-49

Crate graph generated with:

cargo +nightly depgraph --all-deps --dedup-transitive-deps --workspace-only > ~/graph.dot;
dot -Tpng ~/graph.dot > ~/graph.png

Based on this, I think significant parts of this PR are unnecessary:

  • Anything moved from rustc_codegen_ssa to rustc_middle should be left where it is. (E.g. you moved rustc_codegen_ssa/src/target_features.rs to rustc_middle.)
  • Anything moved from rustc_codegen_{llvm,gcc} to rustc_middle should instead be moved to rustc_codegen_ssa.

This will significantly reduce the size of the PR, e.g. the entire first commit would disappear, along with part of the third commit.

@RalfJung
Copy link
Member Author

RalfJung commented May 29, 2025

rustc_codegen_ssa is the logical spot for stuff shared between backends, because all backends depend on it.

That's not correct, the cranelift backend does not. The comment you cite seems to be outdated. In my understanding, rustc_codegen_ssa is a convenience wrapper that a codegen backend can choose to use, but not all do.

cranelift does not currently support target features, but it'd be a bad idea to fundamentally exclude it from using the shared target feature infrastructure in the future.

Also, rustc_middle is already too big and shouldn't get anything added to it that doesn't need to be.

I agree, which is why I didn't like putting things there -- but for the reason given above, I'm not sure where else to put it.

@nnethercote
Copy link
Contributor

That's not correct, the cranelift backend does not.

extern crate rustc_codegen_ssa;

@RalfJung
Copy link
Member Author

The last thing I heard from @bjorn3 is that it does not use codegen_ssa. Maybe it uses just some helper types, or maybe that changed -- @bjorn3, could you clarify?

But if it imports that crate then I guess even if it doesn't use the actual SSA builder part of codegen_ssa, codegen_ssa is still a good place to put shared helpers. Good point!

@bjorn3
Copy link
Member

bjorn3 commented May 29, 2025

cg_clif doesn't use the MIR building infrastructure or codegen scheduling code of cg_ssa, but it does use the linking code, archive builder, naked asm implementation and a bunch of other things from cg_ssa. My goal is to slowly make more and more of cg_ssa usable for cg_clif and then migrate cg_clif to use those as opposed to its own code, reducing the maintenance burden of cg_clif.

RalfJung added 4 commits May 29, 2025 14:11
This does change the logic a bit: previously, we didn't forward reverse
implications of negated features to the backend, instead relying on the backend
to handle the implication itself.
@RalfJung RalfJung force-pushed the target-feature-unification branch from 8915a90 to 4e481c6 Compare May 29, 2025 12:24
@rustbot rustbot added the A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. label May 29, 2025
@RalfJung
Copy link
Member Author

This will significantly reduce the size of the PR, e.g. the entire first commit would disappear, along with part of the third commit.

I did this now. Thanks for catching this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-attributes Area: Attributes (`#[…]`, `#![…]`) A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. 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.

Target feature implications for negative features are handled inconsistently between codegen and cfg(target_feature)
9 participants