// Regression test for the -O0 byte-store-through-pointer miscompile // (W65816 STB_DPIndLongY atomic pseudo). // // The i8 store `*pcout = ...` through a ptr32 lowers to a [dp],Y store // wrapped in SEP #$20 / STA / REP #$20 (M=8 so only one byte is written). // The custom inserter used to emit those as THREE separate instructions, // so the -O0 fast register allocator (which spills everything and reloads // before each use) could wedge a 16-bit reload BETWEEN the SEP and REP — // running it in M=8, it loaded only the low byte of a 16-bit value. That // truncated `probe`'s `px + 1` pointer reload, so a value carried across // the call came back wrong (reported by an external SNES user: an // `unsigned char pid` packed via `<< 16` returned 0). // // Fix: emit ONE atomic STB_DPIndLongY pseudo, expanded to SEP/STA/REP at // the AsmPrinter, so nothing can be inserted inside the M=8 window. // // caller(34): probe writes pc = 34 & 7 = 2 through the pointer and returns // 34 + 1 = 35; caller returns 35 + 2 = 37 = 0x25. The buggy -O0 build // returned 3 (probe's return truncated to 1, + pc 2). MUST be compiled // at -O0 (the bug does not occur at -O1+). __attribute__((noinline)) static short probe(short px, unsigned char *pcout) { *pcout = (unsigned char)(px & 7); return (short)(px + 1); } __attribute__((noinline)) static short caller(short px) { unsigned char pc; short y = probe(px, &pc); // y (probe's return) is live across the call return (short)(y + pc); // + pc, the byte written through the pointer } int main(void) { *(volatile unsigned short *)0x025000 = (unsigned short)caller(34); // 0x0025 while (1) {} return 0; }