Mengapa representasi intermediate (LLVM IR) LLVM lebih mirip perakitan daripada pohon?
Atau, mengapa implementasi bahasa menargetkan LLVM IR daripada AST clang?
Saya tidak mencoba mengajukan dua pertanyaan berbeda sekaligus jika tampaknya demikian. Bagi saya, sepertinya klien dan pemrogram perpustakaan telah mencapai kesepakatan bahwa API LLVM, tidak lebih dan tidak kurang, jelas merupakan desain perangkat lunak yang baik dan pertanyaan saya adalah "mengapa?".
Alasan saya bertanya adalah sepertinya LLVM dapat memberikan lebih banyak fungsi ke frontend jika IR-nya seperti AST karena alat berbasis AST yang berdering dapat digunakan untuk frontend apa pun. Atau, bahasa yang menargetkan LLVM IR bisa mendapatkan lebih banyak fungsi jika mereka menargetkan AST dentang.
Clang memiliki kelas dan fungsi untuk membuat dan bekerja dengan AST dan itu satu - satunya proyek frontend yang sangat terkait dengan proyek LLVM jadi mengapa AST-fungsionalitas clang eksternal ke LLVM?
Dari atas kepala saya, saya tahu bahwa Rust (rustc), D (ldc), dan Haskell (GHC) semua dapat menggunakan LLVM sebagai backend tetapi mereka tidak menggunakan Dentang Dentang (sejauh yang saya tahu, saya bisa salah). Saya tidak tahu semua detail internal dari kompiler ini, tetapi setidaknya Rust dan D sepertinya bisa dikompilasi ke AST clang. Mungkin Haskell juga bisa, tetapi saya kurang yakin tentang itu.
Apakah ini karena alasan historis (LLVM awalnya menjadi "mesin virtual tingkat rendah" dan berbunyi nanti)? Apakah ini karena frontend lain ingin memiliki kontrol sebanyak mungkin atas apa yang mereka berikan ke LLVM? Apakah ada alasan mendasar bahwa AST dentang tidak sesuai untuk bahasa "non-C-like"?
Saya tidak bermaksud pertanyaan ini menjadi latihan dalam mindreading. Saya hanya ingin itu bermanfaat bagi kita yang ingin tahu, tetapi belum lancar dalam, desain kompiler. Karena proyek LLVM dan dentang dikembangkan di depan umum, saya berharap seseorang yang akrab dengan pengembangan proyek-proyek ini dapat menjawab atau bahwa jawabannya cukup jelas bagi beberapa kutu buku yang dikompilasi sehingga mereka merasa cukup percaya diri untuk menjawab.
Untuk mencegah beberapa jawaban yang jelas tetapi tidak memuaskan:
Ya, memiliki IR seperti perakitan memberikan lebih banyak kontrol kepada siapa pun yang membuat IR (mungkin X lang memiliki basis kode dan format AST yang lebih baik daripada dentang) tetapi jika itu satu-satunya jawaban, maka pertanyaannya adalah "mengapa hanya LLVM memiliki perakitan - seperti IR daripada IR seperti pohon tingkat tinggi dan IR seperti perakitan tingkat rendah? "
Ya, tidak sulit untuk mem-parsing bahasa pemrograman menjadi AST (setidaknya dibandingkan dengan langkah-langkah kompilasi lainnya). Meski begitu, mengapa menggunakan AST terpisah? Jika tidak ada yang lain, menggunakan AST yang sama memungkinkan Anda untuk menggunakan alat yang beroperasi pada AST (bahkan hanya hal-hal sederhana seperti printer AST).
Ya saya sangat setuju bahwa menjadi lebih modular adalah hal yang baik, tetapi jika itu satu-satunya alasan, lalu mengapa implementasi bahasa lain cenderung menargetkan LLVM IR daripada AST dentang?
Pre-emptions ini mungkin keliru atau mengabaikan detail, jadi jangan ragu untuk memberikan jawaban ini jika Anda memiliki lebih banyak detail atau asumsi saya salah.
Bagi siapa pun yang ingin menjawab pertanyaan yang lebih dapat dijawab secara pasti: apa keuntungan dan kerugian dari IR seperti perakitan vs IR seperti pohon?
sumber
Jawaban:
Ada sejumlah pertanyaan yang saling terkait di sini, saya akan mencoba untuk memisahkan mereka sebaik mungkin.
Mengapa bahasa lain menggunakan LLVM IR dan tidak menggunakan AST?
Ini hanya karena dentang adalah ujung depan C / C ++ dan AST yang dihasilkannya tergabung erat dengan C / C ++. Bahasa lain dapat menggunakannya tetapi perlu semantik identik untuk beberapa bagian dari C / C ++ yang sangat terbatas. Seperti yang Anda tunjukkan, menguraikan AST cukup mudah sehingga membatasi pilihan semantik Anda tidak akan sebanding dengan penghematan yang kecil.
Namun, jika Anda menulis alat untuk C / C ++ misal analisa statis, maka menggunakan kembali AST sangat masuk akal karena jauh lebih mudah untuk bekerja dengan AST daripada teks mentah jika Anda bekerja dengan C / C ++ .
Mengapa LLVM IR adalah bentuknya?
LLVM IR dipilih sebagai bentuk yang sesuai untuk menulis optimisasi kompiler. Dengan demikian, fitur utamanya adalah bahwa itu dalam bentuk SSA . Ini adalah level IR yang cukup rendah sehingga dapat diterapkan pada berbagai bahasa misalnya tidak mengetik memori karena ini sangat bervariasi antar bahasa.
Sekarang, kebetulan bahwa penulisan optimisasi kompiler adalah tugas yang cukup spesialis dan sering ortogonal untuk desain fitur bahasa. Namun, memiliki bahasa yang dikompilasi berjalan cepat adalah persyaratan yang cukup umum. Juga, konversi dari LLVM IR ke ASM cukup mekanis dan umumnya tidak menarik bagi perancang bahasa.
Oleh karena itu, menurunkan bahasa ke LLVM IR memberi perancang bahasa banyak "barang gratis" yang sangat berguna dalam praktik membuat mereka berkonsentrasi pada bahasa itu sendiri.
Apakah IR yang berbeda berguna (OK, tidak ditanyakan tetapi semacam tersirat)?
Benar! AST cukup baik untuk transformasi tertentu pada struktur program tetapi sangat sulit digunakan jika Anda ingin mengubah aliran program. Bentuk SSA umumnya lebih baik. Namun, LLVM IR adalah level yang sangat rendah sehingga banyak struktur level tinggi hilang (dengan sengaja sehingga lebih umum berlaku). Memiliki IR antara AST dan IR level rendah dapat bermanfaat di sini. Baik Rust dan Swift mengambil pendekatan ini dan memiliki IR tingkat tinggi di antara keduanya.
sumber