Skip to content

Commit 9331031

Browse files
committed
Auto merge of #46701 - eddyb:vector-newtypes, r=nagisa
rustc: unpack newtyped of #[repr(simd)] vector types. Prerequisite for a `#[repr(transparent)]` implementation that works with SIMD vectors. cc @rkruppe
2 parents 2f35141 + 95c0ad0 commit 9331031

File tree

7 files changed

+98
-87
lines changed

7 files changed

+98
-87
lines changed

Diff for: src/librustc/ty/layout.rs

+28-14
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,10 @@ pub enum Abi {
758758
Uninhabited,
759759
Scalar(Scalar),
760760
ScalarPair(Scalar, Scalar),
761-
Vector,
761+
Vector {
762+
element: Scalar,
763+
count: u64
764+
},
762765
Aggregate {
763766
/// If true, the size is exact, otherwise it's only a lower bound.
764767
sized: bool,
@@ -773,7 +776,7 @@ impl Abi {
773776
Abi::Uninhabited |
774777
Abi::Scalar(_) |
775778
Abi::ScalarPair(..) |
776-
Abi::Vector => false,
779+
Abi::Vector { .. } => false,
777780
Abi::Aggregate { sized, .. } => !sized
778781
}
779782
}
@@ -784,7 +787,7 @@ impl Abi {
784787
Abi::Uninhabited |
785788
Abi::Scalar(_) |
786789
Abi::ScalarPair(..) |
787-
Abi::Vector => false,
790+
Abi::Vector { .. } => false,
788791
Abi::Aggregate { packed, .. } => packed
789792
}
790793
}
@@ -1083,9 +1086,9 @@ impl<'a, 'tcx> LayoutDetails {
10831086
align.abi() == field.align.abi() &&
10841087
size == field.size {
10851088
match field.abi {
1086-
// For plain scalars we can't unpack newtypes
1087-
// for `#[repr(C)]`, as that affects C ABIs.
1088-
Abi::Scalar(_) if optimize => {
1089+
// For plain scalars, or vectors of them, we can't unpack
1090+
// newtypes for `#[repr(C)]`, as that affects C ABIs.
1091+
Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
10891092
abi = field.abi.clone();
10901093
}
10911094
// But scalar pairs are Rust-specific and get
@@ -1320,16 +1323,17 @@ impl<'a, 'tcx> LayoutDetails {
13201323

13211324
// SIMD vector types.
13221325
ty::TyAdt(def, ..) if def.repr.simd() => {
1323-
let count = ty.simd_size(tcx) as u64;
13241326
let element = cx.layout_of(ty.simd_type(tcx))?;
1325-
match element.abi {
1326-
Abi::Scalar(_) => {}
1327+
let count = ty.simd_size(tcx) as u64;
1328+
assert!(count > 0);
1329+
let scalar = match element.abi {
1330+
Abi::Scalar(ref scalar) => scalar.clone(),
13271331
_ => {
13281332
tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \
13291333
a non-machine element type `{}`",
13301334
ty, element.ty));
13311335
}
1332-
}
1336+
};
13331337
let size = element.size.checked_mul(count, dl)
13341338
.ok_or(LayoutError::SizeOverflow(ty))?;
13351339
let align = dl.vector_align(size);
@@ -1341,7 +1345,10 @@ impl<'a, 'tcx> LayoutDetails {
13411345
stride: element.size,
13421346
count
13431347
},
1344-
abi: Abi::Vector,
1348+
abi: Abi::Vector {
1349+
element: scalar,
1350+
count
1351+
},
13451352
size,
13461353
align,
13471354
})
@@ -2266,8 +2273,9 @@ impl<'a, 'tcx> TyLayout<'tcx> {
22662273
pub fn is_zst(&self) -> bool {
22672274
match self.abi {
22682275
Abi::Uninhabited => true,
2269-
Abi::Scalar(_) | Abi::ScalarPair(..) => false,
2270-
Abi::Vector => self.size.bytes() == 0,
2276+
Abi::Scalar(_) |
2277+
Abi::ScalarPair(..) |
2278+
Abi::Vector { .. } => false,
22712279
Abi::Aggregate { sized, .. } => sized && self.size.bytes() == 0
22722280
}
22732281
}
@@ -2322,6 +2330,9 @@ impl<'a, 'tcx> TyLayout<'tcx> {
23222330
scalar_component(b, a.value.size(cx).abi_align(b.value.align(cx)))
23232331
}));
23242332
}
2333+
Abi::Vector { ref element, .. } => {
2334+
return Ok(scalar_component(element, Size::from_bytes(0)));
2335+
}
23252336
_ => {}
23262337
}
23272338

@@ -2424,7 +2435,10 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
24242435
a.hash_stable(hcx, hasher);
24252436
b.hash_stable(hcx, hasher);
24262437
}
2427-
Vector => {}
2438+
Vector { ref element, count } => {
2439+
element.hash_stable(hcx, hasher);
2440+
count.hash_stable(hcx, hasher);
2441+
}
24282442
Aggregate { packed, sized } => {
24292443
packed.hash_stable(hcx, hasher);
24302444
sized.hash_stable(hcx, hasher);

Diff for: src/librustc_trans/abi.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
315315
match self.abi {
316316
layout::Abi::Uninhabited |
317317
layout::Abi::Scalar(_) |
318-
layout::Abi::Vector => false,
318+
layout::Abi::Vector { .. } => false,
319319
layout::Abi::ScalarPair(..) |
320320
layout::Abi::Aggregate { .. } => true
321321
}
@@ -339,7 +339,7 @@ impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> {
339339
})
340340
}
341341

342-
layout::Abi::Vector => {
342+
layout::Abi::Vector { .. } => {
343343
Some(Reg {
344344
kind: RegKind::Vector,
345345
size: self.size

Diff for: src/librustc_trans/cabi_x86_64.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,14 @@ fn classify_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, arg: &ArgType<'tcx>)
7777
unify(cls, off, reg);
7878
}
7979

80-
layout::Abi::Vector => {
80+
layout::Abi::Vector { ref element, count } => {
8181
unify(cls, off, Class::Sse);
8282

8383
// everything after the first one is the upper
8484
// half of a register.
85-
for i in 1..layout.fields.count() {
86-
let field_off = off + layout.fields.offset(i);
85+
let stride = element.value.size(ccx);
86+
for i in 1..count {
87+
let field_off = off + stride * i;
8788
unify(cls, field_off, Class::SseUp);
8889
}
8990
}

Diff for: src/librustc_trans/cabi_x86_win64.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub fn compute_abi_info(fty: &mut FnType) {
2828
_ => a.make_indirect()
2929
}
3030
}
31-
layout::Abi::Vector => {
31+
layout::Abi::Vector { .. } => {
3232
// FIXME(eddyb) there should be a size cap here
3333
// (probably what clang calls "illegal vectors").
3434
}

Diff for: src/librustc_trans/mir/constant.rs

+17-12
Original file line numberDiff line numberDiff line change
@@ -122,17 +122,17 @@ impl<'a, 'tcx> Const<'tcx> {
122122
if field.is_zst() {
123123
return C_undef(field.immediate_llvm_type(ccx));
124124
}
125+
let offset = layout.fields.offset(i);
125126
match layout.abi {
126-
layout::Abi::Scalar(_) => self.llval,
127+
layout::Abi::Scalar(_) |
128+
layout::Abi::ScalarPair(..) |
129+
layout::Abi::Vector { .. }
130+
if offset.bytes() == 0 && field.size == layout.size => self.llval,
131+
127132
layout::Abi::ScalarPair(ref a, ref b) => {
128-
let offset = layout.fields.offset(i);
129133
if offset.bytes() == 0 {
130-
if field.size == layout.size {
131-
self.llval
132-
} else {
133-
assert_eq!(field.size, a.value.size(ccx));
134-
const_get_elt(self.llval, 0)
135-
}
134+
assert_eq!(field.size, a.value.size(ccx));
135+
const_get_elt(self.llval, 0)
136136
} else {
137137
assert_eq!(offset, a.value.size(ccx)
138138
.abi_align(b.value.align(ccx)));
@@ -1131,9 +1131,7 @@ fn trans_const_adt<'a, 'tcx>(
11311131
match l.variants {
11321132
layout::Variants::Single { index } => {
11331133
assert_eq!(variant_index, index);
1134-
if let layout::Abi::Vector = l.abi {
1135-
Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
1136-
} else if let layout::FieldPlacement::Union(_) = l.fields {
1134+
if let layout::FieldPlacement::Union(_) = l.fields {
11371135
assert_eq!(variant_index, 0);
11381136
assert_eq!(vals.len(), 1);
11391137
let contents = [
@@ -1143,6 +1141,12 @@ fn trans_const_adt<'a, 'tcx>(
11431141

11441142
Const::new(C_struct(ccx, &contents, l.is_packed()), t)
11451143
} else {
1144+
if let layout::Abi::Vector { .. } = l.abi {
1145+
if let layout::FieldPlacement::Array { .. } = l.fields {
1146+
return Const::new(C_vector(&vals.iter().map(|x| x.llval)
1147+
.collect::<Vec<_>>()), t);
1148+
}
1149+
}
11461150
build_const_struct(ccx, l, vals, None)
11471151
}
11481152
}
@@ -1206,7 +1210,8 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
12061210

12071211
match layout.abi {
12081212
layout::Abi::Scalar(_) |
1209-
layout::Abi::ScalarPair(..) if discr.is_none() => {
1213+
layout::Abi::ScalarPair(..) |
1214+
layout::Abi::Vector { .. } if discr.is_none() => {
12101215
let mut non_zst_fields = vals.iter().enumerate().map(|(i, f)| {
12111216
(f, layout.fields.offset(i))
12121217
}).filter(|&(f, _)| !ccx.layout_of(f.ty).is_zst());

Diff for: src/librustc_trans/mir/operand.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
163163
};
164164
}
165165

166-
// Newtype of a scalar or scalar pair.
166+
// Newtype of a scalar, scalar pair or vector.
167167
(OperandValue::Immediate(_), _) |
168168
(OperandValue::Pair(..), _) if field.size == self.layout.size => {
169169
assert_eq!(offset.bytes(), 0);
@@ -184,7 +184,7 @@ impl<'a, 'tcx> OperandRef<'tcx> {
184184
}
185185

186186
// `#[repr(simd)]` types are also immediate.
187-
(OperandValue::Immediate(llval), &layout::Abi::Vector) => {
187+
(OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => {
188188
OperandValue::Immediate(
189189
bcx.extract_element(llval, C_usize(bcx.ccx, i as u64)))
190190
}

Diff for: src/librustc_trans/type_of.rs

+44-53
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,22 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
2525
-> Type {
2626
match layout.abi {
2727
layout::Abi::Scalar(_) => bug!("handled elsewhere"),
28-
layout::Abi::Vector => {
28+
layout::Abi::Vector { ref element, count } => {
2929
// LLVM has a separate type for 64-bit SIMD vectors on X86 called
3030
// `x86_mmx` which is needed for some SIMD operations. As a bit of a
3131
// hack (all SIMD definitions are super unstable anyway) we
3232
// recognize any one-element SIMD vector as "this should be an
3333
// x86_mmx" type. In general there shouldn't be a need for other
3434
// one-element SIMD vectors, so it's assumed this won't clash with
3535
// much else.
36-
let use_x86_mmx = layout.fields.count() == 1 &&
37-
layout.size.bits() == 64 &&
36+
let use_x86_mmx = count == 1 && layout.size.bits() == 64 &&
3837
(ccx.sess().target.target.arch == "x86" ||
3938
ccx.sess().target.target.arch == "x86_64");
4039
if use_x86_mmx {
4140
return Type::x86_mmx(ccx)
4241
} else {
43-
return Type::vector(&layout.field(ccx, 0).llvm_type(ccx),
44-
layout.fields.count() as u64);
42+
let element = layout.scalar_llvm_type_at(ccx, element, Size::from_bytes(0));
43+
return Type::vector(&element, count);
4544
}
4645
}
4746
layout::Abi::ScalarPair(..) => {
@@ -198,6 +197,8 @@ pub trait LayoutLlvmExt<'tcx> {
198197
fn is_llvm_scalar_pair<'a>(&self) -> bool;
199198
fn llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type;
200199
fn immediate_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type;
200+
fn scalar_llvm_type_at<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
201+
scalar: &layout::Scalar, offset: Size) -> Type;
201202
fn scalar_pair_element_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
202203
index: usize) -> Type;
203204
fn llvm_field_index(&self, index: usize) -> u64;
@@ -210,7 +211,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
210211
match self.abi {
211212
layout::Abi::Uninhabited |
212213
layout::Abi::Scalar(_) |
213-
layout::Abi::Vector => true,
214+
layout::Abi::Vector { .. } => true,
214215
layout::Abi::ScalarPair(..) => false,
215216
layout::Abi::Aggregate { .. } => self.is_zst()
216217
}
@@ -221,7 +222,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
221222
layout::Abi::ScalarPair(..) => true,
222223
layout::Abi::Uninhabited |
223224
layout::Abi::Scalar(_) |
224-
layout::Abi::Vector |
225+
layout::Abi::Vector { .. } |
225226
layout::Abi::Aggregate { .. } => false
226227
}
227228
}
@@ -244,34 +245,19 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
244245
if let Some(&llty) = ccx.scalar_lltypes().borrow().get(&self.ty) {
245246
return llty;
246247
}
247-
let llty = match scalar.value {
248-
layout::Int(i, _) => Type::from_integer(ccx, i),
249-
layout::F32 => Type::f32(ccx),
250-
layout::F64 => Type::f64(ccx),
251-
layout::Pointer => {
252-
let pointee = match self.ty.sty {
253-
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
254-
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
255-
ccx.layout_of(ty).llvm_type(ccx)
256-
}
257-
ty::TyAdt(def, _) if def.is_box() => {
258-
ccx.layout_of(self.ty.boxed_ty()).llvm_type(ccx)
259-
}
260-
ty::TyFnPtr(sig) => {
261-
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
262-
FnType::new(ccx, sig, &[]).llvm_type(ccx)
263-
}
264-
_ => {
265-
// If we know the alignment, pick something better than i8.
266-
if let Some(pointee) = self.pointee_info_at(ccx, Size::from_bytes(0)) {
267-
Type::pointee_for_abi_align(ccx, pointee.align)
268-
} else {
269-
Type::i8(ccx)
270-
}
271-
}
272-
};
273-
pointee.ptr_to()
248+
let llty = match self.ty.sty {
249+
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
250+
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
251+
ccx.layout_of(ty).llvm_type(ccx).ptr_to()
252+
}
253+
ty::TyAdt(def, _) if def.is_box() => {
254+
ccx.layout_of(self.ty.boxed_ty()).llvm_type(ccx).ptr_to()
274255
}
256+
ty::TyFnPtr(sig) => {
257+
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
258+
FnType::new(ccx, sig, &[]).llvm_type(ccx).ptr_to()
259+
}
260+
_ => self.scalar_llvm_type_at(ccx, scalar, Size::from_bytes(0))
275261
};
276262
ccx.scalar_lltypes().borrow_mut().insert(self.ty, llty);
277263
return llty;
@@ -325,6 +311,24 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
325311
self.llvm_type(ccx)
326312
}
327313

314+
fn scalar_llvm_type_at<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
315+
scalar: &layout::Scalar, offset: Size) -> Type {
316+
match scalar.value {
317+
layout::Int(i, _) => Type::from_integer(ccx, i),
318+
layout::F32 => Type::f32(ccx),
319+
layout::F64 => Type::f64(ccx),
320+
layout::Pointer => {
321+
// If we know the alignment, pick something better than i8.
322+
let pointee = if let Some(pointee) = self.pointee_info_at(ccx, offset) {
323+
Type::pointee_for_abi_align(ccx, pointee.align)
324+
} else {
325+
Type::i8(ccx)
326+
};
327+
pointee.ptr_to()
328+
}
329+
}
330+
}
331+
328332
fn scalar_pair_element_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
329333
index: usize) -> Type {
330334
// HACK(eddyb) special-case fat pointers until LLVM removes
@@ -358,25 +362,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
358362
return Type::i1(ccx);
359363
}
360364

361-
match scalar.value {
362-
layout::Int(i, _) => Type::from_integer(ccx, i),
363-
layout::F32 => Type::f32(ccx),
364-
layout::F64 => Type::f64(ccx),
365-
layout::Pointer => {
366-
// If we know the alignment, pick something better than i8.
367-
let offset = if index == 0 {
368-
Size::from_bytes(0)
369-
} else {
370-
a.value.size(ccx).abi_align(b.value.align(ccx))
371-
};
372-
let pointee = if let Some(pointee) = self.pointee_info_at(ccx, offset) {
373-
Type::pointee_for_abi_align(ccx, pointee.align)
374-
} else {
375-
Type::i8(ccx)
376-
};
377-
pointee.ptr_to()
378-
}
379-
}
365+
let offset = if index == 0 {
366+
Size::from_bytes(0)
367+
} else {
368+
a.value.size(ccx).abi_align(b.value.align(ccx))
369+
};
370+
self.scalar_llvm_type_at(ccx, scalar, offset)
380371
}
381372

382373
fn llvm_field_index(&self, index: usize) -> u64 {

0 commit comments

Comments
 (0)