By: Michael S (already5chosen.delete@this.yahoo.com), February 28, 2013 3:58 am

Room: Moderated Discussions

EduardoS (no.delete@this.spam.com) on February 27, 2013 11:07 pm wrote:

> Michael S (already5chosen.delete@this.yahoo.com) on February 27, 2013 4:24 pm wrote:

> > I say 12 rather than 14, because I don't think that negative/non-negative

> > conditions are really fundamental.

>

> The sign flag helps some times and is essentially free.

>

> > Now, do we really need 4 flag bits in order to implement 12 (or even all 14) fundamental

> > conditions? No, we don't. Up to 64 conditions, including all 14 defined in x86/ARM?SPARC,

> > can be easyly derived from just 7 distinct states = 3 bits.

> > For example, like those:

> > 0 - unsigned_less && signed_less. Implied non-overflow && negative

> > 1 - unsigned_less && signed_greater && non-overflow. Implied non-negative

> > 2 - unsigned_less && signed_greater && overflow. Implied negative

> > 3 - unsigned_greater && signed_less && non-overflow. Implied negative

> > 4 - unsigned_greater && signed_less && overflow. Implied non-negative

> > 5 - unsigned_greater && signed_greater. Implied non-overflow && non-negative

> > 6 - equal. Implied non-overflow && non-negative

>

> Encoding in three bits have the same "advantage" of killing the sign flag

I don't get what you're saying. Sign-of-result information is fully preserved in 3-bit encoding. Using encoding from my table above, SF = (0 || 2 || 3).

> at the expense

> of more complex (and time consuming) flag calculation, but the sign flag is free, so no

> real gain, also... 3 bitsT allow up to 8 resulting states, but there are 9, no?

>

You are right.

I was concerned only with sub/cmp and didn't pay attention to all combinations that can be generated by two-complement addition.

Specifically, my 7 states can not represent two additional zeros - ZF=1,CF=1,OF=0 and ZF=1,CF=1,OF=1. And there is only one 3-bit combination left so, without special measure, it's impossible to distinguish between the two states with just 3 bits.

One possible solution is definition of two separate addition instruction that behave identically except when faced with pair of 0x8000_0000 inputs in which case:

signed_add variant correctly detects carry and overflow, but leaves equivalent of ZF set;

unsigned_add variant correctly detects carry and ZF, but leaves equivalent of OF clear.

Then all 'C' compilers will happily ignore signed_add. All compiler for integer-overflow-paranoid languages will use signed_add when appropriated, being fully aware of the fact that ZF is not reliable after that. Anyway, ZF is most useful after sub/cmp, HLL compilers (unlike human coders) almost never exploit it after addition.

So, lets revisit my table:

0 - Z=0,S=1,C=0,B=1,O=0: unsigned_less && signed_less. Implied non-overflow && negative

1 - Z=0,S=0,C=0,B=1,O=0: unsigned_less && signed_greater && non-overflow. Implied non-negative

2 - Z=0,S=1,C=0,B=1,O=1: unsigned_less && signed_greater && overflow. Implied negative

3 - Z=0,S=1,C=1,B=0,O=0: unsigned_greater && signed_less && non-overflow. Implied negative

4 - Z=0,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

5 - Z=0,S=0,C=1,B=0,O=0: unsigned_greater && signed_greater. Implied non-overflow && non-negative

6 - Z=1,S=0,C=0,B=0,O=0: equal. Implied non-overflow && non-negative

7 - Z=1,S=0,C=1,B=0,O=0: equal with carry && non-overflow. Implied non-negative

Plus:

As result of signed_add:

4 - Z=x,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

As result of unsigned_add:

7 - Z=x,S=0,C=1,B=0,O=x: unsigned_greater && signed_less && overflow. Implied non-negative

So, let's look at your addition cases:

# 1

> mov eax, 1

> add eax, 1

>

> Non-Zero, Non-Negative, Non-Carry, Non-Overflow

1 - Z=0,S=0,C=0,B=1,O=0: unsigned_less && signed_greater && non-overflow. Implied non-negative

# 2

>

> mov eax, 0

> add eax, 0

>

> Zero, Non-Negative, Non-Carry, Non-Overflow

6 - Z=1,S=0,C=0,B=0,O=0: equal. Implied non-overflow && non-negative

# 3

> mov eax, -1

> add eax, 2

>

> Non-Zero, Non-Negative, Carry, Non-Overflow

5 - Z=0,S=0,C=1,B=0,O=0: unsigned_greater && signed_greater. Implied non-overflow && non-negative

# 4

>

> mov eax, -1

> add eax, 1

>

> Zero, Non-Negative, Carry, Non-Overflow

7 - Z=1,S=0,C=1,B=x,O=0: equal with carry. Implied overflow && non-negative

# 5

>

> mov eax, 80000000h

> add eax, 80000000h

>

> Zero, Non-Negative, Carry, Overflow

After unsigned_add:

7 - Z=1,S=0,C=1,B=x,O=0: equal with carry. Implied overflow && non-negative

After signed_add:

4 - Z=0,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

# 6

>

> mov eax, 80000001h

> add eax, 80000000h

>

> Non-Zero, Non-Negative, Carry, Overflow

4 - Z=0,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

#7

> mov eax, -2

> add eax, 1

>

> Non-Zero, Negative, Non-Carry, Non-Overflow

>

0 - Z=0,S=1,C=0,B=1,O=0: unsigned_less && signed_less. Implied non-overflow && negative

#8

> mov eax, 70000000h

> add eax, 70000000h

>

> Non-Zero, Negative, Non-Carry, Overflow

>

2 - Z=0,S=1,C=0,B=1,O=1: unsigned_less && signed_greater && overflow. Implied negative

#9

> mov eax, -1

> add eax, -1

>

> Non-Zero, Negative, Carry, Non-Overflow

>

3 - Z=0,S=1,C=1,B=0,O=0: unsigned_greater && signed_less && non-overflow. Implied negative

> Michael S (already5chosen.delete@this.yahoo.com) on February 27, 2013 4:24 pm wrote:

> > I say 12 rather than 14, because I don't think that negative/non-negative

> > conditions are really fundamental.

>

> The sign flag helps some times and is essentially free.

>

> > Now, do we really need 4 flag bits in order to implement 12 (or even all 14) fundamental

> > conditions? No, we don't. Up to 64 conditions, including all 14 defined in x86/ARM?SPARC,

> > can be easyly derived from just 7 distinct states = 3 bits.

> > For example, like those:

> > 0 - unsigned_less && signed_less. Implied non-overflow && negative

> > 1 - unsigned_less && signed_greater && non-overflow. Implied non-negative

> > 2 - unsigned_less && signed_greater && overflow. Implied negative

> > 3 - unsigned_greater && signed_less && non-overflow. Implied negative

> > 4 - unsigned_greater && signed_less && overflow. Implied non-negative

> > 5 - unsigned_greater && signed_greater. Implied non-overflow && non-negative

> > 6 - equal. Implied non-overflow && non-negative

>

> Encoding in three bits have the same "advantage" of killing the sign flag

I don't get what you're saying. Sign-of-result information is fully preserved in 3-bit encoding. Using encoding from my table above, SF = (0 || 2 || 3).

> at the expense

> of more complex (and time consuming) flag calculation, but the sign flag is free, so no

> real gain, also... 3 bitsT allow up to 8 resulting states, but there are 9, no?

>

You are right.

I was concerned only with sub/cmp and didn't pay attention to all combinations that can be generated by two-complement addition.

Specifically, my 7 states can not represent two additional zeros - ZF=1,CF=1,OF=0 and ZF=1,CF=1,OF=1. And there is only one 3-bit combination left so, without special measure, it's impossible to distinguish between the two states with just 3 bits.

One possible solution is definition of two separate addition instruction that behave identically except when faced with pair of 0x8000_0000 inputs in which case:

signed_add variant correctly detects carry and overflow, but leaves equivalent of ZF set;

unsigned_add variant correctly detects carry and ZF, but leaves equivalent of OF clear.

Then all 'C' compilers will happily ignore signed_add. All compiler for integer-overflow-paranoid languages will use signed_add when appropriated, being fully aware of the fact that ZF is not reliable after that. Anyway, ZF is most useful after sub/cmp, HLL compilers (unlike human coders) almost never exploit it after addition.

So, lets revisit my table:

0 - Z=0,S=1,C=0,B=1,O=0: unsigned_less && signed_less. Implied non-overflow && negative

1 - Z=0,S=0,C=0,B=1,O=0: unsigned_less && signed_greater && non-overflow. Implied non-negative

2 - Z=0,S=1,C=0,B=1,O=1: unsigned_less && signed_greater && overflow. Implied negative

3 - Z=0,S=1,C=1,B=0,O=0: unsigned_greater && signed_less && non-overflow. Implied negative

4 - Z=0,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

5 - Z=0,S=0,C=1,B=0,O=0: unsigned_greater && signed_greater. Implied non-overflow && non-negative

6 - Z=1,S=0,C=0,B=0,O=0: equal. Implied non-overflow && non-negative

7 - Z=1,S=0,C=1,B=0,O=0: equal with carry && non-overflow. Implied non-negative

Plus:

As result of signed_add:

4 - Z=x,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

As result of unsigned_add:

7 - Z=x,S=0,C=1,B=0,O=x: unsigned_greater && signed_less && overflow. Implied non-negative

So, let's look at your addition cases:

# 1

> mov eax, 1

> add eax, 1

>

> Non-Zero, Non-Negative, Non-Carry, Non-Overflow

1 - Z=0,S=0,C=0,B=1,O=0: unsigned_less && signed_greater && non-overflow. Implied non-negative

# 2

>

> mov eax, 0

> add eax, 0

>

> Zero, Non-Negative, Non-Carry, Non-Overflow

6 - Z=1,S=0,C=0,B=0,O=0: equal. Implied non-overflow && non-negative

# 3

> mov eax, -1

> add eax, 2

>

> Non-Zero, Non-Negative, Carry, Non-Overflow

5 - Z=0,S=0,C=1,B=0,O=0: unsigned_greater && signed_greater. Implied non-overflow && non-negative

# 4

>

> mov eax, -1

> add eax, 1

>

> Zero, Non-Negative, Carry, Non-Overflow

7 - Z=1,S=0,C=1,B=x,O=0: equal with carry. Implied overflow && non-negative

# 5

>

> mov eax, 80000000h

> add eax, 80000000h

>

> Zero, Non-Negative, Carry, Overflow

After unsigned_add:

7 - Z=1,S=0,C=1,B=x,O=0: equal with carry. Implied overflow && non-negative

After signed_add:

4 - Z=0,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

# 6

>

> mov eax, 80000001h

> add eax, 80000000h

>

> Non-Zero, Non-Negative, Carry, Overflow

4 - Z=0,S=0,C=1,B=0,O=1: unsigned_greater && signed_less && overflow. Implied non-negative

#7

> mov eax, -2

> add eax, 1

>

> Non-Zero, Negative, Non-Carry, Non-Overflow

>

0 - Z=0,S=1,C=0,B=1,O=0: unsigned_less && signed_less. Implied non-overflow && negative

#8

> mov eax, 70000000h

> add eax, 70000000h

>

> Non-Zero, Negative, Non-Carry, Overflow

>

2 - Z=0,S=1,C=0,B=1,O=1: unsigned_less && signed_greater && overflow. Implied negative

#9

> mov eax, -1

> add eax, -1

>

> Non-Zero, Negative, Carry, Non-Overflow

>

3 - Z=0,S=1,C=1,B=0,O=0: unsigned_greater && signed_less && non-overflow. Implied negative