[解決済み] なぜRustコンパイラは、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)
の場合、2回
int *a
と
int *b
のエイリアスです。
この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コンパイラがまだ開発中で、最適化を行うためのエイリアス解析が組み込まれていないためでしょうか。
という可能性が残っているからでしょうか。
a
と
b
は、安全なRustでもエイリアスできるのでしょうか?
どのように解決するのですか?
元々錆は
した。
は、LLVMの
noalias
属性がありますが、この
はミスコンパイルコードを引き起こした
. サポートされているすべての LLVM バージョンでコードのミスコンパイルが発生しなくなった場合。
を再び有効にします。
.
を追加した場合
-Zmutable-noalias=yes
をコンパイラのオプションに追加すると、期待通りのアセンブリが得られます。
adds:
mov eax, dword ptr [rsi]
add eax, eax
add dword ptr [rdi], eax
ret
簡単に言うと、RustはC言語の
restrict
キーワード
どこでも
通常のC言語プログラムよりもはるかに多く存在する。このため、LLVMのコーナーケースは、LLVMが正しく処理できる以上の力を発揮しました。CとC++のプログラマは、単に
restrict
のように頻繁に
&mut
はRustで使われています。
このようなことがありました 複数回 .
-
Rust 1.0 から 1.7 まで -。
noalias
有効 -
Rust 1.8 から 1.27 まで -。
noalias
無効 -
Rust 1.28 から 1.29 -。
noalias
有効 -
Rust 1.30 から 1.54 -。
noalias
無効 -
Rust 1.54から? -
noalias
コンパイラが使用するLLVMのバージョンによって条件付きで有効になります。
Rust関連問題
-
現在の事例
-
前のケース
-
その他
関連
-
[解決済み] rustupでインストールしたRustをアンインストールするには?
-
[解決済み] Rustで絶対値を求めるには?
-
[解決済み] なぜGCCは、速度の代わりにサイズに最適化すると、15-20%速いコードを生成するのですか?
-
[解決済み】ライブラリとバイナリの両方を持つRustパッケージ?
-
[解決済み】Rustの実行ファイルはなぜこんなに巨大なのですか?
-
[解決済み] 同じプロジェクトの別のファイルからモジュールをインクルードする方法は?
-
[解決済み] Rust の 128 ビット整数 `i128` は 64 ビットシステムでどのように動作するのでしょうか?
-
[解決済み] ローカルの未公開クレートを使うには?
-
[解決済み] アポストロフィが1つ付いているラストタイプは何ですか?
-
[解決済み] なぜコンパイラは予測可能な加算ループを乗算に最適化できないのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] rustupでインストールしたRustをアンインストールするには?
-
[解決済み] Rustにはキューとスタックコレクションがありますか?
-
[解決済み] 構造体のフィールドをメソッドから変異させるには?
-
[解決済み] 文字列を追加して印刷するにはどうすればよいですか?
-
[解決済み】RustプログラムがCargoパッケージからメタデータにアクセスする方法は?
-
[解決済み】Rustの正確な自動再参照のルールは?
-
[解決済み] このクエスチョンマークの演算子は何についてですか?
-
[解決済み] バイトのベクター(u8)を文字列に変換するには?
-
[解決済み] Cargoで複数のバイナリをビルドするにはどうしたらいいですか?
-
[解決済み】iterとinto_iterの違いは何ですか?