dsp.rs - source
Description: Source of the Rust file `library/core/src/../../stdarch/crates/core_arch/src/arm/dsp.rs`.

#
core/stdarch/crates/core_arch/src/arm/
dsp.rs

    1//! # References:
    2//!
    3//! - Section 8.3 "16-bit multiplications"
    4//!
    5//! Intrinsics that could live here:
    6//!
    7//! - \[x\] __smulbb
    8//! - \[x\] __smulbt
    9//! - \[x\] __smultb
    10//! - \[x\] __smultt
    11//! - \[x\] __smulwb
    12//! - \[x\] __smulwt
    13//! - \[x\] __qadd
    14//! - \[x\] __qsub
    15//! - \[x\] __qdbl
    16//! - \[x\] __smlabb
    17//! - \[x\] __smlabt
    18//! - \[x\] __smlatb
    19//! - \[x\] __smlatt
    20//! - \[x\] __smlawb
    21//! - \[x\] __smlawt
    22
    23#[cfg(test)]
    24use stdarch_test::assert_instr;
    25
    26unsafe extern "unadjusted" {
    27    #[link_name = "llvm.arm.smulbb"]
    28    fn arm_smulbb(a: i32, b: i32) -> i32;
    29
    30    #[link_name = "llvm.arm.smulbt"]
    31    fn arm_smulbt(a: i32, b: i32) -> i32;
    32
    33    #[link_name = "llvm.arm.smultb"]
    34    fn arm_smultb(a: i32, b: i32) -> i32;
    35
    36    #[link_name = "llvm.arm.smultt"]
    37    fn arm_smultt(a: i32, b: i32) -> i32;
    38
    39    #[link_name = "llvm.arm.smulwb"]
    40    fn arm_smulwb(a: i32, b: i32) -> i32;
    41
    42    #[link_name = "llvm.arm.smulwt"]
    43    fn arm_smulwt(a: i32, b: i32) -> i32;
    44
    45    #[link_name = "llvm.arm.qadd"]
    46    fn arm_qadd(a: i32, b: i32) -> i32;
    47
    48    #[link_name = "llvm.arm.qsub"]
    49    fn arm_qsub(a: i32, b: i32) -> i32;
    50
    51    #[link_name = "llvm.arm.smlabb"]
    52    fn arm_smlabb(a: i32, b: i32, c: i32) -> i32;
    53
    54    #[link_name = "llvm.arm.smlabt"]
    55    fn arm_smlabt(a: i32, b: i32, c: i32) -> i32;
    56
    57    #[link_name = "llvm.arm.smlatb"]
    58    fn arm_smlatb(a: i32, b: i32, c: i32) -> i32;
    59
    60    #[link_name = "llvm.arm.smlatt"]
    61    fn arm_smlatt(a: i32, b: i32, c: i32) -> i32;
    62
    63    #[link_name = "llvm.arm.smlawb"]
    64    fn arm_smlawb(a: i32, b: i32, c: i32) -> i32;
    65
    66    #[link_name = "llvm.arm.smlawt"]
    67    fn arm_smlawt(a: i32, b: i32, c: i32) -> i32;
    68}
    69
    70/// Insert a SMULBB instruction
    71///
    72/// Returns the equivalent of a\[0\] * b\[0\]
    73/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    74#[inline]
    75#[cfg_attr(test, assert_instr(smulbb))]
    76#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    77pub unsafe fn __smulbb(a: i32, b: i32) -> i32 {
    78    arm_smulbb(a, b)
    79}
    80
    81/// Insert a SMULTB instruction
    82///
    83/// Returns the equivalent of a\[0\] * b\[1\]
    84/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    85#[inline]
    86#[cfg_attr(test, assert_instr(smultb))]
    87#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    88pub unsafe fn __smultb(a: i32, b: i32) -> i32 {
    89    arm_smultb(a, b)
    90}
    91
    92/// Insert a SMULTB instruction
    93///
    94/// Returns the equivalent of a\[1\] * b\[0\]
    95/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    96#[inline]
    97#[cfg_attr(test, assert_instr(smulbt))]
    98#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    99pub unsafe fn __smulbt(a: i32, b: i32) -> i32 {
    100    arm_smulbt(a, b)
    101}
    102
    103/// Insert a SMULTT instruction
    104///
    105/// Returns the equivalent of a\[1\] * b\[1\]
    106/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    107#[inline]
    108#[cfg_attr(test, assert_instr(smultt))]
    109#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    110pub unsafe fn __smultt(a: i32, b: i32) -> i32 {
    111    arm_smultt(a, b)
    112}
    113
    114/// Insert a SMULWB instruction
    115///
    116/// Multiplies the 32-bit signed first operand with the low halfword
    117/// (as a 16-bit signed integer) of the second operand.
    118/// Return the top 32 bits of the 48-bit product
    119#[inline]
    120#[cfg_attr(test, assert_instr(smulwb))]
    121#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    122pub unsafe fn __smulwb(a: i32, b: i32) -> i32 {
    123    arm_smulwb(a, b)
    124}
    125
    126/// Insert a SMULWT instruction
    127///
    128/// Multiplies the 32-bit signed first operand with the high halfword
    129/// (as a 16-bit signed integer) of the second operand.
    130/// Return the top 32 bits of the 48-bit product
    131#[inline]
    132#[cfg_attr(test, assert_instr(smulwt))]
    133#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    134pub unsafe fn __smulwt(a: i32, b: i32) -> i32 {
    135    arm_smulwt(a, b)
    136}
    137
    138/// Signed saturating addition
    139///
    140/// Returns the 32-bit saturating signed equivalent of a + b.
    141/// Sets the Q flag if saturation occurs.
    142#[inline]
    143#[cfg_attr(test, assert_instr(qadd))]
    144#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    145pub unsafe fn __qadd(a: i32, b: i32) -> i32 {
    146    arm_qadd(a, b)
    147}
    148
    149/// Signed saturating subtraction
    150///
    151/// Returns the 32-bit saturating signed equivalent of a - b.
    152/// Sets the Q flag if saturation occurs.
    153#[inline]
    154#[cfg_attr(test, assert_instr(qsub))]
    155#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    156pub unsafe fn __qsub(a: i32, b: i32) -> i32 {
    157    arm_qsub(a, b)
    158}
    159
    160/// Insert a QADD instruction
    161///
    162/// Returns the 32-bit saturating signed equivalent of a + a
    163/// Sets the Q flag if saturation occurs.
    164#[inline]
    165#[cfg_attr(test, assert_instr(qadd))]
    166#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    167pub unsafe fn __qdbl(a: i32) -> i32 {
    168    arm_qadd(a, a)
    169}
    170
    171/// Insert a SMLABB instruction
    172///
    173/// Returns the equivalent of a\[0\] * b\[0\] + c
    174/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    175/// Sets the Q flag if overflow occurs on the addition.
    176#[inline]
    177#[cfg_attr(test, assert_instr(smlabb))]
    178#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    179pub unsafe fn __smlabb(a: i32, b: i32, c: i32) -> i32 {
    180    arm_smlabb(a, b, c)
    181}
    182
    183/// Insert a SMLABT instruction
    184///
    185/// Returns the equivalent of a\[0\] * b\[1\] + c
    186/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    187/// Sets the Q flag if overflow occurs on the addition.
    188#[inline]
    189#[cfg_attr(test, assert_instr(smlabt))]
    190#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    191pub unsafe fn __smlabt(a: i32, b: i32, c: i32) -> i32 {
    192    arm_smlabt(a, b, c)
    193}
    194
    195/// Insert a SMLATB instruction
    196///
    197/// Returns the equivalent of a\[1\] * b\[0\] + c
    198/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    199/// Sets the Q flag if overflow occurs on the addition.
    200#[inline]
    201#[cfg_attr(test, assert_instr(smlatb))]
    202#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    203pub unsafe fn __smlatb(a: i32, b: i32, c: i32) -> i32 {
    204    arm_smlatb(a, b, c)
    205}
    206
    207/// Insert a SMLATT instruction
    208///
    209/// Returns the equivalent of a\[1\] * b\[1\] + c
    210/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    211/// Sets the Q flag if overflow occurs on the addition.
    212#[inline]
    213#[cfg_attr(test, assert_instr(smlatt))]
    214#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    215pub unsafe fn __smlatt(a: i32, b: i32, c: i32) -> i32 {
    216    arm_smlatt(a, b, c)
    217}
    218
    219/// Insert a SMLAWB instruction
    220///
    221/// Returns the equivalent of (a * b\[0\] + (c << 16)) >> 16
    222/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    223/// Sets the Q flag if overflow occurs on the addition.
    224#[inline]
    225#[cfg_attr(test, assert_instr(smlawb))]
    226#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    227pub unsafe fn __smlawb(a: i32, b: i32, c: i32) -> i32 {
    228    arm_smlawb(a, b, c)
    229}
    230
    231/// Insert a SMLAWT instruction
    232///
    233/// Returns the equivalent of (a * b\[1\] + (c << 16)) >> 16
    234/// where \[0\] is the lower 16 bits and \[1\] is the upper 16 bits.
    235/// Sets the Q flag if overflow occurs on the addition.
    236#[inline]
    237#[cfg_attr(test, assert_instr(smlawt))]
    238#[unstable(feature = "stdarch_arm_dsp", issue = "117237")]
    239pub unsafe fn __smlawt(a: i32, b: i32, c: i32) -> i32 {
    240    arm_smlawt(a, b, c)
    241}
    242
    243#[cfg(test)]
    244mod tests {
    245    use crate::core_arch::{
    246        arm::*,
    247        simd::{i8x4, i16x2, u8x4},
    248    };
    249    use std::mem::transmute;
    250    use stdarch_test::simd_test;
    251
    252    #[test]
    253    fn smulbb() {
    254        unsafe {
    255            let a = i16x2::new(10, 20);
    256            let b = i16x2::new(30, 40);
    257            assert_eq!(super::__smulbb(transmute(a), transmute(b)), 10 * 30);
    258        }
    259    }
    260
    261    #[test]
    262    fn smulbt() {
    263        unsafe {
    264            let a = i16x2::new(10, 20);
    265            let b = i16x2::new(30, 40);
    266            assert_eq!(super::__smulbt(transmute(a), transmute(b)), 10 * 40);
    267        }
    268    }
    269
    270    #[test]
    271    fn smultb() {
    272        unsafe {
    273            let a = i16x2::new(10, 20);
    274            let b = i16x2::new(30, 40);
    275            assert_eq!(super::__smultb(transmute(a), transmute(b)), 20 * 30);
    276        }
    277    }
    278
    279    #[test]
    280    fn smultt() {
    281        unsafe {
    282            let a = i16x2::new(10, 20);
    283            let b = i16x2::new(30, 40);
    284            assert_eq!(super::__smultt(transmute(a), transmute(b)), 20 * 40);
    285        }
    286    }
    287
    288    #[test]
    289    fn smulwb() {
    290        unsafe {
    291            let a = i16x2::new(10, 20);
    292            let b = 30;
    293            assert_eq!(super::__smulwb(transmute(a), b), 20 * b);
    294        }
    295    }
    296
    297    #[test]
    298    fn smulwt() {
    299        unsafe {
    300            let a = i16x2::new(10, 20);
    301            let b = 30;
    302            assert_eq!(super::__smulwt(transmute(a), b), (10 * b) >> 16);
    303        }
    304    }
    305
    306    #[test]
    307    fn qadd() {
    308        unsafe {
    309            assert_eq!(super::__qadd(-10, 60), 50);
    310            assert_eq!(super::__qadd(i32::MAX, 10), i32::MAX);
    311            assert_eq!(super::__qadd(i32::MIN, -10), i32::MIN);
    312        }
    313    }
    314
    315    #[test]
    316    fn qsub() {
    317        unsafe {
    318            assert_eq!(super::__qsub(10, 60), -50);
    319            assert_eq!(super::__qsub(i32::MAX, -10), i32::MAX);
    320            assert_eq!(super::__qsub(i32::MIN, 10), i32::MIN);
    321        }
    322    }
    323
    324    fn qdbl() {
    325        unsafe {
    326            assert_eq!(super::__qdbl(10), 20);
    327            assert_eq!(super::__qdbl(i32::MAX), i32::MAX);
    328        }
    329    }
    330
    331    fn smlabb() {
    332        unsafe {
    333            let a = i16x2::new(10, 20);
    334            let b = i16x2::new(30, 40);
    335            let c = 50;
    336            let r = (10 * 30) + c;
    337            assert_eq!(super::__smlabb(transmute(a), transmute(b), c), r);
    338        }
    339    }
    340
    341    fn smlabt() {
    342        unsafe {
    343            let a = i16x2::new(10, 20);
    344            let b = i16x2::new(30, 40);
    345            let c = 50;
    346            let r = (10 * 40) + c;
    347            assert_eq!(super::__smlabt(transmute(a), transmute(b), c), r);
    348        }
    349    }
    350
    351    fn smlatb() {
    352        unsafe {
    353            let a = i16x2::new(10, 20);
    354            let b = i16x2::new(30, 40);
    355            let c = 50;
    356            let r = (20 * 30) + c;
    357            assert_eq!(super::__smlabt(transmute(a), transmute(b), c), r);
    358        }
    359    }
    360
    361    fn smlatt() {
    362        unsafe {
    363            let a = i16x2::new(10, 20);
    364            let b = i16x2::new(30, 40);
    365            let c = 50;
    366            let r = (20 * 40) + c;
    367            assert_eq!(super::__smlatt(transmute(a), transmute(b), c), r);
    368        }
    369    }
    370
    371    fn smlawb() {
    372        unsafe {
    373            let a: i32 = 10;
    374            let b = i16x2::new(30, 40);
    375            let c: i32 = 50;
    376            let r: i32 = ((a * 30) + (c << 16)) >> 16;
    377            assert_eq!(super::__smlawb(a, transmute(b), c), r);
    378        }
    379    }
    380
    381    fn smlawt() {
    382        unsafe {
    383            let a: i32 = 10;
    384            let b = i16x2::new(30, 40);
    385            let c: i32 = 50;
    386            let r: i32 = ((a * 40) + (c << 16)) >> 16;
    387            assert_eq!(super::__smlawt(a, transmute(b), c), r);
    388        }
    389    }
    390}