docs/compiler/turboshaft/compiler-turboshaft-copying-approach.md
This document explains a core design philosophy of the Turboshaft compiler: using a copying approach for graph transformations instead of in-place mutation.
In traditional compilers, optimization passes often mutate the Intermediate Representation (IR) graph in-place. While this avoids copying overhead, it introduces significant complexity:
Turboshaft takes the opposite approach. It assumes that graph copies are cheap and that the graph changes so much between phases that a full copy is often more efficient and much simpler to implement.
Similar to a semi-space garbage collector, a typical Turboshaft phase operates on two graphs:
This approach is primarily implemented by CopyingPhase and GraphVisitor (see src/compiler/turboshaft/copying-phase.h).
A phase iterates linearly through the blocks and operations of the input graph. As it processes each operation, it uses the Reducer Stack to determine what should be emitted into the output graph. The output graph then becomes the input graph for the next phase (often achieved by swapping the graphs, see Graph::SwapWithCompanion in src/compiler/turboshaft/graph.h).
Turboshaft's IR was designed from the ground up to make this copying approach viable and fast:
Unlike Sea-of-Nodes (used in TurboFan), which uses a network of pointers between nodes scattered in memory, Turboshaft stores operations in a contiguous buffer called OperationBuffer (see src/compiler/turboshaft/graph.h).
Operations are compact. References to other operations are not pointers but small integer offsets (OpIndex). This keeps the memory footprint small, making full graph copies fit well within CPU caches.
Emitting an operation into the output graph is typically just an append operation to the end of the OperationBuffer, involving a few pointer increments and a store.
src/compiler/turboshaft/graph.h: Definition of Graph and OperationBuffer.src/compiler/turboshaft/copying-phase.h: Implementation of the copying phase driver.