1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_absmin_q31.c
4  * Description:  Minimum value of absolute values of a Q31 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 Q31 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 
49 #if defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE)
50 
51 #include "arm_helium_utils.h"
52 
arm_absmin_q31(const q31_t * pSrc,uint32_t blockSize,q31_t * pResult,uint32_t * pIndex)53 ARM_DSP_ATTRIBUTE void arm_absmin_q31(
54   const q31_t * pSrc,
55         uint32_t blockSize,
56         q31_t * pResult,
57         uint32_t * pIndex)
58 {
59       uint16_t        blkCnt;           /* loop counters */
60     q31x4_t       vecSrc;
61     q31_t const   *pSrcVec;
62     q31x4_t       curExtremValVec = vdupq_n_s32(Q31_ABSMAX);
63     q31_t           minValue = Q31_ABSMAX;
64     uint16_t        idx = blockSize;
65     uint32x4_t    indexVec;
66     uint32x4_t    curExtremIdxVec;
67     uint32_t        startIdx = 0;
68     mve_pred16_t    p0;
69 
70 
71     indexVec = vidupq_wb_u32(&startIdx, 1);
72     curExtremIdxVec = vdupq_n_u32(0);
73 
74     pSrcVec = (q31_t const *) pSrc;
75     blkCnt = blockSize >> 2;
76     while (blkCnt > 0U)
77     {
78         vecSrc = vldrwq_s32(pSrcVec);
79         pSrcVec += 4;
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_u32(&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 & 3;
100     if (blkCnt > 0U)
101     {
102         vecSrc = vldrwq_s32(pSrcVec);
103         pSrcVec += 4;
104         vecSrc = vabsq(vecSrc);
105 
106         p0 = vctp32q(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_u32(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_q31(const q31_t * pSrc,uint32_t blockSize,q31_t * pResult,uint32_t * pIndex)137 ARM_DSP_ATTRIBUTE void arm_absmin_q31(
138   const q31_t * pSrc,
139         uint32_t blockSize,
140         q31_t * pResult,
141         uint32_t * pIndex)
142 {
143         q31_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 : (q31_t)__QSUB(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 : (q31_t)__QSUB(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 : (q31_t)__QSUB(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 : (q31_t)__QSUB(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 : (q31_t)__QSUB(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 : (q31_t)__QSUB(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_q31(const q31_t * pSrc,uint32_t blockSize,q31_t * pResult,uint32_t * pIndex)224 ARM_DSP_ATTRIBUTE void arm_absmin_q31(
225   const q31_t * pSrc,
226         uint32_t blockSize,
227         q31_t * pResult,
228         uint32_t * pIndex)
229 {
230         q31_t minVal, out;                             /* Temporary variables to store the output value. */
231         uint32_t blkCnt, outIndex;                     /* Loop counter */
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 == INT32_MIN) ? INT32_MAX : -*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 == INT32_MIN) ? INT32_MAX : -*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