Skip to content

Commit 13d636d

Browse files
authored
Rollup merge of #93782 - adamgemmell:dev/adagem01/split-pauth, r=Amanieu
Split `pauth` target feature Per discussion on #86941 we'd like to split `pauth` into `paca` and `pacg` in order to better support possible future environments that only have the keys available for address or generic authentication. At the moment LLVM has the one `pauth` target_feature while Linux presents separate `paca` and `pacg` flags for feature detection. Because the use of [target_feature](https://rust-lang.github.io/rfcs/2045-target-feature.html) will "allow the compiler to generate code under the assumption that this code will only be reached in hosts that support the feature", it does not make sense to simply translate `paca` into the LLVM feature `pauth`, as it will generate code as if `pacg` is available. To accommodate this we error if only one of the two features is present. If LLVM splits them in the future we can remove this restriction without making a breaking change. r? ```@Amanieu```
2 parents ffa8d6b + d39a637 commit 13d636d

File tree

9 files changed

+148
-15
lines changed

9 files changed

+148
-15
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+26-5
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,33 @@ pub fn from_fn_attrs<'ll, 'tcx>(
322322
// The target doesn't care; the subtarget reads our attribute.
323323
apply_tune_cpu_attr(cx, llfn);
324324

325-
let mut function_features = codegen_fn_attrs
326-
.target_features
325+
let function_features =
326+
codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
327+
328+
if let Some(f) = llvm_util::check_tied_features(
329+
cx.tcx.sess,
330+
&function_features.iter().map(|f| (*f, true)).collect(),
331+
) {
332+
let span = cx
333+
.tcx
334+
.get_attrs(instance.def_id())
335+
.iter()
336+
.find(|a| a.has_name(rustc_span::sym::target_feature))
337+
.map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
338+
let msg = format!(
339+
"the target features {} must all be either enabled or disabled together",
340+
f.join(", ")
341+
);
342+
let mut err = cx.tcx.sess.struct_span_err(span, &msg);
343+
err.help("add the missing features in a `target_feature` attribute");
344+
err.emit();
345+
return;
346+
}
347+
348+
let mut function_features = function_features
327349
.iter()
328-
.flat_map(|f| {
329-
let feature = f.as_str();
330-
llvm_util::to_llvm_feature(cx.tcx.sess, feature)
350+
.flat_map(|feat| {
351+
llvm_util::to_llvm_feature(cx.tcx.sess, feat)
331352
.into_iter()
332353
.map(|f| format!("+{}", f))
333354
.collect::<Vec<String>>()

compiler/rustc_codegen_llvm/src/llvm_util.rs

+41-8
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::back::write::create_informational_target_machine;
22
use crate::{llvm, llvm_util};
33
use libc::c_int;
44
use libloading::Library;
5-
use rustc_codegen_ssa::target_features::supported_target_features;
6-
use rustc_data_structures::fx::FxHashSet;
5+
use rustc_codegen_ssa::target_features::{supported_target_features, tied_target_features};
6+
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
77
use rustc_fs_util::path_to_c_string;
88
use rustc_middle::bug;
99
use rustc_session::config::PrintRequest;
@@ -191,10 +191,30 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> {
191191
("aarch64", "frintts") => vec!["fptoint"],
192192
("aarch64", "fcma") => vec!["complxnum"],
193193
("aarch64", "pmuv3") => vec!["perfmon"],
194+
("aarch64", "paca") => vec!["pauth"],
195+
("aarch64", "pacg") => vec!["pauth"],
194196
(_, s) => vec![s],
195197
}
196198
}
197199

200+
// Given a map from target_features to whether they are enabled or disabled,
201+
// ensure only valid combinations are allowed.
202+
pub fn check_tied_features(
203+
sess: &Session,
204+
features: &FxHashMap<&str, bool>,
205+
) -> Option<&'static [&'static str]> {
206+
for tied in tied_target_features(sess) {
207+
// Tied features must be set to the same value, or not set at all
208+
let mut tied_iter = tied.iter();
209+
let enabled = features.get(tied_iter.next().unwrap());
210+
211+
if tied_iter.any(|f| enabled != features.get(f)) {
212+
return Some(tied);
213+
}
214+
}
215+
None
216+
}
217+
198218
pub fn target_features(sess: &Session) -> Vec<Symbol> {
199219
let target_machine = create_informational_target_machine(sess);
200220
supported_target_features(sess)
@@ -395,15 +415,19 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
395415
Some(_) | None => {}
396416
};
397417

418+
fn strip(s: &str) -> &str {
419+
s.strip_prefix(&['+', '-']).unwrap_or(s)
420+
}
421+
398422
let filter = |s: &str| {
399423
if s.is_empty() {
400424
return vec![];
401425
}
402-
let feature = if s.starts_with('+') || s.starts_with('-') {
403-
&s[1..]
404-
} else {
426+
let feature = strip(s);
427+
if feature == s {
405428
return vec![s.to_string()];
406-
};
429+
}
430+
407431
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
408432
// are not passed down to LLVM.
409433
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
@@ -420,8 +444,17 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
420444
features.extend(sess.target.features.split(',').flat_map(&filter));
421445

422446
// -Ctarget-features
423-
features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
424-
447+
let feats: Vec<&str> = sess.opts.cg.target_feature.split(',').collect();
448+
// LLVM enables based on the last occurence of a feature
449+
if let Some(f) =
450+
check_tied_features(sess, &feats.iter().map(|f| (strip(f), !f.starts_with("-"))).collect())
451+
{
452+
sess.err(&format!(
453+
"Target features {} must all be enabled or disabled together",
454+
f.join(", ")
455+
));
456+
}
457+
features.extend(feats.iter().flat_map(|&f| filter(f)));
425458
features
426459
}
427460

compiler/rustc_codegen_ssa/src/target_features.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,10 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
7474
("ssbs", Some(sym::aarch64_target_feature)),
7575
// FEAT_SB
7676
("sb", Some(sym::aarch64_target_feature)),
77-
// FEAT_PAUTH
78-
("pauth", Some(sym::aarch64_target_feature)),
77+
// FEAT_PAUTH (address authentication)
78+
("paca", Some(sym::aarch64_target_feature)),
79+
// FEAT_PAUTH (generic authentication)
80+
("pacg", Some(sym::aarch64_target_feature)),
7981
// FEAT_DPB
8082
("dpb", Some(sym::aarch64_target_feature)),
8183
// FEAT_DPB2
@@ -137,6 +139,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
137139
("v8.7a", Some(sym::aarch64_target_feature)),
138140
];
139141

142+
const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]];
143+
140144
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
141145
("adx", Some(sym::adx_target_feature)),
142146
("aes", None),
@@ -256,6 +260,13 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
256260
}
257261
}
258262

263+
pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] {
264+
match &*sess.target.arch {
265+
"aarch64" => AARCH64_TIED_FEATURES,
266+
_ => &[],
267+
}
268+
}
269+
259270
pub(crate) fn provide(providers: &mut Providers) {
260271
providers.supported_target_features = |tcx, cnum| {
261272
assert_eq!(cnum, LOCAL_CRATE);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: Target features paca, pacg must all be enabled or disabled together
2+
3+
error: aborting due to previous error
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// only-aarch64
2+
// revisions: one two three four
3+
//[one] compile-flags: -C target-feature=+paca
4+
//[two] compile-flags: -C target-feature=-pacg,+pacg
5+
//[three] compile-flags: -C target-feature=+paca,+pacg,-paca
6+
//[four] check-pass
7+
//[four] compile-flags: -C target-feature=-paca,+pacg -C target-feature=+paca
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: Target features paca, pacg must all be enabled or disabled together
2+
3+
error: aborting due to previous error
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: Target features paca, pacg must all be enabled or disabled together
2+
3+
error: aborting due to previous error
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// only-aarch64
2+
// build-fail
3+
4+
#![feature(aarch64_target_feature, target_feature_11)]
5+
6+
fn main() {
7+
#[target_feature(enable = "pacg")]
8+
//~^ ERROR must all be either enabled or disabled together
9+
unsafe fn inner() {}
10+
11+
unsafe {
12+
foo();
13+
bar();
14+
baz();
15+
inner();
16+
}
17+
}
18+
19+
#[target_feature(enable = "paca")]
20+
//~^ ERROR must all be either enabled or disabled together
21+
unsafe fn foo() {}
22+
23+
24+
#[target_feature(enable = "paca,pacg")]
25+
unsafe fn bar() {}
26+
27+
#[target_feature(enable = "paca")]
28+
#[target_feature(enable = "pacg")]
29+
unsafe fn baz() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: the target features paca, pacg must all be either enabled or disabled together
2+
--> $DIR/tied-features.rs:7:5
3+
|
4+
LL | #[target_feature(enable = "pacg")]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= help: add the missing features in a `target_feature` attribute
8+
9+
error: the target features paca, pacg must all be either enabled or disabled together
10+
--> $DIR/tied-features.rs:19:1
11+
|
12+
LL | #[target_feature(enable = "paca")]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
|
15+
= help: add the missing features in a `target_feature` attribute
16+
17+
error: aborting due to 2 previous errors
18+

0 commit comments

Comments
 (0)