LCOV - code coverage report
Current view: top level - zephyr/sys - math_extras_impl.h Hit Total Coverage
Test: new.info Lines: 1 14 7.1 %
Date: 2024-12-22 00:14:23

          Line data    Source code
       1           1 : /*
       2             :  * Copyright (c) 2019 Facebook.
       3             :  *
       4             :  * SPDX-License-Identifier: Apache-2.0
       5             :  */
       6             : 
       7             : /**
       8             :  * @file
       9             :  * @brief Inline implementation of functions declared in math_extras.h.
      10             :  */
      11             : 
      12             : #ifndef ZEPHYR_INCLUDE_SYS_MATH_EXTRAS_H_
      13             : #error "please include <sys/math_extras.h> instead of this file"
      14             : #endif
      15             : 
      16             : #include <zephyr/toolchain.h>
      17             : 
      18             : /*
      19             :  * Force the use of portable C code (no builtins) by defining
      20             :  * PORTABLE_MISC_MATH_EXTRAS before including <misc/math_extras.h>.
      21             :  * This is primarily for use by tests.
      22             :  *
      23             :  * We'll #undef use_builtin again at the end of the file.
      24             :  */
      25             : #ifdef PORTABLE_MISC_MATH_EXTRAS
      26             : #define use_builtin(x) 0
      27             : #else
      28           0 : #define use_builtin(x) HAS_BUILTIN(x)
      29             : #endif
      30             : 
      31             : #if use_builtin(__builtin_add_overflow)
      32             : static inline bool u16_add_overflow(uint16_t a, uint16_t b, uint16_t *result)
      33             : {
      34             :         return __builtin_add_overflow(a, b, result);
      35             : }
      36             : 
      37             : static inline bool u32_add_overflow(uint32_t a, uint32_t b, uint32_t *result)
      38             : {
      39             :         return __builtin_add_overflow(a, b, result);
      40             : }
      41             : 
      42             : static inline bool u64_add_overflow(uint64_t a, uint64_t b, uint64_t *result)
      43             : {
      44             :         return __builtin_add_overflow(a, b, result);
      45             : }
      46             : 
      47             : static inline bool size_add_overflow(size_t a, size_t b, size_t *result)
      48             : {
      49             :         return __builtin_add_overflow(a, b, result);
      50             : }
      51             : #else /* !use_builtin(__builtin_add_overflow) */
      52           0 : static inline bool u16_add_overflow(uint16_t a, uint16_t b, uint16_t *result)
      53             : {
      54             :         uint16_t c = a + b;
      55             : 
      56             :         *result = c;
      57             : 
      58             :         return c < a;
      59             : }
      60             : 
      61           0 : static inline bool u32_add_overflow(uint32_t a, uint32_t b, uint32_t *result)
      62             : {
      63             :         uint32_t c = a + b;
      64             : 
      65             :         *result = c;
      66             : 
      67             :         return c < a;
      68             : }
      69             : 
      70           0 : static inline bool u64_add_overflow(uint64_t a, uint64_t b, uint64_t *result)
      71             : {
      72             :         uint64_t c = a + b;
      73             : 
      74             :         *result = c;
      75             : 
      76             :         return c < a;
      77             : }
      78             : 
      79           0 : static inline bool size_add_overflow(size_t a, size_t b, size_t *result)
      80             : {
      81             :         size_t c = a + b;
      82             : 
      83             :         *result = c;
      84             : 
      85             :         return c < a;
      86             : }
      87             : #endif /* use_builtin(__builtin_add_overflow) */
      88             : 
      89             : #if use_builtin(__builtin_mul_overflow)
      90             : static inline bool u16_mul_overflow(uint16_t a, uint16_t b, uint16_t *result)
      91             : {
      92             :         return __builtin_mul_overflow(a, b, result);
      93             : }
      94             : 
      95             : static inline bool u32_mul_overflow(uint32_t a, uint32_t b, uint32_t *result)
      96             : {
      97             :         return __builtin_mul_overflow(a, b, result);
      98             : }
      99             : 
     100             : static inline bool u64_mul_overflow(uint64_t a, uint64_t b, uint64_t *result)
     101             : {
     102             :         return __builtin_mul_overflow(a, b, result);
     103             : }
     104             : 
     105             : static inline bool size_mul_overflow(size_t a, size_t b, size_t *result)
     106             : {
     107             :         return __builtin_mul_overflow(a, b, result);
     108             : }
     109             : #else /* !use_builtin(__builtin_mul_overflow) */
     110           0 : static inline bool u16_mul_overflow(uint16_t a, uint16_t b, uint16_t *result)
     111             : {
     112             :         uint16_t c = a * b;
     113             : 
     114             :         *result = c;
     115             : 
     116             :         return a != 0 && (c / a) != b;
     117             : }
     118             : 
     119           0 : static inline bool u32_mul_overflow(uint32_t a, uint32_t b, uint32_t *result)
     120             : {
     121             :         uint32_t c = a * b;
     122             : 
     123             :         *result = c;
     124             : 
     125             :         return a != 0 && (c / a) != b;
     126             : }
     127             : 
     128           0 : static inline bool u64_mul_overflow(uint64_t a, uint64_t b, uint64_t *result)
     129             : {
     130             :         uint64_t c = a * b;
     131             : 
     132             :         *result = c;
     133             : 
     134             :         return a != 0 && (c / a) != b;
     135             : }
     136             : 
     137           0 : static inline bool size_mul_overflow(size_t a, size_t b, size_t *result)
     138             : {
     139             :         size_t c = a * b;
     140             : 
     141             :         *result = c;
     142             : 
     143             :         return a != 0 && (c / a) != b;
     144             : }
     145             : #endif /* use_builtin(__builtin_mul_overflow) */
     146             : 
     147             : 
     148             : /*
     149             :  * The GCC builtins __builtin_clz(), __builtin_ctz(), and 64-bit
     150             :  * variants are described by the GCC documentation as having undefined
     151             :  * behavior when the argument is zero. See
     152             :  * https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
     153             :  *
     154             :  * The undefined behavior applies to all architectures, regardless of
     155             :  * the behavior of the instruction used to implement the builtin.
     156             :  *
     157             :  * We don't want to expose users of this API to the undefined behavior,
     158             :  * so we use a conditional to explicitly provide the correct result when
     159             :  * x=0.
     160             :  *
     161             :  * Most instruction set architectures have a CLZ instruction or similar
     162             :  * that already computes the correct result for x=0. Both GCC and Clang
     163             :  * know this and simply generate a CLZ instruction, optimizing away the
     164             :  * conditional.
     165             :  *
     166             :  * For x86, and for compilers that fail to eliminate the conditional,
     167             :  * there is often another opportunity for optimization since code using
     168             :  * these functions tends to contain a zero check already. For example,
     169             :  * from kernel/sched.c:
     170             :  *
     171             :  *      struct k_thread *z_priq_mq_best(struct _priq_mq *pq)
     172             :  *      {
     173             :  *              if (!pq->bitmask) {
     174             :  *                      return NULL;
     175             :  *              }
     176             :  *
     177             :  *              struct k_thread *thread = NULL;
     178             :  *              sys_dlist_t *l =
     179             :  *                      &pq->queues[u32_count_trailing_zeros(pq->bitmask)];
     180             :  *
     181             :  *              ...
     182             :  *
     183             :  * The compiler will often be able to eliminate the redundant x == 0
     184             :  * check after inlining the call to u32_count_trailing_zeros().
     185             :  */
     186             : 
     187             : #if use_builtin(__builtin_clz)
     188             : static inline int u32_count_leading_zeros(uint32_t x)
     189             : {
     190             :         return (x == 0) ? 32 : __builtin_clz(x);
     191             : }
     192             : #else /* !use_builtin(__builtin_clz) */
     193           0 : static inline int u32_count_leading_zeros(uint32_t x)
     194             : {
     195             :         int b;
     196             : 
     197             :         for (b = 0; b < 32 && (x >> 31) == 0; b++) {
     198             :                 x <<= 1;
     199             :         }
     200             : 
     201             :         return b;
     202             : }
     203             : #endif /* use_builtin(__builtin_clz) */
     204             : 
     205             : #if use_builtin(__builtin_clzll)
     206             : static inline int u64_count_leading_zeros(uint64_t x)
     207             : {
     208             :         return (x == 0) ? 64 : __builtin_clzll(x);
     209             : }
     210             : #else /* !use_builtin(__builtin_clzll) */
     211           0 : static inline int u64_count_leading_zeros(uint64_t x)
     212             : {
     213             :         if (x == (uint32_t)x) {
     214             :                 return 32 + u32_count_leading_zeros((uint32_t)x);
     215             :         } else {
     216             :                 return u32_count_leading_zeros(x >> 32);
     217             :         }
     218             : }
     219             : #endif /* use_builtin(__builtin_clzll) */
     220             : 
     221             : #if use_builtin(__builtin_ctz)
     222             : static inline int u32_count_trailing_zeros(uint32_t x)
     223             : {
     224             :         return (x == 0) ? 32 : __builtin_ctz(x);
     225             : }
     226             : #else /* !use_builtin(__builtin_ctz) */
     227           0 : static inline int u32_count_trailing_zeros(uint32_t x)
     228             : {
     229             :         int b;
     230             : 
     231             :         for (b = 0; b < 32 && (x & 1) == 0; b++) {
     232             :                 x >>= 1;
     233             :         }
     234             : 
     235             :         return b;
     236             : }
     237             : #endif /* use_builtin(__builtin_ctz) */
     238             : 
     239             : #if use_builtin(__builtin_ctzll)
     240             : static inline int u64_count_trailing_zeros(uint64_t x)
     241             : {
     242             :         return (x == 0) ? 64 : __builtin_ctzll(x);
     243             : }
     244             : #else /* !use_builtin(__builtin_ctzll) */
     245           0 : static inline int u64_count_trailing_zeros(uint64_t x)
     246             : {
     247             :         if ((uint32_t)x) {
     248             :                 return u32_count_trailing_zeros((uint32_t)x);
     249             :         } else {
     250             :                 return 32 + u32_count_trailing_zeros(x >> 32);
     251             :         }
     252             : }
     253             : #endif /* use_builtin(__builtin_ctzll) */
     254             : 
     255             : #undef use_builtin

Generated by: LCOV version 1.14