Skip to content

Commit 80c3b55

Browse files
authored
Rollup merge of rust-lang#78863 - KodrAus:feat/simd-array, r=oli-obk
Support repr(simd) on ADTs containing a single array field This is a squash and rebase of `@gnzlbg's` rust-lang#63531 I've never actually written code in the compiler before so just fumbled my way around until it would build 😅 I imagine there'll be some work we need to do in `rustc_codegen_cranelift` too for this now, but might need some input from `@bjorn3` to know what that is. cc `@rust-lang/project-portable-simd` ----- This PR allows using `#[repr(simd)]` on ADTs containing a single array field: ```rust #[repr(simd)] struct S0([f32; 4]); #[repr(simd)] struct S1<const N: usize>([f32; N]); #[repr(simd)] struct S2<T, const N: usize>([T; N]); ``` This should allow experimenting with portable packed SIMD abstractions on nightly that make use of const generics.
2 parents 975b50d + e217fc4 commit 80c3b55

17 files changed

+467
-157
lines changed

compiler/rustc_codegen_llvm/src/intrinsic.rs

+55-50
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ fn generic_simd_intrinsic(
792792
_ => return_error!("`{}` is not an integral type", in_ty),
793793
};
794794
require_simd!(arg_tys[1], "argument");
795-
let v_len = arg_tys[1].simd_size(tcx);
795+
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
796796
require!(
797797
// Allow masks for vectors with fewer than 8 elements to be
798798
// represented with a u8 or i8.
@@ -812,8 +812,6 @@ fn generic_simd_intrinsic(
812812
// every intrinsic below takes a SIMD vector as its first argument
813813
require_simd!(arg_tys[0], "input");
814814
let in_ty = arg_tys[0];
815-
let in_elem = arg_tys[0].simd_type(tcx);
816-
let in_len = arg_tys[0].simd_size(tcx);
817815

818816
let comparison = match name {
819817
sym::simd_eq => Some(hir::BinOpKind::Eq),
@@ -825,14 +823,15 @@ fn generic_simd_intrinsic(
825823
_ => None,
826824
};
827825

826+
let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
828827
if let Some(cmp_op) = comparison {
829828
require_simd!(ret_ty, "return");
830829

831-
let out_len = ret_ty.simd_size(tcx);
830+
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
832831
require!(
833832
in_len == out_len,
834833
"expected return type with length {} (same as input type `{}`), \
835-
found `{}` with length {}",
834+
found `{}` with length {}",
836835
in_len,
837836
in_ty,
838837
ret_ty,
@@ -842,7 +841,7 @@ fn generic_simd_intrinsic(
842841
bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
843842
"expected return type with integer elements, found `{}` with non-integer `{}`",
844843
ret_ty,
845-
ret_ty.simd_type(tcx)
844+
out_ty
846845
);
847846

848847
return Ok(compare_simd_types(
@@ -862,7 +861,7 @@ fn generic_simd_intrinsic(
862861

863862
require_simd!(ret_ty, "return");
864863

865-
let out_len = ret_ty.simd_size(tcx);
864+
let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
866865
require!(
867866
out_len == n,
868867
"expected return type of length {}, found `{}` with length {}",
@@ -871,13 +870,13 @@ fn generic_simd_intrinsic(
871870
out_len
872871
);
873872
require!(
874-
in_elem == ret_ty.simd_type(tcx),
873+
in_elem == out_ty,
875874
"expected return element type `{}` (element of input `{}`), \
876-
found `{}` with element type `{}`",
875+
found `{}` with element type `{}`",
877876
in_elem,
878877
in_ty,
879878
ret_ty,
880-
ret_ty.simd_type(tcx)
879+
out_ty
881880
);
882881

883882
let total_len = u128::from(in_len) * 2;
@@ -946,7 +945,7 @@ fn generic_simd_intrinsic(
946945
let m_elem_ty = in_elem;
947946
let m_len = in_len;
948947
require_simd!(arg_tys[1], "argument");
949-
let v_len = arg_tys[1].simd_size(tcx);
948+
let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
950949
require!(
951950
m_len == v_len,
952951
"mismatched lengths: mask length `{}` != other vector length `{}`",
@@ -1173,25 +1172,27 @@ fn generic_simd_intrinsic(
11731172
require_simd!(ret_ty, "return");
11741173

11751174
// Of the same length:
1175+
let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
1176+
let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
11761177
require!(
1177-
in_len == arg_tys[1].simd_size(tcx),
1178+
in_len == out_len,
11781179
"expected {} argument with length {} (same as input type `{}`), \
1179-
found `{}` with length {}",
1180+
found `{}` with length {}",
11801181
"second",
11811182
in_len,
11821183
in_ty,
11831184
arg_tys[1],
1184-
arg_tys[1].simd_size(tcx)
1185+
out_len
11851186
);
11861187
require!(
1187-
in_len == arg_tys[2].simd_size(tcx),
1188+
in_len == out_len2,
11881189
"expected {} argument with length {} (same as input type `{}`), \
1189-
found `{}` with length {}",
1190+
found `{}` with length {}",
11901191
"third",
11911192
in_len,
11921193
in_ty,
11931194
arg_tys[2],
1194-
arg_tys[2].simd_size(tcx)
1195+
out_len2
11951196
);
11961197

11971198
// The return type must match the first argument type
@@ -1215,39 +1216,40 @@ fn generic_simd_intrinsic(
12151216

12161217
// The second argument must be a simd vector with an element type that's a pointer
12171218
// to the element type of the first argument
1218-
let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() {
1219-
ty::RawPtr(p) if p.ty == in_elem => {
1220-
(ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx)))
1221-
}
1219+
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
1220+
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
1221+
let (pointer_count, underlying_ty) = match element_ty1.kind() {
1222+
ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
12221223
_ => {
12231224
require!(
12241225
false,
12251226
"expected element type `{}` of second argument `{}` \
1226-
to be a pointer to the element type `{}` of the first \
1227-
argument `{}`, found `{}` != `*_ {}`",
1228-
arg_tys[1].simd_type(tcx),
1227+
to be a pointer to the element type `{}` of the first \
1228+
argument `{}`, found `{}` != `*_ {}`",
1229+
element_ty1,
12291230
arg_tys[1],
12301231
in_elem,
12311232
in_ty,
1232-
arg_tys[1].simd_type(tcx),
1233+
element_ty1,
12331234
in_elem
12341235
);
12351236
unreachable!();
12361237
}
12371238
};
12381239
assert!(pointer_count > 0);
1239-
assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
1240-
assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
1240+
assert_eq!(pointer_count - 1, ptr_count(element_ty0));
1241+
assert_eq!(underlying_ty, non_ptr(element_ty0));
12411242

12421243
// The element type of the third argument must be a signed integer type of any width:
1243-
match arg_tys[2].simd_type(tcx).kind() {
1244+
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
1245+
match element_ty2.kind() {
12441246
ty::Int(_) => (),
12451247
_ => {
12461248
require!(
12471249
false,
12481250
"expected element type `{}` of third argument `{}` \
12491251
to be a signed integer type",
1250-
arg_tys[2].simd_type(tcx),
1252+
element_ty2,
12511253
arg_tys[2]
12521254
);
12531255
}
@@ -1299,25 +1301,27 @@ fn generic_simd_intrinsic(
12991301
require_simd!(arg_tys[2], "third");
13001302

13011303
// Of the same length:
1304+
let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
1305+
let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
13021306
require!(
1303-
in_len == arg_tys[1].simd_size(tcx),
1307+
in_len == element_len1,
13041308
"expected {} argument with length {} (same as input type `{}`), \
1305-
found `{}` with length {}",
1309+
found `{}` with length {}",
13061310
"second",
13071311
in_len,
13081312
in_ty,
13091313
arg_tys[1],
1310-
arg_tys[1].simd_size(tcx)
1314+
element_len1
13111315
);
13121316
require!(
1313-
in_len == arg_tys[2].simd_size(tcx),
1317+
in_len == element_len2,
13141318
"expected {} argument with length {} (same as input type `{}`), \
1315-
found `{}` with length {}",
1319+
found `{}` with length {}",
13161320
"third",
13171321
in_len,
13181322
in_ty,
13191323
arg_tys[2],
1320-
arg_tys[2].simd_size(tcx)
1324+
element_len2
13211325
);
13221326

13231327
// This counts how many pointers
@@ -1338,39 +1342,42 @@ fn generic_simd_intrinsic(
13381342

13391343
// The second argument must be a simd vector with an element type that's a pointer
13401344
// to the element type of the first argument
1341-
let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() {
1345+
let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
1346+
let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
1347+
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
1348+
let (pointer_count, underlying_ty) = match element_ty1.kind() {
13421349
ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => {
1343-
(ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx)))
1350+
(ptr_count(element_ty1), non_ptr(element_ty1))
13441351
}
13451352
_ => {
13461353
require!(
13471354
false,
13481355
"expected element type `{}` of second argument `{}` \
1349-
to be a pointer to the element type `{}` of the first \
1350-
argument `{}`, found `{}` != `*mut {}`",
1351-
arg_tys[1].simd_type(tcx),
1356+
to be a pointer to the element type `{}` of the first \
1357+
argument `{}`, found `{}` != `*mut {}`",
1358+
element_ty1,
13521359
arg_tys[1],
13531360
in_elem,
13541361
in_ty,
1355-
arg_tys[1].simd_type(tcx),
1362+
element_ty1,
13561363
in_elem
13571364
);
13581365
unreachable!();
13591366
}
13601367
};
13611368
assert!(pointer_count > 0);
1362-
assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx)));
1363-
assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx)));
1369+
assert_eq!(pointer_count - 1, ptr_count(element_ty0));
1370+
assert_eq!(underlying_ty, non_ptr(element_ty0));
13641371

13651372
// The element type of the third argument must be a signed integer type of any width:
1366-
match arg_tys[2].simd_type(tcx).kind() {
1373+
match element_ty2.kind() {
13671374
ty::Int(_) => (),
13681375
_ => {
13691376
require!(
13701377
false,
13711378
"expected element type `{}` of third argument `{}` \
1372-
to be a signed integer type",
1373-
arg_tys[2].simd_type(tcx),
1379+
be a signed integer type",
1380+
element_ty2,
13741381
arg_tys[2]
13751382
);
13761383
}
@@ -1567,7 +1574,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
15671574

15681575
if name == sym::simd_cast {
15691576
require_simd!(ret_ty, "return");
1570-
let out_len = ret_ty.simd_size(tcx);
1577+
let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
15711578
require!(
15721579
in_len == out_len,
15731580
"expected return type with length {} (same as input type `{}`), \
@@ -1578,8 +1585,6 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
15781585
out_len
15791586
);
15801587
// casting cares about nominal type, not just structural type
1581-
let out_elem = ret_ty.simd_type(tcx);
1582-
15831588
if in_elem == out_elem {
15841589
return Ok(args[0].immediate());
15851590
}
@@ -1695,7 +1700,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
16951700
return_error!(
16961701
"expected element type `{}` of vector type `{}` \
16971702
to be a signed or unsigned integer type",
1698-
arg_tys[0].simd_type(tcx),
1703+
arg_tys[0].simd_size_and_type(bx.tcx()).1,
16991704
arg_tys[0]
17001705
);
17011706
}

0 commit comments

Comments
 (0)