walnux/include/nuttx/lib/math32.h
Alin Jerpelea cd2fcf5252 include: migrate to SPDX identifier
Most tools used for compliance and SBOM generation use SPDX identifiers
This change brings us a step closer to an easy SBOM generation.

Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>
2024-10-04 08:18:42 +08:00

496 lines
15 KiB
C

/****************************************************************************
* include/nuttx/lib/math32.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_LIB_MATH32_H
#define __INCLUDE_NUTTX_LIB_MATH32_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <inttypes.h>
#include <stdint.h>
#include <strings.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define div_round_up(n, d) (((n) + (d) - 1) / (d))
#define div_round_closest(n, d) ((((n) < 0) ^ ((d) < 0)) ? \
(((n) - (d)/2)/(d)) : (((n) + (d)/2)/(d)))
/* Returns one plus the index of the most significant 1-bit of n,
* or if n is zero, returns zero.
*/
#if UINTPTR_MAX > UINT32_MAX
# define FLS(n) ((n) & UINT64_C(0xffffffff00000000) ? 32 + \
FLS32((size_t)(n) >> 32) : FLS32(n))
#else
# define FLS(n) FLS32(n)
#endif
#define FLS32(n) ((n) & 0xffff0000 ? 16 + FLS16((n) >> 16) : FLS16(n))
#define FLS16(n) ((n) & 0xff00 ? 8 + FLS8 ((n) >> 8) : FLS8 (n))
#define FLS8(n) ((n) & 0xf0 ? 4 + FLS4 ((n) >> 4) : FLS4 (n))
#define FLS4(n) ((n) & 0xc ? 2 + FLS2 ((n) >> 2) : FLS2 (n))
#define FLS2(n) ((n) & 0x2 ? 1 + FLS1 ((n) >> 1) : FLS1 (n))
#define FLS1(n) ((n) & 0x1 ? 1 : 0)
/* Checks if an integer is power of two at compile time */
#define IS_POWER_OF_2(n) ((n) > 0 && ((n) & (n - 1)) == 0)
/* Returns round up and round down value of log2(n). Note: it can be used at
* compile time.
*/
#define LOG2_CEIL(n) (IS_POWER_OF_2(n) ? FLS(n) - 1 : FLS(n))
#define LOG2_FLOOR(n) (FLS(n) - 1)
/****************************************************************************
* Public Types
****************************************************************************/
/* These types are useful on platforms that do not support 64-bit types. */
struct int64_s
{
#ifdef CONFIG_ENDIAN_BIG
int32_t ms;
uint32_t ls;
#else
uint32_t ls;
int32_t ms;
#endif
};
struct uint64_s
{
#ifdef CONFIG_ENDIAN_BIG
uint32_t ms;
uint32_t ls;
#else
uint32_t ls;
uint32_t ms;
#endif
};
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#define is_power_of_2(n) IS_POWER_OF_2(n)
#define flsx(n) ((sizeof(n) <= sizeof(long)) ? flsl(n) : flsll(n))
/****************************************************************************
* Name: log2ceil
*
* Description:
* Calculate the up-rounded power-of-two for input.
*
* Input Parameters:
* x - Argument to calculate the power-of-two from.
*
* Returned Value:
* Power-of-two for argument, rounded up.
*
****************************************************************************/
#define log2ceil(n) (is_power_of_2(n) ? (flsx(n) - 1) : flsx(n))
/****************************************************************************
* Name: log2floor
*
* Description:
* Calculate the down-rounded (truncated) power-of-two for input.
*
* Input Parameters:
* x - Argument to calculate the power-of-two from.
*
* Returned Value:
* Power-of-two for argument, rounded (truncated) down.
*
****************************************************************************/
#define log2floor(n) (flsx(n) - 1)
/* roundup_pow_of_two() - Round up to nearest power of two
* n: value to round up
*/
#define roundup_pow_of_two(n) (((n) - (n) + 1) << flsx((n) - 1))
/* rounddown_pow_of_two() - Round down to nearest power of two
* n: value to round down
*/
#define rounddown_pow_of_two(n) (((n) - (n) + 1) << (flsx(n) - 1))
/* order_base_2 - Calculate the (rounded up) base 2 order of the argument
* n: parameter
*
* The first few values calculated by this routine:
* ob2(0) = 0
* ob2(1) = 0
* ob2(2) = 1
* ob2(3) = 2
* ob2(4) = 2
* ob2(5) = 3
* ... and so on.
*/
#define order_base_2(n) ((n) > 1 ? log2floor((n) - 1) + 1 : 0)
/* If the divisor happens to be constant, we determine the appropriate
* inverse at compile time to turn the division into a few inline
* multiplications which ought to be much faster.
*
* (It is unfortunate that gcc doesn't perform all this internally.)
*/
#ifdef CONFIG_HAVE_LONG_LONG
/* Default C implementation for umul64_const()
*
* Prototype: uint64_t umul64_const(uint64_t retval, uint64_t m,
* uint64_t n, bool bias);
* Semantic: retval = ((bias ? m : 0) + m * n) >> 64
*
* The product is a 128-bit value, scaled down to 64 bits.
* Assuming constant propagation to optimize away unused conditional code.
* Architectures may provide their own optimized assembly implementation.
*/
# ifdef up_umul64_const
# define umul64_const(res, m, n, bias) \
(res) = up_umul64_const(m, n, bias)
# else
# define umul64_const(res, m, n, bias) \
do \
{ \
uint32_t __m_lo = (m) & 0xffffffff; \
uint32_t __m_hi = (m) >> 32; \
uint32_t __n_lo = (n) & 0xffffffff; \
uint32_t __n_hi = (n) >> 32; \
uint32_t __res_lo; \
uint32_t __res_hi; \
uint32_t __tmp; \
\
if (!(bias)) \
{ \
(res) = ((uint64_t)__m_lo * __n_lo) >> 32; \
} \
else if (!((m) & ((1ULL << 63) | (1ULL << 31)))) \
{ \
(res) = ((m) + (uint64_t)__m_lo * __n_lo) >> 32; \
} \
else \
{ \
(res) = (m) + (uint64_t)__m_lo * __n_lo; \
__res_lo = (res) >> 32; \
__res_hi = (__res_lo < __m_hi); \
(res) = __res_lo | ((uint64_t)__res_hi << 32); \
} \
\
if (!((m) & ((1ULL << 63) | (1ULL << 31)))) \
{ \
(res) += (uint64_t)__m_lo * __n_hi; \
(res) += (uint64_t)__m_hi * __n_lo; \
(res) >>= 32; \
} \
else \
{ \
(res) += (uint64_t)__m_lo * __n_hi; \
__tmp = (res) >> 32; \
(res) += (uint64_t)__m_hi * __n_lo; \
__res_lo = (res) >> 32; \
__res_hi = (__res_lo < __tmp); \
(res) = __res_lo | ((uint64_t)__res_hi << 32); \
} \
\
(res) += (uint64_t)__m_hi * __n_hi; \
} \
while (0)
# endif
# define div64_const32(n, b) \
do \
{ \
uint64_t ___res; \
uint64_t ___x; \
uint64_t ___t; \
uint64_t ___m; \
uint64_t ___n = (n); \
uint32_t ___p; \
uint32_t ___bias; \
uint32_t ___b = (b); \
___p = 1 << LOG2_FLOOR(___b); \
___m = (~0ULL / ___b) * ___p; \
___m += (((~0ULL % ___b + 1) * ___p) + ___b - 1) / ___b; \
___x = ~0ULL / ___b * ___b - 1; \
___res = ((___m & 0xffffffff) * (___x & 0xffffffff)) >> 32; \
___t = ___res += (___m & 0xffffffff) * (___x >> 32); \
___res += (___x & 0xffffffff) * (___m >> 32); \
___t = (___res < ___t) ? (1ULL << 32) : 0; \
___res = (___res >> 32) + ___t; \
___res += (___m >> 32) * (___x >> 32); \
___res /= ___p; \
if (~0ULL % (___b / (___b & -___b)) == 0) \
{ \
___n /= (___b & -___b); \
___m = ~0ULL / (___b / (___b & -___b)); \
___p = 1; \
___bias = 1; \
} \
else if (___res != ___x / ___b) \
{ \
___bias = 1; \
___m = (~0ULL / ___b) * ___p; \
___m += ((~0ULL % ___b + 1) * ___p) / ___b; \
} \
else \
{ \
uint32_t ___bits = -(___m & -___m); \
___bits |= ___m >> 32; \
___bits = (~___bits) << 1; \
if (!___bits) \
{ \
___p /= (___m & -___m); \
___m /= (___m & -___m); \
} \
else \
{ \
___p >>= LOG2_FLOOR(___bits); \
___m >>= LOG2_FLOOR(___bits); \
} \
___bias = 0; \
} \
umul64_const(___res, ___m, ___n, ___bias); \
\
___res /= ___p; \
(n) = ___res; \
} \
while (0)
#endif
#if defined(CONFIG_HAVE_LONG_LONG) && defined(CONFIG_HAVE_EXPRESSION_STATEMENT)
# define div64_const(n, base) \
({ \
uint64_t __n = (n); \
uint32_t __base = (base); \
if (IS_POWER_OF_2(__base)) \
{ \
(__n) >>= LOG2_FLOOR(__base); \
} \
else if (UINTPTR_MAX == UINT32_MAX) \
{ \
div64_const32(__n, __base); \
} \
else \
{ \
__n /= __base; \
} \
__n; \
})
# define div_const(n, base) \
((sizeof(typeof(n)) == sizeof(uint64_t)) ? div64_const(n, base) : ((n) / (base)))
# define div_const_roundup(n, base) \
((sizeof(typeof(n)) == sizeof(uint64_t)) ? div64_const((n) + (base) - 1, base) : \
(((n) + (base) - 1) / (base)))
# define div_const_roundnearest(n, base) \
((sizeof(typeof(n)) == sizeof(uint64_t)) ? div64_const((n) + ((base) / 2), base) : \
(((n) + ((base) / 2)) / (base)))
#else
# define div_const(n, base) ((n) / (base))
# define div_const_roundup(n, base) (((n) + (base) - 1) / (base))
# define div_const_roundnearest(n, base) (((n) + ((base) / 2)) / (base))
#endif
/****************************************************************************
* Name: uneg64
*
* Description:
* Negate a 64-bit unsigned value.
*
* Input Parameters:
* value - The value to be negated.
*
****************************************************************************/
/* void uneg64(FAR const uint64_s *value); */
#define uneg64(value) \
do \
{ \
value->ms = ~value->ms; \
value->ls = -value->ls; \
if (value->ls == 0) \
{ \
value->ms++; \
} \
} \
while (0)
/****************************************************************************
* Name: uadd32x64
*
* Description:
* Add a 32-bit value to a 64-bit values and return the truncated 64-bit
* sum.
*
* Input Parameters:
* term1 and term2 - The values to be added
* sum - The location to return the product of the two values. sum may
* be one of term1 or term2
*
****************************************************************************/
void uadd32x64(uint32_t term1, FAR const struct uint64_s *term2,
FAR struct uint64_s *sum);
/****************************************************************************
* Name: uadd64
*
* Description:
* Add two 64-bit values and return a 64-bit sum.
*
* Input Parameters:
* term1 and term2 - The values to be added
* sum - The location to return the product of the two values. sum may
* be one of term1 or term2
*
****************************************************************************/
void uadd64(FAR const struct uint64_s *term1,
FAR const struct uint64_s *term2,
FAR struct uint64_s *sum);
/****************************************************************************
* Name: usub64x32
*
* Description:
* Subtract a 32-bit value from a 64-bit value and return the 64-bit
* difference.
*
* Input Parameters:
* minuend - The number from which another number (the Subtrahend) is
* to be subtracted.
* subtrahend - The number that is to be subtracted.
* difference - The location to return the difference of the two values.
* difference may the same as one of minuend or subtrahend.
*
****************************************************************************/
void usub64x32(FAR const struct uint64_s *minuend, uint32_t subtrahend,
FAR struct uint64_s *difference);
/****************************************************************************
* Name: usub64
*
* Description:
* Subtract two 64-bit values and return the 64-bit difference.
*
* Input Parameters:
* minuend - The number from which another number (the Subtrahend) is
* to be subtracted.
* subtrahend - The number that is to be subtracted.
* difference - The location to return the difference of the two values.
* difference may the same as one of minuend or subtrahend.
*
****************************************************************************/
void usub64(FAR const struct uint64_s *minuend,
FAR const struct uint64_s *subtrahend,
FAR struct uint64_s *difference);
/****************************************************************************
* Name: umul32
*
* Description:
* Multiply two 32-bit values, factor1 and factor2, and return the
* full 64-bit product.
*
* Input Parameters:
* factor1 and factor2 - The values to be multiplied
* product - The location to return the product of the two values.
*
****************************************************************************/
void umul32(uint32_t factor1, uint32_t factor2,
FAR struct uint64_s *product);
/****************************************************************************
* Name: umul32x64
*
* Description:
* Multiply one 32-bit and one 64-bit values, factor1 and factor2,
* respectively, and return the truncated 64-bit product.
*
* Input Parameters:
* factor1 and factor2 - The values to be multiplied
* product - The location to return the product of the two values.
*
****************************************************************************/
void umul32x64(uint32_t factor1, FAR const struct uint64_s *factor2,
FAR struct uint64_s *product);
/****************************************************************************
* Name: umul64
*
* Description:
* Multiply two 64-bit values, factor1 and factor2, and return the
* truncated 64-bit product.
*
* Input Parameters:
* factor1 and factor2 - The values to be multiplied
* product - The location to return the product of the two values.
*
****************************************************************************/
void umul64(FAR const struct uint64_s *factor1,
FAR const struct uint64_s *factor2,
FAR struct uint64_s *product);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __INCLUDE_NUTTX_LIB_MATH32_H */