1 /* ----------------------------------------------------------------------
2 * Project: CMSIS DSP Library
3 * Title: arm_min_q7.c
4 * Description: Minimum value of a Q7 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 Min
38 @{
39 */
40
41 /**
42 @brief Minimum value of a Q7 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_small_blk_min_q7(const q7_t * pSrc,uint8_t blockSize,q7_t * pResult,uint32_t * pIndex)52 static void arm_small_blk_min_q7(
53 const q7_t * pSrc,
54 uint8_t blockSize,
55 q7_t * pResult,
56 uint32_t * pIndex)
57 {
58 uint32_t blkCnt; /* loop counters */
59 q7x16_t vecSrc;
60 q7x16_t curExtremValVec = vdupq_n_s8(Q7_MAX);
61 q7_t minValue = Q7_MAX,temp;
62 uint32_t idx = blockSize;
63 uint8x16_t indexVec;
64 uint8x16_t curExtremIdxVec;
65 mve_pred16_t p0;
66
67
68 indexVec = vidupq_u8((uint32_t)0, 1);
69 curExtremIdxVec = vdupq_n_u8(0);
70
71 blkCnt = blockSize >> 4;
72 while (blkCnt > 0U)
73 {
74 vecSrc = vldrbq_s8(pSrc);
75 pSrc += 16;
76 /*
77 * Get current min per lane and current index per lane
78 * when a min is selected
79 */
80 p0 = vcmpleq(vecSrc, curExtremValVec);
81 curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
82 curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
83
84 indexVec = indexVec + 16;
85 /*
86 * Decrement the blockSize loop counter
87 */
88 blkCnt--;
89 }
90
91 /*
92 * Get min value across the vector
93 */
94 minValue = vminvq(minValue, curExtremValVec);
95 /*
96 * set index for lower values to min possible index
97 */
98 p0 = vcmpleq(curExtremValVec, minValue);
99 indexVec = vpselq(curExtremIdxVec, vdupq_n_u8(blockSize), p0);
100 /*
101 * Get min index which is thus for a min value
102 */
103 idx = vminvq(idx, indexVec);
104
105 blkCnt = blockSize & 0xF;
106 while (blkCnt > 0U)
107 {
108 /* Initialize minVal to the next consecutive values one by one */
109 temp = *pSrc++;
110
111 /* compare for the minimum value */
112 if (minValue > temp)
113 {
114 /* Update the minimum value and it's index */
115 minValue = temp;
116 idx = blockSize - blkCnt;
117 }
118
119 /* Decrement loop counter */
120 blkCnt--;
121 }
122 /*
123 * Save result
124 */
125 *pIndex = idx;
126 *pResult = minValue;
127 }
128
arm_min_q7(const q7_t * pSrc,uint32_t blockSize,q7_t * pResult,uint32_t * pIndex)129 ARM_DSP_ATTRIBUTE void arm_min_q7(
130 const q7_t * pSrc,
131 uint32_t blockSize,
132 q7_t * pResult,
133 uint32_t * pIndex)
134 {
135 int32_t totalSize = blockSize;
136
137 if (totalSize <= UINT8_MAX)
138 {
139 arm_small_blk_min_q7(pSrc, blockSize, pResult, pIndex);
140 }
141 else
142 {
143 uint32_t curIdx = 0;
144 q7_t curBlkExtr = Q7_MAX;
145 uint32_t curBlkPos = 0;
146 uint32_t curBlkIdx = 0;
147 /*
148 * process blocks of 255 elts
149 */
150 while (totalSize >= UINT8_MAX)
151 {
152 const q7_t *curSrc = pSrc;
153
154 arm_small_blk_min_q7(curSrc, UINT8_MAX, pResult, pIndex);
155 if (*pResult < curBlkExtr)
156 {
157 /*
158 * update partial extrema
159 */
160 curBlkExtr = *pResult;
161 curBlkPos = *pIndex;
162 curBlkIdx = curIdx;
163 }
164 curIdx++;
165 pSrc += UINT8_MAX;
166 totalSize -= UINT8_MAX;
167 }
168 /*
169 * remainder
170 */
171 arm_small_blk_min_q7(pSrc, totalSize, pResult, pIndex);
172 if (*pResult < curBlkExtr)
173 {
174 curBlkExtr = *pResult;
175 curBlkPos = *pIndex;
176 curBlkIdx = curIdx;
177 }
178 *pIndex = curBlkIdx * UINT8_MAX + curBlkPos;
179 *pResult = curBlkExtr;
180 }
181 }
182 #else
arm_min_q7(const q7_t * pSrc,uint32_t blockSize,q7_t * pResult,uint32_t * pIndex)183 ARM_DSP_ATTRIBUTE void arm_min_q7(
184 const q7_t * pSrc,
185 uint32_t blockSize,
186 q7_t * pResult,
187 uint32_t * pIndex)
188 {
189 q7_t minVal, out; /* Temporary variables to store the output value. */
190 uint32_t blkCnt, outIndex; /* Loop counter */
191
192 #if defined (ARM_MATH_LOOPUNROLL)
193 uint32_t index; /* index of maximum value */
194 #endif
195
196 /* Initialise index value to zero. */
197 outIndex = 0U;
198 /* Load first input value that act as reference value for comparision */
199 out = *pSrc++;
200
201 #if defined (ARM_MATH_LOOPUNROLL)
202 /* Initialise index of maximum value. */
203 index = 0U;
204
205 /* Loop unrolling: Compute 4 outputs at a time */
206 blkCnt = (blockSize - 1U) >> 2U;
207
208 while (blkCnt > 0U)
209 {
210 /* Initialize minVal to next consecutive values one by one */
211 minVal = *pSrc++;
212
213 /* compare for the minimum value */
214 if (out > minVal)
215 {
216 /* Update the minimum value and it's index */
217 out = minVal;
218 outIndex = index + 1U;
219 }
220
221 minVal = *pSrc++;
222 if (out > minVal)
223 {
224 out = minVal;
225 outIndex = index + 2U;
226 }
227
228 minVal = *pSrc++;
229 if (out > minVal)
230 {
231 out = minVal;
232 outIndex = index + 3U;
233 }
234
235 minVal = *pSrc++;
236 if (out > minVal)
237 {
238 out = minVal;
239 outIndex = index + 4U;
240 }
241
242 index += 4U;
243
244 /* Decrement loop counter */
245 blkCnt--;
246 }
247
248 /* Loop unrolling: Compute remaining outputs */
249 blkCnt = (blockSize - 1U) % 4U;
250
251 #else
252
253 /* Initialize blkCnt with number of samples */
254 blkCnt = (blockSize - 1U);
255
256 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
257
258 while (blkCnt > 0U)
259 {
260 /* Initialize minVal to the next consecutive values one by one */
261 minVal = *pSrc++;
262
263 /* compare for the minimum value */
264 if (out > minVal)
265 {
266 /* Update the minimum value and it's index */
267 out = minVal;
268 outIndex = blockSize - blkCnt;
269 }
270
271 /* Decrement loop counter */
272 blkCnt--;
273 }
274
275 /* Store the minimum value and it's index into destination pointers */
276 *pResult = out;
277 *pIndex = outIndex;
278 }
279 #endif /* defined(ARM_MATH_MVEI) */
280
281 /**
282 @} end of Min group
283 */
284