From 004a81b26f74fcd78482b97bf01ab70d47763b67 Mon Sep 17 00:00:00 2001 From: Michael Platings Date: Wed, 28 Feb 2024 15:58:50 +0000 Subject: [PATCH] Enable building with GCC * Fix apparent typos in vget_high and vget_low. * __builtin_align_up not supported by GCC. Replace it with code that typically compiles to the same instructions. * Removed some invalid loop unroll pragmas. * Work around GCC not supporting template specialisation in classes. * Add missing return value checks in tests. * Various minor fixes to address warnings and compilation failures. * Build with GCC in CI. --- intrinsiccv/CMakeLists.txt | 20 ++++++++++------ intrinsiccv/include/intrinsiccv/config.h.in | 5 ++++ .../intrinsiccv/morphology/workspace.h | 8 +++---- .../include/intrinsiccv/neon_intrinsics.h | 8 +++---- intrinsiccv/include/intrinsiccv/utils.h | 15 ++++++++++++ .../include/intrinsiccv/workspace/borders.h | 12 ++++++++++ .../include/intrinsiccv/workspace/separable.h | 6 ++++- intrinsiccv/src/analysis/canny_neon.cpp | 3 +-- intrinsiccv/src/conversions/gray_to_rgb_sc.h | 12 ++++++---- intrinsiccv/src/conversions/merge_neon.cpp | 12 +++------- intrinsiccv/src/conversions/split_neon.cpp | 16 ++++--------- .../src/conversions/yuv_to_rgb_neon.cpp | 5 +--- intrinsiccv/src/conversions/yuv_to_rgb_sc.h | 4 ++-- scripts/ci.sh | 24 ++++++++++++------- test/api/test_add_abs_with_threshold.cpp | 4 ++-- test/api/test_count_nonzeros.cpp | 7 +++--- test/api/test_min_max.cpp | 9 +++---- test/api/test_saturating_absdiff.cpp | 4 ++-- test/api/test_saturating_add.cpp | 2 +- test/api/test_saturating_multiply.cpp | 4 ++-- test/api/test_saturating_sub.cpp | 2 +- test/api/test_scale.cpp | 4 +++- test/api/test_sobel.cpp | 12 +++++----- test/api/test_split.cpp | 2 +- test/api/test_threshold_binary.cpp | 4 ++-- test/api/test_transpose.cpp | 2 +- test/api/test_yuv_to_rgb.cpp | 3 ++- test/framework/utils.h | 8 +++---- 28 files changed, 127 insertions(+), 90 deletions(-) diff --git a/intrinsiccv/CMakeLists.txt b/intrinsiccv/CMakeLists.txt index 31d3b1c8e..553f13acf 100644 --- a/intrinsiccv/CMakeLists.txt +++ b/intrinsiccv/CMakeLists.txt @@ -87,12 +87,6 @@ set(INTRINSICCV_WARNING_FLAGS "-Wold-style-cast" ) -set(INTRINSICCV_CLANG_FLAGS - "-mllvm" - "-inline-threshold=10000" - "-fno-unroll-loops" -) - set(INTRINSICCV_CXX_FLAGS "-O2" "-g0" @@ -100,10 +94,22 @@ set(INTRINSICCV_CXX_FLAGS "-fno-stack-protector" "-fno-exceptions" "-fno-rtti" - ${INTRINSICCV_CLANG_FLAGS} + "-fno-unroll-loops" ${INTRINSICCV_WARNING_FLAGS} ) +if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + list(APPEND INTRINSICCV_CXX_FLAGS + "-mllvm" + "-inline-threshold=10000" + ) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + list(APPEND INTRINSICCV_CXX_FLAGS + "-flax-vector-conversions" + "-Wno-unused-label" + ) +endif() + if (INTRINSICCV_CHECK_BANNED_FUNCTIONS) # The `SHELL:` prefix is used to turn off de-duplication of compiler flags, # it is necessary if other headers are need to be force included. diff --git a/intrinsiccv/include/intrinsiccv/config.h.in b/intrinsiccv/include/intrinsiccv/config.h.in index a842fdfff..a92ddfc1a 100644 --- a/intrinsiccv/include/intrinsiccv/config.h.in +++ b/intrinsiccv/include/intrinsiccv/config.h.in @@ -65,7 +65,12 @@ #define INTRINSICCV_IFUNC_RESOLVER \ INTRINSICCV_ATTR_SECTION(".text.ifunc_resolvers") +#ifdef __clang__ #define INTRINSICCV_FORCE_LOOP_UNROLL _Pragma("clang loop unroll(full)") +#else +// GCC doesn't have clang's unroll(full). 16 is typically plenty. +#define INTRINSICCV_FORCE_LOOP_UNROLL _Pragma("GCC unroll 16") +#endif #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) || \ (defined(__cplusplus) && __cplusplus >= 201703L) diff --git a/intrinsiccv/include/intrinsiccv/morphology/workspace.h b/intrinsiccv/include/intrinsiccv/morphology/workspace.h index 3132c9054..460fa7fe0 100644 --- a/intrinsiccv/include/intrinsiccv/morphology/workspace.h +++ b/intrinsiccv/include/intrinsiccv/morphology/workspace.h @@ -82,7 +82,7 @@ class MorphologyWorkspace final { size_t wide_rows_width = margin.left() + image_size.width() + margin.right(); size_t wide_rows_stride = wide_rows_width * channels; - wide_rows_stride = __builtin_align_up(wide_rows_stride, kAlignment); + wide_rows_stride = align_up(wide_rows_stride, kAlignment); size_t wide_rows_height = 1UL; // There is only one wide row. size_t wide_rows_size = wide_rows_stride * wide_rows_height; wide_rows_size += kAlignment - 1; @@ -90,7 +90,7 @@ class MorphologyWorkspace final { // Multiple buffer rows to hold rows without any borders. size_t buffer_rows_width = type_size * image_size.width(); size_t buffer_rows_stride = buffer_rows_width * channels; - buffer_rows_stride = __builtin_align_up(buffer_rows_stride, kAlignment); + buffer_rows_stride = align_up(buffer_rows_stride, kAlignment); size_t buffer_rows_height = 2 * rows_per_iteration; size_t buffer_rows_size = 0UL; if (__builtin_mul_overflow(buffer_rows_stride, buffer_rows_height, @@ -118,14 +118,14 @@ class MorphologyWorkspace final { workspace->channels_ = channels; auto *buffer_rows_address = &workspace->data_[indirect_row_storage_size]; - buffer_rows_address = __builtin_align_up(buffer_rows_address, kAlignment); + buffer_rows_address = align_up(buffer_rows_address, kAlignment); workspace->buffer_rows_offset_ = buffer_rows_address - &workspace->data_[0]; workspace->buffer_rows_stride_ = buffer_rows_stride; auto *wide_rows_address = &workspace->data_[indirect_row_storage_size + buffer_rows_size]; wide_rows_address += margin.left() * channels; - wide_rows_address = __builtin_align_up(wide_rows_address, kAlignment); + wide_rows_address = align_up(wide_rows_address, kAlignment); wide_rows_address -= margin.left() * channels; workspace->wide_rows_offset_ = wide_rows_address - &workspace->data_[0]; workspace->wide_rows_stride_ = wide_rows_stride; diff --git a/intrinsiccv/include/intrinsiccv/neon_intrinsics.h b/intrinsiccv/include/intrinsiccv/neon_intrinsics.h index 0c8b6b5fa..bea4058a8 100644 --- a/intrinsiccv/include/intrinsiccv/neon_intrinsics.h +++ b/intrinsiccv/include/intrinsiccv/neon_intrinsics.h @@ -110,8 +110,8 @@ static inline int16x4_t vget_high(int16x8_t vec) { return vget_high_s16(vec); static inline uint16x4_t vget_high(uint16x8_t vec) { return vget_high_u16(vec); } static inline int32x2_t vget_high(int32x4_t vec) { return vget_high_s32(vec); } static inline uint32x2_t vget_high(uint32x4_t vec) { return vget_high_u32(vec); } -static inline int64x1_t vget_high(int64x2_t vec) { return vget_high_s32(vec); } -static inline uint64x1_t vget_high(uint64x2_t vec) { return vget_high_u32(vec); } +static inline int64x1_t vget_high(int64x2_t vec) { return vget_high_s64(vec); } +static inline uint64x1_t vget_high(uint64x2_t vec) { return vget_high_u64(vec); } // ----------------------------------------------------------------------------- // vget_low* @@ -123,8 +123,8 @@ static inline int16x4_t vget_low(int16x8_t vec) { return vget_low_s16(vec); } static inline uint16x4_t vget_low(uint16x8_t vec) { return vget_low_u16(vec); } static inline int32x2_t vget_low(int32x4_t vec) { return vget_low_s32(vec); } static inline uint32x2_t vget_low(uint32x4_t vec) { return vget_low_u32(vec); } -static inline int64x1_t vget_low(int64x2_t vec) { return vget_low_s32(vec); } -static inline uint64x1_t vget_low(uint64x2_t vec) { return vget_low_u32(vec); } +static inline int64x1_t vget_low(int64x2_t vec) { return vget_low_s64(vec); } +static inline uint64x1_t vget_low(uint64x2_t vec) { return vget_low_u64(vec); } // ----------------------------------------------------------------------------- // vminq* diff --git a/intrinsiccv/include/intrinsiccv/utils.h b/intrinsiccv/include/intrinsiccv/utils.h index c6d4652a9..54765279a 100644 --- a/intrinsiccv/include/intrinsiccv/utils.h +++ b/intrinsiccv/include/intrinsiccv/utils.h @@ -364,6 +364,21 @@ bool is_misaligned(Value v) INTRINSICCV_STREAMING_COMPATIBLE { return (v & kMask) != 0; } +// Return value aligned up to the next multiple of alignment +// Assumes alignment is a power of two. +template +T align_up(T value, size_t alignment) INTRINSICCV_STREAMING_COMPATIBLE { + return (value + alignment - 1) & ~(alignment - 1); +} + +template +T *align_up(T *value, size_t alignment) INTRINSICCV_STREAMING_COMPATIBLE { + // NOLINTBEGIN(performance-no-int-to-ptr) + return reinterpret_cast( + align_up(reinterpret_cast(value), alignment)); + // NOLINTEND(performance-no-int-to-ptr) +} + // Specialisation for when stride misalignment is possible. template std::enable_if_t check_pointer_and_stride( diff --git a/intrinsiccv/include/intrinsiccv/workspace/borders.h b/intrinsiccv/include/intrinsiccv/workspace/borders.h index 6b4b7c8e2..9f72b9c55 100644 --- a/intrinsiccv/include/intrinsiccv/workspace/borders.h +++ b/intrinsiccv/include/intrinsiccv/workspace/borders.h @@ -80,6 +80,9 @@ class FixedBorderInfo final { return get(1, 0, 1); break; } + // Unreachable. Compiler should emit a warning-as-error if any cases are + // uncovered above. + return Offsets{}; // GCOVR_EXCL_LINE } // Retuns offsets for columns affected by right border. @@ -99,6 +102,9 @@ class FixedBorderInfo final { return get(-1, 0, -1); break; } + // Unreachable. Compiler should emit a warning-as-error if any cases are + // uncovered above. + return Offsets{}; // GCOVR_EXCL_LINE } // Retuns offsets for rows or columns affected by any border. @@ -193,6 +199,9 @@ class FixedBorderInfo final { } break; } + // Unreachable. Compiler should emit a warning-as-error if any cases are + // uncovered above. + return Offsets{}; // GCOVR_EXCL_LINE } // Retuns offsets for columns affected by right border. @@ -231,6 +240,9 @@ class FixedBorderInfo final { } break; } + // Unreachable. Compiler should emit a warning-as-error if any cases are + // uncovered above. + return Offsets{}; // GCOVR_EXCL_LINE } // Retuns offsets for rows or columns affected by any border. diff --git a/intrinsiccv/include/intrinsiccv/workspace/separable.h b/intrinsiccv/include/intrinsiccv/workspace/separable.h index 4b7f80007..c26d082aa 100644 --- a/intrinsiccv/include/intrinsiccv/workspace/separable.h +++ b/intrinsiccv/include/intrinsiccv/workspace/separable.h @@ -106,7 +106,7 @@ class SeparableFilterWorkspace final { } auto *buffer_rows_address = &workspace->data_[0]; - buffer_rows_address = __builtin_align_up(buffer_rows_address, kAlignment); + buffer_rows_address = align_up(buffer_rows_address, kAlignment); workspace->buffer_rows_offset_ = buffer_rows_address - &workspace->data_[0]; workspace->buffer_rows_stride_ = buffer_rows_stride; workspace->image_size_ = rect; @@ -164,7 +164,9 @@ class SeparableFilterWorkspace final { typename FilterType::BorderInfoType horizontal_border) INTRINSICCV_STREAMING_COMPATIBLE { // Process data affected by left border. +#ifdef __clang__ // GCC is unable to unroll the loop INTRINSICCV_FORCE_LOOP_UNROLL +#endif for (size_t horizontal_index = 0; horizontal_index < margin.left(); ++horizontal_index) { auto offsets = @@ -184,7 +186,9 @@ class SeparableFilterWorkspace final { } // Process data affected by right border. +#ifdef __clang__ // GCC is unable to unroll the loop INTRINSICCV_FORCE_LOOP_UNROLL +#endif for (size_t horizontal_index = 0; horizontal_index < margin.right(); ++horizontal_index) { size_t index = width - margin.right() + horizontal_index; diff --git a/intrinsiccv/src/analysis/canny_neon.cpp b/intrinsiccv/src/analysis/canny_neon.cpp index a76bddecf..67fc5e045 100644 --- a/intrinsiccv/src/analysis/canny_neon.cpp +++ b/intrinsiccv/src/analysis/canny_neon.cpp @@ -24,8 +24,7 @@ class SobelBuffer final : public RowsOverUniquePtr { private: // Align the width up to an integral number of lanes in a vector. static Margin get_margin(Rectangle rect) { - size_t width = - __builtin_align_up(rect.width(), VecTraits::num_lanes()); + size_t width = align_up(rect.width(), VecTraits::num_lanes()); return Margin{0, 0, width - rect.width(), 0}; } }; // end of class SobelBuffer diff --git a/intrinsiccv/src/conversions/gray_to_rgb_sc.h b/intrinsiccv/src/conversions/gray_to_rgb_sc.h index 968da8cb6..b0aa59a8f 100644 --- a/intrinsiccv/src/conversions/gray_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/gray_to_rgb_sc.h @@ -77,9 +77,11 @@ class GrayToRGB final : indices_0 = svindex_u8(0, 1); if (INTRINSICCV_UNLIKELY(svcntb() == 256)) { - indices_1 = - svext(svdup_u8(0), svqadd(svindex_u8(svcntb() % 3, 1), 2), 254); - indices_2 = svext(svdup_u8(0), svqadd(svindex_u8(0, 1), 3), 255); + indices_1 = svext( + svdup_u8(0), + svqadd(svindex_u8(svcntb() % 3, 1), static_cast(2)), 254); + indices_2 = svext(svdup_u8(0), + svqadd(svindex_u8(0, 1), static_cast(3)), 255); } else { indices_1 = svindex_u8(svcntb() % 3, 1); indices_2 = svindex_u8((svcntb() * 2) % 3, 1); @@ -88,10 +90,10 @@ class GrayToRGB final : indices_0 = svlsr_x(pg_all, svmulh_x(pg_all, indices_0, const_171), 1); indices_1 = svqadd_x( pg_all, svlsr_x(pg_all, svmulh_x(pg_all, indices_1, const_171), 1), - svcntb() / 3); + static_cast(svcntb() / 3)); indices_2 = svqadd_x( pg_all, svlsr_x(pg_all, svmulh_x(pg_all, indices_2, const_171), 1), - (svcntb() * 2) / 3); + static_cast((svcntb() * 2) / 3)); indices_ = svcreate3(indices_0, indices_1, indices_2); } diff --git a/intrinsiccv/src/conversions/merge_neon.cpp b/intrinsiccv/src/conversions/merge_neon.cpp index 41402fbaf..19d995b9e 100644 --- a/intrinsiccv/src/conversions/merge_neon.cpp +++ b/intrinsiccv/src/conversions/merge_neon.cpp @@ -68,7 +68,7 @@ class Merge3 final : public UnrollTwice { using Vector3Type = typename VecTraits::Vector3Type; #if !INTRINSICCV_PREFER_INTERLEAVING_LOAD_STORE - Merge3() : table_indices_{vld1q_u8_x3(lookup_table())} {} + Merge3() : table_indices_{vld1q_u8_x3(lookup_table(ScalarType()))} {} #endif void vector_path(VectorType src_a, VectorType src_b, VectorType src_c, @@ -100,12 +100,7 @@ class Merge3 final : public UnrollTwice { private: #if !INTRINSICCV_PREFER_INTERLEAVING_LOAD_STORE - template - static const uint8_t *lookup_table(); - - // Lookup table for 8-bit inputs. - template <> - static const uint8_t *lookup_table() { + static const uint8_t *lookup_table(uint8_t) { // clang-format off static constexpr uint8_t kIndices[48] = { 0, 16, 32, 1, 17, 33, 2, 18, 34, 3, 19, 35, 4, 20, 36, 5, @@ -117,8 +112,7 @@ class Merge3 final : public UnrollTwice { } // Lookup table for 16-bit inputs. - template <> - static const uint8_t *lookup_table() { + static const uint8_t *lookup_table(uint16_t) { // clang-format off static constexpr uint8_t kIndices[48] = { 0, 1, 16, 17, 32, 33, 2, 3, 18, 19, 34, 35, 4, 5, 20, 21, diff --git a/intrinsiccv/src/conversions/split_neon.cpp b/intrinsiccv/src/conversions/split_neon.cpp index b0d7aeeec..9892266d4 100644 --- a/intrinsiccv/src/conversions/split_neon.cpp +++ b/intrinsiccv/src/conversions/split_neon.cpp @@ -58,7 +58,7 @@ class Split3 final : public UnrollTwice { #if !INTRINSICCV_PREFER_INTERLEAVING_LOAD_STORE // NOLINTBEGIN(hicpp-member-init) - Split3() { Split3Init(); } + Split3() { Split3Init(ScalarType()); } // NOLINTEND(hicpp-member-init) #endif @@ -94,11 +94,8 @@ class Split3 final : public UnrollTwice { private: #if !INTRINSICCV_PREFER_INTERLEAVING_LOAD_STORE uint8x16_t index1_, index2_, index3_; - template - void Split3Init() {} - template <> - void Split3Init() { + void Split3Init(uint8_t) { // clang-format off const uint8_t kIndices[3][16] = { {0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45}, @@ -111,8 +108,7 @@ class Split3 final : public UnrollTwice { index3_ = vld1q_u8(kIndices[2]); } - template <> - void Split3Init() { + void Split3Init(uint16_t) { // clang-format off const uint8_t kIndices[3][16] = { {0, 1, 6, 7, 12, 13, 18, 19, 24, 25, 30, 31, 36, 37, 42, 43}, @@ -125,8 +121,7 @@ class Split3 final : public UnrollTwice { index3_ = vld1q_u8(kIndices[2]); } - template <> - void Split3Init() { + void Split3Init(uint32_t) { // clang-format off const uint8_t kIndices[3][16] = { {0, 1, 2, 3, 12, 13, 14, 15, 24, 25, 26, 27, 36, 37, 38, 39}, @@ -139,8 +134,7 @@ class Split3 final : public UnrollTwice { index3_ = vld1q_u8(kIndices[2]); } - template <> - void Split3Init() { + void Split3Init(uint64_t) { // clang-format off const uint8_t kIndices[3][16] = { {0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 28, 29, 30, 31}, diff --git a/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp b/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp index 04861ee8c..be9c92b74 100644 --- a/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp +++ b/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp @@ -211,10 +211,7 @@ class YUVSpToRGBxOrBGRx final : public UnrollOnce { const uint8_t *y_rows[2] = {y_row_0, y_row_1}; uint8_t *rgbx_rows[2] = {rgbx_row_0, rgbx_row_1}; - // These are set near the start of the first loop. - // NOLINTBEGIN(cppcoreguidelines-init-variables) - int32_t u_m128, v_m128; - // NOLINTEND(cppcoreguidelines-init-variables) + int32_t u_m128 = 0, v_m128 = 0; for (size_t index = 0; index < length; ++index) { disable_loop_vectorization(); diff --git a/intrinsiccv/src/conversions/yuv_to_rgb_sc.h b/intrinsiccv/src/conversions/yuv_to_rgb_sc.h index aedfcc62a..0eb57330a 100644 --- a/intrinsiccv/src/conversions/yuv_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/yuv_to_rgb_sc.h @@ -46,7 +46,7 @@ class YUVSpToRGBxOrBGRx final { svuint8_t uv = svld1(pg, uv_row); // Y' = saturating(Ya - 16) and widen to signed 32-bits. - svuint8_t y0_m16 = svqsub(y0, 16); + svuint8_t y0_m16 = svqsub(y0, static_cast(16)); svuint16_t y0_m16_b = svmovlb(y0_m16); // 'b' means bottom svuint16_t y0_m16_t = svmovlt(y0_m16); // 't' means top svint32_t y0_m16_bb = svreinterpret_s32(svmovlb(y0_m16_b)); @@ -54,7 +54,7 @@ class YUVSpToRGBxOrBGRx final { svint32_t y0_m16_tb = svreinterpret_s32(svmovlb(y0_m16_t)); svint32_t y0_m16_tt = svreinterpret_s32(svmovlt(y0_m16_t)); - svuint8_t y1_m16 = svqsub(y1, 16); + svuint8_t y1_m16 = svqsub(y1, static_cast(16)); svuint16_t y1_m16_b = svmovlb(y1_m16); svuint16_t y1_m16_t = svmovlt(y1_m16); svint32_t y1_m16_bb = svreinterpret_s32(svmovlb(y1_m16_b)); diff --git a/scripts/ci.sh b/scripts/ci.sh index 6f940903f..ff8d0321f 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -41,22 +41,28 @@ echo '{"Checks": "-*,cppcoreguidelines-avoid-goto"}'>build/.clang-tidy ninja -C build +# Build with GCC +CC=gcc CXX=g++ cmake -S . -B build/gcc -G Ninja +ninja -C build/gcc + # Run tests LONG_VECTOR_TESTS="GRAY2.*:RGB*" TESTRESULT=0 qemu-aarch64 build/test/framework/intrinsiccv-framework-test --gtest_output=xml:build/test-results/ || TESTRESULT=1 -qemu-aarch64 -cpu cortex-a35 build/test/api/intrinsiccv-api-test --gtest_output=xml:build/test-results/neon/ || TESTRESULT=1 +qemu-aarch64 -cpu cortex-a35 build/test/api/intrinsiccv-api-test --gtest_output=xml:build/test-results/clang-neon/ || TESTRESULT=1 qemu-aarch64 -cpu max,sve128=on,sme=off \ - build/test/api/intrinsiccv-api-test --gtest_output=xml:build/test-results/sve128/ --vector-length=16 || TESTRESULT=1 + build/test/api/intrinsiccv-api-test --gtest_output=xml:build/test-results/clang-sve128/ --vector-length=16 || TESTRESULT=1 qemu-aarch64 -cpu max,sve2048=on,sve-default-vector-length=256,sme=off \ - build/test/api/intrinsiccv-api-test --gtest_filter="${LONG_VECTOR_TESTS}" --gtest_output=xml:build/test-results/sve2048/ --vector-length=256 || TESTRESULT=1 + build/test/api/intrinsiccv-api-test --gtest_filter="${LONG_VECTOR_TESTS}" --gtest_output=xml:build/test-results/clang-sve2048/ --vector-length=256 || TESTRESULT=1 qemu-aarch64 -cpu max,sve128=on,sme512=on \ - build/test/api/intrinsiccv-api-test --gtest_output=xml:build/test-results/sme/ --vector-length=64 || TESTRESULT=1 - -scripts/prefix_testsuite_names.py build/test-results/neon/intrinsiccv-api-test.xml "neon." -scripts/prefix_testsuite_names.py build/test-results/sve128/intrinsiccv-api-test.xml "sve128." -scripts/prefix_testsuite_names.py build/test-results/sve2048/intrinsiccv-api-test.xml "sve2048." -scripts/prefix_testsuite_names.py build/test-results/sme/intrinsiccv-api-test.xml "sme." + build/test/api/intrinsiccv-api-test --gtest_output=xml:build/test-results/clang-sme/ --vector-length=64 || TESTRESULT=1 +qemu-aarch64 -cpu cortex-a35 build/gcc/test/api/intrinsiccv-api-test --gtest_output=xml:build/test-results/gcc-neon/ || TESTRESULT=1 + +scripts/prefix_testsuite_names.py build/test-results/clang-neon/intrinsiccv-api-test.xml "clang-neon." +scripts/prefix_testsuite_names.py build/test-results/clang-sve128/intrinsiccv-api-test.xml "clang-sve128." +scripts/prefix_testsuite_names.py build/test-results/clang-sve2048/intrinsiccv-api-test.xml "clang-sve2048." +scripts/prefix_testsuite_names.py build/test-results/clang-sme/intrinsiccv-api-test.xml "clang-sme." +scripts/prefix_testsuite_names.py build/test-results/gcc-neon/intrinsiccv-api-test.xml "gcc-neon." # Generate test coverage report LLVM_COV=llvm-cov scripts/generate_coverage_report.py diff --git a/test/api/test_add_abs_with_threshold.cpp b/test/api/test_add_abs_with_threshold.cpp index a5f792d52..1246d6948 100644 --- a/test/api/test_add_abs_with_threshold.cpp +++ b/test/api/test_add_abs_with_threshold.cpp @@ -156,7 +156,7 @@ TYPED_TEST(SaturatingAddAbsWithThresholdTest, TestMax) { } TYPED_TEST(SaturatingAddAbsWithThresholdTest, NullPointer) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; test::test_null_args(intrinsiccv_saturating_add_abs_with_threshold_s16, src, sizeof(TypeParam), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 1); @@ -183,7 +183,7 @@ TYPED_TEST(SaturatingAddAbsWithThresholdTest, Misalignment) { } TYPED_TEST(SaturatingAddAbsWithThresholdTest, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, intrinsiccv_saturating_add_abs_with_threshold_s16( src, sizeof(TypeParam), src, sizeof(TypeParam), dst, diff --git a/test/api/test_count_nonzeros.cpp b/test/api/test_count_nonzeros.cpp index 077622777..f8063cc9f 100644 --- a/test/api/test_count_nonzeros.cpp +++ b/test/api/test_count_nonzeros.cpp @@ -71,8 +71,9 @@ class CountNonZerosTest { size_t expected = data_.calculateExpected(width, height); size_t actual = SIZE_MAX; - count_nonzeros()(source.data(), source.stride(), width, height, - &actual); + EXPECT_EQ(INTRINSICCV_OK, + count_nonzeros()(source.data(), source.stride(), + width, height, &actual)); EXPECT_EQ(expected, actual); } }; @@ -131,7 +132,7 @@ TYPED_TEST(CountNonZeros, Misalignment) { } TYPED_TEST(CountNonZeros, ImageSize) { - TypeParam src[1]; + TypeParam src[1] = {}; size_t count = 0; EXPECT_EQ( INTRINSICCV_ERROR_RANGE, diff --git a/test/api/test_min_max.cpp b/test/api/test_min_max.cpp index d44d5e974..91a7542d0 100644 --- a/test/api/test_min_max.cpp +++ b/test/api/test_min_max.cpp @@ -250,8 +250,9 @@ class MinMaxLocTest : public MinMaxTest { if (p_max_offset) { *p_max_offset = std::numeric_limits::max(); } - min_max_loc()(source.data(), source.stride(), width(), - height(), p_min_offset, p_max_offset); + EXPECT_EQ(INTRINSICCV_OK, min_max_loc()( + source.data(), source.stride(), width(), + height(), p_min_offset, p_max_offset)); if (p_min_offset) { EXPECT_EQ(*p_min_offset, expected_min_offset); } @@ -311,7 +312,7 @@ TYPED_TEST(MinMax, Misalignment) { } TYPED_TEST(MinMax, ImageSize) { - TypeParam src[1], min_value, max_value; + TypeParam src[1] = {}, min_value, max_value; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, min_max()(src, sizeof(TypeParam), INTRINSICCV_MAX_IMAGE_PIXELS + 1, 1, @@ -334,7 +335,7 @@ TYPED_TEST(MinMaxLoc, API) { } TYPED_TEST(MinMaxLoc, ImageSize) { - TypeParam src[1]; + TypeParam src[1] = {}; size_t min_offset = 0, max_offset = 8; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, diff --git a/test/api/test_saturating_absdiff.cpp b/test/api/test_saturating_absdiff.cpp index 54852878f..fa27a7670 100644 --- a/test/api/test_saturating_absdiff.cpp +++ b/test/api/test_saturating_absdiff.cpp @@ -108,7 +108,7 @@ TYPED_TEST(SaturatingAbsDiff, Misalignment) { // misalignment impossible return; } - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, saturating_absdiff()(src, sizeof(TypeParam) + 1, src, sizeof(TypeParam), dst, @@ -124,7 +124,7 @@ TYPED_TEST(SaturatingAbsDiff, Misalignment) { } TYPED_TEST(SaturatingAbsDiff, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, saturating_absdiff()( src, sizeof(TypeParam), src, sizeof(TypeParam), dst, diff --git a/test/api/test_saturating_add.cpp b/test/api/test_saturating_add.cpp index 74607e860..2964f7d10 100644 --- a/test/api/test_saturating_add.cpp +++ b/test/api/test_saturating_add.cpp @@ -116,7 +116,7 @@ TYPED_TEST(SaturatingAdd, Misalignment) { } TYPED_TEST(SaturatingAdd, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, saturating_add()( src, sizeof(TypeParam), src, sizeof(TypeParam), dst, diff --git a/test/api/test_saturating_multiply.cpp b/test/api/test_saturating_multiply.cpp index 6e3f33c59..8112f373b 100644 --- a/test/api/test_saturating_multiply.cpp +++ b/test/api/test_saturating_multiply.cpp @@ -108,7 +108,7 @@ TYPED_TEST(SaturatingMultiply, Misalignment) { // misalignment impossible return; } - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, saturating_multiply()(src, sizeof(TypeParam) + 1, src, sizeof(TypeParam), dst, @@ -124,7 +124,7 @@ TYPED_TEST(SaturatingMultiply, Misalignment) { } TYPED_TEST(SaturatingMultiply, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, saturating_multiply()( src, sizeof(TypeParam), src, sizeof(TypeParam), dst, diff --git a/test/api/test_saturating_sub.cpp b/test/api/test_saturating_sub.cpp index b60060a16..71737b99d 100644 --- a/test/api/test_saturating_sub.cpp +++ b/test/api/test_saturating_sub.cpp @@ -118,7 +118,7 @@ TYPED_TEST(SaturatingSub, Misalignment) { } TYPED_TEST(SaturatingSub, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, saturating_sub()( src, sizeof(TypeParam), src, sizeof(TypeParam), dst, diff --git a/test/api/test_scale.cpp b/test/api/test_scale.cpp index 9a4b85634..b1c0bef68 100644 --- a/test/api/test_scale.cpp +++ b/test/api/test_scale.cpp @@ -16,6 +16,7 @@ INTRINSICCV_SCALE(uint8_t, u8); template class ScaleTestBase : public UnaryOperationTest { + protected: using UnaryOperationTest::min; using UnaryOperationTest::max; @@ -46,6 +47,7 @@ class ScaleTestBase : public UnaryOperationTest { template class ScaleTestLinearBase { + protected: static constexpr ElementType min() { return std::numeric_limits::min(); } @@ -411,7 +413,7 @@ TYPED_TEST(ScaleTest, Misalignment) { } TYPED_TEST(ScaleTest, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, scale()(src, sizeof(TypeParam), dst, sizeof(TypeParam), INTRINSICCV_MAX_IMAGE_PIXELS + 1, 1, 2, 0)); diff --git a/test/api/test_sobel.cpp b/test/api/test_sobel.cpp index e0ac95b1a..53db4631a 100644 --- a/test/api/test_sobel.cpp +++ b/test/api/test_sobel.cpp @@ -43,9 +43,10 @@ static constexpr std::array kSupportedBorders = { // Test for Sobel 3x3 operator. template class Sobel3x3Test : public test::KernelTest { - using typename test::KernelTest::InputType; - using typename test::KernelTest::IntermediateType; - using typename test::KernelTest::OutputType; + using Base = test::KernelTest; + using typename Base::InputType; + using typename Base::IntermediateType; + using typename Base::OutputType; intrinsiccv_error_t call_api(const test::Array2D *input, test::Array2D *output, @@ -72,9 +73,8 @@ class Sobel3x3Test : public test::KernelTest { test::SequenceGenerator tested_borders{kSupportedBorders}; test::SequenceGenerator tested_border_values{kSupportedBorderValues}; test::PseudoRandomNumberGenerator element_generator; - this->test::KernelTest::test( - kernel, tested_array_layouts, tested_borders, tested_border_values, - element_generator); + Base::test(kernel, tested_array_layouts, tested_borders, + tested_border_values, element_generator); } }; // end of class Sobel3x3Test diff --git a/test/api/test_split.cpp b/test/api/test_split.cpp index 7d9f37393..af095db80 100644 --- a/test/api/test_split.cpp +++ b/test/api/test_split.cpp @@ -227,7 +227,7 @@ TYPED_TEST(Split, Misalignment) { TYPED_TEST(Split, ImageSize) { const size_t kChannels = 2; - TypeParam src[1], dst1[1], dst2[1]; + TypeParam src[1] = {}, dst1[1], dst2[1]; const size_t src_stride = kChannels * sizeof(TypeParam); void* dsts[kChannels] = {dst1, dst2}; size_t dst_strides[kChannels] = {sizeof(TypeParam), sizeof(TypeParam)}; diff --git a/test/api/test_threshold_binary.cpp b/test/api/test_threshold_binary.cpp index 42ef20532..f0d325aa7 100644 --- a/test/api/test_threshold_binary.cpp +++ b/test/api/test_threshold_binary.cpp @@ -14,10 +14,10 @@ INTRINSICCV_THRESHOLD_BINARY(uint8_t, u8); template class ThresholdBinaryTestBase : public UnaryOperationTest { + protected: // Needed to initialize value() using UnaryOperationTest::max; - protected: // Calls the API-under-test in the appropriate way. intrinsiccv_error_t call_api() override { return intrinsiccv_threshold_binary_u8( @@ -147,7 +147,7 @@ TYPED_TEST(ThresholdBinary, Misalignment) { } TYPED_TEST(ThresholdBinary, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, threshold_binary()( src, sizeof(TypeParam), dst, sizeof(TypeParam), diff --git a/test/api/test_transpose.cpp b/test/api/test_transpose.cpp index 2d3f9f312..1da53a059 100644 --- a/test/api/test_transpose.cpp +++ b/test/api/test_transpose.cpp @@ -224,7 +224,7 @@ TYPED_TEST(Transpose, Misalignment) { } TYPED_TEST(Transpose, ImageSize) { - TypeParam src[1], dst[1]; + TypeParam src[1] = {}, dst[1]; EXPECT_EQ(INTRINSICCV_ERROR_RANGE, intrinsiccv_transpose( src, sizeof(TypeParam), dst, sizeof(TypeParam), diff --git a/test/api/test_yuv_to_rgb.cpp b/test/api/test_yuv_to_rgb.cpp index a7854d8ec..8e0924a9f 100644 --- a/test/api/test_yuv_to_rgb.cpp +++ b/test/api/test_yuv_to_rgb.cpp @@ -7,6 +7,7 @@ #include "framework/array.h" #include "framework/utils.h" #include "intrinsiccv/intrinsiccv.h" +#include "intrinsiccv/utils.h" class YuvTest final { public: @@ -42,7 +43,7 @@ class YuvTest final { input_y.set(4, 0, {7, 11, 128, 129}); // the width of the UV input must be even - test::Array2D input_uv{__builtin_align_up(logical_width, 2), 3, + test::Array2D input_uv{intrinsiccv::align_up(logical_width, 2), 3, padding}; input_uv.set(0, 0, {100, 130, 255, 255}); input_uv.set(1, 0, {0, 1, 3, 4}); diff --git a/test/framework/utils.h b/test/framework/utils.h index 00492c5f9..438b23223 100644 --- a/test/framework/utils.h +++ b/test/framework/utils.h @@ -113,14 +113,12 @@ class NullPointerTester { template static void test(Function f, const Tuple &t) { // Recurse to test earlier arguments first - test(f, t); + if constexpr (ArgIndex > 0) { + test(f, t); + } using ArgType = typename std::tuple_element_t; test_with_null_arg(f, t); } - - // Terminate recursion - template <> - static void test<-1>(Function, const Tuple &) {} }; template -- GitLab