An Intermediate Representation (IR) is a compiler's internal, machine-independent data structure or code used to represent a program between its source form and its final executable machine code. It serves as a central abstraction layer, enabling sophisticated analysis and transformations—such as constant folding and dead code elimination—without being tied to the specifics of the source language or the target hardware. This decoupling is fundamental to modern graph compilation strategies for neural networks, where a high-level model graph is progressively lowered and optimized through multiple IR levels before deployment on an NPU or other accelerator.
Glossary
Intermediate Representation (IR)

What is Intermediate Representation (IR)?
A core data structure in compilers that bridges high-level code and machine-specific instructions.
In machine learning compilers, IRs are often structured as computational graphs where nodes represent operations (like convolutions) and edges represent data flow (tensors). Compiler passes iteratively refine this graph through optimizations like operator fusion and memory planning. Frameworks like MLIR formalize this by providing a modular system of interoperable, domain-specific IR dialects. The choice and design of the IR directly influence the compiler's ability to perform hardware-aware optimizations, manage memory hierarchy, and exploit parallelism, making it a critical component for achieving peak performance on specialized accelerators.
Key Characteristics of an Intermediate Representation
An Intermediate Representation (IR) is the compiler's core data structure, designed to facilitate analysis and transformation between source code and target machine instructions. Its design principles directly enable the powerful optimizations required for efficient NPU execution.
Machine Independence
A primary purpose of an IR is to decouple the source program from the target hardware. It provides an abstract, hardware-agnostic model of computation, enabling machine-independent optimizations like common subexpression elimination and dead code elimination. This allows a single frontend (e.g., PyTorch, TensorFlow) to target multiple backends (e.g., different NPUs, GPUs, CPUs) through a shared optimization pipeline.
Explicit Dataflow & Dependencies
IRs for machine learning, such as computational graphs, explicitly encode the dataflow between operations (nodes) and the dependencies between tensors (edges). This explicit structure is crucial for:
- Automatic differentiation (autodiff) for gradient calculation.
- Static analysis to determine memory requirements and execution schedules.
- Enabling optimizations like operator reordering and graph fusion that respect these dependencies.
Multiple Levels of Abstraction
Modern compiler frameworks like MLIR employ a multi-level IR design. High-level IRs capture domain-specific concepts (e.g., neural network layers, tensor contractions), while lower-level IRs resemble generic compiler IRs (e.g., loops, memory buffers) or even target-specific instructions. This hierarchy allows for progressive lowering, where optimizations are applied at the most appropriate abstraction level before legalizing the IR for a specific hardware target.
Facilitates Analysis & Transformation
The IR is the substrate for all compiler passes. Its structure is designed to make program properties easy to compute and transformations safe to apply.
- Analysis Passes: Traverse the IR to gather information (e.g., liveness analysis, static shape inference).
- Transformation Passes: Modify the IR based on analysis results (e.g., constant folding, loop tiling, memory planning). A well-designed IR makes these passes simpler, more composable, and less error-prone.
Canonical Form & Legalization
A canonical IR is a standardized, simplified version where semantically equivalent programs have identical or nearly identical representations. Graph canonicalization eliminates syntactic noise, making pattern matching for optimizations reliable. Legalization is the process of transforming an IR from a high-level, possibly illegal form for the target, into a lower-level form that uses only operations supported by the hardware backend.
Enables Hardware-Specific Mapping
While machine-independent initially, the IR serves as the interface for hardware-aware optimizations. The final stages of compilation involve:
- Instruction Selection: Mapping IR operations to specific NPU instructions.
- Scheduling & Mapping: Assigning operations to NPU cores and determining execution order.
- Register Allocation: Managing the finite fast memory (registers) of the NPU. The IR's structure directly influences the efficiency of these critical backend phases.
The Role of IR in ML Compilation for NPUs
An Intermediate Representation (IR) is the compiler's central data structure, acting as the bridge between a high-level neural network description and the low-level machine code executed on a Neural Processing Unit (NPU).
An Intermediate Representation (IR) is a compiler's internal, machine-independent data structure that encodes a program's logic between its source form and final hardware instructions. In ML compilation for NPUs, the IR typically represents the neural network's computational graph, enabling critical, hardware-agnostic analyses and transformations like dead code elimination and common subexpression elimination before targeting specific silicon.
The IR undergoes a process called graph lowering, where high-level operations are progressively decomposed into lower-level, hardware-specific primitives. This multi-level abstraction, exemplified by frameworks like MLIR, allows compilers to apply architecture-agnostic optimizations early and vendor-specific mappings late, ultimately generating optimized kernels that fully leverage the NPU's parallel execution units and memory hierarchy.
Common Intermediate Representations in AI Compilation
An Intermediate Representation (IR) is the compiler's internal data structure used to represent a program between its source form and target machine code. These are the key IRs and frameworks that enable machine-independent analysis and optimization for AI workloads.
Levels of Intermediate Representation
A comparison of IR levels, from high-level, hardware-agnostic graphs to low-level, hardware-specific instructions, illustrating the progressive lowering process in an NPU compiler stack.
| Representation Level | High-Level IR (HIR) | Mid-Level IR (MIR) | Low-Level IR (LIR) |
|---|---|---|---|
Primary Abstraction | Computational Graph / Operator Dialect | Static Single Assignment (SSA) Form | Machine Instructions / Intrinsics |
Hardware Specificity | Hardware-agnostic | Target-aware | Target-specific |
Typical Content | Neural network layers, high-level ops, dataflow | Loops, memory buffers, address calculations | Register allocations, instruction schedules, memory accesses |
Key Optimizations Performed | Graph fusion, constant folding, dead code elimination | Loop transformations, common subexpression elimination | Instruction selection, peephole optimization, register allocation |
Control Flow Representation | Implicit via data dependencies | Explicit (loops, branches) | Basic blocks with jumps/branches |
Memory Model | Logical tensors with symbolic shapes | Explicit buffers with static/dynamic shapes | Physical registers and memory addresses |
Example Formats / Dialects | ONNX, TensorFlow GraphDef, PyTorch FX, MLIR 'linalg' dialect | MLIR 'scf' & 'memref' dialects, LLVM IR (partially) | MLIR 'llvm' dialect, vendor-specific assembly, SPIR-V |
Target Audience | ML Engineers, Framework Developers | Compiler Engineers, Performance Architects | Backend Engineers, Hardware Architects |
Frequently Asked Questions
An Intermediate Representation (IR) is the core data structure used by compilers to represent a program between its source form and target machine code. This section answers key questions about its role in machine learning compilation and NPU acceleration.
An Intermediate Representation (IR) is a compiler's internal, machine-independent data structure or code used to represent a program between its source form and its final target machine code. It acts as a central, canonical abstraction that enables sophisticated analysis and transformations without being tied to the specifics of the source language or the target hardware. In the context of machine learning compilers like TVM, XLA, or MLIR, the IR represents the neural network's computational graph, where nodes are operations (like convolutions or matrix multiplications) and edges are data dependencies (tensors). This graph-based IR allows the compiler to perform optimizations—such as operator fusion, constant folding, and dead code elimination—in a hardware-agnostic way before specializing the code for a specific Neural Processing Unit (NPU) or GPU.
Enabling Efficiency, Speed & Accuracy
Intelligent Analysis, Decision & Execution
We build AI systems for teams that need search across company data, workflow automation across tools, or AI features inside products and internal software.
Talk to Us
Search across company data
Give teams answers from docs, tickets, runbooks, and product data with sources and permissions.
Useful when people spend too long searching or get different answers from different systems.

Automate internal workflows
Use AI to route work, draft outputs, trigger actions, and keep approvals and logs in place.
Useful when repetitive work moves across multiple tools and teams.

Add AI to products and internal tools
Build assistants, guided actions, or decision support into the software your team or customers already use.
Useful when AI needs to be part of the product, not a separate tool.
Related Terms
Intermediate Representations are the foundational data structures enabling compiler transformations. These related concepts represent the specific analyses, optimizations, and transformations applied to an IR during the compilation pipeline for NPUs.
Graph Lowering
The process of progressively transforming a high-level, abstract computational graph into a lower-level, hardware-specific representation. This involves a series of legalization and conversion passes that make the graph executable on a target NPU.
- Purpose: Bridges the gap between framework-level operators (e.g., PyTorch
nn.Conv2d) and vendor-specific kernel libraries or assembly instructions. - Process: Each lowering pass replaces a set of operations with a more primitive equivalent, eventually reaching a level where operations map directly to hardware instructions.
- Example: A
tf.nn.bias_addnode might be lowered first to a genericaddoperation, then to a specific NPU vector addition intrinsic.
Static Single Assignment (SSA) Form
A property of an Intermediate Representation where each variable is assigned exactly once, and every variable is defined before it is used. This form drastically simplifies compiler dataflow analysis.
- Key Benefit: Enables powerful optimizations like constant propagation and dead code elimination by providing a clear, unambiguous definition-use chain for every value.
- Compiler Use: Many modern IRs (e.g., LLVM IR, MLIR's CFG dialect) use SSA form. It allows the compiler to easily track how values flow through the program.
- Example: Instead of
x = x + 1, SSA form creates a new variable:x2 = x1 + 1.
Graph Canonicalization
A compiler transformation that rewrites a computational graph into a standard, simplified, and canonical form. It eliminates syntactic variations that do not affect semantics, ensuring subsequent optimization passes are more predictable and effective.
- Goal: To reduce the number of equivalent graph patterns the compiler must recognize. For example, it ensures
Add(A, B)andAdd(B, A)are represented identically if addition is commutative. - Common Canonicalizations: Constant folding, identity operation removal (e.g.,
Mul(X, 1) -> X), and canonicalizing operation order. - Impact: Essential for pattern-matching-based optimizations like common subexpression elimination.
Control Flow Flattening
A compiler transformation that converts structured control flow constructs (like loops, conditionals, and nested blocks) into a simpler, flattened representation. This is often necessary for hardware that lacks native support for complex control flow primitives.
- Typical Output: A dataflow graph with explicit
switch/mergenodes or a goto-based block structure. - NPU Context: Many NPUs are optimized for executing straight-line code or simple loops. Flattening complex control flow allows the compiler to schedule operations more effectively for these architectures.
- Example: A
forloop may be flattened into a sequence of predicated operations or unrolled into a linear block of instructions.
Instruction Selection
The compiler backend phase responsible for mapping intermediate representation operations to specific sequences of machine instructions available on the target hardware. It is a pattern-matching problem that seeks the most efficient instruction sequence.
- Process: The compiler's IR (e.g., a
multiplyandaddnode) is matched against patterns defined for the target NPU's instruction set (e.g., a fusedmultiply-addormacinstruction). - Goal: To exploit specialized hardware features like fused operations, vector instructions, and special function units.
- Challenge: The search space can be large; compilers often use heuristic or cost-based algorithms to select the best instruction pattern.

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.
Partnered with leading AI, data, and software stack.
How We Work
Custom AI workflows for your Business
One-fit-all AI don't work for modern businesses. At Inferensys, we aim to understand your business & custom requirements; which we use to define most efficient agentic workflows, the data, and the tools for your business.
01
Review the use case
We understand the task, the users, and where AI can actually help.
Read more02
Pick the right approach
We define what needs search, automation, or product integration.
Read more03
Build the first useful version
We implement the part that proves the value first.
Read more04
Improve from there
We add the checks and visibility needed to keep it useful.
Read moreThe first call is a practical review of your use case and the right next step.
Talk to Us