gpt4 book ai didi

c - int 与短矢量化

转载 作者:太空宇宙 更新时间:2023-11-03 23:27:54 24 4
gpt4 key购买 nike

我将以下内核向量化为整数数组:

    long valor = 0, i=0;

__m128i vsum, vecPi, vecCi, vecQCi;

vsum = _mm_set1_epi32(0);

int32_t * const pA = A->data;
int32_t * const pB = B->data;

int sumDot[1];

for( ; i<SIZE-3 ;i+=4){
vecPi = _mm_loadu_si128((__m128i *)&(pA)[i] );
vecCi = _mm_loadu_si128((__m128i *)&(pB)[i] );
vecQCi = _mm_mullo_epi32(vecPi,vecCi);
vsum = _mm_add_epi32(vsum,vecQCi);
}

vsum = _mm_hadd_epi32(vsum, vsum);
vsum = _mm_hadd_epi32(vsum, vsum);
_mm_storeu_si128((__m128i *)&(sumDot), vsum);

for( ; i<SIZE; i++)
valor += A->data[i] * B->data[i];

valor += sumDot[0];

而且效果很好。但是,如果我将 A 和 B 的数据类型更改为 short 而不是 int,我不应该使用以下代码吗:

    long valor = 0, i=0;

__m128i vsum, vecPi, vecCi, vecQCi;

vsum = _mm_set1_epi16(0);

int16_t * const pA = A->data;
int16_t * const pB = B->data;

int sumDot[1];

for( ; i<SIZE-7 ;i+=8){
vecPi = _mm_loadu_si128((__m128i *)&(pA)[i] );
vecCi = _mm_loadu_si128((__m128i *)&(pB)[i] );
vecQCi = _mm_mullo_epi16(vecPi,vecCi);
vsum = _mm_add_epi16(vsum,vecQCi);
}

vsum = _mm_hadd_epi16(vsum, vsum);
vsum = _mm_hadd_epi16(vsum, vsum);
_mm_storeu_si128((__m128i *)&(sumDot), vsum);

for( ; i<SIZE; i++)
valor += A->data[i] * B->data[i];

valor += sumDot[0];

第二个内核不起作用,我不知道为什么。我知道第一种和第二种情况下 vector 的所有条目都是相同的(也没有溢出)。有人可以帮我找出错误吗?

谢谢

最佳答案

这是我看到的一些事情。

  1. int 中和 short情况下,当您存储 __m128 时至 sumDot , 你使用 _mm_storeu_si128在比 128 位小得多的目标上。这意味着你一直在破坏内存,幸运的是你没有被咬伤。

    • 与此相关,因为sumDot是一个 int[1]即使在 short案例,你存储了两个 short合二为一int , 然后将其读作 int .
  2. short万一你错过了一个水平 vector 减少步骤。请记住,现在您有 8 short s 每个 vector ,您现在必须有 log_2(8) = 3 个 vector 缩减步骤。

    vsum = _mm_hadd_epi16(vsum, vsum);
    vsum = _mm_hadd_epi16(vsum, vsum);
    vsum = _mm_hadd_epi16(vsum, vsum);
  3. (可选)既然您已经在使用 SSE4.1,不妨使用它的优点之一:PEXTR*指示。他们获取要提取的车道的索引。您对底部泳道(泳道 0)感兴趣,因为那是 vector 缩减后总和结束的地方。 <罢工>

    <罢工>
    /* 32-bit */
    sumDot[0] = _mm_extract_epi32(vsum, 0);
    /* 16-bit */
    sumDot[0] = _mm_extract_epi16(vsum, 0);

    <罢工> 编辑:显然编译器不会对用_mm_extract_epi16 提取的16 位字进行符号扩展。 .您必须自己说服它这样做。

    /* 32-bit */
    sumDot[0] = (int32_t)_mm_extract_epi32(vsum, 0);
    /* 16-bit */
    sumDot[0] = (int16_t)_mm_extract_epi16(vsum, 0);

    EDIT2:我找到了一个更好的解决方案!它完全使用我们需要的指令 ( PMADDWD ),并且与 32 位代码相同 除了迭代边界不同,而不是 _mm_mullo_epi16。你用_mm_madd_epi16在循环。这只需要两个 32 位 vector 缩减阶段。 http://pastebin.com/A9ibkMwP

  4. (可选)这是很好的风格,但使用 _mm_setzero_*() 没有任何区别函数而不是 _mm_set1_*(0) .

关于c - int 与短矢量化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22585306/

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