2016-10-25 3 views
3

applyに渡されるクロージャはLLVM IR {i64*, i64*}*として渡されなぜRustはLLVM IRクロージャ環境でi64 *としてクロージャによってキャプチャされたi64を格納しますか?

#[inline(never)] 
fn apply<F, A, B>(f: F, x: A) -> B 
    where F: FnOnce(A) -> B { 
    f(x) 
} 

fn main() { 
    let y: i64 = 1; 
    let z: i64 = 2; 
    let f = |x: i64| x + y + z; 
    print!("{}", apply(f, 42)); 
} 

この単純な例では:

%closure = type { i64*, i64* } 
define internal fastcc i64 @apply(%closure* noalias nocapture readonly dereferenceable(16)) unnamed_addr #0 personality i32 (i32, i32, i64, %"8.unwind::libunwind::_Unwind_Exception"*, %"8.unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality { 
entry-block: 
    %1 = getelementptr inbounds %closure, %closure* %0, i64 0, i32 1 
    %2 = getelementptr inbounds %closure, %closure* %0, i64 0, i32 0 
    %3 = load i64*, i64** %2, align 8 
    %4 = load i64*, i64** %1, align 8 
    %.idx.val.val.i = load i64, i64* %3, align 8, !noalias !1 
    %.idx1.val.val.i = load i64, i64* %4, align 8, !noalias !1 
    %5 = add i64 %.idx.val.val.i, 42 
    %6 = add i64 %5, %.idx1.val.val.i 
    ret i64 %6 
} 

applyが実際に発生LLVMコードでより複雑な名前を持っている。)

これにより、キャプチャされた各変数に2つの負荷が発生します。 %closureはなぜapply{i64, i64}*になるのですか?{i64, i64}はなぜですか?

答えて

6

Closuresデフォルトで参照キャプチャ。あなたは、パラメータリスト前moveキーワードを追加することによって、値でキャプチャするためにその動作を変更することができます。

let f = move |x: i64| x + y + z; 

これは非常に希薄なコードを生成します。

define internal fastcc i64 @apply(i64 %.0.0.val, i64 %.0.1.val) unnamed_addr #0 personality i32 (i32, i32, i64, %"8.unwind::libunwind::_Unwind_Exception"*, %"8.unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality { 
entry-block: 
    %0 = add i64 %.0.0.val, 42 
    %1 = add i64 %0, %.0.1.val 
    ret i64 %1 
} 

moveキーワードを追加すると、その任意の値を意味し、閉鎖することを使用はクロージャの環境に移動されます。 Copyの整数の場合はそれほど大きな違いはありませんが、Stringのような他のタイプの場合は、クロージャを作成した後に外側の範囲でもうStringを使用できないことを意味します。それはすべてかどうかの取引ですが、moveクロージャの外側にある個々の変数への参照を手動で取ることができ、クロージャが元の値の代わりにこれらの参照を使用するようにして、

このコードでは、値と照合の違いを何とか観察できますか?

If you take the address of the captured variable, you can observe the difference.第1と第2の出力ラインが同じで、第3の出力ラインが異なることに注意してください。

+0

ありがとうございます。私は 'i64'をコピーするのが安価で、安価でない場合は参考にして、' i64'のRustを変更することはできないので、値だけ透過的にコピーすると仮定していました。あなたはこのコードで何らかの形で値と基準の違いを観察できますか? – tibbe

関連する問題