Skip to content

Commit b349e09

Browse files
committed
[UnitTests] Add initial set of dedicated early-exit unit tests.
Adds initial unit tests for early-exit vectorization covering a variation of auto-vectorization and forced interleaving with pragmas. The interleaving variant is currently mis-compiled and needs * llvm/llvm-project#145340 * llvm/llvm-project#145394. We should probably extend the tests to make sure we cover various other scenarios, including returning the loaded element for the early exit, different index types and array sizes.
1 parent ff244c4 commit b349e09

File tree

2 files changed

+111
-0
lines changed

2 files changed

+111
-0
lines changed

SingleSource/UnitTests/Vectorizer/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
2+
# Enable matrix types extension tests for compilers supporting -fenable-matrix.
3+
check_c_compiler_flag("-mllvm -enable-early-exit-vectorization" COMPILER_HAS_EE_VEC_FLAG)
4+
if (COMPILER_HAS_EE_VEC_FLAG)
5+
set_property(SOURCE early-exit.cpp PROPERTY COMPILE_FLAGS "-mllvm -enable-early-exit-vectorization")
6+
else()
7+
list(REMOVE_ITEM Source early-exit.cpp)
8+
endif()
9+
110
llvm_singlesource()
211
set_property(TARGET runtime-checks PROPERTY CXX_STANDARD 17)
312

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#include <algorithm>
2+
#include <functional>
3+
#include <iostream>
4+
#include <limits>
5+
#include <stdint.h>
6+
7+
#define N 512
8+
9+
template <typename Ty>
10+
using TestFnTy = std::function<unsigned(std::function<void(Ty *)>)>;
11+
12+
template <typename Ty>
13+
static void checkVectorFunction(TestFnTy<Ty> ScalarFn, TestFnTy<Ty> VectorFn,
14+
TestFnTy<Ty> InterleavedFn, const char *Name) {
15+
std::cout << "Checking " << Name << "\n";
16+
17+
std::array Tests = {std::make_pair(VectorFn, "autovec"),
18+
std::make_pair(InterleavedFn, "interleave-forced")};
19+
20+
// Check finding the target element at all indices between 0 and 512.
21+
for (unsigned IdxToFind = 0; IdxToFind < 512; ++IdxToFind) {
22+
// Labmda to initialize all array elements to one, except the one to look for to zero.
23+
auto Init1 = [IdxToFind](int * Arr) {
24+
std::fill_n(Arr, N, 1);
25+
if (IdxToFind < N)
26+
Arr[IdxToFind] = 0;
27+
};
28+
29+
// Labmda to initialize all array elements to one, except the one to look for and the IdxToFind + 3 to zero.
30+
auto Init2 = [IdxToFind](int * Arr) {
31+
std::fill_n(Arr, N, 1);
32+
if (IdxToFind < N)
33+
Arr[IdxToFind] = 0;
34+
if (IdxToFind+3 < N)
35+
Arr[IdxToFind+3] = 0;
36+
};
37+
38+
auto Reference1 = ScalarFn(Init1);
39+
auto Reference2 = ScalarFn(Init2);
40+
// Run vector functions and check against the scalar result.
41+
for (const auto &[Fn, Name] : Tests) {
42+
auto ToCheck1 = Fn(Init1);
43+
if (Reference1 != ToCheck1) {
44+
std::cerr << "Miscompare for " << Name << ": " << Reference1
45+
<< " != " << ToCheck1 << "\n";
46+
exit(1);
47+
}
48+
auto ToCheck2 = Fn(Init2);
49+
if (Reference2 != ToCheck2) {
50+
std::cerr << "Miscompare for " << Name << ": " << Reference1
51+
<< " != " << ToCheck2 << "\n";
52+
exit(1);
53+
}
54+
}
55+
}
56+
}
57+
58+
/// Define 3 test functions
59+
/// * one with vectorization and interleaving disabled,
60+
/// * one with auto-vectorization w/o any pargmas
61+
/// * one where VF is picked automatically and interleaving is forced.
62+
#define DEFINE_SCALAR_AND_VECTOR_EARLY_EXIT(Init, Src, Loop) \
63+
auto ScalarFn = [](std::function<void(int *)> II) -> unsigned { \
64+
Init II(Src); \
65+
_Pragma("clang loop vectorize(disable) interleave_count(1)") Loop \
66+
}; \
67+
auto VectorFn = [](std::function<void(int *)> II) -> unsigned { \
68+
Init II(Src); \
69+
_Pragma("clang loop vectorize(enable)") Loop \
70+
}; \
71+
auto InterleavedFn = \
72+
[](std::function<void(int *)> II) -> unsigned { \
73+
Init II(Src); \
74+
_Pragma("clang loop vectorize(enable) interleave_count(4)") Loop \
75+
};
76+
77+
int main(void) {
78+
{
79+
DEFINE_SCALAR_AND_VECTOR_EARLY_EXIT(
80+
int A[N];, A,
81+
for (unsigned I = 0; I < N; I++) {
82+
if (A[I] == 0)
83+
return I;
84+
} return -1;);
85+
checkVectorFunction<int>(ScalarFn, VectorFn, InterleavedFn,
86+
"early_exit_find_step_1");
87+
}
88+
89+
{
90+
DEFINE_SCALAR_AND_VECTOR_EARLY_EXIT(
91+
int A[N];
92+
unsigned J = 2;, A,
93+
for (unsigned I = 0; I < N; I++) {
94+
if (A[I] == 0)
95+
return J;
96+
J += 3;
97+
} return -1;);
98+
checkVectorFunction<int>(ScalarFn, VectorFn, InterleavedFn,
99+
"early_exit_find_step_3");
100+
}
101+
return 0;
102+
}

0 commit comments

Comments
 (0)