2 use rustc_attr::InstructionSetAttr;
3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_data_structures::fx::FxHashSet;
5 use rustc_errors::Applicability;
7 use rustc_hir::def_id::DefId;
8 use rustc_hir::def_id::LocalDefId;
9 use rustc_hir::def_id::LOCAL_CRATE;
10 use rustc_middle::ty::query::Providers;
11 use rustc_middle::ty::TyCtxt;
12 use rustc_session::parse::feature_err;
13 use rustc_session::Session;
14 use rustc_span::symbol::sym;
15 use rustc_span::symbol::Symbol;
18 /// Features that control behaviour of rustc, rather than the codegen.
19 pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
21 // When adding features to the below lists
22 // check whether they're named already elsewhere in rust
23 // e.g. in stdarch and whether the given name matches LLVM's
24 // if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted
26 const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
27 // tidy-alphabetical-start
28 ("aclass", Some(sym::arm_target_feature)),
29 ("aes", Some(sym::arm_target_feature)),
30 ("crc", Some(sym::arm_target_feature)),
31 ("crypto", Some(sym::arm_target_feature)),
32 ("d32", Some(sym::arm_target_feature)),
33 ("dotprod", Some(sym::arm_target_feature)),
34 ("dsp", Some(sym::arm_target_feature)),
35 ("fp-armv8", Some(sym::arm_target_feature)),
36 ("i8mm", Some(sym::arm_target_feature)),
37 ("mclass", Some(sym::arm_target_feature)),
38 ("neon", Some(sym::arm_target_feature)),
39 ("rclass", Some(sym::arm_target_feature)),
40 ("sha2", Some(sym::arm_target_feature)),
41 // This is needed for inline assembly, but shouldn't be stabilized as-is
42 // since it should be enabled per-function using #[instruction_set], not
44 ("thumb-mode", Some(sym::arm_target_feature)),
45 ("thumb2", Some(sym::arm_target_feature)),
46 ("v5te", Some(sym::arm_target_feature)),
47 ("v6", Some(sym::arm_target_feature)),
48 ("v6k", Some(sym::arm_target_feature)),
49 ("v6t2", Some(sym::arm_target_feature)),
50 ("v7", Some(sym::arm_target_feature)),
51 ("v8", Some(sym::arm_target_feature)),
52 ("vfp2", Some(sym::arm_target_feature)),
53 ("vfp3", Some(sym::arm_target_feature)),
54 ("vfp4", Some(sym::arm_target_feature)),
55 // tidy-alphabetical-end
58 const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
59 // tidy-alphabetical-start
100 // FEAT_AdvSimd & FEAT_FP
102 // FEAT_PAUTH (address authentication)
104 // FEAT_PAUTH (generic authentication)
122 // FEAT_SHA1 & FEAT_SHA256
124 // FEAT_SHA512 & FEAT_SHA3
126 // FEAT_SM3 & FEAT_SM4
139 ("sve2-bitperm", None),
146 ("v8.1a", Some(sym::aarch64_ver_target_feature)),
147 ("v8.2a", Some(sym::aarch64_ver_target_feature)),
148 ("v8.3a", Some(sym::aarch64_ver_target_feature)),
149 ("v8.4a", Some(sym::aarch64_ver_target_feature)),
150 ("v8.5a", Some(sym::aarch64_ver_target_feature)),
151 ("v8.6a", Some(sym::aarch64_ver_target_feature)),
152 ("v8.7a", Some(sym::aarch64_ver_target_feature)),
155 // tidy-alphabetical-end
158 const AARCH64_TIED_FEATURES: &[&[&str]] = &[
159 &["paca", "pacg"], // Together these represent `pauth` in LLVM
162 const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
163 // tidy-alphabetical-start
168 ("avx512bf16", Some(sym::avx512_target_feature)),
169 ("avx512bitalg", Some(sym::avx512_target_feature)),
170 ("avx512bw", Some(sym::avx512_target_feature)),
171 ("avx512cd", Some(sym::avx512_target_feature)),
172 ("avx512dq", Some(sym::avx512_target_feature)),
173 ("avx512er", Some(sym::avx512_target_feature)),
174 ("avx512f", Some(sym::avx512_target_feature)),
175 ("avx512gfni", Some(sym::avx512_target_feature)),
176 ("avx512ifma", Some(sym::avx512_target_feature)),
177 ("avx512pf", Some(sym::avx512_target_feature)),
178 ("avx512vaes", Some(sym::avx512_target_feature)),
179 ("avx512vbmi", Some(sym::avx512_target_feature)),
180 ("avx512vbmi2", Some(sym::avx512_target_feature)),
181 ("avx512vl", Some(sym::avx512_target_feature)),
182 ("avx512vnni", Some(sym::avx512_target_feature)),
183 ("avx512vp2intersect", Some(sym::avx512_target_feature)),
184 ("avx512vpclmulqdq", Some(sym::avx512_target_feature)),
185 ("avx512vpopcntdq", Some(sym::avx512_target_feature)),
188 ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
189 ("ermsb", Some(sym::ermsb_target_feature)),
190 ("f16c", Some(sym::f16c_target_feature)),
193 ("gfni", Some(sym::avx512_target_feature)),
195 ("movbe", Some(sym::movbe_target_feature)),
200 ("rtm", Some(sym::rtm_target_feature)),
207 ("sse4a", Some(sym::sse4a_target_feature)),
209 ("tbm", Some(sym::tbm_target_feature)),
210 ("vaes", Some(sym::avx512_target_feature)),
211 ("vpclmulqdq", Some(sym::avx512_target_feature)),
216 // tidy-alphabetical-end
219 const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
220 // tidy-alphabetical-start
221 ("hvx", Some(sym::hexagon_target_feature)),
222 ("hvx-length128b", Some(sym::hexagon_target_feature)),
223 // tidy-alphabetical-end
226 const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
227 // tidy-alphabetical-start
228 ("altivec", Some(sym::powerpc_target_feature)),
229 ("power10-vector", Some(sym::powerpc_target_feature)),
230 ("power8-altivec", Some(sym::powerpc_target_feature)),
231 ("power8-vector", Some(sym::powerpc_target_feature)),
232 ("power9-altivec", Some(sym::powerpc_target_feature)),
233 ("power9-vector", Some(sym::powerpc_target_feature)),
234 ("vsx", Some(sym::powerpc_target_feature)),
235 // tidy-alphabetical-end
238 const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
239 // tidy-alphabetical-start
240 ("fp64", Some(sym::mips_target_feature)),
241 ("msa", Some(sym::mips_target_feature)),
242 ("virt", Some(sym::mips_target_feature)),
243 // tidy-alphabetical-end
246 const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
247 // tidy-alphabetical-start
248 ("a", Some(sym::riscv_target_feature)),
249 ("c", Some(sym::riscv_target_feature)),
250 ("d", Some(sym::riscv_target_feature)),
251 ("e", Some(sym::riscv_target_feature)),
252 ("f", Some(sym::riscv_target_feature)),
253 ("m", Some(sym::riscv_target_feature)),
254 ("v", Some(sym::riscv_target_feature)),
255 ("zba", Some(sym::riscv_target_feature)),
256 ("zbb", Some(sym::riscv_target_feature)),
257 ("zbc", Some(sym::riscv_target_feature)),
258 ("zbkb", Some(sym::riscv_target_feature)),
259 ("zbkc", Some(sym::riscv_target_feature)),
260 ("zbkx", Some(sym::riscv_target_feature)),
261 ("zbs", Some(sym::riscv_target_feature)),
262 ("zdinx", Some(sym::riscv_target_feature)),
263 ("zfh", Some(sym::riscv_target_feature)),
264 ("zfhmin", Some(sym::riscv_target_feature)),
265 ("zfinx", Some(sym::riscv_target_feature)),
266 ("zhinx", Some(sym::riscv_target_feature)),
267 ("zhinxmin", Some(sym::riscv_target_feature)),
268 ("zk", Some(sym::riscv_target_feature)),
269 ("zkn", Some(sym::riscv_target_feature)),
270 ("zknd", Some(sym::riscv_target_feature)),
271 ("zkne", Some(sym::riscv_target_feature)),
272 ("zknh", Some(sym::riscv_target_feature)),
273 ("zkr", Some(sym::riscv_target_feature)),
274 ("zks", Some(sym::riscv_target_feature)),
275 ("zksed", Some(sym::riscv_target_feature)),
276 ("zksh", Some(sym::riscv_target_feature)),
277 ("zkt", Some(sym::riscv_target_feature)),
278 // tidy-alphabetical-end
281 const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
282 // tidy-alphabetical-start
283 ("atomics", Some(sym::wasm_target_feature)),
284 ("bulk-memory", Some(sym::wasm_target_feature)),
285 ("multivalue", Some(sym::wasm_target_feature)),
286 ("mutable-globals", Some(sym::wasm_target_feature)),
287 ("nontrapping-fptoint", Some(sym::wasm_target_feature)),
288 ("reference-types", Some(sym::wasm_target_feature)),
289 ("sign-ext", Some(sym::wasm_target_feature)),
291 // tidy-alphabetical-end
294 const BPF_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[("alu32", Some(sym::bpf_target_feature))];
296 /// When rustdoc is running, provide a list of all known features so that all their respective
297 /// primitives may be documented.
299 /// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
300 pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
302 .chain(ARM_ALLOWED_FEATURES.iter())
303 .chain(AARCH64_ALLOWED_FEATURES.iter())
304 .chain(X86_ALLOWED_FEATURES.iter())
305 .chain(HEXAGON_ALLOWED_FEATURES.iter())
306 .chain(POWERPC_ALLOWED_FEATURES.iter())
307 .chain(MIPS_ALLOWED_FEATURES.iter())
308 .chain(RISCV_ALLOWED_FEATURES.iter())
309 .chain(WASM_ALLOWED_FEATURES.iter())
310 .chain(BPF_ALLOWED_FEATURES.iter())
314 pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
315 match &*sess.target.arch {
316 "arm" => ARM_ALLOWED_FEATURES,
317 "aarch64" => AARCH64_ALLOWED_FEATURES,
318 "x86" | "x86_64" => X86_ALLOWED_FEATURES,
319 "hexagon" => HEXAGON_ALLOWED_FEATURES,
320 "mips" | "mips64" => MIPS_ALLOWED_FEATURES,
321 "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
322 "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
323 "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
324 "bpf" => BPF_ALLOWED_FEATURES,
329 pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] {
330 match &*sess.target.arch {
331 "aarch64" => AARCH64_TIED_FEATURES,
336 pub fn from_target_feature(
338 attr: &ast::Attribute,
339 supported_target_features: &FxHashMap<String, Option<Symbol>>,
340 target_features: &mut Vec<Symbol>,
342 let Some(list) = attr.meta_item_list() else { return };
343 let bad_item = |span| {
344 let msg = "malformed `target_feature` attribute input";
345 let code = "enable = \"..\"";
347 .struct_span_err(span, msg)
348 .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
351 let rust_features = tcx.features();
353 // Only `enable = ...` is accepted in the meta-item list.
354 if !item.has_name(sym::enable) {
355 bad_item(item.span());
359 // Must be of the form `enable = "..."` (a string).
360 let Some(value) = item.value_str() else {
361 bad_item(item.span());
365 // We allow comma separation to enable multiple features.
366 target_features.extend(value.as_str().split(',').filter_map(|feature| {
367 let Some(feature_gate) = supported_target_features.get(feature) else {
369 format!("the feature named `{}` is not valid for this target", feature);
370 let mut err = tcx.sess.struct_span_err(item.span(), &msg);
373 format!("`{}` is not valid for this target", feature),
375 if let Some(stripped) = feature.strip_prefix('+') {
376 let valid = supported_target_features.contains_key(stripped);
378 err.help("consider removing the leading `+` in the feature name");
385 // Only allow features whose feature gates have been enabled.
386 let allowed = match feature_gate.as_ref().copied() {
387 Some(sym::arm_target_feature) => rust_features.arm_target_feature,
388 Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature,
389 Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature,
390 Some(sym::mips_target_feature) => rust_features.mips_target_feature,
391 Some(sym::riscv_target_feature) => rust_features.riscv_target_feature,
392 Some(sym::avx512_target_feature) => rust_features.avx512_target_feature,
393 Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature,
394 Some(sym::tbm_target_feature) => rust_features.tbm_target_feature,
395 Some(sym::wasm_target_feature) => rust_features.wasm_target_feature,
396 Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
397 Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
398 Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
399 Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
400 Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
401 Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
402 Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
403 Some(name) => bug!("unknown target feature gate {}", name),
408 &tcx.sess.parse_sess,
409 feature_gate.unwrap(),
411 &format!("the target feature `{}` is currently unstable", feature),
415 Some(Symbol::intern(feature))
420 /// Computes the set of target features used in a function for the purposes of
422 fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<Symbol> {
423 let mut target_features = tcx.sess.unstable_target_features.clone();
424 if tcx.def_kind(did).has_codegen_attrs() {
425 let attrs = tcx.codegen_fn_attrs(did);
426 target_features.extend(&attrs.target_features);
427 match attrs.instruction_set {
429 Some(InstructionSetAttr::ArmA32) => {
430 target_features.remove(&sym::thumb_mode);
432 Some(InstructionSetAttr::ArmT32) => {
433 target_features.insert(sym::thumb_mode);
438 tcx.arena.alloc(target_features)
441 /// Checks the function annotated with `#[target_feature]` is not a safe
442 /// trait method implementation, reporting an error if it is.
443 pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) {
444 let hir_id = tcx.hir().local_def_id_to_hir_id(id);
445 let node = tcx.hir().get(hir_id);
446 if let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
447 let parent_id = tcx.hir().get_parent_item(hir_id);
448 let parent_item = tcx.hir().expect_item(parent_id.def_id);
449 if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
453 "`#[target_feature(..)]` cannot be applied to safe trait method",
455 .span_label(attr_span, "cannot be applied to safe trait method")
456 .span_label(tcx.def_span(id), "not an `unsafe` function")
462 pub(crate) fn provide(providers: &mut Providers) {
463 *providers = Providers {
464 supported_target_features: |tcx, cnum| {
465 assert_eq!(cnum, LOCAL_CRATE);
466 if tcx.sess.opts.actually_rustdoc {
467 // rustdoc needs to be able to document functions that use all the features, so
468 // whitelist them all
469 all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
471 supported_target_features(tcx.sess)
473 .map(|&(a, b)| (a.to_string(), b))