diff --git a/number_theory/bitmatrix.hpp b/number_theory/bitmatrix.hpp index cb18e29..c48b54c 100644 --- a/number_theory/bitmatrix.hpp +++ b/number_theory/bitmatrix.hpp @@ -256,14 +256,6 @@ constexpr void transpose64(uint64_t (&src)[64]) noexcept { #define CONSTEXPR_POINTER_CAST #endif -#if CONFIG_HAS_AT_LEAST_CXX_20 -#define NODISCARD_WITH_MESSAGE(message) [[nodiscard(message)]] -#elif CONFIG_HAS_AT_LEAST_CXX_17 -#define NODISCARD_WITH_MESSAGE(message) [[nodiscard]] -#else -#define NODISCARD_WITH_MESSAGE(message) -#endif - namespace detail { struct square_bitmatrix_helper { private: @@ -685,7 +677,7 @@ struct alignas(std::uint64_t) alignas(word_type) square_bitmatrix { do_flip_inplace(data_); return *this; } - NODISCARD_WITH_MESSAGE("This method is not inplace. Use flip() for this purpose") + ATTRIBUTE_NODISCARD_WITH_MESSAGE("This method is not inplace. Use flip() for this purpose") ATTRIBUTE_PURE CONSTEXPR_BITSET_OPS square_bitmatrix operator~() const noexcept { @@ -708,7 +700,7 @@ struct alignas(std::uint64_t) alignas(word_type) square_bitmatrix { transpose_matrix(data_); return *this; } - NODISCARD_WITH_MESSAGE("This method is not inplace. Use transpose() for this purpose") + ATTRIBUTE_NODISCARD_WITH_MESSAGE("This method is not inplace. Use transpose() for this purpose") ATTRIBUTE_PURE CONSTEXPR_POINTER_CAST square_bitmatrix T() const noexcept { @@ -980,6 +972,5 @@ struct alignas(std::uint64_t) alignas(word_type) square_bitmatrix { } }; -#undef NODISCARD_WITH_MESSAGE #undef CONSTEXPR_POINTER_CAST #undef CONSTEXPR_BITSET_OPS diff --git a/number_theory/config_macros.hpp b/number_theory/config_macros.hpp index 4cf4650..416efb2 100644 --- a/number_theory/config_macros.hpp +++ b/number_theory/config_macros.hpp @@ -16,13 +16,13 @@ #endif /* Test for __has_attribute as per __glibc_has_attribute in glibc */ -#if defined(__has_attribute) && (!defined(__clang__) || CONFIG_CLANG_AT_LEAST(2, 5)) +#if defined(__has_attribute) && (!defined(__clang__) || CONFIG_CLANG_AT_LEAST(4, 5)) #define CONFIG_HAS_GCC_ATTRIBUTE(attr) __has_attribute(attr) #else #define CONFIG_HAS_GCC_ATTRIBUTE(attr) 0 #endif -#ifdef __has_cpp_attribute +#if defined(__cplusplus) && defined(__has_cpp_attribute) #define CONFIG_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) #else #define CONFIG_HAS_CPP_ATTRIBUTE(attr) 0 @@ -79,6 +79,24 @@ #define CONFIG_HAS_AT_LEAST_CXX_23 0 #endif +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define CONFIG_HAS_AT_LEAST_C_11 1 +#else +#define CONFIG_HAS_AT_LEAST_C_11 0 +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L +#define CONFIG_HAS_AT_LEAST_C_17 1 +#else +#define CONFIG_HAS_AT_LEAST_C_17 0 +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +#define CONFIG_HAS_AT_LEAST_C_23 1 +#else +#define CONFIG_HAS_AT_LEAST_C_23 0 +#endif + // https://en.cppreference.com/w/cpp/feature_test #if defined(__cpp_concepts) && __cpp_concepts >= 201907L #define CONFIG_HAS_CONCEPTS 1 @@ -116,15 +134,33 @@ #elif CONFIG_HAS_BUILTIN(__builtin_unreachable) #define CONFIG_UNREACHABLE() __builtin_unreachable() #elif CONFIG_HAS_BUILTIN(__builtin_assume) +#if defined(__cplusplus) #define CONFIG_UNREACHABLE() __builtin_assume(false) +#else +#define CONFIG_UNREACHABLE() __builtin_assume(0) +#endif #elif CONFIG_GNUC_AT_LEAST(13, 0) && CONFIG_HAS_GCC_ATTRIBUTE(assume) +#if defined(__cplusplus) #define CONFIG_UNREACHABLE() __attribute__((assume(false))) +#else +#define CONFIG_UNREACHABLE() __attribute__((assume(0))) +#endif #elif defined(_MSC_VER) +#if defined(__cplusplus) #define CONFIG_UNREACHABLE() __assume(false) #else +#define CONFIG_UNREACHABLE() __assume(0) +#endif +#else +#if defined(__cplusplus) #define CONFIG_UNREACHABLE() \ do { \ } while (false) +#else +#define CONFIG_UNREACHABLE() \ + do { \ + } while (0) +#endif #endif #if CONFIG_HAS_AT_LEAST_CXX_23 && CONFIG_HAS_CPP_ATTRIBUTE(assume) @@ -137,12 +173,21 @@ #elif defined(_MSC_VER) #define ATTRIBUTE_ASSUME(expr) __assume(expr) #else +#if defined(__cplusplus) #define ATTRIBUTE_ASSUME(expr) \ do { \ if (!(expr)) { \ CONFIG_UNREACHABLE(); \ } \ } while (false) +#else +#define ATTRIBUTE_ASSUME(expr) \ + do { \ + if (!(expr)) { \ + CONFIG_UNREACHABLE(); \ + } \ + } while (0) +#endif #endif /* __builtin_expect is in gcc 3.0 */ @@ -159,8 +204,8 @@ #define likely(x) __builtin_expect(static_cast(x), true) #define unlikely(x) __builtin_expect(static_cast(x), false) #else -#define likely(x) __builtin_expect((x), true) -#define unlikely(x) __builtin_expect((x), false) +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) #endif #else @@ -283,9 +328,15 @@ __attribute__((access(mode, memory_argument_pos))) #define ATTRIBUTE_SIZED_ACCESS(mode, memory_argument_pos, range_size_argument_pos) \ __attribute__((access(mode, memory_argument_pos, range_size_argument_pos))) +#if CONFIG_GNUC_AT_LEAST(11, 0) +#define ATTRIBUTE_ACCESS_NONE(memory_argument_pos) ATTRIBUTE_ACCESS(none, memory_argument_pos) +#else +#define ATTRIBUTE_ACCESS_NONE(memory_argument_pos) +#endif #else #define ATTRIBUTE_ACCESS(mode, memory_argument_pos) #define ATTRIBUTE_SIZED_ACCESS(mode, memory_argument_pos, range_size_argument_pos) +#define ATTRIBUTE_ACCESS_NONE(memory_argument_pos) #endif /** @@ -323,6 +374,59 @@ #define ATTRIBUTE_REINITIALIZES #endif +#if CONFIG_HAS_AT_LEAST_CXX_17 +#define ATTRIBUTE_NODISCARD [[nodiscard]] +#if CONFIG_HAS_AT_LEAST_CXX_20 +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) [[nodiscard(message)]] +#else +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) [[nodiscard]] +#endif +#elif CONFIG_GNUC_AT_LEAST(3, 4) || CONFIG_HAS_GCC_ATTRIBUTE(warn_unused_result) +#define ATTRIBUTE_NODISCARD __attribute__((warn_unused_result)) +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) __attribute__((warn_unused_result)) +#else +#define ATTRIBUTE_NODISCARD +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) +#endif + +#if CONFIG_HAS_AT_LEAST_CXX_11 +#define ATTRIBUTE_NORETURN [[noreturn]] +#elif CONFIG_HAS_AT_LEAST_C_23 +#define ATTRIBUTE_NORETURN [[noreturn]] +#elif CONFIG_HAS_AT_LEAST_C_11 +#define ATTRIBUTE_NORETURN _Noreturn +#elif CONFIG_GNUC_AT_LEAST(2, 8) || CONFIG_HAS_GCC_ATTRIBUTE(noreturn) +#define ATTRIBUTE_NORETURN __attribute__((noreturn)) +#else +#define ATTRIBUTE_NORETURN +#endif + +#if defined(__cplusplus) && (CONFIG_GNUC_AT_LEAST(2, 8) || CONFIG_CLANG_AT_LEAST(4, 0)) +#if CONFIG_HAS_AT_LEAST_CXX_11 +#define CONFIG_NOEXCEPT_FUNCTION noexcept(true) +#else +#define CONFIG_NOEXCEPT_FUNCTION throw() +#endif +#else +#define CONFIG_NOEXCEPT_FUNCTION +#endif + +#if CONFIG_GNUC_AT_LEAST(3, 4) || CONFIG_HAS_GCC_ATTRIBUTE(nothrow) +#define ATTRIBUTE_NOTHROW __attribute__((nothrow)) +#else +#define ATTRIBUTE_NOTHROW +#endif + +#if CONFIG_HAS_AT_LEAST_CXX_17 +#define ATTRIBUTE_FALLTHROUGH [[fallthrough]] +#elif CONFIG_HAS_AT_LEAST_C_23 +#define ATTRIBUTE_FALLTHROUGH [[fallthrough]] +#elif CONFIG_GNUC_AT_LEAST(7, 1) || CONFIG_HAS_GCC_ATTRIBUTE(fallthrough) +#define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough)) +#else +#define ATTRIBUTE_FALLTHROUGH +#endif + // Copypasted from LLVM's int_endianness.h /* ===-- int_endianness.h - configuration header for compiler-rt ------------=== @@ -436,6 +540,8 @@ #error Unable to determine endian #endif /* Check we found an endianness correctly. */ +#ifdef __cplusplus + #if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() #include // for _ReadWriteBarrier #endif @@ -445,13 +551,21 @@ namespace config { namespace detail { #if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() -ATTRIBUTE_NOINLINE inline void sink_char_ptr(char const volatile*) {} +#if defined(__GNUC__) +// inline function 'sink_char_ptr' given attribute 'noinline' +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif +ATTRIBUTE_NOINLINE static inline void sink_char_ptr(char const volatile*) {} +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif #endif } // namespace detail template -ATTRIBUTE_ALWAYS_INLINE inline void do_not_optimize_away(T&& expr) noexcept { +ATTRIBUTE_ALWAYS_INLINE static inline void do_not_optimize_away(T&& expr) noexcept { #if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() ::config::detail::sink_char_ptr(&reinterpret_cast(expr)); _ReadWriteBarrier(); @@ -500,4 +614,35 @@ ATTRIBUTE_ALWAYS_INLINE constexpr bool is_gcc_constant_p(ATTRIBUTE_MAYBE_UNUSED } // namespace config +#else + +#if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() +#include // for _ReadWriteBarrier +#if defined(__GNUC__) +// inline function 'sink_char_ptr' given attribute 'noinline' +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif +ATTRIBUTE_NOINLINE static inline void sink_char_ptr( + ATTRIBUTE_MAYBE_UNUSED char const volatile* ptr) {} +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#define do_not_optimize_away(expr) \ + do { \ + sink_char_ptr((volatile const char*)&(expr)); \ + _ReadWriteBarrier(); \ + } while (0) + +#elif defined(__GNUG__) +#define do_not_optimize_away(expr) asm volatile("" ::"r,m,i"(expr)) +#elif defined(__GNUC__) +#define do_not_optimize_away(expr) __asm__ volatile("" ::"r,m,i"(expr)) +#else +#define do_not_optimize_away(expr) __asm__("" ::"r,m,i"(expr)); +#endif + +#endif + #endif // !CONFIG_MACROS_HPP diff --git a/number_theory/test_math_functions.cpp b/number_theory/test_math_functions.cpp index 695c1c3..2a71931 100644 --- a/number_theory/test_math_functions.cpp +++ b/number_theory/test_math_functions.cpp @@ -46,8 +46,8 @@ void test_isqrt() { constexpr auto test_sqrts = [](uint32_t n, uint32_t n_squared) { assert(n == isqrt(n_squared)); - assert(n == isqrt(uint64_t(n_squared))); - assert(n == isqrt(uint128_t(n_squared))); + assert(n == isqrt(uint64_t{n_squared})); + assert(n == isqrt(uint128_t{n_squared})); }; constexpr uint32_t kProbes = 100'000; @@ -64,39 +64,42 @@ void test_isqrt() { assert(r - 1 == isqrt(rs - 1)); assert(r == isqrt(rs)); assert(r == isqrt(rs + 1)); - assert(r - 1 == isqrt(uint128_t(rs - 1))); - assert(r == isqrt(uint128_t(rs))); - assert(r == isqrt(uint128_t(rs + 1))); + assert(r - 1 == isqrt(uint128_t{rs - 1})); + assert(r == isqrt(uint128_t{rs})); + assert(r == isqrt(uint128_t{rs + 1})); } for (uint64_t r = std::numeric_limits::max() - kIters; r != 0; r++) { - uint128_t rs = uint128_t(r) * r; - assert(r - 1 == isqrt(uint128_t(rs - 1))); - assert(r == isqrt(uint128_t(rs))); - assert(r == isqrt(uint128_t(rs + 1))); + uint128_t rs = uint128_t{r} * r; + assert(r - 1 == isqrt(uint128_t{rs - 1})); + assert(r == isqrt(rs)); + assert(r == isqrt(rs + 1)); } constexpr std::pair root_with_square[] = { - {uint8_t(-1), uint16_t(-1)}, - {uint16_t(-1), uint32_t(-1)}, - {uint32_t(-1), uint64_t(-1)}, - {uint64_t(8347849ull), uint128_t(8347849ull) * 8347849ull}, - {uint64_t(23896778463ull), uint128_t(23896778463ull) * 23896778463ull}, - {uint64_t(26900711288786ull), - uint128_t(72364826784263874ull) * 10'000'000'000ull + 2'638'723'478}, - {uint64_t(3748237487274238478ull), - uint128_t(3748237487274238478ull) * 3748237487274238478ull}, - {uint64_t(9472294799293ull), uint128_t(8972436876473126137ull) * 10'000'000ull + 7'236'478}, - {uint64_t(18015752134763552034ull), - (uint128_t(17594829943123320651ull) << 64) | 2622055845271657274ull}, - {uint64_t(-1), uint128_t(-1)}, + {uint64_t{std::numeric_limits::max()}, + uint128_t{std::numeric_limits::max()}}, + {uint64_t{std::numeric_limits::max()}, + uint128_t{std::numeric_limits::max()}}, + {uint64_t{std::numeric_limits::max()}, + uint128_t{std::numeric_limits::max()}}, + {uint64_t{8347849ull}, uint128_t{8347849ull} * 8347849ull}, + {uint64_t{23896778463ull}, uint128_t{23896778463ull} * 23896778463ull}, + {uint64_t{26900711288786ull}, + uint128_t{72364826784263874ull} * 10'000'000'000ull + 2'638'723'478}, + {uint64_t{3748237487274238478ull}, + uint128_t{3748237487274238478ull} * 3748237487274238478ull}, + {uint64_t{9472294799293ull}, uint128_t{8972436876473126137ull} * 10'000'000ull + 7'236'478}, + {uint64_t{18015752134763552034ull}, + (uint128_t{17594829943123320651ull} << 64) | 2622055845271657274ull}, + {std::numeric_limits::max(), static_cast(-1)}, }; for (const auto& [root, square] : root_with_square) { - if (uint32_t(square) == square) { - assert(root == isqrt(uint32_t(square))); + if (static_cast(square) == square) { + assert(root == isqrt(static_cast(square))); } - if (uint64_t(square) == square) { - assert(root == isqrt(uint64_t(square))); + if (static_cast(square) == square) { + assert(root == isqrt(static_cast(square))); } assert(root == isqrt(square)); } @@ -109,11 +112,11 @@ void test_icbrt() noexcept { const uint32_t tr = n * n * n; const uint32_t n_cube_minus_one = tr + 3 * n * n + 3 * n; assert(icbrt(tr) == n); - assert(icbrt(uint64_t(tr)) == n); + assert(icbrt(uint64_t{tr}) == n); assert(icbrt(n_cube_minus_one) == n); - assert(icbrt(uint64_t(n_cube_minus_one)) == n); + assert(icbrt(uint64_t{n_cube_minus_one}) == n); assert(icbrt(n_cube_minus_one + 1) == n + 1); - assert(icbrt(uint64_t(n_cube_minus_one + 1)) == n + 1); + assert(icbrt(uint64_t{n_cube_minus_one + 1}) == n + 1); } assert(icbrt(1625u * 1625u * 1625u) == 1625); assert(icbrt(std::numeric_limits::max()) == 1625); @@ -125,7 +128,7 @@ void test_icbrt() noexcept { assert(icbrt(n_cube_minus_one) == n); assert(icbrt(n_cube_minus_one + 1) == n + 1); } - assert(icbrt(uint64_t(2642245) * 2642245 * 2642245) == 2642245); + assert(icbrt(uint64_t{2642245} * 2642245 * 2642245) == 2642245); assert(icbrt(std::numeric_limits::max()) == 2642245); } @@ -133,7 +136,7 @@ void test_log2() noexcept { log_tests_started(); for (uint32_t k = 0; k < sizeof(uint32_t) * CHAR_BIT; k++) { - uint32_t pw = uint32_t(1) << k; + uint32_t pw = uint32_t{1} << k; assert(log2_floor(pw) == k); assert(log2_ceil(pw) == k); if (!is_power_of_two(pw + 1)) { @@ -143,7 +146,7 @@ void test_log2() noexcept { } for (uint32_t k = 0; k < sizeof(uint64_t) * CHAR_BIT; k++) { - uint64_t pw = uint64_t(1) << k; + uint64_t pw = uint64_t{1} << k; assert(log2_floor(pw) == k); assert(log2_ceil(pw) == k); if (!is_power_of_two(pw + 1)) { @@ -153,7 +156,7 @@ void test_log2() noexcept { } for (uint32_t k = 0; k < sizeof(uint128_t) * CHAR_BIT; k++) { - uint128_t pw = uint128_t(1) << k; + uint128_t pw = uint128_t{1} << k; assert(log2_floor(pw) == k); assert(log2_ceil(pw) == k); if (!is_power_of_two(pw + 1)) { @@ -162,27 +165,30 @@ void test_log2() noexcept { } } - assert(log2_floor(uint32_t(0)) == uint32_t(-1)); - assert(log2_ceil(uint32_t(0)) == uint32_t(-1)); - assert(log2_floor(uint64_t(0)) == uint32_t(-1)); - assert(log2_ceil(uint64_t(0)) == uint32_t(-1)); - assert(log2_floor(uint128_t(0)) == uint32_t(-1)); - assert(log2_ceil(uint128_t(0)) == uint32_t(-1)); + assert(log2_floor(uint32_t{0}) == static_cast(-1)); + assert(log2_ceil(uint32_t{0}) == static_cast(-1)); + assert(log2_floor(uint64_t{0}) == static_cast(-1)); + assert(log2_ceil(uint64_t{0}) == static_cast(-1)); + assert(log2_floor(uint128_t{0}) == static_cast(-1)); + assert(log2_ceil(uint128_t{0}) == static_cast(-1)); } void test_bit_reverse() noexcept { log_tests_started(); for (uint32_t n = 0; n < 256; n++) { - assert(bit_reverse(uint8_t(n)) == (bit_reverse(n) >> 24)); + assert(bit_reverse(static_cast(n)) == (bit_reverse(n) >> 24)); } - constexpr uint32_t shifts[32] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, - 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, - 83, 89, 97, 101, 103, 107, 109, 113, 127, 131}; - uint128_t n = uint64_t(-1); - for (uint32_t k = uint32_t(1e7); k > 0; k--) { - uint128_t b = (uint128_t(bit_reverse(uint64_t(n))) << 64) | bit_reverse(uint64_t(n >> 64)); + constexpr uint32_t shifts[32] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, + 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, + }; + uint128_t n = std::numeric_limits::max(); + for (auto k = static_cast(1e7); k > 0; k--) { + const auto hi_64 = static_cast(n >> 64); + const auto low_64 = static_cast(n); + uint128_t b = (uint128_t{bit_reverse(low_64)} << 64) | bit_reverse(hi_64); assert(bit_reverse(n) == b); n += shifts[k % 32]; } @@ -368,7 +374,7 @@ void test_prime_bitarrays() { void test_factorizer() { log_tests_started(); - constexpr auto N = uint32_t(1e7); + constexpr auto N = static_cast(1e7); Factorizer fact(N); { const auto is_prime = dynamic_primes_sieve(N); @@ -1805,37 +1811,37 @@ void test_general_asserts() { ASSERT_THAT(base_b_len(-99ll) == 3); ASSERT_THAT(base_b_len(-100ll) == 4); ASSERT_THAT(base_b_len(-101ll) == 4); - ASSERT_THAT(base_b_len(int64_t(uint64_t(1) << 63)) == 20); + ASSERT_THAT(base_b_len(std::numeric_limits::min()) == 20); #if defined(INTEGERS_128_BIT_HPP) && HAS_I128_CONSTEXPR - ASSERT_THAT(base_b_len(uint128_t(0)) == 1); - ASSERT_THAT(base_b_len(uint128_t(1)) == 1); - ASSERT_THAT(base_b_len(uint128_t(9)) == 1); - ASSERT_THAT(base_b_len(uint128_t(10)) == 2); - ASSERT_THAT(base_b_len(uint128_t(11)) == 2); - ASSERT_THAT(base_b_len(uint128_t(99)) == 2); - ASSERT_THAT(base_b_len(uint128_t(100)) == 3); - ASSERT_THAT(base_b_len(uint128_t(101)) == 3); + ASSERT_THAT(base_b_len(uint128_t{0}) == 1); + ASSERT_THAT(base_b_len(uint128_t{1}) == 1); + ASSERT_THAT(base_b_len(uint128_t{9}) == 1); + ASSERT_THAT(base_b_len(uint128_t{10}) == 2); + ASSERT_THAT(base_b_len(uint128_t{11}) == 2); + ASSERT_THAT(base_b_len(uint128_t{99}) == 2); + ASSERT_THAT(base_b_len(uint128_t{100}) == 3); + ASSERT_THAT(base_b_len(uint128_t{101}) == 3); ASSERT_THAT(base_b_len(uint128_t(-1)) == 39); - ASSERT_THAT(base_b_len(int128_t(0)) == 1); - ASSERT_THAT(base_b_len(int128_t(1)) == 1); - ASSERT_THAT(base_b_len(int128_t(9)) == 1); - ASSERT_THAT(base_b_len(int128_t(10)) == 2); - ASSERT_THAT(base_b_len(int128_t(11)) == 2); - ASSERT_THAT(base_b_len(int128_t(99)) == 2); - ASSERT_THAT(base_b_len(int128_t(100)) == 3); - ASSERT_THAT(base_b_len(int128_t(101)) == 3); - ASSERT_THAT(base_b_len(-int128_t(0)) == 1); - ASSERT_THAT(base_b_len(-int128_t(1)) == 2); - ASSERT_THAT(base_b_len(-int128_t(9)) == 2); - ASSERT_THAT(base_b_len(-int128_t(10)) == 3); - ASSERT_THAT(base_b_len(-int128_t(11)) == 3); - ASSERT_THAT(base_b_len(-int128_t(99)) == 3); - ASSERT_THAT(base_b_len(-int128_t(100)) == 4); - ASSERT_THAT(base_b_len(-int128_t(101)) == 4); - ASSERT_THAT(base_b_len(int128_t(uint128_t(1) << 127)) == 40); + ASSERT_THAT(base_b_len(int128_t{0}) == 1); + ASSERT_THAT(base_b_len(int128_t{1}) == 1); + ASSERT_THAT(base_b_len(int128_t{9}) == 1); + ASSERT_THAT(base_b_len(int128_t{10}) == 2); + ASSERT_THAT(base_b_len(int128_t{11}) == 2); + ASSERT_THAT(base_b_len(int128_t{99}) == 2); + ASSERT_THAT(base_b_len(int128_t{100}) == 3); + ASSERT_THAT(base_b_len(int128_t{101}) == 3); + ASSERT_THAT(base_b_len(-int128_t{0}) == 1); + ASSERT_THAT(base_b_len(-int128_t{1}) == 2); + ASSERT_THAT(base_b_len(-int128_t{9}) == 2); + ASSERT_THAT(base_b_len(-int128_t{10}) == 3); + ASSERT_THAT(base_b_len(-int128_t{11}) == 3); + ASSERT_THAT(base_b_len(-int128_t{99}) == 3); + ASSERT_THAT(base_b_len(-int128_t{100}) == 4); + ASSERT_THAT(base_b_len(-int128_t{101}) == 4); + ASSERT_THAT(base_b_len(static_cast(uint128_t{1} << 127)) == 40); #endif // INTEGERS_128_BIT_HPP @@ -1843,47 +1849,47 @@ void test_general_asserts() { #if defined(HAS_I128_CONSTEXPR) && HAS_I128_CONSTEXPR - ASSERT_THAT(gcd(uint128_t(1), uint128_t(1)) == 1); - ASSERT_THAT(gcd(uint128_t(3), uint128_t(7)) == 1); - ASSERT_THAT(gcd(uint128_t(0), uint128_t(112378432)) == 112378432); - ASSERT_THAT(gcd(uint128_t(112378432), uint128_t(0)) == 112378432); - ASSERT_THAT(gcd(uint128_t(429384832), uint128_t(324884)) == 4); - ASSERT_THAT(gcd(uint128_t(18446744073709551521ull), uint128_t(18446744073709551533ull)) == 1); - ASSERT_THAT(gcd(uint128_t(18446744073709551521ull) * 18446744073709551521ull, - uint128_t(18446744073709551521ull)) == 18446744073709551521ull); - ASSERT_THAT(gcd(uint128_t(23999993441ull) * 23999993377ull, - uint128_t(23999992931ull) * 23999539633ull) == 1); - ASSERT_THAT(gcd(uint128_t(2146514599u) * 2146514603u * 2146514611u, - uint128_t(2146514611u) * 2146514621u * 2146514647u) == 2146514611ull); - ASSERT_THAT(gcd(uint128_t(2146514599u) * 2146514603u * 2146514611u * 2, - uint128_t(2146514599u) * 2146514603u * 2146514611u * 3) == - uint128_t(2146514599u) * 2146514603u * 2146514611u); - ASSERT_THAT(gcd(uint128_t(100000000000000003ull) * 1000000000000000003ull, - uint128_t(1000000000000000003ull) * 1000000000000000009ull) == + ASSERT_THAT(gcd(uint128_t{1}, uint128_t{1}) == 1); + ASSERT_THAT(gcd(uint128_t{3}, uint128_t{7}) == 1); + ASSERT_THAT(gcd(uint128_t{0}, uint128_t{112378432}) == 112378432); + ASSERT_THAT(gcd(uint128_t{112378432}, uint128_t{0}) == 112378432); + ASSERT_THAT(gcd(uint128_t{429384832}, uint128_t{324884}) == 4); + ASSERT_THAT(gcd(uint128_t{18446744073709551521ull}, uint128_t{18446744073709551533ull}) == 1); + ASSERT_THAT(gcd(uint128_t{18446744073709551521ull} * 18446744073709551521ull, + uint128_t{18446744073709551521ull}) == 18446744073709551521ull); + ASSERT_THAT(gcd(uint128_t{23999993441ull} * 23999993377ull, + uint128_t{23999992931ull} * 23999539633ull) == 1); + ASSERT_THAT(gcd(uint128_t{2146514599u} * 2146514603u * 2146514611u, + uint128_t{2146514611u} * 2146514621u * 2146514647u) == 2146514611ull); + ASSERT_THAT(gcd(uint128_t{2146514599u} * 2146514603u * 2146514611u * 2, + uint128_t{2146514599u} * 2146514603u * 2146514611u * 3) == + uint128_t{2146514599u} * 2146514603u * 2146514611u); + ASSERT_THAT(gcd(uint128_t{100000000000000003ull} * 1000000000000000003ull, + uint128_t{1000000000000000003ull} * 1000000000000000009ull) == 1000000000000000003ull); - ASSERT_THAT(gcd(uint128_t(3 * 2 * 5 * 7 * 11 * 13 * 17 * 19), - uint128_t(18446744073709551557ull) * 3) == 3); - ASSERT_THAT(gcd(uint128_t(1000000000000000009ull), - uint128_t(1000000000000000009ull) * 1000000000000000009ull) == + ASSERT_THAT(gcd(uint128_t{3u * 2 * 5 * 7 * 11 * 13 * 17 * 19}, + uint128_t{18446744073709551557ull} * 3) == 3); + ASSERT_THAT(gcd(uint128_t{1000000000000000009ull}, + uint128_t{1000000000000000009ull} * 1000000000000000009ull) == 1000000000000000009ull); - ASSERT_THAT(gcd(uint128_t(0), uint128_t(1000000000000000009ull) * 1000000000000000009ull) == - uint128_t(1000000000000000009ull) * 1000000000000000009ull); - ASSERT_THAT(gcd(uint128_t(18446744073709551557ull), uint128_t(0)) == 18446744073709551557ull); - - ASSERT_THAT(gcd(uint64_t(2), int128_t(4)) == 2); - ASSERT_THAT(gcd(uint64_t(2), int128_t(-4)) == 2); - ASSERT_THAT(gcd(uint64_t(3), int128_t(7)) == 1); - ASSERT_THAT(gcd(uint64_t(3), int128_t(-7)) == 1); - ASSERT_THAT(gcd(uint64_t(3), int128_t(18446744073709551557ull) * 3) == 3); - ASSERT_THAT(gcd(uint64_t(3), int128_t(18446744073709551557ull) * (-3)) == 3); - ASSERT_THAT(gcd(uint64_t(3) * 2 * 5 * 7 * 11 * 13 * 17 * 19, - int128_t(18446744073709551557ull) * 3) == 3); - ASSERT_THAT(gcd(uint64_t(1000000000000000009ull), - int128_t(1000000000000000009ll) * 1000000000000000009ll) == + ASSERT_THAT(gcd(uint128_t{0}, uint128_t{1000000000000000009ull} * 1000000000000000009ull) == + uint128_t{1000000000000000009ull} * 1000000000000000009ull); + ASSERT_THAT(gcd(uint128_t{18446744073709551557ull}, uint128_t(0)) == 18446744073709551557ull); + + ASSERT_THAT(gcd(uint64_t{2}, int128_t{4}) == 2); + ASSERT_THAT(gcd(uint64_t{2}, int128_t{-4}) == 2); + ASSERT_THAT(gcd(uint64_t{3}, int128_t{7}) == 1); + ASSERT_THAT(gcd(uint64_t{3}, int128_t{-7}) == 1); + ASSERT_THAT(gcd(uint64_t{3}, int128_t{18446744073709551557ull} * 3) == 3); + ASSERT_THAT(gcd(uint64_t{3}, int128_t{18446744073709551557ull} * (-3)) == 3); + ASSERT_THAT(gcd(uint64_t{3} * 2 * 5 * 7 * 11 * 13 * 17 * 19, + int128_t{18446744073709551557ull} * 3) == 3); + ASSERT_THAT(gcd(uint64_t{1000000000000000009ull}, + int128_t{1000000000000000009ll} * 1000000000000000009ll) == 1000000000000000009ull); - ASSERT_THAT(gcd(uint64_t(0), int128_t(1000000000000000009ll) * 1000000000000000009ll) == - uint128_t(1000000000000000009ll) * 1000000000000000009ull); - ASSERT_THAT(gcd(uint64_t(18446744073709551557ull), int128_t(0)) == 18446744073709551557ull); + ASSERT_THAT(gcd(uint64_t{0}, int128_t{1000000000000000009ll} * 1000000000000000009ll) == + uint128_t{1000000000000000009ll} * 1000000000000000009ull); + ASSERT_THAT(gcd(uint64_t{18446744073709551557ull}, int128_t{0}) == 18446744073709551557ull); ASSERT_THAT(math_functions::popcount(0u) == 0); ASSERT_THAT(math_functions::popcount(1u << 1) == 1); @@ -1950,31 +1956,31 @@ void test_general_asserts() { #endif // defined(HAS_I128_CONSTEXPR) && HAS_I128_CONSTEXPR ASSERT_THAT(([]() constexpr noexcept { - const auto [q, r] = math_functions::extract_pow2(uint32_t(0)); + const auto [q, r] = math_functions::extract_pow2(uint32_t{0}); return q == 0 && r == 32; }())); ASSERT_THAT(([]() constexpr noexcept { - const auto [q, r] = math_functions::extract_pow2(uint32_t(1) << 31); + const auto [q, r] = math_functions::extract_pow2(uint32_t{1} << 31); return q == 1 && r == 31; }())); ASSERT_THAT(([]() constexpr noexcept { - const auto [q, r] = math_functions::extract_pow2(uint64_t(0)); + const auto [q, r] = math_functions::extract_pow2(uint64_t{0}); return q == 0 && r == 64; }())); ASSERT_THAT(([]() constexpr noexcept { - const auto [q, r] = math_functions::extract_pow2(uint64_t(1) << 31); + const auto [q, r] = math_functions::extract_pow2(uint64_t{1} << 31); return q == 1 && r == 31; }())); ASSERT_THAT(([]() constexpr noexcept { - const auto [q, r] = math_functions::extract_pow2(uint64_t(1) << 63); + const auto [q, r] = math_functions::extract_pow2(uint64_t{1} << 63); return q == 1 && r == 63; }())); ASSERT_THAT(([]() constexpr noexcept { - const auto [q, r] = math_functions::extract_pow2(uint64_t(9221685055305285632ull)); + const auto [q, r] = math_functions::extract_pow2(uint64_t{9221685055305285632ull}); return q == 2147090867 && r == 32; }())); ASSERT_THAT(([]() constexpr noexcept { - const auto [q, r] = math_functions::extract_pow2(uint64_t(4610842527652642816ull)); + const auto [q, r] = math_functions::extract_pow2(uint64_t{4610842527652642816ull}); return q == 2147090867 && r == 31; }())); @@ -1993,8 +1999,8 @@ void test_general_asserts() { ASSERT_THAT( (math_functions::powers_sum_u128<3>(100) == 100u * 100u * (100u + 1) * (100u + 1) / 4)); - constexpr auto kN = uint32_t(3e9); - constexpr auto kN128 = uint128_t(kN); + constexpr auto kN = static_cast(3e9); + constexpr auto kN128 = static_cast(kN); ASSERT_THAT( (math_functions::powers_sum_u128<3>(kN) == kN128 * kN128 * (kN128 + 1) * (kN128 + 1) / 4)); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 651c7d8..acf071f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,13 +1,14 @@ cmake_minimum_required(VERSION 3.20) -project(tests VERSION 0.1.0 LANGUAGES CXX) +project(tests VERSION 0.1.0 LANGUAGES C CXX) set(USING_MINGW_GCC False) set(USING_MINGW_GCC_32 False) set(USING_MSYS2_MINGW_GCC False) # other versions can be added below depending on the compiler version -set(SUPPORTED_CXX_VERSIONS "17") +set(COMPILER_SUPPORTED_C_VERSIONS "99") +set(COMPILER_SUPPORTED_CXX_VERSIONS "11;14;17") string(TOLOWER ${CMAKE_CXX_COMPILER} STRING_LOWER_CMAKE_CXX_COMPILER) if (MINGW OR MSYS) @@ -63,12 +64,10 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux") list(GET LSB_DISTRIBUTOR_ID_AND_RELEASE_VERSION_SHORT 1 LSB_RELEASE_VERSION_SHORT) string(TOLOWER "${LSB_DISTRIBUTOR_ID_SHORT}" LSB_DISTRIBUTOR_ID_SHORT) - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if (LSB_DISTRIBUTOR_ID_SHORT STREQUAL "ubuntu" AND LSB_RELEASE_VERSION_SHORT VERSION_LESS_EQUAL "20.04") - set(LINK_THREADS_LIBRARY_MANUALLY True) - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - endif() + if (LSB_DISTRIBUTOR_ID_SHORT STREQUAL "ubuntu" AND LSB_RELEASE_VERSION_SHORT VERSION_LESS_EQUAL "20.04") + set(LINK_THREADS_LIBRARY_MANUALLY True) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) endif() if (CMAKE_CXX_CPPCHECK) if (LSB_DISTRIBUTOR_ID_SHORT STREQUAL "ubuntu" AND LSB_RELEASE_VERSION_SHORT VERSION_GREATER_EQUAL "24.04") @@ -90,7 +89,8 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux") endif() # Empty by default -set(TEST_COMPILE_OPTIONS) +set(TEST_C_COMPILE_OPTIONS) +set(TEST_CXX_COMPILE_OPTIONS) set(TEST_COMPILE_DEFINITIONS) function(configure_gcc_or_clang_gcc_options) @@ -98,15 +98,20 @@ function(configure_gcc_or_clang_gcc_options) message(FATAL_ERROR "ClangCL should not be configured with this function") endif() - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${TEST_COMPILE_OPTIONS}) + set(LOCAL_FN_TEST_C_COMPILE_OPTIONS + ${TEST_C_COMPILE_OPTIONS}) + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${TEST_CXX_COMPILE_OPTIONS}) set(LOCAL_FN_TEST_COMPILE_DEFINITIONS ${TEST_COMPILE_DEFINITIONS}) + set(LOCAL_FN_CMAKE_C_FLAGS_RELWITHDEBINFO + ${CMAKE_C_FLAGS_RELWITHDEBINFO}) set(LOCAL_FN_CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + # Flags for both C and C++ + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} -Wall -Wextra -Wcast-qual @@ -115,10 +120,8 @@ function(configure_gcc_or_clang_gcc_options) -Wshadow -Wnull-dereference -Wundef - -Wwrite-strings -Wsign-conversion -Wsign-compare - -Wsign-promo -Wconversion -Wmissing-noreturn -Wunreachable-code @@ -127,33 +130,23 @@ function(configure_gcc_or_clang_gcc_options) -Wswitch-bool -Wswitch-default -Wswitch-enum - -Wold-style-cast -Wdeprecated - -Weffc++ -Werror -pedantic-errors ) - if (NOT USING_MINGW_GCC AND CMAKE_SYSTEM_NAME MATCHES "Linux") - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} - -fstack-protector-strong - -mshstk - ) - endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} -Warray-bounds=2 -Wshift-overflow=2 -Wlogical-op -Wunsafe-loop-optimizations -Wduplicated-cond - -Wsign-promo -fdiagnostics-color=always) endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} -Warray-bounds -Wshift-overflow -Wshift-sign-overflow @@ -166,6 +159,38 @@ function(configure_gcc_or_clang_gcc_options) ${LOCAL_FN_TEST_COMPILE_DEFINITIONS} _LIBCPP_ENABLE_ASSERTIONS) endif() + if (NOT USING_MINGW_GCC AND CMAKE_SYSTEM_NAME MATCHES "Linux") + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} + -fstack-protector-strong + ) + endif() + + set(LOCAL_FN_TEST_C_COMPILE_OPTIONS + ${LOCAL_FN_TEST_C_COMPILE_OPTIONS} + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} + ) + + # Flags for C only + set(LOCAL_FN_TEST_C_COMPILE_OPTIONS + ${LOCAL_FN_TEST_C_COMPILE_OPTIONS} + -Wwrite-strings + -Wbad-function-cast + -Wint-conversion + ) + # Flags for C++ only + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} + -Weffc++ + -Wsign-promo + -Wold-style-cast + ) + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} + -U_GLIBCXX_USE_DEPRECATED) + set(LOCAL_FN_TEST_COMPILE_DEFINITIONS + ${LOCAL_FN_TEST_COMPILE_DEFINITIONS} + _GLIBCXX_SANITIZE_VECTOR) if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0) # In gcc with version < 10.0 these checks break `constexpr`-tivity of some std:: functions set(LOCAL_FN_TEST_COMPILE_DEFINITIONS @@ -174,34 +199,39 @@ function(configure_gcc_or_clang_gcc_options) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_CONCEPT_CHECKS) endif() - set(LOCAL_FN_TEST_COMPILE_DEFINITIONS - ${LOCAL_FN_TEST_COMPILE_DEFINITIONS} - _GLIBCXX_SANITIZE_VECTOR) - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} - -U_GLIBCXX_USE_DEPRECATED) - + + # Remove -DNDEBUG from the RelWithDebInfo mode flags + string(REGEX REPLACE "-D\\s?NDEBUG(=\\d)?" "" LOCAL_FN_CMAKE_C_FLAGS_RELWITHDEBINFO "${LOCAL_FN_CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REGEX REPLACE "-D\\s?NDEBUG(=\\d)?" "" LOCAL_FN_CMAKE_CXX_FLAGS_RELWITHDEBINFO "${LOCAL_FN_CMAKE_CXX_FLAGS_RELWITHDEBINFO}") - set(TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(TEST_C_COMPILE_OPTIONS + ${LOCAL_FN_TEST_C_COMPILE_OPTIONS} + PARENT_SCOPE) + set(TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} PARENT_SCOPE) set(TEST_COMPILE_DEFINITIONS ${LOCAL_FN_TEST_COMPILE_DEFINITIONS} PARENT_SCOPE) + set(CMAKE_C_FLAGS_RELWITHDEBINFO + ${LOCAL_FN_CMAKE_C_FLAGS_RELWITHDEBINFO} + PARENT_SCOPE) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${LOCAL_FN_CMAKE_CXX_FLAGS_RELWITHDEBINFO} PARENT_SCOPE) if (NOT USING_MINGW_GCC) - set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -fsanitize=address,undefined PARENT_SCOPE) + # set(CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO} -fsanitize=address,undefined PARENT_SCOPE) + # set(CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fsanitize=address,undefined PARENT_SCOPE) endif() endfunction(configure_gcc_or_clang_gcc_options) function(configure_msvc_or_clang_msvc_options) - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${TEST_COMPILE_OPTIONS}) + set(LOCAL_FN_TEST_C_COMPILE_OPTIONS + ${TEST_C_COMPILE_OPTIONS}) + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${TEST_CXX_COMPILE_OPTIONS}) set(LOCAL_FN_TEST_COMPILE_DEFINITIONS ${TEST_COMPILE_DEFINITIONS}) @@ -210,29 +240,36 @@ function(configure_msvc_or_clang_msvc_options) _CRT_SECURE_NO_WARNINGS=1) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} -UNDEBUG) - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} "/W4" # Enable -Wall and -Wextra ) else() if (MSVC_VERSION GREATER_EQUAL 1914) - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} "/Zc:__cplusplus") endif() - set(LOCAL_FN_TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(LOCAL_FN_TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} "/W4" "/UNDEBUG" "/wd4146" # Disable C4146: unary minus operator applied to unsigned type, result still unsigned ) endif() - set(TEST_COMPILE_OPTIONS - ${LOCAL_FN_TEST_COMPILE_OPTIONS} + set(LOCAL_FN_TEST_C_COMPILE_OPTIONS + ${LOCAL_FN_TEST_C_COMPILE_OPTIONS} + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS}) + + set(TEST_C_COMPILE_OPTIONS + ${LOCAL_FN_TEST_C_COMPILE_OPTIONS} + PARENT_SCOPE) + set(TEST_CXX_COMPILE_OPTIONS + ${LOCAL_FN_TEST_CXX_COMPILE_OPTIONS} PARENT_SCOPE) set(TEST_COMPILE_DEFINITIONS ${LOCAL_FN_TEST_COMPILE_DEFINITIONS} @@ -250,33 +287,51 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Ap message(FATAL_ERROR "Clang with unknown frontend") endif() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.0.0) + list(APPEND COMPILER_SUPPORTED_C_VERSIONS 11) + endif() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0.0) + list(APPEND COMPILER_SUPPORTED_C_VERSIONS 17) + endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.0) - list(APPEND SUPPORTED_CXX_VERSIONS 20) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 20) endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0.0) - list(APPEND SUPPORTED_CXX_VERSIONS 23) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 23) + endif() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18.0.0) + list(APPEND COMPILER_SUPPORTED_C_VERSIONS 23) endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.0.0) - list(APPEND SUPPORTED_CXX_VERSIONS 26) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 26) endif() elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") configure_gcc_or_clang_gcc_options() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0.0) + list(APPEND COMPILER_SUPPORTED_C_VERSIONS 11) + endif() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0.0) + list(APPEND COMPILER_SUPPORTED_C_VERSIONS 17) + endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.0) - list(APPEND SUPPORTED_CXX_VERSIONS 20) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 20) endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0.0) - list(APPEND SUPPORTED_CXX_VERSIONS 23) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 23) + endif() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0.0) + list(APPEND COMPILER_SUPPORTED_C_VERSIONS 23) endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15.0.0) - list(APPEND SUPPORTED_CXX_VERSIONS 26) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 26) endif() elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") configure_msvc_or_clang_msvc_options() if (MSVC_VERSION GREATER_EQUAL 1928) - list(APPEND SUPPORTED_CXX_VERSIONS 20) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 20) endif() if (MSVC_VERSION GREATER_EQUAL 1937) - list(APPEND SUPPORTED_CXX_VERSIONS 23) + list(APPEND COMPILER_SUPPORTED_CXX_VERSIONS 23) endif() endif() @@ -302,121 +357,168 @@ endfunction() message(STATUS "+-") message(STATUS "| TEST_COMPILE_DEFINITIONS = ${TEST_COMPILE_DEFINITIONS}") -message(STATUS "| TEST_COMPILE_OPTIONS = ${TEST_COMPILE_OPTIONS}") +message(STATUS "| TEST_C_COMPILE_OPTIONS = ${TEST_C_COMPILE_OPTIONS}") +message(STATUS "| TEST_CXX_COMPILE_OPTIONS = ${TEST_CXX_COMPILE_OPTIONS}") message(STATUS "| USING_MINGW_GCC = ${USING_MINGW_GCC}") message(STATUS "| USING_MINGW_GCC_32 = ${USING_MINGW_GCC_32}") message(STATUS "| USING_MSYS2_MINGW_GCC = ${USING_MSYS2_MINGW_GCC}") +message(STATUS "| COMPILER_SUPPORTED_C_VERSIONS = ${COMPILER_SUPPORTED_C_VERSIONS}") +message(STATUS "| COMPILER_SUPPORTED_CXX_VERSIONS = ${COMPILER_SUPPORTED_CXX_VERSIONS}") message(STATUS "+-") set(TestFilenames "dummy") set(TestDirectories "dummy") -set(TestCxxVersions "dummy") +set(TestLangVersions "dummy") set(TestDependencies "dummy") set(TestOptionalDependencies "dummy") +set(TestIsCProject "dummy") if (NOT USING_MINGW_GCC_32) - list(APPEND TestFilenames "test_fibonacci_num") + list(APPEND TestFilenames "test_fibonacci_num.cpp") list(APPEND TestDirectories "number_theory") - list(APPEND TestCxxVersions "17 20 23 26") + list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject False) - list(APPEND TestFilenames "test_gosper_algorithm") + list(APPEND TestFilenames "test_gosper_algorithm.cpp") list(APPEND TestDirectories "number_theory") - list(APPEND TestCxxVersions "17 20 23 26") + list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject False) if (NOT (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) - list(APPEND TestFilenames "test_integers_128_bit") + list(APPEND TestFilenames "test_integers_128_bit.cpp") list(APPEND TestDirectories "number_theory") - list(APPEND TestCxxVersions "17 20 23 26") + list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject False) - list(APPEND TestFilenames "test_math_functions") + list(APPEND TestFilenames "test_math_functions.cpp") list(APPEND TestDirectories "number_theory") - list(APPEND TestCxxVersions "17 20 23 26") + list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") AND NOT APPLE) list(APPEND TestOptionalDependencies "mpfr") else() list(APPEND TestOptionalDependencies "") endif() + list(APPEND TestIsCProject False) endif() if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") - list(APPEND TestFilenames "test_is_prime_bpsw") + list(APPEND TestFilenames "test_is_prime_bpsw.cpp") list(APPEND TestDirectories "number_theory") - list(APPEND TestCxxVersions "17 20 23 26") + list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") if (NOT APPLE) list(APPEND TestOptionalDependencies "gmp") else() list(APPEND TestOptionalDependencies "") endif() + list(APPEND TestIsCProject False) - list(APPEND TestFilenames "test_kronecker_symbol") + list(APPEND TestFilenames "test_kronecker_symbol.cpp") list(APPEND TestDirectories "number_theory") - list(APPEND TestCxxVersions "17 20 23 26") + list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") if (NOT APPLE) list(APPEND TestOptionalDependencies "gmp gmpxx") else() list(APPEND TestOptionalDependencies "") endif() + list(APPEND TestIsCProject False) - list(APPEND TestFilenames "test_long_int") + list(APPEND TestFilenames "test_long_int.cpp") list(APPEND TestDirectories "number_theory") - list(APPEND TestCxxVersions "17 20 23 26") + list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject False) endif() endif() -list(APPEND TestFilenames "test_bitmatrix") +list(APPEND TestFilenames "test_bitmatrix.cpp") list(APPEND TestDirectories "number_theory") -list(APPEND TestCxxVersions "17 20 23 26") +list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") +list(APPEND TestIsCProject False) -list(APPEND TestFilenames "test_cnk_counter") +list(APPEND TestFilenames "test_cnk_counter.cpp") list(APPEND TestDirectories "number_theory") -list(APPEND TestCxxVersions "17 20 23 26") +list(APPEND TestLangVersions "17 20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") +list(APPEND TestIsCProject False) set(mingw_gcc_or_clang USING_MINGW_GCC OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if ((NOT mingw_gcc_or_clang) OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 10.0.0)) # gcc mingw w64 10.0.0 supports C++20 but doesn't have std::bit_cast, same with clang # gcc: https://gcc.gnu.org/projects/cxx-status.html # clang: https://clang.llvm.org/cxx_status.html - list(APPEND TestFilenames "test_hungarian_algo") + list(APPEND TestFilenames "test_hungarian_algo.cpp") list(APPEND TestDirectories "graphs HungarianAlgorithm") - list(APPEND TestCxxVersions "20 23 26") + list(APPEND TestLangVersions "20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject False) endif() unset(mingw_gcc_or_clang) -list(APPEND TestFilenames "test_actrie") +list(APPEND TestFilenames "test_actrie.cpp") list(APPEND TestDirectories "tf_idf_actrie") -list(APPEND TestCxxVersions "20 23 26") +list(APPEND TestLangVersions "20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") +list(APPEND TestIsCProject False) -list(APPEND TestFilenames "test_tf_idf_actrie search_lib") +list(APPEND TestFilenames "test_tf_idf_actrie.cpp search_lib.cpp") list(APPEND TestDirectories "tf_idf_actrie") -list(APPEND TestCxxVersions "20 23 26") +list(APPEND TestLangVersions "20 23 26") list(APPEND TestDependencies "") list(APPEND TestOptionalDependencies "") +list(APPEND TestIsCProject False) -list(POP_FRONT TestFilenames) -list(POP_FRONT TestDirectories) -list(POP_FRONT TestCxxVersions) -list(POP_FRONT TestDependencies) -list(POP_FRONT TestOptionalDependencies) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU") AND NOT APPLE) + list(APPEND TestFilenames "test_memcount.c") + list(APPEND TestDirectories "vec_instructs") + list(APPEND TestLangVersions "99 11 17 23") + list(APPEND TestDependencies "") + list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject True) + + list(APPEND TestFilenames "test_memcount.cpp") + list(APPEND TestDirectories "vec_instructs") + list(APPEND TestLangVersions "11 14 17 20 23 26") + list(APPEND TestDependencies "") + list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject False) + + list(APPEND TestFilenames "test_memset_int.c") + list(APPEND TestDirectories "vec_instructs") + list(APPEND TestLangVersions "99 11 17 23") + list(APPEND TestDependencies "") + list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject True) + + list(APPEND TestFilenames "test_memset_int.cpp") + list(APPEND TestDirectories "vec_instructs") + list(APPEND TestLangVersions "11 14 17 20 23 26") + list(APPEND TestDependencies "") + list(APPEND TestOptionalDependencies "") + list(APPEND TestIsCProject False) +endif() + +list(POP_FRONT TestFilenames) # pop dummy +list(POP_FRONT TestDirectories) # pop dummy +list(POP_FRONT TestLangVersions) # pop dummy +list(POP_FRONT TestDependencies) # pop dummy +list(POP_FRONT TestOptionalDependencies) # pop dummy +list(POP_FRONT TestIsCProject) # pop dummy function( @@ -425,20 +527,26 @@ function( target_dir target_dependencies target_optional_dependencies - target_cxx_version + target_lang_version + is_c_project ) string(REPLACE " " ";" target_filenames "${target_filenames}") - set(target_cpp_filenames) + set(target_full_filenames) string(REPLACE " " ";" target_dir "${target_dir}") foreach(target_filename ${target_filenames}) - set(target_cpp_filename "${target_filename}.cpp") - string(JOIN "/" target_path_to_cpp ".." ${target_dir} ${target_cpp_filename}) - list(APPEND target_cpp_filenames ${target_path_to_cpp}) + string(JOIN "/" target_path_to_cpp ".." ${target_dir} ${target_filename}) + list(APPEND target_full_filenames ${target_path_to_cpp}) endforeach() list(GET target_filenames 0 first_target_filename) - set(target "target_cxx_${target_cxx_version}_${first_target_filename}") + # remove file extension + string(REGEX REPLACE "\\.[^.]*$" "" first_target_filename ${first_target_filename}) + if (is_c_project) + set(target "target_c_${target_lang_version}_${first_target_filename}") + else() + set(target "target_cxx_${target_lang_version}_${first_target_filename}") + endif() string(COMPARE EQUAL "${target_dependencies}" "" empty_dependencies) if (NOT empty_dependencies) @@ -452,10 +560,10 @@ function( message(STATUS "+-") message(STATUS "| target = ${target}") - message(STATUS "| target_cpp_filenames = ${target_cpp_filenames}") + message(STATUS "| target_full_filenames = ${target_full_filenames}") message(STATUS "| target_dependencies = ${target_dependencies}") message(STATUS "| target_optional_dependencies = ${target_optional_dependencies}") - message(STATUS "| target_cxx_version = ${target_cxx_version}") + message(STATUS "| target_lang_version = ${target_lang_version}") message(STATUS "+-") set(has_missing_dependency FALSE) @@ -472,7 +580,7 @@ function( return() endif() - add_executable(${target} ${target_cpp_filenames}) + add_executable(${target} ${target_full_filenames}) if (NOT empty_dependencies) target_link_libraries(${target} PUBLIC ${target_dependencies}) @@ -497,28 +605,46 @@ function( target_link_options(${target} PUBLIC -static -static-libgcc -static-libstdc++) endif() - target_compile_options(${target} PUBLIC ${TEST_COMPILE_OPTIONS}) target_compile_definitions(${target} PUBLIC ${TEST_COMPILE_DEFINITIONS}) - set_target_properties(${target} PROPERTIES CXX_STANDARD ${target_cxx_version} CXX_EXTENSIONS OFF CXX_STANDARD_REQUIRED ON) + if (is_c_project) + target_compile_options(${target} PUBLIC ${TEST_C_COMPILE_OPTIONS}) + set_target_properties(${target} PROPERTIES + C_STANDARD ${target_lang_version} + C_EXTENSIONS OFF + C_STANDARD_REQUIRED ON + LINKER_LANGUAGE C) + else() + target_compile_options(${target} PUBLIC ${TEST_CXX_COMPILE_OPTIONS}) + set_target_properties(${target} PROPERTIES + CXX_STANDARD ${target_lang_version} + CXX_EXTENSIONS OFF + CXX_STANDARD_REQUIRED ON) + endif() add_test(NAME ${target} COMMAND $) endfunction(add_test_target) -foreach(target_filenames target_dir target_supported_cxx_versions target_dependencies target_optional_dependencies +foreach(target_filenames target_dir target_supported_lang_versions target_dependencies target_optional_dependencies is_c_project IN ZIP_LISTS TestFilenames TestDirectories - TestCxxVersions + TestLangVersions TestDependencies - TestOptionalDependencies) - string(REPLACE " " ";" target_supported_cxx_versions "${target_supported_cxx_versions}") - foreach(version ${SUPPORTED_CXX_VERSIONS}) - if (${version} IN_LIST target_supported_cxx_versions) + TestOptionalDependencies + TestIsCProject) + string(REPLACE " " ";" target_supported_lang_versions "${target_supported_lang_versions}") + foreach(version ${target_supported_lang_versions}) + if ( + (NOT is_c_project AND ${version} IN_LIST COMPILER_SUPPORTED_CXX_VERSIONS) + OR + (is_c_project AND ${version} IN_LIST COMPILER_SUPPORTED_C_VERSIONS) + ) add_test_target( "${target_filenames}" "${target_dir}" "${target_dependencies}" "${target_optional_dependencies}" ${version} + ${is_c_project} ) endif() endforeach() diff --git a/tests/run_codechecker.sh b/tests/run_codechecker.sh index ecb603a..d8dba68 100755 --- a/tests/run_codechecker.sh +++ b/tests/run_codechecker.sh @@ -3,6 +3,8 @@ build_dir=cmake-build-codechecker cmake_build_dir=cmake-build-dir +set -e + mkdir -p "$build_dir" cp ./.clang-tidy ./$build_dir cd ./$build_dir || exit 1 diff --git a/tests/run_gcc_mingw_32_tests.sh b/tests/run_gcc_mingw_32_tests.sh index fff241d..ba8112f 100755 --- a/tests/run_gcc_mingw_32_tests.sh +++ b/tests/run_gcc_mingw_32_tests.sh @@ -16,5 +16,6 @@ cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=i686-w64-mingw32-gcc shopt -s nullglob for test_executable in *.exe; do + echo "Starting $test_executable" wine "$test_executable" done diff --git a/tests/run_gcc_mingw_64_tests.sh b/tests/run_gcc_mingw_64_tests.sh index d01526f..de9ca7c 100755 --- a/tests/run_gcc_mingw_64_tests.sh +++ b/tests/run_gcc_mingw_64_tests.sh @@ -16,5 +16,6 @@ cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=x86_64-w64-mingw32-g shopt -s nullglob for test_executable in *.exe; do + echo "Starting $test_executable" wine "$test_executable" done diff --git a/vec_instructs/config_macros.hpp b/vec_instructs/config_macros.hpp new file mode 100644 index 0000000..416efb2 --- /dev/null +++ b/vec_instructs/config_macros.hpp @@ -0,0 +1,648 @@ +#ifndef CONFIG_MACROS_HPP +#define CONFIG_MACROS_HPP 1 + +/* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +#define CONFIG_GNUC_AT_LEAST(maj, min) ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +#define CONFIG_GNUC_AT_LEAST(maj, min) 0 +#endif + +#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) +#define CONFIG_CLANG_AT_LEAST(maj, min) \ + ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min)) +#else +#define CONFIG_CLANG_AT_LEAST(maj, min) 0 +#endif + +/* Test for __has_attribute as per __glibc_has_attribute in glibc */ +#if defined(__has_attribute) && (!defined(__clang__) || CONFIG_CLANG_AT_LEAST(4, 5)) +#define CONFIG_HAS_GCC_ATTRIBUTE(attr) __has_attribute(attr) +#else +#define CONFIG_HAS_GCC_ATTRIBUTE(attr) 0 +#endif + +#if defined(__cplusplus) && defined(__has_cpp_attribute) +#define CONFIG_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr) +#else +#define CONFIG_HAS_CPP_ATTRIBUTE(attr) 0 +#endif + +#if defined(__has_builtin) +#define CONFIG_HAS_BUILTIN(name) __has_builtin(name) +#else +#define CONFIG_HAS_BUILTIN(name) 0 +#endif + +#if defined(__has_include) +#define CONFIG_HAS_INCLUDE(include_string) __has_include(include_string) +#else +#define CONFIG_HAS_INCLUDE(include_string) 0 +#endif + +#if CONFIG_HAS_INCLUDE() +#include +#elif CONFIG_HAS_INCLUDE() +#include +#elif CONFIG_HAS_INCLUDE() +#include +#endif + +#if defined(__cplusplus) && __cplusplus >= 201103L +#define CONFIG_HAS_AT_LEAST_CXX_11 1 +#else +#define CONFIG_HAS_AT_LEAST_CXX_11 0 +#endif + +#if defined(__cplusplus) && __cplusplus >= 201402L +#define CONFIG_HAS_AT_LEAST_CXX_14 1 +#else +#define CONFIG_HAS_AT_LEAST_CXX_14 0 +#endif + +// https://en.cppreference.com/w/cpp/feature_test +#if defined(__cplusplus) && __cplusplus >= 201703L +#define CONFIG_HAS_AT_LEAST_CXX_17 1 +#else +#define CONFIG_HAS_AT_LEAST_CXX_17 0 +#endif + +#if defined(__cplusplus) && __cplusplus >= 202002L +#define CONFIG_HAS_AT_LEAST_CXX_20 1 +#else +#define CONFIG_HAS_AT_LEAST_CXX_20 0 +#endif + +#if defined(__cplusplus) && __cplusplus >= 202302L +#define CONFIG_HAS_AT_LEAST_CXX_23 1 +#else +#define CONFIG_HAS_AT_LEAST_CXX_23 0 +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define CONFIG_HAS_AT_LEAST_C_11 1 +#else +#define CONFIG_HAS_AT_LEAST_C_11 0 +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201710L +#define CONFIG_HAS_AT_LEAST_C_17 1 +#else +#define CONFIG_HAS_AT_LEAST_C_17 0 +#endif + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L +#define CONFIG_HAS_AT_LEAST_C_23 1 +#else +#define CONFIG_HAS_AT_LEAST_C_23 0 +#endif + +// https://en.cppreference.com/w/cpp/feature_test +#if defined(__cpp_concepts) && __cpp_concepts >= 201907L +#define CONFIG_HAS_CONCEPTS 1 +#else +#define CONFIG_HAS_CONCEPTS 0 +#endif + +/** + * Restrict qualifier for the C++ (C has `restrict` keyword since C99) + */ +#if defined(__GNUC__) || defined(__clang__) +#define RESTRICT_QUALIFIER __restrict__ +#elif defined(_MSC_VER) +#define RESTRICT_QUALIFIER __restrict +#else +#define RESTRICT_QUALIFIER +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define FUNCTION_MACRO __PRETTY_FUNCTION__ +#elif defined(_MSC_VER) +#define FUNCTION_MACRO __FUNCSIG__ +#else +#define FUNCTION_MACRO __func__ +#endif + +#if CONFIG_HAS_INCLUDE() +#include +#endif + +#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L +#define CONFIG_UNREACHABLE() std::unreachable() +#elif CONFIG_HAS_AT_LEAST_CXX_23 && CONFIG_HAS_CPP_ATTRIBUTE(assume) +#define CONFIG_UNREACHABLE() [[assume(false)]] +#elif CONFIG_HAS_BUILTIN(__builtin_unreachable) +#define CONFIG_UNREACHABLE() __builtin_unreachable() +#elif CONFIG_HAS_BUILTIN(__builtin_assume) +#if defined(__cplusplus) +#define CONFIG_UNREACHABLE() __builtin_assume(false) +#else +#define CONFIG_UNREACHABLE() __builtin_assume(0) +#endif +#elif CONFIG_GNUC_AT_LEAST(13, 0) && CONFIG_HAS_GCC_ATTRIBUTE(assume) +#if defined(__cplusplus) +#define CONFIG_UNREACHABLE() __attribute__((assume(false))) +#else +#define CONFIG_UNREACHABLE() __attribute__((assume(0))) +#endif +#elif defined(_MSC_VER) +#if defined(__cplusplus) +#define CONFIG_UNREACHABLE() __assume(false) +#else +#define CONFIG_UNREACHABLE() __assume(0) +#endif +#else +#if defined(__cplusplus) +#define CONFIG_UNREACHABLE() \ + do { \ + } while (false) +#else +#define CONFIG_UNREACHABLE() \ + do { \ + } while (0) +#endif +#endif + +#if CONFIG_HAS_AT_LEAST_CXX_23 && CONFIG_HAS_CPP_ATTRIBUTE(assume) +#define ATTRIBUTE_ASSUME(expr) [[assume(expr)]] +#elif CONFIG_GNUC_AT_LEAST(13, 0) && CONFIG_HAS_GCC_ATTRIBUTE(assume) +#define ATTRIBUTE_ASSUME(expr) __attribute__((assume(expr))) +#elif defined(__clang__) && CONFIG_HAS_BUILTIN(__builtin_assume) +// Side effect of expr is discarded +#define ATTRIBUTE_ASSUME(expr) __builtin_assume(expr) +#elif defined(_MSC_VER) +#define ATTRIBUTE_ASSUME(expr) __assume(expr) +#else +#if defined(__cplusplus) +#define ATTRIBUTE_ASSUME(expr) \ + do { \ + if (!(expr)) { \ + CONFIG_UNREACHABLE(); \ + } \ + } while (false) +#else +#define ATTRIBUTE_ASSUME(expr) \ + do { \ + if (!(expr)) { \ + CONFIG_UNREACHABLE(); \ + } \ + } while (0) +#endif +#endif + +/* __builtin_expect is in gcc 3.0 */ +#if CONFIG_GNUC_AT_LEAST(3, 0) || CONFIG_HAS_BUILTIN(__builtin_expect) + +#if defined(likely) +#undef likely +#endif +#if defined(unlikely) +#undef unlikely +#endif + +#if defined(__cplusplus) +#define likely(x) __builtin_expect(static_cast(x), true) +#define unlikely(x) __builtin_expect(static_cast(x), false) +#else +#define likely(x) __builtin_expect((x), 1) +#define unlikely(x) __builtin_expect((x), 0) +#endif + +#else + +#if !defined(likely) +#if defined(__cplusplus) +#define likely(x) static_cast(x) +#else +#define likely(x) !!(x) +#endif +#endif + +#if !defined(unlikely) +#if defined(__cplusplus) +#define unlikely(x) static_cast(x) +#else +#define unlikely(x) !!(x) +#endif +#endif + +#endif + +/* Copied from the sys/cdefs.h from the glibc */ +#if !(defined(__GNUC__) || defined(__clang__)) +#define __attribute__(...) +#endif + +#if CONFIG_GNUC_AT_LEAST(2, 6) || CONFIG_HAS_GCC_ATTRIBUTE(__const__) +#define ATTRIBUTE_CONST __attribute__((__const__)) +#elif (defined(__GNUG__) || defined(__clang__)) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::__const__) +#define ATTRIBUTE_CONST [[gnu::__const__]] +#else +#define ATTRIBUTE_CONST +#endif + +#if CONFIG_GNUC_AT_LEAST(2, 7) || CONFIG_HAS_GCC_ATTRIBUTE(unused) +#define ATTRIBUTE_MAYBE_UNUSED __attribute__((unused)) +#elif CONFIG_HAS_AT_LEAST_CXX_17 +#define ATTRIBUTE_MAYBE_UNUSED [[maybe_unused]] +#else +#define ATTRIBUTE_MAYBE_UNUSED +#endif + +#if CONFIG_GNUC_AT_LEAST(2, 96) || CONFIG_HAS_GCC_ATTRIBUTE(pure) +#define ATTRIBUTE_PURE __attribute__((pure)) +#elif defined(__GNUG__) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::pure) +#define ATTRIBUTE_PURE [[gnu::pure]] +#else +#define ATTRIBUTE_PURE +#endif + +#if CONFIG_GNUC_AT_LEAST(3, 0) || CONFIG_HAS_GCC_ATTRIBUTE(noinline) +#define ATTRIBUTE_NOINLINE __attribute__((noinline)) +#elif defined(__clang__) && CONFIG_HAS_CPP_ATTRIBUTE(clang::noinline) +#define ATTRIBUTE_NOINLINE [[clang::noinline]] +#elif defined(__GNUG__) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::noinline) +#define ATTRIBUTE_NOINLINE [[gnu::noinline]] +#elif defined(_MSC_VER) && CONFIG_HAS_CPP_ATTRIBUTE(msvc::noinline) +#define ATTRIBUTE_NOINLINE [[msvc::noinline]] +#elif defined(_MSC_VER) && \ + (_MSC_VER >= 1920 || defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 191025017) +#define ATTRIBUTE_NOINLINE __declspec(noinline) +#else +#define ATTRIBUTE_NOINLINE +#endif + +#if CONFIG_GNUC_AT_LEAST(3, 2) || CONFIG_HAS_GCC_ATTRIBUTE(always_inline) +#define ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) +#elif defined(__clang__) && CONFIG_HAS_CPP_ATTRIBUTE(clang::always_inline) +#define ATTRIBUTE_ALWAYS_INLINE [[clang::always_inline]] +#elif defined(__GNUG__) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::always_inline) +#define ATTRIBUTE_ALWAYS_INLINE [[gnu::always_inline]] +#elif defined(_MSC_VER) && CONFIG_HAS_CPP_ATTRIBUTE(msvc::forceinline) +#define ATTRIBUTE_ALWAYS_INLINE [[msvc::forceinline]] +#else +#define ATTRIBUTE_ALWAYS_INLINE +#endif + +#if CONFIG_GNUC_AT_LEAST(4, 3) || CONFIG_HAS_GCC_ATTRIBUTE(cold) +#define ATTRIBUTE_COLD __attribute__((cold)) +#elif (defined(__GNUG__) || defined(__clang__)) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::cold) +#define ATTRIBUTE_COLD [[gnu::cold]] +#else +#define ATTRIBUTE_COLD +#endif + +#if CONFIG_GNUC_AT_LEAST(4, 4) || CONFIG_HAS_GCC_ATTRIBUTE(hot) +#define ATTRIBUTE_HOT __attribute__((hot)) +#elif (defined(__GNUG__) || defined(__clang__)) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::hot) +#define ATTRIBUTE_HOT [[gnu::hot]] +#else +#define ATTRIBUTE_HOT +#endif + +/** + * From glibc: + * Tell the compiler which arguments to an allocation function + * indicate the size of the allocation. + * Clang docs: https://clang.llvm.org/docs/AttributeReference.html#alloc-size + */ +#if CONFIG_GNUC_AT_LEAST(4, 3) || CONFIG_HAS_GCC_ATTRIBUTE(alloc_size) +#define ATTRIBUTE_ALLOC_SIZE(...) __attribute__((alloc_size(__VA_ARGS__))) +#elif (defined(__GNUG__) || defined(__clang__)) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::alloc_size) +#define ATTRIBUTE_ALLOC_SIZE(...) [[gnu::alloc_size(__VA_ARGS__)]] +#else +#define ATTRIBUTE_ALLOC_SIZE(...) +#endif + +/** + * mode in { "read_only", "read_write", "write_only", "none" }, + * mode "none" is valid iff CONFIG_GNUC_AT_LEAST(11, 0) + * + * memory_argument_pos >= 1 + * range_size_argument_pos >= 1 + * + * See https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html for more info + */ +#if CONFIG_GNUC_AT_LEAST(10, 0) +#define ATTRIBUTE_ACCESS(mode, memory_argument_pos) \ + __attribute__((access(mode, memory_argument_pos))) +#define ATTRIBUTE_SIZED_ACCESS(mode, memory_argument_pos, range_size_argument_pos) \ + __attribute__((access(mode, memory_argument_pos, range_size_argument_pos))) +#if CONFIG_GNUC_AT_LEAST(11, 0) +#define ATTRIBUTE_ACCESS_NONE(memory_argument_pos) ATTRIBUTE_ACCESS(none, memory_argument_pos) +#else +#define ATTRIBUTE_ACCESS_NONE(memory_argument_pos) +#endif +#else +#define ATTRIBUTE_ACCESS(mode, memory_argument_pos) +#define ATTRIBUTE_SIZED_ACCESS(mode, memory_argument_pos, range_size_argument_pos) +#define ATTRIBUTE_ACCESS_NONE(memory_argument_pos) +#endif + +/** + * See https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html + * and https://clang.llvm.org/docs/AttributeReference.html#id664 for more info + */ +#if CONFIG_GNUC_AT_LEAST(3, 3) || CONFIG_HAS_GCC_ATTRIBUTE(nonnull) +#define ATTRIBUTE_NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) +#define ATTRIBUTE_NONNULL_ALL_ARGS __attribute__((nonnull)) +#elif CONFIG_HAS_AT_LEAST_CXX_17 && (defined(__GNUG__) || defined(__clang__)) +#define ATTRIBUTE_NONNULL(...) [[gnu::nonnull(__VA_ARGS__)]] +#define ATTRIBUTE_NONNULL_ALL_ARGS [[gnu::nonnull]] +#else +#define ATTRIBUTE_NONNULL(...) +#define ATTRIBUTE_NONNULL_ALL_ARGS +#endif + +#if CONFIG_GNUC_AT_LEAST(4, 9) || CONFIG_HAS_GCC_ATTRIBUTE(returns_nonnull) +#define ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull)) +#elif (defined(__GNUG__) || defined(__clang__)) && CONFIG_HAS_CPP_ATTRIBUTE(gnu::returns_nonnull) +#define ATTRIBUTE_RETURNS_NONNULL [[gnu::returns_nonnull]] +#else +#define ATTRIBUTE_RETURNS_NONNULL +#endif + +#if defined(__clang__) && CONFIG_HAS_CPP_ATTRIBUTE(clang::lifetimebound) +#define ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]] +#else +#define ATTRIBUTE_LIFETIME_BOUND +#endif + +#if defined(__clang__) && CONFIG_HAS_CPP_ATTRIBUTE(clang::reinitializes) +#define ATTRIBUTE_REINITIALIZES [[clang::reinitializes]] +#else +#define ATTRIBUTE_REINITIALIZES +#endif + +#if CONFIG_HAS_AT_LEAST_CXX_17 +#define ATTRIBUTE_NODISCARD [[nodiscard]] +#if CONFIG_HAS_AT_LEAST_CXX_20 +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) [[nodiscard(message)]] +#else +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) [[nodiscard]] +#endif +#elif CONFIG_GNUC_AT_LEAST(3, 4) || CONFIG_HAS_GCC_ATTRIBUTE(warn_unused_result) +#define ATTRIBUTE_NODISCARD __attribute__((warn_unused_result)) +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) __attribute__((warn_unused_result)) +#else +#define ATTRIBUTE_NODISCARD +#define ATTRIBUTE_NODISCARD_WITH_MESSAGE(message) +#endif + +#if CONFIG_HAS_AT_LEAST_CXX_11 +#define ATTRIBUTE_NORETURN [[noreturn]] +#elif CONFIG_HAS_AT_LEAST_C_23 +#define ATTRIBUTE_NORETURN [[noreturn]] +#elif CONFIG_HAS_AT_LEAST_C_11 +#define ATTRIBUTE_NORETURN _Noreturn +#elif CONFIG_GNUC_AT_LEAST(2, 8) || CONFIG_HAS_GCC_ATTRIBUTE(noreturn) +#define ATTRIBUTE_NORETURN __attribute__((noreturn)) +#else +#define ATTRIBUTE_NORETURN +#endif + +#if defined(__cplusplus) && (CONFIG_GNUC_AT_LEAST(2, 8) || CONFIG_CLANG_AT_LEAST(4, 0)) +#if CONFIG_HAS_AT_LEAST_CXX_11 +#define CONFIG_NOEXCEPT_FUNCTION noexcept(true) +#else +#define CONFIG_NOEXCEPT_FUNCTION throw() +#endif +#else +#define CONFIG_NOEXCEPT_FUNCTION +#endif + +#if CONFIG_GNUC_AT_LEAST(3, 4) || CONFIG_HAS_GCC_ATTRIBUTE(nothrow) +#define ATTRIBUTE_NOTHROW __attribute__((nothrow)) +#else +#define ATTRIBUTE_NOTHROW +#endif + +#if CONFIG_HAS_AT_LEAST_CXX_17 +#define ATTRIBUTE_FALLTHROUGH [[fallthrough]] +#elif CONFIG_HAS_AT_LEAST_C_23 +#define ATTRIBUTE_FALLTHROUGH [[fallthrough]] +#elif CONFIG_GNUC_AT_LEAST(7, 1) || CONFIG_HAS_GCC_ATTRIBUTE(fallthrough) +#define ATTRIBUTE_FALLTHROUGH __attribute__((fallthrough)) +#else +#define ATTRIBUTE_FALLTHROUGH +#endif + +// Copypasted from LLVM's int_endianness.h + +/* ===-- int_endianness.h - configuration header for compiler-rt ------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + * ===----------------------------------------------------------------------=== + * + * This file is a configuration header for compiler-rt. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && defined(__ORDER_LITTLE_ENDIAN__) + +/* Clang and GCC provide built-in endianness definitions. */ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 0 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 1 +#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 1 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 0 +#endif /* __BYTE_ORDER__ */ + +#else /* Compilers other than Clang or GCC. */ + +#if defined(__SVR4) && defined(__sun) +#include + +#if defined(_BIG_ENDIAN) +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 0 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 1 +#elif defined(_LITTLE_ENDIAN) +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 1 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 0 +#else /* !_LITTLE_ENDIAN */ +#error "unknown endianness" +#endif /* !_LITTLE_ENDIAN */ + +#endif /* Solaris and AuroraUX. */ + +/* .. */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 0 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 1 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* *BSD */ + +#if defined(__OpenBSD__) || defined(__Bitrig__) +#include + +#if _BYTE_ORDER == _BIG_ENDIAN +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 0 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 1 +#elif _BYTE_ORDER == _LITTLE_ENDIAN +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 1 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 0 +#endif /* _BYTE_ORDER */ + +#endif /* OpenBSD and Bitrig. */ + +/* .. */ + +/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the + * compiler (at least with GCC) */ +#if defined(__APPLE__) || defined(__ellcc__) + +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 0 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 1 +#endif +#endif /* __BIG_ENDIAN__ */ + +#ifdef __LITTLE_ENDIAN__ +#if __LITTLE_ENDIAN__ +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 1 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 0 +#endif +#endif /* __LITTLE_ENDIAN__ */ + +#endif /* Mac OSX */ + +/* .. */ + +#if defined(_WIN32) + +#define CONFIG_BYTE_ORDER_LITTLE_ENDIAN 1 +#define CONFIG_BYTE_ORDER_BIG_ENDIAN 0 + +#endif /* Windows */ + +#endif /* Clang or GCC. */ + +/* . */ + +#if !defined(CONFIG_BYTE_ORDER_LITTLE_ENDIAN) || !defined(CONFIG_BYTE_ORDER_BIG_ENDIAN) +// cppcheck-suppress [preprocessorErrorDirective] +#error Unable to determine endian +#endif /* Check we found an endianness correctly. */ + +#ifdef __cplusplus + +#if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() +#include // for _ReadWriteBarrier +#endif + +namespace config { + +namespace detail { + +#if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() +#if defined(__GNUC__) +// inline function 'sink_char_ptr' given attribute 'noinline' +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif +ATTRIBUTE_NOINLINE static inline void sink_char_ptr(char const volatile*) {} +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#endif + +} // namespace detail + +template +ATTRIBUTE_ALWAYS_INLINE static inline void do_not_optimize_away(T&& expr) noexcept { +#if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() + ::config::detail::sink_char_ptr(&reinterpret_cast(expr)); + _ReadWriteBarrier(); +#elif defined(__GNUC__) + asm volatile("" ::"r,m,i"(expr)); +#else + __asm__("" ::"r,m,i"(expr)); +#endif +} + +} // namespace config + +#if CONFIG_HAS_INCLUDE() +#include +#endif + +namespace config { + +ATTRIBUTE_ALWAYS_INLINE constexpr bool is_constant_evaluated() noexcept { +#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L && \ + CONFIG_HAS_INCLUDE() + return std::is_constant_evaluated(); +#elif CONFIG_HAS_BUILTIN(__builtin_is_constant_evaluated) + return __builtin_is_constant_evaluated(); +#else + return false; +#endif +} + +} // namespace config + +namespace config { + +template +ATTRIBUTE_ALWAYS_INLINE constexpr bool is_gcc_constant_p(ATTRIBUTE_MAYBE_UNUSED T expr) noexcept { +#if CONFIG_HAS_INCLUDE() + static_assert(std::is_trivial::value, + "Type passed to the is_gcc_constant_p() should be trivial"); +#endif +#if CONFIG_HAS_BUILTIN(__builtin_constant_p) + return static_cast(__builtin_constant_p(expr)); +#else + return false; +#endif +} + +} // namespace config + +#else + +#if (defined(_MSC_VER) || defined(__MINGW32__)) && CONFIG_HAS_INCLUDE() +#include // for _ReadWriteBarrier +#if defined(__GNUC__) +// inline function 'sink_char_ptr' given attribute 'noinline' +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif +ATTRIBUTE_NOINLINE static inline void sink_char_ptr( + ATTRIBUTE_MAYBE_UNUSED char const volatile* ptr) {} +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#define do_not_optimize_away(expr) \ + do { \ + sink_char_ptr((volatile const char*)&(expr)); \ + _ReadWriteBarrier(); \ + } while (0) + +#elif defined(__GNUG__) +#define do_not_optimize_away(expr) asm volatile("" ::"r,m,i"(expr)) +#elif defined(__GNUC__) +#define do_not_optimize_away(expr) __asm__ volatile("" ::"r,m,i"(expr)) +#else +#define do_not_optimize_away(expr) __asm__("" ::"r,m,i"(expr)); +#endif + +#endif + +#endif // !CONFIG_MACROS_HPP diff --git a/vec_instructs/measure_memset_int.c b/vec_instructs/measure_memset_int.c index bbe77ea..6c3fb8f 100644 --- a/vec_instructs/measure_memset_int.c +++ b/vec_instructs/measure_memset_int.c @@ -8,13 +8,16 @@ #include #include +#include "config_macros.hpp" #include "memset_int.h" -const size_t kTests = 32; +const size_t kTests = 32; const size_t kBufferSize = 10000000; -__attribute__((__noinline__)) uint64_t measure_memset(int32_t* buffer, - int32_t value) { +ATTRIBUTE_NOINLINE +ATTRIBUTE_ACCESS(write_only, 1) +ATTRIBUTE_NODISCARD_WITH_MESSAGE("returned time should be used") +uint64_t measure_memset(int32_t* const buffer, const int32_t value) { struct timespec start; struct timespec end; uint64_t avg_time = 0; @@ -29,8 +32,10 @@ __attribute__((__noinline__)) uint64_t measure_memset(int32_t* buffer, return avg_time / kTests; } -__attribute__((__noinline__)) uint64_t measure_memset_int(int32_t* buffer, - int32_t value) { +ATTRIBUTE_NOINLINE +ATTRIBUTE_ACCESS(write_only, 1) +ATTRIBUTE_NODISCARD_WITH_MESSAGE("returned time should be used") +uint64_t measure_memset_int(int32_t* const buffer, const int32_t value) { struct timespec start; struct timespec end; uint64_t avg_time = 0; @@ -46,45 +51,44 @@ __attribute__((__noinline__)) uint64_t measure_memset_int(int32_t* buffer, } int main(void) { - int32_t* buffer = (int32_t*)malloc(kBufferSize * sizeof(int32_t)); - if (buffer == NULL) + int32_t* const buffer = (int32_t*)calloc(kBufferSize, sizeof(int32_t)); + if (buffer == NULL) { return EXIT_FAILURE; - int32_t value = atoi("255"); + } + + const int32_t value = atoi("255"); - measure_memset(buffer, value); - measure_memset_int(buffer, value); - measure_memset(buffer, value); - measure_memset_int(buffer, value); + do_not_optimize_away(measure_memset(buffer, value)); + do_not_optimize_away(measure_memset_int(buffer, value)); + do_not_optimize_away(measure_memset(buffer, value)); + do_not_optimize_away(measure_memset_int(buffer, value)); - uint64_t time1 = measure_memset_int(buffer, value); - uint64_t time2 = measure_memset(buffer, value); + const uint64_t time1 = measure_memset_int(buffer, value); + const uint64_t time2 = measure_memset(buffer, value); - measure_memset(buffer, value); - measure_memset_int(buffer, value); - measure_memset(buffer, value); - measure_memset_int(buffer, value); + do_not_optimize_away(measure_memset(buffer, value)); + do_not_optimize_away(measure_memset_int(buffer, value)); + do_not_optimize_away(measure_memset(buffer, value)); + do_not_optimize_away(measure_memset_int(buffer, value)); - uint64_t time3 = measure_memset(buffer, value); - uint64_t time4 = measure_memset_int(buffer, value); + const uint64_t time3 = measure_memset(buffer, value); + const uint64_t time4 = measure_memset_int(buffer, value); - printf( + // clang-format off + int ret = printf( "memset_int:\n" - " test 1: %" PRIu64 - " ns\n" - " test 2: %" PRIu64 - " ns\n" - " avrg : %" PRIu64 - " ns\n" + " test 1: %" PRIu64 " ns\n" + " test 2: %" PRIu64 " ns\n" + " avrg : %" PRIu64 " ns\n" "memset:\n" - " test 1: %" PRIu64 - " ns\n" - " test 2: %" PRIu64 - " ns\n" + " test 1: %" PRIu64 " ns\n" + " test 2: %" PRIu64 " ns\n" " avrg : %" PRIu64 " ns\n", time1, time4, (time1 + time4) / 2, time2, time3, (time2 + time3) / 2); + // clang-format on free(buffer); - return EXIT_SUCCESS; + return ret > 0 ? EXIT_SUCCESS : EXIT_FAILURE; } /** @@ -137,4 +141,25 @@ int main(void) { * test 2: 1312409 ns * avrg : 1296824 ns * + * + *----------------------- + * + * memset_int: + * test 1: 3670030 ns + * test 2: 3668985 ns + * avrg : 3669507 ns + * memset: + * test 1: 3679393 ns + * test 2: 3690278 ns + * avrg : 3684835 ns + * + * memset_int: + * test 1: 3677818 ns + * test 2: 3668477 ns + * avrg : 3673147 ns + * memset: + * test 1: 3686079 ns + * test 2: 3687984 ns + * avrg : 3687031 ns + * */ diff --git a/vec_instructs/memcount.h b/vec_instructs/memcount.h index 634507e..49e2530 100644 --- a/vec_instructs/memcount.h +++ b/vec_instructs/memcount.h @@ -1,95 +1,172 @@ -#if !defined(MEMSET_COUNT_H) -#define MEMSET_COUNT_H 1 +#if !defined(MEMCOUNT_H) +#define MEMCOUNT_H 1 #if defined(__cplusplus) -extern "C" { -#endif // __cplusplus - -#if defined(__GNUC__) -#if !defined(__clang__) -#pragma GCC push_options -#pragma GCC target("popcnt,avx,avx2") +#define EXTERN_WITH_C_LINKAGE_BEGIN extern "C" { +#define EXTERN_WITH_C_LINKAGE_END } #else -#pragma clang attribute push(__attribute__((target("popcnt,avx,avx2"))), apply_to = function) -#endif // !__clang__ -#endif // __GNUC__ +#define EXTERN_WITH_C_LINKAGE_BEGIN +#define EXTERN_WITH_C_LINKAGE_END +#endif #include +EXTERN_WITH_C_LINKAGE_BEGIN #include +EXTERN_WITH_C_LINKAGE_END -#if defined(__GNUC__) -__attribute__((nonnull(1))) -#if !defined(__clang__) -__attribute__((access(read_only, 1, 3))) -#endif // !__clang__ -#endif // __GNUC__ -size_t memcount(const void* src, int chr, size_t size) { -#if defined(__GNUC__) -#if !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull-compare" +#include "config_macros.hpp" + +EXTERN_WITH_C_LINKAGE_BEGIN + +#define MEMCOUNT_ATTRIBUTES \ + ATTRIBUTE_NODISCARD_WITH_MESSAGE("return value of the memcount should not be ommited") \ + ATTRIBUTE_NOTHROW ATTRIBUTE_SIZED_ACCESS(read_only, 1, 3) ATTRIBUTE_PURE + +#if defined(__GNUC__) || defined(__clang__) +#define FAST_MEMCOUNT_TARGET_ATTRIBUTE __attribute__((target("popcnt,avx,avx2"))) #else -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-pointer-compare" +#define FAST_MEMCOUNT_TARGET_ATTRIBUTE #endif - if (__builtin_expect(src == NULL, 0)) - return 0; -#if !defined(__clang__) -#pragma GCC diagnostic pop -#else -#pragma clang diagnostic pop + +MEMCOUNT_ATTRIBUTES +FAST_MEMCOUNT_TARGET_ATTRIBUTE +static inline size_t memcount_avx(const uint8_t* const src, const uint8_t chr, + size_t size) CONFIG_NOEXCEPT_FUNCTION { +#if defined(__cplusplus) +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" #endif -#else - if (src == NULL) - return 0; #endif - const unsigned char* not_aligned_address = (const unsigned char*)src; - const __m256i* aligned_32_address = (const __m256i*)(((uintptr_t)not_aligned_address + 31) & ~(uintptr_t)31); + const uint8_t* not_aligned_address = src; + const __m256i* aligned_32_address = + (const __m256i*)(((uintptr_t)not_aligned_address + 31) & ~(uintptr_t)31); uintptr_t mem_offset = (uintptr_t)aligned_32_address - (uintptr_t)not_aligned_address; -#if defined(__GNUC__) - if (__builtin_expect(mem_offset > size, 0)) -#else - if (mem_offset > size) -#endif + if (unlikely(mem_offset > size)) { mem_offset = size; + } size -= mem_offset; size_t eq_count = 0; - for (const uint32_t cmp_chr_u32 = (uint32_t)(unsigned int)(chr); - mem_offset--; ++not_aligned_address) { + for (const uint32_t cmp_chr_u32 = (uint32_t)(unsigned int)(chr); mem_offset--; + ++not_aligned_address) { eq_count += *not_aligned_address == cmp_chr_u32; } - mem_offset = size % 32; - size /= 32; + mem_offset = size % 32; + size_t steps = size / 32; - for (const __m256i chr_vector = _mm256_set1_epi8((char)chr); size != 0; - --size, ++aligned_32_address) { - eq_count += (uint32_t)_popcnt32((uint32_t)_mm256_movemask_epi8( - _mm256_cmpeq_epi8(chr_vector, *aligned_32_address))); + for (const __m256i chr_vector = _mm256_set1_epi8((char)chr); steps > 0; + --steps, ++aligned_32_address) { + eq_count += (uint32_t)_popcnt32( + (uint32_t)_mm256_movemask_epi8(_mm256_cmpeq_epi8(chr_vector, *aligned_32_address))); } - not_aligned_address = (const unsigned char*)aligned_32_address; - for (const uint32_t cmp_chr_u32 = (uint32_t)(unsigned int)(chr); - mem_offset--; ++not_aligned_address) { + not_aligned_address = (const uint8_t*)aligned_32_address; + for (const uint32_t cmp_chr_u32 = (uint32_t)(unsigned int)(chr); mem_offset--; + ++not_aligned_address) { eq_count += *not_aligned_address == cmp_chr_u32; } +#if defined(__cplusplus) +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#endif + return eq_count; } -#if defined(__GNUC__) -#if !defined(__clang__) -#pragma GCC pop_options +#undef FAST_MEMCOUNT_TARGET_ATTRIBUTE + +MEMCOUNT_ATTRIBUTES +static inline size_t memcount_default(const uint8_t* const src, const uint8_t chr, + size_t size) CONFIG_NOEXCEPT_FUNCTION { + size_t cnt = 0; + const uint32_t c = chr; + for (const uint8_t* s = src; size > 0; ++s, --size) { + cnt += *s == c; + } + return cnt; +} + +#if defined(__GNUC__) || defined(__clang__) + +ATTRIBUTE_NODISCARD_WITH_MESSAGE("this function is resolver and should not be used") +ATTRIBUTE_MAYBE_UNUSED +ATTRIBUTE_NOTHROW +ATTRIBUTE_RETURNS_NONNULL +#if defined(__clang__) +__attribute__((no_sanitize("address", "thread", "memory", "undefined"))) +#elif defined(__GNUC__) +__attribute__((no_sanitize_address, no_sanitize_thread, no_sanitize_undefined)) +#endif +static inline size_t (*resolve_memcount(void))(const uint8_t*, uint8_t, size_t) { + __builtin_cpu_init(); + return __builtin_cpu_supports("avx2") && __builtin_cpu_supports("popcnt") ? memcount_avx + : memcount_default; +} + +#if defined(linux) || defined(__linux__) + +// clang-format off + +MEMCOUNT_ATTRIBUTES +#if defined(__cplusplus) && defined(__clang__) +__attribute__((ifunc("_ZL16resolve_memcountv"))) #else -#pragma clang attribute pop -#endif // !__clang__ -#endif // __GNUC__ +__attribute__((ifunc("resolve_memcount"))) +#endif +static inline size_t memcount(const uint8_t* const src, const uint8_t chr, size_t size) CONFIG_NOEXCEPT_FUNCTION; + +#else // !__linux__ #if defined(__cplusplus) + +#if CONFIG_HAS_AT_LEAST_CXX_17 +static inline +#endif +size_t (*const memcount)(const uint8_t* const src, const uint8_t chr, size_t size) = resolve_memcount(); + +#else + +size_t (*memcount)(const uint8_t* const src, const uint8_t chr, size_t size) = NULL; + +// clang-format on + +ATTRIBUTE_NOTHROW +__attribute__((constructor)) static inline void memcount_initializer(void) + CONFIG_NOEXCEPT_FUNCTION { + memcount = resolve_memcount(); } -#endif // __cplusplus -#endif // !MEMSET_COUNT_H +#endif + +#endif + +#else // !__GNUC__ + +MEMCOUNT_ATTRIBUTES +ATTRIBUTE_ALWAYS_INLINE +static inline size_t memcount(const uint8_t* const src, const uint8_t chr, + size_t size) CONFIG_NOEXCEPT_FUNCTION { + return memcount_default(src, chr, size); +} + +#endif + +#undef MEMCOUNT_ATTRIBUTES + +EXTERN_WITH_C_LINKAGE_END + +#undef EXTERN_WITH_C_LINKAGE_END +#undef EXTERN_WITH_C_LINKAGE_BEGIN + +#endif // !MEMCOUNT_H diff --git a/vec_instructs/memset_int.h b/vec_instructs/memset_int.h index 10c83e1..da92c4d 100644 --- a/vec_instructs/memset_int.h +++ b/vec_instructs/memset_int.h @@ -2,142 +2,95 @@ #define MEMSET_INT_H 1 #if defined(__cplusplus) -extern "C" { -#endif // __cplusplus - -#if defined(__GNUC__) -#if !defined(__clang__) -#pragma GCC push_options -#pragma GCC target("avx") +#define EXTERN_WITH_C_LINKAGE_BEGIN extern "C" { +#define EXTERN_WITH_C_LINKAGE_END } #else -#pragma clang attribute push(__attribute__((target("avx"))), \ - apply_to = function) -#endif // !__clang__ -#endif // __GNUC__ +#define EXTERN_WITH_C_LINKAGE_BEGIN +#define EXTERN_WITH_C_LINKAGE_END +#endif #include +EXTERN_WITH_C_LINKAGE_BEGIN #include +EXTERN_WITH_C_LINKAGE_END -#if defined(__GNUC__) -#if !defined(__clang__) -#define MEMSET_INT_FUNC_ATTRIBUTES \ - __attribute__((nonnull(1))) __attribute__((access(write_only, 1, 3))) -#else -#define MEMSET_INT_FUNC_ATTRIBUTES __attribute__((nonnull(1))) -#endif // !__clang__ -#else -#define MEMSET_INT_FUNC_ATTRIBUTES -#endif // __GNUC__ +#include "config_macros.hpp" -MEMSET_INT_FUNC_ATTRIBUTES -void memset_int_avx(int32_t* dst, int32_t value, size_t size) { -#if defined(__GNUC__) -#if !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull-compare" -#else +EXTERN_WITH_C_LINKAGE_BEGIN + +#if defined(__cplusplus) +#if defined(__clang__) #pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-pointer-compare" +#pragma clang diagnostic ignored "-Wold-style-cast" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" #endif - if (__builtin_expect(dst == NULL, 0)) - return; -#if !defined(__clang__) -#pragma GCC diagnostic pop -#else -#pragma clang diagnostic pop #endif + +#define MEMSET_INT_FUNC_ATTRIBUTES ATTRIBUTE_NOTHROW ATTRIBUTE_SIZED_ACCESS(write_only, 1, 3) + +#if defined(__GNUC__) || defined(__clang__) +#define FAST_MEMSET_INT_TARGET_ATTRIBUTE __attribute__((target("avx"))) #else - if (dst == NULL) - return; +#define FAST_MEMSET_INT_TARGET_ATTRIBUTE #endif +MEMSET_INT_FUNC_ATTRIBUTES +FAST_MEMSET_INT_TARGET_ATTRIBUTE +static inline void memset_int_avx(int32_t* dst, int32_t value, + size_t size) CONFIG_NOEXCEPT_FUNCTION { uint32_t* aligned_4_address = (uint32_t*)dst; - __m256i* aligned_32_address = - (__m256i*)(((uintptr_t)aligned_4_address + 31) & ~(uintptr_t)31); - const uint32_t uvalue_32 = (uint32_t)value; + __m256i* aligned_32_address = (__m256i*)(((uintptr_t)aligned_4_address + 31) & ~(uintptr_t)31); + const uint32_t uvalue_32 = (uint32_t)value; uintptr_t offset = - ((uintptr_t)aligned_32_address - (uintptr_t)aligned_4_address) / 4; -#if defined(__GNUC__) - if (__builtin_expect(offset > size, 0)) -#else - if (offset > size) -#endif + ((uintptr_t)aligned_32_address - (uintptr_t)aligned_4_address) / sizeof(uint32_t); + if (unlikely(offset > size)) { offset = size; + } size -= offset; while (offset--) { *aligned_4_address = uvalue_32; ++aligned_4_address; } - for (const __m256i value_vector = _mm256_set1_epi32(value); size >= 8; - size -= 8) { + for (const __m256i value_vector = _mm256_set1_epi32(value); size >= 8; size -= 8) { _mm256_store_si256(aligned_32_address, value_vector); ++aligned_32_address; } uint64_t* aligned_8_address = (uint64_t*)aligned_32_address; - const uint64_t uvalue_64 = ((uint64_t)uvalue_32 << 32) | uvalue_32; + const uint64_t uvalue_64 = ((uint64_t)uvalue_32 << 32) | uvalue_32; switch (size / 2) { case 3: *aligned_8_address = uvalue_64; ++aligned_8_address; -#if defined(__GNUC__) - __attribute__((fallthrough)); -#endif + ATTRIBUTE_FALLTHROUGH; case 2: *aligned_8_address = uvalue_64; ++aligned_8_address; -#if defined(__GNUC__) - __attribute__((fallthrough)); -#endif + ATTRIBUTE_FALLTHROUGH; case 1: *aligned_8_address = uvalue_64; ++aligned_8_address; break; -#if defined(__GNUC__) case 0: break; default: - __builtin_unreachable(); + CONFIG_UNREACHABLE(); break; -#endif } if (size % 2) { - aligned_4_address = (uint32_t*)aligned_8_address; + aligned_4_address = (uint32_t*)aligned_8_address; *aligned_4_address = uvalue_32; } } -#if defined(__GNUC__) -#if !defined(__clang__) -#pragma GCC pop_options -#else -#pragma clang attribute pop -#endif // !__clang__ -#endif // __GNUC__ +#undef FAST_MEMSET_INT_TARGET_ATTRIBUTE MEMSET_INT_FUNC_ATTRIBUTES -void memset_int_default(int32_t* dst, int32_t value, size_t size) { -#if defined(__GNUC__) -#if !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wnonnull-compare" -#else -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wtautological-pointer-compare" -#endif - if (__builtin_expect(dst == NULL, 0)) - return; -#if !defined(__clang__) -#pragma GCC diagnostic pop -#else -#pragma clang diagnostic pop -#endif -#else - if (dst == NULL) - return; -#endif - +static inline void memset_int_default(int32_t* dst, int32_t value, + size_t size) CONFIG_NOEXCEPT_FUNCTION { while (size >= 4) { dst[0] = value; dst[1] = value; @@ -150,71 +103,108 @@ void memset_int_default(int32_t* dst, int32_t value, size_t size) { switch (size) { case 3: dst[2] = value; -#if defined(__GNUC__) - __attribute__((fallthrough)); -#endif + ATTRIBUTE_FALLTHROUGH; case 2: dst[1] = value; -#if defined(__GNUC__) - __attribute__((fallthrough)); -#endif + ATTRIBUTE_FALLTHROUGH; case 1: dst[0] = value; break; -#if defined(__GNUC__) case 0: break; default: - __builtin_unreachable(); + CONFIG_UNREACHABLE(); break; -#endif } } -#if defined(__GNUC__) +#if defined(__cplusplus) +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +#endif -#if (defined(linux) || defined(__linux__)) +#if defined(__GNUC__) || defined(__clang__) -__attribute__((unused)) static void (*resolve_memset_int(void))(int32_t*, - int32_t, - size_t) { +#if defined(__clang__) && defined(__cplusplus) && !CONFIG_HAS_AT_LEAST_CXX_17 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++17-compat-mangling" +#endif + +ATTRIBUTE_NODISCARD_WITH_MESSAGE("this function is resolver and should not be used") +ATTRIBUTE_MAYBE_UNUSED +ATTRIBUTE_NOTHROW +ATTRIBUTE_RETURNS_NONNULL +#if defined(__clang__) +__attribute__((no_sanitize("address", "thread", "memory", "undefined"))) +#elif defined(__GNUC__) +__attribute__((no_sanitize_address, no_sanitize_thread, no_sanitize_undefined)) +#endif +static inline void (*resolve_memset_int(void))(int32_t*, int32_t, size_t) CONFIG_NOEXCEPT_FUNCTION { __builtin_cpu_init(); - if (__builtin_cpu_supports("avx")) { - return memset_int_avx; - } - return memset_int_default; + return __builtin_cpu_supports("avx") ? memset_int_avx : memset_int_default; } +#if defined(__clang__) && defined(__cplusplus) && !CONFIG_HAS_AT_LEAST_CXX_17 +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++17-compat-mangling" +#endif + +#if defined(linux) || defined(__linux__) + +// clang-format off + MEMSET_INT_FUNC_ATTRIBUTES -__attribute__((ifunc("resolve_memset_int"))) void memset_int(int32_t* dst, - int32_t value, - size_t size); +#if defined(__cplusplus) && defined(__clang__) +__attribute__((ifunc("_ZL18resolve_memset_intv"))) +#else +__attribute__((ifunc("resolve_memset_int"))) +#endif +static inline void memset_int(int32_t* dst, int32_t value, size_t size) CONFIG_NOEXCEPT_FUNCTION; + +#else // !__linux__ + +#if defined(__cplusplus) + +#if CONFIG_HAS_AT_LEAST_CXX_17 +static inline +#endif +void (*const memset_int)(int32_t* dst, int32_t value, size_t size) CONFIG_NOEXCEPT_FUNCTION = resolve_memset_int(); #else -MEMSET_INT_FUNC_ATTRIBUTES void (*memset_int)(int32_t* dst, int32_t value, size_t size) = NULL; -__attribute__((constructor)) static inline void memset_int_initializer(void) { - memset_int = - __builtin_cpu_supports("avx") ? memset_int_avx : memset_int_default; +// clang-format on + +ATTRIBUTE_NOTHROW +__attribute__((constructor)) static inline void memset_int_initializer(void) + CONFIG_NOEXCEPT_FUNCTION { + __builtin_cpu_init(); + memset_int = resolve_memset_int(); } #endif -#else +#endif + +#else // !__GNUC__ MEMSET_INT_FUNC_ATTRIBUTES -static inline memset_int(int32_t* dst, int32_t value, size_t size) { - return memset_int_default(dst, value, size); +ATTRIBUTE_ALWAYS_INLINE +static inline void memset_int(int32_t* dst, int32_t value, size_t size) CONFIG_NOEXCEPT_FUNCTION { + memset_int_default(dst, value, size); } #endif #undef MEMSET_INT_FUNC_ATTRIBUTES -#if defined(__cplusplus) -} -#endif // __cplusplus +EXTERN_WITH_C_LINKAGE_END + +#undef EXTERN_WITH_C_LINKAGE_END +#undef EXTERN_WITH_C_LINKAGE_BEGIN #endif // !MEMSET_INT_H diff --git a/vec_instructs/test_memcount.c b/vec_instructs/test_memcount.c index 109d322..0df0a10 100644 --- a/vec_instructs/test_memcount.c +++ b/vec_instructs/test_memcount.c @@ -1,24 +1,25 @@ +#ifdef NDEBUG +// cppcheck-suppress [preprocessorErrorDirective] +#error "NDEBUG defined, asserts are off" +#endif + #include #include +#include #include "memcount.h" -size_t memcount_slow(const void* src, int c, size_t size) { - size_t cnt = 0; - for (const unsigned char* s = (const unsigned char*)src; size != 0; - ++s, --size) { +static size_t memcount_slow(const uint8_t* const src, const uint8_t chr, size_t size) { + size_t cnt = 0; + const uint32_t c = chr; + for (const uint8_t* s = src; size > 0; ++s, --size) { cnt += *s == c; } return cnt; } int main(void) { -#if defined(__GNUC__) - assert(__builtin_cpu_supports("popcnt")); - assert(__builtin_cpu_supports("avx")); - assert(__builtin_cpu_supports("avx2")); -#endif - const char arr[] = + const uint8_t arr[] = "aaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaa" "aaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaa" "aabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacc" @@ -34,13 +35,12 @@ int main(void) { "aaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaa" "bacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccc" "cccbbdddddddaaabaaaaaaaaaabacccccccbbddddddd"; - const int c = 'a'; + const uint8_t c = (uint8_t)(atoi("97")); const size_t arr_len = sizeof(arr) - 1; for (size_t slice_len = 0; slice_len < arr_len; slice_len++) { for (size_t slice_start = 0; slice_start + slice_len <= arr_len; slice_start++) { - assert(memcount(&arr[slice_start], c, slice_len) == memcount_slow(&arr[slice_start], c, slice_len)); + assert(memcount(&arr[slice_start], c, slice_len) == + memcount_slow(&arr[slice_start], c, slice_len)); } } } - -// clang -g3 .\test_memcount.c -O2 -fsanitize="address,undefined" -Wall -Wextra -Wpedantic -Werror -Wunused -pedantic-errors -Wconversion -Wshadow -Wnull-dereference -Wundef -Wwrite-strings -Wbad-function-cast -Wsign-conversion -Wmissing-noreturn -Wunreachable-code -Wint-conversion -Warray-bounds -o test_memcount.exe diff --git a/vec_instructs/test_memcount.cpp b/vec_instructs/test_memcount.cpp new file mode 100644 index 0000000..d47767e --- /dev/null +++ b/vec_instructs/test_memcount.cpp @@ -0,0 +1,50 @@ +#ifdef NDEBUG +// cppcheck-suppress [preprocessorErrorDirective] +#error "NDEBUG defined, asserts are off" +#endif + +#include +#include +#include + +#include "memcount.h" + +namespace { + +size_t memcount_slow(const uint8_t* const src, const uint8_t chr, size_t size) noexcept { + size_t cnt = 0; + const uint32_t c = chr; + for (const uint8_t* s = src; size > 0; ++s, --size) { + cnt += *s == c; + } + return cnt; +} + +} // namespace + +int main() { + constexpr uint8_t arr[] = + "aaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaa" + "aaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaa" + "aabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacc" + "cccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccb" + "bdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbddddd" + "ddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaab" + "aaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaa" + "aaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaaba" + "cccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccc" + "cbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbddd" + "ddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaa" + "abaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaa" + "aaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaa" + "bacccccccbbdddddddaaabaaaaaaaaaabacccccccbbdddddddaaabaaaaaaaaaabacccc" + "cccbbdddddddaaabaaaaaaaaaabacccccccbbddddddd"; + const uint8_t c = static_cast(std::atoi("97")); + constexpr size_t arr_len = sizeof(arr) - 1; + for (size_t slice_len = 0; slice_len < arr_len; slice_len++) { + for (size_t slice_start = 0; slice_start + slice_len <= arr_len; slice_start++) { + assert(memcount(&arr[slice_start], c, slice_len) == + memcount_slow(&arr[slice_start], c, slice_len)); + } + } +} diff --git a/vec_instructs/test_memset_int.c b/vec_instructs/test_memset_int.c index 4ab7394..4f08edd 100644 --- a/vec_instructs/test_memset_int.c +++ b/vec_instructs/test_memset_int.c @@ -1,5 +1,6 @@ #include -#include +#include +#include #include #include "memset_int.h" @@ -12,15 +13,20 @@ int main(void) { for (size_t offset = 0; offset <= 1; offset++) { // offset = 0 => arr is aligned on a 8-byte boundary // offset = 1 => arr is aligned on a 4-byte boundary - int32_t* arr = &buffer[offset]; + int32_t* const arr = &buffer[offset]; for (size_t i = 0; i <= arr_len; i++) { - memset(arr, 0, arr_len * sizeof(int32_t)); + const uint8_t kMagicByte = 251; + const int32_t kMagicInt32 = + (int32_t)((((uint32_t)kMagicByte) << 24) | (((uint32_t)kMagicByte) << 16) | + (((uint32_t)kMagicByte) << 8) | (((uint32_t)kMagicByte) << 0)); + + memset(arr, kMagicByte, arr_len * sizeof(int32_t)); memset_int(arr, k, i); for (size_t j = 0; j < i; j++) { assert(arr[j] == k); } for (size_t j = i; j < arr_len; j++) { - assert(arr[j] == 0); + assert(arr[j] == kMagicInt32); } } } diff --git a/vec_instructs/test_memset_int.cpp b/vec_instructs/test_memset_int.cpp new file mode 100644 index 0000000..3638efd --- /dev/null +++ b/vec_instructs/test_memset_int.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include + +#include "memset_int.h" + +int main() { + using std::int32_t; + using std::size_t; + using std::uint32_t; + using std::uint8_t; + + constexpr size_t arr_len = 512; + int32_t buffer[arr_len + 1]{}; + const int32_t k = std::atoi("-1345452112"); + + for (size_t offset = 0; offset <= 1; offset++) { + // offset = 0 => arr is aligned on a 8-byte boundary + // offset = 1 => arr is aligned on a 4-byte boundary + int32_t* const arr = &buffer[offset]; + for (size_t i = 0; i <= arr_len; i++) { + const uint8_t kMagicByte = 251; + const int32_t kMagicInt32 = static_cast( + ((uint32_t{kMagicByte}) << 24) | ((uint32_t{kMagicByte}) << 16) | + ((uint32_t{kMagicByte}) << 8) | ((uint32_t{kMagicByte}) << 0)); + + std::memset(arr, kMagicByte, arr_len * sizeof(int32_t)); + memset_int(arr, k, i); + for (size_t j = 0; j < i; j++) { + assert(arr[j] == k); + } + for (size_t j = i; j < arr_len; j++) { + assert(arr[j] == kMagicInt32); + } + } + } +}