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:
parent
92bc3e47c0
commit
f00573555b
5 changed files with 89 additions and 13 deletions
|
@ -381,6 +381,9 @@ if(NOT CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||||
if(NOT ${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "xcc")
|
if(NOT ${ZEPHYR_TOOLCHAIN_VARIANT} STREQUAL "xcc")
|
||||||
zephyr_cc_option(-fno-defer-pop)
|
zephyr_cc_option(-fno-defer-pop)
|
||||||
endif()
|
endif()
|
||||||
|
else()
|
||||||
|
# Clang produces false positive vla warnings
|
||||||
|
zephyr_cc_option(-Wno-vla)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
zephyr_cc_option_ifdef(CONFIG_STACK_USAGE -fstack-usage)
|
zephyr_cc_option_ifdef(CONFIG_STACK_USAGE -fstack-usage)
|
||||||
|
|
|
@ -595,15 +595,8 @@ do { \
|
||||||
* @param x Nonzero unsigned long value
|
* @param x Nonzero unsigned long value
|
||||||
* @return X rounded up to the next power of two
|
* @return X rounded up to the next power of two
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_64BIT
|
#define Z_POW2_CEIL(x) \
|
||||||
#define Z_POW2_CEIL(x) ((1UL << (63U - __builtin_clzl(x))) < x ? \
|
((x) <= 2UL ? (x) : (1UL << (8 * sizeof(long) - __builtin_clzl((x) - 1))))
|
||||||
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
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check whether or not a value is a power of 2
|
* @brief Check whether or not a value is a power of 2
|
||||||
|
|
|
@ -22,7 +22,8 @@ target_sources(app PRIVATE
|
||||||
src/main.c
|
src/main.c
|
||||||
src/timeout_order.c
|
src/timeout_order.c
|
||||||
src/multilib.c
|
src/multilib.c
|
||||||
src/errno.c
|
src/errno.c
|
||||||
src/boot_delay.c
|
src/boot_delay.c
|
||||||
src/irq_offload.c
|
src/irq_offload.c
|
||||||
|
src/pow2.c
|
||||||
)
|
)
|
||||||
|
|
|
@ -52,6 +52,7 @@ extern void test_bitarray_alloc_free(void);
|
||||||
extern void test_bitarray_region_set_clear(void);
|
extern void test_bitarray_region_set_clear(void);
|
||||||
extern void test_nop(void);
|
extern void test_nop(void);
|
||||||
extern void test_ffs(void);
|
extern void test_ffs(void);
|
||||||
|
extern void test_pow2_ceil(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup kernel_common_tests Common Tests
|
* @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_ms_time_duration),
|
||||||
ztest_unit_test(test_bounds_check_mitigation),
|
ztest_unit_test(test_bounds_check_mitigation),
|
||||||
ztest_unit_test(test_nop),
|
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);
|
ztest_run_test_suite(common);
|
||||||
|
|
77
tests/kernel/common/src/pow2.c
Normal file
77
tests/kernel/common/src/pow2.c
Normal 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);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue