diff --git a/tests/tcctest.c b/tests/tcctest.c index 9f88c51..1b04c1f 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -88,6 +88,7 @@ void weak_test(void); void global_data_test(void); void cmp_comparison_test(void); void math_cmp_test(void); +void callsave_test(void); int fib(int n); void num(int n); @@ -596,6 +597,7 @@ int main(int argc, char **argv) global_data_test(); cmp_comparison_test(); math_cmp_test(); + callsave_test(); return 0; } @@ -2658,3 +2660,21 @@ void math_cmp_test(void) FCMP(nan, nan, >, !=, 4); FCMP(nan, nan, <=, !=, 5); } + +double get100 () { return 100.0; } + +void callsave_test(void) +{ + int i, s; double *d; double t; + s = sizeof (double); + printf ("callsavetest: %d\n", s); + d = alloca (sizeof(double)); + d[0] = 10.0; + /* x86-64 had a bug were the next call to get100 would evict + the lvalue &d[0] as VT_LLOCAL, and the reload would be done + in int type, not pointer type. When alloca returns a pointer + with the high 32 bit set (which is likely on x86-64) the access + generates a segfault. */ + i = d[0] > get100 (); + printf ("%d\n", i); +} diff --git a/x86_64-gen.c b/x86_64-gen.c index 6dfe1e4..1fa8dd5 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -1460,7 +1460,7 @@ void gen_opf(int op) if ((r & VT_VALMASK) == VT_LLOCAL) { SValue v1; r = get_reg(RC_INT); - v1.type.t = VT_INT; + v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; v1.c.ul = fc; load(r, &v1); @@ -1531,7 +1531,7 @@ void gen_opf(int op) if ((r & VT_VALMASK) == VT_LLOCAL) { SValue v1; r = get_reg(RC_INT); - v1.type.t = VT_INT; + v1.type.t = VT_PTR; v1.r = VT_LOCAL | VT_LVAL; v1.c.ul = fc; load(r, &v1);