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
}














