Are the carry flag and overflow flag always set the same in SUB operations?

Started by Matthew, October 07, 2005, 08:50:58 PM

Previous topic - Next topic

Matthew

Intel says the SUB instruction works for both signed and unsigned integers.  I'm wondering how this affects the overflow and carry flags, especially in extended subtraction.

Suppose I can operate only on one-byte operands.

Consider two values:

Value 1:  0111_1111
Value 2:  1111_1111

Suppose my program treats these as signed binary values in the two's complement format.  Then Value 1 is equal to 127 and Value 2 is equal to -1.

So, if I use SUB to subtract Value 2 from Value 1 [127 - (-1)] I should get 128, which should cause an overflow and hence set the overflow flag in EFLAGS because I cannot represent positive 128 in a single byte using two's complement format.  But there is no reason it should set the carry flag.

Of course, the SUB instruction doesn't differentiate between signed and unsigned values.  So, Value 2 could just as well represent 256.  If I use SUB to subtract Value 2 from Value 1 [127 - 256] the answer would be -128, which should cause an underflow and set the overflow flag in EFLAGS because I cannot have an unsigned value less than 0.  But again, it should not set the carry flag.

The result of the subtraction would leave 1000_0000 in AL and should set the overflow flag in EFLAGS in both cases.  Would it also set the carry flag in EFLAGS?  If so, is the carry flag always set when the overflow flag is set?  Because if the carry flag is not set then in the extended precision subtraction case, a problem could arise as follows:

Suppose I can still operate only on one byte at a time.  I want to subtract two word values:

Value 1:  0000_0001_0111_1111
Value 2:  0000_0000_1111_1111

Value 1 - Value 2, whether these operands are treated as signed or unsigned, should result in a positive number, namely 0000_0000_1000_0000.

But, if I operate one byte at a time, then there is an issue.  As discussed above, the operation on the L.O. bytes should leave 1000_0000 in whatever register I'm using and should set the overflow flag.  But unless it also sets the carry flag, when I go to operate on the H.O. byte, I'll get the wrong answer using SBB (because the carry flag won't be set).

The Intel manuals don't specify, as far as I can tell, how exactly the flags are set after a SUB operation.  They say "Carry flag — Set if an arithmetic operation generates a carry or a borrow out
of the most-significant bit of the result; cleared otherwise. This flag indicates an overflow condition for unsigned-integer arithmetic. It is also used in multiple-precision arithmetic."  And "The SUB instruction performs integer subtraction. It evaluates the result for both signed and
unsigned integer operands and sets the OF and CF flags to indicate an overflow in the signed or
unsigned result, respectively."  Does this latter statement mean that the SUB instruction always sets the carry flag when it sets the overflow flag?

Any help would be greatly appreciated.

Matthew

QvasiModo

I've never used the OF flag for anything but, from what I can tell from the Intel docs, the CF flag is set for unsigned overflows only and OF for signed overflows only.

tenkey

Basically, OF is set when the sign bit of the destination register does not match the expected sign. (-127) - 2 = -129 = 127 (truncated to 8 bits). We have signed overflow. However, -127 = 129 (unsigned 8 bits), so 129 - 2 = 127. There is no unsigned overflow (borrow).

1000 0001 = 129 or -127
0000 0010 = 2
A programming language is low level when its programs require attention to the irrelevant.
Alan Perlis, Epigram #8

Matthew

OK.  So, if I understand your answers, the hardware is built so that it sets (or clears) the OF assuming the two values are signed and it also simultaneously sets (or clears) the CF assuming the two values are unsigned.  Is that basically it?

Thank you very much for your help.

Matthew

Ratch

Matthew,

     OK, here is how it works, short 'n sweet.  The CF will be set if there is a carry out or a borrow in of the MSB (bit 7, sign bit).  The OF will be set when the carry out of bit 7 is NOT matched by a carry in from bit 6 OR a borrow in of bit 7 is NOT matched by a borrow out to bit 6.  Lets see how that works for your example.

Quote
Value 1:  0111_1111
Value 2:  1111_1111

Suppose my program treats these as signed binary values in the two's complement format.  Then Value 1 is equal to 127 and Value 2 is equal to -1.

So, if I use SUB to subtract Value 2 from Value 1 [127 - (-1)] I should get 128, which should cause an overflow and hence set the overflow flag in EFLAGS because I cannot represent positive 128 in a single byte using two's complement format.  But there is no reason it should set the carry flag.

     Bit 7 needs to borrow 1, so it IS going to set the CF.  Bit 6 did not have to borrow from bit 7, so bit 7 has a borrow in but no matching borrow out.  Up pops of OF for that operation. 

Quote
Of course, the SUB instruction doesn't differentiate between signed and unsigned values.  So, Value 2 could just as well represent 256.  If I use SUB to subtract Value 2 from Value 1 [127 - 256] the answer would be -128, which should cause an underflow and set the overflow flag in EFLAGS because I cannot have an unsigned value less than 0.  But again, it should not set the carry flag.

     Value2 represents 255 unsigned. Yes, it does set the CF for the reason stated above.  For unsigned numbers, ignore the OF and use the CF to determine if your results are valid.

Quote
The result of the subtraction would leave 1000_0000 in AL and should set the overflow flag in EFLAGS in both cases.  Would it also set the carry flag in EFLAGS?

     Yes, it will set the CF for the reason given above, not because the OF is set also.

Quote
If so, is the carry flag always set when the overflow flag is set?

     No, that is a not true.  The OF is set according to the rules I gave above.  In this instance, for this example, it is set.

Quote
But, if I operate one byte at a time, then there is an issue.  As discussed above, the operation on the L.O. bytes should leave 1000_0000 in whatever register I'm using and should set the overflow flag.  But unless it also sets the carry flag, when I go to operate on the H.O. byte, I'll get the wrong answer using SBB (because the carry flag won't be set).

     The CF will be set according to the rule I gave above.  In this instance, for this example, it will be set.

Quote
The Intel manuals don't specify, as far as I can tell, how exactly the flags are set after a SUB operation.  They say "Carry flag — Set if an arithmetic operation generates a carry or a borrow out
of the most-significant bit of the result; cleared otherwise. This flag indicates an overflow condition for unsigned-integer arithmetic. It is also used in multiple-precision arithmetic."  And "The SUB instruction performs integer subtraction. It evaluates the result for both signed and
unsigned integer operands and sets the OF and CF flags to indicate an overflow in the signed or
unsigned result, respectively."  Does this latter statement mean that the SUB instruction always sets the carry flag when it sets the overflow flag?

     Carry flag--Set if carry out or borrow in.  OF is ignored for unsigned operations.  For a SUB instruction, the CF and OF are mutually exclusive from each other.  There can be 4 different combinations.

Quote
Any help would be greatly appreciated.

     There you have it.  Ratch


tenkey

Quote from: Matthew on October 08, 2005, 12:40:05 AM
OK.  So, if I understand your answers, the hardware is built so that it sets (or clears) the OF assuming the two values are signed and it also simultaneously sets (or clears) the CF assuming the two values are unsigned.  Is that basically it?

You got it. That's basically it.
A programming language is low level when its programs require attention to the irrelevant.
Alan Perlis, Epigram #8

Ratch

tenkey,

Quote

OK.  So, if I understand your answers, the hardware is built so that it sets (or clears) the OF assuming the two values are signed and it also simultaneously sets (or clears) the CF assuming the two values are unsigned.  Is that basically it?

You got it. That's basically it.

     No, that is NOT it.  The hardware has no knowledge of, nor does it care whether the number is signed or unsigned.  It just blindly sets or clears the status bits according to the definitions posted in INTEL docs and computer science texts.  It just so happens that SUB/ADD signed/unsigned operations use the same operation, but are interpreted differently.  That is not the same for multiplication or division operations however.  Again I iterate, the hardware makes no assumptions, nor does it, or is it able to detect what kind of number is in the register.  Ratch

Matthew