diff --git a/SingleSource/UnitTests/Vectorizer/common.h b/SingleSource/UnitTests/Vectorizer/common.h index fc7b850400a5..cd376c52144b 100644 --- a/SingleSource/UnitTests/Vectorizer/common.h +++ b/SingleSource/UnitTests/Vectorizer/common.h @@ -84,6 +84,14 @@ } \ }; +#define DEFINE_SCALAR_AND_VECTOR_FN4_PTR(Loop) \ + auto ScalarFn = [](auto *FirstA, auto *LastA, auto *FirstB, auto *LastB) { \ + _Pragma("clang loop vectorize(disable) interleave_count(1)") Loop \ + }; \ + auto VectorFn = [](auto *FirstA, auto *LastA, auto *FirstB, auto *LastB) { \ + _Pragma("clang loop vectorize(enable)") Loop \ + }; + static std::mt19937 rng; // Initialize arrays A with random numbers. diff --git a/SingleSource/UnitTests/Vectorizer/find-first-of.cpp b/SingleSource/UnitTests/Vectorizer/find-first-of.cpp new file mode 100644 index 000000000000..e634a232c816 --- /dev/null +++ b/SingleSource/UnitTests/Vectorizer/find-first-of.cpp @@ -0,0 +1,195 @@ + +#include +#include +#include +#include +#include + +#include "common.h" + +template +using Fn2Ty = std::function; +template +static void checkVectorFunction(Fn2Ty ScalarFn, Fn2Ty VectorFn, + const char *Name) { + std::cout << "Checking " << Name << "\n"; + + const unsigned A_n = 1000; + const unsigned B_n = 64; + std::unique_ptr A(new Ty[A_n]); + std::unique_ptr B(new Ty[B_n]); + init_data(A, A_n); + init_data(B, B_n); + + // Test VectorFn with different input data. + { + // Check with random inputs. + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } + + { + // Check with A < B for all elements. + for (unsigned i = 0; i < A_n; ++i) { + A[i] = std::numeric_limits::min(); + } + for (unsigned i = 0; i < B_n; ++i) { + B[i] = std::numeric_limits::max(); + } + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } + + { + // Check with no match -> should return sentinel. + for (unsigned i = 0; i < A_n; ++i) { + A[i] = std::numeric_limits::min(); + } + for (unsigned i = 0; i < B_n; ++i) { + B[i] = std::numeric_limits::max(); + } + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } + + { + // Check with all matching -> should return first element. + for (unsigned i = 0; i < A_n; ++i) { + A[i] = std::numeric_limits::min(); + } + for (unsigned i = 0; i < B_n; ++i) { + B[i] = std::numeric_limits::min(); + } + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } + + { + // Check with only first element of A matching first element of B. + for (unsigned i = 0; i < A_n; ++i) { + A[i] = std::numeric_limits::min(); + } + for (unsigned i = 0; i < B_n; ++i) { + B[i] = std::numeric_limits::max(); + } + A[0] = B[0] = std::numeric_limits::min() + 1; + + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } + + { + // Check with only first element of A matching last element of B. + for (unsigned i = 0; i < A_n; ++i) { + A[i] = std::numeric_limits::min(); + } + for (unsigned i = 0; i < B_n; ++i) { + B[i] = std::numeric_limits::max(); + } + A[0] = B[B_n - 1] = std::numeric_limits::min() + 1; + + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } + + { + // Check multiple matches, first at index 7. + for (unsigned i = 0; i < A_n; ++i) { + A[i] = std::numeric_limits::min(); + } + for (unsigned i = 0; i < B_n; ++i) { + B[i] = std::numeric_limits::max(); + } + A[7] = B[0] = std::numeric_limits::min() + 1; + A[19] = B[37] = std::numeric_limits::min() + 2; + A[450] = B[52] = std::numeric_limits::min() + 3; + + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } + + { + // Check multiple matches, first at A[0] matching B[N-1], second at A[1] + // matching B[0]. + for (unsigned i = 0; i < A_n; ++i) { + A[i] = std::numeric_limits::min(); + } + for (unsigned i = 0; i < B_n; ++i) { + B[i] = std::numeric_limits::max(); + } + A[0] = B[B_n - 1] = std::numeric_limits::min() + 1; + A[1] = B[0] = std::numeric_limits::min() + 2; + + auto Reference = ScalarFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + auto ToCheck = VectorFn(A.get(), A.get() + A_n, B.get(), B.get() + B_n); + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } + } +} + +int main() { + rng = std::mt19937(15); + +#define DEFINE_FIND_FIRST_OF_LOOP \ + for (; FirstA != LastA; ++FirstA) \ + for (auto *It = FirstB; It != LastB; ++It) \ + if (*FirstA == *It) \ + return FirstA; \ + return LastA; + + { + DEFINE_SCALAR_AND_VECTOR_FN4_PTR(DEFINE_FIND_FIRST_OF_LOOP); + + checkVectorFunction(ScalarFn, VectorFn, "find_first_of_u8"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4_PTR(DEFINE_FIND_FIRST_OF_LOOP); + + checkVectorFunction(ScalarFn, VectorFn, "find_first_of_u16"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4_PTR(DEFINE_FIND_FIRST_OF_LOOP); + + checkVectorFunction(ScalarFn, VectorFn, "find_first_of_u32"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4_PTR(DEFINE_FIND_FIRST_OF_LOOP); + + checkVectorFunction(ScalarFn, VectorFn, "find_first_of_u64"); + } + + return 0; +} diff --git a/SingleSource/UnitTests/Vectorizer/find-first-of.reference_output b/SingleSource/UnitTests/Vectorizer/find-first-of.reference_output new file mode 100644 index 000000000000..adb8992ff4c2 --- /dev/null +++ b/SingleSource/UnitTests/Vectorizer/find-first-of.reference_output @@ -0,0 +1,5 @@ +Checking find_first_of_u8 +Checking find_first_of_u16 +Checking find_first_of_u32 +Checking find_first_of_u64 +exit 0