Rust: Ajarkan rustc untuk melakukan panggilan ekor

Dibuat pada 27 Jan 2011  ·  18Komentar  ·  Sumber: rust-lang/rust

Rustc belum tahu bagaimana melakukan panggilan ekor ('menjadi' daripada 'ret'). Seharusnya tidak terlalu sulit untuk mengajarkannya.

A-LLVM

Komentar yang paling membantu

Kami memiliki rencana untuk menerapkan TCO yang dijamin, jika memungkinkan. Kami bahkan memesan kata kunci untuk itu, "menjadi". Silakan periksa repo RFC.

Pada 3 Agustus 2016, 19:46 -0400, Antoine [email protected] , menulis:

Saya berita di karat dan saya sangat sedih. Saya mencoba fungsi rekursif ekor dan saya menumpuk overflow dengan sangat cepat. terburuk ketika saya mengkompilasi dalam rilis perubahan perilaku. Dia hanya tidak memanggil fungsi saya. Seorang teman berkata kepada saya bahwa LLVM mengoptimalkan nilai yang tidak ditentukan (LLVM tahu itu adalah rekursi ekor tak terbatas?!?).

fn rec(i: i32) { rec(i + 1) } fn main() { println!("{}", rec(0)); }

Saya setuju dengan Boiethios, bahasa dengan fitur fungsional yang tidak mengimplementasikan panggilan ekor melewatkan sesuatu.

Saya menulis dalam C dan C++, mereka tidak menjamin panggilan ekor tetapi sebenarnya mereka menanganinya dengan sangat baik. Itu tidak akan menghentikan saya untuk belajar karat, sekarang saya tahu bahwa karat tidak menanganinya, saya akan membuat kode tanpanya jadi itu bukan masalah besar.

Tapi saya pikir itu adalah fitur yang sangat bagus untuk bahasa modern.


Anda menerima ini karena Anda berlangganan utas ini.
Balas email ini secara langsung, lihat di GitHub (https://github.com/rust-lang/rust/issues/217#issuecomment-237409642), atau nonaktifkan utas (https://github.com/notifications/unsubscribe -auth/AABsipoedHrbnKDekmzCr-dl8M6g-Gojks5qcShKgaJpZM4AC-q_).

Semua 18 komentar

Per Graydon, kita perlu memikirkan lebih banyak tentang konvensi pemanggilan sebelum mengimplementasikan ini. LLVM memerlukan konvensi fastcc untuk mengimplementasikan panggilan ekor, tetapi tidak melakukan apa yang kita inginkan:

greydon: brson: dilihat dari komentar di llvm-land, kita mungkin dalam masalah. kita mungkin bisa mengimbangi apa yang fastcc lakukan hari ini, tapi itu diperbolehkan untuk berubah pikiran besok.
greydon: Saya pikir fastcc == x86_fastcall, tapi saya salah.
greydon: itu adalah konvensi pemanggilan yang berbeda. fastcc adalah "apa pun rasanya llvm minggu ini"
greydon: kita perlu beralih ke x86_fastcall dan kemudian, dalam jangka panjang, menulis konvensi pemanggilan kita sendiri.

Ini saat ini setengah diterapkan karena beberapa komplikasi dalam cara LLVM menangani panggilan ekor. Rustc mem-parsing ekspresi 'be' dan menerjemahkannya sebagai call+ret pair, yang cukup untuk membuat kita 'bekerja' pada kasus sederhana yang tidak terlalu dalam. Mungkin cukup untuk bootstrap.

Tampaknya hanya ada satu CC (fastcc) yang mendukung panggilan ekor yang dijamin, dan untuk beradaptasi dengannya kami perlu mengubah asumsi ABI kami di beberapa tempat (berubah menjadi callee-restore ketika Anda mengaktifkan flag -tailcallopt). Jadi, meskipun kami memberi anotasi pada pasangan panggilan+ret kami dengan 'ekor', seperti yang diperlukan, kami sebenarnya belum dapat memberi tahu LLVM untuk mulai melakukan pengoptimalan itu.

Ternyata tidak membutuhkan lebih banyak implementasi daripada yang ditampilkan di sini untuk hosting sendiri. Punting ke tonggak berikutnya.

Adakah yang merasa kita benar-benar akan melakukan ini lagi?

Sepertinya itu tidak akan terjadi.

Bagaimana situasi dengan LLVM dan panggilan ekor? Jika mereka dapat dibuat untuk bekerja dengan andal tanpa beberapa hal invasif seperti mendeklarasikan callee untuk dipanggil ekor, kita dapat mendefinisikan serangkaian hal terbatas yang dapat diteruskan ke panggilan ekor (argumen pemanggil sendiri, skalar), dan kesalahan ketika sesuatu lain dilewatkan. Panggilan ekor seperti itu mungkin tidak terlalu berguna dalam praktiknya.

Mereka hanya bekerja dengan callee ABI yang suboptimal dalam kasus non-tail-call. Jadi dalam arti tertentu, ya, mereka membutuhkan callee untuk dideklarasikan-to-be-tail-dipanggil.

Kita dapat mengimplementasikan ini dengan, katakanlah, menganalisis peti dan ketika kita menemukan fungsi yang dipanggil ekor, baik mengompilasinya secara terpisah di bawah ABI friendly-to-tail-call, atau mengkompilasi pembungkus yang mengaktifkan ABI saat masuk, atau semacamnya. Atau sebagai alternatif, kita dapat mengganti fungsi _every_ di mana saja untuk menggunakan ABI yang ramah panggilan. Saya tidak yakin apakah kita sedang melakukan itu. Kami untuk sementara waktu tetapi kami mungkin telah berhenti. Ini adalah ABI "panggilan cepat" LLVM, yang menurut saya tidak lagi kita gunakan.

Bagaimanapun, ini sedikit berantakan.

Kami memiliki pengoptimalan panggilan saudara, sekarang. Apakah kita berencana untuk mencoba berbuat lebih banyak?

Tidak akan terjadi, kecuali sejauh ditangani oleh #2216. Solusi untuk #2216 harus cukup luas untuk mendukung pengkodean mesin keadaan umum.

Ini terus muncul dalam percakapan, dan kami telah memesan be lagi. Pembukaan kembali.

Saya pikir komentar Graydon di milis:

https://mail.mozilla.org/pipermail/rust-dev/2013-April/003557.html

menempatkan paku di peti mati ini. Direproduksi di sini:


Pada 10/04/2013 5:43 AM, Artella Coding menulis:

Hai, apakah karat melakukan optimasi panggilan ekor? Alasan saya bertanya adalah
implementasi rekursif panggilan ekor berikut menghasilkan tumpukan
meluap. Terima kasih.

Tidak, dan kemungkinan besar tidak akan. Kami memiliki bug lama dalam hal ini:

https://github.com/mozilla/rust/issues/217

serta halaman wiki dan beberapa utas milis:

https://github.com/mozilla/rust/wiki/Bikeshed-tailcall
https://mail.mozilla.org/pipermail/rust-dev/2011-August/000689.html
https://mail.mozilla.org/pipermail/rust-dev/2012-January/001280.html
...

Ringkasan dari semua ini adalah:

  • Kita semua tahu bahwa panggilan ekor adalah fitur bahasa yang baik.
    Elaborasi lebih lanjut dari kebajikan mereka tidak diperlukan. Banyak dari kita
    memiliki latar belakang cadel dan ML dan sangat menyukainya. Milik mereka
    ketidakhadiran adalah sakit hati dan kesedihan, tidak ditanggapi dengan enteng.
  • Tail menyebut "bermain buruk" dengan kehancuran deterministik. Termasuk
    penurunan deterministik kotak ~. Bukan untuk mengatakan bahwa mereka tidak
    dapat dikomposisi, tetapi opsi untuk menyusunnya adalah UI-canggung,
    kinerja-menghukum, semantik-merumitkan atau semua hal di atas.
  • Panggilan ekor juga "bermain buruk" dengan asumsi di alat C, termasuk
    platform ABI dan penautan dinamis.
  • Panggilan ekor memerlukan konvensi panggilan yang merupakan hit kinerja
    relatif terhadap konvensi C.
  • Kami menemukan sebagian besar kasus tail _recursion_ dikonversi dengan cukup baik ke
    loop, dan sebagian besar kasus panggilan ekor non-rekursif menyandikan status
    mesin yang mengkonversi cukup baik ke loop melilit
    enum. Tak satu pun dari ini _cukup_ secantik
    varian tail-call-menggunakan, tetapi mereka berfungsi dan "secepat"*,
    serta idiomatik untuk programmer C dan C++ (yang merupakan
    audiens utama).

Saya minta maaf untuk mengatakan semua ini, dan dengan berat hati, tapi kami
mencoba dan tidak menemukan cara untuk membuat pengorbanan yang terkait dengannya
meringkas argumen untuk dimasukkan dalam karat.

-Graydon

  • dari segi kecepatan, mesin status switch-in-a-loop adalah pengiriman tidak langsung jadi
    kemungkinan akan berjalan lebih lambat daripada mesin negara yang dikodekan oleh panggilan ekor dari
    negara ke negara; di sisi lain jika cara untuk mendapatkan kinerja ini
    "kembali" adalah untuk mengaktifkan panggilan ekor di mana-mana, kami akan memperdagangkan satu yang terisolasi
    kasus kinerja suboptimal untuk pajak kinerja suboptimal lintas semua program. Kita
    tidak menemukan perdagangan ini dapat diterima.

Mungkin perlu dicatat bahwa Haskell biasanya membutuhkan transformasi argumen statis untuk inlining, fusion, dll. http://stackoverflow.com/a/9660027/667457

Rust dapat mendukung transformasi argumen statis dengan mengatakan bahwa fungsi yang didefinisikan di dalam fungsi lain harus memenuhi syarat untuk optimasi tailcall. Atau cukup peringatkan jika panggilan ekor antar fungsi yang bersarang di dalam fungsi lain gagal optimasi saudara. Tidak yakin dengan situasi saat ini.

Sayangnya rekursi ekor tidak akan diimplementasikan. Lalu saya punya pertanyaan: mengapa membuat sintaks bahasa yang tampak seperti sintaksis bahasa fungsional jika tidak ada fitur esensial fungsional?

Saya berita di karat dan saya sangat sedih. Saya mencoba fungsi rekursif ekor dan saya menumpuk overflow dengan sangat cepat. terburuk ketika saya mengkompilasi dalam rilis perubahan perilaku. Dia hanya tidak memanggil fungsi saya. Seorang teman berkata kepada saya bahwa LLVM mengoptimalkan ke nilai yang tidak ditentukan (LLVM tahu itu adalah rekursi ekor yang tak terbatas?!?).

fn rec(i: i32) {
  rec(i + 1)
}

fn main() {
  println!("{}", rec(0));
}

Saya setuju dengan Boiethios, bahasa dengan fitur fungsional yang tidak menerapkan panggilan ekor melewatkan sesuatu.

Saya menulis dalam C dan C++, mereka tidak menjamin panggilan ekor, tetapi sebenarnya mereka menanganinya dengan sangat baik. Itu tidak akan menghentikan saya untuk belajar karat, sekarang saya tahu bahwa karat tidak menanganinya. Saya akan membuat kode tanpa jadi itu bukan masalah besar.

Tapi saya pikir itu adalah fitur yang sangat bagus untuk bahasa modern.

perhatikan itu

fn rec(i: i32) {
  println!("Hello");
  rec(i + 1)
}

stack overflow juga dalam mode pelepasan kargo

Kami memiliki rencana untuk menerapkan TCO yang dijamin, jika memungkinkan. Kami bahkan memesan kata kunci untuk itu, "menjadi". Silakan periksa repo RFC.

Pada 3 Agustus 2016, 19:46 -0400, Antoine [email protected] , menulis:

Saya berita di karat dan saya sangat sedih. Saya mencoba fungsi rekursif ekor dan saya menumpuk overflow dengan sangat cepat. terburuk ketika saya mengkompilasi dalam rilis perubahan perilaku. Dia hanya tidak memanggil fungsi saya. Seorang teman berkata kepada saya bahwa LLVM mengoptimalkan nilai yang tidak ditentukan (LLVM tahu itu adalah rekursi ekor tak terbatas?!?).

fn rec(i: i32) { rec(i + 1) } fn main() { println!("{}", rec(0)); }

Saya setuju dengan Boiethios, bahasa dengan fitur fungsional yang tidak mengimplementasikan panggilan ekor melewatkan sesuatu.

Saya menulis dalam C dan C++, mereka tidak menjamin panggilan ekor tetapi sebenarnya mereka menanganinya dengan sangat baik. Itu tidak akan menghentikan saya untuk belajar karat, sekarang saya tahu bahwa karat tidak menanganinya, saya akan membuat kode tanpanya jadi itu bukan masalah besar.

Tapi saya pikir itu adalah fitur yang sangat bagus untuk bahasa modern.


Anda menerima ini karena Anda berlangganan utas ini.
Balas email ini secara langsung, lihat di GitHub (https://github.com/rust-lang/rust/issues/217#issuecomment-237409642), atau nonaktifkan utas (https://github.com/notifications/unsubscribe -auth/AABsipoedHrbnKDekmzCr-dl8M6g-Gojks5qcShKgaJpZM4AC-q_).

Hanya sebuah pertanyaan: Secara hipotetis mungkin untuk melakukan analisis grafik panggilan dan mengubah panggilan ekor menjadi loop, setidaknya dalam satu peti, tetapi secara komputasi mahal pada waktu kompilasi dan cukup rumit untuk dikodekan. Apakah ada diskusi tentang kemungkinan ini? Itu masih menjadi pilihan sekarang, tanpa memperhatikan pilihan konvensi pemanggilan.

Pendekatan lbstanza adalah meminta anotasi fungsi agar memenuhi syarat untuk TCO (defn+ alih-alih defn). Dalam karat, itu sebagian besar akan mengurangi overhead waktu kompilasi tambahan untuk saran timthelion, asalkan Anda tidak menggunakan panggilan ekor secara harfiah di mana-mana lol.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat