1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_min_f32.c
4  * Description:  Minimum value of a floating-point 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 #if (defined(ARM_MATH_NEON) || defined(ARM_MATH_MVEF)) && !defined(ARM_MATH_AUTOVECTORIZE)
32 #include <limits.h>
33 #endif
34 
35 
36 /**
37   @ingroup groupStats
38  */
39 
40 /**
41   @defgroup Min Minimum
42 
43   Computes the minimum value of an array of data.
44   The function returns both the minimum value and its position within the array.
45   There are separate functions for floating-point, Q31, Q15, and Q7 data types.
46  */
47 
48 /**
49   @addtogroup Min
50   @{
51  */
52 
53 /**
54   @brief         Minimum value of a floating-point vector.
55   @param[in]     pSrc       points to the input vector
56   @param[in]     blockSize  number of samples in input vector
57   @param[out]    pResult    minimum value returned here
58   @param[out]    pIndex     index of minimum value returned here
59   @return        none
60  */
61 
62 #if defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE)
63 
arm_min_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)64 void arm_min_f32(
65   const float32_t * pSrc,
66   uint32_t blockSize,
67   float32_t * pResult,
68   uint32_t * pIndex)
69 {
70     uint32_t  blkCnt;           /* loop counters */
71     f32x4_t vecSrc;
72     float32_t const *pSrcVec;
73     f32x4_t curExtremValVec = vdupq_n_f32(F32_MAX);
74     float32_t minValue = F32_MAX;
75     uint32_t  idx = blockSize;
76     uint32x4_t indexVec;
77     uint32x4_t curExtremIdxVec;
78     float32_t tmp;
79     mve_pred16_t p0;
80 
81     indexVec = vidupq_u32((uint32_t)0, 1);
82     curExtremIdxVec = vdupq_n_u32(0);
83 
84     pSrcVec = (float32_t const *) pSrc;
85     /* Compute 4 outputs at a time */
86     blkCnt = blockSize >> 2U;
87     while (blkCnt > 0U)
88     {
89         vecSrc = vldrwq_f32(pSrcVec);
90         pSrcVec += 4;
91         /*
92          * Get current max per lane and current index per lane
93          * when a max is selected
94          */
95         p0 = vcmpleq(vecSrc, curExtremValVec);
96         curExtremValVec = vpselq(vecSrc, curExtremValVec, p0);
97         curExtremIdxVec = vpselq(indexVec, curExtremIdxVec, p0);
98 
99         indexVec = indexVec +  4;
100         /*
101          * Decrement the blockSize loop counter
102          */
103         blkCnt--;
104     }
105 
106     /*
107      * Get min value across the vector
108      */
109     minValue = vminnmvq(minValue, curExtremValVec);
110     /*
111      * set index for lower values to max possible index
112      */
113     p0 = vcmpleq(curExtremValVec, minValue);
114     indexVec = vpselq(curExtremIdxVec, vdupq_n_u32(blockSize), p0);
115     /*
116      * Get min index which is thus for a max value
117      */
118     idx = vminvq(idx, indexVec);
119 
120     /*
121      * tail
122      */
123     blkCnt = blockSize & 0x3;
124 
125     while (blkCnt > 0U)
126     {
127       /* Initialize minVal to the next consecutive values one by one */
128       tmp = *pSrc++;
129 
130       /* compare for the minimum value */
131       if (minValue > tmp)
132       {
133         /* Update the minimum value and it's index */
134         minValue = tmp;
135         idx = blockSize - blkCnt;
136       }
137       blkCnt--;
138     }
139     /*
140      * Save result
141      */
142     *pIndex = idx;
143     *pResult = minValue;
144 }
145 
146 #else
147 #if defined(ARM_MATH_NEON) && !defined(ARM_MATH_AUTOVECTORIZE)
arm_min_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)148 void arm_min_f32(
149   const float32_t * pSrc,
150   uint32_t blockSize,
151   float32_t * pResult,
152   uint32_t * pIndex)
153 {
154   float32_t maxVal1, out;               /* Temporary variables to store the output value. */
155   uint32_t blkCnt, outIndex;              /* loop counter */
156 
157   float32x4_t outV, srcV;
158   float32x2_t outV2;
159 
160   uint32x4_t idxV;
161   static const uint32_t indexInit[4]={4,5,6,7};
162   static const uint32_t countVInit[4]={0,1,2,3};
163   uint32x4_t maxIdx;
164   uint32x4_t index;
165   uint32x4_t delta;
166   uint32x4_t countV;
167   uint32x2_t countV2;
168 
169   maxIdx = vdupq_n_u32(UINT_MAX);
170   delta = vdupq_n_u32(4);
171   index = vld1q_u32(indexInit);
172   countV = vld1q_u32(countVInit);
173 
174   /* Initialise the index value to zero. */
175   outIndex = 0U;
176 
177   /* Load first input value that act as reference value for comparison */
178   if (blockSize <= 3)
179   {
180       out = *pSrc++;
181 
182       blkCnt = blockSize - 1;
183 
184       while (blkCnt > 0U)
185       {
186         /* Initialize maxVal to the next consecutive values one by one */
187         maxVal1 = *pSrc++;
188 
189         /* compare for the maximum value */
190         if (out > maxVal1)
191         {
192           /* Update the maximum value and it's index */
193           out = maxVal1;
194           outIndex = blockSize - blkCnt;
195         }
196 
197         /* Decrement the loop counter */
198         blkCnt--;
199       }
200   }
201   else
202   {
203       outV = vld1q_f32(pSrc);
204       pSrc += 4;
205 
206       /* Compute 4 outputs at a time */
207       blkCnt = (blockSize - 4 ) >> 2U;
208 
209       while (blkCnt > 0U)
210       {
211         srcV = vld1q_f32(pSrc);
212         pSrc += 4;
213 
214         idxV = vcltq_f32(srcV, outV);
215         outV = vbslq_f32(idxV, srcV, outV );
216         countV = vbslq_u32(idxV, index,countV );
217 
218         index = vaddq_u32(index,delta);
219 
220         /* Decrement the loop counter */
221         blkCnt--;
222       }
223 
224       outV2 = vpmin_f32(vget_low_f32(outV),vget_high_f32(outV));
225       outV2 = vpmin_f32(outV2,outV2);
226       out = vget_lane_f32(outV2,0);
227 
228       idxV = vceqq_f32(outV, vdupq_n_f32(out));
229       countV = vbslq_u32(idxV, countV,maxIdx);
230 
231       countV2 = vpmin_u32(vget_low_u32(countV),vget_high_u32(countV));
232       countV2 = vpmin_u32(countV2,countV2);
233       outIndex = vget_lane_u32(countV2,0);
234 
235       /* if (blockSize - 1U) is not multiple of 4 */
236       blkCnt = (blockSize - 4 ) % 4U;
237 
238       while (blkCnt > 0U)
239       {
240         /* Initialize maxVal to the next consecutive values one by one */
241         maxVal1 = *pSrc++;
242 
243         /* compare for the maximum value */
244         if (out > maxVal1)
245         {
246           /* Update the maximum value and it's index */
247           out = maxVal1;
248           outIndex = blockSize - blkCnt ;
249         }
250 
251         /* Decrement the loop counter */
252         blkCnt--;
253       }
254   }
255 
256   /* Store the maximum value and it's index into destination pointers */
257   *pResult = out;
258   *pIndex = outIndex;
259 }
260 #else
arm_min_f32(const float32_t * pSrc,uint32_t blockSize,float32_t * pResult,uint32_t * pIndex)261 void arm_min_f32(
262   const float32_t * pSrc,
263         uint32_t blockSize,
264         float32_t * pResult,
265         uint32_t * pIndex)
266 {
267         float32_t minVal, out;                         /* Temporary variables to store the output value. */
268         uint32_t blkCnt, outIndex;                     /* Loop counter */
269 
270 #if defined (ARM_MATH_LOOPUNROLL) && !defined(ARM_MATH_AUTOVECTORIZE)
271         uint32_t index;                                /* index of maximum value */
272 #endif
273 
274   /* Initialise index value to zero. */
275   outIndex = 0U;
276 
277   /* Load first input value that act as reference value for comparision */
278   out = *pSrc++;
279 
280 #if defined (ARM_MATH_LOOPUNROLL) && !defined(ARM_MATH_AUTOVECTORIZE)
281   /* Initialise index of maximum value. */
282   index = 0U;
283 
284   /* Loop unrolling: Compute 4 outputs at a time */
285   blkCnt = (blockSize - 1U) >> 2U;
286 
287   while (blkCnt > 0U)
288   {
289     /* Initialize minVal to next consecutive values one by one */
290     minVal = *pSrc++;
291 
292     /* compare for the minimum value */
293     if (out > minVal)
294     {
295       /* Update the minimum value and it's index */
296       out = minVal;
297       outIndex = index + 1U;
298     }
299 
300     minVal = *pSrc++;
301     if (out > minVal)
302     {
303       out = minVal;
304       outIndex = index + 2U;
305     }
306 
307     minVal = *pSrc++;
308     if (out > minVal)
309     {
310       out = minVal;
311       outIndex = index + 3U;
312     }
313 
314     minVal = *pSrc++;
315     if (out > minVal)
316     {
317       out = minVal;
318       outIndex = index + 4U;
319     }
320 
321     index += 4U;
322 
323     /* Decrement loop counter */
324     blkCnt--;
325   }
326 
327   /* Loop unrolling: Compute remaining outputs */
328   blkCnt = (blockSize - 1U) % 4U;
329 
330 #else
331 
332   /* Initialize blkCnt with number of samples */
333   blkCnt = (blockSize - 1U);
334 
335 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
336 
337   while (blkCnt > 0U)
338   {
339     /* Initialize minVal to the next consecutive values one by one */
340     minVal = *pSrc++;
341 
342     /* compare for the minimum value */
343     if (out > minVal)
344     {
345       /* Update the minimum value and it's index */
346       out = minVal;
347       outIndex = blockSize - blkCnt;
348     }
349 
350     /* Decrement loop counter */
351     blkCnt--;
352   }
353 
354   /* Store the minimum value and it's index into destination pointers */
355   *pResult = out;
356   *pIndex = outIndex;
357 }
358 #endif /* #if defined(ARM_MATH_NEON) */
359 #endif /* defined(ARM_MATH_MVEF) && !defined(ARM_MATH_AUTOVECTORIZE) */
360 
361 /**
362   @} end of Min group
363  */
364