Skip to content

Commit 4c14a6d

Browse files
committed
Prototype of scalable vectors
The representation of the element type has been changed to be a slice rather than a zero length array. Two feature gates are now required in core_arch unsized fn params and unsized locals. This still leaves unsized return types being an issue. For this we are currently bypassing some of the `Sized` trait checking to pass when the type is scalable simd. This still leaves the copy issue. For that we have marked scalable simd types as trivally pure clone copy. We have still had to remove some trait checks for the copy trait with this though as they are still performed in certain situations. The implementation of `transmute` is also an issue for us. For this a new SIMD intrinsic has been created simd_reinterpret which performs a transmute on SIMD vectors. A few intrinsics need to be able to produce an LLVM `undef` this intrinsic will also produce that when given a zero sized input.
1 parent 5a9e0e8 commit 4c14a6d

File tree

48 files changed

+292
-44
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+292
-44
lines changed

compiler/rustc_abi/src/layout.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ pub trait LayoutCalculator {
231231
hide_niches(a);
232232
hide_niches(b);
233233
}
234-
Abi::Vector { element, count: _ } => hide_niches(element),
234+
Abi::Vector { element, .. } => hide_niches(element),
235+
Abi::ScalableVector { element, .. } => hide_niches(element),
235236
Abi::Aggregate { sized: _ } => {}
236237
}
237238
st.largest_niche = None;

compiler/rustc_abi/src/lib.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ bitflags! {
4141
// If true, the type's layout can be randomized using
4242
// the seed stored in `ReprOptions.layout_seed`
4343
const RANDOMIZE_LAYOUT = 1 << 4;
44+
const IS_SCALABLE = 1 << 5;
4445
// Any of these flags being set prevent field reordering optimisation.
4546
const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits
4647
| ReprFlags::IS_SIMD.bits
48+
| ReprFlags::IS_SCALABLE.bits
4749
| ReprFlags::IS_LINEAR.bits;
4850
}
4951
}
@@ -76,6 +78,7 @@ pub struct ReprOptions {
7678
pub align: Option<Align>,
7779
pub pack: Option<Align>,
7880
pub flags: ReprFlags,
81+
pub scalable: Option<u32>,
7982
/// The seed to be used for randomizing a type's layout
8083
///
8184
/// Note: This could technically be a `u128` which would
@@ -92,6 +95,11 @@ impl ReprOptions {
9295
self.flags.contains(ReprFlags::IS_SIMD)
9396
}
9497

98+
#[inline]
99+
pub fn scalable(&self) -> bool {
100+
self.flags.contains(ReprFlags::IS_SCALABLE)
101+
}
102+
95103
#[inline]
96104
pub fn c(&self) -> bool {
97105
self.flags.contains(ReprFlags::IS_C)
@@ -1243,6 +1251,10 @@ pub enum Abi {
12431251
Uninhabited,
12441252
Scalar(Scalar),
12451253
ScalarPair(Scalar, Scalar),
1254+
ScalableVector {
1255+
element: Scalar,
1256+
elt: u64,
1257+
},
12461258
Vector {
12471259
element: Scalar,
12481260
count: u64,
@@ -1260,6 +1272,7 @@ impl Abi {
12601272
match *self {
12611273
Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
12621274
Abi::Aggregate { sized } => !sized,
1275+
Abi::ScalableVector { .. } => true,
12631276
}
12641277
}
12651278

@@ -1306,7 +1319,7 @@ impl Abi {
13061319
Abi::Vector { element, count } => {
13071320
cx.data_layout().vector_align(element.size(cx) * count)
13081321
}
1309-
Abi::Uninhabited | Abi::Aggregate { .. } => return None,
1322+
Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None,
13101323
})
13111324
}
13121325

@@ -1327,7 +1340,7 @@ impl Abi {
13271340
// to make the size a multiple of align (e.g. for vectors of size 3).
13281341
(element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
13291342
}
1330-
Abi::Uninhabited | Abi::Aggregate { .. } => return None,
1343+
Abi::Uninhabited | Abi::Aggregate { .. } | Abi::ScalableVector { .. } => return None,
13311344
})
13321345
}
13331346

@@ -1337,6 +1350,9 @@ impl Abi {
13371350
Abi::Scalar(s) => Abi::Scalar(s.to_union()),
13381351
Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()),
13391352
Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count },
1353+
Abi::ScalableVector { element, elt } => {
1354+
Abi::ScalableVector { element: element.to_union(), elt }
1355+
}
13401356
Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
13411357
}
13421358
}
@@ -1620,6 +1636,11 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
16201636
self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1
16211637
}
16221638

1639+
/// Returns true if the size of the type is only known at runtime.
1640+
pub fn is_runtime_sized(&self) -> bool {
1641+
matches!(self.abi, Abi::ScalableVector { .. })
1642+
}
1643+
16231644
/// Returns `true` if the type is a ZST and not unsized.
16241645
///
16251646
/// Note that this does *not* imply that the type is irrelevant for layout! It can still have
@@ -1629,6 +1650,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutS<FieldIdx, VariantIdx> {
16291650
Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
16301651
Abi::Uninhabited => self.size.bytes() == 0,
16311652
Abi::Aggregate { sized } => sized && self.size.bytes() == 0,
1653+
Abi::ScalableVector { .. } => false,
16321654
}
16331655
}
16341656

compiler/rustc_attr/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ attr_rustc_allowed_unstable_pairing =
8888
attr_rustc_promotable_pairing =
8989
`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
9090
91+
attr_scalable_missing_n =
92+
invalid `scalable(num)` attribute: `scalable` needs an argument
93+
.suggestion = supply an argument here
9194
attr_soft_no_args =
9295
`soft` should not have any arguments
9396

compiler/rustc_attr/src/builtin.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ pub enum ReprAttr {
909909
ReprSimd,
910910
ReprTransparent,
911911
ReprAlign(u32),
912+
ReprScalable(u32),
912913
}
913914

914915
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
@@ -964,6 +965,13 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
964965
recognised = true;
965966
None
966967
}
968+
sym::scalable => {
969+
sess.emit_err(session_diagnostics::ScalableAttrMissingN {
970+
span: item.span(),
971+
});
972+
recognised = true;
973+
None
974+
}
967975
name => int_type_of_word(name).map(ReprInt),
968976
};
969977

@@ -985,6 +993,12 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
985993
Ok(literal) => acc.push(ReprPacked(literal)),
986994
Err(message) => literal_error = Some(message),
987995
};
996+
} else if name == sym::scalable {
997+
recognised = true;
998+
match parse_scalable(&value.kind) {
999+
Ok(literal) => acc.push(ReprScalable(literal)),
1000+
Err(message) => literal_error = Some(message),
1001+
};
9881002
} else if matches!(name, sym::C | sym::simd | sym::transparent)
9891003
|| int_type_of_word(name).is_some()
9901004
{
@@ -1004,7 +1018,10 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
10041018
} else if let Some(meta_item) = item.meta_item() {
10051019
match &meta_item.kind {
10061020
MetaItemKind::NameValue(value) => {
1007-
if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
1021+
if meta_item.has_name(sym::align)
1022+
|| meta_item.has_name(sym::packed)
1023+
|| meta_item.has_name(sym::scalable)
1024+
{
10081025
let name = meta_item.name_or_empty().to_ident_string();
10091026
recognised = true;
10101027
sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
@@ -1199,3 +1216,11 @@ pub fn parse_confusables(attr: &Attribute) -> Option<Vec<Symbol>> {
11991216

12001217
return Some(candidates);
12011218
}
1219+
1220+
pub fn parse_scalable(node: &ast::LitKind) -> Result<u32, &'static str> {
1221+
if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
1222+
(*literal).try_into().map_err(|_| "integer too large")
1223+
} else {
1224+
Err("not an unsuffixed integer")
1225+
}
1226+
}

compiler/rustc_attr/src/session_diagnostics.rs

+8
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,11 @@ pub(crate) struct UnknownVersionLiteral {
390390
#[primary_span]
391391
pub span: Span,
392392
}
393+
394+
#[derive(Diagnostic)]
395+
#[diag(attr_scalable_missing_n, code = "E0796")]
396+
pub(crate) struct ScalableAttrMissingN {
397+
#[primary_span]
398+
#[suggestion(applicability = "has-placeholders", code = "scalable(...)")]
399+
pub span: Span,
400+
}

compiler/rustc_borrowck/src/type_check/mod.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
515515
place_ty = self.sanitize_projection(place_ty, elem, place, location, context);
516516
}
517517

518-
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
518+
// The Copy trait isn't implemented for scalable SIMD types.
519+
// These types live somewhere between `Sized` and `Unsize`.
520+
// The bounds on `Copy` disallow the trait from being
521+
// implemented for them. As a result of this no bounds from
522+
// `Copy` apply for the type, therefore, skipping this check
523+
// should be perfectly legal.
524+
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context
525+
&& !place_ty.ty.is_scalable_simd()
526+
{
519527
let tcx = self.tcx();
520528
let trait_ref =
521529
ty::TraitRef::from_lang_item(tcx, LangItem::Copy, self.last_span, [place_ty.ty]);
@@ -1763,11 +1771,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
17631771
// expressions evaluate through `as_temp` or `into` a return
17641772
// slot or local, so to find all unsized rvalues it is enough
17651773
// to check all temps, return slots and locals.
1766-
if self.reported_errors.replace((ty, span)).is_none() {
1767-
// While this is located in `nll::typeck` this error is not
1768-
// an NLL error, it's a required check to prevent creation
1769-
// of unsized rvalues in a call expression.
1770-
self.tcx().sess.emit_err(MoveUnsized { ty, span });
1774+
if !ty.is_scalable_simd() {
1775+
if self.reported_errors.replace((ty, span)).is_none() {
1776+
// While this is located in `nll::typeck` this error is not
1777+
// an NLL error, it's a required check to prevent creation
1778+
// of unsized rvalues in a call expression.
1779+
self.tcx().sess.emit_err(MoveUnsized { ty, span });
1780+
}
17711781
}
17721782
}
17731783
}

compiler/rustc_codegen_gcc/src/abi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ impl GccType for Reg {
9494
}
9595
},
9696
RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()),
97+
RegKind::ScalableVector => unimplemented!(),
9798
}
9899
}
99100
}

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
274274
let layout = self.layout_of(tp_ty).layout;
275275
let _use_integer_compare = match layout.abi() {
276276
Scalar(_) | ScalarPair(_, _) => true,
277-
Uninhabited | Vector { .. } => false,
277+
Uninhabited | Vector { .. } | ScalableVector { .. } => false,
278278
Aggregate { .. } => {
279279
// For rusty ABIs, small aggregates are actually passed
280280
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),

compiler/rustc_codegen_gcc/src/type_of.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
8080
false,
8181
);
8282
}
83+
Abi::ScalableVector { .. } => todo!(),
8384
Abi::Uninhabited | Abi::Aggregate { .. } => {}
8485
}
8586

@@ -158,15 +159,15 @@ pub trait LayoutGccExt<'tcx> {
158159
impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
159160
fn is_gcc_immediate(&self) -> bool {
160161
match self.abi {
161-
Abi::Scalar(_) | Abi::Vector { .. } => true,
162+
Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } => true,
162163
Abi::ScalarPair(..) | Abi::Uninhabited | Abi::Aggregate { .. } => false,
163164
}
164165
}
165166

166167
fn is_gcc_scalar_pair(&self) -> bool {
167168
match self.abi {
168169
Abi::ScalarPair(..) => true,
169-
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false,
170+
Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::ScalableVector { .. } | Abi::Aggregate { .. } => false,
170171
}
171172
}
172173

compiler/rustc_codegen_llvm/src/abi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ impl LlvmType for Reg {
124124
_ => bug!("unsupported float: {:?}", self),
125125
},
126126
RegKind::Vector => cx.type_vector(cx.type_i8(), self.size.bytes()),
127+
RegKind::ScalableVector => cx.type_scalable_vector(cx.type_i8(), 16),
127128
}
128129
}
129130
}

compiler/rustc_codegen_llvm/src/builder.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
489489

490490
#[instrument(level = "trace", skip(self))]
491491
fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> {
492-
assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
492+
assert_eq!(
493+
place.llextra.is_some(),
494+
place.layout.is_unsized() && !place.layout.is_runtime_sized()
495+
);
493496

494497
if place.layout.is_zst() {
495498
return OperandRef::zero_sized(place.layout);

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,7 @@ fn build_struct_type_di_node<'ll, 'tcx>(
10061006
Cow::Borrowed(f.name.as_str())
10071007
};
10081008
let field_layout = struct_type_and_layout.field(cx, i);
1009+
10091010
build_field_di_node(
10101011
cx,
10111012
owner,

compiler/rustc_codegen_llvm/src/intrinsic.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,14 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
302302
let use_integer_compare = match layout.abi() {
303303
Scalar(_) | ScalarPair(_, _) => true,
304304
Uninhabited | Vector { .. } => false,
305+
ScalableVector { .. } => {
306+
tcx.sess.emit_err(InvalidMonomorphization::NonScalableType {
307+
span,
308+
name: sym::raw_eq,
309+
ty: tp_ty,
310+
});
311+
return;
312+
}
305313
Aggregate { .. } => {
306314
// For rusty ABIs, small aggregates are actually passed
307315
// as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
@@ -983,6 +991,19 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
983991
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
984992
}
985993

994+
if name == sym::simd_reinterpret {
995+
require_simd!(ret_ty, SimdReturn);
996+
997+
use rustc_codegen_ssa::mir::operand::OperandValue;
998+
return Ok(match args[0].val {
999+
OperandValue::Ref(val, _, _) | OperandValue::Immediate(val) => {
1000+
bx.bitcast(val, llret_ty)
1001+
}
1002+
OperandValue::ZeroSized => bx.const_undef(llret_ty),
1003+
OperandValue::Pair(_, _) => todo!(),
1004+
});
1005+
}
1006+
9861007
// every intrinsic below takes a SIMD vector as its first argument
9871008
let (in_len, in_elem) = require_simd!(arg_tys[0], SimdInput);
9881009
let in_ty = arg_tys[0];
@@ -1176,12 +1197,16 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
11761197
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
11771198
);
11781199
match m_elem_ty.kind() {
1179-
ty::Int(_) => {}
1200+
ty::Int(_) | ty::Bool => {}
11801201
_ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
11811202
}
11821203
// truncate the mask to a vector of i1s
11831204
let i1 = bx.type_i1();
1184-
let i1xn = bx.type_vector(i1, m_len as u64);
1205+
let i1xn = if arg_tys[1].is_scalable_simd() {
1206+
bx.type_scalable_vector(i1, m_len as u64)
1207+
} else {
1208+
bx.type_vector(i1, m_len as u64)
1209+
};
11851210
let m_i1s = bx.trunc(args[0].immediate(), i1xn);
11861211
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
11871212
}
@@ -1952,6 +1977,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
19521977
out_elem
19531978
});
19541979
}
1980+
19551981
macro_rules! arith_binary {
19561982
($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
19571983
$(if name == sym::$name {

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+1
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ extern "C" {
882882
pub fn LLVMRustArrayType(ElementType: &Type, ElementCount: u64) -> &Type;
883883
pub fn LLVMPointerTypeInContext(C: &Context, AddressSpace: c_uint) -> &Type;
884884
pub fn LLVMVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
885+
pub fn LLVMScalableVectorType(ElementType: &Type, ElementCount: c_uint) -> &Type;
885886

886887
pub fn LLVMGetElementType(Ty: &Type) -> &Type;
887888
pub fn LLVMGetVectorSize(VectorTy: &Type) -> c_uint;

compiler/rustc_codegen_llvm/src/type_.rs

+4
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ impl<'ll> CodegenCx<'ll, '_> {
6969
unsafe { llvm::LLVMVectorType(ty, len as c_uint) }
7070
}
7171

72+
pub(crate) fn type_scalable_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
73+
unsafe { llvm::LLVMScalableVectorType(ty, len as c_uint) }
74+
}
75+
7276
pub(crate) fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
7377
unsafe {
7478
let n_args = llvm::LLVMCountParamTypes(ty) as usize;

0 commit comments

Comments
 (0)