A Tour of XLA: Where MLIR Lives (and Where It Doesn't) XLA, the compiler under JAX, TensorFlow, and PyTorch/XLA, uses two intermediate representations: classic HLO (a hand-built C++ IR) and MLIR dialects such as StableHLO and CHLO, with a translation layer moving programs between them. The core optimizer works on classic HLO, while MLIR appears at the front door (framework targeting), the sharding system, and code generation, making XLA a mixed compiler rather than a pure MLIR one. A Tour of XLA: Where MLIR Lives and Where It Doesn't XLA is the compiler under JAX, TensorFlow, and PyTorch/XLA, turning tensor programs into fast code for CPUs, GPUs, and TPUs. This is a tour of its architecture through one particular lens — where it uses MLIR, and where it doesn’t — because XLA’s structure is mixed, and the mix is the part worth understanding. XLA predates MLIR by several years, and its optimizer core is still its own representation: classic HLO, a hand-built C++ IR with its own passes, serialization, and text format. That core is not MLIR. MLIR appears, instead, at particular layers around it — the front door the frameworks target, the sharding system, and a growing share of code generation. So the useful question about XLA is not whether it “is an MLIR compiler” but which parts are and which parts aren’t — and that turns out to be specific enough to map. That map is the rest of this post, walked from the way in to the way out and grounded in the openxla/xla source tree with paths cited. It is a companion to the tour of MLIR /posts/mlir-dialect-stack-for-ml/ , which covered MLIR as a general IR construction kit; here we look at one large, mature consumer of it and note how much shows up, and where. The two IRs The single most important architectural fact about XLA is that it has two intermediate representations, and only one of them is MLIR. The core is classic HLO — “High Level Operations.” It is a set of hand-written C++ classes HloModule , HloComputation , HloInstruction , in xla/hlo/ir/ , with its own protobuf serialization, its own pass manager, and a text format that is not MLIR’s. 1 This is what the optimizer works on, and it reads like this — note the f32 4,16 {1,0} shape-and-layout notation, the fusion ... ops, no func.func , no tensor< types: 1 2 3 4 5 6 7 8 php %fused computation.1 param 0.2: f32 4,16 , param 1.4: f32 16 - f32 4,16 { %add.1 = f32 4,16 {1,0} broadcast %param 1.4 , dimensions={1} %add.0 = f32 4,16 {1,0} add %param 0.2, %add.1 ROOT %max.0 = f32 4,16 {1,0} maximum %add.0, %constant.0 } ENTRY %main { %ynn fusion = f32 4,16 {1,0} fusion %x, %W , kind=kCustom, calls=%fused computation } The other IR is a family of MLIR dialects . XLA defines some in-tree — MHLO the MLIR-native rendering of HLO and the IFRT / VIFRT dialects for its multi-device runtime interchange 2 — and depends on others, chiefly StableHLO and its higher-level sibling CHLO . A jit -ed relu x @ W + b , straight from JAX’s lower , comes out as StableHLO, and it is unmistakably MLIR — func.func , SSA % values, tensor<... types, dialect-prefixed ops: 1 2 3 4 5 6 7 8 9 func.func public @main %arg0: tensor<4x8xf32 , %arg1: tensor<8x16xf32 , %arg2: tensor<16xf32 - tensor<4x16xf32 { %0 = stablehlo.dot general %arg0, %arg1, contracting dims = 1 x 0 : tensor<4x8xf32 , tensor<8x16xf32 - tensor<4x16xf32 %1 = stablehlo.broadcast in dim %arg2, dims = 1 : tensor<16xf32 - tensor<1x16xf32 %3 = stablehlo.add %0, %1 : tensor<4x16xf32 %5 = stablehlo.maximum %3, %cst : tensor<4x16xf32 return %5 : tensor<4x16xf32 } Same computation, two worlds. And critically, there is a translation layer, xla/hlo/translate/ , whose whole job is to move programs across the seam: stablehlo to hlo , hlo to mhlo , mhlo to hlo . 3 So the life of a program is: a framework hands XLA StableHLO MLIR , XLA translates it down into classic HLO , optimizes it as classic HLO , and then translates back into MLIR to generate code. MLIR bookends the classic-HLO core — and, as we will see, there is a second entry path that skips the core entirely. php graph TD FW "JAX / TF / PyTorch" FW -- |"lower "| SHLO "StableHLO / CHLO