Skip to content

Commit c4e86b6

Browse files
authored
Merge pull request #299 from rust-lang/feature/jit-cpu-features
Add support for detecting CPU features
2 parents 48a3613 + 91e0400 commit c4e86b6

File tree

5 files changed

+50
-52
lines changed

5 files changed

+50
-52
lines changed

Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Readme.md

+1-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ A secondary goal is to check if using the gcc backend will provide any run-time
1414
## Building
1515

1616
**This requires a patched libgccjit in order to work.
17-
The patches in [this repository](https://github.com/antoyo/libgccjit-patches) need to be applied.
18-
(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.)
19-
You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
17+
You need to use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
2018

2119
To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue):
2220

failing-ui-tests.txt

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ tests/ui/sepcomp/sepcomp-fns-backwards.rs
2121
tests/ui/sepcomp/sepcomp-fns.rs
2222
tests/ui/sepcomp/sepcomp-statics.rs
2323
tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
24-
tests/ui/sse2.rs
2524
tests/ui/target-feature/missing-plusminus.rs
2625
tests/ui/asm/x86_64/may_unwind.rs
2726
tests/ui/backtrace.rs

src/base.rs

+30-21
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
use std::collections::HashSet;
12
use std::env;
3+
use std::sync::Arc;
24
use std::time::Instant;
35

46
use gccjit::{
57
Context,
68
FunctionType,
7-
GlobalKind,
9+
GlobalKind, TargetInfo,
810
};
911
use rustc_middle::dep_graph;
1012
use rustc_middle::ty::TyCtxt;
@@ -63,15 +65,15 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
6365
}
6466
}
6567

66-
pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_integers: bool) -> (ModuleCodegen<GccContext>, u64) {
68+
pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Arc<TargetInfo>) -> (ModuleCodegen<GccContext>, u64) {
6769
let prof_timer = tcx.prof.generic_activity("codegen_module");
6870
let start_time = Instant::now();
6971

7072
let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
7173
let (module, _) = tcx.dep_graph.with_task(
7274
dep_node,
7375
tcx,
74-
(cgu_name, supports_128bit_integers),
76+
(cgu_name, target_info),
7577
module_codegen,
7678
Some(dep_graph::hash_result),
7779
);
@@ -82,7 +84,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
8284
// the time we needed for codegenning it.
8385
let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
8486

85-
fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, supports_128bit_integers): (Symbol, bool)) -> ModuleCodegen<GccContext> {
87+
fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, Arc<TargetInfo>)) -> ModuleCodegen<GccContext> {
8688
let cgu = tcx.codegen_unit(cgu_name);
8789
// Instantiate monomorphizations without filling out definitions yet...
8890
//let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
@@ -91,29 +93,36 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
9193
context.add_command_line_option("-fexceptions");
9294
context.add_driver_option("-fexceptions");
9395

96+
let disabled_features: HashSet<_> = tcx.sess.opts.cg.target_feature.split(',')
97+
.filter(|feature| feature.starts_with('-'))
98+
.map(|string| &string[1..])
99+
.collect();
100+
101+
let add_cpu_feature_flag = |feature: &str| {
102+
// FIXME(antoyo): some tests cause a segfault in GCC when not enabling all these
103+
// features.
104+
if (true || target_info.cpu_supports(feature)) && !disabled_features.contains(feature) {
105+
context.add_command_line_option(&format!("-m{}", feature));
106+
}
107+
};
108+
94109
// TODO(antoyo): only set on x86 platforms.
95110
context.add_command_line_option("-masm=intel");
96-
// TODO(antoyo): only add the following cli argument if the feature is supported.
97-
context.add_command_line_option("-msse2");
98-
context.add_command_line_option("-mavx2");
99-
// FIXME(antoyo): the following causes an illegal instruction on vmovdqu64 in std_example on my CPU.
100-
// Only add if the CPU supports it.
101-
context.add_command_line_option("-msha");
111+
112+
let features = ["sse2", "avx", "avx2", "sha", "fma", "gfni", "f16c", "aes", "bmi2", "rtm",
113+
"vaes", "vpclmulqdq", "xsavec",
114+
];
115+
116+
for feature in &features {
117+
add_cpu_feature_flag(feature);
118+
}
119+
120+
// TODO(antoyo): only add the following cli arguments if the feature is supported.
102121
context.add_command_line_option("-mpclmul");
103-
context.add_command_line_option("-mfma");
104122
context.add_command_line_option("-mfma4");
105123
context.add_command_line_option("-m64");
106124
context.add_command_line_option("-mbmi");
107-
context.add_command_line_option("-mgfni");
108125
//context.add_command_line_option("-mavxvnni"); // The CI doesn't support this option.
109-
context.add_command_line_option("-mf16c");
110-
context.add_command_line_option("-maes");
111-
context.add_command_line_option("-mxsavec");
112-
context.add_command_line_option("-mbmi2");
113-
context.add_command_line_option("-mrtm");
114-
context.add_command_line_option("-mvaes");
115-
context.add_command_line_option("-mvpclmulqdq");
116-
context.add_command_line_option("-mavx");
117126

118127
for arg in &tcx.sess.opts.cg.llvm_args {
119128
context.add_command_line_option(arg);
@@ -156,7 +165,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, supports_128bit_i
156165
context.set_allow_unreachable_blocks(true);
157166

158167
{
159-
let cx = CodegenCx::new(&context, cgu, tcx, supports_128bit_integers);
168+
let cx = CodegenCx::new(&context, cgu, tcx, target_info.supports_128bit_int());
160169

161170
let mono_items = cgu.items_in_deterministic_order(tcx);
162171
for &(mono_item, (linkage, visibility)) in &mono_items {

src/lib.rs

+17-25
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ extern crate rustc_middle;
3535
extern crate rustc_session;
3636
extern crate rustc_span;
3737
extern crate rustc_target;
38-
extern crate tempfile;
3938

4039
// This prevents duplicating functions and statics that are already part of the host rustc process.
4140
#[allow(unused_extern_crates)]
@@ -64,10 +63,10 @@ mod type_;
6463
mod type_of;
6564

6665
use std::any::Any;
67-
use std::sync::{Arc, Mutex};
66+
use std::sync::Arc;
6867

6968
use crate::errors::LTONotSupported;
70-
use gccjit::{Context, OptimizationLevel, CType};
69+
use gccjit::{Context, OptimizationLevel, TargetInfo};
7170
use rustc_ast::expand::allocator::AllocatorKind;
7271
use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
7372
use rustc_codegen_ssa::base::codegen_crate;
@@ -86,7 +85,6 @@ use rustc_session::config::{Lto, OptLevel, OutputFilenames};
8685
use rustc_session::Session;
8786
use rustc_span::Symbol;
8887
use rustc_span::fatal_error::FatalError;
89-
use tempfile::TempDir;
9088

9189
fluent_messages! { "../messages.ftl" }
9290

@@ -102,7 +100,7 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
102100

103101
#[derive(Clone)]
104102
pub struct GccCodegenBackend {
105-
supports_128bit_integers: Arc<Mutex<bool>>,
103+
target_info: Arc<TargetInfo>,
106104
}
107105

108106
impl CodegenBackend for GccCodegenBackend {
@@ -116,15 +114,6 @@ impl CodegenBackend for GccCodegenBackend {
116114
if sess.lto() != Lto::No {
117115
sess.emit_warning(LTONotSupported {});
118116
}
119-
120-
let temp_dir = TempDir::new().expect("cannot create temporary directory");
121-
let temp_file = temp_dir.into_path().join("result.asm");
122-
let check_context = Context::default();
123-
check_context.set_print_errors_to_stderr(false);
124-
let _int128_ty = check_context.new_c_type(CType::UInt128t);
125-
// NOTE: we cannot just call compile() as this would require other files than libgccjit.so.
126-
check_context.compile_to_file(gccjit::OutputKind::Assembler, temp_file.to_str().expect("path to str"));
127-
*self.supports_128bit_integers.lock().expect("lock") = check_context.get_last_error() == Ok(None);
128117
}
129118

130119
fn provide(&self, providers: &mut Providers) {
@@ -160,7 +149,7 @@ impl CodegenBackend for GccCodegenBackend {
160149
}
161150

162151
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
163-
target_features(sess, allow_unstable)
152+
target_features(sess, allow_unstable, &self.target_info)
164153
}
165154
}
166155

@@ -174,7 +163,7 @@ impl ExtraBackendMethods for GccCodegenBackend {
174163
}
175164

176165
fn compile_codegen_unit(&self, tcx: TyCtxt<'_>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
177-
base::compile_codegen_unit(tcx, cgu_name, *self.supports_128bit_integers.lock().expect("lock"))
166+
base::compile_codegen_unit(tcx, cgu_name, Arc::clone(&self.target_info))
178167
}
179168

180169
fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel, _features: &[String]) -> TargetMachineFactoryFn<Self> {
@@ -273,8 +262,17 @@ impl WriteBackendMethods for GccCodegenBackend {
273262
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
274263
#[no_mangle]
275264
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
265+
// Get the native arch and check whether the target supports 128-bit integers.
266+
let context = Context::default();
267+
let arch = context.get_target_info().arch().unwrap();
268+
269+
// Get the second TargetInfo with the correct CPU features by setting the arch.
270+
let context = Context::default();
271+
context.add_driver_option(&format!("-march={}", arch.to_str().unwrap()));
272+
let target_info = Arc::new(context.get_target_info());
273+
276274
Box::new(GccCodegenBackend {
277-
supports_128bit_integers: Arc::new(Mutex::new(false)),
275+
target_info,
278276
})
279277
}
280278

@@ -308,7 +306,7 @@ pub fn target_cpu(sess: &Session) -> &str {
308306
}
309307
}
310308

311-
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
309+
pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &Arc<TargetInfo>) -> Vec<Symbol> {
312310
supported_target_features(sess)
313311
.iter()
314312
.filter_map(
@@ -317,14 +315,9 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
317315
},
318316
)
319317
.filter(|_feature| {
320-
// TODO(antoyo): implement a way to get enabled feature in libgccjit.
321-
// Probably using the equivalent of __builtin_cpu_supports.
322-
// TODO(antoyo): maybe use whatever outputs the following command:
323-
// gcc -march=native -Q --help=target
324318
#[cfg(feature="master")]
325319
{
326-
// NOTE: the CPU in the CI doesn't support sse4a, so disable it to make the stdarch tests pass in the CI.
327-
(_feature.contains("sse") || _feature.contains("avx")) && !_feature.contains("avx512") && !_feature.contains("sse4a")
320+
target_info.cpu_supports(_feature)
328321
}
329322
#[cfg(not(feature="master"))]
330323
{
@@ -336,7 +329,6 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
336329
bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm,
337330
sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves
338331
*/
339-
//false
340332
})
341333
.map(|feature| Symbol::intern(feature))
342334
.collect()

0 commit comments

Comments
 (0)