Skip to content

Commit 03ef8a0

Browse files
committed
Auto merge of #76260 - xd009642:rfc/2867, r=jonas-schievink
Implementation of RFC2867 #74727 So I've started work on this, I think my next steps are to make use of the `instruction_set` value in the llvm codegen but this is the point where I begin to get a bit lost. I'm looking at the code but it would be nice to have some guidance on what I've currently done and what I'm doing next 😄
2 parents 8a84c4f + bdb3f77 commit 03ef8a0

22 files changed

+247
-4
lines changed

compiler/rustc_attr/src/builtin.rs

+6
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ pub enum InlineAttr {
7575
Never,
7676
}
7777

78+
#[derive(Clone, Encodable, Decodable)]
79+
pub enum InstructionSetAttr {
80+
ArmA32,
81+
ArmT32,
82+
}
83+
7884
#[derive(Clone, Encodable, Decodable)]
7985
pub enum OptimizeAttr {
8086
None,

compiler/rustc_codegen_llvm/src/attributes.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::attributes;
1818
use crate::llvm::AttributePlace::Function;
1919
use crate::llvm::{self, Attribute};
2020
use crate::llvm_util;
21-
pub use rustc_attr::{InlineAttr, OptimizeAttr};
21+
pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
2222

2323
use crate::context::CodegenCx;
2424
use crate::value::Value;
@@ -310,6 +310,10 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
310310
let feature = &f.as_str();
311311
format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
312312
}))
313+
.chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
314+
InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
315+
InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
316+
}))
313317
.collect::<Vec<String>>()
314318
.join(",");
315319

compiler/rustc_error_codes/src/error_codes.rs

+2
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,8 @@ E0774: include_str!("./error_codes/E0774.md"),
460460
E0775: include_str!("./error_codes/E0775.md"),
461461
E0776: include_str!("./error_codes/E0776.md"),
462462
E0777: include_str!("./error_codes/E0777.md"),
463+
E0778: include_str!("./error_codes/E0778.md"),
464+
E0779: include_str!("./error_codes/E0779.md"),
463465
;
464466
// E0006, // merged with E0005
465467
// E0008, // cannot bind by-move into a pattern guard
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
The `instruction_set` attribute was malformed.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0778
6+
#![feature(isa_attribute)]
7+
8+
#[instruction_set()] // error: expected one argument
9+
pub fn something() {}
10+
fn main() {}
11+
```
12+
13+
The parenthesized `instruction_set` attribute requires the parameter to be
14+
specified:
15+
16+
```
17+
#![feature(isa_attribute)]
18+
19+
#[cfg_attr(target_arch="arm", instruction_set(arm::a32))]
20+
fn something() {}
21+
```
22+
23+
or:
24+
25+
```
26+
#![feature(isa_attribute)]
27+
28+
#[cfg_attr(target_arch="arm", instruction_set(arm::t32))]
29+
fn something() {}
30+
```
31+
32+
For more information see the [`instruction_set` attribute][isa-attribute]
33+
section of the Reference.
34+
35+
[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
An unknown argument was given to the `instruction_set` attribute.
2+
3+
Erroneous code example:
4+
5+
```compile_fail,E0779
6+
#![feature(isa_attribute)]
7+
8+
#[instruction_set(intel::x64)] // error: invalid argument
9+
pub fn something() {}
10+
fn main() {}
11+
```
12+
13+
The `instruction_set` attribute only supports two arguments currently:
14+
15+
* arm::a32
16+
* arm::t32
17+
18+
All other arguments given to the `instruction_set` attribute will return this
19+
error. Example:
20+
21+
```
22+
#![feature(isa_attribute)]
23+
24+
#[cfg_attr(target_arch="arm", instruction_set(arm::a32))] // ok!
25+
pub fn something() {}
26+
fn main() {}
27+
```
28+
29+
For more information see the [`instruction_set` attribute][isa-attribute]
30+
section of the Reference.
31+
32+
[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html

compiler/rustc_feature/src/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,9 @@ declare_features! (
599599
/// Allows argument and return position `impl Trait` in a `const fn`.
600600
(active, const_impl_trait, "1.48.0", Some(77463), None),
601601

602+
/// Allows `#[instruction_set(_)]` attribute
603+
(active, isa_attribute, "1.48.0", Some(74727), None),
604+
602605
// -------------------------------------------------------------------------
603606
// feature-group-end: actual feature gates
604607
// -------------------------------------------------------------------------

compiler/rustc_feature/src/builtin_attrs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
336336
optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute,
337337
experimental!(optimize),
338338
),
339+
// RFC 2867
340+
gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
339341

340342
gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)),
341343
gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)),

compiler/rustc_middle/src/ich/impls_hir.rs

+6
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
221221
}
222222
}
223223

224+
impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InstructionSetAttr {
225+
fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
226+
mem::discriminant(self).hash_stable(hcx, hasher);
227+
}
228+
}
229+
224230
impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
225231
fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
226232
mem::discriminant(self).hash_stable(hcx, hasher);

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::mir::mono::Linkage;
2-
use rustc_attr::{InlineAttr, OptimizeAttr};
2+
use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
33
use rustc_session::config::SanitizerSet;
44
use rustc_span::symbol::Symbol;
55

@@ -34,6 +34,10 @@ pub struct CodegenFnAttrs {
3434
/// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
3535
/// instrumentation should be disabled inside the annotated function.
3636
pub no_sanitize: SanitizerSet,
37+
/// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
38+
/// be generated against a specific instruction set. Only usable on architectures which allow
39+
/// switching between multiple instruction sets.
40+
pub instruction_set: Option<InstructionSetAttr>,
3741
}
3842

3943
bitflags! {
@@ -98,6 +102,7 @@ impl CodegenFnAttrs {
98102
linkage: None,
99103
link_section: None,
100104
no_sanitize: SanitizerSet::empty(),
105+
instruction_set: None,
101106
}
102107
}
103108

compiler/rustc_span/src/symbol.rs

+5
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ symbols! {
212212
_d,
213213
_e,
214214
_task_context,
215+
a32,
215216
aarch64_target_feature,
216217
abi,
217218
abi_amdgpu_kernel,
@@ -256,6 +257,7 @@ symbols! {
256257
arbitrary_enum_discriminant,
257258
arbitrary_self_types,
258259
arith_offset,
260+
arm,
259261
arm_target_feature,
260262
array,
261263
arrays,
@@ -592,11 +594,13 @@ symbols! {
592594
inlateout,
593595
inline,
594596
inout,
597+
instruction_set,
595598
intel,
596599
into_iter,
597600
into_result,
598601
intrinsics,
599602
irrefutable_let_patterns,
603+
isa_attribute,
600604
isize,
601605
issue,
602606
issue_5723_bootstrap,
@@ -1065,6 +1069,7 @@ symbols! {
10651069
sym,
10661070
sync,
10671071
sync_trait,
1072+
t32,
10681073
target_arch,
10691074
target_endian,
10701075
target_env,

compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub fn target() -> TargetResult {
2020
max_atomic_width: Some(32),
2121
unsupported_abis: super::arm_base::unsupported_abis(),
2222
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
23+
has_thumb_interworking: true,
2324
..base
2425
},
2526
})

compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub fn target() -> TargetResult {
2020
max_atomic_width: Some(32),
2121
unsupported_abis: super::arm_base::unsupported_abis(),
2222
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
23+
has_thumb_interworking: true,
2324
..base
2425
},
2526
})

compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub fn target() -> TargetResult {
2323
max_atomic_width: Some(32),
2424
unsupported_abis: super::arm_base::unsupported_abis(),
2525
target_mcount: "\u{1}mcount".to_string(),
26+
has_thumb_interworking: true,
2627
..base
2728
},
2829
})

compiler/rustc_target/src/spec/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,10 @@ pub struct TargetOptions {
994994
/// used to locate unwinding information is passed
995995
/// (only has effect if the linker is `ld`-like).
996996
pub eh_frame_header: bool,
997+
998+
/// Is true if the target is an ARM architecture using thumb v1 which allows for
999+
/// thumb and arm interworking.
1000+
pub has_thumb_interworking: bool,
9971001
}
9981002

9991003
impl Default for TargetOptions {
@@ -1086,6 +1090,7 @@ impl Default for TargetOptions {
10861090
llvm_args: vec![],
10871091
use_ctors_section: false,
10881092
eh_frame_header: true,
1093+
has_thumb_interworking: false,
10891094
}
10901095
}
10911096
}
@@ -1479,6 +1484,7 @@ impl Target {
14791484
key!(llvm_args, list);
14801485
key!(use_ctors_section, bool);
14811486
key!(eh_frame_header, bool);
1487+
key!(has_thumb_interworking, bool);
14821488

14831489
// NB: The old name is deprecated, but support for it is retained for
14841490
// compatibility.
@@ -1717,6 +1723,7 @@ impl ToJson for Target {
17171723
target_option_val!(llvm_args);
17181724
target_option_val!(use_ctors_section);
17191725
target_option_val!(eh_frame_header);
1726+
target_option_val!(has_thumb_interworking);
17201727

17211728
if default.unsupported_abis != self.options.unsupported_abis {
17221729
d.insert(

compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub fn target() -> TargetResult {
5555

5656
// don't have atomic compare-and-swap
5757
atomic_cas: false,
58+
has_thumb_interworking: true,
5859

5960
..super::thumb_base::opts()
6061
},

compiler/rustc_typeck/src/collect.rs

+71-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use crate::constrained_generic_params as cgp;
2121
use crate::errors;
2222
use crate::middle::resolve_lifetime as rl;
2323
use rustc_ast as ast;
24-
use rustc_ast::MetaItemKind;
25-
use rustc_attr::{list_contains_name, InlineAttr, OptimizeAttr};
24+
use rustc_ast::{MetaItemKind, NestedMetaItem};
25+
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
2626
use rustc_data_structures::captures::Captures;
2727
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
2828
use rustc_errors::{struct_span_err, Applicability};
@@ -2647,6 +2647,75 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
26472647
}
26482648
}
26492649
}
2650+
} else if tcx.sess.check_name(attr, sym::instruction_set) {
2651+
codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) {
2652+
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
2653+
[NestedMetaItem::MetaItem(set)] => {
2654+
let segments =
2655+
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
2656+
match segments.as_slice() {
2657+
[sym::arm, sym::a32] | [sym::arm, sym::t32] => {
2658+
if !tcx.sess.target.target.options.has_thumb_interworking {
2659+
struct_span_err!(
2660+
tcx.sess.diagnostic(),
2661+
attr.span,
2662+
E0779,
2663+
"target does not support `#[instruction_set]`"
2664+
)
2665+
.emit();
2666+
None
2667+
} else if segments[1] == sym::a32 {
2668+
Some(InstructionSetAttr::ArmA32)
2669+
} else if segments[1] == sym::t32 {
2670+
Some(InstructionSetAttr::ArmT32)
2671+
} else {
2672+
unreachable!()
2673+
}
2674+
}
2675+
_ => {
2676+
struct_span_err!(
2677+
tcx.sess.diagnostic(),
2678+
attr.span,
2679+
E0779,
2680+
"invalid instruction set specified",
2681+
)
2682+
.emit();
2683+
None
2684+
}
2685+
}
2686+
}
2687+
[] => {
2688+
struct_span_err!(
2689+
tcx.sess.diagnostic(),
2690+
attr.span,
2691+
E0778,
2692+
"`#[instruction_set]` requires an argument"
2693+
)
2694+
.emit();
2695+
None
2696+
}
2697+
_ => {
2698+
struct_span_err!(
2699+
tcx.sess.diagnostic(),
2700+
attr.span,
2701+
E0779,
2702+
"cannot specify more than one instruction set"
2703+
)
2704+
.emit();
2705+
None
2706+
}
2707+
},
2708+
_ => {
2709+
struct_span_err!(
2710+
tcx.sess.diagnostic(),
2711+
attr.span,
2712+
E0778,
2713+
"must specify an instruction set"
2714+
)
2715+
.emit();
2716+
None
2717+
}
2718+
};
26502719
}
26512720
}
26522721

src/test/ui/error-codes/E0778.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![feature(isa_attribute)]
2+
3+
#[instruction_set()] //~ ERROR
4+
fn no_isa_defined() {
5+
}
6+
7+
fn main() {
8+
}

src/test/ui/error-codes/E0778.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0778]: `#[instruction_set]` requires an argument
2+
--> $DIR/E0778.rs:3:1
3+
|
4+
LL | #[instruction_set()]
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0778`.

src/test/ui/error-codes/E0779.rs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#![feature(isa_attribute)]
2+
3+
#[instruction_set(arm::magic)] //~ ERROR
4+
fn main() {
5+
6+
}

src/test/ui/error-codes/E0779.stderr

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0779]: invalid instruction set specified
2+
--> $DIR/E0779.rs:3:1
3+
|
4+
LL | #[instruction_set(arm::magic)]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0779`.

0 commit comments

Comments
 (0)