私の知る限り、参照/ポインターのエイリアスは、2つの参照/ポインターが実際にエイリアスする場合に生成されたバイナリが正しく動作するようにする必要があるため、最適化されたコードを生成するコンパイラーの能力を妨げる可能性があります。たとえば、次のCコードでは、
_void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
_
clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
で_-O3
_フラグを指定してコンパイルすると、出力します
_0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi) # The first time
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi) # The second time
a: c3 retq
_
ここで、コードは、別名_(%rdi)
_および_int *a
_の場合に_int *b
_に2回保存します。
これらの2つのポインターがrestrict
キーワードでエイリアスできないことをコンパイラーに明示的に伝えると:
_void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
_
その後、Clangはバイナリコードのより最適化されたバージョンを出力します。
_0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
_
Rustは(安全でないコードを除いて)2つの可変参照がエイリアスできないことを確認するので、コンパイラはより最適化されたバージョンのコードを出力できるはずだと思います。
以下のコードでテストし、_rustc 1.35.0
_で_-C opt-level=3 --emit obj
_でコンパイルすると、
_#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
_
以下を生成します。
_0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi)
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi)
a: c3 retq
_
これは、a
とb
がエイリアスできないという保証を利用しません。
これは、現在のRustコンパイラがまだ開発中であり、最適化を行うためにエイリアス分析をまだ組み込んでいないためですか?
これは、安全なRustでも、a
とb
がエイリアスする可能性があるためですか?
元々の錆didはLLVMのnoalias
属性を有効にしますが、これは コードのコンパイルミス です。サポートされているすべてのLLVMバージョンがコードを誤ってコンパイルしなくなったら、 再び有効になります 。
-Zmutable-noalias=yes
をコンパイラオプションに追加すると、予想されるアセンブリが取得されます。
adds:
mov eax, dword ptr [rsi]
add eax, eax
add dword ptr [rdi], eax
ret
簡単に言えば、Rust Cのrestrict
キーワードに相当するものを入れてくださいeverywhere、他よりもはるかに普及しているCおよびC++プログラマーは、Rustで&mut
が使用されるほど頻繁にrestrict
を使用しないことが判明しました。 。
これは、複数回発生しました。
noalias
有効noalias
無効noalias
有効noalias
無効現在のケース
前のケース
その他