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