Open-Source Wikis

/

Kotlin

/

Compiler

/

Backend IR

JetBrains/kotlin

Backend IR

Active contributors: Ivan Kylchik, Sergej Jaskiewicz, Wojciech Litewka

compiler/ir/ holds the backend Intermediate Representation: the platform-agnostic tree that every code-generation backend (JVM, JS, Wasm, Native) lowers and emits. Both frontends produce IR — K1 via compiler/ir/ir.psi2ir/ and K2 via compiler/fir/fir2ir/ — so once a program is in IR, the front-end split is no longer visible.

Purpose

Provide a single representation for the compiler's middle and back ends. IR is rich enough to express every Kotlin construct, target-friendly enough to lower into JVM bytecode / JavaScript / Wasm / LLVM IR, and serializable so that multi-module Kotlin projects (Multiplatform, Native, JS, Wasm) can ship klibs.

Directory layout

compiler/ir/
├── ir.tree/                Tree types: IrFile, IrClass, IrFunction, IrCall, ...
├── ir.psi2ir/              K1 (PSI + descriptors) → IR
├── ir.actualization/       expect/actual matching for IR
├── ir.inline/              Inline-function expansion
├── ir.interpreter/         Compile-time evaluation (intrinsics, const eval)
├── ir.objcinterop/         Kotlin/Native Objective-C interop helpers
├── ir.validation/          IR consistency checks (verifier)
├── backend.common/         Shared lowering passes
├── backend.jvm/            JVM-specific lowerings + codegen
├── backend.js/             JS-specific lowerings (output via js/js.ast)
├── backend.wasm/           Wasm-specific lowerings (output via wasm/wasm.ir)
├── backend.native/         Common Native-side IR helpers
├── serialization.common/   Klib IR serialization (target-agnostic)
├── serialization.js/       JS-specific klib serialization
├── serialization.jvm/      JVM-specific klib serialization
├── serialization.native/   Native klib serialization
└── serialization.jklib/    "JKLib" experimental klib variant

Key abstractions

Type Where Role
IrElement compiler/ir/ir.tree/.../IrElement.kt Root of the IR class hierarchy.
IrFile compiler/ir/ir.tree/.../IrFile.kt An IR translation of a single source file.
IrClass, IrFunction, IrProperty, IrField compiler/ir/ir.tree/... Declaration nodes.
IrCall, IrConstructorCall, IrGetField, IrSetField compiler/ir/ir.tree/... Expression nodes.
IrType compiler/ir/ir.tree/.../IrType.kt The IR-level type.
IrSymbol compiler/ir/ir.tree/.../symbols A reference to a declaration; backed by descriptor (K1) or FIR symbol (K2).
IrVisitor, IrTransformer compiler/ir/ir.tree/.../IrVisitor.kt The standard visitor/transform pattern over IR.
IrLowering compiler/ir/backend.common/... Common interface for a lowering pass.
JvmIrIntrinsicGenerator, JsIntrinsics, WasmIntrinsics, ... per backend Backend-specific built-ins / intrinsics tables.

The IR tree definitions are partially generated — see compiler/ir/ir.tree/tree-generator/. Fields, types, and visitor methods are derived from a structured definition.

How lowering works

A lowering is a pass that takes IR in, emits IR out, and rewrites some construct into a target-friendlier form. Examples:

  • Suspend functions → state machines.
  • Inline functions → inlined call sites.
  • Local classes → top-level classes with captured state.
  • when expressions → cascades of if/else (or tableswitch on the JVM).
  • Default arguments → wrapper methods.

Most lowerings live in compiler/ir/backend.common/ and apply to every target. Each backend then layers its own platform-specific lowerings (e.g., compiler/ir/backend.jvm/lower/ for the JVM).

graph LR
    Front["FIR / Descriptors"] --> Build["psi2ir / fir2ir"]
    Build --> IR["IR tree"]
    IR --> CommonLower["backend.common lowerings"]
    CommonLower --> JvmLower["backend.jvm lowerings"]
    CommonLower --> JsLower["backend.js lowerings"]
    CommonLower --> WasmLower["backend.wasm lowerings"]
    CommonLower --> NativeLower["backend.native lowerings"]
    JvmLower --> JvmEmit["ASM bytecode"]
    JsLower --> JsEmit["js.ast → .js"]
    WasmLower --> WasmEmit["wasm.ir → .wasm"]
    NativeLower --> NativeEmit["LLVM IR → binary"]

klibs (Kotlin libraries)

Multiplatform / Native / JS / Wasm code is shipped as klibs — a portable archive of serialized IR plus metadata. The serialization format is shared (compiler/ir/serialization.common/) with target-specific extensions (serialization.js, serialization.native, serialization.jklib).

A klib lets the compiler resolve a multiplatform module without re-running the frontend on the source. It also serves as the unit of incremental linking on Native and JS.

IR validation

compiler/ir/ir.validation/ provides a verifier that checks invariants like "every IrSymbol resolves", "every IrType is well-formed", "no orphan owners". Many tests run the verifier after each lowering to catch lowering bugs early.

Inline-function machinery

compiler/ir/ir.inline/ houses the inline-function expander. Inlining is global to all backends and runs before backend-specific lowerings. Capturing inline lambdas, default value handling, and reified type parameters all live here.

Compile-time evaluation

compiler/ir/ir.interpreter/ provides limited compile-time evaluation — used for const val initialization, default argument evaluation in some cases, and intrinsics. Each backend can opt into using it for additional folding.

Integration points

  • Producers: compiler/ir/ir.psi2ir/ and compiler/fir/fir2ir/.
  • Consumers: every backend (backend.jvm, backend.js, backend.wasm, backend.native).
  • klibs: written by serialization.*, read back by the deserialization paths in the frontend (e.g., compiler/fir/fir-deserialization/).

Where to start

When adding a new lowering, find the closest existing one in compiler/ir/backend.common/ (cross-target) or in the relevant backend's lower/ subdirectory. Most lowerings are pattern-matching IrTransformers.

When debugging IR shape, run a irText test (the corresponding .ir.txt files are checked into testData/) — they show the IR before/after a chosen phase.

See per-backend pages:

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Backend IR – Kotlin wiki | Factory