From 7f945b2b5b0d8123d6031bb655d2a9fe5c71ee01 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Apr 2022 11:00:55 -0400 Subject: [PATCH 1/3] add simd_arith_offset intrinsics --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 21 ++++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_typeck/src/check/intrinsic.rs | 1 + 3 files changed, 23 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 48840c76cac8b..cf9cf1b70aaa7 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1839,6 +1839,27 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, simd_neg: Int => neg, Float => fneg; } + if name == sym::simd_arith_offset { + // This also checks that the first operand is a ptr type. + let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { + span_bug!(span, "must be called with a vector of pointer types as first argument") + }); + let layout = bx.layout_of(pointee.ty); + let ptrs = args[0].immediate(); + // The second argument must be a ptr-sized integer. + // (We don't care about the signedness, this is wrapping anyway.) + let (_offsets_len, offsets_elem) = arg_tys[1].simd_size_and_type(bx.tcx()); + if !matches!(offsets_elem.kind(), ty::Int(ty::IntTy::Isize) | ty::Uint(ty::UintTy::Usize)) { + span_bug!( + span, + "must be called with a vector of pointer-sized integers as second argument" + ); + } + let offsets = args[1].immediate(); + + return Ok(bx.gep(bx.backend_type(layout), ptrs, &[offsets])); + } + if name == sym::simd_saturating_add || name == sym::simd_saturating_sub { let lhs = args[0].immediate(); let rhs = args[1].immediate(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dc4d10f699c75..1070cb1cd9ed8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1245,6 +1245,7 @@ symbols! { simd, simd_add, simd_and, + simd_arith_offset, simd_as, simd_bitmask, simd_cast, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index cd6b1115ed806..8bad238f5976d 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -437,6 +437,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) | sym::simd_fpow | sym::simd_saturating_add | sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)), + sym::simd_arith_offset => (2, vec![param(0), param(1)], param(0)), sym::simd_neg | sym::simd_fsqrt | sym::simd_fsin From e886dc52eedf3d074c6cc66f0518a996f7bbe735 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Apr 2022 11:01:22 -0400 Subject: [PATCH 2/3] portable-simd: use simd_arith_offset to avoid ptr-int transmutation --- .../portable-simd/crates/core_simd/src/intrinsics.rs | 4 ++++ .../portable-simd/crates/core_simd/src/vector/ptr.rs | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/library/portable-simd/crates/core_simd/src/intrinsics.rs b/library/portable-simd/crates/core_simd/src/intrinsics.rs index 426c4de6ab1ea..82508c6882dab 100644 --- a/library/portable-simd/crates/core_simd/src/intrinsics.rs +++ b/library/portable-simd/crates/core_simd/src/intrinsics.rs @@ -61,6 +61,10 @@ extern "platform-intrinsic" { /// xor pub(crate) fn simd_xor(x: T, y: T) -> T; + /// getelementptr (without inbounds) + #[cfg(not(bootstrap))] + pub(crate) fn simd_arith_offset(ptrs: T, offsets: U) -> T; + /// fptoui/fptosi/uitofp/sitofp /// casting floats to integers is truncating, so it is safe to convert values like e.g. 1.5 /// but the truncated value must fit in the target type or the result is poison. diff --git a/library/portable-simd/crates/core_simd/src/vector/ptr.rs b/library/portable-simd/crates/core_simd/src/vector/ptr.rs index 417d255c28d63..68a9c67f795af 100644 --- a/library/portable-simd/crates/core_simd/src/vector/ptr.rs +++ b/library/portable-simd/crates/core_simd/src/vector/ptr.rs @@ -1,5 +1,8 @@ //! Private implementation details of public gather/scatter APIs. +#[cfg(not(bootstrap))] +use crate::simd::intrinsics; use crate::simd::{LaneCount, Simd, SupportedLaneCount}; +#[cfg(bootstrap)] use core::mem; /// A vector of *const T. @@ -21,12 +24,16 @@ where #[inline] #[must_use] pub fn wrapping_add(self, addend: Simd) -> Self { + #[cfg(bootstrap)] // Safety: converting pointers to usize and vice-versa is safe // (even if using that pointer is not) unsafe { let x: Simd = mem::transmute_copy(&self); mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::())) }) } + #[cfg(not(bootstrap))] + // Safety: this intrinsic doesn't have a precondition + unsafe { intrinsics::simd_arith_offset(self, addend) } } } @@ -49,11 +56,15 @@ where #[inline] #[must_use] pub fn wrapping_add(self, addend: Simd) -> Self { + #[cfg(bootstrap)] // Safety: converting pointers to usize and vice-versa is safe // (even if using that pointer is not) unsafe { let x: Simd = mem::transmute_copy(&self); mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::())) }) } + #[cfg(not(bootstrap))] + // Safety: this intrinsic doesn't have a precondition + unsafe { intrinsics::simd_arith_offset(self, addend) } } } From 73f9571d4f45fb56a2076d2c43d21ff618c396d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Apr 2022 22:25:52 -0400 Subject: [PATCH 3/3] add codegen smoke test --- src/test/codegen/simd_arith_offset.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/test/codegen/simd_arith_offset.rs diff --git a/src/test/codegen/simd_arith_offset.rs b/src/test/codegen/simd_arith_offset.rs new file mode 100644 index 0000000000000..a858270d4e76d --- /dev/null +++ b/src/test/codegen/simd_arith_offset.rs @@ -0,0 +1,26 @@ +// compile-flags: -C no-prepopulate-passes +// only-64bit (because the LLVM type of i64 for usize shows up) +// + +#![crate_type = "lib"] +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + pub(crate) fn simd_arith_offset(ptrs: T, offsets: U) -> T; +} + +/// A vector of *const T. +#[derive(Debug, Copy, Clone)] +#[repr(simd)] +pub struct SimdConstPtr([*const T; LANES]); + +#[derive(Debug, Copy, Clone)] +#[repr(simd)] +pub struct Simd([T; LANES]); + +// CHECK-LABEL: smoke +#[no_mangle] +pub fn smoke(ptrs: SimdConstPtr, offsets: Simd) -> SimdConstPtr { + // CHECK: getelementptr i8, <8 x i8*> %_3, <8 x i64> %_4 + unsafe { simd_arith_offset(ptrs, offsets) } +}