diff --git a/intrinsiccv/CMakeLists.txt b/intrinsiccv/CMakeLists.txt index 31d3b1c8eaee93b7a8b884ddcca85dd3afa5548e..553f13acfd158eab75b7839649036f4829e518f9 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 a842fdfff12ae45ccd445cd7a22e6a11b991584d..a92ddfc1a6fa460b8b41a1704f9b5dfd24e52739 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 3132c9054c865938b425bd9396bc9e8c880c555b..460fa7fe0f6081006fc8b788b7ec7565b9a2ca3d 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 0c8b6b5fa2e9f6edd1c0e037f3d6f32d38393af4..bea4058a80364fedf0c5fa2e10ddd8ade722873d 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 c6d4652a9fc80f35eb587ffbdd3a8c639ae162c8..54765279a072bcf2803934ce089f45eff9ea5131 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 6b4b7c8e238bf38037180f7d02b69f1e7c04e50d..9f72b9c5569017f37c9afbf498ffa9cad8d23c1a 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 4b7f80007f93312a20eb63d644d8e912e6a58491..c26d082aaf3c36c8e3fc188e0904a5e7f414c0c8 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 a76bddecf81042483edfce14b20cfb2e14a5b4ad..67fc5e045984de5746d1decfdbab92f090b88178 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 968da8cb69c04ed81b29ed65cad63f3b7e7b7585..b0aa59a8fd47498bf71ab61fe040ea96f4a43483 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 41402fbaf4d222fb32ee470e623d2b3a4582f461..19d995b9e2fc8efa45003d6797bdb79dd5529c94 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 b0d7aeeeced349760a0045df178c4b611403c415..9892266d4b95e47439c1bc66ed71ad7f4154866b 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 04861ee8c5e78bb048cb740eca63fe5ab088862b..be9c92b7411619c920a64e9ab709dbc76d056800 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 aedfcc62aeb88071ee0578911a46ba1593ba1a34..0eb57330a65c8be40916f45c3cdc437d178d6cdd 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 6f940903fa37f52f86e2b7386da0f95610e45fd3..ff8d0321f3debed39f4e6f5ad49ed55c3b7fe86b 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 a5f792d520422eaf22415290ba58bdfd7ae81b3c..1246d694893d8d19fff93f564e490fe3c0ec6623 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 077622777ef70e4fd5843fab2b287ebaad327d35..f8063cc9fcbdf10f200d87a82265fd3fe5eb8964 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 d44d5e97421e917f092ffbd326dc3386946d8e9f..91a7542d06ed748ea6a35e5b4e21b11f4174480c 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 54852878f9ebe44be4129ada9b927c574e995831..fa27a7670f3d5a9031843f0cf42016a138cdf91f 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 74607e8607261f4f9a5274eb0a8c05d91e0d32ab..2964f7d101a413e48135077f63a329344e4b5e9f 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 6e3f33c5927dd14739d38eb0737c3f667b091bea..8112f373ba532cd5aa72fa19bbc337754945d975 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 b60060a16246267c71fadebdc5021d8c346ac70b..71737b99d3d643499763651462a0876f08d50db1 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 9a4b85634c78eb9680caa2de6fe78d3e54c9143a..b1c0bef687a637fbb39aa1bbd52c67c25b790e29 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 e0ac95b1a3db63cc169fe27134add6fe3564a867..53db4631a019e0bffcb41fefeff959ed5f8f38fe 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 7d9f37393adba8e62da063264a553f8c0c0924be..af095db80709557ae29113cc698480f1c71b4006 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 42ef20532f457844973064e6810ceca2712c325d..f0d325aa792658e72ea33528b5cd5eaf62ac56b0 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 2d3f9f3129b5f753476427faafc06c88ec796fc8..1da53a05966a0e9670659f08b8b8468f0eaa4787 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 a7854d8eccf7e82e21ee2cb2e24cfd7e2888c717..8e0924a9f1349772bc933eab6b283f81a27446a8 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 00492c5f986bde85ef40c558005076fc450d46db..438b23223cf1c43eaa0c63038d365f35f13ecb3d 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