check if carry flag is set

后端 未结 4 2166
北海茫月
北海茫月 2020-12-18 22:25

Using inline assembler [gcc, intel, c], how to check if the carry flag is set after an operation?

4条回答
  •  挽巷
    挽巷 (楼主)
    2020-12-18 23:11

    However the x86 assembler hes dedicated fast ALU flag test instructions named SETcc where the cc is desired ALU flag. So you can write:

    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
    

    With SETcc instruction you can test flags like carry, zero, sign, overflow or parity, some SETcc instructions allow to test two flags at once.

    EDIT: Added simple test made in Delphi to disappear a doubt about term fast

    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;
    

    The loop (1M iterations) wich using instruction setc is more than 5 times faster than loop with adc instriuction.

    EDIT: Added second test which test result stored in register AL comulative in register CL to be more realistic case.

    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;
    

    Rutine part with SETcc instruction is still faster for about 20%.

提交回复
热议问题