Using inline assembler [gcc, intel, c], how to check if the carry flag is set after an operation?
With conditional jumps jc
(jump if carry) or jnc
(jump if not carry).
Or you can store the carry flag,
;; Intel syntax
mov eax, 0
adc eax, 0 ; add with carry
sbb %eax,%eax
will store -1 in eax if the carry flag is set, 0 if it is clear. There's no need to pre-clear eax to 0; subtracting eax from itself does that for you. This technique can be very powerful since you can use the result as a bitmask to modify the results of computations in place of using conditional jumps.
You should be aware that it is only valid to test the carry flag if it was set by arithmetic performed INSIDE the inline asm block. You can't test carry of a computation that was performed in C code because there are all sorts of ways the compiler could optimize/reorder things that would clobber the carry flag.
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%.