2016-07-25 6 views
6

いつかオブジェクトの移動中にビットワイズコピーを最適化できますか?

struct Foo { 
    dummy: [u8; 65536], 
} 

fn bar(foo: Foo) { 
    println!("{:p}", &foo) 
} 

fn main() { 
    let o = Foo { dummy: [42u8; 65536] }; 
    println!("{:p}", &o); 
    bar(o); 
} 

スニペットを検討プログラムの典型的なresult

アドレスが異なる
0x7fffc1239890 
0x7fffc1229890 

あります。

明らかに、大きな配列dummyは、コンパイラの移動実装で期待どおりにコピーされています。残念ながら、dummyは非常に大きな配列なので、これはパフォーマンスにはあまり影響しません。この影響は、関数が実際に引数を概念的に「消費」している場合でも、人々が代わりに参照渡しを選択するよう強制する可能性があります。

FooCopyを派生しないため、オブジェクトoが移動されます。 Rustは移動オブジェクトのアクセスを禁止しているので、元のオブジェクトoを "再利用"することを避けるために、コンパイラは潜在的に高価なビット単位のコピーを生成しますか?基本的な難しさはありますか、またはいつかコンパイラがこのビット単位のコピーを最適化するのを見ていきますか?

+7

Rustcは動きを最適化します。この場合は、llvmがインラインバーを表示していなかったためです。これはポインターの値を観察しようとしていることが原因でもあり、llvmは最適化が安全かどうかはわかりません。私は ':p'の出力を使わずに試してみましたが、代わりにtest :: black_boxを使いました。そのコピーはアセンブリから消えてしまいました。 – Manishearth

+0

@Manishearth 'bar'がインライン化しています。 LLVMは大規模な配列の移動を取り除くのが難しいだけです。 – Veedrac

答えて

13

Rust(CまたはC++とは異なります)では、値のアドレスは重要ではないと考えられるので、コピーのエリジョンを防ぐの言語という点で何もありません。

しかし、今日のrustcでは最適化されていません。すべての最適化がLLVMに委任されています。ここではLLVMオプティマイザの制限に遭っているようです(LLVMがCのセマンティクスに近いかどうかは不明です。ただの省略)。この最適化を実行するrustcを教える

  • 教示LLVM(可能な場合)、この最適化を実行する
  • (最適化パスが今rustcするために来ている:

    そこで、このためのコード生成を改善二道があります

しかし、今のところ、このような大きなオブジェクトがスタックに割り当てられないようにしたい場合は、Boxなどがあります。

+5

MIR最適化パスについて言えば、最初のものは単純な移動先伝播パスです:https://github.com/rust-lang/rust/pull/34693。追跡の問題はhttps://github.com/rust-lang/rust/issues/32966です。 – eddyb

+1

単にスタックの割り当てを避けるのではなく、移動が最適化されることを前提とする方が良いでしょう。 Rustのほとんどの時間は、物事をコピーしないようにすることを考えてはいけません。 –

+0

@MichaelYounkin:私は部分的に同意します。問題は、スタックに数回コピーされた大きなオブジェクトが、特に最適化が発生しないデバッグターゲットで、スタックオーバーフローにつながりやすいことです。バッファが非常に大きい場合、動的割り当てのコストは、バッファそのものを初期化するコストに比べて小さくなります。 –

関連する問題