Skip to content

Commit

Permalink
Implement the instruction_set attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
xd009642 committed Oct 8, 2020
1 parent 4437b4b commit a6e2b63
Show file tree
Hide file tree
Showing 22 changed files with 247 additions and 4 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_attr/src/builtin.rs
Expand Up @@ -75,6 +75,12 @@ pub enum InlineAttr {
Never,
}

#[derive(Clone, Encodable, Decodable)]
pub enum InstructionSetAttr {
ArmA32,
ArmT32,
}

#[derive(Clone, Encodable, Decodable)]
pub enum OptimizeAttr {
None,
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_codegen_llvm/src/attributes.rs
Expand Up @@ -18,7 +18,7 @@ use crate::attributes;
use crate::llvm::AttributePlace::Function;
use crate::llvm::{self, Attribute};
use crate::llvm_util;
pub use rustc_attr::{InlineAttr, OptimizeAttr};
pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};

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

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_error_codes/src/error_codes.rs
Expand Up @@ -460,6 +460,8 @@ E0774: include_str!("./error_codes/E0774.md"),
E0775: include_str!("./error_codes/E0775.md"),
E0776: include_str!("./error_codes/E0776.md"),
E0777: include_str!("./error_codes/E0777.md"),
E0778: include_str!("./error_codes/E0778.md"),
E0779: include_str!("./error_codes/E0779.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
Expand Down
35 changes: 35 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0778.md
@@ -0,0 +1,35 @@
The `instruction_set` attribute was malformed.

Erroneous code example:

```compile_fail,E0778
#![feature(isa_attribute)]
#[instruction_set()] // error: expected one argument
pub fn something() {}
fn main() {}
```

The parenthesized `instruction_set` attribute requires the parameter to be
specified:

```
#![feature(isa_attribute)]
#[cfg_attr(target_arch="arm", instruction_set(arm::a32))]
fn something() {}
```

or:

```
#![feature(isa_attribute)]
#[cfg_attr(target_arch="arm", instruction_set(arm::t32))]
fn something() {}
```

For more information see the [`instruction_set` attribute][isa-attribute]
section of the Reference.

[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html
32 changes: 32 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0779.md
@@ -0,0 +1,32 @@
An unknown argument was given to the `instruction_set` attribute.

Erroneous code example:

```compile_fail,E0779
#![feature(isa_attribute)]
#[instruction_set(intel::x64)] // error: invalid argument
pub fn something() {}
fn main() {}
```

The `instruction_set` attribute only supports two arguments currently:

* arm::a32
* arm::t32

All other arguments given to the `instruction_set` attribute will return this
error. Example:

```
#![feature(isa_attribute)]
#[cfg_attr(target_arch="arm", instruction_set(arm::a32))] // ok!
pub fn something() {}
fn main() {}
```

For more information see the [`instruction_set` attribute][isa-attribute]
section of the Reference.

[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/active.rs
Expand Up @@ -599,6 +599,9 @@ declare_features! (
/// Allows argument and return position `impl Trait` in a `const fn`.
(active, const_impl_trait, "1.48.0", Some(77463), None),

/// Allows `#[instruction_set(_)]` attribute
(active, isa_attribute, "1.48.0", Some(74727), None),

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Expand Up @@ -336,6 +336,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute,
experimental!(optimize),
),
// RFC 2867
gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)),

gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)),
gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)),
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ich/impls_hir.rs
Expand Up @@ -221,6 +221,12 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
}
}

impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InstructionSetAttr {
fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
}
}

impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,5 +1,5 @@
use crate::mir::mono::Linkage;
use rustc_attr::{InlineAttr, OptimizeAttr};
use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_session::config::SanitizerSet;
use rustc_span::symbol::Symbol;

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

bitflags! {
Expand Down Expand Up @@ -98,6 +102,7 @@ impl CodegenFnAttrs {
linkage: None,
link_section: None,
no_sanitize: SanitizerSet::empty(),
instruction_set: None,
}
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Expand Up @@ -212,6 +212,7 @@ symbols! {
_d,
_e,
_task_context,
a32,
aarch64_target_feature,
abi,
abi_amdgpu_kernel,
Expand Down Expand Up @@ -256,6 +257,7 @@ symbols! {
arbitrary_enum_discriminant,
arbitrary_self_types,
arith_offset,
arm,
arm_target_feature,
array,
arrays,
Expand Down Expand Up @@ -592,11 +594,13 @@ symbols! {
inlateout,
inline,
inout,
instruction_set,
intel,
into_iter,
into_result,
intrinsics,
irrefutable_let_patterns,
isa_attribute,
isize,
issue,
issue_5723_bootstrap,
Expand Down Expand Up @@ -1065,6 +1069,7 @@ symbols! {
sym,
sync,
sync_trait,
t32,
target_arch,
target_endian,
target_env,
Expand Down
Expand Up @@ -20,6 +20,7 @@ pub fn target() -> TargetResult {
max_atomic_width: Some(32),
unsupported_abis: super::arm_base::unsupported_abis(),
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
has_thumb_interworking: true,
..base
},
})
Expand Down
Expand Up @@ -20,6 +20,7 @@ pub fn target() -> TargetResult {
max_atomic_width: Some(32),
unsupported_abis: super::arm_base::unsupported_abis(),
target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
has_thumb_interworking: true,
..base
},
})
Expand Down
Expand Up @@ -23,6 +23,7 @@ pub fn target() -> TargetResult {
max_atomic_width: Some(32),
unsupported_abis: super::arm_base::unsupported_abis(),
target_mcount: "\u{1}mcount".to_string(),
has_thumb_interworking: true,
..base
},
})
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Expand Up @@ -994,6 +994,10 @@ pub struct TargetOptions {
/// used to locate unwinding information is passed
/// (only has effect if the linker is `ld`-like).
pub eh_frame_header: bool,

/// Is true if the target is an ARM architecture using thumb v1 which allows for
/// thumb and arm interworking.
pub has_thumb_interworking: bool,
}

impl Default for TargetOptions {
Expand Down Expand Up @@ -1086,6 +1090,7 @@ impl Default for TargetOptions {
llvm_args: vec![],
use_ctors_section: false,
eh_frame_header: true,
has_thumb_interworking: false,
}
}
}
Expand Down Expand Up @@ -1479,6 +1484,7 @@ impl Target {
key!(llvm_args, list);
key!(use_ctors_section, bool);
key!(eh_frame_header, bool);
key!(has_thumb_interworking, bool);

// NB: The old name is deprecated, but support for it is retained for
// compatibility.
Expand Down Expand Up @@ -1717,6 +1723,7 @@ impl ToJson for Target {
target_option_val!(llvm_args);
target_option_val!(use_ctors_section);
target_option_val!(eh_frame_header);
target_option_val!(has_thumb_interworking);

if default.unsupported_abis != self.options.unsupported_abis {
d.insert(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
Expand Up @@ -55,6 +55,7 @@ pub fn target() -> TargetResult {

// don't have atomic compare-and-swap
atomic_cas: false,
has_thumb_interworking: true,

..super::thumb_base::opts()
},
Expand Down
73 changes: 71 additions & 2 deletions compiler/rustc_typeck/src/collect.rs
Expand Up @@ -21,8 +21,8 @@ use crate::constrained_generic_params as cgp;
use crate::errors;
use crate::middle::resolve_lifetime as rl;
use rustc_ast as ast;
use rustc_ast::MetaItemKind;
use rustc_attr::{list_contains_name, InlineAttr, OptimizeAttr};
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{struct_span_err, Applicability};
Expand Down Expand Up @@ -2647,6 +2647,75 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
}
}
}
} else if tcx.sess.check_name(attr, sym::instruction_set) {
codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) {
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
[NestedMetaItem::MetaItem(set)] => {
let segments =
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
match segments.as_slice() {
[sym::arm, sym::a32] | [sym::arm, sym::t32] => {
if !tcx.sess.target.target.options.has_thumb_interworking {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"target does not support `#[instruction_set]`"
)
.emit();
None
} else if segments[1] == sym::a32 {
Some(InstructionSetAttr::ArmA32)
} else if segments[1] == sym::t32 {
Some(InstructionSetAttr::ArmT32)
} else {
unreachable!()
}
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"invalid instruction set specified",
)
.emit();
None
}
}
}
[] => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"`#[instruction_set]` requires an argument"
)
.emit();
None
}
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0779,
"cannot specify more than one instruction set"
)
.emit();
None
}
},
_ => {
struct_span_err!(
tcx.sess.diagnostic(),
attr.span,
E0778,
"must specify an instruction set"
)
.emit();
None
}
};
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/error-codes/E0778.rs
@@ -0,0 +1,8 @@
#![feature(isa_attribute)]

#[instruction_set()] //~ ERROR
fn no_isa_defined() {
}

fn main() {
}
9 changes: 9 additions & 0 deletions src/test/ui/error-codes/E0778.stderr
@@ -0,0 +1,9 @@
error[E0778]: `#[instruction_set]` requires an argument
--> $DIR/E0778.rs:3:1
|
LL | #[instruction_set()]
| ^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0778`.
6 changes: 6 additions & 0 deletions src/test/ui/error-codes/E0779.rs
@@ -0,0 +1,6 @@
#![feature(isa_attribute)]

#[instruction_set(arm::magic)] //~ ERROR
fn main() {

}
9 changes: 9 additions & 0 deletions src/test/ui/error-codes/E0779.stderr
@@ -0,0 +1,9 @@
error[E0779]: Invalid instruction set specified
--> $DIR/E0779.rs:3:1
|
LL | #[instruction_set(arm::magic)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0779`.

0 comments on commit a6e2b63

Please sign in to comment.