diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index b67f6ca851177..2b547e5502842 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -51,9 +51,9 @@ unsafe fn configure_llvm(sess: &EarlySession) { let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); + let (llvm_major, llvm_minor, llvm_patch) = get_version(); // Check to ensure we're running against the correct LLVM version. unsafe { - let (llvm_major, llvm_minor, llvm_patch) = get_version(); let expected_version = llvm::LLVMRustVersionMajor(); if llvm_major != expected_version { sess.dcx().emit_fatal(diagnostics::LlvmVersionMismatch { @@ -127,10 +127,14 @@ unsafe fn configure_llvm(sess: &EarlySession) { } } - if get_version() < (24, 0, 0) && wants_wasm_eh(&sess.target) { + if llvm_major < 24 && wants_wasm_eh(&sess.target) { add("-wasm-enable-eh", false); } + for arg in sess.target.llvm_args_for_llvm_version(llvm_major) { + add(arg.as_ref(), false); + } + // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes // during inlining. Unfortunately these may block other optimizations. add("-preserve-alignment-assumptions-during-inlining=false", false); diff --git a/compiler/rustc_target/src/spec/base/bpf.rs b/compiler/rustc_target/src/spec/base/bpf.rs index 8d541cb78deac..95bf9494de733 100644 --- a/compiler/rustc_target/src/spec/base/bpf.rs +++ b/compiler/rustc_target/src/spec/base/bpf.rs @@ -1,8 +1,11 @@ +use std::collections::BTreeMap; + use rustc_abi::Endian; -use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, TargetOptions}; +use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, StaticCow, TargetOptions, cvs}; pub(crate) fn opts(endian: Endian) -> TargetOptions { + let allows_libcalls: StaticCow<[StaticCow]> = cvs!["-bpf-allows-libcalls"]; TargetOptions { allow_asm: true, endian, @@ -24,6 +27,7 @@ pub(crate) fn opts(endian: Endian) -> TargetOptions { // and would require a bit of a refactor. min_atomic_width: Some(64), max_atomic_width: Some(64), + llvm_args_by_version: BTreeMap::from([(23, allows_libcalls)]), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 03dbbcb5b481d..57fa78bee6c36 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -203,6 +203,7 @@ impl Target { forward_opt!(rustc_abi); forward!(relax_elf_relocations); forward!(llvm_args); + forward!(llvm_args_by_version); forward!(use_ctors_section); forward!(eh_frame_header); forward!(has_thumb_interworking); @@ -396,6 +397,7 @@ impl ToJson for Target { target_option_val!(rustc_abi); target_option_val!(relax_elf_relocations); target_option_val!(llvm_args); + target_option_val!(llvm_args_by_version); target_option_val!(use_ctors_section); target_option_val!(eh_frame_header); target_option_val!(has_thumb_interworking); @@ -619,6 +621,7 @@ struct TargetSpecJson { rustc_abi: Option, relax_elf_relocations: Option, llvm_args: Option]>>, + llvm_args_by_version: Option]>>>, use_ctors_section: Option, eh_frame_header: Option, has_thumb_interworking: Option, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index ae17e37e29f86..200ba166d09dd 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2550,6 +2550,7 @@ pub struct TargetOptions { /// Additional arguments to pass to LLVM, similar to the `-C llvm-args` codegen option. pub llvm_args: StaticCow<[StaticCow]>, + pub llvm_args_by_version: BTreeMap]>>, /// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults /// to false (uses .init_array). @@ -2835,6 +2836,7 @@ impl Default for TargetOptions { rustc_abi: None, relax_elf_relocations: false, llvm_args: cvs![], + llvm_args_by_version: BTreeMap::new(), use_ctors_section: false, eh_frame_header: true, has_thumb_interworking: false, @@ -2893,6 +2895,13 @@ impl Target { self.max_atomic_width.unwrap_or_else(|| self.pointer_width.into()) } + pub fn llvm_args_for_llvm_version<'a>( + &'a self, + major: u32, + ) -> impl Iterator> { + self.llvm_args_by_version.range(..=major).flat_map(|(_, args)| args.iter()) + } + /// Test target self-consistency and JSON encoding/decoding roundtrip. #[cfg(test)] fn test_target(mut self) { diff --git a/compiler/rustc_target/src/tests.rs b/compiler/rustc_target/src/tests.rs index bb17dd151b58d..3cdbc13fc429e 100644 --- a/compiler/rustc_target/src/tests.rs +++ b/compiler/rustc_target/src/tests.rs @@ -1,5 +1,8 @@ +use std::borrow::Cow; +use std::collections::BTreeMap; + use crate::json::ToJson; -use crate::spec::Target; +use crate::spec::{Target, TargetTuple}; #[test] fn report_unused_fields() { @@ -40,3 +43,54 @@ fn custom_arch_propagates_from_json() { assert_eq!(serialized["arch"], "customarch"); }); } + +fn bpf_target_with_versioned_args(map: BTreeMap]>>) -> Target { + let mut t = Target::expect_builtin(&TargetTuple::from_tuple("bpfeb-unknown-none")); + t.options.llvm_args_by_version = map; + t +} + +#[test] +fn llvm_args_by_version_empty_map_returns_no_args() { + let t = bpf_target_with_versioned_args(BTreeMap::new()); + assert!(t.llvm_args_for_llvm_version(1).collect::>().is_empty()); + assert!(t.llvm_args_for_llvm_version(9999).collect::>().is_empty()); +} + +#[test] +fn llvm_args_by_version_excludes_entries_above_major() { + let t = bpf_target_with_versioned_args(BTreeMap::from([ + (23u32, Cow::Borrowed(&[Cow::Borrowed("-a")][..])), + (24, Cow::Borrowed(&[Cow::Borrowed("-b")][..])), + ])); + assert!(t.llvm_args_for_llvm_version(22).collect::>().is_empty()); + assert_eq!(t.llvm_args_for_llvm_version(23).collect::>(), &[&Cow::Borrowed("-a")]); + assert_eq!( + t.llvm_args_for_llvm_version(24).collect::>(), + &[&Cow::Borrowed("-a"), &Cow::Borrowed("-b")] + ); + assert_eq!( + t.llvm_args_for_llvm_version(25).collect::>(), + &[&Cow::Borrowed("-a"), &Cow::Borrowed("-b")] + ); +} + +#[test] +fn llvm_args_by_version_accumulates_multiple_entries() { + let t = bpf_target_with_versioned_args(BTreeMap::from([ + (23u32, Cow::Borrowed(&[Cow::Borrowed("-a"), Cow::Borrowed("-b")][..])), + (24, Cow::Borrowed(&[Cow::Borrowed("-c")][..])), + ])); + assert_eq!( + t.llvm_args_for_llvm_version(23).collect::>(), + &[&Cow::Borrowed("-a"), &Cow::Borrowed("-b")] + ); + assert_eq!( + t.llvm_args_for_llvm_version(24).collect::>(), + &[&Cow::Borrowed("-a"), &Cow::Borrowed("-b"), &Cow::Borrowed("-c")] + ); + assert_eq!( + t.llvm_args_for_llvm_version(100).collect::>(), + &[&Cow::Borrowed("-a"), &Cow::Borrowed("-b"), &Cow::Borrowed("-c")] + ); +} diff --git a/tests/assembly-llvm/bpf-libcall.rs b/tests/assembly-llvm/bpf-libcall.rs new file mode 100644 index 0000000000000..7133c08aa7474 --- /dev/null +++ b/tests/assembly-llvm/bpf-libcall.rs @@ -0,0 +1,19 @@ +//@ add-minicore +//@ revisions: el eb +//@ assembly-output: emit-asm +//@ [el] compile-flags: --target bpfel-unknown-none -Copt-level=0 +//@ [eb] compile-flags: --target bpfeb-unknown-none -Copt-level=0 +//@ needs-llvm-components: bpf +//@ min-llvm-version: 23 +#![feature(no_core, f16)] +#![no_core] +#![crate_type = "lib"] + +extern crate minicore; + +// CHECK-LABEL: f16_to_f32: +// CHECK: call __extendhfsf2 +#[no_mangle] +pub fn f16_to_f32(x: f16) -> f32 { + x as f32 +}