aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2012-06-10 09:01:13 +0200
committerMichael Matz <matz@suse.de>2012-06-10 09:01:26 +0200
commita42b029101a758127de570b113767977fbce7b2a (patch)
treec42dba40767b40fcdb98e0361d46931f6c59c135
parent9a81dcab0ab1c992efa4a6d74eeb86812758de20 (diff)
downloadtinycc-a42b029101a758127de570b113767977fbce7b2a.tar.gz
tinycc-a42b029101a758127de570b113767977fbce7b2a.tar.bz2
x86-64: Fix call saved register restore
Loads of VT_LLOCAL values (which effectively represent saved addresses of lvalues) were done in VT_INT type, loosing the upper 32 bits. Needs to be done in VT_PTR type.
-rw-r--r--tests/tcctest.c20
-rw-r--r--x86_64-gen.c4
2 files changed, 22 insertions, 2 deletions
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);