88 lines
2.3 KiB
C
88 lines
2.3 KiB
C
// Regression test: a longjmp must not hand a caller back IMG8..IMG15
|
|
// ($C0..$CE) words that a function it unwound overwrote.
|
|
//
|
|
// IMG8..IMG15 survive calls because every function that writes one gives
|
|
// its caller the old value back on return (W65816ImgCalleeSave, and the
|
|
// entry/return swaps of W65816StackRelToImg's IMG8..15 pointer homes). A
|
|
// longjmp skips those returns. walk() keeps q and r in $C2..$C8 and
|
|
// longjmps out of ext(); outer() keeps ITS q and r in the same words
|
|
// across the call to f0(). Before the fix outer() came back from f0()
|
|
// walking walk()'s r (bufF) instead of its own (bufE).
|
|
//
|
|
// Fix: a call that can return twice (setjmp) clobbers IMG8..IMG15
|
|
// (W65816TargetLowering::AdjustInstrPostInstrSelection), so f0() keeps
|
|
// nothing in them across setjmp and saves and restores all eight for
|
|
// outer().
|
|
//
|
|
// outer(bufB, bufC, bufE, 2) = 2 + bufC[1] (5) + bufE[2] (9) = 16; the
|
|
// broken build gave 9, 5, 8.
|
|
|
|
#include <setjmp.h>
|
|
|
|
static jmp_buf gJb;
|
|
volatile int gSink;
|
|
|
|
int bufA[4] = {5, 0, 0, 0};
|
|
int bufB[4] = {0, 1, 2, 3};
|
|
int bufC[4] = {0, 4, 5, 6};
|
|
int bufD[4] = {9, 9, 9, 9};
|
|
int bufE[4] = {0, 0, 8, 0};
|
|
int bufF[4] = {0, 0, 0, 0};
|
|
|
|
__attribute__((noinline)) void ext(int v) {
|
|
gSink = v;
|
|
if (v == 7) {
|
|
longjmp(gJb, 1);
|
|
}
|
|
}
|
|
|
|
|
|
// q and r live across the calls to ext in IMG8..15 homes.
|
|
__attribute__((noinline)) void walk(int *p, int *q, int *r, int n) {
|
|
int i = 0;
|
|
|
|
do {
|
|
ext(p[0]);
|
|
q[1] += i;
|
|
r[2] ^= q[1];
|
|
p[2] = r[2];
|
|
p[0]++;
|
|
} while (++i != n);
|
|
}
|
|
|
|
|
|
__attribute__((noinline)) int f0(int *p, int *q, int *r) {
|
|
if (setjmp(gJb)) {
|
|
return 1;
|
|
}
|
|
walk(p, q, r, 3);
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Its own q and r in the same IMG8..15 words across the call to f0.
|
|
__attribute__((noinline)) int outer(int *p, int *q, int *r, int n) {
|
|
int i = 0;
|
|
int t = 0;
|
|
|
|
do {
|
|
t += f0(bufA, bufD, bufF);
|
|
q[1] += i;
|
|
r[2] ^= q[1];
|
|
p[3] = r[2];
|
|
} while (++i != n);
|
|
return t + q[1] + r[2];
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
volatile int *out = (volatile int *)0x025000;
|
|
|
|
out[1] = outer(bufB, bufC, bufE, 2); // 0x0010
|
|
out[2] = bufC[1]; // 0x0005
|
|
out[3] = bufE[2]; // 0x0009
|
|
out[0] = 0xC0DE;
|
|
while (1) {
|
|
}
|
|
return 0;
|
|
}
|