You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by pa...@apache.org on 2019/03/15 01:52:03 UTC
[arrow] branch new_divide created (now 12a24e9)
This is an automated email from the ASF dual-hosted git repository.
paddyhoran pushed a change to branch new_divide
in repository https://gitbox.apache.org/repos/asf/arrow.git.
at 12a24e9 A clean build
This branch includes the following new commits:
new 12a24e9 A clean build
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
[arrow] 01/01: A clean build
Posted by pa...@apache.org.
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 <pa...@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)
}