如何使用SSE内在函数在非连续内存位置存储值?

时间:2010-10-19 15:10:10

标签: c sse intrinsics sse2

我是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);

ycbcr是字节(unsigned char)数组。由于我无法定义的原因,这对我来说似乎是错误的。有没有人对更好的方法有任何建议?

谢谢!

4 个答案:

答案 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

获得更多想法