diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index bcbafab585b40..3baaadfe477d7 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -210,6 +210,12 @@ pub(crate) struct FixedX18InvalidArch<'a> { pub arch: &'a str, } +#[derive(Diagnostic)] +#[diag("the `-Zmips-nan2008` flag is not supported on the `{$arch}` architecture")] +pub(crate) struct MipsNan2008InvalidArch<'a> { + pub arch: &'a str, +} + #[derive(Diagnostic)] #[diag("`-Zpacked-stack` is incompatible with `backchain` target feature")] #[note( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 73b7f699b606d..adf5cb72b81cb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -639,6 +639,19 @@ fn llvm_features_by_flags(sess: &Session, features: &mut Vec) { features.push("+reserve-x18".into()); } } + + // -Zmips-nan2008 + if sess.opts.unstable_opts.mips_nan2008 { + match sess.target.arch { + Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => { + features.push("+nan2008".into()); + } + _ => { + sess.dcx() + .emit_fatal(errors::MipsNan2008InvalidArch { arch: sess.target.arch.desc() }); + } + } + } } /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 22b643e74e582..8794b5f5c85bc 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -846,6 +846,7 @@ fn test_unstable_options_tracking_hash() { tracked!(merge_functions, Some(MergeFunctions::Disabled)); tracked!(min_function_alignment, Some(Align::EIGHT)); tracked!(min_recursion_limit, Some(256)); + tracked!(mips_nan2008, true); tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]); tracked!(mir_opt_level, Some(4)); tracked!(mir_preserve_ub, true); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 6f3a505c2c26f..934f0eb86991a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2579,6 +2579,8 @@ options! { "align all functions to at least this many bytes. Must be a power of 2"), min_recursion_limit: Option = (None, parse_opt_number, [TRACKED], "set a minimum recursion limit (final limit = max(this, recursion_limit_from_crate))"), + mips_nan2008: bool = (false, parse_bool, [TRACKED] { TARGET_MODIFIER: MipsNan2008 }, + "enable the nan2008 target feature (IEEE 754-2008 NaN encoding) on MIPS targets (default: no)"), mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED], "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the \ specified passes to be enabled, overriding all other checks. In particular, this will \ diff --git a/src/doc/unstable-book/src/compiler-flags/mips-nan2008.md b/src/doc/unstable-book/src/compiler-flags/mips-nan2008.md new file mode 100644 index 0000000000000..f0c478cb4b97b --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/mips-nan2008.md @@ -0,0 +1,24 @@ +# `mips-nan2008` + +This option enables the LLVM `nan2008` subtarget feature on MIPS targets. It is +only supported on `mips`, `mips32r6`, `mips64`, and `mips64r6` architectures. +Using this flag on other targets is an error. + +When enabled, this flag causes the compiler to select the IEEE 754-2008 NaN +encoding for MIPS targets, as opposed to the legacy MIPS NaN encoding. This is +useful when linking against C libraries and toolchains built with GCC's +`-mnan=2008` flag, or when the system ABI mandates the 2008 NaN encoding. + +This flag is a target modifier. All crates in the crate graph must agree on +whether the `mips-nan2008` flag is used. The compiler will emit an error if +crates with conflicting settings are linked together. This error can be bypassed +at your own risk using the `-Cunsafe-allow-abi-mismatch=mips-nan2008` flag, +though this may cause runtime failures if the ABIs are truly incompatible. + +## Example + +To compile code for MIPS with the 2008 NaN encoding: + +```sh +rustc -Zmips-nan2008 --target mips-unknown-linux-gnu example.rs +``` diff --git a/tests/codegen-llvm/mips-nan2008.rs b/tests/codegen-llvm/mips-nan2008.rs new file mode 100644 index 0000000000000..f6cbb53e7bf24 --- /dev/null +++ b/tests/codegen-llvm/mips-nan2008.rs @@ -0,0 +1,23 @@ +// Test that the `nan2008` target feature is (not) emitted when +// the `-Zmips-nan2008` flag is (not) set. + +//@ add-minicore +//@ revisions: unset set +//@ needs-llvm-components: mips +//@ compile-flags: --target mips-unknown-linux-gnu +//@ [set] compile-flags: -Zmips-nan2008 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // unset-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+nan2008{{.*}} } + // set: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+nan2008{{.*}} } +} diff --git a/tests/ui/target_modifiers/auxiliary/mips_nan2008.rs b/tests/ui/target_modifiers/auxiliary/mips_nan2008.rs new file mode 100644 index 0000000000000..10ff30521eb0e --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/mips_nan2008.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ compile-flags: --target mips-unknown-linux-gnu -Zmips-nan2008 +//@ needs-llvm-components: mips + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/incompatible_mips_nan2008.error_generated.stderr b/tests/ui/target_modifiers/incompatible_mips_nan2008.error_generated.stderr new file mode 100644 index 0000000000000..c9585b5d98519 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_mips_nan2008.error_generated.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zmips-nan2008` will cause an ABI mismatch in crate `incompatible_mips_nan2008` + --> $DIR/incompatible_mips_nan2008.rs:13:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zmips-nan2008` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zmips-nan2008` in this crate is incompatible with `-Zmips-nan2008=` in dependency `mips_nan2008` + = help: set `-Zmips-nan2008=` in this crate or unset `-Zmips-nan2008` in `mips_nan2008` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=mips-nan2008` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/incompatible_mips_nan2008.rs b/tests/ui/target_modifiers/incompatible_mips_nan2008.rs new file mode 100644 index 0000000000000..d9a383fa8ba80 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_mips_nan2008.rs @@ -0,0 +1,18 @@ +//@ aux-build:mips_nan2008.rs +//@ compile-flags: --target mips-unknown-linux-gnu +//@ needs-llvm-components: mips + +//@ revisions:allow_match allow_mismatch error_generated +//@[allow_match] compile-flags: -Zmips-nan2008 +//@[allow_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=mips-nan2008 +// [error_generated] no extra compile-flags +//@[allow_mismatch] check-pass +//@[allow_match] check-pass +//@ ignore-backends: gcc + +#![feature(no_core)] +//[error_generated]~^ ERROR mixing `-Zmips-nan2008` will cause an ABI mismatch in crate `incompatible_mips_nan2008` +#![crate_type = "rlib"] +#![no_core] + +extern crate mips_nan2008;