Inferensys

Glossary

Intermediate Representation (IR)

An Intermediate Representation (IR) is an abstract, platform-independent data structure or code used within a compiler to represent a program, such as a neural network's computational graph, between its source form and its final executable form.
Data scientist building training data pipeline on laptop, data preprocessing visible, technical workspace.
COMPUTE GRAPH OPTIMIZATION

What is Intermediate Representation (IR)?

An intermediate representation (IR) is the core data structure used by compilers to represent a program, such as a neural network's computational graph, between its source form and its final executable machine code.

An Intermediate Representation (IR) is an abstract, platform-independent data structure or code used within a compiler to represent a program between its source form and its final executable form. For machine learning, the IR typically encodes the model's computational graph, including operations (ops), tensors, and data dependencies. This abstraction enables a suite of hardware-agnostic graph optimizations—like constant folding, operator fusion, and dead code elimination—before targeting specific silicon.

The IR serves as the central interface between the frontend (framework like PyTorch) and backend (hardware like an NPU). High-level IRs are expressive and close to the source, while lower-level IRs are more restrictive and closer to machine code through a process called graph lowering. This multi-stage design allows compilers like TVM, XLA, and MLIR to perform sophisticated transformations for optimal execution, separating logical model design from physical deployment constraints.

COMPUTE GRAPH OPTIMIZATION

Key Characteristics of an IR

An Intermediate Representation (IR) is the core data structure within a compiler that bridges a high-level model definition and low-level machine code. Its design dictates the efficiency and portability of the entire compilation pipeline.

01

Abstraction Level

An IR's abstraction level defines its distance from source code or hardware. High-Level IRs (HIR) preserve rich semantic information (e.g., loops, function calls) for architecture-agnostic optimizations. Mid-Level IRs (MIR) are often control-flow graphs suitable for analysis and transformation. Low-Level IRs (LIR) resemble assembly, exposing hardware details like registers and instruction selection. Compilers like LLVM use a tiered system, progressively lowering from a HIR to a LIR.

02

Graph Structure

Most modern ML IRs represent computation as a Directed Acyclic Graph (DAG). Nodes represent operations (ops) or tensors, and edges represent data dependencies. This structure enables:

  • Topological sorting for correct execution order.
  • Easy analysis of data flow and operator lifetimes for static memory planning.
  • Efficient application of transformations like operator fusion and dead code elimination.
  • Frameworks like TensorFlow (GraphDef), PyTorch (TorchScript), and ONNX use this graph paradigm.
03

Platform Independence

A core purpose of an IR is to decouple model definition from hardware execution. A platform-independent IR (e.g., ONNX, MLIR's dialect-ir) allows:

  • A single model definition to target CPUs, GPUs, NPUs, and microcontrollers.
  • Hardware vendors to develop specialized compiler backends that lower the IR to their native instructions.
  • Enables retargeting without modifying the original model, a key tenet of frameworks like Apache TVM and Google's XLA.
04

Extensibility & Dialects

Advanced IRs provide mechanisms to model diverse computational domains. MLIR pioneered the dialect system, where the IR can be extended with custom operations, types, and attributes. This allows:

  • A Neural Network dialect for high-level ML ops.
  • An LLVM dialect for low-level CPU/GPU code.
  • Domain-specific dialects for linear algebra, affine loops (polyhedral model), or quantum computing.
  • Dialects can be progressively lowered and legalized to a final target, enabling complex, multi-stage compilation.
05

Optimization Passes

The IR is the substrate for compiler passes—transformations that analyze and rewrite the graph. Common passes include:

  • Canonicalization: Simplifies patterns to a standard form.
  • Constant Folding: Pre-computes operations on constant values.
  • Common Subexpression Elimination (CSE): Removes redundant calculations.
  • Algebraic Simplification: Applies mathematical identities (e.g., x*1 => x). Passes can be greedy, pattern-based, or guided by a cost model, and are often applied in a specific pipeline.
06

Static vs. Dynamic

This axis defines when graph structure is finalized. Static IR (e.g., TensorFlow 1.x, ONNX) fixes the graph topology and tensor shapes ahead-of-time (AOT), enabling aggressive optimization. Dynamic IR (e.g., PyTorch's eager mode) is built at runtime, offering flexibility. Modern systems use tracing or scripting to capture dynamic execution into a static graph, or employ just-in-time (JIT) compilation to specialize a dynamic graph based on runtime shapes (shape inference).

COMPUTE GRAPH OPTIMIZATION

How an IR Works in an ML Compiler Pipeline

An intermediate representation (IR) is the core data structure that enables the transformation of a neural network from a high-level framework definition into optimized, executable code for target hardware.

An Intermediate Representation (IR) is an abstract, platform-independent data structure or code used within a compiler to represent a program, such as a neural network's computational graph, between its source form and its final executable form. It serves as the central artifact for all graph optimizations, including operator fusion, constant folding, and dead code elimination, allowing transformations to be applied uniformly before targeting specific hardware.

The IR undergoes a process of graph lowering, where high-level operations are decomposed into sequences of lower-level, hardware-specific instructions. This multi-level abstraction enables hardware-agnostic optimizations at higher IR levels and performance-tuning at lower levels, facilitating efficient code generation for diverse backends like CPUs, GPUs, and specialized Neural Processing Units (NPUs) through mechanisms like hardware delegates.

COMPUTE GRAPH OPTIMIZATION

Common IRs in Machine Learning Systems

An Intermediate Representation (IR) is the abstract, platform-independent data structure used by compilers to represent a program between its source form and final executable code. In ML systems, different IRs serve distinct roles in the optimization pipeline.

01

High-Level Graph IR

A High-Level Graph IR represents a neural network as a computational graph of abstract operators, independent of hardware specifics. This is the initial representation after importing a model from frameworks like PyTorch or TensorFlow.

  • Purpose: Enables hardware-agnostic graph-level optimizations like constant folding, dead code elimination, and operator fusion.
  • Examples: ONNX (Open Neural Network Exchange) Graph, TensorFlow GraphDef, PyTorch FX Graph, and Relay IR (from Apache TVM).
  • Characteristics: Nodes represent coarse-grained operations (e.g., Conv2D, MatMul); tensors have abstract data types and symbolic shapes.
02

Lowered IR / Kernel IR

A Lowered IR is the result of graph lowering, where high-level operators are decomposed into primitive, target-specific operations. It bridges the gap between abstract computation and hardware execution.

  • Purpose: Exposes low-level details for backend-specific optimizations like loop tiling, vectorization, and efficient memory layout planning.
  • Examples: MLIR's Affine Dialect for loop nests, Halide IR for image processing pipelines, TensorFlow XLA's HLO IR after target-specific lowering, and LLVM IR for CPU targets.
  • Characteristics: Includes memory buffers, explicit loops, and address calculations. It is often linear or in Static Single Assignment (SSA) form.
03

Hardware-Specific IR

A Hardware-Specific IR is a final, vendor-optimized representation that maps directly to the execution model of a particular accelerator, such as a GPU, NPU, or DSP.

  • Purpose: Encodes instructions, memory hierarchies, and parallelism models (e.g., warps, workgroups) unique to the target silicon. Enables kernel auto-tuning and optimal operator dispatch.
  • Examples: NVIDIA PTX (Parallel Thread Execution), CUDA Graphs, Google TPU's HLO (after further TPU lowering), ARM Compute Library's Graph IR, and proprietary NPU compiler IRs (e.g., Qualcomm SNPE, Apple Core ML).
  • Characteristics: Contains explicit parallel constructs, synchronization primitives, and hardware intrinsic functions.
04

Quantized & Sparse IRs

Specialized IRs encode optimizations for model compression, representing networks after quantization or pruning. They are crucial for efficient on-device inference.

  • Purpose: Explicitly represents low-precision data types (e.g., int8, uint4) and sparse tensor encoding formats (e.g., CSR, Block-Sparse) to enable integer-only kernels and skip zero computations.
  • Examples: TFLite's FlatBuffer schema with quantized operators, ONNX with QuantizeLinear/DequantizeLinear nodes, MLIR's TOSA dialect with quantization attributes, and frameworks using the Sparse Tensor Core extension in LLVM.
  • Optimization: Quantization folding is a key pass that merges fake quantization nodes with linear ops in these IRs.
05

Polyhedral IR

A Polyhedral IR uses mathematical polyhedra to model loop nests and their data dependencies, enabling powerful automatic transformations for compute-intensive, regular kernels like convolutions and matrix multiplications.

  • Purpose: Provides a unified model for complex loop optimizations such as loop tiling, fusion, skewing, and interchange while preserving correctness.
  • Examples: MLIR's Affine Dialect, the ISL (Integer Set Library) framework, and the core IR of the Polyhedral Model used in compilers like Pluto.
  • Use Case: Critical for optimizing linear algebra operations on CPUs and GPUs, guided by a cost model and the Roofline model to achieve peak performance.
06

Runtime IR / JIT IR

A Runtime IR or JIT IR is an intermediate representation that is constructed, optimized, and compiled during program execution. It enables dynamic optimizations based on runtime information.

  • Purpose: Allows for Just-In-Time (JIT) compilation where optimizations like shape specialization, kernel selection, and graph rewriting can use concrete tensor shapes and values known only at runtime.
  • Examples: PyTorch's TorchScript IR (for JIT), TensorFlow's XLA JIT compilation path, Apache TVM's runtime module, and Triton's JIT IR for GPU programming.
  • Advantage: Balances optimization potential with flexibility, avoiding the need for Ahead-Of-Time (AOT) compilation to handle all possible input variations.
COMPILER ABSTRACTION HIERARCHY

Comparing Levels of Intermediate Representation

This table compares the characteristics of high-level, mid-level, and low-level intermediate representations (IRs) used in machine learning compilers and inference frameworks.

CharacteristicHigh-Level IR (HIR)Mid-Level IR (MIR)Low-Level IR (LIR)

Abstraction Level

Graph-Level

Operator-Level

Instruction-Level

Primary Representation

Computational Graph (e.g., ONNX, TensorFlow GraphDef)

Three-Address Code / Static Single Assignment (SSA)

Machine-Specific Instructions / Assembly

Hardware Dependence

Fully Hardware-Agnostic

Partially Hardware-Aware

Highly Hardware-Specific

Optimizations Performed

Graph Transformations (Fusion, Pruning), Algebraic Simplifications

Loop Optimizations, Memory Planning, Common Subexpression Elimination

Register Allocation, Instruction Scheduling, Peephole Optimizations

Typical Input

Framework-Specific Model (PyTorch, TensorFlow)

High-Level IR (HIR)

Mid-Level IR (MIR)

Typical Output

Mid-Level IR (MIR)

Low-Level IR (LIR)

Machine Code / Executable Binary

Key Compiler Passes

Canonicalization, Shape Inference, Constant Folding

Vectorization, Loop Tiling, Static Memory Planning

Instruction Selection, Software Pipelining

Human Readability

High (Semantic, close to source)

Moderate (Structured, but verbose)

Low (Machine-oriented, terse)

Example Formats/Systems

ONNX, Relay (TVM), XLA HLO, TorchScript

LLVM IR, MLIR (affine, linalg dialects), TIR (TVM)

LLVM Machine IR, SPIR-V, Vendor-Specific ISA (e.g., CUDA PTX, NPU VLIW)

INTERMEDIATE REPRESENTATION (IR)

Frequently Asked Questions

An intermediate representation (IR) is the abstract, platform-independent data structure used by compilers to represent a program—like a neural network's computational graph—between its source form and its final executable code. This section answers key questions about its role in machine learning compilation and optimization.

An Intermediate Representation (IR) is an abstract, platform-independent data structure or code used within a compiler to represent a program, such as a neural network's computational graph, between its source form (e.g., a PyTorch model) and its final executable form for a target hardware (e.g., CPU, GPU, NPU). It serves as the central, canonical format for performing analyses and transformations, enabling optimizations like operator fusion, constant folding, and dead code elimination without being tied to a specific frontend framework or backend hardware. In ML compilers like TVM, XLA, or MLIR, the IR captures the model's operations, data dependencies, and tensor shapes in a graph or hierarchical structure that is amenable to automated rewriting and lowering.

Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.