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)
             }

Reply via email to