相关疑难解决方法(0)

如何使用SIMD实现atoi?

我想尝试使用SIMD指令编写atoi实现,包含在RapidJSON(C++ JSON /写库)中.它目前在其他地方有一些SSE2和SSE4.2优化.

如果是速度增益,atoi则可以并行执行多个结果.字符串最初来自JSON数据的缓冲区,因此多atoi函数将不得不进行任何所需的调配.

我想出的算法如下:

  1. 我可以用以下方式初始化长度为N的向量:[10 ^ N..10 ^ 1]
  2. 我将缓冲区中的每个字符转换为整数并将它们放在另一个向量中.
  3. 我将有效数字向量中的每个数字乘以数字向量中的匹配数,并将结果相加.

我的目标是x86和x86-64架构.

我知道AVX2支持三个操作数Fused Multiply-Add,所以我将能够执行Sum = Number*有效数字+和.
那是我到目前为止的地方.
我的算法是否正确?有没有更好的办法?
是否有使用任何SIMD指令集的atoi参考实现?

c++ x86 sse simd atoi

25
推荐指数
2
解决办法
3598
查看次数

AVX2中的VPERMB在哪里?

AVX2有很多好东西.例如,它有很多指令,它们比它们的前体更加强大.Take VPERMD:它允许您从一个256位长的32位值向量中完全任意地广播/混洗/置换到另一个,并且在运行时1可以选择置换.在功能上,它废除了大量现有的旧解包,广播,置换,随机和移位指令3.

凉豆.

那么在哪里VPERMB?即,相同的指令,但在字节大小的元素上工作.或者,就此而言,VPERMW对于16位元素,在哪里?已经涉足x86程序集已经有一段时间了,很明显SSE PSHUFB指令几乎是有史以来最有用的指令之一.它可以进行任何可能的排列,广播或逐字节混洗.此外,它还可用于执行16个并行4位 - > 8位表查找2.

不幸的是,PSHUFB在AVX2中没有延伸到跨车道,所以它仅限于车道内行为.该VPERM指令能够做到跨洗牌(事实上,"烫发"和"SHUF"似乎是在指令助记符同义词?) -但被省略了8位和16位版本?

甚至似乎没有一种好的方法来模拟这个指令,而你可以轻松地模拟宽度较小的shuffles(通常,它甚至是免费的:你只需要一个不同的掩码).

我毫不怀疑英特尔已经意识到它的广泛使用PSHUFB,因此自然会出现为什么在AVX2中省略字节变体的问题.操作本质上难以在硬件中实现吗?是否有编码限制迫使其遗漏?


1通过在运行时选择,我的意思是定义混洗行为的掩码来自寄存器.这使得指令比采用立即随机掩码的早期变体更灵活,其方式与add更灵活的inc变换相比,或者变量比立即变换更灵活.

2或AVX2中的32个此类查找.

3较旧的指令偶尔会有用,如果它们的编码较短,或者避免从内存中加载掩码,但在功能上它们会被取代.

x86 assembly sse intel avx2

11
推荐指数
1
解决办法
1104
查看次数

将散点索引转换为聚集索引的有效方法?

我正在尝试使用SIMD内在函数编写流压缩(获取数组并删除空元素).循环的每次迭代一次处理8个元素(SIMD宽度).

使用SSE内在函数,我可以使用_mm_shuffle_epi8()进行相当有效的操作,它执行16条表查找(收集并行计算术语).shuffle索引是预先计算的,并使用位掩码查找.

for (i = 0; i < n; i += 8)
{
  v8n_Data = _mm_load_si128(&data[i]);
  mask = _mm_movemask_epi8(&is_valid[i]) & 0xff;     // is_valid is byte array
  v8n_Compacted = _mm_shuffle_epi8(v16n_ShuffleIndices[mask]);
  _mm_storeu_si128(&compacted[count], v8n_Compacted);

  count += bitCount[mask];
}
Run Code Online (Sandbox Code Playgroud)

我的问题是现在我想为Altivec SIMD实现这个(不要问为什么 - 错误的商业决策).Altivec没有_mm_movemask_epi8()的等价物,这是一个关键因素.所以,我需要找到一种方法

  1. 模拟_mm_movemask_epi8() - 似乎很贵,有几个班次和OR

  2. 直接生成有效的shuffle指数 -

即,索引i将是未压缩数据中第i个有效元素的索引

element_valid:   0 0 1 0 1 0 0 1 0
gather_indices:  x x x x x x 6 4 1
scatter_indices: 3 3 2 2 1 1 1 0 0
Run Code Online (Sandbox Code Playgroud)

串行执行此操作非常简单,但我需要它是并行(SIMD).使用前缀sum生成散列索引似乎很容易,但由于AltiVec和SSE都没有散点指令,我需要收集索引.收集索引是散射指数的反函数,但是如何并行获得?我知道在GPU编程的开创性时代,将散射转换为收集是一种常见的技术,但这两种方法中没有一种看似实用.

也许如果不坚持压缩保留元素顺序将允许更有效的实现?我可以放弃.

sse simd vectorization altivec stream-compaction

8
推荐指数
1
解决办法
2081
查看次数

我可以使用 SIMD 来加速字符串操作吗?

SIMD 指令是否仅用于矢量数值计算?或者它是否适合一类字符串操作任务,例如将数据行写入文本文件,其中行的顺序无关紧要?如果是这样,我应该从哪些 API 或库开始?

c c++ string optimization simd

8
推荐指数
3
解决办法
672
查看次数

sse/avx相当于霓虹灯vuzp

英特尔的矢量扩展SSE,AVX等为每个元素大小提供了两个解包操作,例如SSE内在函数是_mm_unpacklo_*_mm_unpackhi_*.对于向量中的4个元素,它执行此操作:

inputs:      (A0 A1 A2 A3) (B0 B1 B2 B3)
unpacklo/hi: (A0 B0 A1 B1) (A2 B2 A3 B3)
Run Code Online (Sandbox Code Playgroud)

解压缩的等价物vzip在ARM的NEON指令集中.但是,NEON指令集也提供了与之vuzp相反的操作vzip.对于向量中的4个元素,它执行此操作:

inputs: (A0 A1 A2 A3) (B0 B1 B2 B3)
vuzp:   (A0 A2 B0 B2) (A1 A3 B1 B3)
Run Code Online (Sandbox Code Playgroud)

如何vuzp使用SSE或AVX内在函数有效实现?似乎没有针对它的指示.对于4个元素,我假设它可以使用shuffle和随后的unpack移动2个元素来完成:

inputs:        (A0 A1 A2 A3) (B0 B1 B2 B3)
shuffle:       (A0 A2 A1 A3) (B0 B2 B1 B3)
unpacklo/hi 2: (A0 A2 B0 B2) (A1 A3 B1 B3)
Run Code Online (Sandbox Code Playgroud)

使用单个指令是否有更高效的解决方案?(也许对于SSE优先 …

sse simd avx neon

5
推荐指数
1
解决办法
709
查看次数

计算__mm256向量中非零项数的最快方法是什么?

我编写了一个算法,使用Intel内部函数并行执行多个单精度操作.我的算法的每次迭代的结果是单个256位向量(__m256)中的非零项的数量.

例如:

 00000000  FFFFFFFF  00000000  00000000  00000000  FFFFFFFF  FFFFFFFF  FFFFFFFF
Run Code Online (Sandbox Code Playgroud)

其中迭代的结果是4.

计算向量中非零项数的最快方法是什么?

目前我正在做这样的事情:

float results[8];
_mm256_storeu_ps(results, result_vector);

int count = 0;
for (uint32_t idx = 0; idx < 8; ++idx)
{
    if (results[idx] != 0)
    {            
        ++count;
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法运行得很好,但我想知道是否有更有效的方法来做,也许是一个不涉及商店的方法.

algorithm vector simd avx avx2

5
推荐指数
1
解决办法
474
查看次数

在内存中交换未对齐的 64 位值的字节的最快方法是什么?

我在内存中有大量 64 位值。不幸的是,它们可能不会与 64 位地址对齐。我的目标是改变所有这些值的字节序,即交换/反转它们的字节。

我知道bswap交换 32 位或 64 位寄存器字节的指令。但是因为它需要一个寄存器参数,所以我不能将它传递给我的内存地址。当然我可以先将内存加载到寄存器中,然后交换,然后写回:

mov rax, qword [rsi]
bswap rax
mov qword [rsi], rax
Run Code Online (Sandbox Code Playgroud)

但这是否正确,因为地址可能未对齐?

另一种可能性是手动进行交换:

mov al, byte [rsi + 0]
mov bl, byte [rsi + 7]
mov byte [rsi + 0], bl
mov byte [rsi + 7], al

mov al, byte [rsi + 1]
mov bl, byte [rsi + 6]
mov byte [rsi + 1], bl
mov byte [rsi + 6], al

mov al, byte [rsi + 2]
mov bl, …
Run Code Online (Sandbox Code Playgroud)

performance assembly x86-64 endianness micro-optimization

5
推荐指数
1
解决办法
510
查看次数

通过 avx 指令向量化间接访问

我最近被介绍了向量指令(理论上)并且对如何使用它们来加速我的应用程序感到兴奋。

我想改进的一个方面是一个非常热的循环:

__declspec(noinline) void pleaseVectorize(int* arr, int* someGlobalArray, int* output)
{
    for (int i = 0; i < 16; ++i)
    {
        auto someIndex = arr[i];
        output[i] = someGlobalArray[someIndex];
    }

    for (int i = 0; i < 16; ++i)
    {
         if (output[i] == 1)
         {
             return i;
         }
    }

    return -1;
}
Run Code Online (Sandbox Code Playgroud)

但是,当然,所有 3 个主要编译器(msvc、gcc、clang)都拒绝对此进行矢量化。我可以理解为什么,但我想得到确认。

如果我必须手动矢量化它,它将是:

(1) VectorLoad "arr", 这带来了 16 个 4 字节整数,让我们说到 zmm0

(2) 16个内存从zmm0[0..3]指向的地址加载到zmm1[0..3],从zmm0[4..7]指向的地址加载到zmm1[4..7]所以等等

(3)比较zmm0和zmm1

(4) 向量 popcnt 到输出中找出最高有效位并基本上除以 8 得到匹配的索引

首先,向量指令可以做这些事情吗?就像他们可以执行这种“收集”操作,即从指向 zmm0 的地址加载?

以下是 clang 生成的内容:

0000000000400530 …
Run Code Online (Sandbox Code Playgroud)

c++ simd vectorization compiler-optimization avx512

3
推荐指数
1
解决办法
697
查看次数

比较AVX/AVX2中的2个向量(c)

我有两个__m256i向量(每个包含字符),我想知道它们是否完全相同.我需要的只是true所有位都相等,0否则.

这样做最有效的方法是什么?这是加载数组的代码:

char * a1 = "abcdefhgabcdefhgabcdefhgabcdefhg";
__m256i r1 = _mm256_load_si256((__m256i *) a1);

char * a2 = "abcdefhgabcdefhgabcdefhgabcdefhg";
__m256i r2 = _mm256_load_si256((__m256i *) a2);
Run Code Online (Sandbox Code Playgroud)

c simd avx avx2

2
推荐指数
1
解决办法
1655
查看次数

从程序员的角度来看,"新"处理器中的"新"是什么

我最近对理解低级计算很感兴趣.据我所知,今天广泛使用的计算机遵循x86/x86-64架构.

据我所知,架构,更具体地说,指令集架构(ISA)是程序员能够向CPU发出的指令集.

第一个问题,ISA是不断发展还是保持不变?

我认为它不断发展(意味着新指令不断被添加/先前的指令被修改?)但是旧的处理器如何能够执行用新指令编写的代码?(它不知道新的指令,但应该能够执行代码,因为它具有x86架构).编译器是处理这个东西还是处理器?基本上,相同的指令集如何能够在所有处理器上运行,无论是旧的还是新的?

最后,除了微体系结构,这不是程序员的关注(如果我错了,请纠正我),程序员在处理新处理器时会看到哪些变化?由于微体系结构的变化,旧的指令可能因为有效的实现而快速运行.但是,是否引入了新的指令以允许以前无法完成的操作?或者之前可以用一堆指令做什么,但现在可以通过硬件的变化来完成一个?新的寄存器?还要别的吗?

它是否完成了 - 如果处理器支持这个新的强大指令以加快执行速度,那么使用新指令,否则回退到较慢的旧指令.如果是,谁实现了这个if - else子句?编译器?如果不是,那会发生什么?

x86 x86-64 processor cpu-architecture micro-architecture

0
推荐指数
1
解决办法
79
查看次数