37 lines
1.7 KiB
C
37 lines
1.7 KiB
C
// 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;
|
|
}
|