SSE2包装的8位整数签名乘数(高半):将M128i(16x8位)分解为两个M128i(每个8x16),然后重新包装
SSE2 packed 8-bit integer signed multiply (high-half): Decomposing a m128i (16x8 bit) into two m128i (8x16 each) and repack
我正在尝试乘以两个 m128i
byte perte(8位签名的整数(。
这里的问题是溢出。我的解决方案是将这8位签名的整数存储到16位签名的整数中,然后将整个内容包装到16 x 8位整数的m128i
中。
这是我制作的__m128i mulhi_epi8(__m128i a, __m128i b)
仿真:
inline __m128i mulhi_epi8(__m128i a, __m128i b)
{
auto a_decomposed = decompose_epi8(a);
auto b_decomposed = decompose_epi8(b);
__m128i r1 = _mm_mullo_epi16(a_decomposed.first, b_decomposed.first);
__m128i r2 = _mm_mullo_epi16(a_decomposed.second, b_decomposed.second);
return _mm_packs_epi16(_mm_srai_epi16(r1, 8), _mm_srai_epi16(r2, 8));
}
decompose_epi8
以非SIMD方式实现:
inline std::pair<__m128i, __m128i> decompose_epi8(__m128i input)
{
std::pair<__m128i, __m128i> result;
// result.first => should contain 8 shorts in [-128, 127] (8 first bytes of the input)
// result.second => should contain 8 shorts in [-128, 127] (8 last bytes of the input)
for (int i = 0; i < 8; ++i)
{
result.first.m128i_i16[i] = input.m128i_i8[i];
result.second.m128i_i16[i] = input.m128i_i8[i + 8];
}
return result;
}
此代码运行良好。我现在的目标是实现此循环的SIMD版本。我查看了英特尔内在指南,但找不到这样做的方法。我想洗牌可以解决这个问题,但我很难概念化这个问题。
当您想执行签名乘法时,您需要签名每个字节至16位单词,或将它们移至每个16位单词的上半部分。由于您之后将结果包装在一起,因此您可以将输入分为奇数甚至字节,而不是较高和下半部。然后,可以通过将所有16位零件转移到右侧来完成奇数字节的登录范围,您可以通过掩盖偶数字节来提取奇数字节,并获得均匀的字节,您可以移动左侧的所有16位零件(都需要乘以_mm_mulhi_epi16
(。
以下应与SSE2合作:
__m128i mulhi_epi8(__m128i a, __m128i b)
{
__m128i mask = _mm_set1_epi16(0xff00);
// mask higher bytes:
__m128i a_hi = _mm_and_si128(a, mask);
__m128i b_hi = _mm_and_si128(b, mask);
__m128i r_hi = _mm_mulhi_epi16(a_hi, b_hi);
// mask out garbage in lower half:
r_hi = _mm_and_si128(r_hi, mask);
// shift lower bytes to upper half
__m128i a_lo = _mm_slli_epi16(a,8);
__m128i b_lo = _mm_slli_epi16(b,8);
__m128i r_lo = _mm_mulhi_epi16(a_lo, b_lo);
// shift result to the lower half:
r_lo = _mm_srli_epi16(r_lo,8);
// join result and return:
return _mm_or_si128(r_hi, r_lo);
}
注意:先前使用的版本转移以扩展奇数字节。在大多数Intel CPU上,这将增加P0使用率(也需要用于乘法(。位逻辑可以在更多端口上运行,因此此版本应该具有更好的吞吐量。
相关文章:
- 如何在c++17中制作一个模板包装器/装饰器
- std::vector的包装器,使数组的结构看起来像结构的数组
- 如何在c++迭代器类型中包装std::chrono
- 是否可以用"iostream"包装现有的TCP/OOpenSSL会话
- 用pybind11包装C++抽象类时出错
- 为左值和右值的包装器实现C++范围
- C结构,其指针将被包装在unique_ptr中
- 如何包装第三方DLL在R中使用
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 将 N-arg 函数包装到另一个函数中
- 元组由 Swig 生成的 Python 包装器返回,用于C++向量
- 包装一个对象并假装它是一个 int
- 使用 Python Extension API 包装复杂C++类
- 外壳包装器句柄/执行交互式命令管道C++ UNIX
- 包装C++类时不完整的类型 GLFWwindow
- 将函数包装器转换为 std::function
- C++函数包装器来捕获某些信号
- 创建包装升压适配器的自定义范围类
- 如何包装(撰写)增强 hana 地图并访问括号运算符(运算符 [])?
- SSE2包装的8位整数签名乘数(高半):将M128i(16x8位)分解为两个M128i(每个8x16),然后重新包装