aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShinichiro Hamaji <shinichiro.hamaji@gmail.com>2010-08-27 01:28:52 +0900
committerShinichiro Hamaji <shinichiro.hamaji@gmail.com>2010-08-27 02:32:19 +0900
commit1f6781f0eebcfed20faad10e0224d48ef884c3e5 (patch)
treef7a4e70521651bfc85c19716f4bc40396ae7e46c
parent4ab4efd3a69e0e10262b3010aa9162e73b1cddfb (diff)
downloadtinycc-1f6781f0eebcfed20faad10e0224d48ef884c3e5.tar.gz
tinycc-1f6781f0eebcfed20faad10e0224d48ef884c3e5.tar.bz2
Fix alignment around struct for SSE.
- Fix a wrong calculation for size of struct - Handle cases where struct size isn't multple of 8 - Recover vstack after memcpy for pushing struct - Add a float parameter for struct_assign_test1 to check SSE alignment
-rw-r--r--tests/tcctest.c6
-rw-r--r--x86_64-gen.c24
2 files changed, 21 insertions, 9 deletions
diff --git a/tests/tcctest.c b/tests/tcctest.c
index 536f5aa..7236971 100644
--- a/tests/tcctest.c
+++ b/tests/tcctest.c
@@ -1061,9 +1061,9 @@ struct structa1 {
struct structa1 ssta1;
-void struct_assign_test1(struct structa1 s1, int t)
+void struct_assign_test1(struct structa1 s1, int t, float f)
{
- printf("%d %d %d\n", s1.f1, s1.f2, t);
+ printf("%d %d %d %f\n", s1.f1, s1.f2, t, f);
}
struct structa1 struct_assign_test2(struct structa1 s1, int t)
@@ -1089,7 +1089,7 @@ void struct_assign_test(void)
lsta2.f1 = 1;
lsta2.f2 = 2;
#endif
- struct_assign_test1(lsta2, 3);
+ struct_assign_test1(lsta2, 3, 4.5);
printf("before call: %d %d\n", lsta2.f1, lsta2.f2);
lsta2 = struct_assign_test2(lsta2, 4);
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 10003d1..01213ad 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -820,7 +820,8 @@ void gfunc_call(int nb_args)
args_size = 0;
for(i = 0; i < nb_args; i++) {
if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) {
- args_size += type_size(&vtop->type, &align);
+ args_size += type_size(&vtop[-i].type, &align);
+ args_size = (args_size + 3) & ~3;
} else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) {
args_size += 16;
} else if (is_sse_float(vtop[-i].type.t)) {
@@ -840,9 +841,16 @@ void gfunc_call(int nb_args)
sse_reg = nb_sse_args;
/* adjust stack to align SSE boundary */
- if (args_size &= 8) {
- o(0x50); /* push $rax */
+ if (args_size &= 15) {
+ /* fetch cpu flag before the following sub will change the value */
+ if (vtop >= vstack && (vtop->r & VT_VALMASK) == VT_CMP)
+ gv(RC_INT);
+
+ args_size = 16 - args_size;
+ o(0x48);
+ oad(0xec81, args_size); /* sub $xxx, %rsp */
}
+
for(i = 0; i < nb_args; i++) {
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
size = type_size(&vtop->type, &align);
@@ -856,12 +864,16 @@ void gfunc_call(int nb_args)
orex(1, r, 0, 0x89); /* mov %rsp, r */
o(0xe0 + REG_VALUE(r));
{
- /* following code breaks vtop[1] */
- SValue tmp = vtop[1];
+ /* following code breaks vtop[1], vtop[2], and vtop[3] */
+ SValue tmp1 = vtop[1];
+ SValue tmp2 = vtop[2];
+ SValue tmp3 = vtop[3];
vset(&vtop->type, r | VT_LVAL, 0);
vswap();
vstore();
- vtop[1] = tmp;
+ vtop[1] = tmp1;
+ vtop[2] = tmp2;
+ vtop[3] = tmp3;
}
args_size += size;
} else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {