cmp a, b を実行したときの CF(キャリーフラグ) は、
a と b を符号無し整数として、比較した結果になります。
ハードウェアの比較回路がどう実現されているかには関係ありません。
2の補数表現で引き算をしていると考えないでください。
符号無し整数の比較で、a < b であれば CF は 1 になります。
int u_cmp(unsigned a, unsigned b) { return a < b; }
このコードを gcc でコンパイルすると
コード:
u_cmp:
pushq %rbp
movq %rsp, %rbp
movl %ecx, 16(%rbp)
movl %edx, 24(%rbp)
movl 16(%rbp), %eax
cmpl 24(%rbp), %eax
setb %al
movzbl %al, %eax
popq %rbp
ret
setb は、setc や setnae というニーモニックと同じ
0f 92 というコードになります。
これは、CF の値を AL にセットする命令です。
では、2の補数表現による比較はどうなるでしょうか?
int s_cmp(int a, int b) { return a < b; }
このコードを gcc でコンパイルすると
コード:
s_cmp:
pushq %rbp
movq %rsp, %rbp
movl %ecx, 16(%rbp)
movl %edx, 24(%rbp)
movl 16(%rbp), %eax
cmpl 24(%rbp), %eax
setl %al
movzbl %al, %eax
popq %rbp
ret
setl は、setnge というニーモニックと同じで
0f 9c というコードになります。
これは SF(符号フラグ) と OF(オーバーフローフラグ) が
異なる場合に AL に 1 をセットする命令です。
cmp 5, 3 では、引き算結果は 2 (0x00000002) で、符号は正なので SF = 0。
引き算でオーバーフローが起こらないので OF = 0 です。
SF と OF が等しいので AL には 0 がセットされます。
a < b の演算結果として偽を返します。
cmp 5, 6 では、引き算結果は -1 (0xffffffff) で、符号は負なので SF = 1。
引き算でオーバーフローが起こらないので OF = 0 です。
SF と OF が異なるので AL には 1 がセットされます。
a < b の演算結果として真を返します。
OF = 1 になるのはどんな時かというと、例えば、
cmp 20億, -20億 という符号付整数を比較した場合、
引き算の結果が 40億となり、32ビットの符号付き整数の
範囲外となる場合です。