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