Dual 16-bit Signed Multiply with Addition/Subtraction (#543)

Add support for `smlad` and `smlsd`.

- `smlad`: Dual 16-bit Signed Multiply with Addition and
           32-bit accumulation

- `smlsd`: Dual 16-bit Signed Multiply with Subtraction and
           32-bit accumulation
This commit is contained in:
Paolo Teti 2018-07-27 19:00:28 +02:00 committed by Alex Crichton
parent 923ed00d4d
commit 608265e15d

View File

@ -1,4 +1,8 @@
//! ARM DSP Intrinsics.
//!
//! Based on "Arm C Language Extensions (ACLE) Version Q2 2018"
//!
//! https://developer.arm.com/products/software-development-tools/compilers/arm-compiler-5/docs/101028/0006
#[cfg(test)]
use stdsimd_test::assert_instr;
@ -54,6 +58,12 @@ extern "C" {
#[link_name = "llvm.arm.sasx"]
fn arm_sasx(a: i32, b: i32) -> i32;
#[link_name = "llvm.arm.smlad"]
fn arm_smlad(a: i32, b: i32, c: i32) -> i32;
#[link_name = "llvm.arm.smlsd"]
fn arm_smlsd(a: i32, b: i32, c: i32) -> i32;
#[link_name = "llvm.arm.sel"]
fn arm_sel(a: i32, b: i32) -> i32;
@ -201,6 +211,28 @@ pub unsafe fn sadd8(a: int8x4_t, b: int8x4_t) -> int8x4_t {
dsp_call!(arm_sadd8, a, b)
}
/// Dual 16-bit Signed Multiply with Addition of products
/// and 32-bit accumulation.
///
/// Returns the 16-bit signed equivalent of
/// res = a\[0\] * b\[0\] + a\[1\] * b\[1\] + c
#[inline]
#[cfg_attr(test, assert_instr(smlad))]
pub unsafe fn smlad(a: int16x2_t , b: int16x2_t, c: i32) -> i32 {
arm_smlad(::mem::transmute(a), ::mem::transmute(b), c)
}
/// Dual 16-bit Signed Multiply with Subtraction of products
/// and 32-bit accumulation and overflow detection.
///
/// Returns the 16-bit signed equivalent of
/// res = a\[0\] * b\[0\] - a\[1\] * b\[1\] + c
#[inline]
#[cfg_attr(test, assert_instr(smlsd))]
pub unsafe fn smlsd(a: int16x2_t , b: int16x2_t, c: i32) -> i32 {
arm_smlsd(::mem::transmute(a), ::mem::transmute(b), c)
}
/// Returns the 16-bit signed equivalent of
///
/// res\[0\] = a\[0\] - b\[1\]
@ -213,6 +245,8 @@ pub unsafe fn sasx(a: int16x2_t, b: int16x2_t) -> int16x2_t {
dsp_call!(arm_sasx, a, b)
}
/// Select bytes from each operand according to APSR GE flags
///
/// Returns the equivalent of
///
/// res\[0\] = GE\[0\] ? a\[0\] : b\[0\]
@ -480,6 +514,26 @@ mod tests {
}
}
#[test]
fn smlad() {
unsafe {
let a = i16x2::new(1, 2);
let b = i16x2::new(3, 4);
let r = dsp::smlad(::mem::transmute(a), ::mem::transmute(b), 10);
assert_eq!(r, (1 * 3) + (2 * 4) + 10);
}
}
#[test]
fn smlsd() {
unsafe {
let a = i16x2::new(1, 2);
let b = i16x2::new(3, 4);
let r = dsp::smlsd(::mem::transmute(a), ::mem::transmute(b), 10);
assert_eq!(r, ((1 * 3) - (2 * 4)) + 10);
}
}
#[test]
fn sel() {
unsafe {