Skip to content

[EXPERIMENT] require simd types be used in target_feature-annotated functions #143682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub struct ReprOptions {
pub align: Option<Align>,
pub pack: Option<Align>,
pub flags: ReprFlags,
pub target_feature: Option<u16>,
/// The seed to be used for randomizing a type's layout
///
/// Note: This could technically be a `u128` which would
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_data_structures/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub enum ReprAttr {
ReprRust,
ReprC,
ReprPacked(Align),
ReprSimd,
ReprSimd(Option<u16>),
ReprTransparent,
ReprAlign(Align),
}
Expand Down
19 changes: 17 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,28 @@ fn parse_repr<S: Stage>(

(Some(sym::Rust), ArgParser::NoArgs) => Some(ReprRust),
(Some(sym::C), ArgParser::NoArgs) => Some(ReprC),
(Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd),
(Some(sym::simd), ArgParser::NoArgs) => Some(ReprSimd(None)),
(Some(sym::transparent), ArgParser::NoArgs) => Some(ReprTransparent),
(Some(name @ int_pat!()), ArgParser::NoArgs) => {
// int_pat!() should make sure it always parses
Some(ReprInt(int_type_of_word(name).unwrap()))
}

(Some(sym::simd), ArgParser::List(x)) => {
let Some(item) = x.single() else {
todo!("Handle incorrect syntax");
};
let Some(lit) = item.lit() else {
todo!("Handle invalid lit");
};
match lit.kind {
LitKind::Int(v, _) => {
Some(ReprSimd(Some(v.0 as u16)))
}
_ => todo!("Handle invalid lit kind"),
}
}

(
Some(
name @ sym::Rust
Expand All @@ -167,7 +182,7 @@ fn parse_repr<S: Stage>(
Some(
name @ sym::Rust
| name @ sym::C
| name @ sym::simd
// | name @ sym::simd
| name @ sym::transparent
| name @ int_pat!(),
),
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in

codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}

codegen_ssa_type_depends_target_feature = The `{$ty}` type depends on the target feature `{$target_feature}` being enabled

codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}`
.note = {$error}
.command_note = {$command_formatted}
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1310,3 +1310,13 @@ pub(crate) struct FeatureNotValid<'a> {
#[help]
pub plus_hint: bool,
}

#[derive(Diagnostic)]
#[diag(codegen_ssa_type_depends_target_feature)]
pub(crate) struct TypeDependsOnTargetFeature<'tcx> {
#[primary_span]
pub span: Span,

pub target_feature: String,
pub ty: Ty<'tcx>,
}
28 changes: 28 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::{bug, span_bug};
use rustc_span::Symbol;
use tracing::debug;

use super::FunctionCx;
use crate::errors::TypeDependsOnTargetFeature;
use crate::traits::*;

pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
Expand Down Expand Up @@ -157,6 +159,30 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx>
self.visit_local(place_ref.local, context, location);
}
}

fn check_type_abi_concerns(&self, local: mir::Local) {
static IGNORED_CRATES: [&str; 3] = ["memchr", "core", "hashbrown"];

let ty = self.fx.mir.local_decls[local].ty;
let ty = self.fx.monomorphize(ty);
let ty = ty.peel_refs();

if let Some(abi_feature) = ty.abi_target_feature() {
let tcx = self.fx.cx.tcx();
let krate = tcx.crate_name(self.fx.instance.def_id().krate);
if !IGNORED_CRATES.contains(&krate.as_str()) {
if !self.fx.target_features.contains(&Symbol::intern(&abi_feature)) {
let span = self.fx.mir.local_decls[local].source_info.span;

tcx.sess.dcx().emit_err(TypeDependsOnTargetFeature {
span,
ty,
target_feature: abi_feature,
});
}
}
}
}
}

impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer<'a, 'b, 'tcx, Bx> {
Expand Down Expand Up @@ -189,6 +215,8 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer
}

fn visit_local(&mut self, local: mir::Local, context: PlaceContext, location: Location) {
self.check_type_abi_concerns(local);

match context {
PlaceContext::MutatingUse(MutatingUseContext::Call) => {
let call = location.block;
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use std::iter;

use rustc_data_structures::fx::FxIndexSet;
use rustc_index::IndexVec;
use rustc_index::bit_set::DenseBitSet;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::{Body, Local, UnwindTerminateReason, traversal};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::Symbol;
use rustc_target::callconv::{FnAbi, PassMode};
use tracing::{debug, instrument};

Expand Down Expand Up @@ -120,6 +122,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {

/// Caller location propagated if this function has `#[track_caller]`.
caller_location: Option<OperandRef<'tcx, Bx::Value>>,

target_features: FxIndexSet<Symbol>,
}

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Expand Down Expand Up @@ -176,6 +180,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

let mut mir = tcx.instance_mir(instance.def);

let mut target_features = tcx.sess.unstable_target_features.clone();
if tcx.def_kind(instance.def_id()).has_codegen_attrs() {
let attrs = tcx.codegen_fn_attrs(instance.def_id());
target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
}
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
debug!("fn_abi: {:?}", fn_abi);

Expand Down Expand Up @@ -228,6 +237,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
debug_context,
per_local_var_debug_info: None,
caller_location: None,
target_features,
};

// It may seem like we should iterate over `required_consts` to ensure they all successfully
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,7 @@ impl<'tcx> TyCtxt<'tcx> {
let mut size = None;
let mut max_align: Option<Align> = None;
let mut min_pack: Option<Align> = None;
let mut target_feature: Option<u16> = None;

// Generate a deterministically-derived seed from the item's path hash
// to allow for cross-crate compilation to actually work
Expand Down Expand Up @@ -1541,7 +1542,10 @@ impl<'tcx> TyCtxt<'tcx> {
ReprFlags::empty()
}
attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
attr::ReprSimd => ReprFlags::IS_SIMD,
attr::ReprSimd(feature) => {
target_feature = feature;
ReprFlags::IS_SIMD
}
attr::ReprInt(i) => {
size = Some(match i {
attr::IntType::SignedInt(x) => match x {
Expand Down Expand Up @@ -1586,7 +1590,14 @@ impl<'tcx> TyCtxt<'tcx> {
flags.insert(ReprFlags::IS_LINEAR);
}

ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
ReprOptions {
int: size,
align: max_align,
pack: min_pack,
flags,
field_shuffle_seed,
target_feature,
}
}

/// Look up the name of a definition across crates. This does not look at HIR.
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,24 @@ impl<'tcx> Ty<'tcx> {
}
}

pub fn abi_target_feature(self) -> Option<String> {
self.ty_adt_def()
.map(|adt| {
adt.repr().target_feature.map(|id| {
String::from(match id {
0 => "neon",
1 => "sse",
2 => "sse2",
3 => "avx",
4 => "avx512f",
5 => "amx-avx512",
_ => panic!("Unknown ID: {id}"),
})
})
})
.flatten()
}

pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
let Adt(def, args) = self.kind() else {
bug!("`simd_size_and_type` called on invalid type")
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2018,7 +2018,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
continue;
}
}
ReprAttr::ReprSimd => {
ReprAttr::ReprSimd(_) => {
is_simd = true;
if target != Target::Struct {
self.dcx().emit_err(errors::AttrApplication::Struct {
Expand Down
4 changes: 2 additions & 2 deletions library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ types! {
#![stable(feature = "neon_intrinsics", since = "1.59.0")]

/// ARM-specific 64-bit wide vector of one packed `f64`.
pub struct float64x1_t(1 x f64); // FIXME: check this!
pub struct float64x1_t(1 x f64) feature=0; // FIXME: check this!
/// ARM-specific 128-bit wide vector of two packed `f64`.
pub struct float64x2_t(2 x f64);
pub struct float64x2_t(2 x f64) feature=0;
}

/// ARM-specific type containing two `float64x1_t` vectors.
Expand Down
52 changes: 26 additions & 26 deletions library/stdarch/crates/core_arch/src/arm_shared/neon/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,63 +53,63 @@ types! {
#![cfg_attr(target_arch = "arm", unstable(feature = "stdarch_arm_neon_intrinsics", issue = "111800"))]

/// Arm-specific 64-bit wide vector of eight packed `i8`.
pub struct int8x8_t(8 x pub(crate) i8);
pub struct int8x8_t(8 x pub(crate) i8) feature=0;
/// Arm-specific 64-bit wide vector of eight packed `u8`.
pub struct uint8x8_t(8 x pub(crate) u8);
pub struct uint8x8_t(8 x pub(crate) u8) feature=0;
/// Arm-specific 64-bit wide polynomial vector of eight packed `p8`.
pub struct poly8x8_t(8 x pub(crate) p8);
pub struct poly8x8_t(8 x pub(crate) p8) feature=0;
/// Arm-specific 64-bit wide vector of four packed `i16`.
pub struct int16x4_t(4 x pub(crate) i16);
pub struct int16x4_t(4 x pub(crate) i16) feature=0;
/// Arm-specific 64-bit wide vector of four packed `u16`.
pub struct uint16x4_t(4 x pub(crate) u16);
pub struct uint16x4_t(4 x pub(crate) u16) feature=0;
/// Arm-specific 64-bit wide vector of four packed `p16`.
pub struct poly16x4_t(4 x pub(crate) p16);
pub struct poly16x4_t(4 x pub(crate) p16) feature=0;
/// Arm-specific 64-bit wide vector of two packed `i32`.
pub struct int32x2_t(2 x pub(crate) i32);
pub struct int32x2_t(2 x pub(crate) i32) feature=0;
/// Arm-specific 64-bit wide vector of two packed `u32`.
pub struct uint32x2_t(2 x pub(crate) u32);
pub struct uint32x2_t(2 x pub(crate) u32) feature=0;
/// Arm-specific 64-bit wide vector of two packed `f32`.
pub struct float32x2_t(2 x pub(crate) f32);
pub struct float32x2_t(2 x pub(crate) f32) feature=0;
/// Arm-specific 64-bit wide vector of one packed `i64`.
pub struct int64x1_t(1 x pub(crate) i64);
pub struct int64x1_t(1 x pub(crate) i64) feature=0;
/// Arm-specific 64-bit wide vector of one packed `u64`.
pub struct uint64x1_t(1 x pub(crate) u64);
pub struct uint64x1_t(1 x pub(crate) u64) feature=0;
/// Arm-specific 64-bit wide vector of one packed `p64`.
pub struct poly64x1_t(1 x pub(crate) p64);
pub struct poly64x1_t(1 x pub(crate) p64) feature=0;

/// Arm-specific 128-bit wide vector of sixteen packed `i8`.
pub struct int8x16_t(16 x pub(crate) i8);
pub struct int8x16_t(16 x pub(crate) i8) feature=0;
/// Arm-specific 128-bit wide vector of sixteen packed `u8`.
pub struct uint8x16_t(16 x pub(crate) u8);
pub struct uint8x16_t(16 x pub(crate) u8) feature=0;
/// Arm-specific 128-bit wide vector of sixteen packed `p8`.
pub struct poly8x16_t(16 x pub(crate) p8);
pub struct poly8x16_t(16 x pub(crate) p8) feature=0;
/// Arm-specific 128-bit wide vector of eight packed `i16`.
pub struct int16x8_t(8 x pub(crate) i16);
pub struct int16x8_t(8 x pub(crate) i16) feature=0;
/// Arm-specific 128-bit wide vector of eight packed `u16`.
pub struct uint16x8_t(8 x pub(crate) u16);
pub struct uint16x8_t(8 x pub(crate) u16) feature=0;
/// Arm-specific 128-bit wide vector of eight packed `p16`.
pub struct poly16x8_t(8 x pub(crate) p16);
pub struct poly16x8_t(8 x pub(crate) p16) feature=0;
/// Arm-specific 128-bit wide vector of four packed `i32`.
pub struct int32x4_t(4 x pub(crate) i32);
pub struct int32x4_t(4 x pub(crate) i32) feature=0;
/// Arm-specific 128-bit wide vector of four packed `u32`.
pub struct uint32x4_t(4 x pub(crate) u32);
pub struct uint32x4_t(4 x pub(crate) u32) feature=0;
/// Arm-specific 128-bit wide vector of four packed `f32`.
pub struct float32x4_t(4 x pub(crate) f32);
pub struct float32x4_t(4 x pub(crate) f32) feature=0;
/// Arm-specific 128-bit wide vector of two packed `i64`.
pub struct int64x2_t(2 x pub(crate) i64);
pub struct int64x2_t(2 x pub(crate) i64) feature=0;
/// Arm-specific 128-bit wide vector of two packed `u64`.
pub struct uint64x2_t(2 x pub(crate) u64);
pub struct uint64x2_t(2 x pub(crate) u64) feature=0;
/// Arm-specific 128-bit wide vector of two packed `p64`.
pub struct poly64x2_t(2 x pub(crate) p64);
pub struct poly64x2_t(2 x pub(crate) p64) feature=0;
}

types! {
#![unstable(feature = "stdarch_neon_f16", issue = "136306")]

/// Arm-specific 64-bit wide vector of four packed `f16`.
pub struct float16x4_t(4 x pub(crate) f16);
pub struct float16x4_t(4 x pub(crate) f16) feature=0;
/// Arm-specific 128-bit wide vector of eight packed `f16`.
pub struct float16x8_t(8 x pub(crate) f16);
pub struct float16x8_t(8 x pub(crate) f16) feature=0;
}

/// Arm-specific type containing two `int8x8_t` vectors.
Expand Down
8 changes: 4 additions & 4 deletions library/stdarch/crates/core_arch/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ macro_rules! types {
$(
$(#[$doc:meta])*
$(stability: [$stability_already: meta])*
pub struct $name:ident($len:literal x $v:vis $elem_type:ty);
pub struct $name:ident($len:literal x $v:vis $elem_type:ty) $(feature=$target_feature:literal)*;
)*
) => (types! {
$(
Expand All @@ -70,22 +70,22 @@ macro_rules! types {
$(#[$doc])*
$(stability: [$stability_already])*
stability: [$stability_first]
pub struct $name($len x $v $elem_type);
pub struct $name($len x $v $elem_type) $(feature=$target_feature)*;
)*
});

(
$(
$(#[$doc:meta])*
$(stability: [$stability: meta])+
pub struct $name:ident($len:literal x $v:vis $elem_type:ty);
pub struct $name:ident($len:literal x $v:vis $elem_type:ty) $(feature=$target_feature:literal)*;
)*
) => ($(
$(#[$doc])*
$(#[$stability])+
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
#[repr(simd)]
#[repr(simd$(($target_feature))*)]
#[allow(clippy::missing_inline_in_public_items)]
pub struct $name($v [$elem_type; $len]);

Expand Down
Loading
Loading