Auto merge of #84004 - mattico:print-target-features-improvements, r=petrochenkov

Categorize and explain target features support

There are 3 different uses of the `-C target-feature` args passed to rustc:
1. All of the features are passed to LLVM, which uses them to configure code-generation. This is sort-of stabilized since 1.0 though LLVM does change/add/remove target features regularly.
2. Target features which are in [the compiler's allowlist](69e1d22ddb/compiler/rustc_codegen_ssa/src/target_features.rs (L12-L34)) can be used in `cfg!(target_feature)` etc. These may have different names than in LLVM and are renamed before passing them to LLVM.
3. Target features which are in the allowlist and which are stabilized or feature-gate-enabled can be used in `#[target_feature]`.

It can be confusing that `rustc --print target-features` just prints out the LLVM features without separating out the rustc features or even mentioning that the dichotomy exists.

This improves the situation by separating out the rustc and LLVM target features and adding a brief explanation about the difference.

Abbreviated Example Output:
```
$ rustc --print target-features
Features supported by rustc for this target:
    adx                         - Support ADX instructions.
    aes                         - Enable AES instructions.
...
    xsaves                      - Support xsaves instructions.
    crt-static                  - Enables libraries with C Run-time Libraries(CRT) to be statically linked.

Code-generation features supported by LLVM for this target:
    16bit-mode                  - 16-bit mode (i8086).
    32bit-mode                  - 32-bit mode (80386).
...
    x87                         - Enable X87 float instructions.
    xop                         - Enable XOP instructions.

Use +feature to enable a feature, or -feature to disable it.
For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2

Code-generation features cannot be used in cfg or #[target_feature],
and may be renamed or removed in a future version of LLVM or rustc.

```

Motivated by #83975.
CC https://github.com/rust-lang/rust/issues/49653
This commit is contained in:
bors 2021-04-09 21:14:50 +00:00
commit dae9d6ac3e
3 changed files with 91 additions and 25 deletions

View File

@ -2128,7 +2128,13 @@ extern "C" {
pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
pub fn LLVMRustPrintTargetFeatures(T: &TargetMachine);
pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
pub fn LLVMRustGetTargetFeature(
T: &TargetMachine,
Index: size_t,
Feature: &mut *const c_char,
Desc: &mut *const c_char,
);
pub fn LLVMRustGetHostCPUName(len: *mut usize) -> *const c_char;
pub fn LLVMRustCreateTargetMachine(

View File

@ -10,6 +10,7 @@ use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy};
use std::ffi::{CStr, CString};
use std::ptr;
use std::slice;
use std::str;
use std::sync::atomic::{AtomicBool, Ordering};
@ -192,15 +193,77 @@ pub fn print_passes() {
}
}
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
}
fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
let mut target_features = llvm_target_features(tm);
let mut rustc_target_features = supported_target_features(sess)
.iter()
.filter_map(|(feature, _gate)| {
let llvm_feature = to_llvm_feature(sess, *feature);
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
target_features.binary_search_by_key(&llvm_feature, |(f, _d)| *f).ok().map(|index| {
let (_f, desc) = target_features.remove(index);
(*feature, desc)
})
})
.collect::<Vec<_>>();
rustc_target_features.extend_from_slice(&[(
"crt-static",
"Enables C Run-time Libraries to be statically linked",
)]);
let max_feature_len = target_features
.iter()
.chain(rustc_target_features.iter())
.map(|(feature, _desc)| feature.len())
.max()
.unwrap_or(0);
println!("Features supported by rustc for this target:");
for (feature, desc) in &rustc_target_features {
println!(" {1:0$} - {2}.", max_feature_len, feature, desc);
}
println!("\nCode-generation features supported by LLVM for this target:");
for (feature, desc) in &target_features {
println!(" {1:0$} - {2}.", max_feature_len, feature, desc);
}
if target_features.len() == 0 {
println!(" Target features listing is not supported by this LLVM version.");
}
println!("\nUse +feature to enable a feature, or -feature to disable it.");
println!("For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n");
println!("Code-generation features cannot be used in cfg or #[target_feature],");
println!("and may be renamed or removed in a future version of LLVM or rustc.\n");
}
pub(crate) fn print(req: PrintRequest, sess: &Session) {
require_inited();
let tm = create_informational_target_machine(sess);
unsafe {
match req {
PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
}
match req {
PrintRequest::TargetCPUs => unsafe { llvm::LLVMRustPrintTargetCPUs(tm) },
PrintRequest::TargetFeatures => print_target_features(sess, tm),
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
}
}

View File

@ -404,26 +404,21 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
printf("\n");
}
extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef TM) {
extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) {
const TargetMachine *Target = unwrap(TM);
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
unsigned MaxFeatLen = getLongestEntryLength(FeatTable);
return FeatTable.size();
}
printf("Available features for this target:\n");
for (auto &Feature : FeatTable)
printf(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);
printf("\nRust-specific features:\n");
printf(" %-*s - %s.\n",
MaxFeatLen,
"crt-static",
"Enables libraries with C Run-time Libraries(CRT) to be statically linked"
);
printf("\n");
printf("Use +feature to enable a feature, or -feature to disable it.\n"
"For example, rustc -C -target-cpu=mycpu -C "
"target-feature=+feature1,-feature2\n\n");
extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index,
const char** Feature, const char** Desc) {
const TargetMachine *Target = unwrap(TM);
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
const SubtargetFeatureKV Feat = FeatTable[Index];
*Feature = Feat.Key;
*Desc = Feat.Desc;
}
#else
@ -432,9 +427,11 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) {
printf("Target CPU help is not supported by this LLVM version.\n\n");
}
extern "C" void LLVMRustPrintTargetFeatures(LLVMTargetMachineRef) {
printf("Target features help is not supported by this LLVM version.\n\n");
extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef) {
return 0;
}
extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef, const char**, const char**) {}
#endif
extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {