diff options
| author | Shinichiro Hamaji <shinichiro.hamaji@gmail.com> | 2010-08-27 01:28:52 +0900 |
|---|---|---|
| committer | Shinichiro Hamaji <shinichiro.hamaji@gmail.com> | 2010-08-27 02:32:19 +0900 |
| commit | 1f6781f0eebcfed20faad10e0224d48ef884c3e5 (patch) | |
| tree | f7a4e70521651bfc85c19716f4bc40396ae7e46c | |
| parent | 4ab4efd3a69e0e10262b3010aa9162e73b1cddfb (diff) | |
| download | tinycc-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.c | 6 | ||||
| -rw-r--r-- | x86_64-gen.c | 24 |
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) { |
