Reduce register clobber
[vlc.git] / modules / audio_filter / converter / neon.c
1 /*****************************************************************************
2  * arm_neon.c: NEON assembly optimized audio conversions
3  *****************************************************************************
4  * Copyright (C) 2009 RĂ©mi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <vlc_common.h>
26 #include <vlc_plugin.h>
27 #include <vlc_aout.h>
28
29 static int Open (vlc_object_t *);
30
31 vlc_module_begin ()
32     set_description (N_("ARM NEON audio format conversions") )
33     add_submodule ()
34         set_capability ("audio filter", 20)
35         set_callbacks (Open, NULL)
36 vlc_module_end ()
37
38 static void Do_F32_S32 (aout_instance_t *, aout_filter_t *,
39                         aout_buffer_t *, aout_buffer_t *);
40
41 static int Open (vlc_object_t *obj)
42 {
43     aout_filter_t *filter = (aout_filter_t *)obj;
44
45     if (!(vlc_CPU () & CPU_CAPABILITY_NEON))
46         return VLC_EGENERIC;
47     if (!AOUT_FMTS_SIMILAR (&filter->input, &filter->output))
48         return VLC_EGENERIC;
49
50     if (filter->input.i_format == VLC_CODEC_FL32)
51     {
52         if (filter->output.i_format == VLC_CODEC_FI32)
53             filter->pf_do_work = Do_F32_S32;
54         else
55             return VLC_EGENERIC;
56     }
57     else
58         return VLC_EGENERIC;
59
60     filter->b_in_place = true;
61     return 0;
62 }
63
64 /**
65  * Half-precision floating point to signed fixed point conversion.
66  */
67 static void Do_F32_S32 (aout_instance_t *aout, aout_filter_t *filter,
68                         aout_buffer_t *inbuf, aout_buffer_t *outbuf)
69 {
70     unsigned nb_samples = inbuf->i_nb_samples
71                      * aout_FormatNbChannels (&filter->input);
72     const float *inp = (float *)inbuf->p_buffer;
73     const float *endp = inp + nb_samples;
74     int32_t *outp = (int32_t *)outbuf->p_buffer;
75
76     if (nb_samples & 1)
77         *(outp++) = *(inp++) * FIXED32_ONE;
78
79     if (nb_samples & 2)
80         asm volatile (
81             "vld1.f32 {d0}, [%[inp]]!\n"
82             "vcvt.s32.f32 d0, d0, #28\n"
83             "vst1.s32 {d0}, [%[outp]]!\n"
84             : [outp] "+r" (outp), [inp] "+r" (inp)
85             :
86             : "d0", "memory");
87
88     if (nb_samples & 4)
89         asm volatile (
90             "vld2.f32 {q0}, [%[inp]]!\n"
91             "vcvt.s32.f32 q0, q0, #28\n"
92             "vst2.s32 {q0}, [%[outp]]!\n"
93             : [outp] "+r" (outp), [inp] "+r" (inp)
94             :
95             : "q0", "memory");
96
97     while (inp != endp)
98         asm volatile (
99             "vld4.f32 {q0-q1}, [%[inp]]!\n"
100             "vcvt.s32.f32 q0, q0, #28\n"
101             "vcvt.s32.f32 q1, q1, #28\n"
102             "vst4.s32 {q0-q1}, [%[outp]]!\n"
103             : [outp] "+r" (outp), [inp] "+r" (inp)
104             :
105             : "q0", "q1", "memory");
106
107     outbuf->i_nb_samples = inbuf->i_nb_samples;
108     outbuf->i_nb_bytes = inbuf->i_nb_bytes;
109     (void) aout;
110 }