{"schemaVersion":1,"id":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects","title":"LLVM MLIR: Construyendo Dialectos de Compilador Custom para Optimización de Dominio","description":"Análisis de la arquitectura de representación intermedia multi-nivel de MLIR, construcción de dialectos personalizados y la convergencia de compiladores de ML, aceleradores de hardware y DSLs en el framework MLIR.","language":"es","datePublished":"2026-01-27","dateModified":null,"contentFormat":"text/markdown","content":"Compilers\n\n# LLVM MLIR: Construyendo Dialectos de Compilador Custom para Optimización de Dominio\n\n2026-01-2710 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/llvm-mlir-compiler-infrastructure-custom-dialects>)\n\n## El Problema: Por Qué LLVM IR No Alcanzaba\n\nLLVM es brillante para lo que hace: tomar IR moderadamente de bajo nivel y convertirlo en código máquina optimizado para una docena de arquitecturas. Pero tiene una limitación fundamental, hay un solo nivel de IR, y está aproximadamente al nivel de abstracción de C.\n\nSi se construye un compilador para un lenguaje de alto nivel (por ejemplo, un DSL de procesamiento de tensores), es necesario bajar los conceptos de alto nivel a LLVM IR tempranamente. Una vez realizada esa transformación, la información se pierde. El optimizador de LLVM ve loops y aritmética de punteros, no multiplicaciones de matrices y convoluciones. No puede fusionar dos operaciones de matrices que no sabe que son operaciones de matrices.\n\nEste es el \"gap de abstracción\" que plagó a los compiladores de ML durante años:\n\n```\nDSL de alto nivel: matmul(A, B) + transpose(C)\n │\n ┌───────────────┤ (pérdida de información aquí)\n ▼ │\nLLVM IR: loops anidados, instrucciones gep, loads/stores\n → LLVM puede optimizar los loops pero no ve el álgebra lineal\n```\n\nCada framework de ML lo resolvió distinto: TensorFlow tenía XLA, PyTorch tenía TorchScript y después Torch-MLIR, TVM tenía su propio IR, Halide tenía su propio IR. Cada uno reinventó sistemas de tipos, construcción de SSA, infraestructura de passes y canonicalización. Duplicación masiva.\n\n## La Idea Central de MLIR: Dialectos Hasta el Fondo\n\nLa idea clave de MLIR es que no se necesita un IR, se necesita un framework para construir muchos IRs que puedan coexistir e interoperar. Ese framework es el sistema de **dialectos**.\n\nUn dialecto es un namespace que contiene:\n\n- **Operaciones** (las \"instrucciones\" de tu IR)\n- **Tipos** (el sistema de tipos para tu dominio)\n- **Atributos** (constantes de compilación y metadata)\n- **Interfaces** (traits que las operaciones pueden implementar para transformaciones genéricas)\n\nLa magia es que operaciones de distintos dialectos pueden existir en el mismo IR, y es posible bajar progresivamente de dialectos de alto nivel a los de bajo nivel:\n\n```mlir\n// Alto nivel: dialecto linalg (operaciones de álgebra lineal)\n%result = linalg.matmul ins(%A, %B : tensor<64x128xf32>, tensor<128x256xf32>)\n outs(%C : tensor<64x256xf32>) -> tensor<64x256xf32>\n\n// Nivel medio: dialecto affine (nidos de loops poliédricos)\naffine.for %i = 0 to 64 {\n affine.for %j = 0 to 256 {\n affine.for %k = 0 to 128 {\n %a = affine.load %A[%i, %k] : memref<64x128xf32>\n %b = affine.load %B[%k, %j] : memref<128x256xf32>\n %c = affine.load %C[%i, %j] : memref<64x256xf32>\n %prod = arith.mulf %a, %b : f32\n %sum = arith.addf %c, %prod : f32\n affine.store %sum, %C[%i, %j] : memref<64x256xf32>\n }\n }\n}\n\n// Bajo nivel: dialecto llvm (operaciones de LLVM IR)\n%ptr = llvm.getelementptr %base[%idx] : (!llvm.ptr, i64) -> !llvm.ptr\n%val = llvm.load %ptr : !llvm.ptr -> f32\n```\n\nEn cada nivel, es posible aplicar optimizaciones específicas del dominio que serían imposibles en niveles más bajos. El nivel ` linalg ` sabe de estrategias de tiling y fusión para operaciones de matrices. El nivel ` affine ` puede aplicar transformaciones poliédricas. El nivel ` llvm ` hace register allocation y selección de instrucciones.\n\n## Construyendo un Dialecto Custom: Un Ejemplo de Juguete\n\nEl siguiente ejemplo construye un dialecto simple para un DSL hipotético de procesamiento de imágenes. Se definen operaciones para cargar imágenes, aplicar filtros y compositar.\n\n### Paso 1: Definir el Dialecto en TableGen\n\n```tablegen\n// ImageOps.td\ninclude \"mlir/IR/OpBase.td\"\ninclude \"mlir/IR/AttrTypeBase.td\"\ninclude \"mlir/Interfaces/SideEffectInterfaces.td\"\n\n// Definir el dialecto\ndef ImageDialect : Dialect {\n let name = \"image\";\n let cppNamespace = \"::image\";\n let summary = \"Un dialecto para operaciones de procesamiento de imágenes\";\n}\n\n// Definir un tipo custom para imágenes con info de canales\ndef Image_ImageType : TypeDef<ImageDialect, \"Image\"> {\n let mnemonic = \"img\";\n let parameters = (ins\n \"int64_t\":$width,\n \"int64_t\":$height,\n \"int64_t\":$channels // 1=gris, 3=RGB, 4=RGBA\n );\n let assemblyFormat = \"`<` $width `,` $height `,` $channels `>`\";\n}\n\n// Operación de carga\ndef Image_LoadOp : Op<ImageDialect, \"load\", [Pure]> {\n let summary = \"Cargar una imagen desde un path\";\n let arguments = (ins StrAttr:$path);\n let results = (outs Image_ImageType:$result);\n let assemblyFormat = \"$path attr-dict `:` type($result)\";\n}\n\n// Operación de blur\ndef Image_BlurOp : Op<ImageDialect, \"blur\", [Pure]> {\n let summary = \"Aplicar desenfoque gaussiano\";\n let arguments = (ins\n Image_ImageType:$input,\n F32Attr:$sigma\n );\n let results = (outs Image_ImageType:$result);\n let assemblyFormat = \"$input `,` $sigma attr-dict `:` type($input) `->` type($result)\";\n\n // Verificar que input y output tengan las mismas dimensiones\n let verifier = [{\n auto inType = getInput().getType().cast<ImageType>();\n auto outType = getResult().getType().cast<ImageType>();\n if (inType.getWidth() != outType.getWidth() ||\n inType.getHeight() != outType.getHeight())\n return emitOpError(\"las dimensiones de input y output deben coincidir\");\n return success();\n }];\n}\n\n// Operación de composición\ndef Image_CompositeOp : Op<ImageDialect, \"composite\", [Pure]> {\n let summary = \"Componer dos imágenes con modo de mezcla\";\n let arguments = (ins\n Image_ImageType:$foreground,\n Image_ImageType:$background,\n StrAttr:$blend_mode // \"over\", \"multiply\", \"screen\"\n );\n let results = (outs Image_ImageType:$result);\n}\n```\n\n### Paso 2: Escribir un Pass de Optimización Específico del Dominio\n\nAhora se puede escribir un pass que fusiona operaciones de blur consecutivas en un solo blur con sigma combinado:\n\n```cpp\n// FuseBlursPass.cpp\n#include \"mlir/Pass/Pass.h\"\n#include \"ImageOps.h\"\n#include <cmath>\n\nnamespace {\nstruct FuseBlursPass\n : public mlir::PassWrapper<FuseBlursPass,\n mlir::OperationPass<mlir::func::FuncOp>> {\n\n void runOnOperation() override {\n getOperation().walk([](image::BlurOp outerBlur) {\n // Chequear si el input de este blur es otro blur\n auto innerBlur = outerBlur.getInput().getDefiningOp<image::BlurOp>();\n if (!innerBlur)\n return;\n\n // Chequear que el blur interno no tenga otros usuarios\n if (!innerBlur.getResult().hasOneUse())\n return;\n\n // Fusionar: sigma_combinado = sqrt(sigma1^2 + sigma2^2)\n float sigma1 = innerBlur.getSigma().convertToFloat();\n float sigma2 = outerBlur.getSigma().convertToFloat();\n float fusedSigma = std::sqrt(sigma1 * sigma1 + sigma2 * sigma2);\n\n // Reemplazar el blur exterior con un solo blur sobre el input del interior\n mlir::OpBuilder builder(outerBlur);\n auto fusedBlur = builder.create<image::BlurOp>(\n outerBlur.getLoc(),\n outerBlur.getType(),\n innerBlur.getInput(),\n builder.getF32FloatAttr(fusedSigma));\n\n outerBlur.replaceAllUsesWith(fusedBlur.getResult());\n outerBlur.erase();\n if (innerBlur.getResult().use_empty())\n innerBlur.erase();\n });\n }\n\n mlir::StringRef getArgument() const final { return \"image-fuse-blurs\"; }\n mlir::StringRef getDescription() const final {\n return \"Fusionar operaciones de blur consecutivas\";\n }\n};\n} // namespace\n```\n\n## El IR En Acción\n\nAsí se ve un pipeline completo en nuestro dialecto de imágenes:\n\n```mlir\n// IR de entrada (operaciones de imagen de alto nivel)\nfunc.func @process_photo(%path: !image.img<1920, 1080, 3>) -> !image.img<1920, 1080, 3> {\n %photo = image.load \"/photos/input.jpg\" : !image.img<1920, 1080, 3>\n %blurred1 = image.blur %photo, 2.0 : !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n %blurred2 = image.blur %blurred1, 3.0 : !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n %overlay = image.load \"/photos/overlay.png\" : !image.img<1920, 1080, 4>\n %result = image.composite %overlay, %blurred2, \"over\" :\n !image.img<1920, 1080, 4>, !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n return %result : !image.img<1920, 1080, 3>\n}\n\n// Después del pass de fusión de blur (sigma = sqrt(4 + 9) = 3.606):\nfunc.func @process_photo(%path: !image.img<1920, 1080, 3>) -> !image.img<1920, 1080, 3> {\n %photo = image.load \"/photos/input.jpg\" : !image.img<1920, 1080, 3>\n %blurred = image.blur %photo, 3.606 : !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n %overlay = image.load \"/photos/overlay.png\" : !image.img<1920, 1080, 4>\n %result = image.composite %overlay, %blurred, \"over\" :\n !image.img<1920, 1080, 4>, !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n return %result : !image.img<1920, 1080, 3>\n}\n```\n\nEl pass de fusión convirtió dos operaciones de blur en una, cortando el trabajo de convolución aproximadamente a la mitad. Esta optimización es trivial de expresar a nivel del dialecto de imagen, pero sería casi imposible de descubrir después de bajar a loops.\n\n## MLIR en el Mundo Real: El Panorama de Compiladores de ML\n\nLos mayores usuarios de MLIR son los compiladores de ML, y con razón. Los workloads de ML tienen una estructura multi-nivel natural:\n\n```\nNivel framework: torch.nn.Linear(256, 128)\n │\n ▼ TorchMLIR\nNivel grafo: linalg.matmul + linalg.add (bias)\n │\n ▼ Tiling + Fusión\nNivel tile: loops scf.for con cuerpos internos vectorizados\n │\n ▼ Lowering a hardware\nNivel hardware: gpu.launch_func / vector.contract / amx.tile_mulf\n │\n ▼ Lowering a LLVM\nCódigo máquina: instrucciones AVX-512 / CUDA PTX / AMX\n```\n\nCada nivel tiene sus propias oportunidades de optimización:\n\n- **Nivel grafo**: fusión de operadores (matmul + bias + relu = un kernel), optimización de layout (NHWC vs NCHW)\n- **Nivel tile**: selección de tamaño de tile, scheduling consciente de caché, estrategia de vectorización\n- **Nivel hardware**: mapeo a extensiones ISA específicas (AMX para Intel, Tensor Cores para NVIDIA)\n\n### IREE: El Runtime de ML de Google Construido sobre MLIR\n\nIREE (Intermediate Representation Execution Environment) es probablemente el compilador de ML basado en MLIR más completo en producción. Toma modelos de TensorFlow, PyTorch o JAX, los baja a través de dialectos MLIR, y genera código optimizado para CPUs, GPUs y aceleradores.\n\n### Mojo: Un Lenguaje Construido sobre MLIR\n\nEl lenguaje de programación Mojo de Modular está construido directamente sobre MLIR. Esto significa que el compilador de Mojo puede expresar abstracciones de alto nivel (sintaxis tipo Python) y operaciones de hardware de bajo nivel (intrínsecos SIMD) en el mismo IR, y el pipeline de optimización puede ver ambos simultáneamente.\n\n```mojo\n# Código Mojo que compila a través de MLIR\nfn matmul_tiled[M: Int, N: Int, K: Int](\n A: SIMD[DType.float32, M*K],\n B: SIMD[DType.float32, K*N],\n) -> SIMD[DType.float32, M*N]:\n var C = SIMD[DType.float32, M*N](0)\n for i in range(M):\n for j in range(N):\n for k in range(K):\n C[i*N + j] += A[i*K + k] * B[k*N + j]\n return C\n```\n\n## Empezando: El Camino Práctico\n\nPara experimentar con MLIR, aquí va un camino recomendado:\n\n### 1. Compilar MLIR Desde Source\n\n```bash\ngit clone https://github.com/llvm/llvm-project.git\ncd llvm-project\nmkdir build && cd build\n\ncmake -G Ninja ../llvm \\\n -DLLVM_ENABLE_PROJECTS=mlir \\\n -DLLVM_BUILD_EXAMPLES=ON \\\n -DLLVM_TARGETS_TO_BUILD=\"host\" \\\n -DCMAKE_BUILD_TYPE=Release \\\n -DLLVM_ENABLE_ASSERTIONS=ON\n\nninja -j$(nproc)\n```\n\n### 2. Jugar con mlir-opt\n\n```bash\n# Escribir un programa MLIR simple\ncat > test.mlir << 'EOF'\nfunc.func @add(%arg0: f32, %arg1: f32) -> f32 {\n %0 = arith.addf %arg0, %arg1 : f32\n return %0 : f32\n}\nEOF\n\n# Correr canonicalización\n./bin/mlir-opt --canonicalize test.mlir\n\n# Bajar al dialecto LLVM\n./bin/mlir-opt --convert-func-to-llvm --convert-arith-to-llvm test.mlir\n\n# Ver todos los passes disponibles\n./bin/mlir-opt --help | grep \"Passes:\"\n```\n\n### 3. Estudiar el Tutorial Toy\n\nEl repo de MLIR incluye un tutorial completo que construye un compilador para un lenguaje de juguete desde cero. Está en ` mlir/docs/Tutorials/Toy/ ` y cubre todo desde lexing hasta codegen LLVM a través de MLIR.\n\n## Por Qué Esto Importa Más Allá de los Compiladores\n\nEl sistema de dialectos de MLIR es genuinamente útil fuera del trabajo tradicional de compiladores:\n\n- **Diseño de hardware**: CIRCT usa dialectos MLIR para representar lenguajes de descripción de hardware, reemplazando toolchains de Verilog/VHDL.\n- **Computación cuántica**: El dialecto ` quake ` representa circuitos cuánticos para optimización antes de mapear al hardware cuántico.\n- **Motores de base de datos**: Los planificadores de queries pueden usar dialectos custom para representar álgebra relacional y optimizar planes de ejecución.\n- **Simulación numérica**: El dialecto ` sparse_tensor ` maneja operaciones de matrices sparse con selección automática de formato.\n\nEl patrón es siempre el mismo: teners un dominio con operaciones específicas y reglas de optimización que son invisibles a un nivel de abstracción más bajo. MLIR te da la infraestructura para expresar ese dominio sin construir todo desde cero.\n\nMLIR no es solo un LLVM IR mejor. Es un framework para construir compiladores a cualquier nivel de abstracción, con infraestructura que tardó décadas en desarrollarse en LLVM, disponible out of the box. Si se está construyendo algo que transforma representaciones estructuradas, ya sean modelos de ML, descripciones de hardware, o queries de bases de datos, MLIR vale tu tiempo.\n\n## Preguntas frecuentes\n\n### ¿Qué es MLIR?\n\nMLIR (Multi-Level Intermediate Representation) es una infraestructura de compiladores dentro del proyecto LLVM que provee un framework flexible y extensible para construir compiladores de dominio específico usando 'dialectos' componibles, colecciones de tipos, operaciones y reglas de transformación.\n\n### ¿En qué se diferencia MLIR del LLVM IR?\n\nLLVM IR es una representación de un solo nivel fijo, diseñada para generación de código de CPU de propósito general. MLIR soporta múltiples niveles de abstracción simultáneamente, permitiendo representar conceptos de alto nivel del dominio (operaciones tensoriales, intrínsecos de hardware) junto con código de bajo nivel.\n\n### ¿Qué son los dialectos de MLIR?\n\nLos dialectos son colecciones modulares de operaciones, tipos y atributos en MLIR. Cada dialecto define su propio vocabulario, por ejemplo, el dialecto 'linalg' tiene operaciones para álgebra lineal, mientras que el dialecto 'gpu' tiene operaciones para kernels de GPU. Puede mezclar dialectos libremente en el mismo IR.\n\n### ¿Quién usa MLIR en producción?\n\nGoogle (TensorFlow/XLA, IREE), AMD (stack de compilador ROCm), Intel (oneAPI), Modular (lenguaje Mojo), y varias startups de hardware ML usan MLIR como backbone de sus compiladores.\n\n## Tips\n\n1. **Tip:** Cuando se define ops custom en MLIR, utilizar siempre TableGen (archivos ` .td `) en vez de escribir clases C++ de ops a mano. TableGen auto-genera verificadores, builders, parsers y printers. Escribir ops a mano es una pesadilla de debugging.\n2. **Tip:** El flag ` -mlir-print-ir-after-all ` de MLIR vuelca el IR después de cada pass. Pasarlo por ` diff ` para ver exactamente qué hace cada transformación. Esta es la técnica de depuración más útil para desarrollo de passes.\n3. **Tip:** Iniciar con los dialectos ` func ` y ` arith ` al aprender MLIR. Son lo suficientemente simples para comprender en una tarde pero demuestran todos los conceptos centrales, regions, blocks, valores SSA y sistemas de tipos.\n4. **Tip:** Utilizar ` mlir-opt --canonicalize ` como primer pass de optimización. Los patrones de canonicalización (constant folding, dead code elimination, identity removal) se registran por operación y se ejecutan hasta fixpoint. Captura el 80% de las redundancias obvias.\n\n- llvm\n- mlir\n- compiladores\n- dialectos\n- optimización\n- machine-learning\n- dsl\n- representación-intermedia\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)","headings":[{"level":1,"text":"LLVM MLIR: Construyendo Dialectos de Compilador Custom para Optimización de Dominio","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#title"},{"level":2,"text":"El Problema: Por Qué LLVM IR No Alcanzaba","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#el-problema-por-qu-llvm-ir-no-alcanzaba"},{"level":2,"text":"La Idea Central de MLIR: Dialectos Hasta el Fondo","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#la-idea-central-de-mlir-dialectos-hasta-el-fondo"},{"level":2,"text":"Construyendo un Dialecto Custom: Un Ejemplo de Juguete","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#construyendo-un-dialecto-custom-un-ejemplo-de-juguete"},{"level":3,"text":"Paso 1: Definir el Dialecto en TableGen","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#paso-1-definir-el-dialecto-en-tablegen"},{"level":3,"text":"Paso 2: Escribir un Pass de Optimización Específico del Dominio","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#paso-2-escribir-un-pass-de-optimizacin-especfico-del-dominio"},{"level":2,"text":"El IR En Acción","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#el-ir-en-accin"},{"level":2,"text":"MLIR en el Mundo Real: El Panorama de Compiladores de ML","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#mlir-en-el-mundo-real-el-panorama-de-compiladores-de-ml"},{"level":3,"text":"IREE: El Runtime de ML de Google Construido sobre MLIR","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#iree-el-runtime-de-ml-de-google-construido-sobre-mlir"},{"level":3,"text":"Mojo: Un Lenguaje Construido sobre MLIR","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#mojo-un-lenguaje-construido-sobre-mlir"},{"level":2,"text":"Empezando: El Camino Práctico","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#empezando-el-camino-prctico"},{"level":3,"text":"1. Compilar MLIR Desde Source","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#1-compilar-mlir-desde-source"},{"level":3,"text":"2. Jugar con mlir-opt","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#2-jugar-con-mlir-opt"},{"level":3,"text":"3. Estudiar el Tutorial Toy","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#3-estudiar-el-tutorial-toy"},{"level":2,"text":"Por Qué Esto Importa Más Allá de los Compiladores","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#por-qu-esto-importa-ms-all-de-los-compiladores"},{"level":2,"text":"Preguntas frecuentes","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#questions"},{"level":3,"text":"¿Qué es MLIR?","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-1"},{"level":3,"text":"¿En qué se diferencia MLIR del LLVM IR?","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-2"},{"level":3,"text":"¿Qué son los dialectos de MLIR?","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-3"},{"level":3,"text":"¿Quién usa MLIR en producción?","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-4"},{"level":2,"text":"Tips","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#article-tips"}],"sections":[{"heading":"LLVM MLIR: Construyendo Dialectos de Compilador Custom para Optimización de Dominio","level":1,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects","content":"Compilers"},{"heading":"LLVM MLIR: Construyendo Dialectos de Compilador Custom para Optimización de Dominio","level":1,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#title","content":"2026-01-2710 min lectura\n\nLucio Durán\nEngineering Manager & AI Solutions Architect\n\nTambién disponible en: [English](<https://lucioduran.com/blog/llvm-mlir-compiler-infrastructure-custom-dialects>)"},{"heading":"El Problema: Por Qué LLVM IR No Alcanzaba","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#el-problema-por-qu-llvm-ir-no-alcanzaba","content":"LLVM es brillante para lo que hace: tomar IR moderadamente de bajo nivel y convertirlo en código máquina optimizado para una docena de arquitecturas. Pero tiene una limitación fundamental, hay un solo nivel de IR, y está aproximadamente al nivel de abstracción de C.\n\nSi se construye un compilador para un lenguaje de alto nivel (por ejemplo, un DSL de procesamiento de tensores), es necesario bajar los conceptos de alto nivel a LLVM IR tempranamente. Una vez realizada esa transformación, la información se pierde. El optimizador de LLVM ve loops y aritmética de punteros, no multiplicaciones de matrices y convoluciones. No puede fusionar dos operaciones de matrices que no sabe que son operaciones de matrices.\n\nEste es el \"gap de abstracción\" que plagó a los compiladores de ML durante años:\n\n```\nDSL de alto nivel: matmul(A, B) + transpose(C)\n │\n ┌───────────────┤ (pérdida de información aquí)\n ▼ │\nLLVM IR: loops anidados, instrucciones gep, loads/stores\n → LLVM puede optimizar los loops pero no ve el álgebra lineal\n```\n\nCada framework de ML lo resolvió distinto: TensorFlow tenía XLA, PyTorch tenía TorchScript y después Torch-MLIR, TVM tenía su propio IR, Halide tenía su propio IR. Cada uno reinventó sistemas de tipos, construcción de SSA, infraestructura de passes y canonicalización. Duplicación masiva."},{"heading":"La Idea Central de MLIR: Dialectos Hasta el Fondo","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#la-idea-central-de-mlir-dialectos-hasta-el-fondo","content":"La idea clave de MLIR es que no se necesita un IR, se necesita un framework para construir muchos IRs que puedan coexistir e interoperar. Ese framework es el sistema de **dialectos**.\n\nUn dialecto es un namespace que contiene:\n\n- **Operaciones** (las \"instrucciones\" de tu IR)\n- **Tipos** (el sistema de tipos para tu dominio)\n- **Atributos** (constantes de compilación y metadata)\n- **Interfaces** (traits que las operaciones pueden implementar para transformaciones genéricas)\n\nLa magia es que operaciones de distintos dialectos pueden existir en el mismo IR, y es posible bajar progresivamente de dialectos de alto nivel a los de bajo nivel:\n\n```mlir\n// Alto nivel: dialecto linalg (operaciones de álgebra lineal)\n%result = linalg.matmul ins(%A, %B : tensor<64x128xf32>, tensor<128x256xf32>)\n outs(%C : tensor<64x256xf32>) -> tensor<64x256xf32>\n\n// Nivel medio: dialecto affine (nidos de loops poliédricos)\naffine.for %i = 0 to 64 {\n affine.for %j = 0 to 256 {\n affine.for %k = 0 to 128 {\n %a = affine.load %A[%i, %k] : memref<64x128xf32>\n %b = affine.load %B[%k, %j] : memref<128x256xf32>\n %c = affine.load %C[%i, %j] : memref<64x256xf32>\n %prod = arith.mulf %a, %b : f32\n %sum = arith.addf %c, %prod : f32\n affine.store %sum, %C[%i, %j] : memref<64x256xf32>\n }\n }\n}\n\n// Bajo nivel: dialecto llvm (operaciones de LLVM IR)\n%ptr = llvm.getelementptr %base[%idx] : (!llvm.ptr, i64) -> !llvm.ptr\n%val = llvm.load %ptr : !llvm.ptr -> f32\n```\n\nEn cada nivel, es posible aplicar optimizaciones específicas del dominio que serían imposibles en niveles más bajos. El nivel ` linalg ` sabe de estrategias de tiling y fusión para operaciones de matrices. El nivel ` affine ` puede aplicar transformaciones poliédricas. El nivel ` llvm ` hace register allocation y selección de instrucciones."},{"heading":"Construyendo un Dialecto Custom: Un Ejemplo de Juguete","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#construyendo-un-dialecto-custom-un-ejemplo-de-juguete","content":"El siguiente ejemplo construye un dialecto simple para un DSL hipotético de procesamiento de imágenes. Se definen operaciones para cargar imágenes, aplicar filtros y compositar."},{"heading":"Paso 1: Definir el Dialecto en TableGen","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#paso-1-definir-el-dialecto-en-tablegen","content":"```tablegen\n// ImageOps.td\ninclude \"mlir/IR/OpBase.td\"\ninclude \"mlir/IR/AttrTypeBase.td\"\ninclude \"mlir/Interfaces/SideEffectInterfaces.td\"\n\n// Definir el dialecto\ndef ImageDialect : Dialect {\n let name = \"image\";\n let cppNamespace = \"::image\";\n let summary = \"Un dialecto para operaciones de procesamiento de imágenes\";\n}\n\n// Definir un tipo custom para imágenes con info de canales\ndef Image_ImageType : TypeDef<ImageDialect, \"Image\"> {\n let mnemonic = \"img\";\n let parameters = (ins\n \"int64_t\":$width,\n \"int64_t\":$height,\n \"int64_t\":$channels // 1=gris, 3=RGB, 4=RGBA\n );\n let assemblyFormat = \"`<` $width `,` $height `,` $channels `>`\";\n}\n\n// Operación de carga\ndef Image_LoadOp : Op<ImageDialect, \"load\", [Pure]> {\n let summary = \"Cargar una imagen desde un path\";\n let arguments = (ins StrAttr:$path);\n let results = (outs Image_ImageType:$result);\n let assemblyFormat = \"$path attr-dict `:` type($result)\";\n}\n\n// Operación de blur\ndef Image_BlurOp : Op<ImageDialect, \"blur\", [Pure]> {\n let summary = \"Aplicar desenfoque gaussiano\";\n let arguments = (ins\n Image_ImageType:$input,\n F32Attr:$sigma\n );\n let results = (outs Image_ImageType:$result);\n let assemblyFormat = \"$input `,` $sigma attr-dict `:` type($input) `->` type($result)\";\n\n // Verificar que input y output tengan las mismas dimensiones\n let verifier = [{\n auto inType = getInput().getType().cast<ImageType>();\n auto outType = getResult().getType().cast<ImageType>();\n if (inType.getWidth() != outType.getWidth() ||\n inType.getHeight() != outType.getHeight())\n return emitOpError(\"las dimensiones de input y output deben coincidir\");\n return success();\n }];\n}\n\n// Operación de composición\ndef Image_CompositeOp : Op<ImageDialect, \"composite\", [Pure]> {\n let summary = \"Componer dos imágenes con modo de mezcla\";\n let arguments = (ins\n Image_ImageType:$foreground,\n Image_ImageType:$background,\n StrAttr:$blend_mode // \"over\", \"multiply\", \"screen\"\n );\n let results = (outs Image_ImageType:$result);\n}\n```"},{"heading":"Paso 2: Escribir un Pass de Optimización Específico del Dominio","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#paso-2-escribir-un-pass-de-optimizacin-especfico-del-dominio","content":"Ahora se puede escribir un pass que fusiona operaciones de blur consecutivas en un solo blur con sigma combinado:\n\n```cpp\n// FuseBlursPass.cpp\n#include \"mlir/Pass/Pass.h\"\n#include \"ImageOps.h\"\n#include <cmath>\n\nnamespace {\nstruct FuseBlursPass\n : public mlir::PassWrapper<FuseBlursPass,\n mlir::OperationPass<mlir::func::FuncOp>> {\n\n void runOnOperation() override {\n getOperation().walk([](image::BlurOp outerBlur) {\n // Chequear si el input de este blur es otro blur\n auto innerBlur = outerBlur.getInput().getDefiningOp<image::BlurOp>();\n if (!innerBlur)\n return;\n\n // Chequear que el blur interno no tenga otros usuarios\n if (!innerBlur.getResult().hasOneUse())\n return;\n\n // Fusionar: sigma_combinado = sqrt(sigma1^2 + sigma2^2)\n float sigma1 = innerBlur.getSigma().convertToFloat();\n float sigma2 = outerBlur.getSigma().convertToFloat();\n float fusedSigma = std::sqrt(sigma1 * sigma1 + sigma2 * sigma2);\n\n // Reemplazar el blur exterior con un solo blur sobre el input del interior\n mlir::OpBuilder builder(outerBlur);\n auto fusedBlur = builder.create<image::BlurOp>(\n outerBlur.getLoc(),\n outerBlur.getType(),\n innerBlur.getInput(),\n builder.getF32FloatAttr(fusedSigma));\n\n outerBlur.replaceAllUsesWith(fusedBlur.getResult());\n outerBlur.erase();\n if (innerBlur.getResult().use_empty())\n innerBlur.erase();\n });\n }\n\n mlir::StringRef getArgument() const final { return \"image-fuse-blurs\"; }\n mlir::StringRef getDescription() const final {\n return \"Fusionar operaciones de blur consecutivas\";\n }\n};\n} // namespace\n```"},{"heading":"El IR En Acción","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#el-ir-en-accin","content":"Así se ve un pipeline completo en nuestro dialecto de imágenes:\n\n```mlir\n// IR de entrada (operaciones de imagen de alto nivel)\nfunc.func @process_photo(%path: !image.img<1920, 1080, 3>) -> !image.img<1920, 1080, 3> {\n %photo = image.load \"/photos/input.jpg\" : !image.img<1920, 1080, 3>\n %blurred1 = image.blur %photo, 2.0 : !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n %blurred2 = image.blur %blurred1, 3.0 : !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n %overlay = image.load \"/photos/overlay.png\" : !image.img<1920, 1080, 4>\n %result = image.composite %overlay, %blurred2, \"over\" :\n !image.img<1920, 1080, 4>, !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n return %result : !image.img<1920, 1080, 3>\n}\n\n// Después del pass de fusión de blur (sigma = sqrt(4 + 9) = 3.606):\nfunc.func @process_photo(%path: !image.img<1920, 1080, 3>) -> !image.img<1920, 1080, 3> {\n %photo = image.load \"/photos/input.jpg\" : !image.img<1920, 1080, 3>\n %blurred = image.blur %photo, 3.606 : !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n %overlay = image.load \"/photos/overlay.png\" : !image.img<1920, 1080, 4>\n %result = image.composite %overlay, %blurred, \"over\" :\n !image.img<1920, 1080, 4>, !image.img<1920, 1080, 3> -> !image.img<1920, 1080, 3>\n return %result : !image.img<1920, 1080, 3>\n}\n```\n\nEl pass de fusión convirtió dos operaciones de blur en una, cortando el trabajo de convolución aproximadamente a la mitad. Esta optimización es trivial de expresar a nivel del dialecto de imagen, pero sería casi imposible de descubrir después de bajar a loops."},{"heading":"MLIR en el Mundo Real: El Panorama de Compiladores de ML","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#mlir-en-el-mundo-real-el-panorama-de-compiladores-de-ml","content":"Los mayores usuarios de MLIR son los compiladores de ML, y con razón. Los workloads de ML tienen una estructura multi-nivel natural:\n\n```\nNivel framework: torch.nn.Linear(256, 128)\n │\n ▼ TorchMLIR\nNivel grafo: linalg.matmul + linalg.add (bias)\n │\n ▼ Tiling + Fusión\nNivel tile: loops scf.for con cuerpos internos vectorizados\n │\n ▼ Lowering a hardware\nNivel hardware: gpu.launch_func / vector.contract / amx.tile_mulf\n │\n ▼ Lowering a LLVM\nCódigo máquina: instrucciones AVX-512 / CUDA PTX / AMX\n```\n\nCada nivel tiene sus propias oportunidades de optimización:\n\n- **Nivel grafo**: fusión de operadores (matmul + bias + relu = un kernel), optimización de layout (NHWC vs NCHW)\n- **Nivel tile**: selección de tamaño de tile, scheduling consciente de caché, estrategia de vectorización\n- **Nivel hardware**: mapeo a extensiones ISA específicas (AMX para Intel, Tensor Cores para NVIDIA)"},{"heading":"IREE: El Runtime de ML de Google Construido sobre MLIR","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#iree-el-runtime-de-ml-de-google-construido-sobre-mlir","content":"IREE (Intermediate Representation Execution Environment) es probablemente el compilador de ML basado en MLIR más completo en producción. Toma modelos de TensorFlow, PyTorch o JAX, los baja a través de dialectos MLIR, y genera código optimizado para CPUs, GPUs y aceleradores."},{"heading":"Mojo: Un Lenguaje Construido sobre MLIR","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#mojo-un-lenguaje-construido-sobre-mlir","content":"El lenguaje de programación Mojo de Modular está construido directamente sobre MLIR. Esto significa que el compilador de Mojo puede expresar abstracciones de alto nivel (sintaxis tipo Python) y operaciones de hardware de bajo nivel (intrínsecos SIMD) en el mismo IR, y el pipeline de optimización puede ver ambos simultáneamente.\n\n```mojo\n# Código Mojo que compila a través de MLIR\nfn matmul_tiled[M: Int, N: Int, K: Int](\n A: SIMD[DType.float32, M*K],\n B: SIMD[DType.float32, K*N],\n) -> SIMD[DType.float32, M*N]:\n var C = SIMD[DType.float32, M*N](0)\n for i in range(M):\n for j in range(N):\n for k in range(K):\n C[i*N + j] += A[i*K + k] * B[k*N + j]\n return C\n```"},{"heading":"Empezando: El Camino Práctico","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#empezando-el-camino-prctico","content":"Para experimentar con MLIR, aquí va un camino recomendado:"},{"heading":"1. Compilar MLIR Desde Source","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#1-compilar-mlir-desde-source","content":"```bash\ngit clone https://github.com/llvm/llvm-project.git\ncd llvm-project\nmkdir build && cd build\n\ncmake -G Ninja ../llvm \\\n -DLLVM_ENABLE_PROJECTS=mlir \\\n -DLLVM_BUILD_EXAMPLES=ON \\\n -DLLVM_TARGETS_TO_BUILD=\"host\" \\\n -DCMAKE_BUILD_TYPE=Release \\\n -DLLVM_ENABLE_ASSERTIONS=ON\n\nninja -j$(nproc)\n```"},{"heading":"2. Jugar con mlir-opt","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#2-jugar-con-mlir-opt","content":"```bash\n# Escribir un programa MLIR simple\ncat > test.mlir << 'EOF'\nfunc.func @add(%arg0: f32, %arg1: f32) -> f32 {\n %0 = arith.addf %arg0, %arg1 : f32\n return %0 : f32\n}\nEOF\n\n# Correr canonicalización\n./bin/mlir-opt --canonicalize test.mlir\n\n# Bajar al dialecto LLVM\n./bin/mlir-opt --convert-func-to-llvm --convert-arith-to-llvm test.mlir\n\n# Ver todos los passes disponibles\n./bin/mlir-opt --help | grep \"Passes:\"\n```"},{"heading":"3. Estudiar el Tutorial Toy","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#3-estudiar-el-tutorial-toy","content":"El repo de MLIR incluye un tutorial completo que construye un compilador para un lenguaje de juguete desde cero. Está en ` mlir/docs/Tutorials/Toy/ ` y cubre todo desde lexing hasta codegen LLVM a través de MLIR."},{"heading":"Por Qué Esto Importa Más Allá de los Compiladores","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#por-qu-esto-importa-ms-all-de-los-compiladores","content":"El sistema de dialectos de MLIR es genuinamente útil fuera del trabajo tradicional de compiladores:\n\n- **Diseño de hardware**: CIRCT usa dialectos MLIR para representar lenguajes de descripción de hardware, reemplazando toolchains de Verilog/VHDL.\n- **Computación cuántica**: El dialecto ` quake ` representa circuitos cuánticos para optimización antes de mapear al hardware cuántico.\n- **Motores de base de datos**: Los planificadores de queries pueden usar dialectos custom para representar álgebra relacional y optimizar planes de ejecución.\n- **Simulación numérica**: El dialecto ` sparse_tensor ` maneja operaciones de matrices sparse con selección automática de formato.\n\nEl patrón es siempre el mismo: teners un dominio con operaciones específicas y reglas de optimización que son invisibles a un nivel de abstracción más bajo. MLIR te da la infraestructura para expresar ese dominio sin construir todo desde cero.\n\nMLIR no es solo un LLVM IR mejor. Es un framework para construir compiladores a cualquier nivel de abstracción, con infraestructura que tardó décadas en desarrollarse en LLVM, disponible out of the box. Si se está construyendo algo que transforma representaciones estructuradas, ya sean modelos de ML, descripciones de hardware, o queries de bases de datos, MLIR vale tu tiempo."},{"heading":"Preguntas frecuentes","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#questions","content":""},{"heading":"¿Qué es MLIR?","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-1","content":"MLIR (Multi-Level Intermediate Representation) es una infraestructura de compiladores dentro del proyecto LLVM que provee un framework flexible y extensible para construir compiladores de dominio específico usando 'dialectos' componibles, colecciones de tipos, operaciones y reglas de transformación."},{"heading":"¿En qué se diferencia MLIR del LLVM IR?","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-2","content":"LLVM IR es una representación de un solo nivel fijo, diseñada para generación de código de CPU de propósito general. MLIR soporta múltiples niveles de abstracción simultáneamente, permitiendo representar conceptos de alto nivel del dominio (operaciones tensoriales, intrínsecos de hardware) junto con código de bajo nivel."},{"heading":"¿Qué son los dialectos de MLIR?","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-3","content":"Los dialectos son colecciones modulares de operaciones, tipos y atributos en MLIR. Cada dialecto define su propio vocabulario, por ejemplo, el dialecto 'linalg' tiene operaciones para álgebra lineal, mientras que el dialecto 'gpu' tiene operaciones para kernels de GPU. Puede mezclar dialectos libremente en el mismo IR."},{"heading":"¿Quién usa MLIR en producción?","level":3,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#question-4","content":"Google (TensorFlow/XLA, IREE), AMD (stack de compilador ROCm), Intel (oneAPI), Modular (lenguaje Mojo), y varias startups de hardware ML usan MLIR como backbone de sus compiladores."},{"heading":"Tips","level":2,"url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#article-tips","content":"1. **Tip:** Cuando se define ops custom en MLIR, utilizar siempre TableGen (archivos ` .td `) en vez de escribir clases C++ de ops a mano. TableGen auto-genera verificadores, builders, parsers y printers. Escribir ops a mano es una pesadilla de debugging.\n2. **Tip:** El flag ` -mlir-print-ir-after-all ` de MLIR vuelca el IR después de cada pass. Pasarlo por ` diff ` para ver exactamente qué hace cada transformación. Esta es la técnica de depuración más útil para desarrollo de passes.\n3. **Tip:** Iniciar con los dialectos ` func ` y ` arith ` al aprender MLIR. Son lo suficientemente simples para comprender en una tarde pero demuestran todos los conceptos centrales, regions, blocks, valores SSA y sistemas de tipos.\n4. **Tip:** Utilizar ` mlir-opt --canonicalize ` como primer pass de optimización. Los patrones de canonicalización (constant folding, dead code elimination, identity removal) se registran por operación y se ejecutan hasta fixpoint. Captura el 80% de las redundancias obvias.\n\n- llvm\n- mlir\n- compiladores\n- dialectos\n- optimización\n- machine-learning\n- dsl\n- representación-intermedia\n\n[Volver al Blog](<https://lucioduran.com/es/blog>)"}],"links":[{"text":"English","url":"https://lucioduran.com/blog/llvm-mlir-compiler-infrastructure-custom-dialects"},{"text":"Volver al Blog","url":"https://lucioduran.com/es/blog"}],"structuredData":[{"@context":"https://schema.org","@graph":[{"@type":"BlogPosting","@id":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects#article","mainEntityOfPage":{"@type":"WebPage","@id":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects"},"headline":"LLVM MLIR: Construyendo Dialectos de Compilador Custom para Optimización de Dominio","description":"Análisis de la arquitectura de representación intermedia multi-nivel de MLIR, construcción de dialectos personalizados y la convergencia de compiladores de ML, aceleradores de hardware y DSLs en el framework MLIR.","datePublished":"2026-01-27","author":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"publisher":{"@type":"Person","@id":"https://lucioduran.com/#person","name":"Lucio Durán","url":"https://lucioduran.com"},"image":"https://statics.lucioduran.com/images/lucioduran-social-card.jpg","url":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects","inLanguage":"es","isPartOf":{"@id":"https://lucioduran.com/blog#blog"},"articleSection":"Compilers","keywords":"llvm, mlir, compiladores, dialectos, optimización, machine-learning, dsl, representación-intermedia","wordCount":1803,"timeRequired":"PT10M","workTranslation":[{"@type":"BlogPosting","inLanguage":"en","url":"https://lucioduran.com/blog/llvm-mlir-compiler-infrastructure-custom-dialects"}]},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https://lucioduran.com/"},{"@type":"ListItem","position":2,"name":"Blog","item":"https://lucioduran.com/es/blog"},{"@type":"ListItem","position":3,"name":"LLVM MLIR: Construyendo Dialectos de Compilador Custom para Optimización de Dominio","item":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects"}]},{"@type":"FAQPage","mainEntity":[{"@type":"Question","name":"¿Qué es MLIR?","acceptedAnswer":{"@type":"Answer","text":"MLIR (Multi-Level Intermediate Representation) es una infraestructura de compiladores dentro del proyecto LLVM que provee un framework flexible y extensible para construir compiladores de dominio específico usando 'dialectos' componibles, colecciones de tipos, operaciones y reglas de transformación."}},{"@type":"Question","name":"¿En qué se diferencia MLIR del LLVM IR?","acceptedAnswer":{"@type":"Answer","text":"LLVM IR es una representación de un solo nivel fijo, diseñada para generación de código de CPU de propósito general. MLIR soporta múltiples niveles de abstracción simultáneamente, permitiendo representar conceptos de alto nivel del dominio (operaciones tensoriales, intrínsecos de hardware) junto con código de bajo nivel."}},{"@type":"Question","name":"¿Qué son los dialectos de MLIR?","acceptedAnswer":{"@type":"Answer","text":"Los dialectos son colecciones modulares de operaciones, tipos y atributos en MLIR. Cada dialecto define su propio vocabulario, por ejemplo, el dialecto 'linalg' tiene operaciones para álgebra lineal, mientras que el dialecto 'gpu' tiene operaciones para kernels de GPU. Puede mezclar dialectos libremente en el mismo IR."}},{"@type":"Question","name":"¿Quién usa MLIR en producción?","acceptedAnswer":{"@type":"Answer","text":"Google (TensorFlow/XLA, IREE), AMD (stack de compilador ROCm), Intel (oneAPI), Modular (lenguaje Mojo), y varias startups de hardware ML usan MLIR como backbone de sus compiladores."}}]}]}],"contentHash":"84591268295b366838f897dc30bbf1a10e532010a0248c57da76153f252e70e7","provenance":{"method":"Deterministic serialization of the server-rendered main element","source":"https://lucioduran.com/es/blog/llvm-mlir-compiler-infrastructure-custom-dialects","hashAlgorithm":"sha256","hashScope":"JSON document fields before contentHash and provenance","sourceHTMLBytes":76636,"contentBytes":16095}}
