将SSE转换为霓虹灯:如何打包然后提取32位结果
Translating SSE to Neon: How to pack and then extract 32bit result
我必须将以下指令从SSE转换为Neon
uint32_t a = _mm_cvtsi128_si32(_mm_shuffle_epi8(a,SHUFFLE_MASK) );
其中:
static const __m128i SHUFFLE_MASK = _mm_setr_epi8(3, 7, 11, 15, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1);
所以基本上,我必须从寄存器中取出第4、第8、第12和第16个字节,并将其放入uint32_t
中。看起来像一条打包指令(在SSE中,我似乎记得我使用了shuffle,因为与打包相比,它只保存了一条指令,本例显示了打包指令的使用)。
这个操作在霓虹灯中是如何翻译的
我应该使用包装说明吗
然后如何提取32位?(有类似_mm_cvtsi128_si32
的东西吗?)
编辑:
首先,vgetq_lane_u32
应该允许替换_mm_cvtsi128_si32
(但我必须将uint8x16_t转换为uint32x4_t)
uint32_t vgetq_lane_u32(uint32x4_t vec, __constrange(0,3) int lane);
或者直接存储车道vst1q_lane_u32
void vst1q_lane_u32(__transfersize(1) uint32_t * ptr, uint32x4_t val, __constrange(0,3) int lane); // VST1.32 {d0[0]}, [r0]
我发现了这个优秀的指南。我正在处理这个问题,我的操作似乎可以用一条VTBL指令(查找表)来完成,但我将用两个去交错操作来实现它,因为目前它看起来更简单。
uint8x8x2_t vuzp_u8(uint8x8_t a, uint8x8_t b);
所以类似于:
uint8x16_t a;
uint8_t* out;
[...]
//a = 138 0 0 0 140 0 0 0 146 0 0 0 147 0 0 0
a = vuzp_u8(vget_low_u8(a), vget_high_u8(a) );
//a = 138 0 140 0 146 0 147 0 0 0 0 0 0 0 0 0
a = vuzp_u8(vget_low_u8(a), vget_high_u8(a) );
//a = 138 140 146 147 0 0 0 0 0 0 0 0 0 0 0 0
vst1q_lane_u32(out,a,0);
最后一个使用__attribute__((optimize("lax-vector-conversions")))
不发出警告
但是,由于数据转换,这两个赋值是不可能的。一种解决方法是这样的(编辑:这打破了严格的别名规则!编译器可以假设a
在分配d
的地址时不会更改。):
uint8x8x2_t* d = (uint8x8x2_t*) &a;
*d = vuzp_u8(vget_low_u8(a), vget_high_u8(a) );
*d = vuzp_u8(vget_low_u8(a), vget_high_u8(a) );
vst1q_lane_u32(out,a,0);
我通过一种灵活的数据类型实现了一种更通用的解决方法:
NeonVectorType<uint8x16_t> a; //a can be used as a uint8x16_t, uint8x8x2_t, uint32x4_t, etc.
a = vuzp_u8(vget_low_u8(a), vget_high_u8(a) );
a = vuzp_u8(vget_low_u8(a), vget_high_u8(a) );
vst1q_lane_u32(out,a,0);
编辑:
这是带有shuffle掩码/查找表的版本。它确实让我的内环更快了一点。我再次使用了这里描述的数据类型。
static const uint8x8_t MASK = {0x00,0x04,0x08,0x0C,0xff,0xff,0xff,0xff};
NeonVectorType<uint8x16_t> a; //a can be used as a uint8x16_t, uint8x8x2_t, uint32x4_t, etc.
NeonVectorType<uint8x8_t> res; //res can be used as uint8x8_t, uint32x2_t, etc.
[...]
res = vtbl2_u8(a, MASK);
vst1_lane_u32(out,res,0);
我会这样写:
uint32_t extract (uint8x16_t x)
{
uint8x8x2_t a = vuzp_u8 (vget_low_u8 (x), vget_high_u8 (x));
uint8x8x2_t b = vuzp_u8 (a.val[0], a.val[1]);
return vget_lane_u32 (vreinterpret_u32_u8 (b.val[0]), 0);
}
在最近的GCC版本中编译为:
extract:
vuzp.8 d0, d1
vuzp.8 d0, d1
vmov.32 r0, d0[0]
bx lr
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 通过套接字[TCP]传输数据 如何在C / C ++中打包多个整数并使用send() recv()传输数据
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 这是我尝试让用户将值输入到数组中.然后将其隐藏为大量的星号
- boost::asio如何生成多个协同程序,然后加入它们
- Python中的for循环与C++有何不同
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 在std::thread中,joinable()然后join()线程安全吗
- C++:如何读取分离变量,然后读取向量
- 为什么我的递归函数按降序打印,然后按升序打印?
- 等待整个 omp 块完成,然后再调用第二个函数
- CMake:如何将库 A 链接到库 B,然后将可执行文件链接到库 A
- 打包可变参数模板具有零元素时的递归
- 使用英特尔内联函数将打包的 8 位整数乘以浮点数向量
- 如何存储用户输入的所有数据,然后在他们想要查看所有数据时显示它们
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- 如何使变量从 x 到 y,然后从 y 返回到 x 并始终重复该过程
- 将SSE转换为霓虹灯:如何打包然后提取32位结果
- 参数打包在 std::tuple<> 中,然后应用