/* SIMD wrapper used by polar encoder and decoder Copyright 2020 Ahmet Inan */ #pragma once #include "simd.hh" namespace CODE { template struct PolarHelper { typedef TYPE PATH; static TYPE one() { return 1; } static TYPE zero() { return 0; } static TYPE signum(TYPE v) { return (v > 0) - (v < 0); } template static TYPE quant(IN in) { return in; } static TYPE qabs(TYPE a) { return std::abs(a); } static TYPE qmin(TYPE a, TYPE b) { return std::min(a, b); } static TYPE qadd(TYPE a, TYPE b) { return a + b; } static TYPE qmul(TYPE a, TYPE b) { return a * b; } static TYPE prod(TYPE a, TYPE b) { return signum(a) * signum(b) * qmin(qabs(a), qabs(b)); } static TYPE madd(TYPE a, TYPE b, TYPE c) { return a * b + c; } }; template struct PolarHelper> { typedef SIMD TYPE; typedef VALUE PATH; typedef SIMD MAP; static TYPE one() { return vdup(1); } static TYPE zero() { return vzero(); } static TYPE signum(TYPE a) { return vsignum(a); } static TYPE qabs(TYPE a) { return vabs(a); } static TYPE qmin(TYPE a, TYPE b) { return vmin(a, b); } static TYPE qadd(TYPE a, TYPE b) { return vadd(a, b); } static TYPE qmul(TYPE a, TYPE b) { return vmul(a, b); } static TYPE prod(TYPE a, TYPE b) { return vmul(vmul(vsignum(a), vsignum(b)), vmin(vabs(a), vabs(b))); } static TYPE madd(TYPE a, TYPE b, TYPE c) { return vadd(vmul(a, b), c); } }; template struct PolarHelper> { typedef SIMD TYPE; typedef int PATH; typedef SIMD MAP; static TYPE one() { return vdup(1); } static TYPE zero() { return vzero(); } static TYPE signum(TYPE a) { return vsignum(a); } static TYPE qabs(TYPE a) { return vqabs(a); } static TYPE qadd(TYPE a, TYPE b) { return vqadd(a, b); } static TYPE qmul(TYPE a, TYPE b) { #ifdef __ARM_NEON return vmul(a, b); #else return vsign(a, b); #endif } static TYPE prod(TYPE a, TYPE b) { #ifdef __ARM_NEON return vmul(vmul(vsignum(a), vsignum(b)), vmin(vqabs(a), vqabs(b))); #else return vsign(vmin(vqabs(a), vqabs(b)), vsign(vsignum(a), b)); #endif } static TYPE madd(TYPE a, TYPE b, TYPE c) { #ifdef __ARM_NEON return vmax(vqadd(vmul(a, vmax(b, vdup(-127))), c), vdup(-127)); #else return vmax(vqadd(vsign(vmax(b, vdup(-127)), a), c), vdup(-127)); #endif } }; template struct PolarHelper> { typedef SIMD TYPE; typedef int PATH; typedef SIMD MAP; static TYPE one() { return vdup(1); } static TYPE zero() { return vzero(); } static TYPE signum(TYPE a) { return vsignum(a); } static TYPE qabs(TYPE a) { return vqabs(a); } static TYPE qadd(TYPE a, TYPE b) { return vqadd(a, b); } static TYPE qmul(TYPE a, TYPE b) { #ifdef __ARM_NEON return vmul(a, b); #else return vsign(a, b); #endif } static TYPE prod(TYPE a, TYPE b) { #ifdef __ARM_NEON return vmul(vmul(vsignum(a), vsignum(b)), vmin(vqabs(a), vqabs(b))); #else return vsign(vmin(vqabs(a), vqabs(b)), vsign(vsignum(a), b)); #endif } static TYPE madd(TYPE a, TYPE b, TYPE c) { #ifdef __ARM_NEON return vmax(vqadd(vmul(a, vmax(b, vdup(-32767))), c), vdup(-32767)); #else return vmax(vqadd(vsign(vmax(b, vdup(-32767)), a), c), vdup(-32767)); #endif } }; template <> struct PolarHelper { typedef int PATH; static int8_t one() { return 1; } static int8_t zero() { return 0; } static int8_t signum(int8_t v) { return (v > 0) - (v < 0); } template static int8_t quant(IN in) { return std::min(std::max(std::nearbyint(in), -127), 127); } static int8_t qabs(int8_t a) { return std::abs(std::max(a, -127)); } static int8_t qmin(int8_t a, int8_t b) { return std::min(a, b); } static int8_t qadd(int8_t a, int8_t b) { return std::min(std::max(int16_t(a) + int16_t(b), -127), 127); } static int8_t qmul(int8_t a, int8_t b) { // return std::min(std::max(int16_t(a) * int16_t(b), -127), 127); // only used for hard decision values anyway return a * b; } static int8_t prod(int8_t a, int8_t b) { return signum(a) * signum(b) * qmin(qabs(a), qabs(b)); } static int8_t madd(int8_t a, int8_t b, int8_t c) { return std::min(std::max(int16_t(a) * int16_t(b) + int16_t(c), -127), 127); } }; template <> struct PolarHelper { typedef int PATH; static int16_t one() { return 1; } static int16_t zero() { return 0; } static int16_t signum(int16_t v) { return (v > 0) - (v < 0); } template static int16_t quant(IN in) { return std::min(std::max(std::nearbyint(in), -32767), 32767); } static int16_t qabs(int16_t a) { return std::abs(std::max(a, -32767)); } static int16_t qmin(int16_t a, int16_t b) { return std::min(a, b); } static int16_t qadd(int16_t a, int16_t b) { return std::min(std::max(int32_t(a) + int32_t(b), -32767), 32767); } static int16_t qmul(int16_t a, int16_t b) { // return std::min(std::max(int32_t(a) * int32_t(b), -32767), 32767); // only used for hard decision values anyway return a * b; } static int16_t prod(int16_t a, int16_t b) { return signum(a) * signum(b) * qmin(qabs(a), qabs(b)); } static int16_t madd(int16_t a, int16_t b, int16_t c) { return std::min(std::max(int32_t(a) * int32_t(b) + int32_t(c), -32767), 32767); } }; }