Skip to content

Commit

Permalink
Auto merge of rust-lang#84004 - mattico:print-target-features-improve…
Browse files Browse the repository at this point in the history
…ments, 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](https://github.com/rust-lang/rust/blob/69e1d22ddbc67b25141a735a22a8895a678b32ca/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 rust-lang#83975.
CC rust-lang#49653
  • Loading branch information
bors committed Apr 9, 2021
2 parents 8513e78 + e258a5b commit dae9d6a
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 25 deletions.
8 changes: 7 additions & 1 deletion compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
75 changes: 69 additions & 6 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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),
}
}

Expand Down
33 changes: 15 additions & 18 deletions compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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");
return FeatTable.size();
}

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
Expand All @@ -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) {
Expand Down

0 comments on commit dae9d6a

Please sign in to comment.