Implement the instruction_set attribute
This commit is contained in:
parent
4437b4b150
commit
a6e2b636e6
22 changed files with 247 additions and 4 deletions
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
@ -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(",");
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
35
compiler/rustc_error_codes/src/error_codes/E0778.md
Normal file
35
compiler/rustc_error_codes/src/error_codes/E0778.md
Normal file
|
@ -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
compiler/rustc_error_codes/src/error_codes/E0779.md
Normal file
32
compiler/rustc_error_codes/src/error_codes/E0779.md
Normal file
|
@ -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
|
|
@ -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
|
||||
// -------------------------------------------------------------------------
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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! {
|
||||
|
@ -98,6 +102,7 @@ impl CodegenFnAttrs {
|
|||
linkage: None,
|
||||
link_section: None,
|
||||
no_sanitize: SanitizerSet::empty(),
|
||||
instruction_set: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -212,6 +212,7 @@ symbols! {
|
|||
_d,
|
||||
_e,
|
||||
_task_context,
|
||||
a32,
|
||||
aarch64_target_feature,
|
||||
abi,
|
||||
abi_amdgpu_kernel,
|
||||
|
@ -256,6 +257,7 @@ symbols! {
|
|||
arbitrary_enum_discriminant,
|
||||
arbitrary_self_types,
|
||||
arith_offset,
|
||||
arm,
|
||||
arm_target_feature,
|
||||
array,
|
||||
arrays,
|
||||
|
@ -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,
|
||||
|
@ -1065,6 +1069,7 @@ symbols! {
|
|||
sym,
|
||||
sync,
|
||||
sync_trait,
|
||||
t32,
|
||||
target_arch,
|
||||
target_endian,
|
||||
target_env,
|
||||
|
|
|
@ -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
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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
|
||||
},
|
||||
})
|
||||
|
|
|
@ -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 {
|
||||
|
@ -1086,6 +1090,7 @@ impl Default for TargetOptions {
|
|||
llvm_args: vec![],
|
||||
use_ctors_section: false,
|
||||
eh_frame_header: true,
|
||||
has_thumb_interworking: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
},
|
||||
|
|
|
@ -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};
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
8
src/test/ui/error-codes/E0778.rs
Normal file
8
src/test/ui/error-codes/E0778.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
#![feature(isa_attribute)]
|
||||
|
||||
#[instruction_set()] //~ ERROR
|
||||
fn no_isa_defined() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
9
src/test/ui/error-codes/E0778.stderr
Normal file
9
src/test/ui/error-codes/E0778.stderr
Normal file
|
@ -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
src/test/ui/error-codes/E0779.rs
Normal file
6
src/test/ui/error-codes/E0779.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#![feature(isa_attribute)]
|
||||
|
||||
#[instruction_set(arm::magic)] //~ ERROR
|
||||
fn main() {
|
||||
|
||||
}
|
9
src/test/ui/error-codes/E0779.stderr
Normal file
9
src/test/ui/error-codes/E0779.stderr
Normal file
|
@ -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`.
|
6
src/test/ui/feature-gate-isa_attribute.rs
Normal file
6
src/test/ui/feature-gate-isa_attribute.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#[instruction_set]
|
||||
//~^ ERROR the `#[instruction_set]` attribute is an experimental feature [E0658]
|
||||
//~| ERROR malformed `instruction_set` attribute input
|
||||
//~| ERROR must specify an instruction set [E0778]
|
||||
fn main() {
|
||||
}
|
25
src/test/ui/feature-gate-isa_attribute.stderr
Normal file
25
src/test/ui/feature-gate-isa_attribute.stderr
Normal file
|
@ -0,0 +1,25 @@
|
|||
error: malformed `instruction_set` attribute input
|
||||
--> $DIR/feature-gate-isa_attribute.rs:1:1
|
||||
|
|
||||
LL | #[instruction_set]
|
||||
| ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]`
|
||||
|
||||
error[E0658]: the `#[instruction_set]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-isa_attribute.rs:1:1
|
||||
|
|
||||
LL | #[instruction_set]
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #74727 <https://github.com/rust-lang/rust/issues/74727> for more information
|
||||
= help: add `#![feature(isa_attribute)]` to the crate attributes to enable
|
||||
|
||||
error[E0778]: must specify an instruction set
|
||||
--> $DIR/feature-gate-isa_attribute.rs:1:1
|
||||
|
|
||||
LL | #[instruction_set]
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0658, E0778.
|
||||
For more information about an error, try `rustc --explain E0658`.
|
Loading…
Add table
Add a link
Reference in a new issue