forked from rust-lang/libc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add few ARM DSP Intrinsics (rust-lang#529)
* Add few ARM DSP Intrinsics - Signed saturating add/sub - Saturating four 8-bit integer add/sub - Saturating two 8-bit integer add/sub The intent is mainly to setup the module and to add all the rest in the future. Listed intrinsics are available on Cortex-M too (+dsp is required on some model except for M4). * Arm DSP: rebase and remove portable vector types Rebase everything on top of master since the portable vector types have been removed.
- Loading branch information
1 parent
5a20376
commit b9de11a
Showing
3 changed files
with
184 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
//! ARM DSP Intrinsics. | ||
#[cfg(test)] | ||
use stdsimd_test::assert_instr; | ||
|
||
types! { | ||
/// ARM-specific 32-bit wide vector of four packed `i8`. | ||
pub struct int8x4_t(i8, i8, i8, i8); | ||
/// ARM-specific 32-bit wide vector of four packed `u8`. | ||
pub struct uint8x4_t(u8, u8, u8, u8); | ||
/// ARM-specific 32-bit wide vector of two packed `i16`. | ||
pub struct int16x2_t(i16, i16); | ||
/// ARM-specific 32-bit wide vector of two packed `u16`. | ||
pub struct uint16x2_t(u16, u16); | ||
} | ||
|
||
extern "C" { | ||
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.qadd")] | ||
fn arm_qadd(a: i32, b: i32) -> i32; | ||
|
||
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.qsub")] | ||
fn arm_qsub(a: i32, b: i32) -> i32; | ||
|
||
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.qadd8")] | ||
fn arm_qadd8(a: i32, b: i32) -> i32; | ||
|
||
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.qsub8")] | ||
fn arm_qsub8(a: i32, b: i32) -> i32; | ||
|
||
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.qadd16")] | ||
fn arm_qadd16(a: i32, b: i32) -> i32; | ||
|
||
#[cfg_attr(target_arch = "arm", link_name = "llvm.arm.qsub16")] | ||
fn arm_qsub16(a: i32, b: i32) -> i32; | ||
} | ||
|
||
/// Signed saturating addition | ||
/// | ||
/// Returns the 32-bit saturating signed equivalent of a + b. | ||
#[inline] | ||
#[cfg_attr(test, assert_instr(qadd))] | ||
pub unsafe fn qadd(a: i32, b: i32) -> i32 { | ||
arm_qadd(a, b) | ||
} | ||
|
||
/// Signed saturating subtraction | ||
/// | ||
/// Returns the 32-bit saturating signed equivalent of a - b. | ||
#[inline] | ||
#[cfg_attr(test, assert_instr(qsub))] | ||
pub unsafe fn qsub(a: i32, b: i32) -> i32 { | ||
arm_qsub(a, b) | ||
} | ||
|
||
/// Saturating four 8-bit integer additions | ||
/// | ||
/// Returns the 8-bit signed equivalent of | ||
/// | ||
/// res[0] = a[0] + b[0] | ||
/// res[1] = a[1] + b[1] | ||
/// res[2] = a[2] + b[2] | ||
/// res[3] = a[3] + b[3] | ||
#[inline] | ||
#[cfg_attr(test, assert_instr(qadd8))] | ||
pub unsafe fn qadd8(a: int8x4_t, b: int8x4_t) -> int8x4_t { | ||
::mem::transmute(arm_qadd8(::mem::transmute(a), ::mem::transmute(b))) | ||
} | ||
|
||
/// Saturating two 8-bit integer subtraction | ||
/// | ||
/// Returns the 8-bit signed equivalent of | ||
/// | ||
/// res[0] = a[0] - b[0] | ||
/// res[1] = a[1] - b[1] | ||
/// res[2] = a[2] - b[2] | ||
/// res[3] = a[3] - b[3] | ||
#[inline] | ||
#[cfg_attr(test, assert_instr(qsub8))] | ||
pub unsafe fn qsub8(a: int8x4_t, b: int8x4_t) -> int8x4_t { | ||
::mem::transmute(arm_qsub8(::mem::transmute(a), ::mem::transmute(b))) | ||
} | ||
|
||
/// Saturating two 16-bit integer subtraction | ||
/// | ||
/// Returns the 16-bit signed equivalent of | ||
/// | ||
/// res[0] = a[0] - b[0] | ||
/// res[1] = a[1] - b[1] | ||
#[inline] | ||
#[cfg_attr(test, assert_instr(qsub16))] | ||
pub unsafe fn qsub16(a: int16x2_t, b: int16x2_t) -> int16x2_t { | ||
::mem::transmute(arm_qsub16(::mem::transmute(a), ::mem::transmute(b))) | ||
} | ||
|
||
/// Saturating two 16-bit integer additions | ||
/// | ||
/// Returns the 16-bit signed equivalent of | ||
/// | ||
/// res[0] = a[0] + b[0] | ||
/// res[1] = a[1] + b[1] | ||
#[inline] | ||
#[cfg_attr(test, assert_instr(qadd16))] | ||
pub unsafe fn qadd16(a: int16x2_t, b: int16x2_t) -> int16x2_t { | ||
::mem::transmute(arm_qadd16(::mem::transmute(a), ::mem::transmute(b))) | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use coresimd::arm::*; | ||
use coresimd::simd::*; | ||
use std::mem; | ||
use stdsimd_test::simd_test; | ||
|
||
#[test] | ||
fn qadd() { | ||
unsafe { | ||
assert_eq!(dsp::qadd(-10, 60), 50); | ||
assert_eq!(dsp::qadd(::std::i32::MAX, 10), ::std::i32::MAX); | ||
assert_eq!(dsp::qadd(::std::i32::MIN, -10), ::std::i32::MIN); | ||
} | ||
} | ||
|
||
#[test] | ||
fn qsub() { | ||
unsafe { | ||
assert_eq!(dsp::qsub(10, 60), -50); | ||
assert_eq!(dsp::qsub(::std::i32::MAX, -10), ::std::i32::MAX); | ||
assert_eq!(dsp::qsub(::std::i32::MIN, 10), ::std::i32::MIN); | ||
} | ||
} | ||
|
||
#[test] | ||
fn qadd8() { | ||
unsafe { | ||
let a = i8x4::new(1, 2, 3, ::std::i8::MAX); | ||
let b = i8x4::new(2, -1, 0, 1); | ||
let c = i8x4::new(3, 1, 3, ::std::i8::MAX); | ||
let r: i8x4 = ::mem::transmute(dsp::qadd8(::mem::transmute(a), ::mem::transmute(b))); | ||
assert_eq!(r, c); | ||
} | ||
} | ||
|
||
#[test] | ||
fn qsub8() { | ||
unsafe { | ||
let a = i8x4::new(1, 2, 3, ::std::i8::MIN); | ||
let b = i8x4::new(2, -1, 0, 1); | ||
let c = i8x4::new(-1, 3, 3, ::std::i8::MIN); | ||
let r: i8x4 = ::mem::transmute(dsp::qsub8(::mem::transmute(a),::mem::transmute(b))); | ||
assert_eq!(r, c); | ||
} | ||
} | ||
|
||
#[test] | ||
fn qadd16() { | ||
unsafe { | ||
let a = i16x2::new(1, 2); | ||
let b = i16x2::new(2, -1); | ||
let c = i16x2::new(3, 1); | ||
let r: i16x2 = ::mem::transmute(dsp::qadd16(::mem::transmute(a),::mem::transmute(b))); | ||
assert_eq!(r, c); | ||
} | ||
} | ||
|
||
#[test] | ||
fn qsub16() { | ||
unsafe { | ||
let a = i16x2::new(10, 20); | ||
let b = i16x2::new(20, -10); | ||
let c = i16x2::new(-10, 30); | ||
let r: i16x2 = ::mem::transmute(dsp::qsub16(::mem::transmute(a), ::mem::transmute(b))); | ||
assert_eq!(r, c); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters