This is an automated email from the ASF dual-hosted git repository. paddyhoran pushed a commit to branch new_divide in repository https://gitbox.apache.org/repos/asf/arrow.git
commit 12a24e917bfdac1760200f2e5f4afed54d608411 Author: Paddy Horan <paddyho...@hotmail.com> AuthorDate: Thu Mar 14 20:58:57 2019 -0400 A clean build --- rust/arrow/src/compute/arithmetic_kernels.rs | 73 ++++++++++++++++++++++++++-- rust/arrow/src/compute/util.rs | 35 +++++++++++++ rust/arrow/src/datatypes.rs | 41 ++++++++++++++++ 3 files changed, 146 insertions(+), 3 deletions(-) diff --git a/rust/arrow/src/compute/arithmetic_kernels.rs b/rust/arrow/src/compute/arithmetic_kernels.rs index 2566002..d7f0b32 100644 --- a/rust/arrow/src/compute/arithmetic_kernels.rs +++ b/rust/arrow/src/compute/arithmetic_kernels.rs @@ -27,13 +27,13 @@ use std::ops::{Add, Div, Mul, Sub}; use std::slice::from_raw_parts_mut; use std::sync::Arc; -use num::Zero; +use num::{One, Zero}; use crate::array::*; use crate::array_data::ArrayData; use crate::buffer::MutableBuffer; use crate::builder::PrimitiveBuilder; -use crate::compute::util::apply_bin_op_to_option_bitmap; +use crate::compute::util::{apply_bin_op_to_option_bitmap, is_valid}; use crate::datatypes; use crate::error::{ArrowError, Result}; @@ -123,6 +123,68 @@ where Ok(PrimitiveArray::<T>::from(Arc::new(data))) } +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn simd_divide<T>( + left: &PrimitiveArray<T>, + right: &PrimitiveArray<T>, +) -> Result<PrimitiveArray<T>> + where + T: datatypes::ArrowNumericType, + T::Native: One + Zero, + T::Simd: Add<Output = T::Simd> + + Sub<Output = T::Simd> + + Mul<Output = T::Simd> + + Div<Output = T::Simd>, +{ + if left.len() != right.len() { + return Err(ArrowError::ComputeError( + "Cannot perform math operation on arrays of different length".to_string(), + )); + } + + let null_bit_buffer = apply_bin_op_to_option_bitmap( + left.data().null_bitmap(), + right.data().null_bitmap(), + |a, b| a & b, + )?; + + let lanes = T::lanes(); + let buffer_size = left.len() * mem::size_of::<T::Native>(); + let mut result = MutableBuffer::new(buffer_size).with_bitset(buffer_size, false); + + for i in (0..left.len()).step_by(lanes) { + let simd_right_raw_check = T::load(right.value_slice(i, lanes)); + let simd_right_check = unsafe{T::mask_select(is_valid::<T>(&None, i, lanes, right.len()), simd_right_raw_check, T::init(T::Native::one()))}; + let is_zero = T::eq(T::init(T::Native::zero()), simd_right_check); + if T::mask_any(is_zero) { + return Err(ArrowError::DivideByZero); + } + let simd_right_raw = T::load(right.value_slice(i, lanes)); + let simd_right = unsafe{T::mask_select(is_valid::<T>(&None, i, lanes, right.len()), simd_right_raw, T::init(T::Native::one()))}; + let simd_left = T::load(left.value_slice(i, lanes)); + let simd_result = T::bin_op(simd_left, simd_right, |a, b| a / b); + + let result_slice: &mut [T::Native] = unsafe { + from_raw_parts_mut( + (result.data_mut().as_mut_ptr() as *mut T::Native).offset(i as isize), + lanes, + ) + }; + T::write(simd_result, result_slice); + } + + let data = ArrayData::new( + T::get_data_type(), + left.len(), + None, + null_bit_buffer, + left.offset(), + vec![result.freeze()], + vec![], + ); + Ok(PrimitiveArray::<T>::from(Arc::new(data))) +} + /// Perform `left + right` operation on two arrays. If either left or right value is null /// then the result is also null. pub fn add<T>( @@ -199,8 +261,13 @@ where + Sub<Output = T::Native> + Mul<Output = T::Native> + Div<Output = T::Native> - + Zero, + + Zero + + One, { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + return simd_divide(&left, &right); + + #[allow(unreachable_code)] math_op(left, right, |a, b| { if b.is_zero() { Err(ArrowError::DivideByZero) diff --git a/rust/arrow/src/compute/util.rs b/rust/arrow/src/compute/util.rs index 55726b8..64f060a 100644 --- a/rust/arrow/src/compute/util.rs +++ b/rust/arrow/src/compute/util.rs @@ -20,6 +20,7 @@ use crate::bitmap::Bitmap; use crate::buffer::Buffer; use crate::error::Result; +use crate::datatypes::*; /// Applies a given binary operation, `op`, to two references to `Option<Bitmap>`'s. /// @@ -44,6 +45,40 @@ where } } + +pub unsafe fn is_valid<T>(bitmap: &Option<Bitmap>, i: usize, lanes: usize, len: usize) -> T::SimdMask +where + T: ArrowNumericType, +{ + + // Validity based on the length of the Array + let upper_bound = i + lanes; + let mut length_based_validity = T::new_mask(true); + for j in upper_bound..len { + length_based_validity = T::mask_set(length_based_validity, j - i, false); + } + + match &bitmap { + Some(_) => length_based_validity, + None => length_based_validity, + } + +// let length_based_validity = if upper_bound < len { +// T::SimdMask::splat(true) +// } else { +// let +// u8x64::splat(255) +// }; +// +// match &buffer { +// Some(ref buf) => { +// let data = from_raw_parts(buffer.raw_data().offset(i as isize), lanes); +// u8x64::from_slice_unaligned_unchecked(data) +// } +// None => length_based_validity +// } +} + #[cfg(test)] mod tests { use super::*; diff --git a/rust/arrow/src/datatypes.rs b/rust/arrow/src/datatypes.rs index e0b6d70..2edcfbe 100644 --- a/rust/arrow/src/datatypes.rs +++ b/rust/arrow/src/datatypes.rs @@ -265,12 +265,26 @@ where /// The number of SIMD lanes available fn lanes() -> usize; + /// Initializes a SIMD register to a constant value + fn init(value: Self::Native) -> Self::Simd; + /// Loads a slice into a SIMD register fn load(slice: &[Self::Native]) -> Self::Simd; + /// Creates a new SIMD mask for this SIMD type filling it with `value` + fn new_mask(value: bool) -> Self::SimdMask; + /// Gets the value of a single lane in a SIMD mask fn mask_get(mask: &Self::SimdMask, idx: usize) -> bool; + /// Sets the value of a single lane of a SIMD mask + fn mask_set(mask: Self::SimdMask, idx: usize, value: bool) -> Self::SimdMask; + + /// Selects elements of `a` and `b` using `mask` + fn mask_select(mask: Self::SimdMask, a: Self::Simd, b: Self::Simd) -> Self::Simd; + + fn mask_any(mask: Self::SimdMask) -> bool; + /// Performs a SIMD binary operation fn bin_op<F: Fn(Self::Simd, Self::Simd) -> Self::Simd>( left: Self::Simd, @@ -278,6 +292,8 @@ where op: F, ) -> Self::Simd; +// fn div(left: Self::Simd, right: Self::Simd, mask: Self::SimdMask) -> Self::Simd; + // SIMD version of equal fn eq(left: Self::Simd, right: Self::Simd) -> Self::SimdMask; @@ -315,14 +331,35 @@ macro_rules! make_numeric_type { Self::Simd::lanes() } + fn init(value: Self::Native) -> Self::Simd { + Self::Simd::splat(value) + } + fn load(slice: &[Self::Native]) -> Self::Simd { unsafe { Self::Simd::from_slice_unaligned_unchecked(slice) } } + fn new_mask(value: bool) -> Self::SimdMask { + Self::SimdMask::splat(value) + } + fn mask_get(mask: &Self::SimdMask, idx: usize) -> bool { unsafe { mask.extract_unchecked(idx) } } + fn mask_set(mask: Self::SimdMask, idx: usize, value: bool) -> Self::SimdMask { + unsafe { mask.replace_unchecked(idx, value) } + } + + /// Selects elements of `a` and `b` using `mask` + fn mask_select(mask: Self::SimdMask, a: Self::Simd, b: Self::Simd) -> Self::Simd { + mask.select(a, b) + } + + fn mask_any(mask: Self::SimdMask) -> bool { + mask.any() + } + fn bin_op<F: Fn(Self::Simd, Self::Simd) -> Self::Simd>( left: Self::Simd, right: Self::Simd, @@ -331,6 +368,10 @@ macro_rules! make_numeric_type { op(left, right) } +// fn div(left: Self::Simd, right: Self::Simd, mask: Self::SimdMask) -> Self::Simd { +// Self::bin_op(left, Self::mask_select(mask, right, Self::Simd::splat($native_ty::one())), |a, b| a / b) +// } + fn eq(left: Self::Simd, right: Self::Simd) -> Self::SimdMask { left.eq(right) }