Skip to content

Commit 66ebf38

Browse files
moulinsworkingjubilee
authored andcommitted
Move SIMD layout logic to rustc_abi
1 parent b2b5c51 commit 66ebf38

File tree

5 files changed

+117
-79
lines changed

5 files changed

+117
-79
lines changed

compiler/rustc_abi/src/layout.rs

+85-12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ mod ty;
1818
#[cfg(feature = "nightly")]
1919
pub use ty::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
2020

21+
const MAX_SIMD_LANES: u64 = crate::TargetDataLayout::MAX_SIMD_LANES;
22+
2123
// A variant is absent if it's uninhabited and only has ZST fields.
2224
// Present uninhabited variants only require space for their fields,
2325
// but *not* an encoding of the discriminant (e.g., a tag value).
@@ -60,31 +62,44 @@ pub enum LayoutCalculatorError<F> {
6062

6163
/// The fields or variants have irreconcilable reprs
6264
ReprConflict,
65+
66+
/// The length of an SIMD type is zero
67+
ZeroLengthSimdType,
68+
69+
/// The length of an SIMD type exceeds the maximum number of lanes
70+
OversizedSimdType { max_lanes: u64 },
71+
72+
/// An element type of an SIMD type isn't a primitive
73+
NonPrimitiveSimdType(F),
6374
}
6475

6576
impl<F> LayoutCalculatorError<F> {
6677
pub fn without_payload(&self) -> LayoutCalculatorError<()> {
67-
match self {
68-
LayoutCalculatorError::UnexpectedUnsized(_) => {
69-
LayoutCalculatorError::UnexpectedUnsized(())
70-
}
71-
LayoutCalculatorError::SizeOverflow => LayoutCalculatorError::SizeOverflow,
72-
LayoutCalculatorError::EmptyUnion => LayoutCalculatorError::EmptyUnion,
73-
LayoutCalculatorError::ReprConflict => LayoutCalculatorError::ReprConflict,
78+
use LayoutCalculatorError::*;
79+
match *self {
80+
UnexpectedUnsized(_) => UnexpectedUnsized(()),
81+
SizeOverflow => SizeOverflow,
82+
EmptyUnion => EmptyUnion,
83+
ReprConflict => ReprConflict,
84+
ZeroLengthSimdType => ZeroLengthSimdType,
85+
OversizedSimdType { max_lanes } => OversizedSimdType { max_lanes },
86+
NonPrimitiveSimdType(_) => NonPrimitiveSimdType(()),
7487
}
7588
}
7689

7790
/// Format an untranslated diagnostic for this type
7891
///
7992
/// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra.
8093
pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94+
use LayoutCalculatorError::*;
8195
f.write_str(match self {
82-
LayoutCalculatorError::UnexpectedUnsized(_) => {
83-
"an unsized type was found where a sized type was expected"
96+
UnexpectedUnsized(_) => "an unsized type was found where a sized type was expected",
97+
SizeOverflow => "size overflow",
98+
EmptyUnion => "type is a union with no fields",
99+
ReprConflict => "type has an invalid repr",
100+
ZeroLengthSimdType | OversizedSimdType { .. } | NonPrimitiveSimdType(_) => {
101+
"invalid simd type definition"
84102
}
85-
LayoutCalculatorError::SizeOverflow => "size overflow",
86-
LayoutCalculatorError::EmptyUnion => "type is a union with no fields",
87-
LayoutCalculatorError::ReprConflict => "type has an invalid repr",
88103
})
89104
}
90105
}
@@ -125,6 +140,64 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
125140
})
126141
}
127142

143+
pub fn simd_type<
144+
FieldIdx: Idx,
145+
VariantIdx: Idx,
146+
F: AsRef<LayoutData<FieldIdx, VariantIdx>> + fmt::Debug,
147+
>(
148+
&self,
149+
element: F,
150+
count: u64,
151+
repr_packed: bool,
152+
) -> LayoutCalculatorResult<FieldIdx, VariantIdx, F> {
153+
let elt = element.as_ref();
154+
if count == 0 {
155+
return Err(LayoutCalculatorError::ZeroLengthSimdType);
156+
} else if count > MAX_SIMD_LANES {
157+
return Err(LayoutCalculatorError::OversizedSimdType { max_lanes: MAX_SIMD_LANES });
158+
}
159+
160+
let BackendRepr::Scalar(e_repr) = elt.backend_repr else {
161+
return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
162+
};
163+
164+
// Compute the size and alignment of the vector
165+
let dl = self.cx.data_layout();
166+
let size =
167+
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
168+
let (repr, align) = if repr_packed && !count.is_power_of_two() {
169+
// Non-power-of-two vectors have padding up to the next power-of-two.
170+
// If we're a packed repr, remove the padding while keeping the alignment as close
171+
// to a vector as possible.
172+
(
173+
BackendRepr::Memory { sized: true },
174+
AbiAndPrefAlign {
175+
abi: Align::max_aligned_factor(size),
176+
pref: dl.llvmlike_vector_align(size).pref,
177+
},
178+
)
179+
} else {
180+
(BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
181+
};
182+
let size = size.align_to(align.abi);
183+
184+
Ok(LayoutData {
185+
variants: Variants::Single { index: VariantIdx::new(0) },
186+
fields: FieldsShape::Arbitrary {
187+
offsets: [Size::ZERO].into(),
188+
memory_index: [0].into(),
189+
},
190+
backend_repr: repr,
191+
largest_niche: elt.largest_niche,
192+
uninhabited: false,
193+
size,
194+
align,
195+
max_repr_align: None,
196+
unadjusted_abi_align: elt.align.abi,
197+
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
198+
})
199+
}
200+
128201
pub fn univariant<
129202
'a,
130203
FieldIdx: Idx,

compiler/rustc_abi/src/layout/ty.rs

+6
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
150150
}
151151
}
152152

153+
impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
154+
fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
155+
&*self.layout.0.0
156+
}
157+
}
158+
153159
/// Trait that needs to be implemented by the higher-level type representation
154160
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
155161
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {

compiler/rustc_abi/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,13 @@ pub enum TargetDataLayoutErrors<'a> {
275275
}
276276

277277
impl TargetDataLayout {
278+
/// The maximum supported number of lanes in a SIMD vector.
279+
///
280+
/// This value is selected based on backend support:
281+
/// * LLVM does not appear to have a vector width limit.
282+
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
283+
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
284+
278285
/// Parse data layout from an
279286
/// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
280287
///

compiler/rustc_middle/src/ty/layout.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,7 @@ pub const WIDE_PTR_ADDR: usize = 0;
182182
/// - For a slice, this is the length.
183183
pub const WIDE_PTR_EXTRA: usize = 1;
184184

185-
/// The maximum supported number of lanes in a SIMD vector.
186-
///
187-
/// This value is selected based on backend support:
188-
/// * LLVM does not appear to have a vector width limit.
189-
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
190-
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
185+
pub const MAX_SIMD_LANES: u64 = TargetDataLayout::MAX_SIMD_LANES;
191186

192187
/// Used in `check_validity_requirement` to indicate the kind of initialization
193188
/// that is checked to be valid

compiler/rustc_ty_utils/src/layout.rs

+18-61
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use hir::def_id::DefId;
55
use rustc_abi::Integer::{I8, I32};
66
use rustc_abi::Primitive::{self, Float, Int, Pointer};
77
use rustc_abi::{
8-
AbiAndPrefAlign, AddressSpace, Align, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape,
9-
HasDataLayout, Layout, LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size,
10-
StructKind, TagEncoding, VariantIdx, Variants, WrappingRange,
8+
AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout,
9+
LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding,
10+
VariantIdx, Variants, WrappingRange,
1111
};
1212
use rustc_hashes::Hash64;
1313
use rustc_index::bit_set::DenseBitSet;
@@ -16,7 +16,7 @@ use rustc_middle::bug;
1616
use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal};
1717
use rustc_middle::query::Providers;
1818
use rustc_middle::ty::layout::{
19-
FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, MAX_SIMD_LANES, TyAndLayout,
19+
FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout,
2020
};
2121
use rustc_middle::ty::print::with_no_trimmed_paths;
2222
use rustc_middle::ty::{
@@ -124,6 +124,19 @@ fn map_error<'tcx>(
124124
.delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}"));
125125
LayoutError::ReferencesError(guar)
126126
}
127+
LayoutCalculatorError::ZeroLengthSimdType => {
128+
// Can't be caught in typeck if the array length is generic.
129+
cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty })
130+
}
131+
LayoutCalculatorError::OversizedSimdType { max_lanes } => {
132+
// Can't be caught in typeck if the array length is generic.
133+
cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes })
134+
}
135+
LayoutCalculatorError::NonPrimitiveSimdType(field) => {
136+
// This error isn't caught in typeck, e.g., if
137+
// the element type of the vector is generic.
138+
cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty })
139+
}
127140
};
128141
error(cx, err)
129142
}
@@ -423,65 +436,9 @@ fn layout_of_uncached<'tcx>(
423436
.try_to_target_usize(tcx)
424437
.ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
425438

426-
// SIMD vectors of zero length are not supported.
427-
// Additionally, lengths are capped at 2^16 as a fixed maximum backends must
428-
// support.
429-
//
430-
// Can't be caught in typeck if the array length is generic.
431-
if e_len == 0 {
432-
tcx.dcx().emit_fatal(ZeroLengthSimdType { ty });
433-
} else if e_len > MAX_SIMD_LANES {
434-
tcx.dcx().emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES });
435-
}
436-
437-
// Compute the ABI of the element type:
438439
let e_ly = cx.layout_of(e_ty)?;
439-
let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else {
440-
// This error isn't caught in typeck, e.g., if
441-
// the element type of the vector is generic.
442-
tcx.dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty });
443-
};
444-
445-
// Compute the size and alignment of the vector:
446-
let size = e_ly
447-
.size
448-
.checked_mul(e_len, dl)
449-
.ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
450-
451-
let (abi, align) = if def.repr().packed() && !e_len.is_power_of_two() {
452-
// Non-power-of-two vectors have padding up to the next power-of-two.
453-
// If we're a packed repr, remove the padding while keeping the alignment as close
454-
// to a vector as possible.
455-
(
456-
BackendRepr::Memory { sized: true },
457-
AbiAndPrefAlign {
458-
abi: Align::max_aligned_factor(size),
459-
pref: dl.llvmlike_vector_align(size).pref,
460-
},
461-
)
462-
} else {
463-
(
464-
BackendRepr::SimdVector { element: e_abi, count: e_len },
465-
dl.llvmlike_vector_align(size),
466-
)
467-
};
468-
let size = size.align_to(align.abi);
469440

470-
tcx.mk_layout(LayoutData {
471-
variants: Variants::Single { index: FIRST_VARIANT },
472-
fields: FieldsShape::Arbitrary {
473-
offsets: [Size::ZERO].into(),
474-
memory_index: [0].into(),
475-
},
476-
backend_repr: abi,
477-
largest_niche: e_ly.largest_niche,
478-
uninhabited: false,
479-
size,
480-
align,
481-
max_repr_align: None,
482-
unadjusted_abi_align: align.abi,
483-
randomization_seed: e_ly.randomization_seed.wrapping_add(Hash64::new(e_len)),
484-
})
441+
map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))?
485442
}
486443

487444
// ADTs.

0 commit comments

Comments
 (0)