1 /* ----------------------------------------------------------------------
2  * Project:      CMSIS DSP Library
3  * Title:        arm_shift_q31.c
4  * Description:  Shifts the elements of a Q31 vector by a specified number of bits
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/basic_math_functions.h"
30 
31 /**
32   @ingroup groupMath
33  */
34 /**
35   @defgroup BasicShift Vector Shift
36 
37   Shifts the elements of a fixed-point vector by a specified number of bits.
38   There are separate functions for Q7, Q15, and Q31 data types.
39   The underlying algorithm used is:
40 
41   <pre>
42       pDst[n] = pSrc[n] << shift,   0 <= n < blockSize.
43   </pre>
44 
45   If <code>shift</code> is positive then the elements of the vector are shifted to the left.
46   If <code>shift</code> is negative then the elements of the vector are shifted to the right.
47 
48   The functions support in-place computation allowing the source and destination
49   pointers to reference the same memory buffer.
50  */
51 
52 /**
53   @addtogroup BasicShift
54   @{
55  */
56 
57 /**
58   @brief         Shifts the elements of a Q31 vector a specified number of bits.
59   @param[in]     pSrc       points to the input vector
60   @param[in]     shiftBits  number of bits to shift.  A positive value shifts left; a negative value shifts right.
61   @param[out]    pDst       points to the output vector
62   @param[in]     blockSize  number of samples in the vector
63 
64   @par           Scaling and Overflow Behavior
65                    The function uses saturating arithmetic.
66                    Results outside of the allowable Q31 range [0x80000000 0x7FFFFFFF] are saturated.
67  */
68 
69 #if defined(ARM_MATH_MVEI) && !defined(ARM_MATH_AUTOVECTORIZE)
70 
71 #include "arm_helium_utils.h"
72 
arm_shift_q31(const q31_t * pSrc,int8_t shiftBits,q31_t * pDst,uint32_t blockSize)73 ARM_DSP_ATTRIBUTE void arm_shift_q31(
74     const q31_t * pSrc,
75     int8_t shiftBits,
76     q31_t * pDst,
77     uint32_t blockSize)
78 {
79     uint32_t  blkCnt;           /* loop counters */
80     q31x4_t vecSrc;
81     q31x4_t vecDst;
82 
83     /* Compute 4 outputs at a time */
84     blkCnt = blockSize >> 2;
85     while (blkCnt > 0U)
86     {
87         /*
88          * C = A (>> or <<) shiftBits
89          * Shift the input and then store the result in the destination buffer.
90          */
91         vecSrc = vld1q((q31_t const *) pSrc);
92         vecDst = vqshlq_r(vecSrc, shiftBits);
93         vst1q(pDst, vecDst);
94         /*
95          * Decrement the blockSize loop counter
96          */
97         blkCnt--;
98         /*
99          * advance vector source and destination pointers
100          */
101         pSrc += 4;
102         pDst += 4;
103     }
104     /*
105      * tail
106      */
107     blkCnt = blockSize & 3;
108     if (blkCnt > 0U)
109     {
110         mve_pred16_t p0 = vctp32q(blkCnt);
111         vecSrc = vld1q((q31_t const *) pSrc);
112         vecDst = vqshlq_r(vecSrc, shiftBits);
113         vstrwq_p(pDst, vecDst, p0);
114     }
115 }
116 
117 
118 #else
arm_shift_q31(const q31_t * pSrc,int8_t shiftBits,q31_t * pDst,uint32_t blockSize)119 ARM_DSP_ATTRIBUTE void arm_shift_q31(
120   const q31_t * pSrc,
121         int8_t shiftBits,
122         q31_t * pDst,
123         uint32_t blockSize)
124 {
125         uint32_t blkCnt;                               /* Loop counter */
126         uint8_t sign = (shiftBits & 0x80);             /* Sign of shiftBits */
127 
128 #if defined (ARM_MATH_LOOPUNROLL)
129 
130   q31_t in, out;                                 /* Temporary variables */
131 
132   /* Loop unrolling: Compute 4 outputs at a time */
133   blkCnt = blockSize >> 2U;
134 
135   /* If the shift value is positive then do right shift else left shift */
136   if (sign == 0U)
137   {
138     while (blkCnt > 0U)
139     {
140       /* C = A << shiftBits */
141 
142       /* Shift input and store result in destination buffer. */
143       in = *pSrc++;
144       out = in << shiftBits;
145       if (in != (out >> shiftBits))
146         out = 0x7FFFFFFF ^ (in >> 31);
147       *pDst++ = out;
148 
149       in = *pSrc++;
150       out = in << shiftBits;
151       if (in != (out >> shiftBits))
152         out = 0x7FFFFFFF ^ (in >> 31);
153       *pDst++ = out;
154 
155       in = *pSrc++;
156       out = in << shiftBits;
157       if (in != (out >> shiftBits))
158         out = 0x7FFFFFFF ^ (in >> 31);
159       *pDst++ = out;
160 
161       in = *pSrc++;
162       out = in << shiftBits;
163       if (in != (out >> shiftBits))
164         out = 0x7FFFFFFF ^ (in >> 31);
165       *pDst++ = out;
166 
167       /* Decrement loop counter */
168       blkCnt--;
169     }
170   }
171   else
172   {
173     while (blkCnt > 0U)
174     {
175       /* C = A >> shiftBits */
176 
177       /* Shift input and store results in destination buffer. */
178       *pDst++ = (*pSrc++ >> -shiftBits);
179       *pDst++ = (*pSrc++ >> -shiftBits);
180       *pDst++ = (*pSrc++ >> -shiftBits);
181       *pDst++ = (*pSrc++ >> -shiftBits);
182 
183       /* Decrement loop counter */
184       blkCnt--;
185     }
186   }
187 
188   /* Loop unrolling: Compute remaining outputs */
189   blkCnt = blockSize % 0x4U;
190 
191 #else
192 
193   /* Initialize blkCnt with number of samples */
194   blkCnt = blockSize;
195 
196 #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
197 
198   /* If the shift value is positive then do right shift else left shift */
199   if (sign == 0U)
200   {
201     while (blkCnt > 0U)
202     {
203       /* C = A << shiftBits */
204 
205       /* Shift input and store result in destination buffer. */
206       *pDst++ = clip_q63_to_q31((q63_t) *pSrc++ << shiftBits);
207 
208       /* Decrement loop counter */
209       blkCnt--;
210     }
211   }
212   else
213   {
214     while (blkCnt > 0U)
215     {
216       /* C = A >> shiftBits */
217 
218       /* Shift input and store result in destination buffer. */
219       *pDst++ = (*pSrc++ >> -shiftBits);
220 
221       /* Decrement loop counter */
222       blkCnt--;
223     }
224   }
225 
226 }
227 #endif /* defined(ARM_MATH_MVEI) */
228 
229 /**
230   @} end of BasicShift group
231  */
232