为了账号安全,请及时绑定邮箱和手机立即绑定

在某些CPU上的紧密循环中ADC / SBB和INC / DEC的问题

在某些CPU上的紧密循环中ADC / SBB和INC / DEC的问题

我在Delphi中编写一个简单的BigInteger类型。它主要由一个动态数组TLimb组成,其中TLimb是一个32位无符号整数,以及一个32位大小的字段,该字段还保存BigInteger的符号位。要添加两个BigInteger,我创建了一个适当大小的新BigInteger,然后进行了一些记账,然后调用以下过程,向其传递三个指针,分别指向左右操作数及其结果的数组的开头,以及左右肢的数量。简码:class procedure BigInteger.PlainAdd(Left, Right, Result: PLimb; LSize, RSize: Integer); asm// EAX = Left, EDX = Right, ECX = Result         PUSH    ESI         PUSH    EDI         PUSH    EBX         MOV     ESI,EAX                 // Left         MOV     EDI,EDX                 // Right         MOV     EBX,ECX                 // Result         MOV     ECX,RSize               // Number of limbs at Left         MOV     EDX,LSize               // Number of limbs at Right         CMP     EDX,ECX         JAE     @SkipSwap         XCHG    ECX,EDX                 // Left and LSize should be largest         XCHG    ESI,EDI                 // so swap@SkipSwap:         SUB     EDX,ECX                 // EDX contains rest         PUSH    EDX                     // ECX contains smaller size        XOR     EDX,EDX                   @MainLoop:         MOV     EAX,[ESI + CLimbSize*EDX]  // CLimbSize = SizeOf(TLimb) = 4.         ADC     EAX,[EDI + CLimbSize*EDX]         MOV     [EBX + CLimbSize*EDX],EAX         INC     EDX         DEC     ECX         JNE     @MainLoop         POP     EDI                                 INC     EDI                        // Do not change Carry Flag         DEC     EDI         JE      @LastLimb@RestLoop:         MOV     EAX,[ESI + CLimbSize*EDX]         ADC     EAX,ECX         MOV     [EBX + CLimbSize*EDX],EAX         INC     EDX         DEC     EDI         JNE     @RestLoop@LastLimb:这段代码很好用,我对此非常满意,直到我注意到,在我的开发设置(iMac上的Parallels VM中为Win7)上,有一个简单的PURE PASCAL加法例程,在用变量和一些if条款,是更快的比我的平淡,简单的手工制作的汇编程序。我花了一段时间才发现,在某些CPU(包括我的iMac和较旧的笔记本电脑)上,DECor INC和ADCor 的组合SBB可能非常慢。但是,在我的大多数其他计算机上(我还有五台PC可以对其进行测试,尽管其中四台完全相同),但是速度却相当快。这使我在“慢速”计算机上的代码快了将近三倍,但在“更快”计算机上的代码却慢了约20%。因此,现在,作为初始化代码,我做了一个简单的定时循环,并用它来决定是否将单元设置为调用普通程序或仿真例程。这几乎总是正确的,但是有时它会在应该选择仿真例程的情况下选择(较慢的)普通例程。但是我不知道这是否是最好的方法。
查看完整描述

3 回答

?
烙印99

TA贡献1829条经验 获得超13个赞

我终于有一些时间来实现单寄存器寻址模式。对于很长的BigIntegers,这相差约12%(总体速度提高)。我认为现在没有什么可以挤出的了。我尝试使用更小的BigIntegers(最多1到10个肢体,平均约3个肢体),并且与简单的简单循环没有明显的时序差异,因此我将使用优化的展开循环例程(即,最后一个版本)作为替换。它变得不那么容易阅读,因此我不得不添加一些其他注释。<g>

查看完整回答
反对 回复 2019-09-26
  • 3 回答
  • 0 关注
  • 563 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信