2019-02-17 18:58:58 +00:00
|
|
|
use crate::back::write::create_informational_target_machine;
|
2022-10-30 18:26:12 +00:00
|
|
|
use crate::errors::{
|
2024-02-04 00:57:47 +00:00
|
|
|
InvalidTargetFeaturePrefix, PossibleFeature, TargetFeatureDisableOrEnable,
|
|
|
|
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
2022-10-30 18:26:12 +00:00
|
|
|
};
|
2022-08-25 13:42:20 +00:00
|
|
|
use crate::llvm;
|
2017-04-30 18:33:25 +00:00
|
|
|
use libc::c_int;
|
2024-02-21 23:32:58 +00:00
|
|
|
use rustc_codegen_ssa::base::wants_wasm_eh;
|
2023-07-13 23:54:25 +00:00
|
|
|
use rustc_codegen_ssa::traits::PrintBackendInfo;
|
2022-01-31 13:04:27 +00:00
|
|
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
2021-07-23 13:19:22 +00:00
|
|
|
use rustc_data_structures::small_c_str::SmallCStr;
|
2021-12-13 00:00:00 +00:00
|
|
|
use rustc_fs_util::path_to_c_string;
|
2020-03-29 15:19:48 +00:00
|
|
|
use rustc_middle::bug;
|
2023-07-17 00:20:28 +00:00
|
|
|
use rustc_session::config::{PrintKind, PrintRequest};
|
2020-03-11 11:49:08 +00:00
|
|
|
use rustc_session::Session;
|
2019-12-31 17:15:40 +00:00
|
|
|
use rustc_span::symbol::Symbol;
|
2019-10-18 21:47:54 +00:00
|
|
|
use rustc_target::spec::{MergeFunctions, PanicStrategy};
|
2023-12-12 20:47:20 +00:00
|
|
|
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
2017-04-30 18:33:25 +00:00
|
|
|
|
2023-07-13 23:56:29 +00:00
|
|
|
use std::ffi::{c_char, c_void, CStr, CString};
|
2021-12-13 00:00:00 +00:00
|
|
|
use std::path::Path;
|
2021-04-08 05:00:47 +00:00
|
|
|
use std::ptr;
|
2018-08-23 18:03:22 +00:00
|
|
|
use std::slice;
|
|
|
|
use std::str;
|
2017-05-14 18:33:37 +00:00
|
|
|
use std::sync::Once;
|
|
|
|
|
2017-10-30 17:42:21 +00:00
|
|
|
static INIT: Once = Once::new();
|
|
|
|
|
|
|
|
pub(crate) fn init(sess: &Session) {
|
2017-04-30 18:33:25 +00:00
|
|
|
unsafe {
|
|
|
|
// Before we touch LLVM, make sure that multithreading is enabled.
|
2021-10-12 00:00:00 +00:00
|
|
|
if llvm::LLVMIsMultithreaded() != 1 {
|
|
|
|
bug!("LLVM compiled without support for threads");
|
|
|
|
}
|
2017-04-30 18:33:25 +00:00
|
|
|
INIT.call_once(|| {
|
|
|
|
configure_llvm(sess);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-30 17:42:21 +00:00
|
|
|
fn require_inited() {
|
2021-10-12 00:00:00 +00:00
|
|
|
if !INIT.is_completed() {
|
|
|
|
bug!("LLVM is not initialized");
|
2017-10-30 17:42:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-30 18:33:25 +00:00
|
|
|
unsafe fn configure_llvm(sess: &Session) {
|
2020-11-08 11:27:51 +00:00
|
|
|
let n_args = sess.opts.cg.llvm_args.len() + sess.target.llvm_args.len();
|
2018-10-08 14:55:04 +00:00
|
|
|
let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
|
|
|
|
let mut llvm_args = Vec::with_capacity(n_args + 1);
|
2017-04-30 18:33:25 +00:00
|
|
|
|
2024-03-15 22:49:06 +00:00
|
|
|
llvm::LLVMRustInstallErrorHandlers();
|
2022-02-03 15:03:44 +00:00
|
|
|
// On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog
|
|
|
|
// box for the purpose of launching a debugger. However, on CI this will
|
|
|
|
// cause it to hang until it times out, which can take several hours.
|
|
|
|
if std::env::var_os("CI").is_some() {
|
|
|
|
llvm::LLVMRustDisableSystemDialogsOnCrash();
|
|
|
|
}
|
2018-10-12 19:35:55 +00:00
|
|
|
|
2019-12-18 13:19:03 +00:00
|
|
|
fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
|
|
|
|
full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
|
|
|
|
}
|
|
|
|
|
2022-03-22 10:43:05 +00:00
|
|
|
let cg_opts = sess.opts.cg.llvm_args.iter().map(AsRef::as_ref);
|
|
|
|
let tg_opts = sess.target.llvm_args.iter().map(AsRef::as_ref);
|
2020-01-18 00:11:52 +00:00
|
|
|
let sess_args = cg_opts.chain(tg_opts);
|
2020-01-09 15:40:40 +00:00
|
|
|
|
|
|
|
let user_specified_args: FxHashSet<_> =
|
2020-02-28 13:20:33 +00:00
|
|
|
sess_args.clone().map(|s| llvm_arg_to_arg_name(s)).filter(|s| !s.is_empty()).collect();
|
2019-12-18 13:19:03 +00:00
|
|
|
|
2017-04-30 18:33:25 +00:00
|
|
|
{
|
2019-12-18 13:19:03 +00:00
|
|
|
// This adds the given argument to LLVM. Unless `force` is true
|
|
|
|
// user specified arguments are *not* overridden.
|
|
|
|
let mut add = |arg: &str, force: bool| {
|
|
|
|
if force || !user_specified_args.contains(llvm_arg_to_arg_name(arg)) {
|
|
|
|
let s = CString::new(arg).unwrap();
|
|
|
|
llvm_args.push(s.as_ptr());
|
|
|
|
llvm_c_strs.push(s);
|
|
|
|
}
|
2017-04-30 18:33:25 +00:00
|
|
|
};
|
2020-08-12 22:30:41 +00:00
|
|
|
// Set the llvm "program name" to make usage and invalid argument messages more clear.
|
|
|
|
add("rustc -Cllvm-args=\"...\" with", true);
|
2022-12-20 14:02:15 +00:00
|
|
|
if sess.opts.unstable_opts.time_llvm_passes {
|
2019-12-18 13:19:03 +00:00
|
|
|
add("-time-passes", false);
|
|
|
|
}
|
2022-12-20 14:02:15 +00:00
|
|
|
if sess.opts.unstable_opts.print_llvm_passes {
|
2019-12-18 13:19:03 +00:00
|
|
|
add("-debug-pass=Structure", false);
|
|
|
|
}
|
2021-11-10 18:47:00 +00:00
|
|
|
if sess.target.generate_arange_section
|
2022-07-06 12:44:47 +00:00
|
|
|
&& !sess.opts.unstable_opts.no_generate_arange_section
|
2021-11-01 21:16:25 +00:00
|
|
|
{
|
2019-12-18 13:19:03 +00:00
|
|
|
add("-generate-arange-section", false);
|
2019-11-18 23:05:01 +00:00
|
|
|
}
|
2021-06-05 11:35:19 +00:00
|
|
|
|
2022-07-06 12:44:47 +00:00
|
|
|
match sess.opts.unstable_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
|
2020-04-14 19:10:58 +00:00
|
|
|
MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
|
|
|
|
MergeFunctions::Aliases => {
|
|
|
|
add("-mergefunc-use-aliases", false);
|
2018-12-31 18:58:13 +00:00
|
|
|
}
|
2018-11-29 22:05:23 +00:00
|
|
|
}
|
2017-04-30 18:33:25 +00:00
|
|
|
|
2024-02-22 22:52:48 +00:00
|
|
|
if wants_wasm_eh(sess) {
|
|
|
|
add("-wasm-enable-eh", false);
|
|
|
|
}
|
|
|
|
|
2020-11-08 11:57:55 +00:00
|
|
|
if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
|
2019-12-18 13:19:03 +00:00
|
|
|
add("-enable-emscripten-cxx-exceptions", false);
|
2019-10-18 21:47:54 +00:00
|
|
|
}
|
|
|
|
|
2018-12-20 23:30:35 +00:00
|
|
|
// HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
|
|
|
|
// during inlining. Unfortunately these may block other optimizations.
|
2019-12-18 13:19:03 +00:00
|
|
|
add("-preserve-alignment-assumptions-during-inlining=false", false);
|
2018-12-20 23:30:35 +00:00
|
|
|
|
Import small cold functions
The Rust code is often written under an assumption that for generic
methods inline attribute is mostly unnecessary, since for optimized
builds using ThinLTO, a method will be generated in at least one CGU and
available for import.
For example, deref implementations for Box, Vec, MutexGuard, and
MutexGuard are not currently marked as inline, neither is identity
implementation of From trait.
In PGO builds, when functions are determined to be cold, the default
multiplier of zero will stop the import, even for completely trivial
functions.
Increase slightly the default multiplier from 0 to 0.1 to import them
regardless.
2021-03-11 00:00:00 +00:00
|
|
|
// Use non-zero `import-instr-limit` multiplier for cold callsites.
|
|
|
|
add("-import-cold-multiplier=0.1", false);
|
2018-12-20 23:30:35 +00:00
|
|
|
|
2022-11-05 08:08:57 +00:00
|
|
|
if sess.print_llvm_stats() {
|
|
|
|
add("-stats", false);
|
|
|
|
}
|
|
|
|
|
2020-01-18 00:11:52 +00:00
|
|
|
for arg in sess_args {
|
2019-12-18 13:19:03 +00:00
|
|
|
add(&(*arg), true);
|
2017-04-30 18:33:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-06 12:44:47 +00:00
|
|
|
if sess.opts.unstable_opts.llvm_time_trace {
|
2023-11-21 18:43:11 +00:00
|
|
|
llvm::LLVMRustTimeTraceProfilerInitialize();
|
2020-01-31 23:58:28 +00:00
|
|
|
}
|
|
|
|
|
2020-10-13 08:17:05 +00:00
|
|
|
rustc_llvm::initialize_available_targets();
|
2017-04-30 18:33:25 +00:00
|
|
|
|
|
|
|
llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
|
|
|
|
}
|
|
|
|
|
2021-12-13 00:00:00 +00:00
|
|
|
pub fn time_trace_profiler_finish(file_name: &Path) {
|
2020-01-31 23:58:28 +00:00
|
|
|
unsafe {
|
2021-12-13 00:00:00 +00:00
|
|
|
let file_name = path_to_c_string(file_name);
|
2023-11-21 18:43:11 +00:00
|
|
|
llvm::LLVMRustTimeTraceProfilerFinish(file_name.as_ptr());
|
2020-01-31 23:58:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-22 13:46:40 +00:00
|
|
|
pub enum TargetFeatureFoldStrength<'a> {
|
|
|
|
// The feature is only tied when enabling the feature, disabling
|
|
|
|
// this feature shouldn't disable the tied feature.
|
|
|
|
EnableOnly(&'a str),
|
|
|
|
// The feature is tied for both enabling and disabling this feature.
|
|
|
|
Both(&'a str),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> TargetFeatureFoldStrength<'a> {
|
|
|
|
fn as_str(&self) -> &'a str {
|
|
|
|
match self {
|
|
|
|
TargetFeatureFoldStrength::EnableOnly(feat) => feat,
|
|
|
|
TargetFeatureFoldStrength::Both(feat) => feat,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct LLVMFeature<'a> {
|
|
|
|
pub llvm_feature_name: &'a str,
|
|
|
|
pub dependency: Option<TargetFeatureFoldStrength<'a>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> LLVMFeature<'a> {
|
|
|
|
pub fn new(llvm_feature_name: &'a str) -> Self {
|
|
|
|
Self { llvm_feature_name, dependency: None }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn with_dependency(
|
|
|
|
llvm_feature_name: &'a str,
|
|
|
|
dependency: TargetFeatureFoldStrength<'a>,
|
|
|
|
) -> Self {
|
|
|
|
Self { llvm_feature_name, dependency: Some(dependency) }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn contains(&self, feat: &str) -> bool {
|
|
|
|
self.iter().any(|dep| dep == feat)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn iter(&'a self) -> impl Iterator<Item = &'a str> {
|
|
|
|
let dependencies = self.dependency.iter().map(|feat| feat.as_str());
|
|
|
|
std::iter::once(self.llvm_feature_name).chain(dependencies)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> IntoIterator for LLVMFeature<'a> {
|
|
|
|
type Item = &'a str;
|
|
|
|
type IntoIter = impl Iterator<Item = &'a str>;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
let dependencies = self.dependency.into_iter().map(|feat| feat.as_str());
|
|
|
|
std::iter::once(self.llvm_feature_name).chain(dependencies)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-23 13:19:22 +00:00
|
|
|
// WARNING: the features after applying `to_llvm_features` must be known
|
2018-02-20 13:05:25 +00:00
|
|
|
// to LLVM or the feature detection code will walk past the end of the feature
|
|
|
|
// array, leading to crashes.
|
2021-07-23 13:19:22 +00:00
|
|
|
//
|
2024-02-28 21:40:13 +00:00
|
|
|
// To find a list of LLVM's names, see llvm-project/llvm/lib/Target/{ARCH}/*.td
|
2022-07-19 00:40:41 +00:00
|
|
|
// where `{ARCH}` is the architecture name. Look for instances of `SubtargetFeature`.
|
|
|
|
//
|
2024-02-28 21:40:13 +00:00
|
|
|
// Check the current rustc fork of LLVM in the repo at https://github.com/rust-lang/llvm-project/.
|
|
|
|
// The commit in use can be found via the `llvm-project` submodule in https://github.com/rust-lang/rust/tree/master/src
|
2020-10-26 07:15:23 +00:00
|
|
|
// Though note that Rust can also be build with an external precompiled version of LLVM
|
|
|
|
// which might lead to failures if the oldest tested / supported LLVM version
|
|
|
|
// doesn't yet support the relevant intrinsics
|
2023-05-22 13:46:40 +00:00
|
|
|
pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
|
Add arm64ec-pc-windows-msvc target
Introduces the `arm64ec-pc-windows-msvc` target for building Arm64EC ("Emulation Compatible") binaries for Windows.
For more information about Arm64EC see <https://learn.microsoft.com/en-us/windows/arm/arm64ec>.
Tier 3 policy:
> A tier 3 target must have a designated developer or developers (the "target maintainers") on record to be CCed when issues arise regarding the target. (The mechanism to track and CC such developers may evolve over time.)
I will be the maintainer for this target.
> Targets must use naming consistent with any existing targets; for instance, a target for the same CPU or OS as an existing Rust target should use the same name for that CPU or OS. Targets should normally use the same names and naming conventions as used elsewhere in the broader ecosystem beyond Rust (such as in other toolchains), unless they have a very good reason to diverge. Changing the name of a target can be highly disruptive, especially once the target reaches a higher tier, so getting the name right is important even for a tier 3 target.
Target uses the `arm64ec` architecture to match LLVM and MSVC, and the `-pc-windows-msvc` suffix to indicate that it targets Windows via the MSVC environment.
> Target names should not introduce undue confusion or ambiguity unless absolutely necessary to maintain ecosystem compatibility. For example, if the name of the target makes people extremely likely to form incorrect beliefs about what it targets, the name should be changed or augmented to disambiguate it.
Target name exactly specifies the type of code that will be produced.
> If possible, use only letters, numbers, dashes and underscores for the name. Periods (.) are known to cause issues in Cargo.
Done.
> Tier 3 targets may have unusual requirements to build or use, but must not create legal issues or impose onerous legal terms for the Rust project or for Rust developers or users.
> The target must not introduce license incompatibilities.
Uses the same dependencies, requirements and licensing as the other `*-pc-windows-msvc` targets.
> Anything added to the Rust repository must be under the standard Rust license (MIT OR Apache-2.0).
Understood.
> The target must not cause the Rust tools or libraries built for any other host (even when supporting cross-compilation to the target) to depend on any new dependency less permissive than the Rust licensing policy. This applies whether the dependency is a Rust crate that would require adding new license exceptions (as specified by the tidy tool in the rust-lang/rust repository), or whether the dependency is a native library or binary. In other words, the introduction of the target must not cause a user installing or running a version of Rust or the Rust tools to be subject to any new license requirements.
> Compiling, linking, and emitting functional binaries, libraries, or other code for the target (whether hosted on the target itself or cross-compiling from another target) must not depend on proprietary (non-FOSS) libraries. Host tools built for the target itself may depend on the ordinary runtime libraries supplied by the platform and commonly used by other applications built for the target, but those libraries must not be required for code generation for the target; cross-compilation to the target must not require such libraries at all. For instance, rustc built for the target may depend on a common proprietary C runtime library or console output library, but must not depend on a proprietary code generation library or code optimization library. Rust's license permits such combinations, but the Rust project has no interest in maintaining such combinations within the scope of Rust itself, even at tier 3.
> "onerous" here is an intentionally subjective term. At a minimum, "onerous" legal/licensing terms include but are not limited to: non-disclosure requirements, non-compete requirements, contributor license agreements (CLAs) or equivalent, "non-commercial"/"research-only"/etc terms, requirements conditional on the employer or employment of any particular Rust developers, revocable terms, any requirements that create liability for the Rust project or its developers or users, or any requirements that adversely affect the livelihood or prospects of the Rust project or its developers or users.
Uses the same dependencies, requirements and licensing as the other `*-pc-windows-msvc` targets.
> Neither this policy nor any decisions made regarding targets shall create any binding agreement or estoppel by any party. If any member of an approving Rust team serves as one of the maintainers of a target, or has any legal or employment requirement (explicit or implicit) that might affect their decisions regarding a target, they must recuse themselves from any approval decisions regarding the target's tier status, though they may otherwise participate in discussions.
> This requirement does not prevent part or all of this policy from being cited in an explicit contract or work agreement (e.g. to implement or maintain support for a target). This requirement exists to ensure that a developer or team responsible for reviewing and approving a target does not face any legal threats or obligations that would prevent them from freely exercising their judgment in such approval, even if such judgment involves subjective matters or goes beyond the letter of these requirements.
Understood, I am not a member of the Rust team.
> Tier 3 targets should attempt to implement as much of the standard libraries as possible and appropriate (core for most targets, alloc for targets that can support dynamic memory allocation, std for targets with an operating system or equivalent layer of system-provided functionality), but may leave some code unimplemented (either unavailable or stubbed out as appropriate), whether because the target makes it impossible to implement or challenging to implement. The authors of pull requests are not obligated to avoid calling any portions of the standard library on the basis of a tier 3 target not implementing those portions.
Both `core` and `alloc` are supported.
Support for `std` dependends on making changes to the standard library, `stdarch` and `backtrace` which cannot be done yet as the bootstrapping compiler raises a warning ("unexpected `cfg` condition value") for `target_arch = "arm64ec"`.
> The target must provide documentation for the Rust community explaining how to build for the target, using cross-compilation if possible. If the target supports running binaries, or running tests (even if they do not pass), the documentation must explain how to run such binaries or tests for the target, using emulation if possible or dedicated hardware if necessary.
Documentation is provided in src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md
> Tier 3 targets must not impose burden on the authors of pull requests, or other developers in the community, to maintain the target. In particular, do not post comments (automated or manual) on a PR that derail or suggest a block on the PR based on a tier 3 target. Do not send automated messages or notifications (via any medium, including via @) to a PR author or others involved with a PR regarding a tier 3 target, unless they have opted into such messages.
> Backlinks such as those generated by the issue/PR tracker when linking to an issue or PR are not considered a violation of this policy, within reason. However, such messages (even on a separate repository) must not generate notifications to anyone involved with a PR who has not requested such notifications.
> Patches adding or updating tier 3 targets must not break any existing tier 2 or tier 1 target, and must not knowingly break another tier 3 target without approval of either the compiler team or the maintainers of the other tier 3 target.
> In particular, this may come up when working on closely related targets, such as variations of the same architecture with different features. Avoid introducing unconditional uses of features that another variation of the target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target.
Understood.
2023-12-16 00:46:34 +00:00
|
|
|
let arch = if sess.target.arch == "x86_64" {
|
|
|
|
"x86"
|
|
|
|
} else if sess.target.arch == "arm64ec" {
|
|
|
|
"aarch64"
|
|
|
|
} else {
|
|
|
|
&*sess.target.arch
|
|
|
|
};
|
2018-02-27 02:05:58 +00:00
|
|
|
match (arch, s) {
|
2023-05-22 13:46:40 +00:00
|
|
|
("x86", "sse4.2") => {
|
|
|
|
LLVMFeature::with_dependency("sse4.2", TargetFeatureFoldStrength::EnableOnly("crc32"))
|
|
|
|
}
|
|
|
|
("x86", "pclmulqdq") => LLVMFeature::new("pclmul"),
|
|
|
|
("x86", "rdrand") => LLVMFeature::new("rdrnd"),
|
|
|
|
("x86", "bmi1") => LLVMFeature::new("bmi"),
|
|
|
|
("x86", "cmpxchg16b") => LLVMFeature::new("cx16"),
|
2024-02-12 12:06:45 +00:00
|
|
|
("x86", "lahfsahf") => LLVMFeature::new("sahf"),
|
2023-05-22 13:46:40 +00:00
|
|
|
("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"),
|
|
|
|
("aarch64", "dpb") => LLVMFeature::new("ccpp"),
|
|
|
|
("aarch64", "dpb2") => LLVMFeature::new("ccdp"),
|
|
|
|
("aarch64", "frintts") => LLVMFeature::new("fptoint"),
|
|
|
|
("aarch64", "fcma") => LLVMFeature::new("complxnum"),
|
|
|
|
("aarch64", "pmuv3") => LLVMFeature::new("perfmon"),
|
|
|
|
("aarch64", "paca") => LLVMFeature::new("pauth"),
|
|
|
|
("aarch64", "pacg") => LLVMFeature::new("pauth"),
|
2023-01-17 15:49:20 +00:00
|
|
|
// Rust ties fp and neon together.
|
2023-05-22 13:46:40 +00:00
|
|
|
("aarch64", "neon") => {
|
|
|
|
LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8"))
|
|
|
|
}
|
2023-01-17 15:49:20 +00:00
|
|
|
// In LLVM neon implicitly enables fp, but we manually enable
|
|
|
|
// neon when a feature only implicitly enables fp
|
2023-05-22 13:46:40 +00:00
|
|
|
("aarch64", "f32mm") => {
|
|
|
|
LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "f64mm") => {
|
|
|
|
LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "fhm") => {
|
|
|
|
LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "fp16") => {
|
|
|
|
LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "jsconv") => {
|
|
|
|
LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "sve") => {
|
|
|
|
LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "sve2") => {
|
|
|
|
LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "sve2-aes") => {
|
|
|
|
LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "sve2-sm4") => {
|
|
|
|
LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "sve2-sha3") => {
|
|
|
|
LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon"))
|
|
|
|
}
|
|
|
|
("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency(
|
|
|
|
"sve2-bitperm",
|
|
|
|
TargetFeatureFoldStrength::EnableOnly("neon"),
|
|
|
|
),
|
2024-04-17 19:05:29 +00:00
|
|
|
// In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called
|
|
|
|
// `fast-unaligned-access`. In LLVM 19, it was split back out.
|
|
|
|
("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => {
|
|
|
|
LLVMFeature::new("fast-unaligned-access")
|
2023-12-04 15:52:26 +00:00
|
|
|
}
|
2024-02-14 15:26:20 +00:00
|
|
|
// For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled.
|
|
|
|
("x86", s) if get_version().0 >= 18 && s.starts_with("avx512") => {
|
|
|
|
LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))
|
|
|
|
}
|
2023-05-22 13:46:40 +00:00
|
|
|
(_, s) => LLVMFeature::new(s),
|
2023-01-23 13:15:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Given a map from target_features to whether they are enabled or disabled,
|
|
|
|
/// ensure only valid combinations are allowed.
|
2022-01-31 13:04:27 +00:00
|
|
|
pub fn check_tied_features(
|
|
|
|
sess: &Session,
|
|
|
|
features: &FxHashMap<&str, bool>,
|
|
|
|
) -> Option<&'static [&'static str]> {
|
2022-06-06 10:05:07 +00:00
|
|
|
if !features.is_empty() {
|
2023-12-12 20:47:20 +00:00
|
|
|
for tied in sess.target.tied_target_features() {
|
2022-06-06 10:05:07 +00:00
|
|
|
// Tied features must be set to the same value, or not set at all
|
|
|
|
let mut tied_iter = tied.iter();
|
|
|
|
let enabled = features.get(tied_iter.next().unwrap());
|
|
|
|
if tied_iter.any(|f| enabled != features.get(f)) {
|
|
|
|
return Some(tied);
|
|
|
|
}
|
2022-01-31 13:04:27 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-06 10:05:07 +00:00
|
|
|
return None;
|
2022-01-31 13:04:27 +00:00
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Used to generate cfg variables and apply features
|
|
|
|
/// Must express features in the way Rust understands them
|
2022-07-11 13:26:58 +00:00
|
|
|
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
2020-04-23 18:10:01 +00:00
|
|
|
let target_machine = create_informational_target_machine(sess);
|
2023-12-12 20:47:20 +00:00
|
|
|
sess.target
|
|
|
|
.supported_target_features()
|
2022-07-11 13:26:58 +00:00
|
|
|
.iter()
|
|
|
|
.filter_map(|&(feature, gate)| {
|
2023-11-12 11:41:22 +00:00
|
|
|
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
2022-07-11 13:26:58 +00:00
|
|
|
Some(feature)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.filter(|feature| {
|
|
|
|
// check that all features in a given smallvec are enabled
|
|
|
|
for llvm_feature in to_llvm_features(sess, feature) {
|
|
|
|
let cstr = SmallCStr::new(llvm_feature);
|
2023-09-17 12:40:22 +00:00
|
|
|
if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } {
|
2022-07-11 13:26:58 +00:00
|
|
|
return false;
|
2021-09-15 14:18:10 +00:00
|
|
|
}
|
2022-07-11 13:26:58 +00:00
|
|
|
}
|
|
|
|
true
|
|
|
|
})
|
|
|
|
.map(|feature| Symbol::intern(feature))
|
2023-02-11 00:13:31 +00:00
|
|
|
.collect()
|
2018-01-05 21:26:26 +00:00
|
|
|
}
|
2017-04-30 18:33:25 +00:00
|
|
|
|
|
|
|
pub fn print_version() {
|
2020-10-13 02:33:27 +00:00
|
|
|
let (major, minor, patch) = get_version();
|
2023-07-25 21:04:01 +00:00
|
|
|
println!("LLVM version: {major}.{minor}.{patch}");
|
2020-10-13 02:33:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_version() -> (u32, u32, u32) {
|
2017-10-30 17:42:21 +00:00
|
|
|
// Can be called without initializing LLVM
|
2017-04-30 18:33:25 +00:00
|
|
|
unsafe {
|
2020-10-13 02:33:27 +00:00
|
|
|
(llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor(), llvm::LLVMRustVersionPatch())
|
2017-04-30 18:33:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn print_passes() {
|
2017-10-30 17:42:21 +00:00
|
|
|
// Can be called without initializing LLVM
|
2017-04-30 18:33:25 +00:00
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustPrintPasses();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-08 05:00:47 +00:00
|
|
|
fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> {
|
|
|
|
let len = unsafe { llvm::LLVMRustGetTargetFeaturesCount(tm) };
|
|
|
|
let mut ret = Vec::with_capacity(len);
|
|
|
|
for i in 0..len {
|
|
|
|
unsafe {
|
|
|
|
let mut feature = ptr::null();
|
|
|
|
let mut desc = ptr::null();
|
|
|
|
llvm::LLVMRustGetTargetFeature(tm, i, &mut feature, &mut desc);
|
|
|
|
if feature.is_null() || desc.is_null() {
|
|
|
|
bug!("LLVM returned a `null` target feature string");
|
|
|
|
}
|
|
|
|
let feature = CStr::from_ptr(feature).to_str().unwrap_or_else(|e| {
|
|
|
|
bug!("LLVM returned a non-utf8 feature string: {}", e);
|
|
|
|
});
|
|
|
|
let desc = CStr::from_ptr(desc).to_str().unwrap_or_else(|e| {
|
|
|
|
bug!("LLVM returned a non-utf8 feature string: {}", e);
|
|
|
|
});
|
|
|
|
ret.push((feature, desc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret
|
|
|
|
}
|
|
|
|
|
2023-07-13 23:54:25 +00:00
|
|
|
fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) {
|
2022-11-20 02:22:17 +00:00
|
|
|
let mut llvm_target_features = llvm_target_features(tm);
|
|
|
|
let mut known_llvm_target_features = FxHashSet::<&'static str>::default();
|
2023-12-12 20:47:20 +00:00
|
|
|
let mut rustc_target_features = sess
|
|
|
|
.target
|
|
|
|
.supported_target_features()
|
2021-04-08 05:00:47 +00:00
|
|
|
.iter()
|
2022-11-20 02:22:17 +00:00
|
|
|
.map(|(feature, _gate)| {
|
2023-05-22 13:46:40 +00:00
|
|
|
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
|
|
|
|
let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name;
|
|
|
|
let desc =
|
2022-11-20 02:22:17 +00:00
|
|
|
match llvm_target_features.binary_search_by_key(&llvm_feature, |(f, _d)| f).ok() {
|
|
|
|
Some(index) => {
|
|
|
|
known_llvm_target_features.insert(llvm_feature);
|
|
|
|
llvm_target_features[index].1
|
|
|
|
}
|
|
|
|
None => "",
|
2023-05-22 13:46:40 +00:00
|
|
|
};
|
|
|
|
|
2022-11-20 02:22:17 +00:00
|
|
|
(*feature, desc)
|
2021-04-08 05:00:47 +00:00
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
rustc_target_features.extend_from_slice(&[(
|
|
|
|
"crt-static",
|
|
|
|
"Enables C Run-time Libraries to be statically linked",
|
|
|
|
)]);
|
2022-11-20 02:22:17 +00:00
|
|
|
llvm_target_features.retain(|(f, _d)| !known_llvm_target_features.contains(f));
|
|
|
|
|
|
|
|
let max_feature_len = llvm_target_features
|
2021-04-08 05:00:47 +00:00
|
|
|
.iter()
|
|
|
|
.chain(rustc_target_features.iter())
|
|
|
|
.map(|(feature, _desc)| feature.len())
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0);
|
|
|
|
|
2023-07-13 23:54:25 +00:00
|
|
|
writeln!(out, "Features supported by rustc for this target:");
|
2021-04-08 05:00:47 +00:00
|
|
|
for (feature, desc) in &rustc_target_features {
|
2023-07-25 21:04:01 +00:00
|
|
|
writeln!(out, " {feature:max_feature_len$} - {desc}.");
|
2021-04-08 05:00:47 +00:00
|
|
|
}
|
2023-07-13 23:54:25 +00:00
|
|
|
writeln!(out, "\nCode-generation features supported by LLVM for this target:");
|
2022-11-20 02:22:17 +00:00
|
|
|
for (feature, desc) in &llvm_target_features {
|
2023-07-25 21:04:01 +00:00
|
|
|
writeln!(out, " {feature:max_feature_len$} - {desc}.");
|
2021-04-08 05:00:47 +00:00
|
|
|
}
|
2022-11-20 02:22:17 +00:00
|
|
|
if llvm_target_features.is_empty() {
|
2023-07-13 23:54:25 +00:00
|
|
|
writeln!(out, " Target features listing is not supported by this LLVM version.");
|
2021-04-08 05:00:47 +00:00
|
|
|
}
|
2023-07-13 23:54:25 +00:00
|
|
|
writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it.");
|
|
|
|
writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n");
|
|
|
|
writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],");
|
|
|
|
writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n");
|
2021-04-08 05:00:47 +00:00
|
|
|
}
|
|
|
|
|
2023-07-13 23:56:29 +00:00
|
|
|
pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess: &Session) {
|
2017-10-30 17:42:21 +00:00
|
|
|
require_inited();
|
2020-04-23 18:10:01 +00:00
|
|
|
let tm = create_informational_target_machine(sess);
|
2023-07-17 00:20:28 +00:00
|
|
|
match req.kind {
|
|
|
|
PrintKind::TargetCPUs => {
|
2023-05-05 00:54:17 +00:00
|
|
|
// SAFETY generate a C compatible string from a byte slice to pass
|
|
|
|
// the target CPU name into LLVM, the lifetime of the reference is
|
|
|
|
// at least as long as the C function
|
2023-04-28 21:23:40 +00:00
|
|
|
let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
|
2023-04-30 13:47:29 +00:00
|
|
|
.unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
|
2023-07-13 23:56:29 +00:00
|
|
|
unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) {
|
|
|
|
let out = &mut *(out as *mut &mut dyn PrintBackendInfo);
|
|
|
|
let bytes = slice::from_raw_parts(string as *const u8, len);
|
|
|
|
write!(out, "{}", String::from_utf8_lossy(bytes));
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
llvm::LLVMRustPrintTargetCPUs(
|
2023-09-17 12:40:22 +00:00
|
|
|
&tm,
|
2023-07-13 23:56:29 +00:00
|
|
|
cpu_cstring.as_ptr(),
|
|
|
|
callback,
|
2024-02-24 13:47:34 +00:00
|
|
|
std::ptr::addr_of_mut!(out) as *mut c_void,
|
2023-07-13 23:56:29 +00:00
|
|
|
);
|
|
|
|
}
|
2023-04-27 01:11:14 +00:00
|
|
|
}
|
2023-09-17 12:40:22 +00:00
|
|
|
PrintKind::TargetFeatures => print_target_features(out, sess, &tm),
|
2021-04-08 05:00:47 +00:00
|
|
|
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
|
2017-04-30 18:33:25 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-23 18:03:22 +00:00
|
|
|
|
2020-09-17 09:39:26 +00:00
|
|
|
fn handle_native(name: &str) -> &str {
|
2018-08-23 18:03:22 +00:00
|
|
|
if name != "native" {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let mut len = 0;
|
|
|
|
let ptr = llvm::LLVMRustGetHostCPUName(&mut len);
|
|
|
|
str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
|
|
|
|
}
|
|
|
|
}
|
2020-09-17 09:39:26 +00:00
|
|
|
|
|
|
|
pub fn target_cpu(sess: &Session) -> &str {
|
2022-03-22 10:43:05 +00:00
|
|
|
match sess.opts.cg.target_cpu {
|
|
|
|
Some(ref name) => handle_native(name),
|
|
|
|
None => handle_native(sess.target.cpu.as_ref()),
|
|
|
|
}
|
2020-09-17 09:39:26 +00:00
|
|
|
}
|
|
|
|
|
2021-03-13 13:29:39 +00:00
|
|
|
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
|
|
|
/// `--target` and similar).
|
2021-07-23 13:19:22 +00:00
|
|
|
pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<String> {
|
2022-03-03 11:47:23 +00:00
|
|
|
// Features that come earlier are overridden by conflicting features later in the string.
|
2021-03-13 13:29:39 +00:00
|
|
|
// Typically we'll want more explicit settings to override the implicit ones, so:
|
|
|
|
//
|
2022-03-03 11:47:23 +00:00
|
|
|
// * Features from -Ctarget-cpu=*; are overridden by [^1]
|
|
|
|
// * Features implied by --target; are overridden by
|
|
|
|
// * Features from -Ctarget-feature; are overridden by
|
2021-03-13 13:29:39 +00:00
|
|
|
// * function specific features.
|
|
|
|
//
|
|
|
|
// [^1]: target-cpu=native is handled here, other target-cpu values are handled implicitly
|
|
|
|
// through LLVM TargetMachine implementation.
|
|
|
|
//
|
|
|
|
// FIXME(nagisa): it isn't clear what's the best interaction between features implied by
|
|
|
|
// `-Ctarget-cpu` and `--target` are. On one hand, you'd expect CLI arguments to always
|
|
|
|
// override anything that's implicit, so e.g. when there's no `--target` flag, features implied
|
2022-03-03 11:47:23 +00:00
|
|
|
// the host target are overridden by `-Ctarget-cpu=*`. On the other hand, what about when both
|
2021-03-13 13:29:39 +00:00
|
|
|
// `--target` and `-Ctarget-cpu=*` are specified? Both then imply some target features and both
|
|
|
|
// flags are specified by the user on the CLI. It isn't as clear-cut which order of precedence
|
|
|
|
// should be taken in cases like these.
|
|
|
|
let mut features = vec![];
|
|
|
|
|
|
|
|
// -Ctarget-cpu=native
|
2021-01-06 08:23:54 +00:00
|
|
|
match sess.opts.cg.target_cpu {
|
2021-03-13 13:29:39 +00:00
|
|
|
Some(ref s) if s == "native" => {
|
2021-01-08 16:50:21 +00:00
|
|
|
let features_string = unsafe {
|
|
|
|
let ptr = llvm::LLVMGetHostCPUFeatures();
|
|
|
|
let features_string = if !ptr.is_null() {
|
|
|
|
CStr::from_ptr(ptr)
|
|
|
|
.to_str()
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
bug!("LLVM returned a non-utf8 features string: {}", e);
|
|
|
|
})
|
|
|
|
.to_owned()
|
|
|
|
} else {
|
|
|
|
bug!("could not allocate host CPU features, LLVM returned a `null` string");
|
|
|
|
};
|
|
|
|
|
|
|
|
llvm::LLVMDisposeMessage(ptr);
|
|
|
|
|
|
|
|
features_string
|
|
|
|
};
|
2021-07-17 21:35:57 +00:00
|
|
|
features.extend(features_string.split(',').map(String::from));
|
2021-01-06 08:23:54 +00:00
|
|
|
}
|
2021-03-13 13:29:39 +00:00
|
|
|
Some(_) | None => {}
|
|
|
|
};
|
|
|
|
|
2021-07-23 13:19:22 +00:00
|
|
|
// Features implied by an implicit or explicit `--target`.
|
|
|
|
features.extend(
|
|
|
|
sess.target
|
|
|
|
.features
|
|
|
|
.split(',')
|
2024-02-04 00:57:47 +00:00
|
|
|
.filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
|
2021-07-23 13:19:22 +00:00
|
|
|
.map(String::from),
|
|
|
|
);
|
2022-01-31 13:04:27 +00:00
|
|
|
|
2024-02-21 23:32:58 +00:00
|
|
|
if wants_wasm_eh(sess) && sess.panic_strategy() == PanicStrategy::Unwind {
|
|
|
|
features.push("+exception-handling".into());
|
|
|
|
}
|
|
|
|
|
2021-07-23 13:19:22 +00:00
|
|
|
// -Ctarget-features
|
2023-12-12 20:47:20 +00:00
|
|
|
let supported_features = sess.target.supported_target_features();
|
2022-06-06 10:05:07 +00:00
|
|
|
let mut featsmap = FxHashMap::default();
|
2021-07-23 13:19:22 +00:00
|
|
|
let feats = sess
|
|
|
|
.opts
|
|
|
|
.cg
|
|
|
|
.target_feature
|
|
|
|
.split(',')
|
|
|
|
.filter_map(|s| {
|
|
|
|
let enable_disable = match s.chars().next() {
|
|
|
|
None => return None,
|
2023-03-22 14:38:55 +00:00
|
|
|
Some(c @ ('+' | '-')) => c,
|
2021-07-23 13:19:22 +00:00
|
|
|
Some(_) => {
|
|
|
|
if diagnostics {
|
2024-01-04 00:28:14 +00:00
|
|
|
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
|
2021-07-23 13:19:22 +00:00
|
|
|
}
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-02-04 00:57:47 +00:00
|
|
|
let feature = backend_feature_name(sess, s)?;
|
2023-11-05 17:06:19 +00:00
|
|
|
// Warn against use of LLVM specific feature names and unstable features on the CLI.
|
|
|
|
if diagnostics {
|
|
|
|
let feature_state = supported_features.iter().find(|&&(v, _)| v == feature);
|
|
|
|
if feature_state.is_none() {
|
|
|
|
let rust_feature = supported_features.iter().find_map(|&(rust_feature, _)| {
|
|
|
|
let llvm_features = to_llvm_features(sess, rust_feature);
|
2023-11-21 19:07:32 +00:00
|
|
|
if llvm_features.contains(feature) && !llvm_features.contains(rust_feature)
|
2023-11-05 17:06:19 +00:00
|
|
|
{
|
|
|
|
Some(rust_feature)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
});
|
|
|
|
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
|
|
|
UnknownCTargetFeature {
|
|
|
|
feature,
|
|
|
|
rust_feature: PossibleFeature::Some { rust_feature },
|
|
|
|
}
|
2021-07-23 13:19:22 +00:00
|
|
|
} else {
|
2023-11-05 17:06:19 +00:00
|
|
|
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
|
|
|
};
|
2024-01-04 00:28:14 +00:00
|
|
|
sess.dcx().emit_warn(unknown_feature);
|
2023-11-12 11:41:22 +00:00
|
|
|
} else if feature_state
|
|
|
|
.is_some_and(|(_name, feature_gate)| !feature_gate.is_stable())
|
2023-11-05 17:06:19 +00:00
|
|
|
{
|
|
|
|
// An unstable feature. Warn about using it.
|
2024-01-04 00:28:14 +00:00
|
|
|
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
2023-11-05 17:06:19 +00:00
|
|
|
}
|
2021-07-23 13:19:22 +00:00
|
|
|
}
|
2022-06-06 10:05:07 +00:00
|
|
|
|
|
|
|
if diagnostics {
|
|
|
|
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
|
|
|
featsmap.insert(feature, enable_disable == '+');
|
|
|
|
}
|
|
|
|
|
|
|
|
// rustc-specific features do not get passed down to LLVM…
|
|
|
|
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
// ... otherwise though we run through `to_llvm_features` when
|
|
|
|
// passing requests down to LLVM. This means that all in-language
|
|
|
|
// features also work on the command line instead of having two
|
|
|
|
// different names when the LLVM name and the Rust name differ.
|
2023-05-22 13:46:40 +00:00
|
|
|
let llvm_feature = to_llvm_features(sess, feature);
|
|
|
|
|
|
|
|
Some(
|
|
|
|
std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
|
|
|
|
.chain(llvm_feature.dependency.into_iter().filter_map(move |feat| {
|
|
|
|
match (enable_disable, feat) {
|
|
|
|
('-' | '+', TargetFeatureFoldStrength::Both(f))
|
|
|
|
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
|
2023-07-25 21:04:01 +00:00
|
|
|
Some(format!("{enable_disable}{f}"))
|
2023-05-22 13:46:40 +00:00
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
})),
|
|
|
|
)
|
2021-07-23 13:19:22 +00:00
|
|
|
})
|
2022-06-06 10:05:07 +00:00
|
|
|
.flatten();
|
|
|
|
features.extend(feats);
|
|
|
|
|
|
|
|
if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
|
2023-12-18 11:21:37 +00:00
|
|
|
sess.dcx().emit_err(TargetFeatureDisableOrEnable {
|
2022-08-26 19:27:17 +00:00
|
|
|
features: f,
|
2022-10-30 18:26:12 +00:00
|
|
|
span: None,
|
|
|
|
missing_features: None,
|
2022-08-26 19:27:17 +00:00
|
|
|
});
|
2022-01-31 13:04:27 +00:00
|
|
|
}
|
|
|
|
|
2021-07-23 13:19:22 +00:00
|
|
|
features
|
|
|
|
}
|
2021-03-13 13:29:39 +00:00
|
|
|
|
2021-07-23 13:19:22 +00:00
|
|
|
/// Returns a feature name for the given `+feature` or `-feature` string.
|
|
|
|
///
|
|
|
|
/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
|
2024-02-04 00:57:47 +00:00
|
|
|
fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
|
2021-07-23 13:19:22 +00:00
|
|
|
// features must start with a `+` or `-`.
|
2024-02-04 00:57:47 +00:00
|
|
|
let feature = s
|
|
|
|
.strip_prefix(&['+', '-'][..])
|
|
|
|
.unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
|
2021-07-23 13:19:22 +00:00
|
|
|
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
|
|
|
|
// are not passed down to LLVM.
|
|
|
|
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
|
|
|
return None;
|
2022-01-31 13:04:27 +00:00
|
|
|
}
|
2021-07-23 13:19:22 +00:00
|
|
|
Some(feature)
|
2021-01-06 08:23:54 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 09:39:26 +00:00
|
|
|
pub fn tune_cpu(sess: &Session) -> Option<&str> {
|
2022-07-06 12:44:47 +00:00
|
|
|
let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
|
2020-12-30 17:22:41 +00:00
|
|
|
Some(handle_native(name))
|
2020-09-17 09:39:26 +00:00
|
|
|
}
|