Never,
}
+#[derive(Clone, Encodable, Decodable)]
+pub enum InstructionSetAttr {
+ ArmA32,
+ ArmT32,
+}
+
#[derive(Clone, Encodable, Decodable)]
pub enum OptimizeAttr {
None,
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;
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(",");
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
--- /dev/null
+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
--- /dev/null
+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
/// 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
// -------------------------------------------------------------------------
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)),
}
}
+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);
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;
/// 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! {
linkage: None,
link_section: None,
no_sanitize: SanitizerSet::empty(),
+ instruction_set: None,
}
}
_d,
_e,
_task_context,
+ a32,
aarch64_target_feature,
abi,
abi_amdgpu_kernel,
arbitrary_enum_discriminant,
arbitrary_self_types,
arith_offset,
+ arm,
arm_target_feature,
array,
arrays,
inlateout,
inline,
inout,
+ instruction_set,
intel,
into_iter,
into_result,
intrinsics,
irrefutable_let_patterns,
+ isa_attribute,
isize,
issue,
issue_5723_bootstrap,
sym,
sync,
sync_trait,
+ t32,
target_arch,
target_endian,
target_env,
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
},
})
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
},
})
max_atomic_width: Some(32),
unsupported_abis: super::arm_base::unsupported_abis(),
target_mcount: "\u{1}mcount".to_string(),
+ has_thumb_interworking: true,
..base
},
})
/// 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 {
llvm_args: vec![],
use_ctors_section: false,
eh_frame_header: true,
+ has_thumb_interworking: false,
}
}
}
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.
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(
// don't have atomic compare-and-swap
atomic_cas: false,
+ has_thumb_interworking: true,
..super::thumb_base::opts()
},
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};
}
}
}
+ } 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
+ }
+ };
}
}
--- /dev/null
+#![feature(isa_attribute)]
+
+#[instruction_set()] //~ ERROR
+fn no_isa_defined() {
+}
+
+fn main() {
+}
--- /dev/null
+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`.
--- /dev/null
+#![feature(isa_attribute)]
+
+#[instruction_set(arm::magic)] //~ ERROR
+fn main() {
+
+}
--- /dev/null
+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`.
--- /dev/null
+#[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() {
+}
--- /dev/null
+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`.