about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-09-17 15:31:07 +0530
committerGitHub <noreply@github.com>2022-09-17 15:31:07 +0530
commitcbd561d41f61201decae3adb45fe827d30aa96ec (patch)
tree61f8f4dce1a826fd0cb071559ab21f7fa925c8b8
parent3ad81e0dd854d0edaeea7429fba6c2255c6a27ef (diff)
parent3f2ce0624dfed866f758521b225e26c00b3250d8 (diff)
downloadrust-cbd561d41f61201decae3adb45fe827d30aa96ec.tar.gz
rust-cbd561d41f61201decae3adb45fe827d30aa96ec.zip
Rollup merge of #98441 - calebzulawski:simd_as, r=oli-obk
Implement simd_as for pointers

Expands `simd_as` (and `simd_cast`) to handle pointer-to-pointer, pointer-to-integer, and integer-to-pointer conversions.

cc ``@programmerjake`` ``@thomcc``
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs91
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs6
-rw-r--r--src/test/ui/simd/intrinsic/ptr-cast.rs33
4 files changed, 132 insertions, 1 deletions
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 3d789904707..a640de42a6a 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1705,6 +1705,97 @@ 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(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) => {
+                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),
+        }
+
+        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 fcc22e22cc1..ae4d1a4635b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1322,9 +1322,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,
@@ -1340,6 +1342,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 4fa33da50c9..c7425ff7865 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -477,7 +477,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<T, U>(x: T) -> U;
+    fn simd_expose_addr<T, U>(x: T) -> U;
+    fn simd_from_exposed_addr<T, U>(x: T) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct V<T>([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<usize> = 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);
+    }
+}