From 6e88e96ccf1ca7621e6177d729a69625838db1c8 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Sat, 13 Jul 2019 17:16:57 +0200 Subject: Support repr(simd) on ADTs containing a single array field This PR allows using `#[repr(simd)]` on ADTs containing a single array field: ```rust #[repr(simd)] struct S0([f32; 4]); #[repr(simd)] struct S1([f32; N]); #[repr(simd)] struct S2([T; N]); ``` This should allow experimenting with portable packed SIMD abstractions on nightly that make use of const generics. --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 122 ++++++++++++++++----------- 1 file changed, 72 insertions(+), 50 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e9900e8bc10..2ea7d7ac2d8 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -740,6 +740,23 @@ fn generic_simd_intrinsic( llret_ty: &'ll Type, span: Span, ) -> Result<&'ll Value, ()> { + // Given a SIMD vector type `x` return the element type and the number of + // elements in the vector. + fn simd_ty_and_len(bx: &Builder<'a, 'll, 'tcx>, simd_ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { + let ty = if let ty::Adt(_def, _substs) = simd_ty.kind() { + let f0_ty = bx.layout_of(simd_ty).field(bx, 0).ty; + if let ty::Array(element_ty, _) = f0_ty.kind() { element_ty } else { f0_ty } + } else { + bug!("should only be called with a SIMD type") + }; + let count = if let abi::Abi::Vector { count, .. } = bx.layout_of(simd_ty).abi { + count + } else { + bug!("should only be called with a SIMD type") + }; + (ty, count) + } + // macros for error handling: macro_rules! emit_error { ($msg: tt) => { @@ -792,7 +809,7 @@ fn generic_simd_intrinsic( _ => return_error!("`{}` is not an integral type", in_ty), }; require_simd!(arg_tys[1], "argument"); - let v_len = arg_tys[1].simd_size(tcx); + let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); require!( // Allow masks for vectors with fewer than 8 elements to be // represented with a u8 or i8. @@ -812,8 +829,6 @@ fn generic_simd_intrinsic( // every intrinsic below takes a SIMD vector as its first argument require_simd!(arg_tys[0], "input"); let in_ty = arg_tys[0]; - let in_elem = arg_tys[0].simd_type(tcx); - let in_len = arg_tys[0].simd_size(tcx); let comparison = match name { sym::simd_eq => Some(hir::BinOpKind::Eq), @@ -825,14 +840,15 @@ fn generic_simd_intrinsic( _ => None, }; + let (in_elem, in_len) = simd_ty_and_len(bx, arg_tys[0]); if let Some(cmp_op) = comparison { require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", in_len, in_ty, ret_ty, @@ -842,7 +858,7 @@ fn generic_simd_intrinsic( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, "expected return type with integer elements, found `{}` with non-integer `{}`", ret_ty, - ret_ty.simd_type(tcx) + out_ty ); return Ok(compare_simd_types( @@ -862,7 +878,7 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); require!( out_len == n, "expected return type of length {}, found `{}` with length {}", @@ -871,13 +887,13 @@ fn generic_simd_intrinsic( out_len ); require!( - in_elem == ret_ty.simd_type(tcx), + in_elem == out_ty, "expected return element type `{}` (element of input `{}`), \ - found `{}` with element type `{}`", + found `{}` with element type `{}`", in_elem, in_ty, ret_ty, - ret_ty.simd_type(tcx) + out_ty ); let total_len = u128::from(in_len) * 2; @@ -946,7 +962,7 @@ fn generic_simd_intrinsic( let m_elem_ty = in_elem; let m_len = in_len; require_simd!(arg_tys[1], "argument"); - let v_len = arg_tys[1].simd_size(tcx); + let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); require!( m_len == v_len, "mismatched lengths: mask length `{}` != other vector length `{}`", @@ -1171,25 +1187,27 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); // Of the same length: + let (_, out_len) = simd_ty_and_len(bx, arg_tys[1]); + let (_, out_len2) = simd_ty_and_len(bx, arg_tys[2]); require!( - in_len == arg_tys[1].simd_size(tcx), + in_len == out_len, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], - arg_tys[1].simd_size(tcx) + out_len ); require!( - in_len == arg_tys[2].simd_size(tcx), + in_len == out_len2, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], - arg_tys[2].simd_size(tcx) + out_len2 ); // The return type must match the first argument type @@ -1213,39 +1231,40 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { - ty::RawPtr(p) if p.ty == in_elem => { - (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) - } + let (element_ty0, _) = simd_ty_and_len(bx, arg_tys[0]); + let (element_ty1, _) = simd_ty_and_len(bx, arg_tys[1]); + let (pointer_count, underlying_ty) = match element_ty1.kind() { + ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)), _ => { require!( false, "expected element type `{}` of second argument `{}` \ - to be a pointer to the element type `{}` of the first \ - argument `{}`, found `{}` != `*_ {}`", - arg_tys[1].simd_type(tcx), + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*_ {}`", + element_ty1, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx), + element_ty1, in_elem ); unreachable!(); } }; assert!(pointer_count > 0); - assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx))); - assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind() { + let (element_ty2, _) = simd_ty_and_len(bx, arg_tys[2]); + match element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, "expected element type `{}` of third argument `{}` \ to be a signed integer type", - arg_tys[2].simd_type(tcx), + element_ty2, arg_tys[2] ); } @@ -1297,25 +1316,27 @@ fn generic_simd_intrinsic( require_simd!(arg_tys[2], "third"); // Of the same length: + let (_, element_len1) = simd_ty_and_len(bx, arg_tys[1]); + let (_, element_len2) = simd_ty_and_len(bx, arg_tys[2]); require!( - in_len == arg_tys[1].simd_size(tcx), + in_len == element_len1, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], - arg_tys[1].simd_size(tcx) + element_len1 ); require!( - in_len == arg_tys[2].simd_size(tcx), + in_len == element_len2, "expected {} argument with length {} (same as input type `{}`), \ - found `{}` with length {}", + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], - arg_tys[2].simd_size(tcx) + element_len2 ); // This counts how many pointers @@ -1336,39 +1357,42 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { + let (element_ty0, _element_len0) = simd_ty_and_len(bx, arg_tys[0]); + let (element_ty1, _element_len1) = simd_ty_and_len(bx, arg_tys[1]); + let (element_ty2, _element_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (pointer_count, underlying_ty) = match element_ty1.kind() { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { - (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) + (ptr_count(element_ty1), non_ptr(element_ty1)) } _ => { require!( false, "expected element type `{}` of second argument `{}` \ - to be a pointer to the element type `{}` of the first \ - argument `{}`, found `{}` != `*mut {}`", - arg_tys[1].simd_type(tcx), + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*mut {}`", + element_ty1, arg_tys[1], in_elem, in_ty, - arg_tys[1].simd_type(tcx), + element_ty1, in_elem ); unreachable!(); } }; assert!(pointer_count > 0); - assert_eq!(pointer_count - 1, ptr_count(arg_tys[0].simd_type(tcx))); - assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + assert_eq!(pointer_count - 1, ptr_count(element_ty0)); + assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind() { + match element_ty2.kind() { ty::Int(_) => (), _ => { require!( false, "expected element type `{}` of third argument `{}` \ - to be a signed integer type", - arg_tys[2].simd_type(tcx), + be a signed integer type", + element_ty2, arg_tys[2] ); } @@ -1565,7 +1589,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, if name == sym::simd_cast { require_simd!(ret_ty, "return"); - let out_len = ret_ty.simd_size(tcx); + let (out_elem, out_len) = simd_ty_and_len(bx, ret_ty); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ @@ -1576,8 +1600,6 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, out_len ); // casting cares about nominal type, not just structural type - let out_elem = ret_ty.simd_type(tcx); - if in_elem == out_elem { return Ok(args[0].immediate()); } @@ -1693,7 +1715,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, return_error!( "expected element type `{}` of vector type `{}` \ to be a signed or unsigned integer type", - arg_tys[0].simd_type(tcx), + simd_ty_and_len(bx, arg_tys[0]).0, arg_tys[0] ); } -- cgit 1.4.1-3-g733a5 From 045105b1a2ed4d93d5e72bc34fdce55e0b3e6dad Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Fri, 13 Nov 2020 14:32:03 +1000 Subject: remove internal simd_size_and_ty from llvm backend --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 51 ++++++++++------------------ compiler/rustc_middle/src/ty/sty.rs | 7 +++- 2 files changed, 23 insertions(+), 35 deletions(-) (limited to 'compiler/rustc_codegen_llvm/src') diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 2ea7d7ac2d8..3df0ab5d36c 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -740,23 +740,6 @@ fn generic_simd_intrinsic( llret_ty: &'ll Type, span: Span, ) -> Result<&'ll Value, ()> { - // Given a SIMD vector type `x` return the element type and the number of - // elements in the vector. - fn simd_ty_and_len(bx: &Builder<'a, 'll, 'tcx>, simd_ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { - let ty = if let ty::Adt(_def, _substs) = simd_ty.kind() { - let f0_ty = bx.layout_of(simd_ty).field(bx, 0).ty; - if let ty::Array(element_ty, _) = f0_ty.kind() { element_ty } else { f0_ty } - } else { - bug!("should only be called with a SIMD type") - }; - let count = if let abi::Abi::Vector { count, .. } = bx.layout_of(simd_ty).abi { - count - } else { - bug!("should only be called with a SIMD type") - }; - (ty, count) - } - // macros for error handling: macro_rules! emit_error { ($msg: tt) => { @@ -809,7 +792,7 @@ fn generic_simd_intrinsic( _ => return_error!("`{}` is not an integral type", in_ty), }; require_simd!(arg_tys[1], "argument"); - let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); + let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( // Allow masks for vectors with fewer than 8 elements to be // represented with a u8 or i8. @@ -840,11 +823,11 @@ fn generic_simd_intrinsic( _ => None, }; - let (in_elem, in_len) = simd_ty_and_len(bx, arg_tys[0]); + let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx()); if let Some(cmp_op) = comparison { require_simd!(ret_ty, "return"); - let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ @@ -878,7 +861,7 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); - let (out_ty, out_len) = simd_ty_and_len(bx, ret_ty); + let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx()); require!( out_len == n, "expected return type of length {}, found `{}` with length {}", @@ -962,7 +945,7 @@ fn generic_simd_intrinsic( let m_elem_ty = in_elem; let m_len = in_len; require_simd!(arg_tys[1], "argument"); - let (_, v_len) = simd_ty_and_len(bx, arg_tys[1]); + let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); require!( m_len == v_len, "mismatched lengths: mask length `{}` != other vector length `{}`", @@ -1187,8 +1170,8 @@ fn generic_simd_intrinsic( require_simd!(ret_ty, "return"); // Of the same length: - let (_, out_len) = simd_ty_and_len(bx, arg_tys[1]); - let (_, out_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected {} argument with length {} (same as input type `{}`), \ @@ -1231,8 +1214,8 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (element_ty0, _) = simd_ty_and_len(bx, arg_tys[0]); - let (element_ty1, _) = simd_ty_and_len(bx, arg_tys[1]); + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); let (pointer_count, underlying_ty) = match element_ty1.kind() { ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)), _ => { @@ -1256,7 +1239,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(element_ty0)); // The element type of the third argument must be a signed integer type of any width: - let (element_ty2, _) = simd_ty_and_len(bx, arg_tys[2]); + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); match element_ty2.kind() { ty::Int(_) => (), _ => { @@ -1316,8 +1299,8 @@ fn generic_simd_intrinsic( require_simd!(arg_tys[2], "third"); // Of the same length: - let (_, element_len1) = simd_ty_and_len(bx, arg_tys[1]); - let (_, element_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx()); require!( in_len == element_len1, "expected {} argument with length {} (same as input type `{}`), \ @@ -1357,9 +1340,9 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (element_ty0, _element_len0) = simd_ty_and_len(bx, arg_tys[0]); - let (element_ty1, _element_len1) = simd_ty_and_len(bx, arg_tys[1]); - let (element_ty2, _element_len2) = simd_ty_and_len(bx, arg_tys[2]); + let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx()); + let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx()); + let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx()); let (pointer_count, underlying_ty) = match element_ty1.kind() { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { (ptr_count(element_ty1), non_ptr(element_ty1)) @@ -1589,7 +1572,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, if name == sym::simd_cast { require_simd!(ret_ty, "return"); - let (out_elem, out_len) = simd_ty_and_len(bx, ret_ty); + let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); require!( in_len == out_len, "expected return type with length {} (same as input type `{}`), \ @@ -1715,7 +1698,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, return_error!( "expected element type `{}` of vector type `{}` \ to be a signed or unsigned integer type", - simd_ty_and_len(bx, arg_tys[0]).0, + arg_tys[0].simd_size_and_type(bx.tcx()).1, arg_tys[0] ); } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 8202d0f0ef1..d1f83d0a83e 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1963,7 +1963,12 @@ impl<'tcx> TyS<'tcx> { match self.kind() { Adt(def, substs) => { let variant = def.non_enum_variant(); - (variant.fields.len() as u64, variant.fields[0].ty(tcx, substs)) + let f0_ty = variant.fields[0].ty(tcx, substs); + + match f0_ty.kind() { + Array(f0_elem_ty, f0_len) => (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty), + _ => (variant.fields.len() as u64, f0_ty), + } } _ => bug!("`simd_size_and_type` called on invalid type"), } -- cgit 1.4.1-3-g733a5