Rustc aún no sabe cómo hacer llamadas de cola ('be' en lugar de 'ret'). No debería ser demasiado difícil enseñarle cómo hacerlo.
Según Graydon, tenemos que pensar un poco más en llamar convenciones antes de implementar esto. LLVM requiere la convención fastcc para implementar llamadas de cola, pero no hace exactamente lo que queremos:
graydon: brson: a juzgar por los comentarios en llvm-land, podemos estar en problemas. es posible que podamos compensar lo que fastcc está haciendo hoy, pero se le permite cambiar de opinión mañana.
graydon: Pensé fastcc == x86_fastcall, pero estaba equivocado.
graydon: esas son convenciones de llamadas diferentes. fastcc es "lo que se siente llvm esta semana"
graydon: necesitamos cambiar a x86_fastcall y luego, a más largo plazo, escribir nuestra propia convención de llamadas.
Actualmente, esto se implementa a medias debido a algunas complicaciones en la forma en que LLVM trata las llamadas de cola. Rustc analiza las expresiones 'be' y las traduce como pares call+ret, lo cual es suficiente para que podamos 'trabajar' en casos simples, no muy profundos. Podría ser suficiente para arrancar.
Aparentemente, solo hay un CC (fastcc) que admite llamadas de seguimiento garantizadas y, para adaptarnos a él, debemos cambiar nuestras suposiciones de ABI en varios lugares (se convierte en restauración de llamadas cuando habilita el indicador -tailcallopt). Entonces, incluso si anotamos nuestros pares call+ret con 'tail', según sea necesario, no podemos decirle a LLVM que comience a realizar esa optimización todavía.
Resultó que no necesitaba más implementación de la que se muestra aquí para el alojamiento propio. Punting al próximo hito.
¿Alguien siente que en realidad vamos a hacer esto nunca más?
No parece que vaya a suceder.
¿Cuál es la situación con LLVM y llamadas de cola? Si se puede hacer que funcionen de manera confiable sin algunas cosas invasivas como declarar que la persona que llama recibe una llamada final, podríamos definir un conjunto limitado de cosas que se pueden pasar a llamadas posteriores (argumentos propios de la persona que llama, escalares) y error cuando algo se pasa lo demás. Sin embargo, tales llamadas de cola pueden no ser muy útiles en la práctica.
¿Es posible que mirar el backend GHC LLVM de Haskell pueda ser útil?
http://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/Backends/LLVM
http://llvm.org/docs/LangRef.html#callingconv
http://llvm.org/docs/CodeGenerator.html#tailcallopt
Solo funcionan con un ABI de destinatario de la llamada que es subóptimo en casos que no son de cola. Entonces, en cierto sentido, sí, requieren que se declare que el destinatario de la llamada será llamado de cola.
Podríamos implementar esto, por ejemplo, analizando una caja y cuando encontremos una función que se llama tail, ya sea compilándola por separado bajo el ABI de llamada amigable a cola, o compilando envoltorios que cambian ABI en la entrada, o algo así. O, alternativamente, podemos cambiar _todas_ las funciones en todas partes para usar el ABI compatible con las llamadas posteriores. No estoy seguro de si actualmente estamos haciendo eso. Estuvimos un tiempo, pero es posible que hayamos parado. Es el ABI de "llamada rápida" de LLVM, que no creo que estemos usando más.
En cualquier caso, es un poco de un lío.
Tenemos optimización de llamadas entre hermanos, ahora. ¿Planeamos intentar hacer más?
No va a suceder, excepto en la medida en que se aborda en el n.° 2216. La solución para #2216 debe ser lo suficientemente amplia como para admitir la codificación de máquina de estado general.
Esto continúa surgiendo en la conversación y hemos reservado be
nuevamente. Reapertura.
Creo que el comentario de Graydon en la lista de correo:
https://mail.mozilla.org/pipermail/rust-dev/2013-April/003557.html
pone un clavo en este ataúd. Reproducido aquí:
El 04/10/2013 a las 5:43 a. m., Artella Coding escribió:
Hola, ¿el óxido optimiza la cola de llamadas? La razón por la que pregunto es que
la siguiente implementación recursiva de llamada de cola da como resultado una pila
Desbordamiento. Gracias.
No, y muy probablemente no lo hará. Tenemos un error de larga data en esto:
https://github.com/mozilla/rust/issues/217
así como una página wiki y varios hilos de listas de correo:
https://github.com/mozilla/rust/wiki/Bikeshed-tailcall
https://mail.mozilla.org/pipermail/rust-dev/2011-agosto/000689.html
https://mail.mozilla.org/pipermail/rust-dev/2012-January/001280.html
...
El resumen de todo esto es:
Lamento decir todo esto, y es con gran pesar en mi corazón, pero
intentó y no encontró una manera de hacer las compensaciones asociadas con ellos
resumen a un argumento para la inclusión en el óxido.
-Graydon
Tal vez valga la pena señalar que Haskell comúnmente necesita una transformación de argumento estático para insertar, fusionar, etc. http://stackoverflow.com/a/9660027/667457
Rust podría respaldar la transformación de argumento estático al decir que las funciones definidas dentro de otra función deberían ser elegibles para las optimizaciones de llamada final. O simplemente advierta si las llamadas posteriores entre funciones anidadas dentro de otra función fallaron en la optimización del hermano. No estoy seguro de la situación actual.
Es triste que no se implemente la recursividad de la cola. Entonces tengo una pregunta: ¿por qué crear una sintaxis de lenguaje que parezca una sintaxis de lenguaje funcional si carece de una característica esencial de funcional?
Soy noticia en rust y estoy muy triste. Intento una función recursiva de cola y apilé el desbordamiento tan rápido. peor cuando compilo en versión el cambio de comportamiento. Él simplemente no llama a mi función. Un amigo me dijo que LLVM se optimiza a un valor indefinido (¿LLVM sabe que es una recursión de cola infinita?!?).
fn rec(i: i32) {
rec(i + 1)
}
fn main() {
println!("{}", rec(0));
}
Estoy de acuerdo con Boiethios, un lenguaje con características funcionales que no implementa tail call miss something.
Escribo en C y C ++, no garantizan la llamada final, pero de hecho lo manejan muy bien. No me impedirá aprender a oxidar, ahora sé que la oxidación no lo maneja. Codificaré sin que no sea un gran problema.
Pero creo que es una característica muy buena para un lenguaje moderno.
Darse cuenta de
fn rec(i: i32) {
println!("Hello");
rec(i + 1)
}
desbordamiento de pila también en modo de liberación de carga
Tenemos planes para implementar eventualmente el TCO garantizado, si es posible. Incluso reservamos una palabra clave para ello, "convertirse". Consulte el repositorio de RFC.
El 3 de agosto de 2016, 19:46 -0400, Antoine PLASKOWSKI [email protected] , escribió:
Soy noticia en rust y estoy muy triste. Intento una función recursiva de cola y apilé el desbordamiento tan rápido. peor cuando compilo en versión el cambio de comportamiento. Él simplemente no llama a mi función. Un amigo me dijo que el LLVM se optimiza a un valor indefinido (¿LLVM sabe que es una recursión de cola infinita?!?).
fn rec(i: i32) { rec(i + 1) } fn main() { println!("{}", rec(0)); }
Estoy de acuerdo con Boiethios, un lenguaje con características funcionales que no implementa tail call miss something.
Escribo en C y C ++, no garantizan la llamada de cola, pero de hecho lo manejan muy bien. No me impedirá aprender a oxidar, ahora que sé que no lo maneja codificaré sin él, así que no es un gran problema.
Pero creo que es una característica muy buena para un lenguaje moderno.
—
Estás recibiendo esto porque estás suscrito a este hilo.
Responda a este correo electrónico directamente, véalo en GitHub (https://github.com/rust-lang/rust/issues/217#issuecomment-237409642) o silencie el hilo (https://github.com/notifications/unsubscribe -auth/AABsipoedHrbnKDekmzCr-dl8M6g-Gojks5qcShKgaJpZM4AC-q_).
Solo una pregunta: es hipotéticamente posible realizar análisis de gráficos de llamadas y transformar llamadas de cola en bucles, al menos dentro de una sola caja, pero es computacionalmente costoso en tiempo de compilación y bastante complicado de codificar. ¿Hubo alguna discusión sobre esta posibilidad? Esa seguiría siendo una opción ahora, sin tener en cuenta la elección de la convención de llamadas.
El enfoque de lbstanza es requerir la anotación de funciones para que sean elegibles para TCO (defn+ en lugar de defn). En rust, eso mitigaría en gran medida el tiempo de compilación adicional de la sugerencia de timthelion, siempre y cuando no esté usando llamadas de cola literalmente en todas partes jajaja.
Comentario más útil
Tenemos planes para implementar eventualmente el TCO garantizado, si es posible. Incluso reservamos una palabra clave para ello, "convertirse". Consulte el repositorio de RFC.
El 3 de agosto de 2016, 19:46 -0400, Antoine PLASKOWSKI [email protected] , escribió: