blob: d2dbffd18ea3ca008803d02f74764786542ba5c2 [file] [edit]
// This program tests the performance impact of vectorization in loops with
// small trip counts. These cases exercise the LoopVectorize path that accepts
// trip counts one larger than the vectorization factor.
#include <array>
#include <cstddef>
#include <cstdint>
#include "benchmark/benchmark.h"
#define NOINLINE __attribute__((noinline))
#define LOOP_VECTORIZE_ENABLE \
_Pragma("clang loop vectorize(enable) unroll(disable)")
#define LOOP_VECTORIZE_DISABLE \
_Pragma("clang loop vectorize(disable) interleave(disable) unroll(disable)")
#define LOOP_INTERLEAVE_COUNT_2 \
_Pragma("clang loop vectorize(enable) interleave_count(2) unroll(disable)")
template <typename Ty>
NOINLINE void loopTc5Vector(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (uint64_t I = 0; I != 5; ++I)
B[I] = A[I] + static_cast<Ty>(1);
}
template <typename Ty>
NOINLINE void loopTc5Scalar(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (uint64_t I = 0; I != 5; ++I)
B[I] = A[I] + static_cast<Ty>(1);
}
template <typename Ty>
NOINLINE void loopTc5I64InterleaveCount2Vector(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_INTERLEAVE_COUNT_2
for (uint64_t I = 0; I != 5; ++I)
B[I] = A[I] + static_cast<Ty>(1);
}
template <typename Ty>
NOINLINE void loopTc5ScalarizedDivVector(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (uint64_t I = 0; I != 5; ++I) {
Ty Den = (A[I] & static_cast<Ty>(15)) + static_cast<Ty>(1);
B[I] = (A[I] * static_cast<Ty>(13)) / Den;
}
}
template <typename Ty>
NOINLINE void loopTc5ScalarizedDivScalar(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (uint64_t I = 0; I != 5; ++I) {
Ty Den = (A[I] & static_cast<Ty>(15)) + static_cast<Ty>(1);
B[I] = (A[I] * static_cast<Ty>(13)) / Den;
}
}
template <typename Ty>
NOINLINE void loopTc3Vector(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (uint64_t I = 0; I != 3; ++I)
B[I] = A[I] + static_cast<Ty>(1);
}
template <typename Ty>
NOINLINE void loopTc3Scalar(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (uint64_t I = 0; I != 3; ++I)
B[I] = A[I] + static_cast<Ty>(1);
}
template <typename Ty>
NOINLINE void loopTc3I64InterleaveCount2Vector(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_INTERLEAVE_COUNT_2
for (uint64_t I = 0; I != 3; ++I)
B[I] = A[I] + static_cast<Ty>(1);
}
template <typename Ty>
NOINLINE void loopTc3SelectionVector(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (int i = 0; i < 3; i++) {
B[i] = B[i] < A[i] ? B[i] : A[i];
}
}
template <typename Ty>
NOINLINE void loopTc3SelectionScalar(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (int i = 0; i < 3; i++) {
B[i] = B[i] < A[i] ? B[i] : A[i];
}
}
template <typename Ty>
NOINLINE void loopTc5SelectionVector(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (int i = 0; i < 5; i++) {
B[i] = B[i] < A[i] ? B[i] : A[i];
}
}
template <typename Ty>
NOINLINE void loopTc5SelectionScalar(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (int i = 0; i < 5; i++) {
B[i] = B[i] < A[i] ? B[i] : A[i];
}
}
template <typename Ty>
NOINLINE void loopTc3BitwiseXOrVector(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (int i = 0; i < 3; i++) {
B[i] ^= A[i];
}
}
template <typename Ty>
NOINLINE void loopTc3BitwiseXOrScalar(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (int i = 0; i < 3; i++) {
B[i] ^= A[i];
}
}
template <typename Ty>
NOINLINE void loopTc5BitwiseXOrVector(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (int i = 0; i < 5; i++) {
B[i] ^= A[i];
}
}
template <typename Ty>
NOINLINE void loopTc5BitwiseXOrScalar(const Ty *__restrict A,
Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (int i = 0; i < 5; i++) {
B[i] ^= A[i];
}
}
template <typename Ty>
NOINLINE void loopTc5ModulusVector(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_ENABLE
for (int i = 0; i < 5; i++) {
B[i] %= (A[i] | 1);
}
}
template <typename Ty>
NOINLINE void loopTc5ModulusScalar(const Ty *__restrict A, Ty *__restrict B) {
LOOP_VECTORIZE_DISABLE
for (int i = 0; i < 5; i++) {
B[i] %= (A[i] | 1);
}
}
template <typename Ty> using KernelFn = void (*)(const Ty *, Ty *);
template <typename Ty> static void initData(std::array<Ty, 16> &A) {
for (size_t I = 0; I != A.size(); ++I)
A[I] = static_cast<Ty>(0x0102030405060708ULL + I);
}
template <typename Ty>
static void runBenchForSmallLoopTripCount(benchmark::State &State,
KernelFn<Ty> Fn) {
std::array<Ty, 16> A;
std::array<Ty, 16> B = {};
initData(A);
for (auto _ : State) {
benchmark::DoNotOptimize(A.data());
benchmark::DoNotOptimize(B.data());
Fn(A.data(), B.data());
benchmark::ClobberMemory();
}
}
template <typename Ty> void benchTc5Vector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5Vector<Ty>);
}
template <typename Ty> void benchTc5Scalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5Scalar<Ty>);
}
template <typename Ty>
void benchTc5I64InterleaveCount2Vector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State,
loopTc5I64InterleaveCount2Vector<Ty>);
}
template <typename Ty>
void benchTc5ScalarizedDivVector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5ScalarizedDivVector<Ty>);
}
template <typename Ty>
void benchTc5ScalarizedDivScalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5ScalarizedDivScalar<Ty>);
}
template <typename Ty> void benchTc3Vector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc3Vector<Ty>);
}
template <typename Ty> void benchTc3Scalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc3Scalar<Ty>);
}
template <typename Ty>
void benchTc3I64InterleaveCount2Vector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State,
loopTc3I64InterleaveCount2Vector<Ty>);
}
template <typename Ty>
void benchloopTc3SelectionVector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc3SelectionVector<Ty>);
}
template <typename Ty>
void benchloopTc3SelectionScalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc3SelectionScalar<Ty>);
}
template <typename Ty>
void benchloopTc5SelectionVector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5SelectionVector<Ty>);
}
template <typename Ty>
void benchloopTc5SelectionScalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5SelectionScalar<Ty>);
}
template <typename Ty>
void benchloopTC3BitwiseXOrVector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc3BitwiseXOrVector<Ty>);
}
template <typename Ty>
void benchloopTC3BitwiseXOrScalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc3BitwiseXOrScalar<Ty>);
}
template <typename Ty>
void benchloopTC5BitwiseXOrVector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5BitwiseXOrVector<Ty>);
}
template <typename Ty>
void benchloopTC5BitwiseXOrScalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5BitwiseXOrScalar<Ty>);
}
template <typename Ty> void benchloopTc5ModulusVector(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5ModulusVector<Ty>);
}
template <typename Ty> void benchloopTc5ModulusScalar(benchmark::State &State) {
runBenchForSmallLoopTripCount<Ty>(State, loopTc5ModulusScalar<Ty>);
}
BENCHMARK_TEMPLATE(benchTc5Vector, uint8_t)->Name("tc5/i8/vector");
BENCHMARK_TEMPLATE(benchTc5Scalar, uint8_t)->Name("tc5/i8/scalar");
BENCHMARK_TEMPLATE(benchTc5Vector, uint16_t)->Name("tc5/i16/vector");
BENCHMARK_TEMPLATE(benchTc5Scalar, uint16_t)->Name("tc5/i16/scalar");
BENCHMARK_TEMPLATE(benchTc5Vector, uint32_t)->Name("tc5/i32/vector");
BENCHMARK_TEMPLATE(benchTc5Scalar, uint32_t)->Name("tc5/i32/scalar");
BENCHMARK_TEMPLATE(benchTc5Vector, uint64_t)->Name("tc5/i64/vector");
BENCHMARK_TEMPLATE(benchTc5Scalar, uint64_t)->Name("tc5/i64/scalar");
BENCHMARK_TEMPLATE(benchTc5I64InterleaveCount2Vector, uint64_t)
->Name("tc5/i64/ic2/vector");
BENCHMARK_TEMPLATE(benchTc5ScalarizedDivVector, uint64_t)
->Name("tc5/i64/scalarized-div/vector");
BENCHMARK_TEMPLATE(benchTc5ScalarizedDivScalar, uint64_t)
->Name("tc5/i64/scalarized-div/scalar");
BENCHMARK_TEMPLATE(benchTc3Vector, uint8_t)->Name("tc3/i8/vector");
BENCHMARK_TEMPLATE(benchTc3Scalar, uint8_t)->Name("tc3/i8/scalar");
BENCHMARK_TEMPLATE(benchTc3Vector, uint16_t)->Name("tc3/i16/vector");
BENCHMARK_TEMPLATE(benchTc3Scalar, uint16_t)->Name("tc3/i16/scalar");
BENCHMARK_TEMPLATE(benchTc3Vector, uint32_t)->Name("tc3/i32/vector");
BENCHMARK_TEMPLATE(benchTc3Scalar, uint32_t)->Name("tc3/i32/scalar");
BENCHMARK_TEMPLATE(benchTc3Vector, uint64_t)->Name("tc3/i64/vector");
BENCHMARK_TEMPLATE(benchTc3Scalar, uint64_t)->Name("tc3/i64/scalar");
BENCHMARK_TEMPLATE(benchTc3I64InterleaveCount2Vector, uint64_t)
->Name("tc3/i64/ic2/vector");
BENCHMARK_TEMPLATE(benchloopTc3SelectionVector, int8_t)
->Name("tc3Selection/i8/vector");
BENCHMARK_TEMPLATE(benchloopTc3SelectionScalar, int8_t)
->Name("tc3Selection/i8/scalar");
BENCHMARK_TEMPLATE(benchloopTc3SelectionVector, int16_t)
->Name("tc3Selection/i16/vector");
BENCHMARK_TEMPLATE(benchloopTc3SelectionScalar, int16_t)
->Name("tc3Selection/i16/scalar");
BENCHMARK_TEMPLATE(benchloopTc5SelectionVector, int8_t)
->Name("tc5Selection/i8/vector");
BENCHMARK_TEMPLATE(benchloopTc5SelectionScalar, int8_t)
->Name("tc5Selection/i8/scalar");
BENCHMARK_TEMPLATE(benchloopTc5SelectionVector, int16_t)
->Name("tc5Selection/i16/vector");
BENCHMARK_TEMPLATE(benchloopTc5SelectionScalar, int16_t)
->Name("tc5Selection/i16/scalar");
BENCHMARK_TEMPLATE(benchloopTC3BitwiseXOrVector, int8_t)
->Name("tc3BitwideXor/i8/vector");
BENCHMARK_TEMPLATE(benchloopTC3BitwiseXOrScalar, int8_t)
->Name("tc3BitwideXor/i8/scalar");
BENCHMARK_TEMPLATE(benchloopTC3BitwiseXOrVector, int16_t)
->Name("tc3BitwideXor/i16/vector");
BENCHMARK_TEMPLATE(benchloopTC3BitwiseXOrScalar, int16_t)
->Name("tc3BitwideXor/i16/scalar");
BENCHMARK_TEMPLATE(benchloopTC5BitwiseXOrVector, int8_t)
->Name("tc5BitwideXor/i8/vector");
BENCHMARK_TEMPLATE(benchloopTC5BitwiseXOrScalar, int8_t)
->Name("tc5BitwideXor/i8/scalar");
BENCHMARK_TEMPLATE(benchloopTC5BitwiseXOrVector, int16_t)
->Name("tc5BitwideXor/i16/vector");
BENCHMARK_TEMPLATE(benchloopTC5BitwiseXOrScalar, int16_t)
->Name("tc5BitwideXor/i16/scalar");
BENCHMARK_TEMPLATE(benchloopTc5ModulusVector, int32_t)
->Name("tc5Modulus/i32/vector");
BENCHMARK_TEMPLATE(benchloopTc5ModulusScalar, int32_t)
->Name("tc5Modulus/i32/scalar");