diff --git a/SingleSource/UnitTests/Vectorizer/common.h b/SingleSource/UnitTests/Vectorizer/common.h --- a/SingleSource/UnitTests/Vectorizer/common.h +++ b/SingleSource/UnitTests/Vectorizer/common.h @@ -1,5 +1,6 @@ #include #include +#include #define DEFINE_SCALAR_AND_VECTOR_FN2(Init, Loop) \ auto ScalarFn = [](auto *A, auto *B, unsigned TC) { \ @@ -17,17 +18,46 @@ _Pragma("clang loop vectorize(enable)") Loop \ }; +#define DEFINE_SCALAR_AND_VECTOR_FN4(Init, Loop) \ + auto ScalarFn = [](auto *cond0, auto *cond1, auto *data0, auto *data1, \ + unsigned N) { \ + Init _Pragma("clang loop vectorize(disable)") Loop \ + }; \ + auto VectorFn = [](auto *cond0, auto *cond1, auto *data0, auto *data1, \ + unsigned N) { \ + Init _Pragma("clang loop vectorize(enable)") Loop \ + }; + + static std::mt19937 rng; -// Initialize arrays A with random numbers. -template -static void init_data(const std::unique_ptr &A, unsigned N) { +// Initialize arrays A with random integers. +template ::value, bool> = true> +static void init_data(const std::unique_ptr &A, unsigned N) { std::uniform_int_distribution distrib( - std::numeric_limits::min(), std::numeric_limits::max()); + std::numeric_limits::min(), std::numeric_limits::max()); + for (unsigned i = 0; i < N; i++) + A[i] = distrib(rng); +} + +// Initialize arrays A with random floating points. +template ::value, bool> = true> +static void init_data(const std::unique_ptr &A, unsigned N) { + std::uniform_real_distribution distrib( + std::numeric_limits::min(), std::numeric_limits::max()); for (unsigned i = 0; i < N; i++) A[i] = distrib(rng); } +// Initialize arrays A with random booleans. +static void init_cond(const std::unique_ptr &A, unsigned N) { + std::uniform_int_distribution distrib(0, 1); + for (unsigned i = 0; i < N; i++) + A[i] = !!distrib(rng); +} + template static void check(const std::unique_ptr &Reference, const std::unique_ptr &Tmp, unsigned NumElements) { @@ -36,3 +66,11 @@ exit(1); } } + +template +static void check(const Ty Reference, const Ty ToCheck, unsigned NumElements) { + if (Reference != ToCheck) { + std::cerr << "Miscompare\n"; + exit(1); + } +} diff --git a/SingleSource/UnitTests/Vectorizer/conditional_scalar_assignment.cpp b/SingleSource/UnitTests/Vectorizer/conditional_scalar_assignment.cpp new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Vectorizer/conditional_scalar_assignment.cpp @@ -0,0 +1,256 @@ +#include +#include +#include +#include +#include + +#include "common.h" + +template +using Fn4Ty = std::function; + +template +static void checkVectorFunction(Fn4Ty ScalarFn, Fn4Ty VectorFn, + const char *Name) { + std::cout << "Checking " << Name << "\n"; + + unsigned N = 1000; + std::unique_ptr Cond0(new bool[N]); + std::unique_ptr Cond1(new bool[N]); + std::unique_ptr Data0(new Ty[N]); + std::unique_ptr Data1(new Ty[N]); + init_cond(Cond0, N); + init_cond(Cond1, N); + init_data(Data0, N); + init_data(Data1, N); + + Ty Reference = ScalarFn(&Cond0[0], &Cond1[0], &Data0[0], &Data1[0], N); + Ty ToCheck = VectorFn(&Cond0[0], &Cond1[0], &Data0[0], &Data1[0], N); + check(Reference, ToCheck, N); +} + +int main(void) { + rng = std::mt19937(15); + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1;, + for (int i = 0; i < N; i++) { + if (i < data0[i]) + t = data0[i]; + } + return t;); + checkVectorFunction(ScalarFn, VectorFn, "simple_csa_int_select"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f;, + for (int i = 0; i < N; i++) { + if (0.0f < data0[i]) + t = data0[i]; + } + return t; // use t + ); + checkVectorFunction(ScalarFn, VectorFn, "simple_csa_float_select"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + } + return t; // use t + ); + checkVectorFunction(ScalarFn, VectorFn, "simple_csa_int"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + } + return t; // use t + ); + checkVectorFunction(ScalarFn, VectorFn, "simple_csa_float"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1; int s = -1;, + for (int i = 0; i < N; i++) { + if (i < data0[i]) + t = data0[i]; + if (i < data1[i]) + s = data1[i]; + } + return t | s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, + "csa_in_series_int_select"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f; float s = 1.0f;, + for (int i = 0; i < N; i++) { + if (0.0f < data0[i]) + t = data0[i]; + if (0.0f < data1[i]) + s = data1[i]; + } + return t + s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, + "csa_in_series_float_select"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1; int s = -1;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + if (cond1[i]) + s = data1[i]; + } + return t | s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, "csa_in_series_int"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f; float s = 1.0f;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + if (cond1[i]) + s = data1[i]; + } + return t + s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, "csa_in_series_float"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + if (cond1[i]) + t = data1[i]; + } + return t; // use t + ); + checkVectorFunction(ScalarFn, VectorFn, + "csa_in_series_same_scalar_int"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + if (cond1[i]) + t = data1[i]; + } + return t; // use t + ); + checkVectorFunction(ScalarFn, VectorFn, + "csa_in_series_same_scalar_float"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1; int s = -1;, + for (int i = 0; i < N; i++) { + if (cond0[i]) { + t = data0[i]; + s = data1[i]; + } + } + return t | s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, "csa_same_cond_int"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f; float s = 1.0f;, + for (int i = 0; i < N; i++) { + if (cond0[i]) { + t = data0[i]; + s = data1[i]; + } + } + return t + s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, "csa_same_cond_float"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + else if (cond1[i]) + t = data1[i]; + } + return t; // use t + ); + checkVectorFunction(ScalarFn, VectorFn, + "csa_else_if_same_scalar_int"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + else if (cond1[i]) + t = data1[i]; + } + return t; // use t + ); + checkVectorFunction(ScalarFn, VectorFn, + "csa_else_if_same_scalar_float"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + int t = -1; int s = -1;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + else if (cond1[i]) + s = data1[i]; + } + return t | s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, "csa_else_if_int"); + } + + { + DEFINE_SCALAR_AND_VECTOR_FN4( + float t = 1.0f; float s = 1.0f;, + for (int i = 0; i < N; i++) { + if (cond0[i]) + t = data0[i]; + else if (cond1[i]) + s = data1[i]; + } + return t + s; // use t and s + ); + checkVectorFunction(ScalarFn, VectorFn, "csa_else_if_float"); + } + return 0; +} diff --git a/SingleSource/UnitTests/Vectorizer/conditional_scalar_assignment.reference_output b/SingleSource/UnitTests/Vectorizer/conditional_scalar_assignment.reference_output new file mode 100644 --- /dev/null +++ b/SingleSource/UnitTests/Vectorizer/conditional_scalar_assignment.reference_output @@ -0,0 +1,17 @@ +Checking simple_csa_int_select +Checking simple_csa_float_select +Checking simple_csa_int +Checking simple_csa_float +Checking csa_in_series_int_select +Checking csa_in_series_float_select +Checking csa_in_series_int +Checking csa_in_series_float +Checking csa_in_series_same_scalar_int +Checking csa_in_series_same_scalar_float +Checking csa_same_cond_int +Checking csa_same_cond_float +Checking csa_else_if_same_scalar_int +Checking csa_else_if_same_scalar_float +Checking csa_else_if_int +Checking csa_else_if_float +exit 0