gpt4 book ai didi

c++ - SSE2 按 vector 移动

转载 作者:行者123 更新时间:2023-11-30 03:39:42 25 4
gpt4 key购买 nike

我一直在尝试在 SSE2 内在函数中通过 vector 实现移位,但来自实验和 the intel intrinsic guide , 它似乎只使用 vector 的最低有效部分。

改写我的问题,给定一个 vector {v1, v2, ..., vn} 和一组位移 {s1, s2, ..., sn},我如何计算结果 {r1, r2, ..., rn} 这样:

r1 = v1 << s1
r2 = v2 << s2
...
rn = vn << sn

因为 _mm_sll_epi* 执行此操作:

r1 = v1 << s1
r2 = v2 << s1
...
rn = vn << s1

提前致谢。

编辑:

这是我的代码:

#include <iostream>

#include <cstdint>

#include <mmintrin.h>
#include <emmintrin.h>

namespace SIMD {

using namespace std;

class SSE2 {
public:
// flipped operands due to function arguments
SSE2(uint64_t a, uint64_t b, uint64_t c, uint64_t d) { low = _mm_set_epi64x(b, a); high = _mm_set_epi64x(d, c); }

uint64_t& operator[](int idx)
{
switch (idx) {
case 0:
_mm_storel_epi64((__m128i*)result, low);
return result[0];
case 1:
_mm_store_si128((__m128i*)result, low);
return result[1];
case 2:
_mm_storel_epi64((__m128i*)result, high);
return result[0];
case 3:
_mm_store_si128((__m128i*)result, high);
return result[1];
}

/* Undefined behaviour */
return 0;
}

SSE2& operator<<=(const SSE2& rhs)
{
low = _mm_sll_epi64(low, rhs.getlow());
high = _mm_sll_epi64(high, rhs.gethigh());

return *this;
}

void print()
{
uint64_t a[2];
_mm_store_si128((__m128i*)a, low);

cout << hex;
cout << a[0] << ' ' << a[1] << ' ';

_mm_store_si128((__m128i*)a, high);

cout << a[0] << ' ' << a[1] << ' ';
cout << dec;
}

__m128i getlow() const
{
return low;
}

__m128i gethigh() const
{
return high;
}
private:
__m128i low, high;
uint64_t result[2];
};
}

int main()
{
cout << "operator<<= test: vector << vector: ";
{
auto x = SIMD::SSE2(7, 8, 15, 10);
auto y = SIMD::SSE2(4, 5, 6, 7);

x.print();
y.print();

x <<= y;

if (x[0] != 112 || x[1] != 256 || x[2] != 960 || x[3] != 1280) {
cout << "FAILED: ";
x.print();
cout << endl;
} else {
cout << "PASSED" << endl;
}
}

return 0;
}

应该发生的结果是 {7 << 4 = 112, 8 << 5 = 256, 15 << 6 = 960, 10 << 7 = 1280}。结果似乎是 {7 << 4 = 112, 8 << 4 = 128, 15 << 6 = 960, 15 << 6 = 640},这不是我想要的。

希望这对您有所帮助,Jens。

最佳答案

如果 AVX2 可用,并且您的元素是 32 位或 64 位,则您的操作需要一个变量移位指令:vpsrlvq , (__m128i _mm_srlv_epi64 (__m128i a, __m128i 计数) )


对于 SSE4.1 的 32 位元素,请参阅 Shifting 4 integers right by different values SIMD .根据延迟与吞吐量要求,您可以进行单独的移位,然后混合,或使用乘法(通过特殊构造的 2 的幂 vector )来获得可变计数的左移,然后进行相同的计数-所有元素右移。


对于您的情况,具有运行时变量移位计数的 64 位元素:

每个 SSE vector 只有两个元素,所以我们只需要两次移位,然后合并结果(我们可以使用 pblendw 或浮点 movsd(这可能会导致某些 CPU 上的额外旁路延迟延迟),或者我们可以使用两次随机播放,或者我们可以执行两个与和一个或。

__m128i SSE2_emulated_srlv_epi64(__m128i a, __m128i count)
{
__m128i shift_low = _mm_srl_epi64(a, count); // high 64 is garbage
__m128i count_high = _mm_unpackhi_epi64(count,count); // broadcast the high element
__m128i shift_high = _mm_srl_epi64(a, count_high); // low 64 is garbage
// SSE4.1:
// return _mm_blend_epi16(shift_low, shift_high, 0x0F);

#if 1 // use movsd to blend
__m128d blended = _mm_move_sd( _mm_castsi128_pd(shift_high), _mm_castsi128_pd(shift_low) ); // use movsd as a blend. Faster than multiple instructions on most CPUs, but probably bad on Nehalem.
return _mm_castpd_si128(blended);
#else // SSE2 without using FP instructions:
// if we're going to do it this way, we could have shuffled the input before shifting. Probably not helpful though.
shift_high = _mm_unpackhi_epi64(shift_high, shift_high); // broadcast the high64
return _mm_unpacklo_epi64(shift_high, shift_low); // combine
#endif
}

其他 shuffle 如 pshufd 或 psrldq 也可以,但是 punpckhqdq无需立即字节即可完成工作,因此缩短了一个字节。 SSSE3 palignr可以从一个寄存器获取高位元素,从另一个寄存器获取低位元素到一个 vector 中,但它们会被颠倒(所以我们需要一个 pshufd 来交换高位和低位)。 shufpd 可以混合,但与 movsd 相比没有优势。

参见 Agner Fog's microarch guide有关在两个整数指令之间使用 FP 指令的潜在旁路延迟延迟的详细信息。它在 Intel SnB 系列 CPU 上可能没问题,因为其他 FP 洗牌是。 (是的,movsd xmm1, xmm0 在 port5 的洗牌单元上运行。如果你不需要合并行为)。


这会(在 Godbolt 上使用 gcc5.3 -O3)编译为

    movdqa  xmm2, xmm0  # tmp97, a
psrlq xmm2, xmm1 # tmp97, count
punpckhqdq xmm1, xmm1 # tmp99, count
psrlq xmm0, xmm1 # tmp100, tmp99
movsd xmm0, xmm2 # tmp102, tmp97
ret

关于c++ - SSE2 按 vector 移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38605451/

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