Pourquoi LLVM a-t-il un IR de type assemblage plutôt qu'un IR de type arborescence? Ou: pourquoi les projets ciblent-ils l'IR LLVM au lieu de l'AST de Clang?

14

Pourquoi la représentation intermédiaire de LLVM (LLVM IR) ressemble-t-elle à un assemblage plutôt qu'à un arbre?

Sinon, pourquoi les implémentations de langage ciblent-elles l'IR LLVM plutôt que l'AST de Clang?

Je n'essaie pas de poser deux questions différentes à la fois si cela semble ainsi. Pour moi, il semble simplement que les programmeurs client et bibliothèque se sont mis d'accord sur le fait que l'API de LLVM, rien de plus et rien de moins, est évidemment une bonne conception logicielle et ma question est "pourquoi?".

La raison pour laquelle je demande, c'est qu'il semble que LLVM pourrait fournir plus de fonctionnalités aux frontaux si son IR était de type AST, car les outils basés sur AST de clang pourraient être utilisés pour n'importe quel frontend. Alternativement, les langages qui ciblent LLVM IR pourraient obtenir plus de fonctionnalités s'ils ciblaient l'AST de clang.

Clang a des classes et des fonctions pour créer et travailler avec des AST et c'est le seul projet frontal fortement lié au projet LLVM, alors pourquoi la fonctionnalité AST de clang est-elle externe à LLVM?

Du haut de ma tête, je sais que Rust (rustc), D (ldc) et Haskell (GHC) peuvent tous utiliser LLVM comme backend mais ils n'utilisent pas le Clang AST (pour autant que je sache, je pourrais se tromper). Je ne connais pas tous les détails internes de ces compilateurs mais au moins Rust et D semblent certainement pouvoir être compilés selon AST de clang. Peut-être que Haskell le pourrait aussi, mais j'en suis beaucoup moins sûr.

Est-ce pour des raisons historiques (LLVM étant à l'origine une "machine virtuelle de bas niveau" et des cliquetis arriveront plus tard)? Est-ce parce que d'autres frontaux veulent avoir autant de contrôle que possible sur ce qu'ils fournissent à LLVM? Y a-t-il des raisons fondamentales pour lesquelles l'AST de clang est inapproprié pour les langages "non-C-like"?

Je n'ai pas l'intention que cette question soit un exercice de lecture d'esprit. Je veux juste que cela soit utile à ceux d'entre nous qui sont curieux de la conception du compilateur, mais qui ne le maîtrisent pas déjà. Étant donné que les projets LLVM et clang sont développés en public, j'espère que quelqu'un familier avec le développement de ces projets pourra répondre ou que la réponse est suffisamment évidente pour certains nerds de compilation qu'ils se sentent suffisamment confiants pour répondre.


Pour anticiper certaines réponses évidentes mais insatisfaisantes:

Oui, avoir un IR de type assemblage donne plus de contrôle à quiconque crée l'IR (peut-être que X lang a un meilleur code et format AST que clang) mais si c'est la seule réponse, alors la question devient "pourquoi LLVM n'a -t-il qu'un assemblage- comme l'IR au lieu d'un IR de type arbre de haut niveau et d'un IR de type assemblage de bas niveau? ".

Oui, ce n'est pas si difficile d'analyser un langage de programmation dans un AST (au moins par rapport aux autres étapes de compilation). Néanmoins, pourquoi utiliser des AST séparés? Si rien d'autre, utiliser le même AST vous permet d'utiliser des outils qui fonctionnent sur les AST (même des choses simples comme les imprimantes AST).

Oui, je suis tout à fait d' accord pour dire que le fait d'être plus modulaire est une bonne chose, mais si c'est la seule raison, alors pourquoi les autres implémentations de langage ont-elles tendance à cibler LLVM IR au lieu de l'AST de Clang?

Ces préemptions peuvent être erronées ou négliger des détails, alors n'hésitez pas à donner ces réponses si vous avez plus de détails ou si mes hypothèses sont erronées.


Pour tous ceux qui souhaitent répondre à une question plus définitive: quels sont les avantages et les inconvénients d'un IR de type assemblage par rapport à un IR de type arbre?

Praxéolitique
la source
1
Je ne suis pas un expert LLVM, mais je pense qu'il y a un petit malentendu de votre côté. LLVM n'a pas d'asm comme IR. En fait, son IR ressemble plus à un graphique qu'à un arbre. Je suppose que par "asm-like" vous faites référence à l'IR lisible par l'homme (fichiers * .ll), si c'est le cas, cela se fait juste pour plus de commodité. Mais attendons un vrai expert qui puisse donner une réponse plus complète :)
AlexDenisov
1
Un aspect important peut être l'histoire: LLVM a été initialement conçu pour dissocier les backends du compilateur des frontends du compilateur. L'idée était que les fournisseurs de compilateurs se concurrenceraient sur les optimisations de langage et les fournisseurs de CPU seraient en concurrence sur les optimisations de bas niveau. Par exemple, Microsoft et Apple se feraient concurrence, dont le compilateur C produit le "meilleur" bitcode à partir de C, et Intel et AMD se feraient concurrence, dont le backend LLVM produit le "meilleur" code machine à partir de bitcode. Les vendeurs d'applications expédieraient leurs applications en bitcode, et la compilation finale se ferait sur l'utilisateur…
Jörg W Mittag
1
… Machine. LLVM a commencé à un moment où il n'était pas du tout clair que tout le monde utiliserait Intel. Apple était toujours sur PowerPC, Intel poussait toujours Itanium, etc. AFAIK, Apple utilise toujours LLVM de cette manière, dans certains de ses frameworks 3D, où le code est livré sous forme de bitcode puis compilé pour nVidia ou ATI selon le type de carte installé.
Jörg W Mittag
1
Pardonnez-moi, mais qu'est-ce qu'un IR?
Adam Copley
1
@AdamCopley représentation intermédiaire
Praxeolitic

Réponses:

13

Il y a un certain nombre de questions interdépendantes ici, je vais essayer de les séparer du mieux que je peux.

Pourquoi les autres langages s'appuient-ils sur LLVM IR et non sur AST?

C'est simplement parce que clang est un frontal C / C ++ et que l'AST qu'il produit est étroitement couplé au C / C ++. Un autre langage pourrait l'utiliser, mais il aurait besoin d'une sémantique presque identique à un sous-ensemble de C / C ++, ce qui est très limitant. Comme vous le faites remarquer, l'analyse d'un AST est assez simple, donc restreindre vos choix sémantiques ne vaut probablement pas la petite économie.

Cependant, si vous écrivez des outils pour C / C ++, par exemple des analyseurs statiques, alors la réutilisation de l'AST a beaucoup de sens car il est beaucoup plus facile de travailler avec l'AST que le texte brut si vous travaillez avec C / C ++ .

Pourquoi LLVM IR est-il la forme qu'il est?

LLVM IR a été choisi comme forme appropriée pour écrire les optimisations du compilateur. En tant que tel, sa principale caractéristique est qu'il est sous forme SSA . C'est un IR assez bas, donc il est applicable à un large éventail de langues, par exemple, il ne tape pas de mémoire car cela varie beaucoup d'une langue à l'autre.

Maintenant, il se trouve que l'écriture des optimisations du compilateur est une tâche assez spécialisée et souvent orthogonale à la conception des fonctionnalités du langage. Cependant, avoir un langage compilé exécuté rapidement est une exigence assez générale. De plus, la conversion de LLVM IR en ASM est assez mécanique et n'est généralement pas intéressante non plus pour les concepteurs de langage.

Par conséquent, réduire une langue en LLVM IR donne au concepteur de langue beaucoup de "trucs gratuits" qui sont très utiles dans la pratique en les laissant se concentrer sur la langue elle-même.

Un IR différent serait-il utile (OK, pas demandé mais en quelque sorte implicite)?

Absolument! Les AST sont assez bons pour certaines transformations de la structure du programme mais sont très difficiles à utiliser si vous souhaitez transformer le flux du programme. Un formulaire SSA est généralement mieux. Cependant, LLVM IR est de très bas niveau, donc une grande partie de la structure de haut niveau est perdue (volontairement, elle est donc plus généralement applicable). Avoir un IR entre l'AST et l'IR de bas niveau peut être bénéfique ici. Rust et Swift adoptent cette approche et ont un IR de haut niveau entre les deux.

Alex
la source
Haskell a également un certain nombre d'IR avant d'arriver à LLVM.
DylanSp
1
@ DylanSp En effet. Cela commence à devenir de facto la meilleure pratique pour les langues complexes. Par exemple, Rust n'a pas fait cela au départ et a refactorisé pour inclure un IR de haut niveau. Je crois également qu'il a été question de faire cela pour clang, mais je ne sais pas où cela est allé.
Alex