即使使用SSE,GCC也会模拟__int128_t算术吗?

Dou*_*ple 8 c x86 gcc sse int128

我听说__int128_tGCC提供的128位整数数据类型 是模拟的,因此很慢.不过,据我所知,各种SSE指令集(SSE,SSE2,...,AVX)推出了128位寄存器至少一些指令.我不太了解SSE或汇编/机器代码,所以我想知道是否有人可以向我解释是否__int128_t使用现代版本的GCC模拟算术运算.

我问这个的原因是因为我想知道__int128_t在不同版本的GCC之间是否期望性能差异是有意义的,这取决于SSE指令的优势.

那么,__int128_tGCC会模拟哪些算术部分,以及哪些部分是用SSE指令实现的(如果有的话)?

Dou*_*ple 12

在我的问题中,我混淆了两件不同的事情.

首先,正如PaulR在评论中所解释的那样:"在SSE或AVX中没有128位算术运算(除了按位运算)".考虑到这一点,必须在现代基于x86-64的处理器(例如AMD Family 10或Intel Core架构)上模拟128位算术.这与GCC无关.

问题的第二部分是GCC中的128位算术仿真是否受益于SSE/AVX指令或寄存器.正如PaulR的评论所暗示的那样,SSE/AVX中没有太多可以让你更容易地进行128位算术; 最有可能的x86-64指令将用于此目的.我感兴趣的代码无法编译-mno-sse,但编译得很好,-mno-sse2 -mno-sse3 -mno-ssse3 -mno-sse4 -mno-sse4.1 -mno-sse4.2 -mno-avx -mno-avx2性能不受影响.所以我的代码没有受益于现代SSE指令.


MBo*_*MBo 5

SSE2-AVX指令适用于8,16,32,64位整数数据类型.它们主要用于将打包数据一起处理,例如,128位寄存器可能包含四个32位整数,依此类推.

  • 这实际上很好地解释了[维基百科](https://en.wikipedia.org/wiki/128-bit):"大多数现代CPU都具有SIMD指令集(SSE,AltiVec等),其中128位向量寄存器是用于存储几个较小的数字,例如四个32位浮点数.然后,单个指令可以并行操作所有这些值.但是,这些处理器不能对长度为128位二进制数字的单个数字进行操作,仅它们的寄存器大小为128位." (3认同)

DrY*_*Yak 5

虽然SSE/AVX/AVX512 /等.没有128位模式(它们的向量元素严格为64位,操作只会溢出),正如 Paul R暗示的那样,主CPU 通过使用一对寄存器确实支持有限的128位操作.

  • 当两个常规64位数相乘时,MUL/IMUL可以在RAX/RDX寄存器对中输出其128位结果.
  • 相反,当分割DIV/IDIV时,可以从RAX/RDX对中获取其输入,将128位数除以64位除数(并输出64位商+ 64位模数)

当然CPU的ALU是64位,因此 - 正如暗示的英特尔文档 - 这些更高的额外64位是以微代码中的额外微操作为代价的.这对于已经需要处理大量微操作的部门(> 3倍以上)来说更为显着.

仍然这意味着在某些情况下(比如使用三个规则来缩放值),编译器可能会发出常规CPU指令而不关心自己做任何128位仿真.

这已经有很长一段时间了:

  • 从80386开始,32位CPU可以使用EAX:EDX对进行64位乘法/除法
  • 从8086/88开始,16位CPU可以使用AX:DX对进行32位乘法/除法

(至于添加和减法:感谢对携带的支持,对任何可以填充存储空间的任意长度的数量进行添加/减少是完全无足轻重的).

  • @PascalCuoq:我碰巧在英特尔看了时间. - 根据您读回64bits x 64bits = 64bits或64bits x 64bits = 128bits的结果,CPU上的64位MUL指令不会花费相同的时间.这些额外的位需要额外的时间(更确切地说,RDX中的高值仅比RAX中的第一个低64位可用).(仅适用于128位结果.32位的64位结果不会这样做.因此额外的周期由额外的位引起,而不是跨越2个寄存器). (2认同)
  • "在ISA中只有一个64位GPR操作数的乘法"实际上没有.ISA中有几个乘法指令.其中只有一个是64x64 = 128(暗示使用RDX:RAX对作为结果),所有其他都是64x64 = 64(明确指定目标寄存器).对于高64位,128位的是唯一一个更长一个周期的.与分歧相同的情况. (2认同)