我是SSE的新手,并使用内在函数优化了一段代码。我对操作本身很满意,但我正在寻找一种更好的方法来编写结果。结果以三个_m128i
变量结束。
我要做的是将结果值中的特定字节存储到非连续的内存位置。我现在正在这样做:
__m128i values0,values1,values2;
/*Do stuff and store the results in values0, values1, and values2*/
y[0] = (BYTE)_mm_extract_epi16(values0,0);
cb[2]=cb[3] = (BYTE)_mm_extract_epi16(values0,2);
y[3] = (BYTE)_mm_extract_epi16(values0,4);
cr[4]=cr[5] = (BYTE)_mm_extract_epi16(values0,6);
cb[0]=cb[1] = (BYTE)_mm_extract_epi16(values1,0);
y[1] = (BYTE)_mm_extract_epi16(values1,2);
cr[2]=cr[3] = (BYTE)_mm_extract_epi16(values1,4);
y[4] = (BYTE)_mm_extract_epi16(values1,6);
cr[0]=cr[1] = (BYTE)_mm_extract_epi16(values2,0);
y[2] = (BYTE)_mm_extract_epi16(values2,2);
cb[4]=cb[5] = (BYTE)_mm_extract_epi16(values2,4);
y[5] = (BYTE)_mm_extract_epi16(values2,6);
y
,cb
和cr
是字节(unsigned char
)数组。由于我无法定义的原因,这对我来说似乎是错误的。有没有人对更好的方法有任何建议?
谢谢!
答案 0 :(得分:9)
你基本上不能 - SSE没有散点存储,而且它的设计都围绕着对连续数据流进行矢量化工作的想法。实际上,制作SIMD 所涉及的大部分工作都是重新排列您的数据,以便它是连续的和可矢量化的。因此,最好的做法是重新排列数据结构,以便您可以一次写入16个字节。不要忘记,在将SIMD向量中的组件提交到内存之前,可以对其进行重新排序。
如果失败,PEXTRW
op(_mm_extract_epi16内在函数)几乎是从SSE寄存器中拉出短路并存储到整数寄存器的唯一方法。您可以使用的另一种方法是使用解压缩和随机播放操作(_mm_shuffle_ps
等)将数据旋转到寄存器的低位字,然后MOVSS
/ _mm_store_ss()
来存储该低位字一次记忆一次。
您可能会发现,使用联合或在SSE和通用寄存器之间移动数据会导致性能非常差,因为称为load - hit - { {3}}失速。基本上,没有直接的方法在寄存器类型之间移动数据;处理器必须首先将SSE数据写入存储器,然后再将其读回GPR。在许多情况下,这意味着它必须停止加载操作并等待存储清除,然后才能运行任何进一步的指令。
答案 1 :(得分:2)
我并不特别了解SSE,但一般来说,矢量化单位的全部意义在于,只要数据服从特定的对齐和格式化,它们就可以非常快速地运行。因此,您需要以正确的格式和对齐方式提供和提取数据。
答案 2 :(得分:2)
SSE没有您需要的分散/聚集功能,尽管这可能会在未来的SIMD架构中出现。
正如已经建议的那样,你可以使用一个联合,例如:
typedef union
{
__m128i v;
uint8_t a8[16];
uint16_t a16[8];
uint32_t a32[4];
} U128;
理想情况下,这种操作只发生在任何关键循环之外,因为与连续数据元素上的直接SIMD操作相比,效率非常低。
答案 3 :(得分:0)
您可以尝试使用union来提取字节。
union
{
float value;
unsigned char ch[8];
};
然后根据需要分配字节
使用union-idea,或者用匿名结构替换unsigned char ch [8]?
也许你可以从here