diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ed0d5e68cbf9a..6aa24acfeb259 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -350,6 +350,19 @@ pub unsafe fn create_module<'ll>( ) } + if let Some(threshold) = sess.opts.unstable_opts.small_data_threshold { + // Set up the small-data optimization limit for architectures that use + // an LLVM module flag to control this. + if sess.target.arch.starts_with("riscv") { + llvm::LLVMRustAddModuleFlag( + llmod, + llvm::LLVMModFlagBehavior::Error, + "SmallDataLimit\0".as_ptr().cast(), + threshold as u32, + ) + } + } + // Insert `llvm.ident` metadata. // // On the wasm targets it will get hooked up to the "producer" sections diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 93cb7327a017e..6a7caba43c563 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -118,6 +118,24 @@ unsafe fn configure_llvm(sess: &Session) { for arg in sess_args { add(&(*arg), true); } + + if let Some(threshold) = sess.opts.unstable_opts.small_data_threshold { + // Set up the small-data optimization limit for architectures that use + // an LLVM argument to control this. + match sess.target.arch.as_ref() { + "hexagon" => add(&format!("--hexagon-small-data-threshold={threshold}"), false), + // m68k accepts the --m68k-ssection-threshold argument but then + // ignores it, so this currently has no effect on m68k + "m68k" => add(&format!("--m68k-ssection-threshold={threshold}"), false), + // There's currently no rustc support for the Lanai architecture, so this is untested + "lanai" => add(&format!("--lanai-ssection-threshold={threshold}"), false), + arch @ _ => { + if arch.starts_with("mips") { + add(&format!("--mips-ssection-threshold={threshold}"), false); + } + } + } + } } if sess.opts.unstable_opts.llvm_time_trace { diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index ce58b2ab06170..54cc9c9913a0b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -813,6 +813,7 @@ fn test_unstable_options_tracking_hash() { tracked!(share_generics, Some(true)); tracked!(show_span, Some(String::from("abc"))); tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc"))); + tracked!(small_data_threshold, Some(16)); tracked!(split_lto_unit, Some(true)); tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1)); tracked!(stack_protector, StackProtector::All); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index d666c5d4d702c..470a67b262f9a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1857,6 +1857,8 @@ written to standard error output)"), simulate_remapped_rust_src_base: Option = (None, parse_opt_pathbuf, [TRACKED], "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ to rust's source base directory. only meant for testing purposes"), + small_data_threshold: Option = (None, parse_opt_number, [TRACKED], + "Set the threshold for objects to be stored in a \"small data\" section"), span_debug: bool = (false, parse_bool, [UNTRACKED], "forward proc_macro::Span's `Debug` impl to `Span`"), /// o/w tests have closure@path diff --git a/src/doc/unstable-book/src/compiler-flags/small-data-threshold.md b/src/doc/unstable-book/src/compiler-flags/small-data-threshold.md new file mode 100644 index 0000000000000..bbc4b7e4b2b99 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/small-data-threshold.md @@ -0,0 +1,8 @@ +# `small-data-threshold` + +----------------------- + +This flag controls the maximum static variable size that may be included in the +"small data sections" (.sdata, .sbss) supported by some architectures (RISCV, +MIPS, M68K, Hexagon). Can be set to `0` to disable the use of small data +sections. diff --git a/tests/assembly/small_data_threshold.rs b/tests/assembly/small_data_threshold.rs new file mode 100644 index 0000000000000..e2c530a928a5e --- /dev/null +++ b/tests/assembly/small_data_threshold.rs @@ -0,0 +1,92 @@ +// Test for -Z small_data_threshold=... +// revisions: RISCV MIPS HEXAGON M68K +// assembly-output: emit-asm +// compile-flags: -Z small_data_threshold=4 +// [RISCV] compile-flags: --target=riscv32im-unknown-none-elf +// [RISCV] needs-llvm-components: riscv +// [MIPS] compile-flags: --target=mips-unknown-linux-uclibc -C relocation-model=static +// [MIPS] compile-flags: -C llvm-args=-mgpopt -C llvm-args=-mlocal-sdata +// [MIPS] compile-flags: -C target-feature=+noabicalls +// [MIPS] needs-llvm-components: mips +// [HEXAGON] compile-flags: --target=hexagon-unknown-linux-musl -C target-feature=+small-data +// [HEXAGON] compile-flags: -C llvm-args=--hexagon-statics-in-small-data +// [HEXAGON] needs-llvm-components: hexagon +// [M68K] compile-flags: --target=m68k-unknown-linux-gnu +// [M68K] needs-llvm-components: m68k + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +#[lang = "drop_in_place"] +fn drop_in_place(_: *mut T) {} + +#[used] +#[no_mangle] +// U is below the threshold, should be in sdata +static mut U: u16 = 123; + +#[used] +#[no_mangle] +// V is below the threshold, should be in sbss +static mut V: u16 = 0; + +#[used] +#[no_mangle] +// W is at the threshold, should be in sdata +static mut W: u32 = 123; + +#[used] +#[no_mangle] +// X is at the threshold, should be in sbss +static mut X: u32 = 0; + +#[used] +#[no_mangle] +// Y is over the threshold, should be in its own .data section +static mut Y: u64 = 123; + +#[used] +#[no_mangle] +/// Z is over the threshold, should be in its own .bss section +static mut Z: u64 = 0; + +// Currently, only MIPS and RISCV successfully put any objects in the small data +// sections so the U/V/W/X tests are skipped on Hexagon and M68K + +// RISCV: .section .sdata, +// RISCV-NOT: .section +// RISCV: U: +// RISCV: .section .sbss +// RISV-NOT: .section +// RISCV: V: +// RISCV .section .sdata +// RISV-NOT: .section +// RISCV: W: +// RISCV: .section .sbss +// RISV-NOT: .section +// RISCV: X: + +// MIPS: .section .sdata, +// MIPS-NOT: .section +// MIPS: U: +// MIPS: .section .sbss +// RISV-NOT: .section +// MIPS: V: +// MIPS .section .sdata +// RISV-NOT: .section +// MIPS: W: +// MIPS: .section .sbss +// RISV-NOT: .section +// MIPS: X: + +// CHECK: .section .data.Y, +// CHECK-NOT: .section +// CHECK: Y: +// CHECK: .section .bss.Z, +// CHECK-NOT: .section +// CHECK: Z: