Project

General

Profile

« Previous | Next » 

Revision edd171a6

Added by David Sorber over 7 years ago

Adding packed single precision (aka "ps") intrinsic test. This includes
useful horizontal sum and horizontal min/max routines.

View differences:

software/misc/ps_test.cc
#include <iostream>
#include <x86intrin.h>
// Return horizontal sum for 128 bit packed float vector
float hsum_ps_sse3(__m128 val)
{
__m128 shuf = _mm_movehdup_ps(val); // broadcast elements 3,1 to 2,0
__m128 sums = _mm_add_ps(val, shuf);
shuf = _mm_movehl_ps(shuf, sums); // high half -> low half
sums = _mm_add_ss(sums, shuf);
return _mm_cvtss_f32(sums);
}
// Return horizontal sum for 256 bit packed float vector
// https://stackoverflow.com/a/35270026/73878 -- Peter Cordes is da man
float hsum256_ps_avx(__m256 val)
{
__m128 vlow = _mm256_castps256_ps128(val);
__m128 vhigh = _mm256_extractf128_ps(val, 1); // high 128
vlow = _mm_add_ps(vlow, vhigh); // add the low 128
return hsum_ps_sse3(vlow); // and inline the sse3 version, which is optimal for AVX
}
void print_debug(__m256 val)
{
float temp[8];
_mm256_store_ps(temp, val);
std::cout << "DEBUG: "
<< temp[0] << " -- " << temp[1] << " -- "
<< temp[2] << " -- " << temp[3] << " -- "
<< temp[4] << " -- " << temp[5] << " -- "
<< temp[6] << " -- " << temp[7] << std::endl;
}
// Return max value across (i.e. horizontally) vector
// Algorithm came from here: https://stackoverflow.com/a/9798369/73878
float max_ps_avx(__m256 val)
{
__m256 m0 = _mm256_permute2f128_ps(val, val, 1); // Permute 128-bit values
__m256 m1 = _mm256_max_ps(val, m0); // Compute max of 4 sets
__m256 m2 = _mm256_permute_ps(m1, 0x4E); // Permute max values
__m256 m3 = _mm256_max_ps(m1, m2); // Compute max of 2 sets
__m256 m4 = _mm256_permute_ps(m3, 0x3B); // Permute max values
__m256 m = _mm256_max_ps(m3, m4); // Compute (final) max
return _mm_cvtss_f32(_mm256_extractf128_ps(m, 0));
}
// Return min value across (i.e. horizontally) vector
// Algorithm came from here: https://stackoverflow.com/a/9798369/73878
float min_ps_avx(__m256 val)
{
__m256 m0 = _mm256_permute2f128_ps(val, val, 1); // Permute 128-bit values
__m256 m1 = _mm256_min_ps(val, m0); // Compute min of 4 sets
__m256 m2 = _mm256_permute_ps(m1, 0x4E); // Permute max values
__m256 m3 = _mm256_min_ps(m1, m2); // Compute min of 2 sets
__m256 m4 = _mm256_permute_ps(m3, 0x3B); // Permute max values
__m256 m = _mm256_min_ps(m3, m4); // Compute (final) min
return _mm_cvtss_f32(_mm256_extractf128_ps(m, 0));
}
// g++ -std=c++11 -O3 -mavx -o ps_test ps_test.cc
int main(int argc, char** argv)
{
std::cout << "Packed Float (PS) Test\n" << std::endl;
float raw_data[8] = {1.0, 2.0, -3.0, 4.0, 5.0, -6.0, 7.0 , 8.0};
// Generate signmask
__m256 SIGNMASK = _mm256_castsi256_ps(_mm256_set1_epi32(0x80000000));
// Load data
__m256 data = _mm256_loadu_ps(raw_data);
// Take absolute value of data
__m256 abs_data = _mm256_andnot_ps(SIGNMASK, data);
// Sum data
float total = hsum256_ps_avx(data);
float total_abs = hsum256_ps_avx(abs_data);
std::cout << "Total: " << total << " -- " << total_abs << std::endl;
std::cout << " Max: " << max_ps_avx(abs_data) << std::endl;
std::cout << " Min: " << min_ps_avx(abs_data) << std::endl;
return 0;
}

Also available in: Unified diff