From e2866c0a673ebe073ebfdd4b48b5f09508d143f6 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 22 Jul 2022 01:48:30 +0000 Subject: [PATCH 1/3] Add simd_cast_ptr, simd_expose_addr, and simd_from_exposed_addr intrinsics --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 79 ++++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 3 + compiler/rustc_typeck/src/check/intrinsic.rs | 6 +- src/test/ui/simd/intrinsic/ptr-cast.rs | 33 ++++++++ 4 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/simd/intrinsic/ptr-cast.rs diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index a18f5b9dd7f9c..78afbdfc521fd 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1704,6 +1704,85 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, bitwise_red!(simd_reduce_all: vector_reduce_and, true); bitwise_red!(simd_reduce_any: vector_reduce_or, true); + if name == sym::simd_cast_ptr { + require_simd!(ret_ty, "return"); + 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 `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", in_elem), + } + match out_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", out_elem), + } + + if in_elem == out_elem { + return Ok(args[0].immediate()); + } else { + return Ok(bx.pointercast(args[0].immediate(), llret_ty)); + } + } + + if name == sym::simd_expose_addr { + require_simd!(ret_ty, "return"); + 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 `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", in_elem), + } + match out_elem.kind() { + ty::Uint(ty::UintTy::Usize) => {} + _ => return_error!("expected `usize`, got `{}`", out_elem), + } + + return Ok(bx.ptrtoint(args[0].immediate(), llret_ty)); + } + + if name == sym::simd_from_exposed_addr { + require_simd!(ret_ty, "return"); + 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 `{}`), \ + found `{}` with length {}", + in_len, + in_ty, + ret_ty, + out_len + ); + + match in_elem.kind() { + ty::Uint(ty::UintTy::Usize) => {} + _ => return_error!("expected `usize`, got `{}`", in_elem), + } + match out_elem.kind() { + ty::RawPtr(_) => {} + _ => return_error!("expected pointer, got `{}`", out_elem), + } + + return Ok(bx.inttoptr(args[0].immediate(), llret_ty)); + } + if name == sym::simd_cast || name == sym::simd_as { require_simd!(ret_ty, "return"); let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx()); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a6941a451621..73e0e784ea24c 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1275,9 +1275,11 @@ symbols! { simd_as, simd_bitmask, simd_cast, + simd_cast_ptr, simd_ceil, simd_div, simd_eq, + simd_expose_addr, simd_extract, simd_fabs, simd_fcos, @@ -1293,6 +1295,7 @@ symbols! { simd_fmin, simd_fpow, simd_fpowi, + simd_from_exposed_addr, simd_fsin, simd_fsqrt, simd_gather, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index 7fe710cf8f4f2..d92fd475f90e5 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -461,7 +461,11 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()), sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)), sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)), - sym::simd_cast | sym::simd_as => (2, vec![param(0)], param(1)), + sym::simd_cast + | sym::simd_as + | sym::simd_cast_ptr + | sym::simd_expose_addr + | sym::simd_from_exposed_addr => (2, vec![param(0)], param(1)), sym::simd_bitmask => (2, vec![param(0)], param(1)), sym::simd_select | sym::simd_select_bitmask => { (2, vec![param(0), param(1), param(1)], param(1)) diff --git a/src/test/ui/simd/intrinsic/ptr-cast.rs b/src/test/ui/simd/intrinsic/ptr-cast.rs new file mode 100644 index 0000000000000..1d13720bcd31e --- /dev/null +++ b/src/test/ui/simd/intrinsic/ptr-cast.rs @@ -0,0 +1,33 @@ +// run-pass + +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_cast_ptr(x: T) -> U; + fn simd_expose_addr(x: T) -> U; + fn simd_from_exposed_addr(x: T) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct V([T; 2]); + +fn main() { + unsafe { + let mut foo = 4i8; + let ptr = &mut foo as *mut i8; + + let ptrs = V::<*mut i8>([ptr, core::ptr::null_mut()]); + + // change constness and type + let const_ptrs: V<*const u8> = simd_cast_ptr(ptrs); + + let exposed_addr: V = simd_expose_addr(const_ptrs); + + let from_exposed_addr: V<*mut i8> = simd_from_exposed_addr(exposed_addr); + + assert!(const_ptrs.0 == [ptr as *const u8, core::ptr::null()]); + assert!(exposed_addr.0 == [ptr as usize, 0]); + assert!(from_exposed_addr.0 == ptrs.0); + } +} From d00928aa69512c02490fcb228a70ad5c3f865613 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Thu, 4 Aug 2022 03:49:16 +0000 Subject: [PATCH 2/3] Require pointers to be sized --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 78afbdfc521fd..45463f96b8b80 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1718,11 +1718,19 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ); match in_elem.kind() { - ty::RawPtr(_) => {} + ty::RawPtr(p) => require!( + p.ty.is_sized(bx.tcx.at(span), ty::ParamEnv::reveal_all()), + "cannot cast pointer to unsized type `{}`", + in_elem + ), _ => return_error!("expected pointer, got `{}`", in_elem), } match out_elem.kind() { - ty::RawPtr(_) => {} + ty::RawPtr(p) => require!( + p.ty.is_sized(bx.tcx.at(span), ty::ParamEnv::reveal_all()), + "cannot cast to pointer to unsized type `{}`", + out_elem + ), _ => return_error!("expected pointer, got `{}`", out_elem), } From 3f2ce0624dfed866f758521b225e26c00b3250d8 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Sat, 27 Aug 2022 13:35:18 +0000 Subject: [PATCH 3/3] Check pointer metadata rather than pointee size --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 45463f96b8b80..82d34ce9d14ec 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1718,19 +1718,23 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ); match in_elem.kind() { - ty::RawPtr(p) => require!( - p.ty.is_sized(bx.tcx.at(span), ty::ParamEnv::reveal_all()), - "cannot cast pointer to unsized type `{}`", - in_elem - ), + ty::RawPtr(p) => { + let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { + bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + }); + assert!(!check_sized); // we are in codegen, so we shouldn't see these types + require!(metadata.is_unit(), "cannot cast fat pointer `{}`", in_elem) + } _ => return_error!("expected pointer, got `{}`", in_elem), } match out_elem.kind() { - ty::RawPtr(p) => require!( - p.ty.is_sized(bx.tcx.at(span), ty::ParamEnv::reveal_all()), - "cannot cast to pointer to unsized type `{}`", - out_elem - ), + ty::RawPtr(p) => { + let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| { + bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty) + }); + assert!(!check_sized); // we are in codegen, so we shouldn't see these types + require!(metadata.is_unit(), "cannot cast to fat pointer `{}`", out_elem) + } _ => return_error!("expected pointer, got `{}`", out_elem), }