我需要在RISC-V上处理bignum计算(加法和减法,但我将减法视为等同于有符号加法),情况有点复杂。我从半个小时的互联网研究中收集到的信息:
- RISC-V操作不提供检查进位或溢出的方法
- 这一决定的动机是,标志或其他处理它的方法给乱序微架构增加了很多复杂性。
- 相反,他们建议做分行后
- 对于无符号加法,溢出处理可以用一个
bltu
来完成。 - 如果其中一个操作数的符号已知,则对有符号加法也是如此
- 否则,需要执行两次检查(三个附加指令)
- 互联网上的人们对此感到愤怒(我不会在这里链接)
据我所知,这些分支确实很好地覆盖了大多数场景,除了一个:bignum addition(签名)因为在那里,我们遇到了热循环中最慢的检查路径。
我对伊萨设计只知道一点点,但是为什么他们不包括一个计算(a + b) >> 32
的指令(有效地执行)?有点像乘法指令如何被分成mul
和mulh
。这将允许总是用两个指令进行所需的计算。更强大的微架构甚至可以检测序列,只做一次加法。
我是否错过了一些技巧,使这条指令过时(或等同于它)?它是否有任何重大的缺点,我监督?我没有找到很多关于这个主题的好文档。
1条答案
按热度按时间iszxjhcz1#
add
/sltu
给你求和和进位:https://godbolt.org/z/Y7f5dzj1P显示GCC使用它进行无符号数学:sum=a+b
/carry = sum<a
。或用于__builtin_uadd_overflow
但问题是缺乏ILP:在
add
结果准备好之前,sltu
不能启动。如果你能像你提议的那样直接从输入中得到执行,这个问题就可以解决;说得好当然,ADD/SLTU的融合也可以解决这个问题;也许这就是建筑师的想法在创建一条根据2输入加法的进位输出产生
0
或1
输出的指令时,我没有看到任何CPU设计挑战。那很容易构建32或64位加法器以支持X1 M9 N1 X指令的任何方式都可以容易地从高位产生进位输出信号。事实上,这可能就是sltu
读取的内容,因为整数ALU使用单个binary adder-subtractor是正常的,其中一个输入为NOT,一个进位为1
来实现减法。(低位是全加器而不是半加器,否则是正常的二进制加法器。对于大于2个reg-width的bignum,另一个主要问题是执行带进位-in 的加法(在带有进位标志和带进位加法指令的ISA上)。
更糟糕的是,从3个输入的加法中得到进位。(其中的任何一部分都可以 Package ,所以AFAIK不可能将其合并组合成一个add和比较。这是
adc
的纯C实现的一个常见缺陷;在这个链接的答案上的注解有工作C,但它编译效率不高)。除非有一些我不知道的技巧,我想这就是人们对Bignum的RISC-V和MIPS等无标志设计感到不安的原因。
更新:Alfredola的答案显示了纯C语言,clang将编译成x86-64的
add/adc/adc/adc
链或其他带有进位加法指令的ISA。对于RV 64(https://godbolt.org/z/oaevGs67q),看起来我们得到了2xsltu
和3xadd
,每个加法步骤都有进位和进位。我不知道这是否是最佳的,clang目前只支持RV 64的_BitInt(128)
,我没有检查https://gmplib.org/mpn
手写asm。