blob: 31110bea27141bb4423c354e927e5b1277c8b065 [file] [log] [blame]
// This program tests vectorized truncates & zero-extends for performance and
// correctness
#include <iostream>
#include <memory>
#include <random>
#include "benchmark/benchmark.h"
#define ITERATIONS 10000
static std::mt19937 rng;
// Initialize array A with random numbers.
template <typename Ty>
static void init_data(const std::unique_ptr<Ty[]> &A, unsigned N) {
std::uniform_int_distribution<Ty> distrib(std::numeric_limits<Ty>::min(),
std::numeric_limits<Ty>::max());
for (unsigned I = 0; I < N; I++)
A[I] = distrib(rng);
}
// Truncate/Zero-extend elements to create expected results with no
// vectorization
template <typename Ty1, typename Ty2>
static void truncOrZextWithNoVec(const Ty1 *A, Ty2 *B, int Iterations) {
#pragma clang loop vectorize(disable)
for (unsigned I = 0; I < Iterations; I++) {
B[I] = A[I];
}
}
// Truncate/Zero-extend each vector element in a vectorized loop with vectorization width 8
template <typename Ty1, typename Ty2>
static void truncOrZextVecInLoopWithVW8(const Ty1 *A, Ty2 *B, int Iterations) {
#pragma clang loop vectorize_width(8) interleave_count(4)
for (unsigned I = 0; I < Iterations; I++) {
B[I] = A[I];
}
}
// Truncate/Zero-extend each vector element in a vectorized loop with
// vectorization width 16
template <typename Ty1, typename Ty2>
static void truncOrZextVecInLoopWithVW16(const Ty1 *A, Ty2 *B, int Iterations) {
#pragma clang loop vectorize_width(16) interleave_count(4)
for (unsigned I = 0; I < Iterations; I++) {
B[I] = A[I];
}
}
// Truncate/Zero-extend each vector element in a vectorized loop
template <typename Ty1, typename Ty2>
static void truncOrZextVecInLoop(const Ty1 *A, Ty2 *B, int Iterations) {
#pragma clang loop vectorize(enable)
for (unsigned I = 0; I < Iterations; I++) {
B[I] = A[I];
}
}
// Truncate/Zero-extend each vector element while adding in a vectorized loop
// with vectorization width 8
template <typename Ty1, typename Ty2>
static void truncOrZextVecWithAddInLoopWithVW8(const Ty1 *A, Ty2 *B,
int Iterations) {
#pragma clang loop vectorize_width(8) interleave_count(4)
for (unsigned I = 0; I < Iterations; I++) {
B[I] += A[I];
}
}
// Truncate/Zero-extend each vector element while adding in a vectorized loop
// vectorization width 16
template <typename Ty1, typename Ty2>
static void truncOrZextVecWithAddInLoopWithVW16(const Ty1 *A, Ty2 *B,
int Iterations) {
#pragma clang loop vectorize_width(16) interleave_count(4)
for (unsigned I = 0; I < Iterations; I++) {
B[I] += A[I];
}
}
// Truncate/Zero-extend each vector element while adding in a vectorized loop
template <typename Ty1, typename Ty2>
static void truncOrZextVecWithAddInLoop(const Ty1 *A, Ty2 *B, int Iterations) {
#pragma clang loop vectorize(enable)
for (unsigned I = 0; I < Iterations; I++) {
B[I] += A[I];
}
}
template <typename Ty1, typename Ty2>
static void __attribute__((always_inline))
benchForTruncOrZextVecInLoop(benchmark::State &state,
void (*Fn)(const Ty1 *, Ty2 *, int)) {
std::unique_ptr<Ty1[]> A(new Ty1[ITERATIONS]);
std::unique_ptr<Ty2[]> B(new Ty2[ITERATIONS]);
std::unique_ptr<Ty2[]> C(new Ty2[ITERATIONS]);
init_data(A, ITERATIONS);
// Check for correctness
truncOrZextWithNoVec(&A[0], &C[0], ITERATIONS);
Fn(&A[0], &B[0], ITERATIONS);
for (int I = 0; I < ITERATIONS; I++) {
if (B[I] != C[I]) {
std::cerr << "ERROR: Trunc or ZExt operation on " << A[I]
<< " is showing result " << B[I] << " instead of " << C[I]
<< "\n";
exit(1);
}
}
for (auto _ : state) {
benchmark::DoNotOptimize(B);
benchmark::ClobberMemory();
Fn(&A[0], &B[0], ITERATIONS);
}
}
template <typename Ty1, typename Ty2>
static void __attribute__((always_inline))
benchForTruncOrZextVecWithAddInLoop(benchmark::State &state,
void (*Fn)(const Ty1 *, Ty2 *, int)) {
std::unique_ptr<Ty1[]> A(new Ty1[ITERATIONS]);
std::unique_ptr<Ty2[]> B(new Ty2[ITERATIONS]);
std::unique_ptr<Ty2[]> C(new Ty2[ITERATIONS]);
init_data(A, ITERATIONS);
init_data(B, ITERATIONS);
for (auto _ : state) {
benchmark::DoNotOptimize(B);
benchmark::ClobberMemory();
Fn(&A[0], &B[0], ITERATIONS);
}
}
// Add vectorized truncate or zero-extend operation benchmarks for different element types
#define ADD_BENCHMARK(ty1, ty2) \
void benchForTruncOrZextVecInLoopWithVW8From_##ty1##_To_##ty2##_( \
benchmark::State &state) { \
benchForTruncOrZextVecInLoop<ty1, ty2>(state, \
&truncOrZextVecInLoopWithVW8); \
} \
BENCHMARK(benchForTruncOrZextVecInLoopWithVW8From_##ty1##_To_##ty2##_); \
void benchForTruncOrZextVecInLoopWithVW16From_##ty1##_To_##ty2##_( \
benchmark::State &state) { \
benchForTruncOrZextVecInLoop<ty1, ty2>(state, \
&truncOrZextVecInLoopWithVW16); \
} \
BENCHMARK(benchForTruncOrZextVecInLoopWithVW16From_##ty1##_To_##ty2##_); \
void benchForTruncOrZextVecInLoopFrom_##ty1##_To_##ty2##_( \
benchmark::State &state) { \
benchForTruncOrZextVecInLoop<ty1, ty2>(state, &truncOrZextVecInLoop); \
} \
BENCHMARK(benchForTruncOrZextVecInLoopFrom_##ty1##_To_##ty2##_); \
void benchForTruncOrZextVecWithAddInLoopWithVW8From_##ty1##_To_##ty2##_( \
benchmark::State &state) { \
benchForTruncOrZextVecWithAddInLoop<ty1, ty2>( \
state, &truncOrZextVecWithAddInLoopWithVW8); \
} \
BENCHMARK( \
benchForTruncOrZextVecWithAddInLoopWithVW8From_##ty1##_To_##ty2##_); \
void benchForTruncOrZextVecWithAddInLoopWithVW16From_##ty1##_To_##ty2##_( \
benchmark::State &state) { \
benchForTruncOrZextVecWithAddInLoop<ty1, ty2>( \
state, &truncOrZextVecWithAddInLoopWithVW16); \
} \
BENCHMARK( \
benchForTruncOrZextVecWithAddInLoopWithVW16From_##ty1##_To_##ty2##_); \
void benchForTruncOrZextVecWithAddInLoopFrom_##ty1##_To_##ty2##_( \
benchmark::State &state) { \
benchForTruncOrZextVecWithAddInLoop<ty1, ty2>( \
state, &truncOrZextVecWithAddInLoop); \
} \
BENCHMARK(benchForTruncOrZextVecWithAddInLoopFrom_##ty1##_To_##ty2##_);
/* Vectorized truncate operations */
ADD_BENCHMARK(uint16_t, uint8_t)
ADD_BENCHMARK(uint32_t, uint8_t)
ADD_BENCHMARK(uint64_t, uint8_t)
ADD_BENCHMARK(uint32_t, uint16_t)
ADD_BENCHMARK(uint64_t, uint16_t)
ADD_BENCHMARK(uint64_t, uint32_t)
/* Vectorized zero extend operations */
ADD_BENCHMARK(uint8_t, uint16_t)
ADD_BENCHMARK(uint8_t, uint32_t)
ADD_BENCHMARK(uint8_t, uint64_t)
ADD_BENCHMARK(uint16_t, uint32_t)
ADD_BENCHMARK(uint16_t, uint64_t)
ADD_BENCHMARK(uint32_t, uint64_t)