gpt4 book ai didi

gcc - 如何使用 SSE 指令集绝对 2 个 double 或 4 个 float ? (高达 SSE4)

转载 作者:行者123 更新时间:2023-12-03 14:31:41 26 4
gpt4 key购买 nike

这是我尝试使用 SSE 加速的示例 C 代码,两个数组的长度为 3072 个元素, double 数,如果我不需要 double 数,可以将其放下以 float 。

double sum = 0.0;

for(k = 0; k < 3072; k++) {
sum += fabs(sima[k] - simb[k]);
}

double fp = (1.0 - (sum / (255.0 * 1024.0 * 3.0)));

无论如何,我当前的问题是如何在 SSE 寄存器中为 double 或浮点数执行 fabs 步骤,以便我可以将整个计算保留在 SSE 寄存器中,以便它保持快速,并且我可以通过部分展开此循环来并行化所有步骤。

这是我找到的一些资源 fabs() asm或者可能是这个 flipping the sign - SO然而,第二个的弱点需要条件检查。

最佳答案

我建议使用按位和带掩码。正负值的表示相同,只有最高位不同,正值是0,负值是1,见double precision number format .您可以使用以下之一:

inline __m128 abs_ps(__m128 x) {
static const __m128 sign_mask = _mm_set1_ps(-0.f); // -0.f = 1 << 31
return _mm_andnot_ps(sign_mask, x);
}

inline __m128d abs_pd(__m128d x) {
static const __m128d sign_mask = _mm_set1_pd(-0.); // -0. = 1 << 63
return _mm_andnot_pd(sign_mask, x); // !sign_mask & x
}

此外,展开循环以打破循环携带的依赖链可能是个好主意。由于这是非负值的总和,因此求和的顺序并不重要:
double norm(const double* sima, const double* simb) {
__m128d* sima_pd = (__m128d*) sima;
__m128d* simb_pd = (__m128d*) simb;

__m128d sum1 = _mm_setzero_pd();
__m128d sum2 = _mm_setzero_pd();
for(int k = 0; k < 3072/2; k+=2) {
sum1 += abs_pd(_mm_sub_pd(sima_pd[k], simb_pd[k]));
sum2 += abs_pd(_mm_sub_pd(sima_pd[k+1], simb_pd[k+1]));
}

__m128d sum = _mm_add_pd(sum1, sum2);
__m128d hsum = _mm_hadd_pd(sum, sum);
return *(double*)&hsum;
}

通过展开和打破依赖关系(sum1 和 sum2 现在是独立的),您可以让处理器按我们的顺序执行加法。由于指令是在现代 CPU 上流水线化的,因此 CPU 可以在前一个指令完成之前开始处理新指令。此外,按位运算是在单独的执行单元上执行的,CPU 实际上可以在与加法/减法相同的周期内执行它。我建议 Agner Fog's optimization manuals .

最后,我不建议使用 openMP。循环太小,在多个线程之间分配作业的开销可能大于任何潜在的好处。

关于gcc - 如何使用 SSE 指令集绝对 2 个 double 或 4 个 float ? (高达 SSE4),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5508628/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com