m03 · Burst · reading · 8 min
Burst — a second compiler for a smaller language
Two compilers, one language
The C# you write for DOTS is compiled twice. The normal path — Mono or IL2CPP — turns it into general-purpose managed code: garbage-collected, able to touch any object, safe against a huge range of programs. That generality has a price the first module already named: pointer-chasing, allocation, indirection. The second path is Burst, and it exists to pay a different bargain entirely.
Burst takes the same C# — the same methods, the same loops — and
compiles them through LLVM, the optimizing backend behind Clang and
much of modern native tooling. The output isn’t managed code that a
runtime interprets; it’s native machine code, vectorized and scheduled
about as aggressively as a C++ compiler would manage. A Burst-compiled
OnUpdate is, at the instruction level, closer to hand-tuned C than to
anything you’d normally associate with C#.
The key thing to hold onto: you don’t rewrite anything to get this.
The system you wrote in the last module, the tight loop over contiguous
components — mark it [BurstCompile] and it runs as native SIMD code.
Leave the mark off and the identical source runs as ordinary managed
code, several times slower. Same characters in the file; the compiler
you route them through is the entire difference.
Why Burst can’t compile all of C#
Here’s the constraint that shapes everything about writing Burst code, and it follows directly from what an optimizer needs. LLVM produces fast code by reasoning about your program — proving that two pointers don’t overlap, that a value doesn’t change between two reads, that a loop has no hidden side effects, so it can reorder, vectorize, and cache aggressively. That reasoning is only sound if the program stays inside a world the optimizer can fully model.
Managed C# is not that world. A managed object reference can point
anywhere on the GC heap; the garbage collector can move objects out
from under native code; a virtual call can dispatch to arbitrary code
the optimizer has never seen; an exception can unwind through anything.
Every one of those is a fact the optimizer cannot pin down, and each
one blocks the reasoning that makes native code fast. So Burst doesn’t
try. It compiles a subset of C#: code that is blittable (data laid
out identically in managed and native memory, no hidden representation),
holds no managed references (no class instances, no string, no
managed arrays — only struct data and native containers), and avoids
the constructs (GC, virtual dispatch, exceptions-as-control-flow) that
would defeat the optimizer.
That subset isn’t a limitation Unity imposed for taste. It’s the exact
set of programs LLVM can compile to the kind of code the
The layout and the compiler are the same bet
Notice how cleanly this stacks on what you’ve already built. The
archetype/
What this buys you
You now know what Burst is — a second, optimizing compiler for a deliberately smaller language — and why its restrictions are the shape of what LLVM can make fast rather than a set of rules to memorize. The next lesson opens up the single most important thing that compiler does with your loops: vectorization, turning one-element-at-a-time arithmetic into instructions that process four or eight lanes at once, and why the contiguous layout is what makes it legal.