{
    "slug": "register_allocation",
    "term": "Register Allocation",
    "category": "compiler",
    "difficulty": "advanced",
    "short": "A compiler back-end pass that maps an unbounded set of virtual registers (or IR variables) to a finite set of physical CPU registers.",
    "long": "Linear scan (Poletto & Sarkar, 1999) trades some code quality for compile speed by walking live ranges in order of start point and maintaining an active set — this is what most JITs use, including PHP 8's JIT (a linear-scan allocator feeding code emission through DynASM), V8's Crankshaft (historically), and LLVM's fast register allocator.",
    "aliases": [
        "regalloc",
        "graph colouring allocation",
        "linear scan allocation",
        "register assignment"
    ],
    "tags": [
        "compiler",
        "optimisation",
        "jit",
        "back-end",
        "code-generation"
    ],
    "misconception": "Register allocation just picks which CPU register to use for each variable — in reality it must also decide which values to spill to memory when registers run out, split live ranges, coalesce moves, and rematerialise cheap-to-recompute values, all under tight time budgets in a JIT.",
    "why_it_matters": "Poor allocation produces spill-heavy code that runs slowly even after every other optimisation has been applied. In JITs like PHP 8's, the choice between fast linear-scan and slow graph-colouring allocators directly trades compile time against steady-state throughput.",
    "common_mistakes": [
        "Assuming the compiler will always keep loop counters in registers — without enough free registers or with address-taken variables, they may spill to the stack.",
        "Confusing register allocation with register renaming — renaming is a CPU micro-architectural feature, allocation is a compile-time decision.",
        "Believing more registers always means faster code — beyond a working-set threshold, extra registers do not help because allocation already fits the live set.",
        "Writing huge functions with many local variables and expecting hot paths to stay in registers — large live sets force spills even with good allocators.",
        "Assuming hints like C's `register` keyword influence modern compilers — they are ignored; allocation is fully automatic and profile-driven."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "jit_compilation_deep",
        "php_jit",
        "opcode_optimisation",
        "bytecode_vm",
        "php_compilation_pipeline"
    ],
    "prerequisites": [
        "php_compilation_pipeline",
        "jit_compilation_deep",
        "bytecode_vm"
    ],
    "refs": [
        "https://en.wikipedia.org/wiki/Register_allocation",
        "https://www.cs.cmu.edu/~fp/courses/15411-f13/lectures/17-regalloc.pdf",
        "https://llvm.org/docs/CodeGenerator.html#register-allocation",
        "https://wiki.php.net/rfc/jit"
    ],
    "bad_code": "// Conceptual: function with huge live set defeats register allocator.\n// Each variable below is live for the entire function body,\n// forcing the allocator to spill most of them to the stack on x86_64.\nfunction hotLoop(array $data): float {\n    $a = 0.0; $b = 0.0; $c = 0.0; $d = 0.0;\n    $e = 0.0; $f = 0.0; $g = 0.0; $h = 0.0;\n    $i = 0.0; $j = 0.0; $k = 0.0; $l = 0.0;\n    $m = 0.0; $n = 0.0; $o = 0.0; $p = 0.0;\n    foreach ($data as $x) {\n        $a += $x; $b += $x*2; $c += $x*3; $d += $x*4;\n        $e += $x*5; $f += $x*6; $g += $x*7; $h += $x*8;\n        $i += $x*9; $j += $x*10; $k += $x*11; $l += $x*12;\n        $m += $x*13; $n += $x*14; $o += $x*15; $p += $x*16;\n    }\n    return $a+$b+$c+$d+$e+$f+$g+$h+$i+$j+$k+$l+$m+$n+$o+$p;\n}",
    "good_code": "// Split work so each loop has a small live set the JIT can keep in registers.\nfunction hotLoop(array $data): float {\n    return sumWeighted($data, 1, 8) + sumWeighted($data, 9, 16);\n}\n\nfunction sumWeighted(array $data, int $start, int $end): float {\n    $total = 0.0;             // only $total and $i are live across iterations\n    foreach ($data as $x) {\n        for ($i = $start; $i <= $end; $i++) {\n            $total += $x * $i; // fits comfortably in physical registers\n        }\n    }\n    return $total;\n}",
    "quick_fix": "Keep hot inner loops small and minimise live variables across calls so the JIT can fit the working set in physical registers — profile with perf to see spill traffic",
    "severity": "info",
    "effort": "high",
    "created": "2026-05-31",
    "updated": "2026-05-31",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/register_allocation",
        "html_url": "https://codeclaritylab.com/glossary/register_allocation",
        "json_url": "https://codeclaritylab.com/glossary/register_allocation.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Register Allocation](https://codeclaritylab.com/glossary/register_allocation) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/register_allocation"
            }
        }
    }
}