La creación de LLVM Flang aborda el problema fundamental de la obsolescencia y la falta de un camino de soporte a largo plazo, no propietario, para el vasto corpus de código Fortran existente en la computación científica y de alto rendimiento (HPC). Fortran, a pesar de su antigüedad, sigue siendo el lenguaje dominante en supercomputadoras, con más del 80% de las aplicaciones en sistemas como ARCHER2 escritas en él. Sin embargo, los compiladores existentes a menudo son propietarios o carecen de la flexibilidad y la infraestructura moderna que ofrece el ecosistema LLVM.

La tesis central es que un compilador Fortran moderno, de código abierto, basado en LLVM y MLIR, no solo preserva la utilidad de estos códigos críticos, sino que también fomenta la innovación en el lenguaje y su ecosistema. Al aprovechar la infraestructura modular de LLVM, Flang puede ofrecer un camino para la experimentación de nuevas características del lenguaje, mejorar la calidad del código a través de la detección de errores y proporcionar un soporte multiplataforma robusto, algo esencial para la diversidad de hardware en HPC. La decisión de adoptar MLIR desde las primeras etapas de su desarrollo subraya la necesidad de manejar representaciones intermedias de alto nivel que conserven la semántica específica de Fortran, algo que LLVM IR por sí solo no puede ofrecer eficientemente para optimizaciones avanzadas como las de arrays.

Arquitectura del Sistema

La arquitectura de LLVM Flang se centra en un diseño modular que aprovecha la infraestructura del proyecto LLVM, con especial énfasis en el uso de la Multi-Level Intermediate Representation (MLIR). El proceso de compilación comienza con el código fuente Fortran, que es procesado por el frontend F18, una reescritura del frontend original de Classic Flang. F18 genera una representación intermedia inicial que es una mezcla de dialectos de MLIR: HLFIR (High-Level Fortran Intermediate Representation), FIR (Fortran Intermediate Representation) y el dialecto MLIR built-in 'func'.

HLFIR opera en un nivel semántico muy cercano al Fortran original, permitiendo optimizaciones específicas del lenguaje, como las de arrays, que serían difíciles de realizar en niveles de IR más bajos. FIR actúa como un nivel intermedio entre HLFIR y LLVM IR, manejando detalles de representación de tipos y operaciones Fortran. Estos dialectos coexisten en el mismo archivo MLIR, lo que permite una transformación gradual y optimizaciones en diferentes niveles de abstracción. Posteriormente, la representación MLIR se convierte a LLVM IR, que luego pasa por las fases de optimización estándar de LLVM, generación de Machine IR (MIR), ensamblado y finalmente la creación del binario ejecutable.

Para el soporte de OpenMP, Flang utiliza un enfoque híbrido. Inicialmente, las directivas OpenMP se traducen a un dialecto MLIR específico de OpenMP ('omp'), que representa la semántica de paralelización de forma más natural que el LLVM IR genérico. Sin embargo, para la generación final de LLVM IR, Flang comparte la biblioteca 'LLVMFrontendOpenMP' y la clase 'OpenMPIRBuilder' con Clang, lo que permite reutilizar la lógica de traducción a llamadas a la runtime library de OpenMP (ej. '__kmpc_fork_call', '__kmpc_for_static_init_4') y asegura la compatibilidad. El driver del compilador de Flang ('flang') también aprovecha la biblioteca 'clangDriver' de Clang, lo que le permite heredar la robusta gestión de opciones de compilación, detección de targets y búsqueda de librerías, evitando la reinvención de la rueda y asegurando una experiencia de usuario consistente con otros compiladores LLVM.

Flujo de Compilación de Fortran con MLIR

  1. 1 Fortran Source Code Código fuente Fortran (ej. subroutine example(a, b))
  2. 2 HLFIR/FIR/func MLIR Frontend F18 genera MLIR con dialectos HLFIR, FIR y func. Optimización de alt...
  3. 3 FIR/func MLIR Conversión de HLFIR a FIR. Optimización de nivel medio.
  4. 4 LLVM IR Conversión de MLIR (FIR/func) a LLVM Intermediate Representation.
  5. 5 MIR LLVM IR pasa por el pipeline estándar de optimización y generación de Machine...
  6. 6 Assembly Generación de código ensamblador específico de la arquitectura.
  7. 7 Binary Program Enlazado y generación del programa ejecutable.
CapaTecnologíaJustificación
data-processing LLVM Infraestructura de compilación de bajo nivel, optimización de código y generación de código máquina. vs GCC
data-processing MLIR Framework para construir representaciones intermedias multinivel y dialectos específicos de dominio (FIR, HLFIR, omp) para optimizaciones de alto nivel. vs IRs propietarias de compiladores
data-processing FIR (Fortran Intermediate Representation) Dialecto MLIR para representar construcciones Fortran de forma amigable para optimizaciones. vs LLVM IR directamente
data-processing HLFIR (High-Level Fortran Intermediate Representation) Dialecto MLIR de nivel superior a FIR, enfocado en optimizaciones de arrays y semántica Fortran. vs FIR para todas las optimizaciones
data-processing OpenMP API estandarizada para paralelismo en Fortran, C y C++. Implementada con un dialecto MLIR 'omp' y compartiendo 'OpenMPIRBuilder' con Clang. vs OpenACC, MPI
data-processing clangDriver Biblioteca reutilizada de Clang para el driver del compilador de Flang, gestionando opciones, targets y búsqueda de librerías. vs Desarrollo de un driver propio desde cero

Trade-offs

Ganancias
  • Flexibilidad de optimización
  • Reutilización de infraestructura de compilador
  • Soporte multiplataforma y de toolchain
  • Calidad del código Fortran (detección de bugs)
  • Rendimiento del compilador (comparable a GFortran)
Costes
  • Tiempo de desarrollo inicial (reescritura completa)
  • Complejidad de la arquitectura (múltiples IRs/dialectos)

Fundamentos Teóricos

El problema de la representación intermedia en compiladores, y la necesidad de mantener información semántica de alto nivel para optimizaciones efectivas, ha sido un tema recurrente en la investigación de compiladores. El concepto de MLIR, aunque relativamente reciente, se basa en décadas de trabajo sobre representaciones intermedias multinivel y la modularidad en el diseño de compiladores. Un paper fundamental que articula la visión detrás de MLIR es "MLIR: A Compiler Infrastructure for the End of Moore’s Law" de Chris Lattner, Mehdi Amini et al. (2020).

Este trabajo postula que, a medida que la Ley de Moore se ralentiza, la optimización de software debe volverse más sofisticada y específica para el dominio, lo que requiere que los compiladores operen en múltiples niveles de abstracción. La incapacidad de LLVM IR para representar eficientemente construcciones de alto nivel de lenguajes como Fortran (ej. arrays multidimensionales con semántica específica) o dominios como el Machine Learning, llevó a la proliferación de IRs propietarias. MLIR proporciona un marco unificado para construir y componer estas IRs de dominio específico (dialects), permitiendo que los compiladores como Flang mantengan la información semántica crucial para optimizaciones agresivas, mientras se benefician de la infraestructura compartida de LLVM. La adopción temprana de MLIR por parte de Flang, incluso antes que Clang, valida la tesis de MLIR sobre la necesidad de flexibilidad en la representación intermedia para lenguajes con requisitos de optimización complejos.