在某些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 INCADCor 的组合SBB可能非常慢。但是,在我的大多数其他计算机上(我还有五台PC可以对其进行测试,尽管其中四台完全相同),但是速度却相当快。

这使我在“慢速”计算机上的代码快了将近三倍,但在“更快”计算机上的代码却慢了约20%。因此,现在,作为初始化代码,我做了一个简单的定时循环,并用它来决定是否将单元设置为调用普通程序或仿真例程。这几乎总是正确的,但是有时它会在应该选择仿真例程的情况下选择(较慢的)普通例程。

但是我不知道这是否是最好的方法。



素胚勾勒不出你
浏览 564回答 3
3回答

烙印99

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