检查是否设置了进位标志

han*_*ans 13 c x86 gcc intel

使用内联汇编程序[gcc,intel,c],如何在操作后检查进位标志是否设置?

R..*_*R.. 14

sbb %eax,%eax如果进位标志设置,则将-1存储在eax中;如果清除则将0存储在eax中.没有必要预先将eax清除为0; 从中减去eax会为你做这件事.这种技术非常强大,因为您可以将结果用作位掩码来修改计算结果,而不是使用条件跳转.

您应该知道,只有通过内联asm块内部执行的算术设置才能测试进位标志.您无法测试在C代码中执行的计算的进位,因为编译器可以通过各种方式优化/重新排序会破坏进位标志的内容.


Nic*_*kis 10

使用条件跳转jc(如果进位则跳转)或jnc(如果不进位则跳转).

或者你可以存储进位标志,

;; Intel syntax
mov eax, 0
adc eax, 0 ; add with carry
Run Code Online (Sandbox Code Playgroud)


GJ.*_*GJ. 5

然而,x86汇编程序专用快速 ALU标志测试指令名为SETcc,其中cc是期望的ALU标志.所以你可以写:

setc    AL                           //will set AL register to 1 or clear to 0 depend on carry flag

or

setc    byte ptr [edx]               //will set memory byte on location edx depend on carry flag

or even

setc    byte ptr [CarryFlagTestByte]  //will set memory variable on location CarryFlagTestByte depend on carry flag
Run Code Online (Sandbox Code Playgroud)

使用SETcc指令可以测试进位,零,符号,溢出或奇偶校验等标志,一些SETcc指令允许一次测试两个标志.

编辑: 在德尔福提出增加简单的测试,消失约任期疑问

procedure TfrmTest.ButtonTestClick(Sender: TObject);
  function GetCPUTimeStamp: int64;
  asm
    rdtsc
  end;
var
 ii, i: int64;
begin
  i := GetCPUTimeStamp;
  asm
    mov   ecx, 1000000
@repeat:
    mov   al, 0
    adc   al, 0
    mov   al, 0
    adc   al, 0
    mov   al, 0
    adc   al, 0
    mov   al, 0
    adc   al, 0
    loop  @repeat
  end;
  i := GetCPUTimeStamp - i;

  ii := GetCPUTimeStamp;
  asm
    mov   ecx, 1000000
@repeat:
    setc  al
    setc  al
    setc  al
    setc  al
    loop  @repeat
  end;
  ii := GetCPUTimeStamp - ii;
  caption := IntToStr(i) + '  ' +  IntToStr(ii));
end;
Run Code Online (Sandbox Code Playgroud)

使用指令setc的循环(1M迭代)比使用adc instriuction的循环快5倍以上.

编辑:添加第二个测试,其中存储在寄存器CL中的寄存器AL中的测试结果是更现实的情况.

procedure TfrmTestOtlContainers.Button1Click(Sender: TObject);
  function GetCPUTimeStamp: int64;
  asm
    rdtsc
  end;

var
 ii, i: int64;
begin
  i := GetCPUTimeStamp;
  asm
    xor   ecx, ecx
    mov   edx, $AAAAAAAA

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

    shl   edx, 1
    mov   al, 0
    adc   al, 0
    add   cl, al

  end;
  i := GetCPUTimeStamp - i;

  ii := GetCPUTimeStamp;
  asm
    xor   ecx, ecx
    mov   edx, $AAAAAAAA

    shl   edx, 1
    setc  al
    add   cl, al

    shl   edx, 1
    setc  al
    add   cl, al

    shl   edx, 1
    setc  al
    add   cl, al

    shl   edx, 1
    setc  al
    add   cl, al

    shl   edx, 1
    setc  al
    add   cl, al

    shl   edx, 1
    setc  al
    add   cl, al

    shl   edx, 1
    setc  al
    add   cl, al

    shl   edx, 1
    setc  al
    add   cl, al

  end;
  ii := GetCPUTimeStamp - ii;
  caption := IntToStr(i) + '  ' +  IntToStr(ii);
end;
Run Code Online (Sandbox Code Playgroud)

使用SETcc指令的Rutine部分仍然更快,约20%.