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   @return        none
48  */
49 #if defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE)
50 
51 #include "arm_helium_utils.h"
52 
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)53 void arm_absmin_q15(
54   const q15_t * pSrc,
55         uint32_t blockSize,
56         q15_t * pResult,
57         uint32_t * pIndex)
58 {
59       uint16_t        blkCnt;           /* loop counters */
60     q15x8_t       vecSrc;
61     q15_t const   *pSrcVec;
62     q15x8_t       curExtremValVec = vdupq_n_s16(Q15_ABSMAX);
63     q15_t           minValue = Q15_ABSMAX;
64     uint16_t        idx = blockSize;
65     uint16x8_t    indexVec;
66     uint16x8_t    curExtremIdxVec;
67     uint32_t        startIdx = 0;
68     mve_pred16_t    p0;
69 
70 
71     indexVec = vidupq_wb_u16(&startIdx, 1);
72     curExtremIdxVec = vdupq_n_u16(0);
73 
74     pSrcVec = (q15_t const *) pSrc;
75     blkCnt = blockSize >> 3;
76     while (blkCnt > 0U)
77     {
78         vecSrc = vld1q(pSrcVec);
79         pSrcVec += 8;
80         vecSrc = vabsq(vecSrc);
81         /*
82          * Get current min per lane and current index per lane
83          * when a min is selected
84          */
85         p0 = vcmpleq(vecSrc, curExtremValVec);
86         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
87         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
88 
89         indexVec = vidupq_wb_u16(&startIdx, 1);
90         /*
91          * Decrement the blockSize loop counter
92          */
93         blkCnt--;
94     }
95     /*
96      * tail
97      * (will be merged thru tail predication)
98      */
99     blkCnt = blockSize & 7;
100     if (blkCnt > 0U)
101     {
102         vecSrc = vld1q(pSrcVec);
103         pSrcVec += 8;
104         vecSrc = vabsq(vecSrc);
105 
106         p0 = vctp16q(blkCnt);
107         /*
108          * Get current min per lane and current index per lane
109          * when a min is selected
110          */
111         p0 = vcmpleq_m(vecSrc, curExtremValVec, p0);
112         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
113         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
114     }
115     /*
116      * Get min value across the vector
117      */
118     minValue = vminvq(minValue, curExtremValVec);
119     /*
120      * set index for lower values to min possible index
121      */
122     p0 = vcmpleq(curExtremValVec, minValue);
123     indexVec = vpselq(curExtremIdxVec, vdupq_n_u16(blockSize), p0);
124     /*
125      * Get min index which is thus for a min value
126      */
127     idx = vminvq(idx, indexVec);
128     /*
129      * Save result
130      */
131     *pIndex = idx;
132     *pResult = minValue;
133 }
134 
135 #else
136 #if defined(ARM_MATH_DSP)
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)137 void arm_absmin_q15(
138   const q15_t * pSrc,
139         uint32_t blockSize,
140         q15_t * pResult,
141         uint32_t * pIndex)
142 {
143         q15_t cur_absmin, out;                     /* Temporary variables to store the output value. */\
144         uint32_t blkCnt, outIndex;                     /* Loop counter */                                   \
145         uint32_t index;                                /* index of maximum value */                         \
146                                                                                                             \
147   /* Initialize index value to zero. */                                                                     \
148   outIndex = 0U;                                                                                            \
149   /* Load first input value that act as reference value for comparision */                                  \
150   out = *pSrc++;                                                                                            \
151   out = (out > 0) ? out : (q15_t)__QSUB16(0, out);                                                                           \
152   /* Initialize index of extrema value. */                                                                  \
153   index = 0U;                                                                                               \
154                                                                                                             \
155   /* Loop unrolling: Compute 4 outputs at a time */                                                         \
156   blkCnt = (blockSize - 1U) >> 2U;                                                                          \
157                                                                                                             \
158   while (blkCnt > 0U)                                                                                       \
159   {                                                                                                         \
160     /* Initialize cur_absmin to next consecutive values one by one */                                         \
161     cur_absmin = *pSrc++;                                                                                     \
162     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                \
163     /* compare for the extrema value */                                                                     \
164     if (cur_absmin < out)                                                                         \
165     {                                                                                                       \
166       /* Update the extrema value and it's index */                                                         \
167       out = cur_absmin;                                                                                       \
168       outIndex = index + 1U;                                                                                \
169     }                                                                                                       \
170                                                                                                             \
171     cur_absmin = *pSrc++;                                                                                     \
172     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                \
173     if (cur_absmin < out)                                                                         \
174     {                                                                                                       \
175       out = cur_absmin;                                                                                       \
176       outIndex = index + 2U;                                                                                \
177     }                                                                                                       \
178                                                                                                             \
179     cur_absmin = *pSrc++;                                                                                     \
180     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                \
181     if (cur_absmin < out)                                                                          \
182     {                                                                                                       \
183       out = cur_absmin;                                                                                       \
184       outIndex = index + 3U;                                                                                \
185     }                                                                                                       \
186                                                                                                             \
187     cur_absmin = *pSrc++;                                                                                     \
188     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                 \
189     if (cur_absmin < out)                                                                          \
190     {                                                                                                       \
191       out = cur_absmin;                                                                                       \
192       outIndex = index + 4U;                                                                                \
193     }                                                                                                       \
194                                                                                                             \
195     index += 4U;                                                                                            \
196                                                                                                             \
197     /* Decrement loop counter */                                                                            \
198     blkCnt--;                                                                                               \
199   }                                                                                                         \
200                                                                                                             \
201   /* Loop unrolling: Compute remaining outputs */                                                           \
202   blkCnt = (blockSize - 1U) % 4U;                                                                           \
203                                                                                                             \
204                                                                                                             \
205   while (blkCnt > 0U)                                                                                       \
206   {                                                                                                         \
207     cur_absmin = *pSrc++;                                                                                     \
208     cur_absmin = (cur_absmin > 0) ? cur_absmin : (q15_t)__QSUB16(0, cur_absmin);                                                                 \
209     if (cur_absmin < out)                                                                         \
210     {                                                                                                       \
211       out = cur_absmin;                                                                                       \
212       outIndex = blockSize - blkCnt;                                                                        \
213     }                                                                                                       \
214                                                                                                             \
215     /* Decrement loop counter */                                                                            \
216     blkCnt--;                                                                                               \
217   }                                                                                                         \
218                                                                                                             \
219   /* Store the extrema value and it's index into destination pointers */                                    \
220   *pResult = out;                                                                                           \
221   *pIndex = outIndex;
222 }
223 #else
arm_absmin_q15(const q15_t * pSrc,uint32_t blockSize,q15_t * pResult,uint32_t * pIndex)224 void arm_absmin_q15(
225   const q15_t * pSrc,
226         uint32_t blockSize,
227         q15_t * pResult,
228         uint32_t * pIndex)
229 {
230        q15_t minVal, out;                             /* Temporary variables to store the output value. */
231         uint32_t blkCnt, outIndex;                     /* Loop counter */
232 
233 
234   /* Initialise index value to zero. */
235   outIndex = 0U;
236   /* Load first input value that act as reference value for comparision */
237   out = (*pSrc > 0) ? *pSrc : ((*pSrc == (q15_t) 0x8000) ? 0x7fff : -*pSrc);
238   pSrc++;
239 
240   /* Initialize blkCnt with number of samples */
241   blkCnt = (blockSize - 1U);
242 
243   while (blkCnt > 0U)
244   {
245     /* Initialize minVal to the next consecutive values one by one */
246     minVal = (*pSrc > 0) ? *pSrc : ((*pSrc == (q15_t) 0x8000) ? 0x7fff : -*pSrc);
247     pSrc++;
248 
249     /* compare for the minimum value */
250     if (out > minVal)
251     {
252       /* Update the minimum value and it's index */
253       out = minVal;
254       outIndex = blockSize - blkCnt;
255     }
256 
257     /* Decrement loop counter */
258     blkCnt--;
259   }
260 
261   /* Store the minimum value and it's index into destination pointers */
262   *pResult = out;
263   *pIndex = outIndex;
264 }
265 #endif /* defined(ARM_MATH_DSP) */
266 #endif /* defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE) */
267 /**
268   @} end of AbsMin group
269  */
270