1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_absmin_q15.c
4  * Description:  Minimum value of absolute values of a Q15 vector
5  *
6  * $Date:        23 April 2021
7  * $Revision:    V1.9.0
8  *
9  * Target Processor: Cortex-M and Cortex-A cores
10  * -------------------------------------------------------------------- */
11 /*
12  * Copyright (C) 2010-2021 ARM Limited or its affiliates. All rights reserved.
13  *
14  * SPDX-License-Identifier: Apache-2.0
15  *
16  * Licensed under the Apache License, Version 2.0 (the License); you may
17  * not use this file except in compliance with the License.
18  * You may obtain a copy of the License at
19  *
20  * www.apache.org/licenses/LICENSE-2.0
21  *
22  * Unless required by applicable law or agreed to in writing, software
23  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25  * See the License for the specific language governing permissions and
26  * limitations under the License.
27  */
28 
29 #include "dsp/statistics_functions.h"
30 
31 /**
32   @ingroup groupStats
33  */
34 
35 
36 /**
37   @addtogroup AbsMin
38   @{
39  */
40 
41 /**
42   @brief         Minimum value of absolute values of a Q15 vector.
43   @param[in]     pSrc       points to the input vector
44   @param[in]     blockSize  number of samples in input vector
45   @param[out]    pResult    minimum value returned here
46   @param[out]    pIndex     index of minimum value returned here
47  */
48 #if defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE)
49 
50 #include "arm_helium_utils.h"
51 
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)52 ARM_DSP_ATTRIBUTE void arm_absmin_q15(
53   const q15_t * pSrc,
54         uint32_t blockSize,
55         q15_t * pResult,
56         uint32_t * pIndex)
57 {
58       uint16_t        blkCnt;           /* loop counters */
59     q15x8_t       vecSrc;
60     q15_t const   *pSrcVec;
61     q15x8_t       curExtremValVec = vdupq_n_s16(Q15_ABSMAX);
62     q15_t           minValue = Q15_ABSMAX;
63     uint16_t        idx = blockSize;
64     uint16x8_t    indexVec;
65     uint16x8_t    curExtremIdxVec;
66     uint32_t        startIdx = 0;
67     mve_pred16_t    p0;
68 
69 
70     indexVec = vidupq_wb_u16(&startIdx, 1);
71     curExtremIdxVec = vdupq_n_u16(0);
72 
73     pSrcVec = (q15_t const *) pSrc;
74     blkCnt = blockSize >> 3;
75     while (blkCnt > 0U)
76     {
77         vecSrc = vld1q(pSrcVec);
78         pSrcVec += 8;
79         vecSrc = vabsq(vecSrc);
80         /*
81          * Get current min per lane and current index per lane
82          * when a min is selected
83          */
84         p0 = vcmpleq(vecSrc, curExtremValVec);
85         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
86         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
87 
88         indexVec = vidupq_wb_u16(&startIdx, 1);
89         /*
90          * Decrement the blockSize loop counter
91          */
92         blkCnt--;
93     }
94     /*
95      * tail
96      * (will be merged thru tail predication)
97      */
98     blkCnt = blockSize & 7;
99     if (blkCnt > 0U)
100     {
101         vecSrc = vld1q(pSrcVec);
102         pSrcVec += 8;
103         vecSrc = vabsq(vecSrc);
104 
105         p0 = vctp16q(blkCnt);
106         /*
107          * Get current min per lane and current index per lane
108          * when a min is selected
109          */
110         p0 = vcmpleq_m(vecSrc, curExtremValVec, p0);
111         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
112         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
113     }
114     /*
115      * Get min value across the vector
116      */
117     minValue = vminvq(minValue, curExtremValVec);
118     /*
119      * set index for lower values to min possible index
120      */
121     p0 = vcmpleq(curExtremValVec, minValue);
122     indexVec = vpselq(curExtremIdxVec, vdupq_n_u16(blockSize), p0);
123     /*
124      * Get min index which is thus for a min value
125      */
126     idx = vminvq(idx, indexVec);
127     /*
128      * Save result
129      */
130     *pIndex = idx;
131     *pResult = minValue;
132 }
133 
134 #else
135 #if defined(ARM_MATH_DSP)
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)136 ARM_DSP_ATTRIBUTE void arm_absmin_q15(
137   const q15_t * pSrc,
138         uint32_t blockSize,
139         q15_t * pResult,
140         uint32_t * pIndex)
141 {
142         q15_t cur_absmin, out;                     /* Temporary variables to store the output value. */\
143         uint32_t blkCnt, outIndex;                     /* Loop counter */                                   \
144         uint32_t index;                                /* index of maximum value */                         \
145                                                                                                             \
146   /* Initialize index value to zero. */                                                                     \
147   outIndex = 0U;                                                                                            \
148   /* Load first input value that act as reference value for comparision */                                  \
149   out = *pSrc++;                                                                                            \
150   out = (out > 0) ? out : (q15_t)__QSUB16(0, out);                                                                           \
151   /* Initialize index of extrema value. */                                                                  \
152   index = 0U;                                                                                               \
153                                                                                                             \
154   /* Loop unrolling: Compute 4 outputs at a time */                                                         \
155   blkCnt = (blockSize - 1U) >> 2U;                                                                          \
156                                                                                                             \
157   while (blkCnt > 0U)                                                                                       \
158   {                                                                                                         \
159     /* Initialize cur_absmin to next consecutive values one by one */                                         \
160     cur_absmin = *pSrc++;                                                                                     \
161     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                \
162     /* compare for the extrema value */                                                                     \
163     if (cur_absmin < out)                                                                         \
164     {                                                                                                       \
165       /* Update the extrema value and it's index */                                                         \
166       out = cur_absmin;                                                                                       \
167       outIndex = index + 1U;                                                                                \
168     }                                                                                                       \
169                                                                                                             \
170     cur_absmin = *pSrc++;                                                                                     \
171     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                \
172     if (cur_absmin < out)                                                                         \
173     {                                                                                                       \
174       out = cur_absmin;                                                                                       \
175       outIndex = index + 2U;                                                                                \
176     }                                                                                                       \
177                                                                                                             \
178     cur_absmin = *pSrc++;                                                                                     \
179     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                \
180     if (cur_absmin < out)                                                                          \
181     {                                                                                                       \
182       out = cur_absmin;                                                                                       \
183       outIndex = index + 3U;                                                                                \
184     }                                                                                                       \
185                                                                                                             \
186     cur_absmin = *pSrc++;                                                                                     \
187     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                 \
188     if (cur_absmin < out)                                                                          \
189     {                                                                                                       \
190       out = cur_absmin;                                                                                       \
191       outIndex = index + 4U;                                                                                \
192     }                                                                                                       \
193                                                                                                             \
194     index += 4U;                                                                                            \
195                                                                                                             \
196     /* Decrement loop counter */                                                                            \
197     blkCnt--;                                                                                               \
198   }                                                                                                         \
199                                                                                                             \
200   /* Loop unrolling: Compute remaining outputs */                                                           \
201   blkCnt = (blockSize - 1U) % 4U;                                                                           \
202                                                                                                             \
203                                                                                                             \
204   while (blkCnt > 0U)                                                                                       \
205   {                                                                                                         \
206     cur_absmin = *pSrc++;                                                                                     \
207     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                 \
208     if (cur_absmin < out)                                                                         \
209     {                                                                                                       \
210       out = cur_absmin;                                                                                       \
211       outIndex = blockSize - blkCnt;                                                                        \
212     }                                                                                                       \
213                                                                                                             \
214     /* Decrement loop counter */                                                                            \
215     blkCnt--;                                                                                               \
216   }                                                                                                         \
217                                                                                                             \
218   /* Store the extrema value and it's index into destination pointers */                                    \
219   *pResult = out;                                                                                           \
220   *pIndex = outIndex;
221 }
222 #else
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)223 ARM_DSP_ATTRIBUTE void arm_absmin_q15(
224   const q15_t * pSrc,
225         uint32_t blockSize,
226         q15_t * pResult,
227         uint32_t * pIndex)
228 {
229        q15_t minVal, out;                             /* Temporary variables to store the output value. */
230         uint32_t blkCnt, outIndex;                     /* Loop counter */
231 
232 
233   /* Initialise index value to zero. */
234   outIndex = 0U;
235   /* Load first input value that act as reference value for comparision */
236   out = (*pSrc > 0) ? *pSrc : ((*pSrc == (q15_t) 0x8000) ? 0x7fff : -*pSrc);
237   pSrc++;
238 
239   /* Initialize blkCnt with number of samples */
240   blkCnt = (blockSize - 1U);
241 
242   while (blkCnt > 0U)
243   {
244     /* Initialize minVal to the next consecutive values one by one */
245     minVal = (*pSrc > 0) ? *pSrc : ((*pSrc == (q15_t) 0x8000) ? 0x7fff : -*pSrc);
246     pSrc++;
247 
248     /* compare for the minimum value */
249     if (out > minVal)
250     {
251       /* Update the minimum value and it's index */
252       out = minVal;
253       outIndex = blockSize - blkCnt;
254     }
255 
256     /* Decrement loop counter */
257     blkCnt--;
258   }
259 
260   /* Store the minimum value and it's index into destination pointers */
261   *pResult = out;
262   *pIndex = outIndex;
263 }
264 #endif /* defined(ARM_MATH_DSP) */
265 #endif /* defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE) */
266 /**
267   @} end of AbsMin group
268  */
269