Skip to content

Commit 44b9c75

Browse files
authored
Merge pull request #329 from rust-lang/fix/enable-features
Fix/enable features
2 parents 067bfc0 + f096c19 commit 44b9c75

File tree

9 files changed

+387
-125
lines changed

9 files changed

+387
-125
lines changed

Readme.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ error: failed to build archive: failed to open object file: No such file or dire
205205
That can be caused by the fact that you try to compile with `lto = "fat"`, but you didn't compile the sysroot with LTO.
206206
(Not sure if that's the reason since I cannot reproduce anymore. Maybe it happened when forgetting setting `FAT_LTO`.)
207207
208+
### ld: cannot find crtbegin.o
209+
210+
When compiling an executable with libgccijt, if setting the `*LIBRARY_PATH` variables to the install directory, you will get the following errors:
211+
212+
```
213+
ld: cannot find crtbegin.o: No such file or directory
214+
ld: cannot find -lgcc: No such file or directory
215+
ld: cannot find -lgcc: No such file or directory
216+
libgccjit.so: error: error invoking gcc driver
217+
```
218+
219+
To fix this, set the variables to `gcc-build/build/gcc`.
220+
208221
### How to debug GCC LTO
209222
210223
Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger.

messages.ftl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
codegen_gcc_unknown_ctarget_feature_prefix =
2+
unknown feature specified for `-Ctarget-feature`: `{$feature}`
3+
.note = features must begin with a `+` to enable or `-` to disable it
4+
15
codegen_gcc_invalid_minimum_alignment =
26
invalid minimum global alignment: {$err}
37
@@ -23,3 +27,15 @@ codegen_gcc_lto_disallowed = lto can only be run for executables, cdylibs and st
2327
codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
2428
2529
codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
30+
31+
codegen_gcc_unknown_ctarget_feature =
32+
unknown feature specified for `-Ctarget-feature`: `{$feature}`
33+
.note = it is still passed through to the codegen backend
34+
.possible_feature = you might have meant: `{$rust_feature}`
35+
.consider_filing_feature_request = consider filing a feature request
36+
37+
codegen_gcc_missing_features =
38+
add the missing features in a `target_feature` attribute
39+
40+
codegen_gcc_target_feature_disable_or_enable =
41+
the target features {$features} must all be either enabled or disabled together

src/abi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
33
use rustc_data_structures::fx::FxHashSet;
44
use rustc_middle::bug;
55
use rustc_middle::ty::Ty;
6+
#[cfg(feature = "master")]
67
use rustc_session::config;
78
use rustc_target::abi::call::{ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind};
89

src/attributes.rs

Lines changed: 26 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,72 +4,13 @@ use gccjit::Function;
44
use rustc_attr::InstructionSetAttr;
55
#[cfg(feature="master")]
66
use rustc_attr::InlineAttr;
7-
use rustc_codegen_ssa::target_features::tied_target_features;
8-
use rustc_data_structures::fx::FxHashMap;
97
use rustc_middle::ty;
108
#[cfg(feature="master")]
119
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
12-
use rustc_session::Session;
1310
use rustc_span::symbol::sym;
14-
use smallvec::{smallvec, SmallVec};
1511

1612
use crate::{context::CodegenCx, errors::TiedTargetFeatures};
17-
18-
// Given a map from target_features to whether they are enabled or disabled,
19-
// ensure only valid combinations are allowed.
20-
pub fn check_tied_features(sess: &Session, features: &FxHashMap<&str, bool>) -> Option<&'static [&'static str]> {
21-
for tied in tied_target_features(sess) {
22-
// Tied features must be set to the same value, or not set at all
23-
let mut tied_iter = tied.iter();
24-
let enabled = features.get(tied_iter.next().unwrap());
25-
if tied_iter.any(|feature| enabled != features.get(feature)) {
26-
return Some(tied);
27-
}
28-
}
29-
None
30-
}
31-
32-
// TODO(antoyo): maybe move to a new module gcc_util.
33-
// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
34-
fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
35-
let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
36-
match (arch, s) {
37-
("x86", "sse4.2") => smallvec!["sse4.2", "crc32"],
38-
("x86", "pclmulqdq") => smallvec!["pclmul"],
39-
("x86", "rdrand") => smallvec!["rdrnd"],
40-
("x86", "bmi1") => smallvec!["bmi"],
41-
("x86", "cmpxchg16b") => smallvec!["cx16"],
42-
("x86", "avx512vaes") => smallvec!["vaes"],
43-
("x86", "avx512gfni") => smallvec!["gfni"],
44-
("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
45-
// NOTE: seems like GCC requires 'avx512bw' for 'avx512vbmi2'.
46-
("x86", "avx512vbmi2") => smallvec!["avx512vbmi2", "avx512bw"],
47-
// NOTE: seems like GCC requires 'avx512bw' for 'avx512bitalg'.
48-
("x86", "avx512bitalg") => smallvec!["avx512bitalg", "avx512bw"],
49-
("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
50-
("aarch64", "dpb") => smallvec!["ccpp"],
51-
("aarch64", "dpb2") => smallvec!["ccdp"],
52-
("aarch64", "frintts") => smallvec!["fptoint"],
53-
("aarch64", "fcma") => smallvec!["complxnum"],
54-
("aarch64", "pmuv3") => smallvec!["perfmon"],
55-
("aarch64", "paca") => smallvec!["pauth"],
56-
("aarch64", "pacg") => smallvec!["pauth"],
57-
// Rust ties fp and neon together. In LLVM neon implicitly enables fp,
58-
// but we manually enable neon when a feature only implicitly enables fp
59-
("aarch64", "f32mm") => smallvec!["f32mm", "neon"],
60-
("aarch64", "f64mm") => smallvec!["f64mm", "neon"],
61-
("aarch64", "fhm") => smallvec!["fp16fml", "neon"],
62-
("aarch64", "fp16") => smallvec!["fullfp16", "neon"],
63-
("aarch64", "jsconv") => smallvec!["jsconv", "neon"],
64-
("aarch64", "sve") => smallvec!["sve", "neon"],
65-
("aarch64", "sve2") => smallvec!["sve2", "neon"],
66-
("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"],
67-
("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"],
68-
("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"],
69-
("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
70-
(_, s) => smallvec![s],
71-
}
72-
}
13+
use crate::gcc_util::{check_tied_features, to_gcc_features};
7314

7415
/// Get GCC attribute for the provided inline heuristic.
7516
#[cfg(feature="master")]
@@ -153,11 +94,33 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
15394
}))
15495
.collect::<Vec<_>>();
15596

156-
// TODO(antoyo): check if we really need global backend features. (Maybe they could be applied
157-
// globally?)
97+
// TODO(antoyo): cg_llvm adds global features to each function so that LTO keep them.
98+
// Check if GCC requires the same.
15899
let mut global_features = cx.tcx.global_backend_features(()).iter().map(|s| s.as_str());
159100
function_features.extend(&mut global_features);
160-
let target_features = function_features.join(",");
101+
let target_features = function_features
102+
.iter()
103+
.filter_map(|feature| {
104+
// FIXME(antoyo): for some reasons, disabling SSE results in the following error when
105+
// compiling Rust for Linux:
106+
// SSE register return with SSE disabled
107+
// TODO(antoyo): support soft-float and retpoline-external-thunk.
108+
if feature.contains("soft-float") || feature.contains("retpoline-external-thunk") || *feature == "-sse" {
109+
return None;
110+
}
111+
112+
if feature.starts_with('-') {
113+
Some(format!("no{}", feature))
114+
}
115+
else if feature.starts_with('+') {
116+
Some(feature[1..].to_string())
117+
}
118+
else {
119+
Some(feature.to_string())
120+
}
121+
})
122+
.collect::<Vec<_>>()
123+
.join(",");
161124
if !target_features.is_empty() {
162125
#[cfg(feature="master")]
163126
func.add_attribute(FnAttribute::Target(&target_features));

src/base.rs

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
use std::collections::HashSet;
22
use std::env;
3-
use std::sync::Arc;
43
use std::time::Instant;
54

65
use gccjit::{
76
Context,
87
FunctionType,
98
GlobalKind,
109
};
11-
#[cfg(feature="master")]
12-
use gccjit::TargetInfo;
1310
use rustc_middle::dep_graph;
1411
use rustc_middle::ty::TyCtxt;
1512
#[cfg(feature="master")]
@@ -22,8 +19,7 @@ use rustc_codegen_ssa::traits::DebugInfoMethods;
2219
use rustc_session::config::DebugInfo;
2320
use rustc_span::Symbol;
2421

25-
#[cfg(not(feature="master"))]
26-
use crate::TargetInfo;
22+
use crate::{LockedTargetInfo, gcc_util};
2723
use crate::GccContext;
2824
use crate::builder::Builder;
2925
use crate::context::CodegenCx;
@@ -70,7 +66,7 @@ pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
7066
}
7167
}
7268

73-
pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Arc<TargetInfo>) -> (ModuleCodegen<GccContext>, u64) {
69+
pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: LockedTargetInfo) -> (ModuleCodegen<GccContext>, u64) {
7470
let prof_timer = tcx.prof.generic_activity("codegen_module");
7571
let start_time = Instant::now();
7672

@@ -89,7 +85,7 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Arc<
8985
// the time we needed for codegenning it.
9086
let cost = time_to_codegen.as_secs() * 1_000_000_000 + time_to_codegen.subsec_nanos() as u64;
9187

92-
fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, Arc<TargetInfo>)) -> ModuleCodegen<GccContext> {
88+
fn module_codegen(tcx: TyCtxt<'_>, (cgu_name, target_info): (Symbol, LockedTargetInfo)) -> ModuleCodegen<GccContext> {
9389
let cgu = tcx.codegen_unit(cgu_name);
9490
// Instantiate monomorphizations without filling out definitions yet...
9591
let context = Context::default();
@@ -102,32 +98,16 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Arc<
10298
.map(|string| &string[1..])
10399
.collect();
104100

105-
let add_cpu_feature_flag = |feature: &str| {
106-
// FIXME(antoyo): some tests cause a segfault in GCC when not enabling all these
107-
// features.
108-
if (true || target_info.cpu_supports(feature)) && !disabled_features.contains(feature) {
109-
context.add_command_line_option(&format!("-m{}", feature));
110-
}
111-
};
112-
113101
// TODO(antoyo): only set on x86 platforms.
114102
context.add_command_line_option("-masm=intel");
115103

116-
let features = ["sse2", "avx", "avx2", "sha", "fma", "gfni", "f16c", "aes", "bmi2", "rtm",
117-
"vaes", "vpclmulqdq", "xsavec",
118-
];
119-
120-
for feature in &features {
121-
add_cpu_feature_flag(feature);
104+
if !disabled_features.contains("avx") {
105+
// NOTE: we always enable AVX because the equivalent of llvm.x86.sse2.cmp.pd in GCC for
106+
// SSE2 is multiple builtins, so we use the AVX __builtin_ia32_cmppd instead.
107+
// FIXME(antoyo): use the proper builtins for llvm.x86.sse2.cmp.pd and similar.
108+
context.add_command_line_option("-mavx");
122109
}
123110

124-
// TODO(antoyo): only add the following cli arguments if the feature is supported.
125-
context.add_command_line_option("-mpclmul");
126-
context.add_command_line_option("-mfma4");
127-
context.add_command_line_option("-m64");
128-
context.add_command_line_option("-mbmi");
129-
//context.add_command_line_option("-mavxvnni"); // The CI doesn't support this option.
130-
131111
for arg in &tcx.sess.opts.cg.llvm_args {
132112
context.add_command_line_option(arg);
133113
}
@@ -145,6 +125,11 @@ pub fn compile_codegen_unit(tcx: TyCtxt<'_>, cgu_name: Symbol, target_info: Arc<
145125
context.add_command_line_option("-fno-pie");
146126
}
147127

128+
let target_cpu = gcc_util::target_cpu(tcx.sess);
129+
if target_cpu != "generic" {
130+
context.add_command_line_option(&format!("-march={}", target_cpu));
131+
}
132+
148133
if tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections) {
149134
context.add_command_line_option("-ffunction-sections");
150135
context.add_command_line_option("-fdata-sections");

src/errors.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,36 @@
1-
use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
2-
use rustc_macros::Diagnostic;
1+
use rustc_errors::{
2+
DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, IntoDiagnosticArg,
3+
};
4+
use rustc_macros::{Diagnostic, Subdiagnostic};
35
use rustc_span::Span;
46
use std::borrow::Cow;
57

8+
use crate::fluent_generated as fluent;
9+
10+
#[derive(Diagnostic)]
11+
#[diag(codegen_gcc_unknown_ctarget_feature_prefix)]
12+
#[note]
13+
pub(crate) struct UnknownCTargetFeaturePrefix<'a> {
14+
pub feature: &'a str,
15+
}
16+
17+
#[derive(Diagnostic)]
18+
#[diag(codegen_gcc_unknown_ctarget_feature)]
19+
#[note]
20+
pub(crate) struct UnknownCTargetFeature<'a> {
21+
pub feature: &'a str,
22+
#[subdiagnostic]
23+
pub rust_feature: PossibleFeature<'a>,
24+
}
25+
26+
#[derive(Subdiagnostic)]
27+
pub(crate) enum PossibleFeature<'a> {
28+
#[help(codegen_gcc_possible_feature)]
29+
Some { rust_feature: &'a str },
30+
#[help(codegen_gcc_consider_filing_feature_request)]
31+
None,
32+
}
33+
634
struct ExitCode(Option<i32>);
735

836
impl IntoDiagnosticArg for ExitCode {
@@ -71,3 +99,27 @@ pub(crate) struct LtoDylib;
7199
pub(crate) struct LtoBitcodeFromRlib {
72100
pub gcc_err: String,
73101
}
102+
103+
pub(crate) struct TargetFeatureDisableOrEnable<'a> {
104+
pub features: &'a [&'a str],
105+
pub span: Option<Span>,
106+
pub missing_features: Option<MissingFeatures>,
107+
}
108+
109+
#[derive(Subdiagnostic)]
110+
#[help(codegen_gcc_missing_features)]
111+
pub(crate) struct MissingFeatures;
112+
113+
impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
114+
fn into_diagnostic(self, sess: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
115+
let mut diag = sess.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
116+
if let Some(span) = self.span {
117+
diag.set_span(span);
118+
};
119+
if let Some(missing_features) = self.missing_features {
120+
diag.subdiagnostic(missing_features);
121+
}
122+
diag.set_arg("features", self.features.join(", "));
123+
diag
124+
}
125+
}

0 commit comments

Comments
 (0)