Sort Visualizer

Algorithms & Data

Bars reshuffle, then re-sort under libc qsort — with a function-pointer comparator that qsort calls back into for every comparison (ascending, evens-first, descending). Building this demo caught a real compiler crash: the ordinary comparator idiom (x>y)-(x<y) tripped an unhandled case in the backend. Runs automatically; no joypad needed. Written in C and compiled with the llvm-mos-based 65816 toolchain (+mos-a16, 16-bit accumulator mode).

loading core…

Self-running demo — bars reshuffle then re-sort under rotating comparators.

Click the screen to focus, then watch. Tab away and it pauses.

What it is

qsort is C's built-in sort. You hand it your array and a comparator — a little function it calls back for each pair it needs to order. Swap the comparator and the same data sorts a different way:

int cmp(const void *a, const void *b) {
    int16_t x = *(int16_t*)a, y = *(int16_t*)b;
    return (x > y) - (x < y);        // ← the spaceship idiom
}
qsort(bars, N, sizeof bars[0], cmp);  // qsort calls cmp back, per compare

That comparator is the whole point of the stress-test: a library calling back into your code through a pointer. And it found a bug — the compiler turned (x>y)-(x<y) into a single three-way-compare instruction the 65816 backend didn't know how to lower, crashing the build. A one-line fix in the backend legalizer resolved it; this demo is its regression test.

Compiler stress-test

ItemWhat it exercises
qsort callbackThe library sort receives a function pointer and calls it back for every comparison — an indirect call into our C, with two const void* arguments and an int return. A rotating pointer picks ascending, evens-first, or descending order.
the bug it foundThat innocuous comparator return (x>y)-(x<y) is canonicalised by the compiler to a single "three-way compare" opcode (G_SCMP). The MOS backend had no rule for it and aborted: "unable to legalize G_SCMP" — so ANY program sorting with the standard comparator idiom failed to build.
the fixOne line in the backend legalizer lowers G_SCMP/G_UCMP to the compare+select primitives it already handles. It reproduced on plain 8-bit C (no exotic mode), so it is a general fix queued upstream to llvm-mos.
bit-exactThe gate sorts a 64-element array three ways and folds the sorted VALUES — so even if two qsort implementations break ties between equal elements differently, the result is identical. host == default == +mos-a16 == +mos-xy16 == bsnes-jg.

Written in C with the llvm-mos 65816 toolchain and verified against bsnes-jg (and MAME where the SPC700 IPL is present). Hit Verify fidelity to reproduce the build gate's WRAM assert (gate hash 0x8EA5 — a fold of a 64-element array sorted three ways) live in this tab. No far pointers — the same source passes every way: host == default == +mos-a16 == +mos-xy16 == bsnes-jg, -verify clean.