Z_POW2_CEIL: simplify implementation

Avoid potentially calling __builtin_clz() twice with non-constant
values. Also add a test for it.

Clang produces false positive vla warnings so disable them. GCC will
spot real vla's already.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2022-04-06 13:36:40 -04:00 committed by Carles Cufí
parent 92bc3e47c0
commit f00573555b
5 changed files with 89 additions and 13 deletions

View file

@ -381,6 +381,9 @@ if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
if(NOT ${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "xcc")
zephyr_cc_option(-fno-defer-pop)
endif()
else()
# Clang produces false positive vla warnings
zephyr_cc_option(-Wno-vla)
endif()
zephyr_cc_option_ifdef(CONFIG_STACK_USAGE -fstack-usage)

View file

@ -595,15 +595,8 @@ do { \
* @param x Nonzero unsigned long value
* @return X rounded up to the next power of two
*/
#ifdef CONFIG_64BIT
#define Z_POW2_CEIL(x) ((1UL << (63U - __builtin_clzl(x))) < x ? \
1UL << (63U - __builtin_clzl(x) + 1U) : \
1UL << (63U - __builtin_clzl(x)))
#else
#define Z_POW2_CEIL(x) ((1UL << (31U - __builtin_clz(x))) < x ? \
1UL << (31U - __builtin_clz(x) + 1U) : \
1UL << (31U - __builtin_clz(x)))
#endif
#define Z_POW2_CEIL(x) \
((x) <= 2UL ? (x) : (1UL << (8 * sizeof(long) - __builtin_clzl((x) - 1))))
/**
* @brief Check whether or not a value is a power of 2

View file

@ -22,7 +22,8 @@ target_sources(app PRIVATE
src/main.c
src/timeout_order.c
src/multilib.c
src/errno.c
src/boot_delay.c
src/irq_offload.c
src/errno.c
src/boot_delay.c
src/irq_offload.c
src/pow2.c
)

View file

@ -52,6 +52,7 @@ extern void test_bitarray_alloc_free(void);
extern void test_bitarray_region_set_clear(void);
extern void test_nop(void);
extern void test_ffs(void);
extern void test_pow2_ceil(void);
/**
* @defgroup kernel_common_tests Common Tests
@ -168,7 +169,8 @@ void test_main(void)
ztest_unit_test(test_ms_time_duration),
ztest_unit_test(test_bounds_check_mitigation),
ztest_unit_test(test_nop),
ztest_unit_test(test_ffs)
ztest_unit_test(test_ffs),
ztest_unit_test(test_pow2_ceil)
);
ztest_run_test_suite(common);

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2022 BayLibre SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <ztest.h>
#include <zephyr.h>
/**
* @brief Test the Z_POW2_CEIL() macro
*
* @defgroup test_pow2_ceil Z_POW2_CEIL() tests
*
* @ingroup all_tests
*
* @{
* @}
*/
/**
* @brief Verify compile-time constant results
*
* @ingroup test_pow2_ceil
*
* @details Check if static array allocations are sized as expected.
*/
char static_array1[Z_POW2_CEIL(1)];
char static_array2[Z_POW2_CEIL(2)];
char static_array3[Z_POW2_CEIL(3)];
char static_array4[Z_POW2_CEIL(4)];
char static_array5[Z_POW2_CEIL(5)];
char static_array7[Z_POW2_CEIL(7)];
char static_array8[Z_POW2_CEIL(8)];
char static_array9[Z_POW2_CEIL(9)];
BUILD_ASSERT(sizeof(static_array1) == 1);
BUILD_ASSERT(sizeof(static_array2) == 2);
BUILD_ASSERT(sizeof(static_array3) == 4);
BUILD_ASSERT(sizeof(static_array4) == 4);
BUILD_ASSERT(sizeof(static_array5) == 8);
BUILD_ASSERT(sizeof(static_array7) == 8);
BUILD_ASSERT(sizeof(static_array8) == 8);
BUILD_ASSERT(sizeof(static_array9) == 16);
/**
* @brief Verify run-time non-constant results
*
* @ingroup test_pow2_ceil
*
* @details Check if run-time non-constant results are as expected.
* Use a volatile variable to prevent compiler optimizations.
*/
static void test_pow2_ceil_x(unsigned long test_value,
unsigned long expected_result)
{
volatile unsigned int x = test_value;
unsigned int result = Z_POW2_CEIL(x);
zassert_equal(result, expected_result,
"ZPOW2_CEIL(%lu) returned %lu, expected %lu",
test_value, result, expected_result);
}
void test_pow2_ceil(void)
{
test_pow2_ceil_x(1, 1);
test_pow2_ceil_x(2, 2);
test_pow2_ceil_x(3, 4);
test_pow2_ceil_x(4, 4);
test_pow2_ceil_x(5, 8);
test_pow2_ceil_x(7, 8);
test_pow2_ceil_x(8, 8);
test_pow2_ceil_x(9, 16);
}