From e2866c0a673ebe073ebfdd4b48b5f09508d143f6 Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Fri, 22 Jul 2022 01:48:30 +0000 Subject: [PATCH] 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 a18f5b9dd7f..78afbdfc521 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 8a6941a4516..73e0e784ea2 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 7fe710cf8f4..d92fd475f90 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 00000000000..1d13720bcd3 --- /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); + } +}