rustc_codegen_llvm: make sse4.2 imply crc32 for LLVM 14
This fixes compiling things like the `snap` crate after https://reviews.llvm.org/D105462. I added a test that verifies the additional attribute gets specified, and confirmed that I can build cargo with both LLVM 13 and 14 with this change applied.
This commit is contained in:
parent
db1fb85cff
commit
4185b76dc3
4 changed files with 83 additions and 34 deletions
|
@ -305,9 +305,12 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
|
||||||
let mut function_features = codegen_fn_attrs
|
let mut function_features = codegen_fn_attrs
|
||||||
.target_features
|
.target_features
|
||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.flat_map(|f| {
|
||||||
let feature = &f.as_str();
|
let feature = &f.as_str();
|
||||||
format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
|
llvm_util::to_llvm_feature(cx.tcx.sess, feature)
|
||||||
|
.into_iter()
|
||||||
|
.map(|f| format!("+{}", f))
|
||||||
|
.collect::<Vec<String>>()
|
||||||
})
|
})
|
||||||
.chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
|
.chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
|
||||||
InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
|
InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
|
||||||
|
|
|
@ -166,25 +166,32 @@ pub fn time_trace_profiler_finish(file_name: &str) {
|
||||||
// Though note that Rust can also be build with an external precompiled version of LLVM
|
// 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
|
// which might lead to failures if the oldest tested / supported LLVM version
|
||||||
// doesn't yet support the relevant intrinsics
|
// doesn't yet support the relevant intrinsics
|
||||||
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
|
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> {
|
||||||
let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
|
let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
|
||||||
match (arch, s) {
|
match (arch, s) {
|
||||||
("x86", "pclmulqdq") => "pclmul",
|
("x86", "sse4.2") => {
|
||||||
("x86", "rdrand") => "rdrnd",
|
if get_version() >= (14, 0, 0) {
|
||||||
("x86", "bmi1") => "bmi",
|
vec!["sse4.2", "crc32"]
|
||||||
("x86", "cmpxchg16b") => "cx16",
|
} else {
|
||||||
("x86", "avx512vaes") => "vaes",
|
vec!["sse4.2"]
|
||||||
("x86", "avx512gfni") => "gfni",
|
}
|
||||||
("x86", "avx512vpclmulqdq") => "vpclmulqdq",
|
}
|
||||||
("aarch64", "fp") => "fp-armv8",
|
("x86", "pclmulqdq") => vec!["pclmul"],
|
||||||
("aarch64", "fp16") => "fullfp16",
|
("x86", "rdrand") => vec!["rdrnd"],
|
||||||
("aarch64", "fhm") => "fp16fml",
|
("x86", "bmi1") => vec!["bmi"],
|
||||||
("aarch64", "rcpc2") => "rcpc-immo",
|
("x86", "cmpxchg16b") => vec!["cx16"],
|
||||||
("aarch64", "dpb") => "ccpp",
|
("x86", "avx512vaes") => vec!["vaes"],
|
||||||
("aarch64", "dpb2") => "ccdp",
|
("x86", "avx512gfni") => vec!["gfni"],
|
||||||
("aarch64", "frintts") => "fptoint",
|
("x86", "avx512vpclmulqdq") => vec!["vpclmulqdq"],
|
||||||
("aarch64", "fcma") => "complxnum",
|
("aarch64", "fp") => vec!["fp-armv8"],
|
||||||
(_, s) => s,
|
("aarch64", "fp16") => vec!["fullfp16"],
|
||||||
|
("aarch64", "fhm") => vec!["fp16fml"],
|
||||||
|
("aarch64", "rcpc2") => vec!["rcpc-immo"],
|
||||||
|
("aarch64", "dpb") => vec!["ccpp"],
|
||||||
|
("aarch64", "dpb2") => vec!["ccdp"],
|
||||||
|
("aarch64", "frintts") => vec!["fptoint"],
|
||||||
|
("aarch64", "fcma") => vec!["complxnum"],
|
||||||
|
(_, s) => vec![s],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,9 +205,13 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.filter(|feature| {
|
.filter(|feature| {
|
||||||
let llvm_feature = to_llvm_feature(sess, feature);
|
for llvm_feature in to_llvm_feature(sess, feature) {
|
||||||
let cstr = CString::new(llvm_feature).unwrap();
|
let cstr = CString::new(llvm_feature).unwrap();
|
||||||
unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) }
|
if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
})
|
})
|
||||||
.map(|feature| Symbol::intern(feature))
|
.map(|feature| Symbol::intern(feature))
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -253,12 +264,19 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
|
||||||
let mut rustc_target_features = supported_target_features(sess)
|
let mut rustc_target_features = supported_target_features(sess)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(feature, _gate)| {
|
.filter_map(|(feature, _gate)| {
|
||||||
let llvm_feature = to_llvm_feature(sess, *feature);
|
for llvm_feature in to_llvm_feature(sess, *feature) {
|
||||||
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
|
// 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| {
|
match target_features.binary_search_by_key(&llvm_feature, |(f, _d)| (*f)).ok().map(
|
||||||
let (_f, desc) = target_features.remove(index);
|
|index| {
|
||||||
(*feature, desc)
|
let (_f, desc) = target_features.remove(index);
|
||||||
})
|
(*feature, desc)
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Some(v) => return Some(v),
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
rustc_target_features.extend_from_slice(&[(
|
rustc_target_features.extend_from_slice(&[(
|
||||||
|
@ -373,30 +391,30 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
|
||||||
|
|
||||||
let filter = |s: &str| {
|
let filter = |s: &str| {
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
return None;
|
return vec![];
|
||||||
}
|
}
|
||||||
let feature = if s.starts_with('+') || s.starts_with('-') {
|
let feature = if s.starts_with('+') || s.starts_with('-') {
|
||||||
&s[1..]
|
&s[1..]
|
||||||
} else {
|
} else {
|
||||||
return Some(s.to_string());
|
return vec![s.to_string()];
|
||||||
};
|
};
|
||||||
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
|
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
|
||||||
// are not passed down to LLVM.
|
// are not passed down to LLVM.
|
||||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||||
return None;
|
return vec![];
|
||||||
}
|
}
|
||||||
// ... otherwise though we run through `to_llvm_feature` feature when
|
// ... otherwise though we run through `to_llvm_feature` feature when
|
||||||
// passing requests down to LLVM. This means that all in-language
|
// passing requests down to LLVM. This means that all in-language
|
||||||
// features also work on the command line instead of having two
|
// features also work on the command line instead of having two
|
||||||
// different names when the LLVM name and the Rust name differ.
|
// different names when the LLVM name and the Rust name differ.
|
||||||
Some(format!("{}{}", &s[..1], to_llvm_feature(sess, feature)))
|
to_llvm_feature(sess, feature).iter().map(|f| format!("{}{}", &s[..1], f)).collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Features implied by an implicit or explicit `--target`.
|
// Features implied by an implicit or explicit `--target`.
|
||||||
features.extend(sess.target.features.split(',').filter_map(&filter));
|
features.extend(sess.target.features.split(',').flat_map(&filter));
|
||||||
|
|
||||||
// -Ctarget-features
|
// -Ctarget-features
|
||||||
features.extend(sess.opts.cg.target_feature.split(',').filter_map(&filter));
|
features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
|
||||||
|
|
||||||
features
|
features
|
||||||
}
|
}
|
||||||
|
|
12
src/test/assembly/x86_64-sse_crc.rs
Normal file
12
src/test/assembly/x86_64-sse_crc.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// only-x86_64
|
||||||
|
// assembly-output: emit-asm
|
||||||
|
// compile-flags: --crate-type staticlib -Ctarget-feature=+sse4.2
|
||||||
|
|
||||||
|
// CHECK-LABEL: banana
|
||||||
|
// CHECK: crc32
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn banana(v: u8) -> u32 {
|
||||||
|
use std::arch::x86_64::*;
|
||||||
|
let out = !0u32;
|
||||||
|
_mm_crc32_u8(out, v)
|
||||||
|
}
|
16
src/test/codegen/sse42-implies-crc32.rs
Normal file
16
src/test/codegen/sse42-implies-crc32.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// only-x86_64
|
||||||
|
// min-llvm-version: 14.0
|
||||||
|
// compile-flags: -Copt-level=3
|
||||||
|
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
#[target_feature(enable = "sse4.2")]
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe fn crc32sse(v: u8) -> u32 {
|
||||||
|
use std::arch::x86_64::*;
|
||||||
|
let out = !0u32;
|
||||||
|
_mm_crc32_u8(out, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: attributes #0 {{.*"target-features"="\+sse4.2,\+crc32"}}
|
Loading…
Add table
Add a link
Reference in a new issue