82 lines
3.0 KiB
C++
82 lines
3.0 KiB
C++
#include <riscv_vector.h>
|
|
|
|
extern "C" {
|
|
|
|
void MNNExpC8(float* dest, const float* source, float* offset, const float* parameters, size_t countC8) {
|
|
size_t count = countC8 * 8;
|
|
float xLimit = 87.0f;
|
|
|
|
float inputScale = offset[0];
|
|
float outputBias = offset[1];
|
|
float inputBias = offset[2];
|
|
float summer = offset[3];
|
|
float param = parameters[0]; // ln(2)
|
|
float invParam = parameters[1]; // 1/ln(2)
|
|
float p4 = parameters[4];
|
|
float p5 = parameters[5];
|
|
float p6 = parameters[6];
|
|
float p7 = parameters[7];
|
|
|
|
size_t n = count;
|
|
const float* srcPtr = source;
|
|
float* dstPtr = dest;
|
|
vfloat32m1_t vSum = __riscv_vfmv_s_f_f32m1(summer, 1);
|
|
|
|
while (n > 0) {
|
|
size_t vl = __riscv_vsetvl_e32m4(n);
|
|
|
|
vfloat32m4_t vX = __riscv_vle32_v_f32m4(srcPtr, vl);
|
|
vX = __riscv_vfmul_vf_f32m4(vX, inputScale, vl);
|
|
vX = __riscv_vfadd_vf_f32m4(vX, inputBias, vl);
|
|
vX = __riscv_vfmax_vf_f32m4(vX, -xLimit, vl);
|
|
vX = __riscv_vfmin_vf_f32m4(vX, xLimit, vl);
|
|
|
|
// div = int(x / ln(2))
|
|
vfloat32m4_t vDiv = __riscv_vfmul_vf_f32m4(vX, invParam, vl);
|
|
vint32m4_t vDivI = __riscv_vfcvt_x_f_v_i32m4(vDiv, vl);
|
|
|
|
// Start float conversion early — its latency overlaps with integer ops below
|
|
vfloat32m4_t vDivF = __riscv_vfcvt_f_x_v_f32m4(vDivI, vl);
|
|
|
|
// expBasic = 2^div via IEEE 754 (integer ops, fast, runs while vDivF completes)
|
|
vfloat32m4_t vExpBasic =
|
|
__riscv_vreinterpret_v_i32m4_f32m4(__riscv_vsll_vx_i32m4(__riscv_vadd_vx_i32m4(vDivI, 127, vl), 23, vl));
|
|
|
|
// xRemain = x - div * ln(2)
|
|
vfloat32m4_t vRemain = __riscv_vfnmsub_vf_f32m4(vDivF, param, vX, vl);
|
|
vfloat32m4_t vT = __riscv_vfmul_vf_f32m4(vRemain, 0.25f, vl);
|
|
|
|
// Taylor: ((((p7*t + p6)*t + p5)*t + p4)*t + 1)*t + 1
|
|
vfloat32m4_t vPoly = __riscv_vfmv_v_f_f32m4(p7, vl);
|
|
vPoly = __riscv_vfmul_vv_f32m4(vPoly, vT, vl);
|
|
vPoly = __riscv_vfadd_vf_f32m4(vPoly, p6, vl);
|
|
vPoly = __riscv_vfmul_vv_f32m4(vPoly, vT, vl);
|
|
vPoly = __riscv_vfadd_vf_f32m4(vPoly, p5, vl);
|
|
vPoly = __riscv_vfmul_vv_f32m4(vPoly, vT, vl);
|
|
vPoly = __riscv_vfadd_vf_f32m4(vPoly, p4, vl);
|
|
vPoly = __riscv_vfmul_vv_f32m4(vPoly, vT, vl);
|
|
vPoly = __riscv_vfadd_vf_f32m4(vPoly, 1.0f, vl);
|
|
vPoly = __riscv_vfmul_vv_f32m4(vPoly, vT, vl);
|
|
vPoly = __riscv_vfadd_vf_f32m4(vPoly, 1.0f, vl);
|
|
|
|
// (exp(x/4))^4: square twice
|
|
vPoly = __riscv_vfmul_vv_f32m4(vPoly, vPoly, vl);
|
|
vPoly = __riscv_vfmul_vv_f32m4(vPoly, vPoly, vl);
|
|
|
|
// result = expBasic * expRemain + outputBias
|
|
vfloat32m4_t vResult = __riscv_vfmul_vv_f32m4(vExpBasic, vPoly, vl);
|
|
vResult = __riscv_vfadd_vf_f32m4(vResult, outputBias, vl);
|
|
__riscv_vse32_v_f32m4(dstPtr, vResult, vl);
|
|
|
|
vSum = __riscv_vfredusum_vs_f32m4_f32m1(vResult, vSum, vl);
|
|
|
|
srcPtr += vl;
|
|
dstPtr += vl;
|
|
n -= vl;
|
|
}
|
|
|
|
offset[3] = __riscv_vfmv_f_s_f32m1_f32(vSum);
|
|
}
|
|
|
|
} // extern "C"
|