【问题标题】:RolDWord Implementation in Delphi (both 32 and 64 bit)?Delphi 中的 RolDWord 实现(32 位和 64 位)?
【发布时间】:2017-01-05 11:18:18
【问题描述】:

根据 http://www.freepascal.org/docs-html/rtl/system/roldword.html

RolDWord 将一个 4 字节的 int 向左旋转(Free Pascal)。

Delphi 中有 RolDWord 吗?

【问题讨论】:

    标签: delphi


    【解决方案1】:

    您可以使用这些功能:

    function rolw(Value: Word; N: Integer): Word;
    asm
    {$IF Defined(CPUX86)}
      MOV  CL, DL
      ROL  AX, CL
    {$ELSEIF Defined(CPUX64)}
      MOV  AX, CX
      MOV  CL, DL
      ROL  AX, CL
    {$ELSE}
    {$Message Fatal 'rolw has not been implemented for this architecture.'}
    {$ENDIF}
    end;
    
    function rorw(Value: Word; N: Integer): Word;
    asm
    {$IF Defined(CPUX86)}
      MOV  CL, DL
      ROR  AX, CL
    {$ELSEIF Defined(CPUX64)}
      MOV  AX, CX
      MOV  CL, DL
      ROR  AX, CL
    {$ELSE}
    {$Message Fatal 'rorw has not been implemented for this architecture.'}
    {$ENDIF}
    end;
    
    function roldw(Value: Cardinal; N: Integer): Cardinal;
    asm
    {$IF Defined(CPUX86)}
      MOV  CL, DL
      ROL  EAX, CL
    {$ELSEIF Defined(CPUX64)}
      MOV  EAX, ECX
      MOV  CL, DL
      ROL  EAX, CL
    {$ELSE}
    {$Message Fatal 'roldw has not been implemented for this architecture.'}
    {$ENDIF}
    end;
    
    function rordw(Value: Cardinal; N: Integer): Cardinal;
    asm
    {$IF Defined(CPUX86)}
      MOV  CL, DL
      ROR  EAX, CL
    {$ELSEIF Defined(CPUX64)}
      MOV  EAX, ECX
      MOV  CL, DL
      ROR  EAX, CL
    {$ELSE}
    {$Message Fatal 'rordw has not been implemented for this architecture.'}
    {$ENDIF}
    end;
    

    然而,正如JohanLU RD 指出的那样,内联Pascal 版本是可移植的,并且通常对于此功能更快,因为内联对于如此小的功能非常重要。

    看起来像这样:

    {$IFOPT Q+}{$DEFINE OVERFLOWCHECKSON}{$ENDIF}
    {$Q-}    
    function rolw_pas(Value: Word; N: Integer): Word; inline;
    begin
      Result:= ((Value shl N) and $ffff) or (Value shr (16-N));
    end;
    
    function rorw_pas(Value: Word; N: Integer): Word; inline;
    begin
      Result:= (Value shr N) or ((Value shl (16-N)) and $ffff);
    end;
    
    function roldw_pas(Value: Cardinal; N: Integer): Cardinal; inline;
    begin
      Result:= (Value shl N) or (Value shr (32-N));
    end;
    
    function rordw_pas(Value: Cardinal; N: Integer): Cardinal; inline;
    begin
      Result:= (Value shr N) or (Value shl (32-N));
    end;
    {$IFDEF OVERFLOWCHECKSON}{$Q+}{$ENDIF}
    

    请注意,我们确实需要确保禁用溢出检查。

    【讨论】:

    • 为什么不包括 purepascal 版本?
    • @Johan 我最初有一个 Pascal 版本,但我想我改变了,因为使用硬件提供的指令感觉更干净。
    • 看来纯帕斯卡解决方案更快。请参阅我对约翰回答的评论。
    • @LURD 这很有趣。不过我想看看基准代码。基准总是有可能是错误的。当然,没想到会是这样。
    • var sw: TStopWatch; dw,dw1:双字; i:整数;开始 dw := 2; sw := TStopWatch.StartNew; for i := 1 to 1000000000 do begin dw1 := roldw(dw,31);结尾; WriteLn(sw.ElapsedMilliseconds, ' ',dw1); sw := TStopWatch.StartNew; for i := 1 to 1000000000 do begin dw1 := roldwPPInline(dw,31);结尾; WriteLn(sw.ElapsedMilliseconds, ' ',dw1);读入;结束。
    【解决方案2】:

    在 purepascal 中,您可以按如下方式使用移位。

    function rolw(input: dword; shift: cardinal): dword; inline;
    begin
      Result:= (input shl shift) or (input shr (32-shift));
    end;
    

    RorW 的工作原理完全相同。

    好处
    它适用于任何版本的 Delphi,包括移动编译器。

    asm 代码实际上更慢,因为它不能被内联,根据 LURD 的时间(在他的系统和他的输入数据上),纯 pascal 版本在 x86 上快 3.5 倍,在 x64 上快 25%。但是对于不同的输入数据,时间可能会完全不同,所以如果性能是一个驱动因素,请确保您使用代表您实际问题的数据进行基准测试。

    源代码更短,因为您不需要针对不同 CPU 类型的不同版本。

    如果你有一个更大的 asm 块,一定要使用 ror/rol 指令;它们具有与移位指令完全相同的延迟,但在 1 条指令而不是 3 条指令中执行操作。

    【讨论】:

    • 我相信单个操作的性能会更快,而不是内联三个操作
    • 1 个 asm 操作实际上是 3 个操作:调用 asm 例程;罗;退休。该调用从返回预测堆栈中刷新一个条目(通常为 6 到 8 深(原子上为 2 个)。如果情况不是最佳的,该调用将导致延迟。这 3 个语句不会受到此影响。
    • 如果 shift > 32,您可能还需要shift := shift mod 32
    • 对于 x32,purepascal 解决方案快 3.5 倍,而在 x64 中快 25%。
    • @LU 我认为 shl 33 与 shl 1 相同,对吗?有趣的 x86 实现细节。
    猜你喜欢
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2012-07-25
    • 2019-03-25
    • 2012-10-26
    • 1970-01-01
    相关资源
    最近更新 更多