strict-aliasingを体験してみた。
gcc47 -O3 -c でオブジェクトコードを生成して、objdump -dで逆アセンブルして調べた。
型がちがえばオブジェクトは別ものなのでエイリアスを仮定しないコードが出る。
int foo_intp_longp(int *a, long *b) { //movl $0x1,(%rdi) *a = 1; //mov $0x1,%eax <-- no aliasing *b = 2; //movq $0x2,(%rsi) return *a; //retq }
型が同じだと同じオブジェクトを指しているかもしれないのでエイリアスを仮定したコードが出る。
int foo_intp_intp(int *a, int *b) { //movl $0x1,(%rdi) *a = 1; //movl $0x2,(%rsi) *b = 2; //mov (%rdi),%eax <-- aliasing return *a; //retq }
引数の型はちがってもキャストして同じになるとエイリアスを仮定したコードが出る。
int foo_intp_longp_cast_int(int *a, long *b) { //movl $0x1,(%rdi) *a = 1; //movl $0x2,(%rsi) *(int*)b = 2; //mov (%rdi),%eax <-- aliasing return *a; //retq }
違う型へのキャストならエイリアスを仮定しないコードが出る。
int foo_intp_longp_cast_short(int *a, long *b) { //movl $0x1,(%rdi) *a = 1; //mov $0x1,%eax <-- no aliasing *(short*)b = 2; //movw $0x2,(%rsi) return *a; //retq }
違う型でもchar*は特別扱いなのでエイリアスを仮定したコードが出る。
int foo_intp_longp_cast_charp(int *a, long *b) { //movl $0x1,(%rdi) *a = 1; //movb $0x2,(%rsi) *(char*)b = 2; //mov (%rdi),%eax <-- aliasing return *a; //retq }
char*/void*を経由したキャストをしてもエイリアスは仮定されない。
int foo_intp_longp_cast_voidp(int *a, long *b) { //movl $0x1,(%rdi) *a = 1; //mov $0x1,%eax <- no aliasing *(short*)(void*)b = 2; //movw $0x2,(%rsi) return *a; //retq } int foo_intp_longp_cast_charp_shortp(int *a, long *b) { //movl $0x1,(%rdi) *a = 1; //mov $0x1,%eax *(short*)(char*)b = 2; //movw $0x2,(%rsi) return *a; //retq }
-fno-strict-aliasingをつけると、すべての場合でaliasingを仮定したコード生成になった。
C99で導入された restrict をつかうと(-fno-strict-aliasingをつけてコンパイルしても)エイリアスが仮定されないコードが出る。
int foo_intp_intp_restrict(int * restrict a, int * restrict b) { //movl $0x1,(%rdi) *a = 1; //movl $0x2,(%rsi) *b = 2; //mov $0x1,%eax return *a; //retq }
出てきたコードが他のものとはちょっとちがってmov $0x1,%eaxが後ろの方になっている。そっちの方が効率がいいのかな?
両方のパラメータにrestrictをつけないといけないようだ。片方だけだとエイリアスを仮定したコードが出る。
int foo_intp_intp_restrict1(int * restrict a, int *b) { //movl $0x1,(%rdi) *a = 1; //movl $0x2,(%rsi) *b = 2; //mov (%rdi),%eax return *a; //retq } int foo_intp_intp_restrict2(int *a, int * restrict b) { //movl $0x1,(%rdi) *a = 1; //movl $0x2,(%rsi) *b = 2; //mov (%rdi),%eax return *a; //retq }