我最近一直在使用SSE内在int _mm_extract_epi8 (__m128i src, const int ndx)
,根据引用“从索引选择的压缩整数数组元素中提取整数字节”。这正是我想要的。
但是,我通过_mm_cmpestri
上的_m128i
确定索引,该const int index = _mm_cmpestri(...);
if (index >= 0 && index < 16) {
int intAtIndex = _mm_extract_epi8(..., index);
}
执行字符串数据与显式长度的打包比较并生成索引。此索引的范围是0..16,其中0..15表示有效索引,16表示未找到索引。现在要提取索引位置的整数,我想做以下几点:
switch
这给我们留下了gcc(-O0)编译错误:
错误:选择器必须是0..15
范围内的整数常量解决此问题的一个令人讨厌的方法是在索引上使用_mm_extract_epi8
并在0..15范围内对每个索引进行{{1}}调用。我的问题是,如果有更好/更好的方式,我没有看到。
更新:使用-O3优化,没有编译错误;仍然使用-O0。
答案 0 :(得分:2)
总结并结束这个问题。
我们讨论了从[{1}}中提取[0..15]中索引i处的字节的3个选项,其中我无法在编译时将其缩减为文字:
1)Switch&amp; _m128i sse
:对{i} _mm_extract_epi8
以及{0..15]中每个i switch
的情况;因为我现在是一个编译时文字。
2)联盟黑客:拥有_mm_extract_epi8(sse,i)
,将其初始化为union SSE128i { __m128i sse; char[16] array; }
并使用SSE128i sse = { _mm_loadu_si128(...) }
访问索引i处的字节。
3)将第i个元素移动到位置0和sse.array[i]
:使用_mm_extract_epi8
将第i个元素移动到位置0;用_mm_shuffle_epi8(sse,_mm_set1_epi8(i))
提取它。
评估:我对Intel Sandy Bridge和AMD Bulldozer架构的三个选项进行了基准测试。切换选项赢得了小幅度。如果有人感兴趣,我可以发布更详细的数字和基准设置。
更新:评估
基准设置:解析1GB文件的每个字节。对于某些特殊字节,请增加计数器。使用_mm_extract_epi8(sse,0)
查找特殊字节的索引;然后使用上述三种方法之一“提取”字节,并进行计数器递增的大小写区分。代码是使用GCC 4.6和_mm_cmpistri
编译的。
对于每种方法,基准测试在Sandy Bridge机器上运行25次。结果(以秒为单位的平均值和标准运行时间):
切换并提取: 平均值:1071.45 标准差:2.72006
联盟黑客: 平均值:1078.61 标准差:2.87131
从位置0开始抽取和提取: 平均值:1079.32 标准差:2.69808
差异很小。我还没机会看到生成的asm。看到差异可能会很有趣。目前我无法发布基准测试的完整代码,因为它包含非公开来源。如果我有时间,我会提取这些并发布消息来源。