¿Por qué la representación intermedia de LLVM es como un ensamblaje en lugar de como un árbol?
Alternativamente, ¿por qué las implementaciones de lenguaje se enfocan en LLVM IR en lugar de AST de Clang?
No estoy tratando de hacer dos preguntas diferentes a la vez si parece que es así. Para mí, simplemente parece que los programadores tanto de clientes como de bibliotecas llegaron al consenso de que la API de LLVM, nada más y nada menos, es obviamente un buen diseño de software y mi pregunta es "¿por qué?".
La razón por la que pregunto es que parece que LLVM podría proporcionar más funcionalidad a las interfaces si su IR era similar a AST porque las herramientas basadas en AST de Clang podrían usarse para cualquier interfaz. Alternativamente, los idiomas que apuntan a LLVM IR podrían obtener más funcionalidad si se enfocaran en AST de Clang.
Clang tiene clases y funciones para crear y trabajar con AST y es el proyecto frontend only que está fuertemente vinculado al proyecto LLVM. ¿Por qué la funcionalidad AST de Clang es externa a LLVM?
Desde lo alto de mi cabeza, sé que Rust (rustc), D (ldc) y Haskell (GHC) pueden usar LLVM como backend pero no usan Clang AST (que yo sepa) , Podría estar equivocado). No conozco todos los detalles internos de estos compiladores, pero al menos Rust y D ciertamente parecen estar compilados para AST de Clang. Tal vez Haskell también podría, pero estoy mucho menos seguro de eso.
¿Esto se debe a razones históricas (LLVM originalmente era una "máquina virtual de bajo nivel" y el clang viene más adelante)? ¿Esto se debe a que otras interfaces quieren tener el mayor control posible sobre lo que alimentan a LLVM? ¿Hay razones fundamentales por las que el AST de Clang no sea apropiado para lenguajes "no similares a C"?
No pretendo que esta pregunta sea un ejercicio de lectura mental. Solo quiero que sea útil para aquellos de nosotros que tenemos curiosidad acerca del diseño del compilador, pero que aún no lo dominamos. Dado que los proyectos LLVM y clang se desarrollan en público, espero que alguien familiarizado con el desarrollo de estos proyectos pueda responder o que la respuesta sea lo suficientemente obvia para algunos nerds de compilación que se sientan lo suficientemente seguros para responder.
Para anticiparse a algunas respuestas obvias pero insatisfactorias:
Sí, tener un IR similar a un ensamblaje le da más control a quienquiera que diseñe el IR (quizás X lang tenga un mejor código de base y formato AST que el clang) pero si esa es la única respuesta, entonces la pregunta es "¿por qué LLVM > solo tiene un IR de ensamblador en lugar de un IR de alto nivel como un árbol y un IR de ensamblaje de bajo nivel? ".
Sí, no es tan difícil analizar un lenguaje de programación en un AST (al menos en comparación con los otros pasos de compilación). Aun así, ¿por qué usar ASTs separados? Si no hace nada más, usar el mismo AST le permite usar herramientas que operan en AST (incluso cosas simples como las impresoras AST).
Sí, estoy muy de acuerdo en que ser más modular es algo bueno, pero si esa es la única razón, ¿por qué las implementaciones de otros lenguajes tienden a apuntar con LLVM IR en lugar de AST de Clang?
Estas preferencias pueden ser erróneas o pasar por alto detalles, así que siéntase libre de dar estas respuestas si tiene más detalles o mis suposiciones están equivocadas.
Para cualquier persona que quiera responder una pregunta con una respuesta más definitiva: ¿cuáles son las ventajas y desventajas de una IR de tipo ensamblaje frente a una IR de tipo árbol?