From a6e2b636e658ca7346ffb32bf11301d92b72a1de Mon Sep 17 00:00:00 2001 From: xd009642 Date: Thu, 8 Oct 2020 23:23:27 +0100 Subject: [PATCH 1/2] Implement the instruction_set attribute --- compiler/rustc_attr/src/builtin.rs | 6 ++ compiler/rustc_codegen_llvm/src/attributes.rs | 6 +- compiler/rustc_error_codes/src/error_codes.rs | 2 + .../src/error_codes/E0778.md | 35 +++++++++ .../src/error_codes/E0779.md | 32 ++++++++ compiler/rustc_feature/src/active.rs | 3 + compiler/rustc_feature/src/builtin_attrs.rs | 2 + compiler/rustc_middle/src/ich/impls_hir.rs | 6 ++ .../src/middle/codegen_fn_attrs.rs | 7 +- compiler/rustc_span/src/symbol.rs | 5 ++ .../src/spec/armv4t_unknown_linux_gnueabi.rs | 1 + .../src/spec/armv5te_unknown_linux_gnueabi.rs | 1 + .../spec/armv5te_unknown_linux_musleabi.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 7 ++ .../src/spec/thumbv4t_none_eabi.rs | 1 + compiler/rustc_typeck/src/collect.rs | 73 ++++++++++++++++++- src/test/ui/error-codes/E0778.rs | 8 ++ src/test/ui/error-codes/E0778.stderr | 9 +++ src/test/ui/error-codes/E0779.rs | 6 ++ src/test/ui/error-codes/E0779.stderr | 9 +++ src/test/ui/feature-gate-isa_attribute.rs | 6 ++ src/test/ui/feature-gate-isa_attribute.stderr | 25 +++++++ 22 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0778.md create mode 100644 compiler/rustc_error_codes/src/error_codes/E0779.md create mode 100644 src/test/ui/error-codes/E0778.rs create mode 100644 src/test/ui/error-codes/E0778.stderr create mode 100644 src/test/ui/error-codes/E0779.rs create mode 100644 src/test/ui/error-codes/E0779.stderr create mode 100644 src/test/ui/feature-gate-isa_attribute.rs create mode 100644 src/test/ui/feature-gate-isa_attribute.stderr diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 94e2a40e1fe36..325af56f3cd8c 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -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, diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index a633ea5e5a9ae..f02c30c3ee392 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -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::>() .join(","); diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 981b5bb8ba72f..0a88759f84c9a 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -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 diff --git a/compiler/rustc_error_codes/src/error_codes/E0778.md b/compiler/rustc_error_codes/src/error_codes/E0778.md new file mode 100644 index 0000000000000..467362dca58fd --- /dev/null +++ b/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 diff --git a/compiler/rustc_error_codes/src/error_codes/E0779.md b/compiler/rustc_error_codes/src/error_codes/E0779.md new file mode 100644 index 0000000000000..146e20c262659 --- /dev/null +++ b/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 diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 1982d098542ba..8a7f0517e732b 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -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 // ------------------------------------------------------------------------- diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index b7e113e601007..527a49b05389a 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -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)), diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs index c2d177b69b6b9..d6c6cef17513d 100644 --- a/compiler/rustc_middle/src/ich/impls_hir.rs +++ b/compiler/rustc_middle/src/ich/impls_hir.rs @@ -221,6 +221,12 @@ impl<'hir> HashStable> for attr::InlineAttr { } } +impl<'hir> HashStable> for attr::InstructionSetAttr { + fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + } +} + impl<'hir> HashStable> for attr::OptimizeAttr { fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index d71cdc4e67de4..a4363bb580a2f 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/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; @@ -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, } bitflags! { @@ -98,6 +102,7 @@ impl CodegenFnAttrs { linkage: None, link_section: None, no_sanitize: SanitizerSet::empty(), + instruction_set: None, } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index a2184c00a28fb..223a0758f008b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -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, diff --git a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs index 2580e8b0f8515..a184934a99d86 100644 --- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs @@ -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 }, }) diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs index f28421dc77593..015d27415ace9 100644 --- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs @@ -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 }, }) diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs index fe1fa88883d3e..e35d805126164 100644 --- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs @@ -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 }, }) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f1e8330425e25..a98dbbc4ed144 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -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( diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs index a8c78f057fc8a..e8b614e8345ee 100644 --- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs @@ -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() }, diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 092dae18192e5..b64a1ce7c3082 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -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::>(); + 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 + } + }; } } diff --git a/src/test/ui/error-codes/E0778.rs b/src/test/ui/error-codes/E0778.rs new file mode 100644 index 0000000000000..60e5c2598f1ee --- /dev/null +++ b/src/test/ui/error-codes/E0778.rs @@ -0,0 +1,8 @@ +#![feature(isa_attribute)] + +#[instruction_set()] //~ ERROR +fn no_isa_defined() { +} + +fn main() { +} diff --git a/src/test/ui/error-codes/E0778.stderr b/src/test/ui/error-codes/E0778.stderr new file mode 100644 index 0000000000000..6ecae79242377 --- /dev/null +++ b/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`. diff --git a/src/test/ui/error-codes/E0779.rs b/src/test/ui/error-codes/E0779.rs new file mode 100644 index 0000000000000..1b4dbce20360c --- /dev/null +++ b/src/test/ui/error-codes/E0779.rs @@ -0,0 +1,6 @@ +#![feature(isa_attribute)] + +#[instruction_set(arm::magic)] //~ ERROR +fn main() { + +} diff --git a/src/test/ui/error-codes/E0779.stderr b/src/test/ui/error-codes/E0779.stderr new file mode 100644 index 0000000000000..4abe0c0263651 --- /dev/null +++ b/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`. diff --git a/src/test/ui/feature-gate-isa_attribute.rs b/src/test/ui/feature-gate-isa_attribute.rs new file mode 100644 index 0000000000000..cb02a0955e913 --- /dev/null +++ b/src/test/ui/feature-gate-isa_attribute.rs @@ -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() { +} diff --git a/src/test/ui/feature-gate-isa_attribute.stderr b/src/test/ui/feature-gate-isa_attribute.stderr new file mode 100644 index 0000000000000..2a95a80ca6178 --- /dev/null +++ b/src/test/ui/feature-gate-isa_attribute.stderr @@ -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 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`. From bdb3f7716b567178ebda5006ed62cbe476408ef3 Mon Sep 17 00:00:00 2001 From: xd009642 Date: Thu, 8 Oct 2020 23:56:59 +0100 Subject: [PATCH 2/2] Fix typo in error code --- src/test/ui/error-codes/E0779.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/error-codes/E0779.stderr b/src/test/ui/error-codes/E0779.stderr index 4abe0c0263651..da787260d4f6d 100644 --- a/src/test/ui/error-codes/E0779.stderr +++ b/src/test/ui/error-codes/E0779.stderr @@ -1,4 +1,4 @@ -error[E0779]: Invalid instruction set specified +error[E0779]: invalid instruction set specified --> $DIR/E0779.rs:3:1 | LL | #[instruction_set(arm::magic)]