Rollup merge of #95961 - RalfJung:gather-scatter, r=workingjubilee
implement SIMD gather/scatter via vector getelementptr Fixes https://github.com/rust-lang/portable-simd/issues/271 However, I don't *really* know what I am doing here... Cc ``@workingjubilee`` ``@calebzulawski`` I didn't do anything for cranelift -- ``@bjorn3`` not sure if it's okay for that backend to temporarily break. I'm happy to cherry-pick a patch that adds cranelift support. :)
This commit is contained in:
commit
ea131bca17
6 changed files with 64 additions and 0 deletions
|
@ -1839,6 +1839,27 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
|
||||||
simd_neg: Int => neg, Float => fneg;
|
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 {
|
if name == sym::simd_saturating_add || name == sym::simd_saturating_sub {
|
||||||
let lhs = args[0].immediate();
|
let lhs = args[0].immediate();
|
||||||
let rhs = args[1].immediate();
|
let rhs = args[1].immediate();
|
||||||
|
|
|
@ -1247,6 +1247,7 @@ symbols! {
|
||||||
simd,
|
simd,
|
||||||
simd_add,
|
simd_add,
|
||||||
simd_and,
|
simd_and,
|
||||||
|
simd_arith_offset,
|
||||||
simd_as,
|
simd_as,
|
||||||
simd_bitmask,
|
simd_bitmask,
|
||||||
simd_cast,
|
simd_cast,
|
||||||
|
|
|
@ -437,6 +437,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
|
||||||
| sym::simd_fpow
|
| sym::simd_fpow
|
||||||
| sym::simd_saturating_add
|
| sym::simd_saturating_add
|
||||||
| sym::simd_saturating_sub => (1, vec![param(0), param(0)], param(0)),
|
| 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_neg
|
||||||
| sym::simd_fsqrt
|
| sym::simd_fsqrt
|
||||||
| sym::simd_fsin
|
| sym::simd_fsin
|
||||||
|
|
|
@ -61,6 +61,10 @@ extern "platform-intrinsic" {
|
||||||
/// xor
|
/// xor
|
||||||
pub(crate) fn simd_xor<T>(x: T, y: T) -> T;
|
pub(crate) fn simd_xor<T>(x: T, y: T) -> T;
|
||||||
|
|
||||||
|
/// getelementptr (without inbounds)
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
pub(crate) fn simd_arith_offset<T, U>(ptrs: T, offsets: U) -> T;
|
||||||
|
|
||||||
/// fptoui/fptosi/uitofp/sitofp
|
/// fptoui/fptosi/uitofp/sitofp
|
||||||
/// casting floats to integers is truncating, so it is safe to convert values like e.g. 1.5
|
/// 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.
|
/// but the truncated value must fit in the target type or the result is poison.
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
//! Private implementation details of public gather/scatter APIs.
|
//! Private implementation details of public gather/scatter APIs.
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
use crate::simd::intrinsics;
|
||||||
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
|
use crate::simd::{LaneCount, Simd, SupportedLaneCount};
|
||||||
|
#[cfg(bootstrap)]
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
/// A vector of *const T.
|
/// A vector of *const T.
|
||||||
|
@ -21,12 +24,16 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
|
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
|
||||||
|
#[cfg(bootstrap)]
|
||||||
// Safety: converting pointers to usize and vice-versa is safe
|
// Safety: converting pointers to usize and vice-versa is safe
|
||||||
// (even if using that pointer is not)
|
// (even if using that pointer is not)
|
||||||
unsafe {
|
unsafe {
|
||||||
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
|
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
|
||||||
mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
|
mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
|
||||||
}
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
// Safety: this intrinsic doesn't have a precondition
|
||||||
|
unsafe { intrinsics::simd_arith_offset(self, addend) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,11 +56,15 @@ where
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
|
pub fn wrapping_add(self, addend: Simd<usize, LANES>) -> Self {
|
||||||
|
#[cfg(bootstrap)]
|
||||||
// Safety: converting pointers to usize and vice-versa is safe
|
// Safety: converting pointers to usize and vice-versa is safe
|
||||||
// (even if using that pointer is not)
|
// (even if using that pointer is not)
|
||||||
unsafe {
|
unsafe {
|
||||||
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
|
let x: Simd<usize, LANES> = mem::transmute_copy(&self);
|
||||||
mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
|
mem::transmute_copy(&{ x + (addend * Simd::splat(mem::size_of::<T>())) })
|
||||||
}
|
}
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
// Safety: this intrinsic doesn't have a precondition
|
||||||
|
unsafe { intrinsics::simd_arith_offset(self, addend) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
26
src/test/codegen/simd_arith_offset.rs
Normal file
26
src/test/codegen/simd_arith_offset.rs
Normal file
|
@ -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<T, U>(ptrs: T, offsets: U) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A vector of *const T.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(simd)]
|
||||||
|
pub struct SimdConstPtr<T, const LANES: usize>([*const T; LANES]);
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(simd)]
|
||||||
|
pub struct Simd<T, const LANES: usize>([T; LANES]);
|
||||||
|
|
||||||
|
// CHECK-LABEL: smoke
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn smoke(ptrs: SimdConstPtr<u8, 8>, offsets: Simd<usize, 8>) -> SimdConstPtr<u8, 8> {
|
||||||
|
// CHECK: getelementptr i8, <8 x i8*> %_3, <8 x i64> %_4
|
||||||
|
unsafe { simd_arith_offset(ptrs, offsets) }
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue