2 * Bluetooth low-complexity, subband codec (SBC)
4 * Copyright (C) 2017 Aurelien Jacobs <aurel@gnuage.org>
5 * Copyright (C) 2008-2010 Nokia Corporation
6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
7 * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
8 * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
10 * This file is part of FFmpeg.
12 * FFmpeg is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * FFmpeg is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with FFmpeg; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 * SBC ARM NEON optimizations
32 #include "libavutil/arm/asm.S"
35 #define SBC_PROTO_FIXED_SCALE 16
37 function ff_sbc_analyze_4_neon, export=1
38 /* TODO: merge even and odd cases (or even merge all four calls to this
39 * function) in order to have only aligned reads from 'in' array
40 * and reduce number of load instructions */
41 vld1.16 {d4, d5}, [r0, :64]!
42 vld1.16 {d8, d9}, [r2, :128]!
45 vld1.16 {d6, d7}, [r0, :64]!
47 vld1.16 {d10, d11}, [r2, :128]!
50 vld1.16 {d4, d5}, [r0, :64]!
52 vld1.16 {d8, d9}, [r2, :128]!
55 vld1.16 {d6, d7}, [r0, :64]!
57 vld1.16 {d10, d11}, [r2, :128]!
60 vld1.16 {d4, d5}, [r0, :64]!
62 vld1.16 {d8, d9}, [r2, :128]!
70 vrshrn.s32 d0, q0, SBC_PROTO_FIXED_SCALE
72 vld1.16 {d2, d3, d4, d5}, [r2, :128]!
74 vdup.i32 d1, d0[1] /* TODO: can be eliminated */
75 vdup.i32 d0, d0[0] /* TODO: can be eliminated */
82 vpadd.s32 d0, d6, d7 /* TODO: can be eliminated */
83 vpadd.s32 d1, d8, d9 /* TODO: can be eliminated */
85 vst1.32 {d0, d1}, [r1, :128]
90 function ff_sbc_analyze_8_neon, export=1
91 /* TODO: merge even and odd cases (or even merge all four calls to this
92 * function) in order to have only aligned reads from 'in' array
93 * and reduce number of load instructions */
94 vld1.16 {d4, d5}, [r0, :64]!
95 vld1.16 {d8, d9}, [r2, :128]!
98 vld1.16 {d6, d7}, [r0, :64]!
100 vld1.16 {d10, d11}, [r2, :128]!
101 vmull.s16 q8, d6, d10
102 vld1.16 {d4, d5}, [r0, :64]!
103 vmull.s16 q9, d7, d11
104 vld1.16 {d8, d9}, [r2, :128]!
107 vld1.16 {d6, d7}, [r0, :64]!
109 vld1.16 {d10, d11}, [r2, :128]!
110 vmlal.s16 q8, d6, d10
111 vld1.16 {d4, d5}, [r0, :64]!
112 vmlal.s16 q9, d7, d11
113 vld1.16 {d8, d9}, [r2, :128]!
116 vld1.16 {d6, d7}, [r0, :64]!
118 vld1.16 {d10, d11}, [r2, :128]!
119 vmlal.s16 q8, d6, d10
120 vld1.16 {d4, d5}, [r0, :64]!
121 vmlal.s16 q9, d7, d11
122 vld1.16 {d8, d9}, [r2, :128]!
125 vld1.16 {d6, d7}, [r0, :64]!
127 vld1.16 {d10, d11}, [r2, :128]!
128 vmlal.s16 q8, d6, d10
129 vld1.16 {d4, d5}, [r0, :64]!
130 vmlal.s16 q9, d7, d11
131 vld1.16 {d8, d9}, [r2, :128]!
134 vld1.16 {d6, d7}, [r0, :64]!
136 vld1.16 {d10, d11}, [r2, :128]!
138 vmlal.s16 q8, d6, d10
139 vmlal.s16 q9, d7, d11
141 vpadd.s32 d0, d12, d13
142 vpadd.s32 d1, d14, d15
143 vpadd.s32 d2, d16, d17
144 vpadd.s32 d3, d18, d19
146 vrshr.s32 q0, q0, SBC_PROTO_FIXED_SCALE
147 vrshr.s32 q1, q1, SBC_PROTO_FIXED_SCALE
151 vdup.i32 d3, d1[1] /* TODO: can be eliminated */
152 vdup.i32 d2, d1[0] /* TODO: can be eliminated */
153 vdup.i32 d1, d0[1] /* TODO: can be eliminated */
154 vdup.i32 d0, d0[0] /* TODO: can be eliminated */
156 vld1.16 {d4, d5}, [r2, :128]!
158 vld1.16 {d6, d7}, [r2, :128]!
163 vld1.16 {d4, d5}, [r2, :128]!
165 vld1.16 {d6, d7}, [r2, :128]!
170 vld1.16 {d4, d5}, [r2, :128]!
172 vld1.16 {d6, d7}, [r2, :128]!
177 vld1.16 {d4, d5}, [r2, :128]!
179 vld1.16 {d6, d7}, [r2, :128]!
184 vpadd.s32 d0, d12, d13 /* TODO: can be eliminated */
185 vpadd.s32 d1, d14, d15 /* TODO: can be eliminated */
186 vpadd.s32 d2, d16, d17 /* TODO: can be eliminated */
187 vpadd.s32 d3, d18, d19 /* TODO: can be eliminated */
189 vst1.32 {d0, d1, d2, d3}, [r1, :128]
194 function ff_sbc_calc_scalefactors_neon, export=1
217 add r5, r0, r9, lsl#5
218 add r7, r1, r9, lsl#5
222 add r6, r5, r10, lsl#2
223 add r8, r7, r10, lsl#2
227 vmov.s32 q1, #0x8000 @ 1 << SCALE_OUT_BITS
229 vmov.s32 q15, #16 @ 31 - SCALE_OUT_BITS
232 vld1.32 {d16, d17}, [r6, :128], r11
234 vld1.32 {d18, d19}, [r6, :128], r11
236 vld1.32 {d20, d21}, [r6, :128], r11
238 vld1.32 {d22, d23}, [r6, :128], r11
250 vst1.32 {d0, d1}, [r8, :128]
265 * constants: q13 = (31 - SCALE_OUT_BITS)
267 * input: q0 - ((1 << SCALE_OUT_BITS) + 1)
268 * r5 - samples for channel 0
269 * r6 - samples for shannel 1
270 * output: q0, q1 - scale factors without joint stereo
271 * q2, q3 - scale factors with joint stereo
272 * q15 - joint stereo selection mask
274 .macro calc_scalefactors
280 vld1.32 {d18, d19}, [r6, :128], r11
281 vbic.s32 q11, q9, q14
282 vld1.32 {d16, d17}, [r5, :128], r11
283 vhadd.s32 q10, q8, q11
284 vhsub.s32 q11, q8, q11
311 * input: q15 - joint stereo selection mask
312 * r5 - value set by calc_scalefactors macro
313 * r6 - value set by calc_scalefactors macro
315 .macro update_joint_stereo_samples
318 sub r6, r6, r11, asl #1
319 sub r5, r5, r11, asl #1
320 vld1.32 {d18, d19}, [r6, :128]
321 vbic.s32 q11, q9, q14
322 vld1.32 {d16, d17}, [r5, :128]
323 vld1.32 {d2, d3}, [r8, :128]
325 vld1.32 {d0, d1}, [r7, :128]
326 vhsub.s32 q10, q8, q11
327 vhadd.s32 q11, q8, q11
330 vbif.s32 q10, q9, q15
331 vbif.s32 d22, d16, d30
332 sub r11, r10, r11, asl #1
335 vbif.s32 d23, d17, d31
336 vst1.32 {d20, d21}, [r6, :128], r11
338 vld1.32 {d18, d19}, [r6, :128]
340 vst1.32 {d22, d23}, [r5, :128], r11
342 vld1.32 {d16, d17}, [r5, :128]
344 vst1.32 {d4, d5}, [r8, :128], r11
345 vbic.s32 q11, q9, q14
346 vld1.32 {d2, d3}, [r8, :128]
347 vst1.32 {d6, d7}, [r7, :128], r11
349 vld1.32 {d0, d1}, [r7, :128]
350 vhsub.s32 q10, q8, q11
351 vhadd.s32 q11, q8, q11
354 vbif.s32 q10, q9, q15
355 vbif.s32 d22, d16, d30
358 sub r11, r10, r11, asr #1
359 vbif.s32 d23, d17, d31
360 vst1.32 {d20, d21}, [r6, :128]
362 vst1.32 {d22, d23}, [r5, :128]
364 vst1.32 {d4, d5}, [r8, :128]
365 vst1.32 {d6, d7}, [r7, :128]
368 function ff_sbc_calc_scalefactors_j_neon, export=1
370 @ r0 = in = sb_sample_f
371 @ r1 = out = scale_factor
375 @ r4 = consts = ff_sbcdsp_joint_bits_mask
385 movrelx r4, X(ff_sbcdsp_joint_bits_mask)
390 vmov.s32 q13, #16 @ 31 - SCALE_OUT_BITS
400 vmov.s32 q0, #0x8000 @ 1 << SCALE_OUT_BITS
405 @ check whether to use joint stereo for subbands 0, 1, 2
408 vmov.s32 d31[1], r10 @ last subband -> no joint
409 vld1.32 {d16, d17}, [r4, :128]!
410 vcgt.s32 q15, q15, q9
412 @ calculate and save to memory 'joint' variable
413 @ update and save scale factors to memory
416 vpadd.s32 d16, d16, d17
418 vpadd.s32 d16, d16, d16
419 vst1.32 {d0, d1}, [r7, :128]
420 vst1.32 {d2, d3}, [r8, :128]
423 update_joint_stereo_samples
431 vmov.s32 q0, #0x8000 @ 1 << SCALE_OUT_BITS
436 @ check whether to use joint stereo for subbands 4, 5, 6
439 vmov.s32 d31[1], r10 @ last subband -> no joint
440 vld1.32 {d16, d17}, [r4, :128]!
441 vcgt.s32 q15, q15, q9
443 @ calculate part of 'joint' variable and save it to d24
444 @ update and save scale factors to memory
447 vpadd.s32 d16, d16, d17
449 vst1.32 {d0, d1}, [r7, :128]
450 vst1.32 {d2, d3}, [r8, :128]
451 vpadd.s32 d24, d16, d16
453 update_joint_stereo_samples
459 vmov.s32 q0, #0x8000 @ 1 << SCALE_OUT_BITS
464 @ check whether to use joint stereo for subbands 0, 1, 2, 3
467 vld1.32 {d16, d17}, [r4, :128]!
468 vcgt.s32 q15, q15, q9
470 @ combine last part of 'joint' with d24 and save to memory
471 @ update and save scale factors to memory
474 vpadd.s32 d16, d16, d17
476 vpadd.s32 d16, d16, d16
477 vst1.32 {d0, d1}, [r7, :128]
478 vadd.s32 d16, d16, d24
479 vst1.32 {d2, d3}, [r8, :128]
482 update_joint_stereo_samples
488 function ff_sbc_enc_process_input_4s_neon, export=1
496 @ r5 = ff_sbc_input_perm_4
502 movrelx r5, X(ff_sbc_input_perm_4)
504 @ handle X buffer wraparound
506 bge 1f @ if (position < nsamples)
507 add r7, r2, #576 @ &X[0][SBC_X_BUFFER_SIZE - 40]
508 add r6, r2, r0, lsl#1 @ &X[0][position]
509 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
510 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
511 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
512 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
513 vld1.16 {d0}, [r6, :64]!
514 vst1.16 {d0}, [r7, :64]!
516 ble 2f @ if (nchannels > 1)
517 add r7, r2, #1232 @ &X[1][SBC_X_BUFFER_SIZE - 40]
519 add r6, r6, r0, lsl#1 @ &X[1][position]
520 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
521 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
522 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
523 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
524 vld1.16 {d0}, [r6, :64]!
525 vst1.16 {d0}, [r7, :64]!
527 mov r0, #288 @ SBC_X_BUFFER_SIZE - 40
530 add r6, r2, r0, lsl#1 @ &X[0][position]
531 add r7, r6, #656 @ &X[1][position]
534 ble 8f @ if (nchannels > 1)
536 beq 7f @ if (pcm & 1)
537 @ poor 'pcm' alignment
538 vld1.8 {d0, d1}, [r5, :128]
543 vld1.8 {d4, d5}, [r1]!
545 vld1.8 {d20, d21}, [r1]!
548 vtbl.8 d16, {d4, d5}, d0
549 vtbl.8 d17, {d4, d5}, d1
550 vtbl.8 d18, {d20, d21}, d0
551 vtbl.8 d19, {d20, d21}, d1
552 vst1.16 {d16, d17}, [r6, :128]
553 vst1.16 {d18, d19}, [r7, :128]
558 @ proper 'pcm' alignment
559 vld1.8 {d0, d1}, [r5, :128]
564 vld2.16 {d4, d5}, [r1]!
565 vld2.16 {d20, d21}, [r1]!
567 vtbl.8 d16, {d4, d5}, d0
568 vtbl.8 d17, {d4, d5}, d1
569 vtbl.8 d18, {d20, d21}, d0
570 vtbl.8 d19, {d20, d21}, d1
571 vst1.16 {d16, d17}, [r6, :128]
572 vst1.16 {d18, d19}, [r7, :128]
578 vld1.8 {d0, d1}, [r5, :128]
582 vld1.8 {d4, d5}, [r1]!
583 vtbl.8 d16, {d4, d5}, d0
584 vtbl.8 d17, {d4, d5}, d1
585 vst1.16 {d16, d17}, [r6, :128]
593 function ff_sbc_enc_process_input_8s_neon, export=1
601 @ r5 = ff_sbc_input_perm_8
607 movrelx r5, X(ff_sbc_input_perm_8)
609 @ handle X buffer wraparound
611 bge 1f @ if (position < nsamples)
612 add r7, r2, #512 @ &X[0][SBC_X_BUFFER_SIZE - 72]
613 add r6, r2, r0, lsl#1 @ &X[0][position]
614 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
615 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
616 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
617 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
618 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
619 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
620 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
621 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
622 vld1.16 {d0, d1}, [r6, :128]!
623 vst1.16 {d0, d1}, [r7, :128]!
625 ble 2f @ if (nchannels > 1)
626 add r7, r2, #1168 @ &X[1][SBC_X_BUFFER_SIZE - 72]
628 add r6, r6, r0, lsl#1 @ &X[1][position]
629 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
630 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
631 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
632 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
633 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
634 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
635 vld1.16 {d0, d1, d2, d3}, [r6, :128]!
636 vst1.16 {d0, d1, d2, d3}, [r7, :128]!
637 vld1.16 {d0, d1}, [r6, :128]!
638 vst1.16 {d0, d1}, [r7, :128]!
640 mov r0, #256 @ SBC_X_BUFFER_SIZE - 72
643 add r6, r2, r0, lsl#1 @ &X[0][position]
644 add r7, r6, #656 @ &X[1][position]
647 ble 8f @ if (nchannels > 1)
649 beq 7f @ if (pcm & 1)
650 @ poor 'pcm' alignment
651 vld1.8 {d0, d1, d2, d3}, [r5, :128]
656 vld1.8 {d4, d5, d6, d7}, [r1]!
658 vld1.8 {d20, d21, d22, d23}, [r1]!
661 vtbl.8 d16, {d4, d5, d6, d7}, d0
662 vtbl.8 d17, {d4, d5, d6, d7}, d1
663 vtbl.8 d18, {d4, d5, d6, d7}, d2
664 vtbl.8 d19, {d4, d5, d6, d7}, d3
665 vst1.16 {d16, d17, d18, d19}, [r6, :128]
666 vtbl.8 d16, {d20, d21, d22, d23}, d0
667 vtbl.8 d17, {d20, d21, d22, d23}, d1
668 vtbl.8 d18, {d20, d21, d22, d23}, d2
669 vtbl.8 d19, {d20, d21, d22, d23}, d3
670 vst1.16 {d16, d17, d18, d19}, [r7, :128]
675 @ proper 'pcm' alignment
676 vld1.8 {d0, d1, d2, d3}, [r5, :128]
681 vld2.16 {d4, d5, d6, d7}, [r1]!
682 vld2.16 {d20, d21, d22, d23}, [r1]!
684 vtbl.8 d16, {d4, d5, d6, d7}, d0
685 vtbl.8 d17, {d4, d5, d6, d7}, d1
686 vtbl.8 d18, {d4, d5, d6, d7}, d2
687 vtbl.8 d19, {d4, d5, d6, d7}, d3
688 vst1.16 {d16, d17, d18, d19}, [r6, :128]
689 vtbl.8 d16, {d20, d21, d22, d23}, d0
690 vtbl.8 d17, {d20, d21, d22, d23}, d1
691 vtbl.8 d18, {d20, d21, d22, d23}, d2
692 vtbl.8 d19, {d20, d21, d22, d23}, d3
693 vst1.16 {d16, d17, d18, d19}, [r7, :128]
699 vld1.8 {d0, d1, d2, d3}, [r5, :128]
703 vld1.8 {d4, d5, d6, d7}, [r1]!
704 vtbl.8 d16, {d4, d5, d6, d7}, d0
705 vtbl.8 d17, {d4, d5, d6, d7}, d1
706 vtbl.8 d18, {d4, d5, d6, d7}, d2
707 vtbl.8 d19, {d4, d5, d6, d7}, d3
708 vst1.16 {d16, d17, d18, d19}, [r6, :128]