Rustc ne sait pas encore comment faire des appels de queue ("be" plutôt que "ret"). Il ne devrait pas être trop difficile de lui apprendre comment.
Selon Graydon, nous devons réfléchir davantage aux conventions d'appel avant de les mettre en œuvre. LLVM nécessite la convention fastcc pour implémenter les appels de fin, mais cela ne fait pas tout à fait ce que nous voulons :
graydon: brson: à en juger par les commentaires dans llvm-land, nous pourrions avoir des problèmes. nous pourrons peut-être compenser ce que fait fastcc aujourd'hui, mais il est permis de changer d'avis demain.
graydon : Je pensais que fastcc == x86_fastcall, mais je me trompais.
graydon : ce sont des conventions d'appel différentes. fastcc est "tout ce que llvm ressent cette semaine"
graydon : nous devons passer à x86_fastcall puis, à plus long terme, écrire notre propre convention d'appel.
Ceci est actuellement à moitié mis en œuvre en raison de certaines complications dans la façon dont LLVM traite les appels de queue. Rustc analyse les expressions 'be' et les traduit en paires call+ret, ce qui est suffisant pour nous permettre de 'travailler' sur des cas simples et pas très profonds. Peut être suffisant pour démarrer.
Il n'y a apparemment qu'un seul CC (fastcc) qui prend en charge les appels de queue garantis, et pour s'y adapter, nous devons modifier nos hypothèses ABI à plusieurs endroits (il se transforme en callee-restore lorsque vous activez le drapeau -tailcallopt). Ainsi, même si nous annotons nos paires call + ret avec 'tail', comme requis, nous ne pouvons pas encore dire à LLVM de commencer à effectuer cette optimisation.
Il s'est avéré qu'il n'était pas nécessaire d'implémenter plus que ce qui est indiqué ici pour l'auto-hébergement. Passer à la prochaine étape.
Quelqu'un pense-t-il que nous allons vraiment continuer à faire ça ?
On dirait que ça n'arrivera pas.
Quelle est la situation avec LLVM et les appels de queue ? S'ils peuvent fonctionner de manière fiable sans certaines choses envahissantes comme déclarer que l'appelé est appelé par la queue, nous pourrions définir un ensemble limité de choses qui peuvent être transmises aux appels de la queue (les propres arguments de l'appelant, les scalaires), et erreur quand quelque chose le reste est passé. Cependant, de tels appels de queue pourraient ne pas être très utiles dans la pratique.
Est-il possible que regarder le backend GHC LLVM de Haskell soit utile?
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
Ils ne fonctionnent qu'avec un ABI d'appelé qui est sous-optimal dans les cas d'appel non final. Donc, dans un sens, oui, ils exigent que l'appelé soit déclaré appelé à la queue.
Nous pourrions implémenter cela, par exemple, en analysant une caisse et lorsque nous trouvons une fonction qui est appelée par la queue, soit en la compilant séparément sous l'ABI d'appel amical à la queue, soit en compilant des wrappers qui changent d'ABI à l'entrée, ou quelque chose comme ça. Ou alternativement, nous pouvons basculer _chaque_ fonction partout pour utiliser l'ABI conviviale pour les appels terminaux. Je ne sais pas si nous le faisons actuellement. Nous étions pendant un certain temps, mais nous avons peut-être arrêté. C'est l'ABI "fastcall" LLVM, que je ne pense pas que nous utilisons plus.
En tout cas, c'est un peu le bordel.
Nous avons maintenant l'optimisation des appels entre frères et sœurs. Envisageons-nous d'essayer d'en faire plus?
Cela n'arrivera pas, sauf dans la mesure abordée par #2216. La solution pour #2216 doit être suffisamment large pour prendre en charge le codage général de la machine d'état.
Cela continue de revenir dans les conversations et nous avons de nouveau réservé be
. Réouverture.
Je pense que le commentaire de Graydon sur la liste de diffusion :
https://mail.mozilla.org/pipermail/rust-dev/2013-avril/003557.html
met un clou dans ce cercueil. Reproduit ici :
Le 04/10/2013 à 05h43, Artella Coding a écrit :
Salut, la rouille fait-elle l'optimisation des appels de queue? La raison pour laquelle je demande est que
l'implémentation récursive de l'appel final suivant donne une pile
débordement. Merci.
Non, et ce ne sera probablement pas le cas. Nous avons un bogue de longue date à ce sujet :
https://github.com/mozilla/rust/issues/217
ainsi qu'une page wiki et plusieurs fils de liste de diffusion :
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-janvier/001280.html
...
Le résumé de tout cela est :
Je suis désolé de dire tout cela, et c'est avec le cœur lourd, mais nous
essayé et n'a pas trouvé le moyen de faire les compromis qui leur sont associés
résumer à un argument pour l'inclusion dans la rouille.
-Graydon
Il convient peut-être de noter que Haskell a généralement besoin d'une transformation d'argument statique pour l'inlining, la fusion, etc. http://stackoverflow.com/a/9660027/667457
Rust pourrait prendre en charge la transformation d'argument statique en disant que les fonctions définies à l'intérieur d'une autre fonction devraient être éligibles pour les optimisations d'appel final. Ou simplement avertir si les appels de queue entre les fonctions imbriquées dans une autre fonction ont échoué à l'optimisation des frères et sœurs. Pas sûr de la situation actuelle.
Il est triste que la récursivité de la queue ne soit pas implémentée. Alors j'ai une question : pourquoi créer une syntaxe de langage qui ressemble à une syntaxe de langage fonctionnel s'il manque une caractéristique essentielle de fonctionnel ?
Je suis de nouvelles dans la rouille et je suis très triste. J'essaie une fonction récursive de queue et j'empile le débordement si vite. pire quand je compile dans release le changement de comportement. Il n'appelle pas ma fonction. Un ami m'a dit que le LLVM s'optimisait à une valeur indéfinie (LLVM sait que c'est une récursivité de queue infinie ?!?).
fn rec(i: i32) {
rec(i + 1)
}
fn main() {
println!("{}", rec(0));
}
Je suis d'accord avec Boiethios, un langage avec des caractéristiques fonctionnelles qui n'implémente pas d'appel de queue manque quelque chose.
J'écris en C et C++, ils ne garantissent pas l'appel final, mais en fait ils le gèrent très bien. Cela ne m'empêchera pas d'apprendre la rouille, maintenant je sais que la rouille ne le supporte pas. Je vais coder sans donc ce n'est pas un gros problème.
Mais je pense que c'est une très bonne fonctionnalité pour une langue moderne.
remarquerez que
fn rec(i: i32) {
println!("Hello");
rec(i + 1)
}
débordement de pile aussi en mode de libération de la cargaison
Nous prévoyons de mettre en œuvre à terme le coût total de possession garanti, si possible. Nous lui avons même réservé un mot-clé, "devenir". Veuillez consulter le référentiel RFC.
Le 3 août 2016, 19:46 -0400, Antoine PLASKOWSKI [email protected] , a écrit :
Je suis de nouvelles dans la rouille et je suis très triste. J'essaie une fonction récursive de queue et j'empile le débordement si vite. pire quand je compile dans release le changement de comportement. Il n'appelle pas ma fonction. Un ami m'a dit que le LLVM s'optimisait pour indéfinir la valeur (LLVM sait que c'est une récursivité de queue infinie ?!?).
fn rec(i : i32) { rec(i + 1) } fn main() { println!("{}", rec(0)); }
Je suis d'accord avec Boiethios, un langage avec des caractéristiques fonctionnelles qui n'implémente pas d'appel de queue manque quelque chose.
J'écris en C et C++, ils ne garantissent pas l'appel final mais en fait ils le gèrent très bien. Cela ne m'empêchera pas d'apprendre la rouille, maintenant je sais que la rouille ne le gère pas, je vais coder sans donc ce n'est pas un gros problème.
Mais je pense que c'est une très bonne fonctionnalité pour une langue moderne.
—
Vous recevez ceci parce que vous êtes abonné à ce fil.
Répondez directement à cet e-mail, consultez-le sur GitHub (https://github.com/rust-lang/rust/issues/217#issuecomment-237409642) ou désactivez le fil de discussion (https://github.com/notifications/unsubscribe -auth/AABsipoedHrbnKDekmzCr-dl8M6g-Gojks5qcShKgaJpZM4AC-q_).
Juste une question : il est hypothétiquement possible d'effectuer une analyse des graphes d'appels et de transformer les appels de queue en boucles, au moins dans une seule caisse, mais cela coûte cher en calcul au moment de la compilation et est assez difficile à coder. Y a-t-il eu des discussions sur cette possibilité? Ce serait toujours une option maintenant, sans égard au choix de la convention d'appel.
L'approche de lbstanza consiste à exiger l'annotation des fonctions pour les rendre éligibles au coût total de possession (defn+ au lieu de defn). Dans Rust, cela atténuerait largement la surcharge de temps de compilation supplémentaire à la suggestion de timthelion, tant que vous n'utilisez pas les appels de queue littéralement partout lol.
Commentaire le plus utile
Nous prévoyons de mettre en œuvre à terme le coût total de possession garanti, si possible. Nous lui avons même réservé un mot-clé, "devenir". Veuillez consulter le référentiel RFC.
Le 3 août 2016, 19:46 -0400, Antoine PLASKOWSKI [email protected] , a écrit :