sdr 0.1.0.0 → 0.1.0.1
raw patch · 3 files changed
+279/−2 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- c_sources/common.h +276/−0
- hs_sources/SDR/PipeUtils.hs +1/−1
- sdr.cabal +2/−1
+ c_sources/common.h view
@@ -0,0 +1,276 @@+/*+ * Common functions used by filters, decimators and resamplers. + * Includes real and complex dot products and SIMD horizontal additions.+ * TODO: better performance might be possible by avoiding unaligned memory accesses.+ */++#include <x86intrin.h>++/*+ * Real horizontal addition+ */+static inline __m128 sse_hadd_R(__m128 in){+ __m128 accum;+ accum = _mm_hadd_ps(in, in);+ return _mm_hadd_ps(accum, accum);+}++static inline __m128 avx_hadd_R(__m256 in){+ __m128 res1 = _mm256_extractf128_ps(in, 0);+ __m128 res2 = _mm256_extractf128_ps(in, 1);++ res1 = _mm_hadd_ps(res1, res1);+ res1 = _mm_hadd_ps(res1, res1);++ res2 = _mm_hadd_ps(res2, res2);+ res2 = _mm_hadd_ps(res2, res2);++ return _mm_add_ss(res1, res2);+}++/*+ * Real dot products+ */+static inline float dotprod_R(int num, float *a, float *b){+ int i;+ float accum = 0;+ for(i=0; i<num; i++){+ accum += a[i] * b[i];+ }+ return accum;+}++static inline __m128 sse_dotprod_R(int num, float *a, float *b){+ int i;+ __m128 accum = _mm_setzero_ps();++ for(i=0; i<num; i+=4){+ //Load the needed vectors+ __m128 coeff = _mm_loadu_ps(a + i);+ __m128 val = _mm_loadu_ps(b + i);++ //Multiply and acumulate+ accum = _mm_add_ps(accum, _mm_mul_ps(coeff, val));+ }+ return accum;+}++static inline __m256 avx_dotprod_R(int num, float *a, float *b){+ int i;+ __m256 accum = _mm256_setzero_ps();++ for(i=0; i<num; i+=8){++ //Load the needed vectors+ __m256 coeff = _mm256_loadu_ps(a + i);+ __m256 val = _mm256_loadu_ps(b + i);++ //Multiply and acumulate+ accum = _mm256_add_ps(accum, _mm256_mul_ps(coeff, val));+ }+ return accum;+}++/*+ * Complex horizontal addition+ */+static inline __m128 sse_hadd_C(__m128 in) {+ __m128 accum = _mm_shuffle_ps(in, in, 0b11011000);+ return _mm_hadd_ps(accum, accum);+}++static inline __m128 avx_hadd_C(__m256 in) {+ __m256 accum = _mm256_permute_ps(in, _MM_SHUFFLE(3, 1, 2, 0));+ __m128 accum_hi = _mm256_extractf128_ps(accum, 1);+ __m128 accum_lo = _mm256_extractf128_ps(accum, 0);+ __m128 added = _mm_hadd_ps(accum_lo, accum_hi);+ added = _mm_permute_ps(added, _MM_SHUFFLE(3, 1, 2, 0));+ added = _mm_hadd_ps(added, added);+ return added;+}++/*+ * Complex dot products+ */+static inline float dotprod_C(int num, float *a, float *b, float *result){+ int i;+ float real = 0;+ float imag = 0;+ for(i=0; i<num; i++){+ real += b[2*i] * a[i];+ imag += b[2*i+1] * a[i];+ }+ result[0] = real;+ result[1] = imag;+}++static inline __m128 sse_dotprod_C(int num, float *coeffs, float *startPtr){+ int i;+ __m128 accum1 = _mm_setzero_ps();+ __m128 accum2 = _mm_setzero_ps();++ for(i=0; i<num; i+=4){++ //Load the needed vectors+ __m128 coeff = _mm_loadu_ps(coeffs + i);+ __m128 coeff1 = _mm_shuffle_ps(coeff, coeff, 0x50);+ __m128 coeff2 = _mm_shuffle_ps(coeff, coeff, 0xfa);+ __m128 val1 = _mm_loadu_ps(startPtr + 2 * i);+ __m128 val2 = _mm_loadu_ps(startPtr + 2 * i + 4);++ //Multiply and acumulate+ accum1 = _mm_add_ps(accum1, _mm_mul_ps(coeff1, val1));+ accum2 = _mm_add_ps(accum2, _mm_mul_ps(coeff2, val2));+ }+ __m128 accum = _mm_add_ps(accum1, accum2);+ return accum;+}++static inline __m256 avx_dotprod_C(int num, float *a, float *b){+ int i;+ __m256 accum1 = _mm256_setzero_ps();+ __m256 accum2 = _mm256_setzero_ps();++ float *startPtr = a;+ for(i=0; i<num; i+=8){++ //Load the needed vectors+ __m256 coeff = _mm256_loadu_ps(a + i);++ __m256 coeffa = _mm256_shuffle_ps(coeff, coeff, 0x50);+ __m256 coeffb = _mm256_shuffle_ps(coeff, coeff, 0xfa);++ __m256 coeff1 = _mm256_permute2f128_ps(coeffa, coeffb, 0x20);+ __m256 coeff2 = _mm256_permute2f128_ps(coeffa, coeffb, 0x31);++ __m256 val1 = _mm256_loadu_ps(b + 2 * i);+ __m256 val2 = _mm256_loadu_ps(b + 2 * i + 8);++ //Multiply and acumulate+ accum1 = _mm256_add_ps(accum1, _mm256_mul_ps(coeff1, val1));+ accum2 = _mm256_add_ps(accum2, _mm256_mul_ps(coeff2, val2));+ }++ return _mm256_add_ps(accum1, accum2);+}++/*+ * Real symmetric dot products+ */+static inline __m128 sse_sym_dotprod_R(int num, float *a, float *b){+ int i;+ __m128 accum = _mm_setzero_ps();++ float *startPtr = b;+ float *endPtr = b + num * 2 - 4;+ for(i=0; i<num; i+=4){++ //Load the needed vectors+ __m128 coeff = _mm_loadu_ps(a + i);+ __m128 val1 = _mm_loadu_ps(startPtr + i);+ __m128 val2 = _mm_loadu_ps(endPtr - i);+ val2 = _mm_permute_ps(val2, _MM_SHUFFLE(0, 1, 2, 3));++ //Multiply and acumulate+ accum = _mm_add_ps(accum, _mm_mul_ps(coeff, _mm_add_ps(val1, val2)));+ }++ return accum;+}++static inline __m256 avx_sym_dotprod_R(int num, float *a, float *b){+ int i;+ __m256 accum = _mm256_setzero_ps();++ float *startPtr = b;+ float *endPtr = b + num * 2 - 8;+ for(i=0; i<num; i+=8){++ //Load the needed vectors+ __m256 coeff = _mm256_loadu_ps(a + i);+ __m256 val1 = _mm256_loadu_ps(startPtr + i);+ __m256 val2 = _mm256_loadu_ps(endPtr - i);+ val2 = _mm256_permute2f128_ps(val2, val2, 0x01);+ val2 = _mm256_permute_ps(val2, _MM_SHUFFLE(0, 1, 2, 3));++ //Multiply and acumulate+ accum = _mm256_add_ps(accum, _mm256_mul_ps(coeff, _mm256_add_ps(val1, val2)));+ }++ return accum;+}++/*+ * Complex symmetric dot products+ */+static inline __m128 sse_sym_dotprod_C(int num, float *a, float *b){+ int i;+ __m128 accum1 = _mm_setzero_ps();+ __m128 accum2 = _mm_setzero_ps();++ float *startPtr = b;+ float *endPtr = b + num * 4 - 4;+ for(i=0; i<num; i+=4){++ //Load the needed vectors+ __m128 coeff = _mm_loadu_ps(a + i);+ __m128 coeff1 = _mm_shuffle_ps(coeff, coeff, 0x50);+ __m128 coeff2 = _mm_shuffle_ps(coeff, coeff, 0xfa);++ __m128 val1 = _mm_loadu_ps(startPtr + 2*i);+ __m128 val2 = _mm_loadu_ps(startPtr + 2*i + 4);+ __m128 val3 = _mm_loadu_ps(endPtr - 2*i - 4);+ val3 = _mm_shuffle_ps(val3, val3, _MM_SHUFFLE(1, 0, 3, 2));+ __m128 val4 = _mm_loadu_ps(endPtr - 2*i);+ val4 = _mm_shuffle_ps(val4, val4, _MM_SHUFFLE(1, 0, 3, 2));++ //Multiply and acumulate+ accum1 = _mm_add_ps(accum1, _mm_mul_ps(coeff1, _mm_add_ps(val1, val4)));+ accum2 = _mm_add_ps(accum2, _mm_mul_ps(coeff2, _mm_add_ps(val2, val3)));+ }++ return _mm_add_ps(accum1, accum2);+}++static inline __m256 avx_sym_dotprod_C(int num, float *a, float *b){+ int i;+ __m256 accum1 = _mm256_setzero_ps();+ __m256 accum2 = _mm256_setzero_ps();++ float *startPtr = b;+ float *endPtr = b + num * 4 - 8;+ for(i=0; i<num; i+=8){+ //+ //Load the needed vectors+ __m256 coeff = _mm256_loadu_ps(a + i);+ __m256 coeffa = _mm256_shuffle_ps(coeff, coeff, 0x50);+ __m256 coeffb = _mm256_shuffle_ps(coeff, coeff, 0xfa);+ __m256 coeff1 = _mm256_permute2f128_ps(coeffa, coeffb, 0x20);+ __m256 coeff2 = _mm256_permute2f128_ps(coeffa, coeffb, 0x31);++ __m256 val1 = _mm256_loadu_ps(startPtr + 2*i);+ __m256 val2 = _mm256_loadu_ps(startPtr + 2*i + 8);+ __m256 val3 = _mm256_loadu_ps(endPtr - 2*i - 8);+ val3 = _mm256_permute_ps(val3, _MM_SHUFFLE(1, 0, 3, 2));+ val3 = _mm256_permute2f128_ps(val3, val3, 0x01);+ __m256 val4 = _mm256_loadu_ps(endPtr - 2*i);+ val4 = _mm256_permute_ps(val4, _MM_SHUFFLE(1, 0, 3, 2));+ val4 = _mm256_permute2f128_ps(val4, val4, 0x01);++ //Multiply and acumulate+ accum1 = _mm256_add_ps(accum1, _mm256_mul_ps(coeff1, _mm256_add_ps(val1, val4)));+ accum2 = _mm256_add_ps(accum2, _mm256_mul_ps(coeff2, _mm256_add_ps(val2, val3)));+ }++ return _mm256_add_ps(accum1, accum2);+}++/*+ * Storing complex numbers+ */+static inline void store_complex(float *loc, __m128 val){+ _mm_store_ss(loc, val);+ val = _mm_shuffle_ps(val, val, 0b00000001);+ _mm_store_ss(loc + 1, val);+}+
hs_sources/SDR/PipeUtils.hs view
@@ -20,7 +20,7 @@ lift $ yield res lift $ lift $ yield res --- | Combime two consumers into a single consumer+-- | Combine two consumers into a single consumer combine :: Monad m => Consumer a m r -> Consumer a m r -> Consumer a m r combine x y = runEffect $ runEffect (fork func >-> hoist (lift . lift) x) >-> hoist lift y where
sdr.cabal view
@@ -1,5 +1,5 @@ name: sdr-version: 0.1.0.0+version: 0.1.0.1 synopsis: A software defined radio library description: Write software defined radio applications in Haskell.@@ -95,6 +95,7 @@ default-language: Haskell2010 ghc-options: -O2 includes: c_sources/common.h+ install-includes: c_sources/common.h c-sources: c_sources/filter.c, c_sources/decimate.c,