Rust: Apprenez à rustc à faire des appels de queue

Créé le 27 janv. 2011  ·  18Commentaires  ·  Source: rust-lang/rust

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.

A-LLVM

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 :

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_).

Tous les 18 commentaires

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.

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 :

  • Nous savons tous que les appels de queue sont une caractéristique de langage vertueux.
    Il n'est pas nécessaire de développer davantage leurs vertus. Plusieurs parmi nous
    ont des antécédents en lisp et ML et les aimeraient bien. Leur
    l'absence est un chagrin d'amour et une tristesse qui ne sont pas arrivés à la légère.
  • Appels de queue "jeu mal" avec destruction déterministe. Y compris
    chute déterministe de ~ boîtes. Pour ne pas dire qu'ils ne le sont pas
    composable, mais les options pour les composer sont gênantes pour l'interface utilisateur,
    pénalisant les performances, compliquant la sémantique ou tout ce qui précède.
  • Les appels de queue "jouent mal" avec des hypothèses dans les outils C, y compris
    plate-forme ABI et liaison dynamique.
  • Les appels de queue nécessitent une convention d'appel qui est un succès en termes de performances
    par rapport à la convention C.
  • Nous trouvons que la plupart des cas de queue _recursion_ se convertissent raisonnablement bien en
    boucles, et la plupart des cas d'appels de queue non récursifs encodent l'état
    machines qui se convertissent raisonnablement bien en boucles enroulées autour
    énumérations. Ni l'un ni l'autre ne sont _assez_ aussi jolis que le
    des variantes utilisant le tail-call, mais elles fonctionnent et sont "aussi rapides"*,
    ainsi que idiomatique pour les programmeurs C et C++ (qui sont nos
    public primaire).

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

  • en termes de vitesse, une machine à états switch-in-a-loop est une répartition indirecte, donc
    fonctionnera probablement plus lentement qu'une machine d'état encodée par des appels de fin de
    état à état; par contre si le moyen d'obtenir cette performance
    "retour" est d'activer les appels de queue partout, nous en échangerions un isolé
    cas de performance sous-optimale pour une taxe de performance sous-optimale sur tous les programmes. Nous
    ne trouve pas ce commerce acceptable.

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.

Cette page vous a été utile?
0 / 5 - 0 notes