使用SIMD操作的可变长度阵列扩展

时间:2014-01-22 20:17:16

标签: arrays sse simd avx

我想使用SIMD内部执行以下数组扩展。 我有两个数组:

  • 群集价值(v_i):10,20,30,40

  • 簇长度(l_i):3,2,1,2

我想创建一个包含值的结果数组:v_i重复l_i次,即:

结果:1​​0,10,10,20,20,30,40,40。

如何使用SIMD内在计算?

1 个答案:

答案 0 :(得分:1)

如果输入数组大小最多为8,输出数组大小最多为16,字节为数组值,则可以通过SIMD优化。至少需要SSSE3。将此方法扩展到更大的阵列/元素是可能的,但效率会迅速降低。

  1. 计算数组长度的前缀和。如果将字节数组长度重新解释为单个64位(32位)字,将其乘以0x101010101010100,并将结果存储在SIMD寄存器中,则可以快速完成此操作。
  2. 使用平均索引(前缀总和数组的一半)填充索引数组(在单个SIMD寄存器中)。
  3. 对索引寄存器的每个字节(并行)执行二进制搜索以获取正确的索引。这可以通过使用PSHUFB指令提取前缀和寄存器的适当字节,使用PCMPGTB(以及可选地使用PCMPEQB)将提取的前缀值与字节数进行比较,然后加上/减去索引范围的一半来完成。
  4. (可选)用0xff填充索引寄存器的所有未使用字节。
  5. 使用PSHUFB使用索引寄存器索引的簇值数组中的值填充某些寄存器。
  6. 算法的主循环(二进制搜索)包含PSHUFB,PCMPGTB以及一些算术和逻辑运算。它执行log(input_array_size)次,很可能是2或3次。

    以下是一个例子:

    cluster value:      10 20 30 40
    cluster length:      3  2  1  2
    prefix sum:          0  3  5  6  8
    indexes:             2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
    prefix value:        5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5
    byte number:         0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
    mask:               ff ff ff ff ff  0  0  0  0  0  0  0  0  0  0  0
    indexes:             1  1  1  1  1  3  3  3  3  3  3  3  3  3  3  3
    prefix value:        3  3  3  3  3  6  6  6  6  6  6  6  6  6  6  6
    byte number:         0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
    mask:               ff ff ff  0  0 ff  0  0  0  0  0  0  0  0  0  0
    indexes:             0  0  0  1  1  2  3  3  3  3  3  3  3  3  3  3
    length constrained:  0  0  0  1  1  2  3  3 ff ff ff ff ff ff ff ff
    cluster value:      10 10 10 20 20 30 40 40  0  0  0  0  0  0  0  0