Rust'tan C'ye derleyici, test geçme oranında %95,9'a ulaştı
(fractalfir.github.io)rustc_codegen_clr, Rust kodunu C ve .NET tarafına üreten bir proje; test geçme oranındaki iyileşmeyle birlikte Rust Week sunumuna hazırlanıyor- Rust core testlerinde geçme oranı iki ay önceki %92 seviyesinden %95,9 seviyesine yükseldi; kalan yaklaşık 65 testteki nedenlerin de birbirine benzer göründüğü belirtiliyor
- Son düzeltmeler 128 bit tamsayı intrinsic’leri, checked arithmetic ve subslicing üzerine yoğunlaştı; .NET tarafı da Rust core testlerinin %96,3’ünü çalıştırabilir hâle geldi
- Daha fazla C derleyicisini hedeflemek için çıktının C99’a veya ANSI C’ye yakın olması ve standart POSIX API kullanımı amaçlanıyor; bazı ANSI C derleyicilerinde çok basit Rust programları çalıştırılabildi
- Büyük ölçekli C kodu üretiminde dosya boyutunu azaltan optimizasyonlar ve iç IR refactoring’i birlikte ilerliyor; bu da Rust’ın eski veya özel platformlarda çalıştırılma kapsamını genişletmek için temel oluşturuyor
Rust Week sunumu ve projenin durumu
rustc_codegen_clrprojesinin sunumu, Hollanda’nın Utrecht kentinde düzenlenecek Rust Week etkinliğinde planlanıyor- Sunum, yeni başlayanların da erişebileceği bir anlatımla Rust-to-C derleme gibi ileri düzey bir konuyu dengelemeyi hedefliyor
- Son birkaç ayda test düzeltmeleri, C derleyici uyumluluğu, performans iyileştirmeleri ve iç refactoring çalışmaları birlikte yürütüldü
Rust core testlerinde geçme oranı arttı
- Rust core testlerinde geçme oranı iki ay önceki %92 seviyesinden %95,9 seviyesine yükseldi
- Hâlâ yaklaşık 65 test kalmış olsa da nedenler birbirine benzer göründüğü için kalan düzeltmelerin niteliği görece daralmış durumda
- .NET tarafı da aynı düzeltmelerden etkilenerek Rust core testlerinin %96,3’ünü çalıştırabilir hâle geldi
128 bit tamsayılar ve checked arithmetic düzeltmeleri
- İyileştirmelerin önemli bir bölümü 128 bit intrinsic’ler, checked arithmetic ve subslicing düzeltmelerinden geldi
- C’deki
popcountintrinsic’i üç çeşide sahip:__builtin_popcount,__builtin_popcountl,__builtin_popcountll__builtin_popcountll, adının aksine__int128_tüzerinde değil,unsigned long longüzerinde çalışıyor- x86_64 Linux ve GCC baz alındığında
unsigned longileunsigned long longikisi de 64 bit
- Önceki uygulama, bit counting intrinsic’lerinde 128 bit tamsayıyı sessizce 64 bite kırpıp hesapladığı için yanlış sonuç üretiyordu
- 128 bit
popcount, alt 64 bit ve üst 64 bit için set bit sayılarını ayrı ayrı hesaplayıp toplama yöntemiyle emüle ediliyor - 128 bit çarpma için overflow check konusunda verimli bir yöntem bulunamadığından basit bir yöntem kullanıldı
bsıfır değilse ve(a * b) / b == aise overflow olmadığı kabul ediliyor- Çığır açıcı bir yöntem değil, ancak birkaç testi daha geçirmek için yeterli
Subslicing hatası ve fallback intrinsic’ler
- Subslicing hatası,
sizeofeksikliği nedeniyle slice’ın veri işaretçisini öğe bazında değil bayt bazında offset’leme sorunuydu - Bu hata yalnızca slice’ın başından değil sonundan subslicing yapılırken bozuluyordu; pattern matching’de daha çok kullanılan biçim bu olduğu için uzun süre fark edilmedi
- Byte slice ve string slice’ta byte ve UTF-8 code unit boyutu 1 bayt olduğundan kendi testlerini geçiyordu; sorun tüm Rust compiler test suite’inde ortaya çıktı
- Bazı intrinsic’ler doğrudan uygulanmadan Rust compiler’ın fallback uygulaması kullanılabiliyor
carrying_mul_add, çarpmayı girdiden 2 kat büyük bir tamsayıda yapmak zorunda- 64 bite kadar işlenebiliyor, ancak 128 bit girdiler için 256 bit tamsayı gerekiyor
- LLVM 256 bit tamsayıları destekliyor, ancak C ve .NET desteklemiyor
- Rust compiler’ın fallback uygulaması, 128 bit tamsayılarla 256 bit çarpma ve toplama yaptığı için yalnızca 64 bit tamsayılarla 128 bit işlemleri emüle etmeye referans olabilir
Daha fazla C derleyicisi desteği
- Proje, Rust kodunun daha fazla özel C derleyicisinde çalışabilme olasılığını artırmayı hedefliyor
- Rust kodunun Game Boy’da çalıştırıldığı, yalnızca move komutlarıyla derlendiği veya Temple OS’in Holly C’siyle çalıştırıldığı örnekler oldu
- Erişilemeyen proprietary C compiler’ları doğrudan desteklemek mümkün olmasa da obscure C compiler desteğinin kapsamı genişletilirse Rust kodunun bu ortamlarda çalışma olasılığı artar
- Birçok platform, dokümantasyon ve erişilebilirlik eksikliği nedeniyle desteklenmiyor
- Git’in bazı bölümlerinin Rust ile yazılması tartışmaları bağlamında, NonStop gibi proprietary platformlar Rust, LLVM ve GCC desteklemediği için Git desteğinin zayıflaması veya kesilmesi gibi sorunlar doğabilir
- Rust’ı C’ye derlemek, teorik olarak C’nin bulunduğu her yerde Rust’ı çalıştırmayı mümkün kılar
- Tüm platformlarda sorunların etrafından dolaşmanın mümkün olup olmayacağı henüz kesin değil
- Söz konusu platform için derleyiciyi yasal olarak edinmek sunucu satın almayı gerektiriyordu ve bu bütçenin çok dışına çıkıyor
- Rust’ın bu tür platformlarda yakın zamanda çalışması pek olası görünmüyor
Mevcut C çıktı stratejisi
- Mevcut plan, mümkün olduğunca standartlara uygun C99 veya ANSI C’ye yakın kod üretmek
- Thread-local başlatma için bir miktar threading support gerektiğinden yalnızca standart POSIX API kullanma yönünde ilerleniyor
- Belirli intrinsic’ler için kendi fallback uygulamalarına sahip ve bu liste kademeli olarak genişletiliyor
- Bazı ANSI C derleyicilerinde çok basit Rust programlarını çalıştırmak başarıldı
- Şimdilik desteklenmesi zor platformların da ihtiyaç doğduğunda görece kolay eklenebilecek durumda olması hedefleniyor
Küçük performans ve dosya boyutu iyileştirmeleri
- Tamsayı literal çıktısında, 2^32’den küçük tamsayılar için decimal gösterimin hexadecimal’den aynı uzunlukta veya daha kısa olduğu dikkate alındı
255,0xFF’ten 1 bayt daha kısa65536da0xFFFF’ten daha kısa0xprefix’i nedeniyle 2^32’ye kadar hexadecimal gösterim daha küçük hâle gelmiyor
- Tüm Rust compiler’ı C’ye dönüştürmek gibi uç bir durumda 1 GB’a kadar C source file üretildiği olmuştu; bu yüzden küçük orandaki dosya boyutu düşüşleri bile etki yaratıyor
- Debug info eklemek için kullanılan
#linedirective’i de daha akıllı hâle getirildi- Source file name yalnızca değiştiğinde ekleniyor
- Debug info kullanılırken dosya boyutunu ciddi biçimde azaltabiliyor
İç refactoring ve IR temizliği
rustc_codegen_clriçindeki bazı işlevler ayrı crate’lere bölünerek incremental build hızı artırıldı- Daha bellek verimli interned IR’a geçiş çalışması da sürüyor
- Mevcut IR’da C’ye iyi eşlenmeyen sıra dışı rvalue/lvalue yapıları vardı; dynamically sized type gibi Rust özelliklerinde sorun büyüyordu
- Örneğin
MyStrgibi custom dynamically sized type içinde&self.sbasit görünse de aslında fat pointer metadata’sını ele almak gerekiyor- C99’daki compound literal kullanılırsa
struct FatPtr_strtek satırda oluşturulabilir - ANSI C’de ise geçici değişkene
datavemetaayrı ayrı konup döndürülmeli
- C99’daki compound literal kullanılırsa
- Rust ve MIR’deki tek bir satır, C’de birçok satıra genişlediğinden eski IR bunu temporary local ve sub-statement içeren iç scope yöntemiyle işliyordu
- Yeni yöntemde setup aşaması daha karmaşık, ancak tüm IR’ı daha basit hâle getiriyor; son kalan zorlu örnek çözüldüğünde eski IR’daki ilgili özellik kaldırılabilecek
Sıradaki çalışmalar
- Proje üzerinde çalışma süresi yaklaşık 1,5 yıl oldu; hatalar azaldıkça kalan hataları bulmak daha fazla zaman gerektiriyor
- “Rust panics under the hood” serisinin 2. bölümü üzerinde çalışılıyor; Rust panic süreci adım adım açıklanmak isteniyor
- Yalnızca panic message üretimini açıklamak bile şimdiden 10 dakikalık içerik ettiği için yazıyı ikiye bölmek de değerlendiriliyor
- Rust için küçük ve doğru bir bellek profiler’ı üzerinde de çalışılıyor
- Kod boyutu yaklaşık 2K LOC
- Takvim sıkışık olsa da birkaç hafta içinde bununla ilgili bir yazı yayımlanmak isteniyor
1 yorum
Hacker News yorumları
Aslında rustc_codegen_gcc projesi bunu vaat etmişti ama sonunda yerine getiremedi
[0] https://github.com/rust-lang/compiler-team/issues/458
GCC/Clang tarafı “%80”den ibaret
| .NET Core tests | 1764 | 48 | 20 | 96.29% |
| C Core tests | 1712 | 71 | 8 | 95.59% |
Bu hack bir Rust derleyici arka ucu. Arka uçlar girdi olarak platforma özgü komutları aldığı için, üretilen basit olmayan C kodu taşınabilir olmayacaktır
Kullanıcılar ya önceden üretilmiş platforma özgü kaynakları almalı ya da Rust derleyicisini ve bu arka ucu kurup kendileri üretmeli
extern "c"fonksiyonlarıyla zaten yapılamayan neyi yeni olarak sağlıyor?“Benim .NET IR temsilim C’ye iyi eşleniyor; bu sayede 2-3 bin satır kodla Rust’ı C’ye derleme desteği ekleyebildim. Kod tabanının neredeyse tamamını yeniden kullanıyor; C’ye ve .NET’e özgü kodlar yalnızca derlemenin en son aşamasında bulunuyor”
Başta .NET arka ucu olarak başladı, ama yaklaşımın C kodu üretimini de kolayca destekleyebileceği anlaşılınca eklenmiş. rustc’nin verdiği şeyi kendi ara temsiline (IR) dönüştürüp işliyor
Sınır denetimi gibi dinamik garantiler de C çalışma zamanında sorunsuz uygulanabilir
unsafebloğunun içine koymak gerekirC, Rust’ta derlenebilmesi için açıkça bilinmesi gereken tüm bilgileri aktarmıyor
https://www.youtube.com/watch?v=1VgptLwP588
unsafebloğu kullanmaları ve ortaya çıkan kodun genelde Rust’a pek benzememesiÖrneğin global değişken tabanlı bir durum makinesini, adlandırılmış enum’lar gibi şeyler kullanan daha Rustvari bir durum makinesine dönüştürmek çok zor olur
Yeterince güçlü bir yapay zekanın yardımıyla mümkün olabilir belki; ama yapay zeka, amaçlanan işi gerçekten yapma konusunda hâlâ oldukça yetersiz, bu yüzden henüz hazır demek zor. Ayrıca tüm C ve Rust kod tabanlarını bağlam penceresine sığdıracak kadar belleğe ihtiyaç olur; kod belli bir ölçeği aşınca bu hızla çok pahalı donanım gerektirir. Aksi hâlde, birçok kod yardımcı LLM gibi, birbirleriyle uyumsuz kodları bağımsız olarak üretir
Yine de bir C projesini Rust ile genişletmek ya da parça parça yeniden yazmak istiyorsanız https://c2rust.com/ hemen kullanılabilir
Rust; paket yönetimi, sadeleştirilmiş birleşik derleme/test araçları, çok daha az eski yük, insanların gerçekten sevdiği üst düzey özellikler ve sözdizimi olan modern bir dil
C de temiz bir dil, ama karmaşık kod tabanları, C’nin hızını korurken sağlam soyutlamalar oluşturmaya yardımcı olan modern bir dilin avantajlarından yararlanır. Elbette ödünç alma denetleyicisi ve bellek güvenliği de cabası
Yeterince standart C kodu üreten bir Rust→C dönüştürücüsü varsa bu boşluğu kapatabilir