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
26extern "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::{i16x2, i8x4, 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}