MATHLIB User Guide
MATHLIB_log.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the
14  * distribution.
15  *
16  * Neither the name of Texas Instruments Incorporated nor the names of
17  * its contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  ******************************************************************************/
33 
34 #define ELEMENT_COUNT(x) c7x::element_count_of<x>::value
35 
36 /******************************************************************************/
37 /* */
38 /* Includes */
39 /* */
40 /******************************************************************************/
41 
42 #include "MATHLIB_ilut.h"
43 #include "MATHLIB_log_scalar.h"
44 #include "MATHLIB_lut.h"
45 #include "MATHLIB_permute.h"
46 #include "MATHLIB_types.h"
47 #include "MATHLIB_utility.h"
48 
49 /******************************************************************************/
50 /* */
51 /* MATHLIB_log */
52 /* */
53 /******************************************************************************/
54 template <typename T> static inline void MATHLIB_log_vector(size_t length, T *restrict pSrc, T *restrict pDst)
55 {
56  size_t numBlocks = 0; // compute loop's iteration count
57  size_t remNumBlocks = 0; // when numBlocks is not a multiple of SIMD width
58 
59  // derive c7x vector type from template typename
60  typedef typename c7x::make_full_vector<T>::type vec;
61 
62  __SE_TEMPLATE_v1 se0Params = __gen_SE_TEMPLATE_v1();
63  __SA_TEMPLATE_v1 sa0Params = __gen_SA_TEMPLATE_v1();
64  MATHLIB_SE0SA01DSequentialInit(&se0Params, &sa0Params, length, pSrc, pDst);
65 
66  // calculate compute loop's iteration counter
67  numBlocks = length / c7x::element_count_of<vec>::value;
68  remNumBlocks = length % c7x::element_count_of<vec>::value;
69  if (remNumBlocks) {
70  numBlocks++;
71  }
72  // open SE0, SE1, and SA0 for reading and writing operands
73  MATHLIB_SE0SA0Open(&se0Params, &sa0Params, pSrc);
74 
75  /**********************************************************************/
76  /* Create and assign values for constants employed on log computation */
77  /**********************************************************************/
78 
79  vec C1, C2, C3, C4, C5, eMax, outVecMin, outVecMax;
80  c7x::double_vec ln2;
81  c7x::uint_vec zero;
82  zero = (c7x::uint_vec) 0;
83 
84  ln2 = (c7x::double_vec) 0.693147180559945;
85  C1 = (vec) -0.2302894f;
86  C2 = (vec) 0.1908169f;
87  C3 = (vec) -0.2505905f;
88  C4 = (vec) 0.3333164f;
89  C5 = (vec) -0.5000002f;
90  eMax = (vec) 3.402823466e+38f;
91  outVecMin = (vec) 0xFF800000u;
92  outVecMax = (vec) 709.7827f;
93 
94  // compute loop to perform vector log
95  for (size_t i = 0; i < numBlocks; i++) {
96  vec inVec = c7x::strm_eng<0, vec>::get_adv();
97 
98  /**********************************************************************/
99  /* Create variables employed on log computation */
100  /**********************************************************************/
101  vec pol, r1, r2, r3, r4;
102  c7x::double_vec inVecVals_odd, inVecVals_even, inVecVals_oddReciprocal, inVecVals_evenReciprocal,
103  inVecReciprocalApprox_8_15, inVecReciprocalApprox_0_7, inVecVals_8_15, inVecVals_0_7, rVals_0_7, rVals_8_15,
104  TVals_8_15, TVals_0_7, NVals_odd, NVals_even, NVals_0_7, NVals_8_15, outVec_8_15, outVec_0_7;
105  c7x::uint_vec inVecReciprocal_32_63, inVecReciprocalClr_32_63, inVecReciprocalApprox_32_63, indexT,
106  upperBitsIndexT, lowerBitsIndexT;
107  c7x::int_vec N;
108  vec outVec;
109 
110  /**********************************************************************/
111  /* Calculate Taylor series approximation for log */
112  /**********************************************************************/
113 
114  // Split vectors to compute r with double precision
115  inVecVals_odd = __high_float_to_double(inVec);
116  inVecVals_even = __low_float_to_double(inVec);
117  inVecVals_oddReciprocal = __recip(inVecVals_odd);
118  inVecVals_evenReciprocal = __recip(inVecVals_even);
119 
120  // Create floating point reciprocal approximation
121  // Upper 32 bits of all inVec reciprocal values
122  inVecReciprocal_32_63 = c7x::reinterpret<c7x::uint_vec>(
123  __permute_odd_odd_int(MATHLIB_vperm_data_interweave_0_63, c7x::as_uchar_vec(inVecVals_oddReciprocal),
124  c7x::as_uchar_vec(inVecVals_evenReciprocal)));
125 
126  // Clear bits 0-16 inclusive
127  inVecReciprocalClr_32_63 = inVecReciprocal_32_63 & 0xFFFE0000u;
128 
129  // Concatenate cleared bit reciprocal with zero bits
130  inVecReciprocalApprox_8_15 = c7x::reinterpret<c7x::double_vec>(__permute_high_high(
131  MATHLIB_vperm_data_interweave_0_63, c7x::as_uchar_vec(inVecReciprocalClr_32_63), c7x::as_uchar_vec(zero)));
132  inVecReciprocalApprox_0_7 = c7x::reinterpret<c7x::double_vec>(__permute_low_low(
133  MATHLIB_vperm_data_interweave_0_63, c7x::as_uchar_vec(inVecReciprocalClr_32_63), c7x::as_uchar_vec(zero)));
134 
135  // Split inVec into two vectors with double precision
136  inVecVals_0_7 = c7x::reinterpret<c7x::double_vec>(__permute_low_low(
137  MATHLIB_vperm_data_dp_interweave_0_63, c7x::as_uchar_vec(inVecVals_odd), c7x::as_uchar_vec(inVecVals_even)));
138  inVecVals_8_15 = c7x::reinterpret<c7x::double_vec>(__permute_high_high(
139  MATHLIB_vperm_data_dp_interweave_0_63, c7x::as_uchar_vec(inVecVals_odd), c7x::as_uchar_vec(inVecVals_even)));
140 
141  // Calculate r in double precision
142  rVals_0_7 = (inVecReciprocalApprox_0_7 * inVecVals_0_7) - 1.0;
143  rVals_8_15 = (inVecReciprocalApprox_8_15 * inVecVals_8_15) - 1.0;
144 
145  // Convert r to float, compute r to the power of 2, 3, 4
146  r1 = c7x::reinterpret<vec>(__permute_even_even_int(MATHLIB_vperm_data_0_63,
147  c7x::as_uchar_vec(__double_to_float(rVals_8_15)),
148  c7x::as_uchar_vec(__double_to_float(rVals_0_7))));
149  r2 = r1 * r1;
150  r3 = r1 * r2;
151  r4 = r2 * r2;
152 
153  // Compute Taylor series polynomial
154  pol = (C5 * r2) + ((C4 * r3) + ((((C2 * r1) + C3) + (C1 * r2)) * r4));
155 
156  /**********************************************************************/
157  /* Calculate N */
158  /**********************************************************************/
159 
160  // Upper 32 bits of all inVec reciprocal approximation values
161  inVecReciprocalApprox_32_63 = c7x::reinterpret<c7x::uint_vec>(
162  __permute_odd_odd_int(MATHLIB_vperm_data_0_63, c7x::as_uchar_vec(inVecReciprocalApprox_8_15),
163  c7x::as_uchar_vec(inVecReciprocalApprox_0_7)));
164 
165  N = c7x::convert<c7x::int_vec>(((inVecReciprocalApprox_32_63 << 1) >> 21) - 1023);
166 
167  // Covert N to double precision for later calculation with LUT values
168  NVals_odd = __high_int_to_double(N);
169  NVals_even = __low_int_to_double(N);
170  NVals_0_7 = c7x::reinterpret<c7x::double_vec>(__permute_low_low(
171  MATHLIB_vperm_data_dp_interweave_0_63, c7x::as_uchar_vec(NVals_odd), c7x::as_uchar_vec(NVals_even)));
172  NVals_8_15 = c7x::reinterpret<c7x::double_vec>(__permute_high_high(
173  MATHLIB_vperm_data_dp_interweave_0_63, c7x::as_uchar_vec(NVals_odd), c7x::as_uchar_vec(NVals_even)));
174 
175  /**********************************************************************/
176  /* Determine LUT values */
177  /**********************************************************************/
178 
179  // Calculate LUT index
180  indexT = (((inVecReciprocalApprox_32_63 << 12) >> 29) + MATHLIB_LOGTABLE_OFFSET);
181 
182  upperBitsIndexT = MATHLIB_LUTReadUpperBits(indexT);
183  lowerBitsIndexT = MATHLIB_LUTReadLowerBits(indexT);
184 
185  // Read from LUT and reconstruct double values split into two vectors
186  TVals_8_15 = c7x::reinterpret<c7x::double_vec>(__permute_high_high(
187  MATHLIB_vperm_data_interweave_0_63, c7x::as_uchar_vec(upperBitsIndexT), c7x::as_uchar_vec(lowerBitsIndexT)));
188  TVals_0_7 = c7x::reinterpret<c7x::double_vec>(__permute_low_low(
189  MATHLIB_vperm_data_interweave_0_63, c7x::as_uchar_vec(upperBitsIndexT), c7x::as_uchar_vec(lowerBitsIndexT)));
190 
191  // Calculate an adjusted T
192  TVals_8_15 = TVals_8_15 - (ln2 * NVals_8_15);
193  TVals_0_7 = TVals_0_7 - (ln2 * NVals_0_7);
194 
195  /**********************************************************************/
196  /* Calculate output with adjusted LUT and Taylor series values */
197  /**********************************************************************/
198 
199  // Add LUT values and Taylor series values
200  outVec_0_7 = rVals_0_7 + TVals_0_7;
201  outVec_8_15 = rVals_8_15 + TVals_8_15;
202 
203  // Combine output vector into one floating point result
204  outVec = c7x::reinterpret<vec>(__permute_even_even_int(MATHLIB_vperm_data_0_63,
205  c7x::as_uchar_vec(__double_to_float(outVec_8_15)),
206  c7x::as_uchar_vec(__double_to_float(outVec_0_7))));
207  outVec = outVec + pol;
208 
209  /**********************************************************************/
210  /* Bounds checking */
211  /**********************************************************************/
212 
213  // if (a <= 0.0f) {
214  // res = _itof(0xFF800000u);
215  // }
216  __vpred cmp_min = __cmp_le_pred(inVec, c7x::convert<vec>(zero));
217  outVec = __select(cmp_min, outVecMin, outVec);
218 
219  // if (a > MAXe) {
220  // res = 709.7827f;
221  // }
222  __vpred cmp_max = __cmp_lt_pred(eMax, inVec);
223  outVec = __select(cmp_max, outVecMax, outVec);
224 
225  __vpred tmp = c7x::strm_agen<0, vec>::get_vpred();
226  vec *addr = c7x::strm_agen<0, vec>::get_adv(pDst);
227  __vstore_pred(tmp, addr, outVec);
228  }
229 
231 }
232 
233 // this method performs log computation of input vector
234 template <typename T> MATHLIB_STATUS MATHLIB_log(size_t length, T *restrict pSrc, T *restrict pDst)
235 {
236  MATHLIB_STATUS status = MATHLIB_SUCCESS; // return function status
237 
238  // check for null pointers and non-zero length
239  status = MATHLIB_checkParams(length, pSrc, pDst);
240 
241  if (status == MATHLIB_SUCCESS) {
242  MATHLIB_log_vector(length, pSrc, pDst);
243  }
244 
245  return status;
246 }
247 
248 /******************************************************************************/
249 /* */
250 /* Explicit templatization for datatypes supported by MATHLIB_log */
251 /* */
252 /******************************************************************************/
253 
254 // single precision
255 template MATHLIB_STATUS MATHLIB_log<float>(size_t length, float *pSrc, float *pDst);
256 
257 /******************************************************************************/
258 /* */
259 /* C-interface wrapper functions */
260 /* */
261 /******************************************************************************/
262 
263 extern "C" {
264 
265 // single-precision wrapper
266 MATHLIB_STATUS MATHLIB_log_sp(size_t length, float *pSrc, float *pDst)
267 {
268  MATHLIB_STATUS status = MATHLIB_log(length, pSrc, pDst);
269  return status;
270 }
271 
272 } // extern "C"
template MATHLIB_STATUS MATHLIB_log< float >(size_t length, float *pSrc, float *pDst)
static void MATHLIB_log_vector(size_t length, T *restrict pSrc, T *restrict pDst)
Definition: MATHLIB_log.cpp:54
MATHLIB_STATUS MATHLIB_log(size_t length, T *restrict pSrc, T *restrict pDst)
MATHLIB_STATUS MATHLIB_log_sp(size_t length, float *pSrc, float *pDst)
This function is the C interface for MATHLIB_log. Function accepts float pointers.
#define MATHLIB_LOGTABLE_OFFSET
Definition: MATHLIB_lut.h:66
static c7x::uint_vec MATHLIB_LUTReadLowerBits(vecType vecOffset)
This method reads bits 31-0 of LUT value at vecOffset.
Definition: MATHLIB_lut.h:111
static c7x::uint_vec MATHLIB_LUTReadUpperBits(vecType vecOffset)
This method reads bits 63-32 of LUT value at vecOffset.
Definition: MATHLIB_lut.h:86
static void MATHLIB_SE0SA0Close()
This method performs SE0 and SA0 close.
static void MATHLIB_SE0SA01DSequentialInit(__SE_TEMPLATE_v1 *se0Params, __SA_TEMPLATE_v1 *sa0Params, size_t length, T *pSrc, T *pDst)
static MATHLIB_STATUS MATHLIB_checkParams(size_t length, T *pSrc, T *pDst)
This method performs parameter checks for MATHLIB function.
static void MATHLIB_SE0SA0Open(__SE_TEMPLATE_v1 *se0Params, __SA_TEMPLATE_v1 *sa0Params, T *pSrc)
This method performs SE0 and SA0 open.
MATHLIB_STATUS_NAME
The enumeration of all status codes.
@ MATHLIB_SUCCESS