java-topology/defects/mesa/mesa-0001.md

2.2 KiB
Raw Permalink Blame History

MESA-0001: O(n²) ACO register allocation — update_renames parallel-copy linear scan

Severity: HIGH CWE: CWE-407 (Algorithmic Complexity — Insufficient Control of Quadratic Complexity) Target: Mesa3D File: src/amd/compiler/aco_register_allocation.cpp Line: 10131062 Status: PATCHED (unit test PASS)

Description

update_renames() resolves parallel-copy conflicts during AMD GCN/RDNA register allocation. It iterates over every pending copy with a while loop, and for each copy calls std::find_if back over the entire vector to locate a previously moved definition:

// aco_register_allocation.cpp:1013
auto it = parallelcopies.begin();
while (it != parallelcopies.end()) {          // O(N) iterations
    ...
    // line 1059 — inner O(N) scan
    auto other = std::find_if(parallelcopies.begin(), parallelcopies.end(),
        [&](parallelcopy& c) {
            return c.def.isTemp() && it->op.getTemp() == c.def.getTemp();
        });
    ...
}

For an instruction with N parallel copies the function is O(N²). This is hit during register spilling for instructions with high register pressure — function calls, image instructions with many descriptors, or large workgroup-reduce operations. A real-world compute shader doing a 64-wide reduction can generate 32+ parallel copies per instruction.

Root Cause

parallelcopies is a std::vector<parallelcopy>. The lookup seeks an entry whose def.getTemp() matches the current op.getTemp(). Since each temporary ID is unique, this is a map lookup disguised as a linear scan.

Fix

Build a std::unordered_map<uint32_t, size_t> (tempId → index) alongside parallelcopies before the while loop, updated incrementally as entries are erased/inserted. The std::find_if becomes an O(1) map lookup.

Patch: patch/mesa-0001.patch

Complexity

N parallel copies Before After
Worst-case O(N²) O(N)
N=32 (64-wide reduce) ~512 comparisons ~32 ops
N=64 (max wave width) ~2048 comparisons ~64 ops
Speedup at N=64 ~32×

Unit Test

unit/MesaParallelCopyAlgorithm.java

Run: javac unit/MesaParallelCopyAlgorithm.java && java -cp unit MesaParallelCopyAlgorithm