mirror of
https://github.com/rust-lang/rust.git
synced 2026-07-21 23:26:41 -04:00
8e9fb78173
Convert `-Ctarget-cpu` into a target-modifier for AVR, AMDGCN and NVPTX Crates built for AVR, AMDGCN and NVPTX that specify different values for `-Ctarget-cpu` cannot be soundly linked together. This PR attempts to make `rustc` ensure that no crates with disagreeing values for `-Ctarget-cpu` are linked together. This is achieved by converting `-Ctarget-cpu` into a target-modifier depending on `--target`. To do this, the consistency check for `-Ctarget-cpu` considers mismatching values as inconsistent only for targets for which the new flag `requires_consistent_cpu` is set in their target spec. **Why should `-Ctarget-cpu` be a target-modifier for `nvptx`?** <details><summary>PTX is a single-module contract</summary> <p> PTX requires a binary to start with .version (`ptx$$`) then .target (`sm_$$`). If the ptx contains instructions that are not supported by either .version or .target, the binary is ill-formed and will be rejected by ptxas. The concept of features that can be mixed and matched in a binary does not exist for nvptx and is therefore not supported by LLVM. </p> </details> <details><summary>It prevents the production of bitcode that cannot be codegen'd after linking</summary> <p> A target modifier should prevent configurations that are not composable across crates when those crates are linked together. The most prominent example is when enabling a target feature changes the ABI, making cross-crate calls inherently unsound. In the case of nvptx, ABI mismatch is (at least for now) not the core problem motivating target modifiers. NVIDIA’s documented PTX calling convention has [remained stable since ptx20](https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability/index.html#function-calling-sequence). However, in the current state it is possible to produce bitcode that cannot be codegen'd after linking, because some operations are only lowerable for sufficiently new SM/PTX levels. In the best case this results in an LLVM error during the final llc step, but this is not something we should rely on for correctness. nvptx has a special compilation pipeline where instead of linking the final PTX object, instead LLVM bitcode is linked. The resulting artifact is then compiled in one invocation. Now consider crate A which is independently compiled into bitcode with the following rustc arguments: ```Rust //@ compile-flags: --target nvptx64-nvidia-cuda -C target-cpu=sm_70 --crate-type=rlib #[cfg(target_feature = "sm_70")] fn foo() { // cannot be lowered to ptx before "sm_70: so currently produces an LLVM error } #[cfg(not(target_feature = "sm_70"))] fn foo() { // can be lowered to ptx before "sm_70" } pub fn bar() { foo() } ``` Crate A is a dependency of crate B. In the *rustc* invocation of crate B 1. crate B is compiled into bitcode, too 2. both bitcode artifacts are bitcode-linked by *llvm-link* 3. the resulting bitcode artifact is compiled by *llc -mcpu=sm_60* This should now ideally create an LLVM error, because the linked bitcode contains code paths that were selected under `sm_70` assumptions but the final NVPTX codegen is targeting `sm_60`, where those operations are not lowerable. An LLVM error here is better than silent miscompilation, but it’s not a promise we should rely on. A real example where this could happen is the lowering of atomic loads and stores with non-relaxed orderings, which is known to depend on the selected SM level. </p> </details> **Why should `-Ctarget-cpu` be a target-modifier for `amdgcn` and `avr`?** - In case of AVR the target-cpu defines the ISA, which is encoded in the ELF header flags, amdgcn also encodes the cpu directly into those flags - To not rely on *lld* which currently prevents it for both by looking at those flags [AVR](https://github.com/llvm/llvm-project/blob/597ffbe09d5f774f861ee55e50022bf84d7f98e2/lld/test/ELF/avr-flags.s) and [amdgcn](https://github.com/llvm/llvm-project/blob/597ffbe09d5f774f861ee55e50022bf84d7f98e2/lld/test/ELF/amdgpu-elf-flags-err.s) Previous discussions about the topic can be found [here](https://github.com/rust-lang/rust/issues/131799#issuecomment-3390563329) and [here](https://github.com/rust-lang/rust/issues/141468). I also created a [Zulip discussion](https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/Making.20-Ctarget-cpu.20a.20target-modifier.20on.20NVPTX/with/566622679). I am unsure if a MCP is needed before proceeding. If you think so please let me know. Creating *target-modifiers* for NVPTX *target-features* is to be done in a follow-up. cc @kjetilkjeka as target maintainer for NVPTX cc @flakebi as target maintainer for amdgcn cc @Patryk27 as target maintainer for AVR cc @RalfJung you were very involved in the discussions so far Target modifier tracking issue: https://github.com/rust-lang/rust/issues/136966