Sejauh yang saya tahu, referensi / pointer aliasing dapat menghambat kemampuan kompiler untuk menghasilkan kode yang dioptimalkan, karena mereka harus memastikan biner yang dihasilkan berperilaku dengan benar dalam kasus di mana dua referensi / pointer memang alias. Misalnya, dalam kode C berikut,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
ketika dikompilasi oleh clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
dengan -O3
bendera, itu memancarkan
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
Di sini kode menyimpan kembali (%rdi)
dua kali dalam kasus int *a
dan int *b
alias.
Ketika kami secara eksplisit memberi tahu kompiler bahwa kedua petunjuk ini tidak dapat alias dengan restrict
kata kunci:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Kemudian Dentang akan mengeluarkan versi yang lebih optimal dari kode biner:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Karena Rust memastikan (kecuali dalam kode yang tidak aman) bahwa dua referensi yang bisa diubah tidak bisa alias, saya akan berpikir bahwa kompiler harus dapat memancarkan versi kode yang lebih optimal.
Ketika saya menguji dengan kode di bawah ini dan mengompilasinya rustc 1.35.0
dengan -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
itu menghasilkan:
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
Ini tidak memanfaatkan jaminan itu a
dan b
tidak bisa alias.
Apakah ini karena compiler Rust saat ini masih dalam pengembangan dan belum memasukkan analisis alias untuk melakukan optimasi?
Apakah ini karena masih ada kemungkinan itu a
dan b
bisa alias, bahkan di Rust yang aman?
unsafe
kode, alias referensi yang dapat diubah tidak diperbolehkan dan menghasilkan perilaku yang tidak ditentukan. Anda dapat memiliki alias mentah pointer, tetapi unsafe
kode sebenarnya tidak memungkinkan Anda untuk mengabaikan aturan standar Rust. Itu hanya kesalahpahaman umum dan dengan demikian layak untuk ditunjukkan.
+=
operasi dalam tubuh adds
dapat ditafsirkan kembali sebagai *a = *a + *b + *b
. Jika pointer tidak alias, mereka bisa, Anda bahkan dapat melihat apa yang berjumlah b* + *b
di asm kedua listing: 2: 01 c0 add %eax,%eax
. Tetapi jika mereka melakukan alias, mereka tidak bisa, karena pada saat Anda menambahkan *b
untuk kedua kalinya, itu akan berisi nilai yang berbeda dari yang pertama kali ada (yang Anda simpan pada baris 4:
daftar asm pertama).