Adjust -Ctarget-cpu=native handling in cg_llvm
When cg_llvm encounters the `-Ctarget-cpu=native` it computes an explciit set of features that applies to the target in order to correctly compile code for the host CPU (because e.g. `skylake` alone is not sufficient to tell if some of the instructions are available or not). However there were a couple of issues with how we did this. Firstly, the order in which features were overriden wasn't quite right – conceptually you'd expect `-Ctarget-cpu=native` option to override the features that are implicitly set by the target definition. However due to how other `-Ctarget-cpu` values are handled we must adopt the following order of priority: * Features from -Ctarget-cpu=*; are overriden by * Features implied by --target; are overriden by * Features from -Ctarget-feature; are overriden by * function specific features. Another problem was in that the function level `target-features` attribute would overwrite the entire set of the globally enabled features, rather than just the features the `#[target_feature(enable/disable)]` specified. With something like `-Ctarget-cpu=native` we'd end up in a situation wherein a function without `#[target_feature(enable)]` annotation would have a broader set of features compared to a function with one such attribute. This turned out to be a cause of heavy run-time regressions in some code using these function-level attributes in conjunction with `-Ctarget-cpu=native`, for example. With this PR rustc is more careful about specifying the entire set of features for functions that use `#[target_feature(enable/disable)]` or `#[instruction_set]` attributes. Sadly testing the original reproducer for this behaviour is quite impossible – we cannot rely on `-Ctarget-cpu=native` to be anything in particular on developer or CI machines.
This commit is contained in:
41
src/test/assembly/target-feature-multiple.rs
Normal file
41
src/test/assembly/target-feature-multiple.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
// assembly-output: emit-asm
|
||||
// needs-llvm-components: x86
|
||||
// revisions: TWOFLAGS SINGLEFLAG
|
||||
// compile-flags: --target=x86_64-unknown-linux-gnu
|
||||
// [TWOFLAGS] compile-flags: -C target-feature=+rdrnd -C target-feature=+rdseed
|
||||
// [SINGLEFLAG] compile-flags: -C target-feature=+rdrnd,+rdseed
|
||||
|
||||
// Target features set via flags aren't necessarily reflected in the IR, so the only way to test
|
||||
// them is to build code that requires the features to be enabled to work.
|
||||
//
|
||||
// In this particular test if `rdrnd,rdseed` somehow didn't make it to LLVM, the instruction
|
||||
// selection should crash.
|
||||
//
|
||||
// > LLVM ERROR: Cannot select: 0x7f00f400c010: i32,i32,ch = X86ISD::RDSEED 0x7f00f400bfa8:2
|
||||
// > In function: foo
|
||||
//
|
||||
// See also src/test/codegen/target-feature-overrides.rs
|
||||
#![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted)]
|
||||
#![crate_type = "lib"]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
// Use of these requires target features to be enabled
|
||||
extern "unadjusted" {
|
||||
#[link_name = "llvm.x86.rdrand.32"]
|
||||
fn x86_rdrand32_step() -> (u32, i32);
|
||||
#[link_name = "llvm.x86.rdseed.32"]
|
||||
fn x86_rdseed32_step() -> (u32, i32);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn foo() -> (u32, u32) {
|
||||
// CHECK-LABEL: foo:
|
||||
// CHECK: rdrand
|
||||
// CHECK: rdseed
|
||||
(x86_rdrand32_step().0, x86_rdseed32_step().0)
|
||||
}
|
||||
Reference in New Issue
Block a user