その他のデータポイントは次のとおりです。
基本的に、gccが最適化されているように見えます(-Oフラグがオフで-gがオンの場合でも)。
[variable] < (type-cast)(1 << [variable2])
に
((type-cast)[variable] >> [variable2]) == 0
と
[variable] >= (type-cast)(1 << [variable2])
に
((type-cast)[variable] >> [variable2]) != 0
ここで、[変数]は配列アクセスである必要があります。
ここでの利点は、リテラル1をレジスターにロードする必要がないことです。これにより、1つのレジスターが節約されます。
したがって、ここにデータポイントがあります。
- 1を1より大きい数に変更すると、正しいバージョンが実装されます。
- 変数のいずれかをリテラルに変更すると、正しいバージョンが実装されます。
- [変数]を非配列アクセスに変更すると、正しいバージョンを実装するように強制されます
- [variable]>(type-cast)(1 << [variable2])は正しいバージョンを実装します。
これはすべてレジスタを保存しようとしているのではないかと思います。[変数]が配列アクセスの場合、インデックスも保持する必要があります。それが間違っているまで、誰かがおそらくこれはとても賢いと思ったでしょう。
バグレポートのコードを使用するhttp://gcc.gnu.org/bugzilla/show_bug.cgi?id=56051
#include <stdio.h>
int main(void)
{
int a, s = 8;
unsigned char data[1] = {0};
a = data[0] < (unsigned char) (1 << s);
printf("%d\n", a);
return 0;
}
gcc-O2-Sでコンパイル
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $8, %esp
pushl $1 ***** seems it already precomputed the result to be 1
pushl $.LC0
pushl $1
call __printf_chk
xorl %eax, %eax
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret
gcc-Sだけでコンパイルする
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %ecx
subl $16, %esp
movl $8, -12(%ebp)
movb $0, -17(%ebp)
movb -17(%ebp), %dl
movl -12(%ebp), %eax
movb %dl, %bl
movb %al, %cl
shrb %cl, %bl ****** (unsigned char)data[0] >> s => %bl
movb %bl, %al %bl => %al
testb %al, %al %al = 0?
sete %dl
movl $0, %eax
movb %dl, %al
movl %eax, -16(%ebp)
movl $.LC0, %eax
subl $8, %esp
pushl -16(%ebp)
pushl %eax
call printf
addl $16, %esp
movl $0, %eax
leal -8(%ebp), %esp
addl $0, %esp
popl %ecx
popl %ebx
popl %ebp
leal -4(%ecx), %esp
ret
次のステップはgccのソースコードを掘り下げることだと思います。