Kompiler Rust ke C Mencapai Tingkat Kelulusan Tes 95,9%
(fractalfir.github.io)rustc_codegen_clradalah proyek yang menghasilkan kode Rust ke C dan .NET, dan sedang bersiap untuk presentasi Rust Week seiring peningkatan tingkat kelulusan tes- Tingkat kelulusan tes Rust core naik dari 92% dua bulan lalu menjadi 95,9%, dan sekitar 65 tes yang tersisa tampaknya memiliki penyebab yang saling mirip
- Perbaikan terbaru berfokus pada intrinsic integer 128-bit, checked arithmetic, dan subslicing; sisi .NET juga kini dapat menjalankan 96,3% tes Rust core
- Dengan target lebih banyak kompiler C, proyek ini bertujuan menghasilkan output yang mendekati C99 atau ANSI C serta menggunakan API POSIX standar; beberapa kompiler ANSI C berhasil menjalankan program Rust yang sangat sederhana
- Optimasi untuk mengurangi ukuran file pada pembuatan kode C berskala besar dan refactoring IR internal juga berjalan bersamaan, menjadi fondasi untuk memperluas jangkauan eksekusi Rust ke platform lama atau khusus
Presentasi Rust Week dan status proyek
- Presentasi proyek
rustc_codegen_clrdijadwalkan di Rust Week yang digelar di Utrecht, Belanda - Presentasi ini berupaya menyeimbangkan aksesibilitas bagi pemula dengan topik tingkat lanjut, yaitu kompilasi Rust ke C
- Dalam beberapa bulan terakhir, perbaikan tes, kompatibilitas kompiler C, peningkatan performa, dan refactoring internal berjalan bersamaan
Tingkat kelulusan tes Rust core meningkat
- Tingkat kelulusan tes Rust core meningkat dari 92% dua bulan lalu menjadi 95,9%
- Masih ada sekitar 65 tes yang tersisa, tetapi penyebabnya tampak saling mirip sehingga karakter perbaikan yang tersisa relatif sudah menyempit
- Sisi .NET juga terdampak perbaikan yang sama dan kini dapat menjalankan 96,3% tes Rust core
Perbaikan integer 128-bit dan checked arithmetic
- Sebagian besar peningkatan berasal dari perbaikan intrinsic 128-bit, checked arithmetic, dan subslicing
- Intrinsic
popcountdi C terdiri dari tiga jenis:__builtin_popcount,__builtin_popcountl, dan__builtin_popcountll- Berbeda dari namanya,
__builtin_popcountllbekerja padaunsigned long long, bukan__int128_t - Berdasarkan x86_64 Linux dan GCC,
unsigned longmaupununsigned long longsama-sama 64-bit
- Berbeda dari namanya,
- Implementasi sebelumnya pada intrinsic bit counting diam-diam memotong integer 128-bit menjadi 64-bit saat menghitung, sehingga menghasilkan hasil yang salah
popcount128-bit diemulasikan dengan menghitung jumlah set bit pada 64-bit bawah dan 64-bit atas secara terpisah, lalu menjumlahkannya- Overflow check untuk perkalian 128-bit ditangani dengan cara sederhana karena belum ditemukan metode yang efisien
- Jika
bbukan 0 dan(a * b) / b == a, maka dianggap tidak terjadi overflow - Ini bukan metode yang revolusioner, tetapi cukup untuk meloloskan beberapa tes tambahan
- Jika
Bug subslicing dan intrinsic fallback
- Bug subslicing disebabkan oleh
sizeofyang hilang, sehingga pointer data slice di-offset dalam satuan byte, bukan satuan elemen - Bug ini hanya rusak saat melakukan subslicing dari akhir slice, bukan dari awal, dan karena pola ini terutama dipakai dalam pattern matching, bug tersebut lama tidak ditemukan
- Pada byte slice dan string slice, ukuran byte dan UTF-8 code unit adalah 1 byte sehingga tes internalnya lolos, dan masalah baru terlihat di seluruh suite tes Rust compiler
- Sebagian intrinsic dapat menggunakan implementasi fallback milik Rust compiler tanpa perlu diimplementasikan langsung
carrying_mul_addharus melakukan perkalian pada integer yang 2 kali lebih besar daripada input- Hingga 64-bit masih bisa ditangani, tetapi input 128-bit membutuhkan integer 256-bit
- LLVM mendukung integer 256-bit, tetapi C dan .NET tidak
- Implementasi fallback Rust compiler melakukan perkalian dan penjumlahan 256-bit dengan integer 128-bit, sehingga dapat dijadikan referensi untuk mengemulasikan operasi 128-bit hanya dengan integer 64-bit
Dukungan untuk lebih banyak kompiler C
- Proyek ini berupaya meningkatkan kemungkinan kode Rust berjalan di lebih banyak kompiler C khusus
- Ada kasus ketika kode Rust berjalan di Game Boy, dikompilasi hanya dengan perintah move, atau dijalankan dengan Holly C dari Temple OS
- Kompiler C proprietary yang tidak dapat diakses memang tidak bisa didukung secara langsung, tetapi dengan memperluas cakupan dukungan kompiler C obscure, peluang kode Rust berjalan di lingkungan seperti itu meningkat
- Banyak platform tidak didukung karena kurangnya dokumentasi dan aksesibilitas
- Terkait diskusi penulisan sebagian Git dengan Rust, platform proprietary seperti NonStop tidak mendukung Rust, LLVM, maupun GCC, sehingga bisa muncul masalah penurunan atau penghentian dukungan Git
- Jika Rust dikompilasi ke C, secara teoretis Rust dapat dijalankan di mana pun C tersedia
- Belum pasti apakah masalah di semua platform dapat diakali
- Untuk memperoleh kompiler bagi platform tersebut secara legal, perlu membeli server, dan biayanya jauh melampaui anggaran
- Kemungkinan Rust segera berjalan di platform semacam ini tampaknya kecil
Strategi output C saat ini
- Rencana saat ini adalah menghasilkan kode yang sedapat mungkin mematuhi standar C99 atau mendekati ANSI C
- Karena beberapa dukungan threading diperlukan untuk inisialisasi thread-local, arahnya adalah hanya menggunakan API POSIX standar
- Proyek ini memiliki implementasi fallback sendiri untuk intrinsic tertentu, dan daftarnya ditambah secara bertahap
- Beberapa kompiler ANSI C berhasil menjalankan program Rust yang sangat sederhana
- Untuk saat ini, targetnya adalah membuat platform yang masih sulit didukung dapat ditambahkan dengan relatif mudah ketika kebutuhan muncul
Peningkatan kecil pada performa dan ukuran file
- Output literal integer kini mencerminkan bahwa integer yang lebih kecil dari 2^32 sama panjang atau lebih pendek dalam decimal dibanding hexadecimal
255lebih pendek 1 byte daripada0xFF65536juga lebih pendek daripada0xFFFF- Karena prefix
0x, representasi hexadecimal tidak menjadi lebih kecil sebelum 2^32
- Dalam kasus ekstrem ketika seluruh Rust compiler dikonversi ke C, pernah dihasilkan C source file hingga 1GB, sehingga pengurangan ukuran file dalam persentase kecil pun berpengaruh
- Directive
#lineyang digunakan untuk menyisipkan debug info juga dibuat lebih cerdas- Nama source file hanya disertakan ketika berubah
- Saat debug info digunakan, ini dapat mengurangi ukuran file secara signifikan
Refactoring internal dan perapihan IR
- Sebagian fungsi internal
rustc_codegen_clrdipisahkan menjadi crate tersendiri untuk mempercepat incremental build - Pekerjaan untuk berpindah ke interned IR yang lebih efisien secara memori juga sedang berjalan
- IR lama memiliki rvalue/lvalue yang tidak lazim dan sulit dipetakan ke C, dan masalahnya membesar pada fitur Rust seperti dynamically sized type
- Sebagai contoh, pada custom dynamically sized type seperti
MyStr,&self.sterlihat sederhana tetapi sebenarnya harus menangani metadata fat pointer- Dengan compound literal C99,
struct FatPtr_strdapat dibuat dalam satu baris - Di ANSI C,
datadanmetaharus masing-masing dimasukkan ke variabel sementara lalu dikembalikan
- Dengan compound literal C99,
- Karena satu baris Rust dan MIR berkembang menjadi beberapa baris C, IR lama menanganinya dengan pendekatan scope internal yang memiliki temporary local dan sub-statement
- Pendekatan baru memiliki tahap setup yang lebih kompleks, tetapi membuat keseluruhan IR lebih sederhana; setelah kasus sulit terakhir terselesaikan, fungsi terkait di IR lama dapat dihapus
Pekerjaan berikutnya
- Masa pengerjaan proyek sudah sekitar 1,5 tahun, dan semakin sedikit bug, semakin banyak waktu yang diperlukan untuk menemukan bug yang tersisa
- Bagian kedua “Rust panics under the hood” sedang dikerjakan, dengan tujuan menguraikan proses panic Rust langkah demi langkah
- Penjelasan pembuatan panic message saja sudah berdurasi 10 menit, sehingga tulisan itu juga sedang dipertimbangkan untuk dibagi dua
- Sebuah memory profiler kecil dan akurat untuk Rust juga sedang dikerjakan
- Skala kodenya sekitar 2K LOC
- Jadwalnya ketat, tetapi penulis ingin menulis artikel terkait dalam beberapa minggu
1 komentar
Komentar Hacker News
Awalnya proyek rustc_codegen_gcc menjanjikan ini, tetapi pada akhirnya tidak memenuhinya
[0] https://github.com/rust-lang/compiler-team/issues/458
Untuk GCC/Clang, angkanya “hanya” 80%
| .NET Core tests | 1764 | 48 | 20 | 96.29% |
| C Core tests | 1712 | 71 | 8 | 95.59% |
Hack ini adalah backend compiler Rust. Karena backend menerima instruksi spesifik platform sebagai input, kode C nontrivial yang dihasilkan tidak akan portabel
Pengguna harus menerima source spesifik platform yang sudah dibuat sebelumnya, atau memasang compiler Rust dan backend ini lalu membuatnya sendiri
extern "c"di Rust?“Representasi .NET IR saya terpetakan dengan baik ke C, dan berkat itu saya bisa menambahkan dukungan untuk mengompilasi Rust ke C hanya dengan 2–3 ribu baris kode. Hampir seluruh codebase digunakan kembali, dan kode khusus C maupun .NET hanya ada pada tahap paling akhir kompilasi”
Awalnya dimulai sebagai backend .NET, tetapi kemudian diketahui bahwa pendekatannya juga bisa dengan mudah mendukung pembuatan kode C, jadi ditambahkan. Ia mengubah apa yang diberikan rustc menjadi intermediate representation (IR) miliknya sendiri lalu memprosesnya
Jaminan dinamis seperti pemeriksaan batas juga bisa diimplementasikan tanpa masalah di runtime C
unsafebesarC tidak membawa semua informasi yang perlu diketahui secara eksplisit agar bisa dikompilasi di Rust
https://www.youtube.com/watch?v=1VgptLwP588
unsafe, dan biasanya kode hasilnya tidak terasa Rust-idiomatisMisalnya, mengubah mesin status berbasis variabel global menjadi mesin status yang lebih Rust-idiomatis dengan enum bernama dan semacamnya akan sangat sulit
Mungkin bisa dengan bantuan AI yang cukup kuat, tetapi AI masih jauh dari mampu benar-benar melakukan hal yang dimaksud, jadi sulit dibilang sudah siap. Dibutuhkan juga memori yang cukup untuk memasukkan seluruh codebase C dan Rust ke dalam context window; setelah kode melewati ukuran tertentu, ini cepat sekali membutuhkan hardware yang sangat mahal. Kalau tidak, seperti banyak LLM pendamping coding, ia akan menghasilkan kode-kode yang tidak saling kompatibel secara independen
Meski begitu, jika ingin memperluas proyek C dengan Rust atau menulis ulang sedikit demi sedikit, https://c2rust.com/ sudah bisa langsung dipakai
Rust adalah bahasa modern dengan manajemen paket, alat build/test terpadu yang lebih sederhana, beban warisan yang jauh lebih sedikit, serta fitur dan sintaks tingkat tinggi yang benar-benar disukai orang
C juga bersih, tetapi codebase yang kompleks mendapat manfaat dari bahasa modern yang membantu membuat abstraksi yang kokoh sambil mempertahankan kecepatan C. Tentu saja borrow checker dan keamanan memori juga tidak boleh dilupakan
Jika ada konverter Rust→C yang menghasilkan kode C yang cukup standar, itu bisa menjembatani celah tersebut