长整数例程可以从SSE中受益吗?

时间:2012-01-15 01:54:29

标签: performance integer sse bignum arbitrary-precision

我仍在使用C ++中任意长整数的例程。到目前为止,我已经为64位Intel CPU实现了加/减和乘法。

一切正常,但我想知道我是否可以通过使用SSE来加快速度。我浏览了SSE文档和处理器指令列表,但我找不到任何我认为可以使用的内容,这就是原因:

  • SSE有一些整数指令,但大多数指令处理浮点数。看起来它不是设计用于整数(例如,是否有较小的整数比较?)

  • SSE的想法是SIMD(相同指令,多个数据),因此它提供了2或4个独立操作的指令。另一方面,我希望有一个像128位整数加(128位输入和输出)的东西。这似乎不存在。 (然而?在AVX2中可能?)

  • 整数加法和减法既不处理输入也不处理输出。因此,手动操作非常麻烦(因而也很慢)。

我的问题是:我的评估是正确的还是我忽略了什么?长整数例程可以从SSE中受益吗?特别是,他们可以帮我写一个更快的添加,分或更常规吗?

1 个答案:

答案 0 :(得分:25)

在过去,这个问题的答案是坚实的,“不”。但截至2017年,情况正在发生变化。

但在我继续之前,需要一些背景术语:

  1. 全字算术
  2. 部分字算术

  3. 全字算术:

    这是标准表示,其中数字使用32位或64位整数数组存储在基数2 32 或2 64 中。 许多bignum库和应用程序(包括GMP)都使用此表示形式。

    在全字表示中,每个整数都有唯一的表示。比较等操作很简单。但是由于需要进行传播,因此像添加这样的东西会更加困难。

    正是这种进位传播使得bignum算术几乎不可能进行矢量化。


    部分字算术

    这是一种较少使用的表示,其中数字使用小于硬件字大小的基数。例如,在每个64位字中只放置60位。或者使用带有32位字大小的基数1,000,000,000进行十进制算术。

    GMP的作者称之为“钉子”,其中“钉子”是该词的未使用部分。

    过去,部分字算法的使用主要限于在非二进制基础上工作的应用程序。但是现在,它变得越来越重要,因为它允许延迟传输传播。


    全字算术问题:

    传统的全字算术历来是一个失败的原因:

    1. SSE / AVX2不支持进位传播。
    2. SSE / AVX2没有128位add / sub。
    3. SSE / AVX2没有64 x 64位整数乘法。*
    4. * AVX512-DQ增加了一个下半部64x64位乘法。但是仍然没有上半部分指令。

      此外,x86 / x64有很多专门用于bignums的标量指令:

      • Add-with-Carry:adcadcxadox
      • 双字乘法:单操作数mulmulx
      鉴于此,SIMD在x64上难以击败标量,因此bignum-add和bignum-multiply都很难。绝对不是SSE或AVX。

      对于AVX2,SIMD几乎与标量bignum-multiply竞争,如果你重新排列数据,以便在4个中的每一个中实现相同长度的4个不同(和独立)乘法的“垂直矢量化” SIMD车道。

      AVX512会在假设垂直矢量化的情况下再次使用SIMD。

      但是在大​​多数情况下,bignums的“水平矢量化”在很大程度上仍然是一个失败的原因,除非你有很多(相同大小)并且可以承担转置它们以使它们“垂直”的成本。


      部分字算术的矢量化

      使用部分字算法,额外的“钉子”位使您能够延迟进位传播。

      因此,只要你没有溢出这个词,SIMD add / sub就可以直接完成。在许多实现中,部分字表示使用有符号整数来允许单词变为负数。

      因为(通常)不需要执行进位,所以可以在垂直和水平矢量化的bignums上同等有效地完成部分单词的SIMD加/减。

      在水平矢量化的bignums上进行仍然很便宜,因为你只需将指甲移到下一个车道上。除非你需要对两个几乎相同的数字进行比较,否则通常没有必要完全清除指甲位并获得独特的表示。

      由于需要处理指甲位,因此乘法对于部分字算法更为复杂。但是与add / sub一样,它仍然可以在水平矢量化的bignums上有效地进行。

      AVX512-IFMA(与Cannonlake处理器配合使用)将提供指令,提供52 x 52位乘法的全部104位(可能使用FPU硬件)。对于每个字使用52位的部分字表示,这将非常有效。


      使用FFT的大型乘法

      对于非常大的bignums,使用Fast-Fourier Transforms (FFTs)最有效地完成乘法。

      FFT完全可以矢量化,因为它们可以在独立的double上工作。这是可能的,因为从根本上说,FFT使用的表示是 部分单词表示。


      总而言之,可以进行bignum算术的矢量化。但必须做出牺牲。

      如果您希望SSE / AVX能够在不对表示和/或数据布局进行根本性更改的情况下加速某些现有的bignum代码,则不太可能发生这种情况。

      但是,bignum算术可以进行矢量化。


      披露:

      我是y-cruncher的作者,它有很多大量的arihmetic。