Rust derleyicisi neden iki değiştirilebilir başvurunun diğer adının kullanılamayacağını varsayarak kodu en iyi duruma getirmiyor?


302

Bildiğim kadarıyla, referans / işaretçi takma adı, derleyicinin optimize edilmiş kod üretme yeteneğini engelleyebilir, çünkü iki referansın / işaretçinin gerçekten takma adda oluşturulduğu ikili kodun doğru şekilde davranmasını sağlamalıdırlar. Örneğin, aşağıdaki C kodunda,

void adds(int  *a, int *b) {
    *a += *b;
    *a += *b;
}

bayrak clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)ile derlendiğinde -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

Burada kod (%rdi)durumda int *ave int *btakma adda iki kez geri saklar .

Derleyiciye bu iki işaretçinin restrictanahtar kelime ile takma ad veremeyeceğini açıkça söylediğimizde :

void adds(int * restrict a, int * restrict b) {
    *a += *b;
    *a += *b;
}

Ardından Clang, ikili kodun daha optimize bir sürümünü yayınlayacaktır:

0000000000000000 <adds>:
   0:    8b 06                    mov    (%rsi),%eax
   2:    01 c0                    add    %eax,%eax
   4:    01 07                    add    %eax,(%rdi)
   6:    c3                       retq

Rust (güvenli olmayan kod hariç) iki değişken referansın diğer adı kullanamayacağından emin olduğundan, derleyicinin kodun daha optimize edilmiş sürümünü yayınlayabilmesi gerektiğini düşünürdüm.

Aşağıda koduyla test etmek ve onu derlerken rustc 1.35.0ile -C opt-level=3 --emit obj,

#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
    *a += *b;
    *a += *b;
}

oluşturur:

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

Bu garanti bu avantajı almaz ave bolamaz takma.

Bunun nedeni, şu anki Rust derleyicisinin hala geliştirilme aşamasında olması ve optimizasyonu yapmak için henüz takma ad analizi içermemesi mi?

Bu hala bir şans çünkü olduğunu ave bcould bile güvenli Rust takma?



76
Yan açıklama: " Rust (güvenli olmayan kod hariç) iki değişken referansın takma ad veremeyeceğinden emin olduğundan " - unsafekodda bile , takma değiştirilebilir referanslara izin verilmediğinden ve tanımlanmamış davranışla sonuçlandığından bahsetmek gerekir . Ham işaretçileri takma adlandırabilirsiniz, ancak unsafekod aslında Rust standart kurallarını yok saymanıza izin vermez. Bu sadece yaygın bir yanlış anlamadır ve bu yüzden belirtmeye değer.
Lukas Kalbertodt

6
Örneğin ne elde ettiğini anlamak biraz zaman aldı, çünkü okuma asmında yetenekli değilim, bu yüzden başka birine yardım etmesi durumunda: +=vücudundaki iki işlemin addsyeniden yorumlanıp yorumlanamayacağı kaygılıyor *a = *a + *b + *b. İşaretçileri takma yoksa, bunlar, hatta ne miktarda görebilirsiniz olabilir b* + *blisteleme ikinci asm: 2: 01 c0 add %eax,%eax. Ancak takma ad yaparlarsa, yapamazlar, çünkü *bikinci kez eklediğiniz zaman, 4:ilk defadan farklı bir değer içerecektir ( ilk asm listesinin satırında sakladığınız değer ).
dlukes

Yanıtlar:


365

Pas aslen yaptığı LLVM en etkinleştirmek noaliasniteliğini, ancak bu sebep miscompiled kodu . Desteklenen tüm LLVM sürümleri artık kodu yanlış derlemediğinde yeniden etkinleştirilecektir .

-Zmutable-noalias=yesDerleyici seçeneklerine eklerseniz , beklenen montajı alırsınız:

adds:
        mov     eax, dword ptr [rsi]
        add     eax, eax
        add     dword ptr [rdi], eax
        ret

Basitçe söylemek gerekirse, Rust , her zamanki C programından çok daha yaygın olan C'nin restrictanahtar kelimesinin eşdeğerini her yere koydu . Bu, LLVM'nin köşe vakalarını doğru bir şekilde ele alabileceğinden daha fazla kullanmıştır. C ve C ++ programcılarının Rust'da kullanıldığı restrictkadar sık kullanmadıkları ortaya çıkıyor &mut.

Bu birçok kez oldu .

  • Pas 1.0 - 1.7 - noaliasetkin
  • Pas 1.8 - 1.27 - noaliasdevre dışı
  • Pas 1.28 - 1.29 - noaliasetkin
  • Pas 1.30 ile ??? - noaliasdevre dışı

İlgili Rust sorunları


12
Bu şaşırtıcı değil. Çok dilli dostu olma konusundaki geniş kapsamlı iddialarına rağmen, LLVM özellikle bir C ++ arka ucu olarak tasarlanmıştır ve her zaman C ++ gibi görünmeyen şeyleri boğma eğilimindedir.
Mason Wheeler

47
@MasonWheeler bazı sorunlara tıklarsanız restrict, hem Clang hem de GCC'de kullanılan ve yanlış derlenen C kodu örneklerini bulabilirsiniz . Bu gruptaki C ++ 'ı saymazsanız , “C ++ yeterli” olmayan dillerle sınırlı değildir .
Shepmaster

6
@MasonWheeler: LLVM'nin gerçekten C veya C ++ kuralları etrafında değil, LLVM kuralları etrafında tasarlandığını düşünüyorum. Genellikle C veya C ++ kodu için doğru olan varsayımlar yapar , ancak söyleyebileceğimden, tasarımın zor köşe durumlarını işleyemeyen statik veri bağımlılıkları modeline dayanır . Kötümser olarak kanıtlanamayan veri bağımlılıklarını varsayarsa, bunun yerine, tutulduğu ile aynı bit desenine sahip bir depolama alanı yazacak olan ve okuma ve yazma.
supercat

8
@supercat Yorumlarınızı birkaç kez okudum ama itiraf ettiğimi itiraf ediyorum - bu soru veya cevapla ne yapmaları gerektiğine dair hiçbir fikrim yok. Burada tanımlanmamış davranışlar ortaya çıkmaz, bu "sadece" birbiriyle zayıf etkileşime giren çoklu optimizasyon geçişleri durumudur.
Shepmaster

2
@avl_sweden yinelemek için, bu sadece bir hata . Döngü açma optimizasyonu adımı noaliasyürütme sırasında işaretçileri tam olarak dikkate almadı (yapmıyor mu?) . Giriş işaretçileri temelinde yeni işaretçiler oluşturdu noaliasve yeni işaretçiler takma ad yapsalar bile niteliği yanlış kopyaladılar .
Shepmaster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.