Una Intermediate Representation (IR) es una representación de un programa entre su forma de código fuente y su forma ejecutable final. Su propósito principal es facilitar transformaciones y optimizaciones del código. A diferencia del código fuente, que es de alto nivel y específico de un lenguaje, y del código máquina, que es de bajo nivel y específico de una arquitectura, la IR se sitúa en un nivel intermedio de abstracción. Puede ser de diferentes tipos: basada en árboles (Abstract Syntax Tree - AST), basada en grafos (Control Flow Graph - CFG, Data Flow Graph - DFG) o lineal (Three-Address Code - TAC, Static Single Assignment - SSA). La elección de la IR influye en la complejidad de las optimizaciones y en la facilidad de generar código para diferentes arquitecturas.
Las IRs son fundamentales en el mundo real en compiladores modernos como LLVM (Low Level Virtual Machine), que utiliza una IR propia (LLVM IR) como su formato central para optimizaciones y generación de código para múltiples lenguajes (C++, Rust, Swift) y arquitecturas (x86, ARM, WebAssembly). GCC (GNU Compiler Collection) también emplea varias IRs internas, como GIMPLE y RTL (Register Transfer Language). Otros ejemplos incluyen GraalVM, que utiliza una IR para optimizaciones JIT (Just-In-Time) de lenguajes de la JVM, y herramientas de análisis estático de código que transforman el código fuente a una IR para detectar vulnerabilidades o errores. Incluso en bases de datos, los optimizadores de consultas pueden usar una forma de IR para representar el plan de ejecución antes de generar el código ejecutable.
Para un arquitecto, comprender las IRs es crucial por varias razones estratégicas. Permiten desacoplar el frontend (parsing del lenguaje) del backend (generación de código máquina), facilitando la creación de compiladores que soportan múltiples lenguajes y arquitecturas. Esto reduce la complejidad y el costo de mantenimiento. La elección de una IR impacta directamente la capacidad de realizar optimizaciones avanzadas, como la eliminación de código muerto o la vectorización, lo que afecta el rendimiento final del software. Además, las IRs son la base para herramientas de análisis estático, transpiladores y plataformas de ejecución políglotas, ofreciendo flexibilidad y extensibilidad. Un arquitecto debe considerar los trade-offs entre la expresividad de la IR (facilidad para representar construcciones de alto nivel) y su bajo nivel (cercanía al hardware para optimizaciones), así como el costo computacional de las transformaciones de IR.