Skip to content

Commit e69491a

Browse files
committed
Move SIMD layout logic to rustc_abi
1 parent 9917173 commit e69491a

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
@@ -62,31 +62,44 @@ pub enum LayoutCalculatorError<F> {
6262

6363
/// The fields or variants have irreconcilable reprs
6464
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),
6574
}
6675

6776
impl<F> LayoutCalculatorError<F> {
6877
pub fn without_payload(&self) -> LayoutCalculatorError<()> {
69-
match self {
70-
LayoutCalculatorError::UnexpectedUnsized(_) => {
71-
LayoutCalculatorError::UnexpectedUnsized(())
72-
}
73-
LayoutCalculatorError::SizeOverflow => LayoutCalculatorError::SizeOverflow,
74-
LayoutCalculatorError::EmptyUnion => LayoutCalculatorError::EmptyUnion,
75-
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(()),
7687
}
7788
}
7889

7990
/// Format an untranslated diagnostic for this type
8091
///
8192
/// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra.
8293
pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94+
use LayoutCalculatorError::*;
8395
f.write_str(match self {
84-
LayoutCalculatorError::UnexpectedUnsized(_) => {
85-
"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"
86102
}
87-
LayoutCalculatorError::SizeOverflow => "size overflow",
88-
LayoutCalculatorError::EmptyUnion => "type is a union with no fields",
89-
LayoutCalculatorError::ReprConflict => "type has an invalid repr",
90103
})
91104
}
92105
}
@@ -127,6 +140,66 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
127140
})
128141
}
129142

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 > crate::MAX_SIMD_LANES {
157+
return Err(LayoutCalculatorError::OversizedSimdType {
158+
max_lanes: crate::MAX_SIMD_LANES,
159+
});
160+
}
161+
162+
let BackendRepr::Scalar(e_repr) = elt.backend_repr else {
163+
return Err(LayoutCalculatorError::NonPrimitiveSimdType(element));
164+
};
165+
166+
// Compute the size and alignment of the vector
167+
let dl = self.cx.data_layout();
168+
let size =
169+
elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?;
170+
let (repr, align) = if repr_packed && !count.is_power_of_two() {
171+
// Non-power-of-two vectors have padding up to the next power-of-two.
172+
// If we're a packed repr, remove the padding while keeping the alignment as close
173+
// to a vector as possible.
174+
(
175+
BackendRepr::Memory { sized: true },
176+
AbiAndPrefAlign {
177+
abi: Align::max_aligned_factor(size),
178+
pref: dl.llvmlike_vector_align(size).pref,
179+
},
180+
)
181+
} else {
182+
(BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size))
183+
};
184+
let size = size.align_to(align.abi);
185+
186+
Ok(LayoutData {
187+
variants: Variants::Single { index: VariantIdx::new(0) },
188+
fields: FieldsShape::Arbitrary {
189+
offsets: [Size::ZERO].into(),
190+
memory_index: [0].into(),
191+
},
192+
backend_repr: repr,
193+
largest_niche: elt.largest_niche,
194+
uninhabited: false,
195+
size,
196+
align,
197+
max_repr_align: None,
198+
unadjusted_abi_align: elt.align.abi,
199+
randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)),
200+
})
201+
}
202+
130203
pub fn univariant<
131204
'a,
132205
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
@@ -205,6 +205,13 @@ impl ReprOptions {
205205
}
206206
}
207207

208+
/// The maximum supported number of lanes in a SIMD vector.
209+
///
210+
/// This value is selected based on backend support:
211+
/// * LLVM does not appear to have a vector width limit.
212+
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
213+
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
214+
208215
/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
209216
/// for a target, which contains everything needed to compute layouts.
210217
#[derive(Debug, PartialEq, Eq)]

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 = rustc_abi::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)