Skip to content

Commit 28ae6ea

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 28ae6ea

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-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: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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
23+
// for to zero.
24+
auto Init1 = [IdxToFind](int *Arr) {
25+
std::fill_n(Arr, N, 1);
26+
if (IdxToFind < N)
27+
Arr[IdxToFind] = 0;
28+
};
29+
30+
// Labmda to initialize all array elements to one, except the one to look
31+
// for and the IdxToFind + 3 to zero.
32+
auto Init2 = [IdxToFind](int *Arr) {
33+
std::fill_n(Arr, N, 1);
34+
if (IdxToFind < N)
35+
Arr[IdxToFind] = 0;
36+
if (IdxToFind + 3 < N)
37+
Arr[IdxToFind + 3] = 0;
38+
};
39+
40+
auto Reference1 = ScalarFn(Init1);
41+
auto Reference2 = ScalarFn(Init2);
42+
// Run vector functions and check against the scalar result.
43+
for (const auto &[Fn, Name] : Tests) {
44+
auto ToCheck1 = Fn(Init1);
45+
if (Reference1 != ToCheck1) {
46+
std::cerr << "Miscompare for " << Name << ": " << Reference1
47+
<< " != " << ToCheck1 << "\n";
48+
exit(1);
49+
}
50+
auto ToCheck2 = Fn(Init2);
51+
if (Reference2 != ToCheck2) {
52+
std::cerr << "Miscompare for " << Name << ": " << Reference1
53+
<< " != " << ToCheck2 << "\n";
54+
exit(1);
55+
}
56+
}
57+
}
58+
}
59+
60+
/// Define 3 test functions
61+
/// * one with vectorization and interleaving disabled,
62+
/// * one with auto-vectorization w/o any pargmas
63+
/// * one where VF is picked automatically and interleaving is forced.
64+
#define DEFINE_SCALAR_AND_VECTOR_EARLY_EXIT(Init, Src, Loop) \
65+
auto ScalarFn = [](std::function<void(int *)> II) -> unsigned { \
66+
Init II(Src); \
67+
_Pragma("clang loop vectorize(disable) interleave_count(1)") Loop \
68+
}; \
69+
auto VectorFn = [](std::function<void(int *)> II) -> unsigned { \
70+
Init II(Src); \
71+
_Pragma("clang loop vectorize(enable)") Loop \
72+
}; \
73+
auto InterleavedFn = [](std::function<void(int *)> II) -> unsigned { \
74+
Init II(Src); \
75+
_Pragma("clang loop vectorize(enable) interleave_count(4)") Loop \
76+
};
77+
78+
int main(void) {
79+
{
80+
DEFINE_SCALAR_AND_VECTOR_EARLY_EXIT(
81+
int A[N];, A, 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]; unsigned J = 2;, A, for (unsigned I = 0; I < N; I++) {
92+
if (A[I] == 0)
93+
return J;
94+
J += 3;
95+
} return -1;);
96+
checkVectorFunction<int>(ScalarFn, VectorFn, InterleavedFn,
97+
"early_exit_find_step_3");
98+
}
99+
return 0;
100+
}

0 commit comments

Comments
 (0)