History

fix-mixed-struct (patch by Pip Cet)

Jsut for testing. It works for me (don't break anything) Small fixes for x86_64-gen.c in "tccpp: fix issues, add tests" are dropped in flavor of this patch. Pip Cet: Okay, here's a first patch that fixes the problem (but I've found another bug, yet unfixed, in the process), though it's not particularly pretty code (I tried hard to keep the changes to the minimum necessary). If we decide to actually get rid of VT_QLONG and VT_QFLOAT (please, can we?), there are some further simplifications in tccgen.c that might offset some of the cost of this patch. The idea is that an integer is no longer enough to describe how an argument is stored in registers. There are a number of possibilities (none, integer register, two integer registers, float register, two float registers, integer register plus float register, float register plus integer register), and instead of enumerating them I've introduced a RegArgs type that stores the offsets for each of our registers (for the other architectures, it's simply an int specifying the number of registers). If someone strongly prefers an enum, we could do that instead, but I believe this is a place where keeping things general is worth it, because this way it should be doable to add SSE or AVX support. There is one line in the patch that looks suspicious: } else { addr = (addr + align - 1) & -align; param_addr = addr; addr += size; - sse_param_index += reg_count; } break; However, this actually fixes one half of a bug we have when calling a function with eight double arguments "interrupted" by a two-double structure after the seventh double argument: f(double,double,double,double,double,double,double,struct { double x,y; },double); In this case, the last argument should be passed in %xmm7. This patch fixes the problem in gfunc_prolog, but not the corresponding problem in gfunc_call, which I'll try tackling next.

seyko committed 11 years ago

Commit 4e04f671 parent 101cc878 files · +452 −228Browse files

Unified · Split

8 files
  1. arm-gen.c +16 −6
  2. arm64-gen.c +10 −1
  3. c67-gen.c +10 −1
  4. i386-gen.c +14 −5
  5. tcc.h +5 −3
  6. tccgen.c +81 −5
  7. tests/abitest.c +4 −4
  8. x86_64-gen.c +312 −203
arm-gen.c+16−6
@@ -34,6 +34,8 @@ · 33 unmodified lines
34#define NB_REGS 934#define NB_REGS 9
35#endif35#endif
36 36
37typedef int RegArgs;
38
37#ifndef TCC_ARM_VERSION39#ifndef TCC_ARM_VERSION
38# define TCC_ARM_VERSION 540# define TCC_ARM_VERSION 5
39#endif41#endif
@@ -867,9 +869,14 @@ int floats_in_core_regs(SValue *sval) · 827 unmodified lines
867 }869 }
868}870}
869 871
872ST_FUNC int regargs_nregs(RegArgs *args)
873{
874 return *args;
875}
876
870/* Return the number of registers needed to return the struct, or 0 if877/* Return the number of registers needed to return the struct, or 0 if
871 returning via struct pointer. */878 returning via struct pointer. */
872ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {879ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
873#ifdef TCC_ARM_EABI880#ifdef TCC_ARM_EABI
874 int size, align;881 int size, align;
875 size = type_size(vt, &align);882 size = type_size(vt, &align);
@@ -879,18 +886,20 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int · 3 unmodified lines
879 *regsize = 8;886 *regsize = 8;
880 ret->ref = NULL;887 ret->ref = NULL;
881 ret->t = VT_DOUBLE;888 ret->t = VT_DOUBLE;
882 return (size + 7) >> 3;889 *args = (size + 7) >> 3;
883 } else if (size <= 4) {890 } else if (size <= 4) {
884 *ret_align = 4;891 *ret_align = 4;
885 *regsize = 4;892 *regsize = 4;
886 ret->ref = NULL;893 ret->ref = NULL;
887 ret->t = VT_INT;894 ret->t = VT_INT;
888 return 1;895 *args = 1;
889 } else896 } else
890 return 0;897 *args = 0;
891#else898#else
892 return 0;899 *args = 0;
893#endif900#endif
901
902 return *args != 0;
894}903}
895 904
896/* Parameters are classified according to how they are copied to their final905/* Parameters are classified according to how they are copied to their final
@@ -1260,6 +1269,7 @@ void gfunc_prolog(CType *func_type) · 363 unmodified lines
1260 int n, nf, size, align, rs, struct_ret = 0;1269 int n, nf, size, align, rs, struct_ret = 0;
1261 int addr, pn, sn; /* pn=core, sn=stack */1270 int addr, pn, sn; /* pn=core, sn=stack */
1262 CType ret_type;1271 CType ret_type;
1272 RegArgs dummy;
1263 1273
1264#ifdef TCC_ARM_EABI1274#ifdef TCC_ARM_EABI
1265 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;1275 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
@@ -1271,7 +1281,7 @@ void gfunc_prolog(CType *func_type) · 5 unmodified lines
1271 1281
1272 n = nf = 0;1282 n = nf = 0;
1273 if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&1283 if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
1274 !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs))1284 !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs, &dummy))
1275 {1285 {
1276 n++;1286 n++;
1277 struct_ret = 1;1287 struct_ret = 1;
arm64-gen.c+10−1
@@ -14,6 +14,8 @@ · 13 unmodified lines
14// Number of registers available to allocator:14// Number of registers available to allocator:
15#define NB_REGS 28 // x0-x18, x30, v0-v715#define NB_REGS 28 // x0-x18, x30, v0-v7
16 16
17typedef int RegArgs;
18
17#define TREG_R(x) (x) // x = 0..1819#define TREG_R(x) (x) // x = 0..18
18#define TREG_R30 1920#define TREG_R30 19
19#define TREG_F(x) (x + 20) // x = 0..721#define TREG_F(x) (x + 20) // x = 0..7
@@ -1196,8 +1198,15 @@ ST_FUNC void gen_va_arg(CType *t) · 1176 unmodified lines
1196 }1198 }
1197}1199}
1198 1200
1199ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize)1201ST_FUNC int regargs_nregs(RegArgs *args)
1200{1202{
1203 return *args;
1204}
1205
1206ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize, RegArgs *args)
1207{
1208 *args = 0;
1209
1201 return 0;1210 return 0;
1202}1211}
1203 1212
c67-gen.c+10−1
@@ -25,6 +25,8 @@ · 24 unmodified lines
25/* number of available registers */25/* number of available registers */
26#define NB_REGS 2426#define NB_REGS 24
27 27
28typedef int RegArgs;
29
28/* a register can belong to several classes. The classes must be30/* a register can belong to several classes. The classes must be
29 sorted from more general to more precise (see gv2() code which does31 sorted from more general to more precise (see gv2() code which does
30 assumptions on it). */32 assumptions on it). */
@@ -1879,10 +1881,17 @@ static void gcall_or_jmp(int is_jmp) · 1848 unmodified lines
1879 }1881 }
1880}1882}
1881 1883
1884ST_FUNC int regargs_nregs(RegArgs *args)
1885{
1886 return *args;
1887}
1888
1882/* Return the number of registers needed to return the struct, or 0 if1889/* Return the number of registers needed to return the struct, or 0 if
1883 returning via struct pointer. */1890 returning via struct pointer. */
1884ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {1891ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
1885 *ret_align = 1; // Never have to re-align return values for x86-641892 *ret_align = 1; // Never have to re-align return values for x86-64
1893 *args = 0;
1894
1886 return 0;1895 return 0;
1887}1896}
1888 1897
i386-gen.c+14−5
@@ -24,6 +24,8 @@ · 23 unmodified lines
24#define NB_REGS 424#define NB_REGS 4
25#define NB_ASM_REGS 825#define NB_ASM_REGS 8
26 26
27typedef int RegArgs;
28
27/* a register can belong to several classes. The classes must be29/* a register can belong to several classes. The classes must be
28 sorted from more general to more precise (see gv2() code which does30 sorted from more general to more precise (see gv2() code which does
29 assumptions on it). */31 assumptions on it). */
@@ -374,9 +376,14 @@ static void gcall_or_jmp(int is_jmp) · 344 unmodified lines
374static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };376static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
375static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };377static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
376 378
379ST_FUNC int regargs_nregs(RegArgs *args)
380{
381 return *args;
382}
383
377/* Return the number of registers needed to return the struct, or 0 if384/* Return the number of registers needed to return the struct, or 0 if
378 returning via struct pointer. */385 returning via struct pointer. */
379ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)386ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
380{387{
381#ifdef TCC_TARGET_PE388#ifdef TCC_TARGET_PE
382 int size, align;389 int size, align;
@@ -385,20 +392,22 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int · 2 unmodified lines
385 *regsize = 4;392 *regsize = 4;
386 size = type_size(vt, &align);393 size = type_size(vt, &align);
387 if (size > 8) {394 if (size > 8) {
388 return 0;395 *args = 0;
389 } else if (size > 4) {396 } else if (size > 4) {
390 ret->ref = NULL;397 ret->ref = NULL;
391 ret->t = VT_LLONG;398 ret->t = VT_LLONG;
392 return 1;399 *args = 1;
393 } else {400 } else {
394 ret->ref = NULL;401 ret->ref = NULL;
395 ret->t = VT_INT;402 ret->t = VT_INT;
396 return 1;403 *args = 1;
397 }404 }
398#else405#else
399 *ret_align = 1; // Never have to re-align return values for x86406 *ret_align = 1; // Never have to re-align return values for x86
400 return 0;407 *args = 0;
401#endif408#endif
409
410 return *args != 0;
402}411}
403 412
404/* Generate function call. The function address is pushed first, then413/* Generate function call. The function address is pushed first, then
tcc.h+5−3
@@ -796,8 +796,8 @@ struct TCCState { · 795 unmodified lines
796#define VT_LLONG 12 /* 64 bit integer */796#define VT_LLONG 12 /* 64 bit integer */
797#define VT_LONG 13 /* long integer (NEVER USED as type, only797#define VT_LONG 13 /* long integer (NEVER USED as type, only
798 during parsing) */798 during parsing) */
799#define VT_QLONG 14 /* 128-bit integer. Only used for x86-64 ABI */799#define VT_QLONG 14 /* 128-bit integer. No longer used. */
800#define VT_QFLOAT 15 /* 128-bit float. Only used for x86-64 ABI */800#define VT_QFLOAT 15 /* 128-bit float. No longer used. */
801#define VT_UNSIGNED 0x0010 /* unsigned type */801#define VT_UNSIGNED 0x0010 /* unsigned type */
802#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */802#define VT_ARRAY 0x0020 /* array type (also has VT_PTR) */
803#define VT_BITFIELD 0x0040 /* bitfield modifier */803#define VT_BITFIELD 0x0040 /* bitfield modifier */
@@ -1267,6 +1267,7 @@ ST_FUNC void save_regs(int n); · 463 unmodified lines
1267ST_FUNC void gaddrof(void);1267ST_FUNC void gaddrof(void);
1268ST_FUNC int gv(int rc);1268ST_FUNC int gv(int rc);
1269ST_FUNC void gv2(int rc1, int rc2);1269ST_FUNC void gv2(int rc1, int rc2);
1270ST_FUNC void vdup(void);
1270ST_FUNC void vpop(void);1271ST_FUNC void vpop(void);
1271ST_FUNC void gen_op(int op);1272ST_FUNC void gen_op(int op);
1272ST_FUNC int type_size(CType *type, int *a);1273ST_FUNC int type_size(CType *type, int *a);
@@ -1355,7 +1356,8 @@ ST_FUNC void gsym_addr(int t, int a); · 82 unmodified lines
1355ST_FUNC void gsym(int t);1356ST_FUNC void gsym(int t);
1356ST_FUNC void load(int r, SValue *sv);1357ST_FUNC void load(int r, SValue *sv);
1357ST_FUNC void store(int r, SValue *v);1358ST_FUNC void store(int r, SValue *v);
1358ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);1359ST_FUNC int regargs_nregs(RegArgs *args);
1360ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize, RegArgs *args);
1359ST_FUNC void gfunc_call(int nb_args);1361ST_FUNC void gfunc_call(int nb_args);
1360ST_FUNC void gfunc_prolog(CType *func_type);1362ST_FUNC void gfunc_prolog(CType *func_type);
1361ST_FUNC void gfunc_epilog(void);1363ST_FUNC void gfunc_epilog(void);
tccgen.c+81−5
@@ -525,7 +525,7 @@ ST_FUNC void vpushv(SValue *v) · 524 unmodified lines
525 *vtop = *v;525 *vtop = *v;
526}526}
527 527
528static void vdup(void)528ST_FUNC void vdup(void)
529{529{
530 vpushv(vtop);530 vpushv(vtop);
531}531}
@@ -4200,6 +4200,7 @@ ST_FUNC void unary(void) · 3668 unmodified lines
4200 SValue ret;4200 SValue ret;
4201 Sym *sa;4201 Sym *sa;
4202 int nb_args, ret_nregs, ret_align, regsize, variadic;4202 int nb_args, ret_nregs, ret_align, regsize, variadic;
4203 RegArgs args;
4203 4204
4204 /* function call */4205 /* function call */
4205 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {4206 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -4224,8 +4225,10 @@ ST_FUNC void unary(void) · 18 unmodified lines
4224 /* compute first implicit argument if a structure is returned */4225 /* compute first implicit argument if a structure is returned */
4225 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {4226 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
4226 variadic = (s->c == FUNC_ELLIPSIS);4227 variadic = (s->c == FUNC_ELLIPSIS);
4227 ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,4228 gfunc_sret(&s->type, variadic, &ret.type,
4228 &ret_align, &regsize);4229 &ret_align, &regsize, &args);
4230 ret_nregs = regargs_nregs(&args);
4231
4229 if (!ret_nregs) {4232 if (!ret_nregs) {
4230 /* get some space for the returned structure */4233 /* get some space for the returned structure */
4231 size = type_size(&s->type, &align);4234 size = type_size(&s->type, &align);
@@ -4303,6 +4306,10 @@ ST_FUNC void unary(void) · 71 unmodified lines
4303 /* handle packed struct return */4306 /* handle packed struct return */
4304 if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {4307 if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
4305 int addr, offset;4308 int addr, offset;
4309#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4310 int i;
4311#endif
4312
4306 4313
4307 size = type_size(&s->type, &align);4314 size = type_size(&s->type, &align);
4308 /* We're writing whole regs often, make sure there's enough4315 /* We're writing whole regs often, make sure there's enough
@@ -4311,6 +4318,34 @@ ST_FUNC void unary(void) · 2 unmodified lines
4311 align = regsize;4318 align = regsize;
4312 loc = (loc - size) & -align;4319 loc = (loc - size) & -align;
4313 addr = loc;4320 addr = loc;
4321#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4322 for (i=0; i<REG_ARGS_MAX; i++) {
4323 offset = args.ireg[i];
4324
4325 if (offset == -1)
4326 break;
4327
4328 ret.type.t = VT_LLONG;
4329 vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
4330 vsetc(&ret.type, i ? REG_LRET : REG_IRET, &ret.c);
4331 vstore();
4332 vtop--;
4333 vtop--;
4334 }
4335 for (i=0; i<REG_ARGS_MAX; i++) {
4336 offset = args.freg[i];
4337
4338 if (offset == -1)
4339 break;
4340
4341 ret.type.t = VT_DOUBLE;
4342 vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
4343 vsetc(&ret.type, i ? REG_QRET : REG_FRET, &ret.c);
4344 vstore();
4345 vtop--;
4346 vtop--;
4347 }
4348#else
4314 offset = 0;4349 offset = 0;
4315 for (;;) {4350 for (;;) {
4316 vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);4351 vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
@@ -4321,6 +4356,7 @@ ST_FUNC void unary(void) · 4 unmodified lines
4321 break;4356 break;
4322 offset += regsize;4357 offset += regsize;
4323 }4358 }
4359#endif
4324 vset(&s->type, VT_LOCAL | VT_LVAL, addr);4360 vset(&s->type, VT_LOCAL | VT_LVAL, addr);
4325 }4361 }
4326 } else {4362 } else {
@@ -4891,8 +4927,11 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 564 unmodified lines
4891 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {4927 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
4892 CType type, ret_type;4928 CType type, ret_type;
4893 int ret_align, ret_nregs, regsize;4929 int ret_align, ret_nregs, regsize;
4894 ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,4930 RegArgs args;
4895 &ret_align, &regsize);4931
4932 gfunc_sret(&func_vt, func_var, &ret_type,
4933 &ret_align, &regsize, &args);
4934 ret_nregs = regargs_nregs(&args);
4896 if (0 == ret_nregs) {4935 if (0 == ret_nregs) {
4897 /* if returning structure, must copy it to implicit4936 /* if returning structure, must copy it to implicit
4898 first pointer arg location */4937 first pointer arg location */
@@ -4906,6 +4945,9 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
4906 } else {4945 } else {
4907 /* returning structure packed into registers */4946 /* returning structure packed into registers */
4908 int r, size, addr, align;4947 int r, size, addr, align;
4948#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4949 int i;
4950#endif
4909 size = type_size(&func_vt,&align);4951 size = type_size(&func_vt,&align);
4910 if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))4952 if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
4911 && (align & (ret_align-1))) {4953 && (align & (ret_align-1))) {
@@ -4919,6 +4961,39 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 7 unmodified lines
4919 vset(&ret_type, VT_LOCAL | VT_LVAL, addr);4961 vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
4920 }4962 }
4921 vtop->type = ret_type;4963 vtop->type = ret_type;
4964#if defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_PE)
4965 for (i=0; i<REG_ARGS_MAX; i++) {
4966 int off = args.ireg[i];
4967
4968 if (off == -1)
4969 break;
4970
4971 r = i ? RC_LRET : RC_IRET;
4972
4973 vdup();
4974 vtop->c.i += off;
4975 vtop->type.t = VT_LLONG;
4976 gv(r);
4977 vpop();
4978 }
4979 for (i=0; i<REG_ARGS_MAX; i++) {
4980 int off = args.freg[i];
4981
4982 if (off == -1)
4983 break;
4984
4985 /* We assume that when a structure is returned in multiple
4986 registers, their classes are consecutive values of the
4987 suite s(n) = 2^n */
4988 r = rc_fret(ret_type.t) << i;
4989
4990 vdup();
4991 vtop->c.i += off;
4992 vtop->type.t = VT_DOUBLE;
4993 gv(r);
4994 vpop();
4995 }
4996#else
4922 if (is_float(ret_type.t))4997 if (is_float(ret_type.t))
4923 r = rc_fret(ret_type.t);4998 r = rc_fret(ret_type.t);
4924 else4999 else
@@ -4935,6 +5010,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 10 unmodified lines
4935 vtop->c.i += regsize;5010 vtop->c.i += regsize;
4936 vtop->r = VT_LOCAL | VT_LVAL;5011 vtop->r = VT_LOCAL | VT_LVAL;
4937 }5012 }
5013#endif
4938 }5014 }
4939 } else if (is_float(func_vt.t)) {5015 } else if (is_float(func_vt.t)) {
4940 gv(rc_fret(func_vt.t));5016 gv(rc_fret(func_vt.t));
tests/abitest.c+4−4
@@ -637,10 +637,10 @@ int main(int argc, char **argv) { · 636 unmodified lines
637 RUN_TEST(ret_longdouble_test);637 RUN_TEST(ret_longdouble_test);
638 RUN_TEST(ret_2float_test);638 RUN_TEST(ret_2float_test);
639 RUN_TEST(ret_2double_test);639 RUN_TEST(ret_2double_test);
640 /* RUN_TEST(ret_8plus2double_test); currently broken on x86_64 */640 RUN_TEST(ret_8plus2double_test);
641 /* RUN_TEST(ret_6plus2longlong_test); currently broken on x86_64 */641 RUN_TEST(ret_6plus2longlong_test);
642 /* RUN_TEST(ret_mixed_test); currently broken on x86_64 */642 RUN_TEST(ret_mixed_test);
643 /* RUN_TEST(ret_mixed2_test); currently broken on x86_64 */643 RUN_TEST(ret_mixed2_test);
644 RUN_TEST(ret_mixed3_test);644 RUN_TEST(ret_mixed3_test);
645 RUN_TEST(reg_pack_test);645 RUN_TEST(reg_pack_test);
646 RUN_TEST(reg_pack_longlong_test);646 RUN_TEST(reg_pack_longlong_test);
x86_64-gen.c+312−203
@@ -25,6 +25,24 @@ · 24 unmodified lines
25/* number of available registers */25/* number of available registers */
26#define NB_REGS 2526#define NB_REGS 25
27#define NB_ASM_REGS 827#define NB_ASM_REGS 8
28#define REG_ARGS_MAX 2 /* at most 2 registers used for each argument */
29
30#ifdef TCC_TARGET_PE
31typedef int RegArgs;
32#else
33/* This struct stores the struct offsets at which %rax, %rdx, %xmm0, and
34 * %xmm1 are to be stored.
35 *
36 * struct { long long l; double x; }: ireg = { 0, -1 } freg = { 8, -1 }
37 * struct { double x; long long l; }: ireg = { 8, -1 } freg = { 0, -1 }
38 * struct { long long l; long long l2; }: ireg = { 0, 8 } freg = { -1, -1 }
39 * struct { double x; double x2; }: ireg = { -1, -1 } freg = { 0, 8 }
40 */
41typedef struct {
42 int ireg[REG_ARGS_MAX];
43 int freg[REG_ARGS_MAX];
44} RegArgs;
45#endif
28 46
29/* a register can belong to several classes. The classes must be47/* a register can belong to several classes. The classes must be
30 sorted from more general to more precise (see gv2() code which does48 sorted from more general to more precise (see gv2() code which does
@@ -745,9 +763,14 @@ void gen_offs_sp(int b, int r, int d) · 714 unmodified lines
745 }763 }
746}764}
747 765
766ST_FUNC int regargs_nregs(RegArgs *args)
767{
768 return *args;
769}
770
748/* Return the number of registers needed to return the struct, or 0 if771/* Return the number of registers needed to return the struct, or 0 if
749 returning via struct pointer. */772 returning via struct pointer. */
750ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)773ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
751{774{
752 int size, align;775 int size, align;
753 *regsize = 8;776 *regsize = 8;
@@ -755,20 +778,22 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int · 1 unmodified line
755 size = type_size(vt, &align);778 size = type_size(vt, &align);
756 ret->ref = NULL;779 ret->ref = NULL;
757 if (size > 8) {780 if (size > 8) {
758 return 0;781 *args = 0;
759 } else if (size > 4) {782 } else if (size > 4) {
760 ret->t = VT_LLONG;783 ret->t = VT_LLONG;
761 return 1;784 *args = 1;
762 } else if (size > 2) {785 } else if (size > 2) {
763 ret->t = VT_INT;786 ret->t = VT_INT;
764 return 1;787 *args = 1;
765 } else if (size > 1) {788 } else if (size > 1) {
766 ret->t = VT_SHORT;789 ret->t = VT_SHORT;
767 return 1;790 *args = 1;
768 } else {791 } else {
769 ret->t = VT_BYTE;792 ret->t = VT_BYTE;
770 return 1;793 *args = 1;
771 }794 }
795
796 return *args != 0;
772}797}
773 798
774static int is_sse_float(int t) {799static int is_sse_float(int t) {
@@ -1041,7 +1066,9 @@ static X86_64_Mode classify_x86_64_merge(X86_64_Mode a, X86_64_Mode b) · 266 unmodified lines
1041 return x86_64_mode_sse;1066 return x86_64_mode_sse;
1042}1067}
1043 1068
1044static X86_64_Mode classify_x86_64_inner(CType *ty)1069/* classify the x86 eightbytes from byte index start to byte index
1070 * end, at offset offset from the root struct */
1071static X86_64_Mode classify_x86_64_inner(CType *ty, int offset, int start, int end)
1045{1072{
1046 X86_64_Mode mode;1073 X86_64_Mode mode;
1047 Sym *f;1074 Sym *f;
@@ -1067,8 +1094,10 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) · 19 unmodified lines
1067 f = ty->ref;1094 f = ty->ref;
1068 1095
1069 mode = x86_64_mode_none;1096 mode = x86_64_mode_none;
1070 for (f = f->next; f; f = f->next)1097 while ((f = f->next) != NULL) {
1071 mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type));1098 if (f->c + offset >= start && f->c + offset < end)
1099 mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type, f->c + offset, start, end));
1100 }
1072 1101
1073 return mode;1102 return mode;
1074 }1103 }
@@ -1076,61 +1105,79 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) · 1 unmodified line
1076 assert(0);1105 assert(0);
1077}1106}
1078 1107
1079static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count)1108static X86_64_Mode classify_x86_64_arg_eightbyte(CType *ty, int offset)
1080{1109{
1081 X86_64_Mode mode;1110 X86_64_Mode mode;
1111
1112 assert((ty->t & VT_BTYPE) == VT_STRUCT);
1113
1114 mode = classify_x86_64_inner(ty, 0, offset, offset + 8);
1115
1116 return mode;
1117}
1118
1119static void regargs_init(RegArgs *args)
1120{
1121 int i;
1122 for(i=0; i<REG_ARGS_MAX; i++) {
1123 args->ireg[i] = -1;
1124 args->freg[i] = -1;
1125 }
1126}
1127
1128static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, RegArgs *args)
1129{
1130 X86_64_Mode mode = x86_64_mode_none;
1082 int size, align, ret_t = 0;1131 int size, align, ret_t = 0;
1083 1132 int ireg = 0, freg = 0;
1133
1134 if (args)
1135 regargs_init(args);
1136
1084 if (ty->t & (VT_BITFIELD|VT_ARRAY)) {1137 if (ty->t & (VT_BITFIELD|VT_ARRAY)) {
1085 *psize = 8;1138 *psize = 8;
1086 *palign = 8;1139 *palign = 8;
1087 *reg_count = 1;1140 if (args)
1141 args->ireg[ireg++] = 0;
1088 ret_t = ty->t;1142 ret_t = ty->t;
1089 mode = x86_64_mode_integer;1143 mode = x86_64_mode_integer;
1090 } else {1144 } else {
1091 size = type_size(ty, &align);1145 size = type_size(ty, &align);
1092 *psize = (size + 7) & ~7;1146 *psize = (size + 7) & ~7;
1093 *palign = (align + 7) & ~7;1147 *palign = (align + 7) & ~7;
1094 1148
1095 if (size > 16) {1149 if (size > 16) {
1096 mode = x86_64_mode_memory;1150 mode = x86_64_mode_memory;
1097 } else {1151 } else {
1098 mode = classify_x86_64_inner(ty);1152 int start;
1099 switch (mode) {1153
1100 case x86_64_mode_integer:1154 for(start=0; start < size; start += 8) {
1101 if (size > 8) {1155 if ((ty->t & VT_BTYPE) == VT_STRUCT) {
1102 *reg_count = 2;1156 mode = classify_x86_64_arg_eightbyte(ty, start);
1103 ret_t = VT_QLONG;
1104 } else {1157 } else {
1105 *reg_count = 1;1158 mode = classify_x86_64_inner(ty, 0, 0, size);
1106 ret_t = (size > 4) ? VT_LLONG : VT_INT;
1107 }1159 }
1108 break;
1109
1110 case x86_64_mode_x87:
1111 *reg_count = 1;
1112 ret_t = VT_LDOUBLE;
1113 break;
1114 1160
1115 case x86_64_mode_sse:1161 if (mode == x86_64_mode_integer) {
1116 if (size > 8) {1162 if (args)
1117 *reg_count = 2;1163 args->ireg[ireg++] = start;
1118 ret_t = VT_QFLOAT;1164 ret_t = (size > 4) ? VT_LLONG : VT_INT;
1119 } else {1165 } else if (mode == x86_64_mode_sse) {
1120 *reg_count = 1;1166 if (args)
1167 args->freg[freg++] = start;
1121 ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT;1168 ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT;
1169 } else {
1170 ret_t = VT_LDOUBLE;
1122 }1171 }
1123 break;
1124 default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/
1125 }1172 }
1126 }1173 }
1127 }1174 }
1128 1175
1129 if (ret) {1176 if (ret) {
1130 ret->ref = NULL;1177 ret->ref = NULL;
1131 ret->t = ret_t;1178 ret->t = ret_t;
1132 }1179 }
1133 1180
1134 return mode;1181 return mode;
1135}1182}
1136 1183
@@ -1140,8 +1187,8 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) · 3 unmodified lines
1140 enum __va_arg_type {1187 enum __va_arg_type {
1141 __va_gen_reg, __va_float_reg, __va_stack1188 __va_gen_reg, __va_float_reg, __va_stack
1142 };1189 };
1143 int size, align, reg_count;1190 int size, align;
1144 X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, &reg_count);1191 X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, NULL);
1145 switch (mode) {1192 switch (mode) {
1146 default: return __va_stack;1193 default: return __va_stack;
1147 case x86_64_mode_integer: return __va_gen_reg;1194 case x86_64_mode_integer: return __va_gen_reg;
@@ -1149,14 +1196,57 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) · 1 unmodified line
1149 }1196 }
1150}1197}
1151 1198
1152/* Return the number of registers needed to return the struct, or 0 if1199static int regargs_iregs(RegArgs *args)
1153 returning via struct pointer. */
1154ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
1155{1200{
1156 int size, align, reg_count;1201 int i;
1202 int ret = 0;
1203 for(i=0; i<REG_ARGS_MAX; i++) {
1204 if(args->ireg[i] != -1)
1205 ret++;
1206 }
1207
1208 return ret;
1209}
1210
1211static int regargs_fregs(RegArgs *args)
1212{
1213 int i;
1214 int ret = 0;
1215 for(i=0; i<REG_ARGS_MAX; i++) {
1216 if(args->freg[i] != -1)
1217 ret++;
1218 }
1219
1220 return ret;
1221}
1222
1223/* Count the total number of registers used by args */
1224ST_FUNC int regargs_nregs(RegArgs *args)
1225{
1226 int i;
1227 int ret = 0;
1228 for(i=0; i<REG_ARGS_MAX; i++) {
1229 if(args->ireg[i] != -1)
1230 ret++;
1231
1232 if(args->freg[i] != -1)
1233 ret++;
1234 }
1235
1236 return ret;
1237}
1238
1239ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
1240{
1241 int size, align;
1242 X86_64_Mode mode;
1157 *ret_align = 1; // Never have to re-align return values for x86-641243 *ret_align = 1; // Never have to re-align return values for x86-64
1158 *regsize = 8;1244 *regsize = 8;
1159 return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);1245
1246 mode = classify_x86_64_arg(vt, ret, &size, &align, args);
1247
1248 return mode != x86_64_mode_memory &&
1249 mode != x86_64_mode_none;
1160}1250}
1161 1251
1162#define REGN 61252#define REGN 6
@@ -1179,18 +1269,28 @@ void gfunc_call(int nb_args) · 16 unmodified lines
1179{1269{
1180 X86_64_Mode mode;1270 X86_64_Mode mode;
1181 CType type;1271 CType type;
1182 int size, align, r, args_size, stack_adjust, run_start, run_end, i, reg_count;1272 int size, align, r, args_size, stack_adjust, run_start, run_end, i;
1183 int nb_reg_args = 0;1273 int nb_reg_args = 0;
1184 int nb_sse_args = 0;1274 int nb_sse_args = 0;
1185 int sse_reg, gen_reg;1275 int sse_reg = 0, gen_reg = 0;
1276 RegArgs *reg_args = alloca(nb_args * sizeof *reg_args);
1186 1277
1187 /* calculate the number of integer/float register arguments */1278 /* calculate the number of integer/float register arguments */
1188 for(i = 0; i < nb_args; i++) {1279 for(i = nb_args - 1; i >= 0; i--) {
1189 mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);1280 int fregs, iregs;
1190 if (mode == x86_64_mode_sse)1281 mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_args[i]);
1191 nb_sse_args += reg_count;1282 fregs = regargs_fregs(&reg_args[i]);
1192 else if (mode == x86_64_mode_integer)1283 iregs = regargs_iregs(&reg_args[i]);
1193 nb_reg_args += reg_count;1284
1285 nb_sse_args += fregs;
1286 nb_reg_args += iregs;
1287
1288 if (sse_reg + fregs > 8 || gen_reg + iregs > REGN) {
1289 regargs_init(&reg_args[i]);
1290 } else {
1291 sse_reg += fregs;
1292 gen_reg += iregs;
1293 }
1194 }1294 }
1195 1295
1196 /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments1296 /* arguments are collected in runs. Each run is a collection of 8-byte aligned arguments
@@ -1209,27 +1309,14 @@ void gfunc_call(int nb_args) · 12 unmodified lines
1209 run_end = nb_args;1309 run_end = nb_args;
1210 stack_adjust = 0;1310 stack_adjust = 0;
1211 for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) {1311 for(i = run_start; (i < nb_args) && (run_end == nb_args); i++) {
1212 mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);1312 int stack = regargs_nregs(&reg_args[i]) == 0;
1213 switch (mode) {1313 classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, NULL);
1214 case x86_64_mode_memory:1314
1215 case x86_64_mode_x87:1315 if (stack) {
1216 stack_arg:
1217 if (align == 16)1316 if (align == 16)
1218 run_end = i;1317 run_end = i;
1219 else1318 else
1220 stack_adjust += size;1319 stack_adjust += size;
1221 break;
1222
1223 case x86_64_mode_sse:
1224 sse_reg -= reg_count;
1225 if (sse_reg + reg_count > 8) goto stack_arg;
1226 break;
1227
1228 case x86_64_mode_integer:
1229 gen_reg -= reg_count;
1230 if (gen_reg + reg_count > REGN) goto stack_arg;
1231 break;
1232 default: break; /* nothing to be done for x86_64_mode_none */
1233 }1320 }
1234 }1321 }
1235 1322
@@ -1249,44 +1336,38 @@ void gfunc_call(int nb_args) · 13 unmodified lines
1249 }1336 }
1250 1337
1251 for(i = run_start; i < run_end;) {1338 for(i = run_start; i < run_end;) {
1339 int arg_stored = regargs_nregs(&reg_args[i]) == 0;
1340 SValue tmp;
1341 RegArgs args;
1342
1343 if (!arg_stored) {
1344 ++i;
1345 continue;
1346 }
1347
1252 /* Swap argument to top, it will possibly be changed here,1348 /* Swap argument to top, it will possibly be changed here,
1253 and might use more temps. At the end of the loop we keep1349 and might use more temps. At the end of the loop we keep
1254 in on the stack and swap it back to its original position1350 in on the stack and swap it back to its original position
1255 if it is a register. */1351 if it is a register. */
1256 SValue tmp = vtop[0];1352 tmp = vtop[0];
1257 int arg_stored = 1;
1258
1259 vtop[0] = vtop[-i];1353 vtop[0] = vtop[-i];
1260 vtop[-i] = tmp;1354 vtop[-i] = tmp;
1261 mode = classify_x86_64_arg(&vtop->type, NULL, &size, &align, &reg_count);
1262 1355
1356 classify_x86_64_arg(&vtop->type, NULL, &size, &align, &args);
1357
1263 switch (vtop->type.t & VT_BTYPE) {1358 switch (vtop->type.t & VT_BTYPE) {
1264 case VT_STRUCT:1359 case VT_STRUCT:
1265 if (mode == x86_64_mode_sse) {1360 /* allocate the necessary size on stack */
1266 if (sse_reg > 8)1361 o(0x48);
1267 sse_reg -= reg_count;1362 oad(0xec81, size); /* sub $xxx, %rsp */
1268 else1363 /* generate structure store */
1269 arg_stored = 0;1364 r = get_reg(RC_INT);
1270 } else if (mode == x86_64_mode_integer) {1365 orex(1, r, 0, 0x89); /* mov %rsp, r */
1271 if (gen_reg > REGN)1366 o(0xe0 + REG_VALUE(r));
1272 gen_reg -= reg_count;1367 vset(&vtop->type, r | VT_LVAL, 0);
1273 else1368 vswap();
1274 arg_stored = 0;1369 vstore();
1275 }1370 args_size += size;
1276
1277 if (arg_stored) {
1278 /* allocate the necessary size on stack */
1279 o(0x48);
1280 oad(0xec81, size); /* sub $xxx, %rsp */
1281 /* generate structure store */
1282 r = get_reg(RC_INT);
1283 orex(1, r, 0, 0x89); /* mov %rsp, r */
1284 o(0xe0 + REG_VALUE(r));
1285 vset(&vtop->type, r | VT_LVAL, 0);
1286 vswap();
1287 vstore();
1288 args_size += size;
1289 }
1290 break;1371 break;
1291 1372
1292 case VT_LDOUBLE:1373 case VT_LDOUBLE:
@@ -1295,57 +1376,43 @@ void gfunc_call(int nb_args) · 2 unmodified lines
1295 1376
1296 case VT_FLOAT:1377 case VT_FLOAT:
1297 case VT_DOUBLE:1378 case VT_DOUBLE:
1298 assert(mode == x86_64_mode_sse);1379 r = gv(RC_FLOAT);
1299 if (sse_reg > 8) {1380 o(0x50); /* push $rax */
1300 --sse_reg;1381 /* movq %xmmN, (%rsp) */
1301 r = gv(RC_FLOAT);1382 o(0xd60f66);
1302 o(0x50); /* push $rax */1383 o(0x04 + REG_VALUE(r)*8);
1303 /* movq %xmmN, (%rsp) */1384 o(0x24);
1304 o(0xd60f66);1385 args_size += size;
1305 o(0x04 + REG_VALUE(r)*8);
1306 o(0x24);
1307 args_size += size;
1308 } else {
1309 arg_stored = 0;
1310 }
1311 break;1386 break;
1312 1387
1313 default:1388 default:
1314 assert(mode == x86_64_mode_integer);
1315 /* simple type */1389 /* simple type */
1316 /* XXX: implicit cast ? */1390 /* XXX: implicit cast ? */
1317 if (gen_reg > REGN) {1391 --gen_reg;
1318 --gen_reg;1392 r = gv(RC_INT);
1319 r = gv(RC_INT);1393 orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */
1320 orex(0,r,0,0x50 + REG_VALUE(r)); /* push r */1394 args_size += size;
1321 args_size += size;
1322 } else {
1323 arg_stored = 0;
1324 }
1325 break;1395 break;
1326 }1396 }
1327 1397
1328 /* And swap the argument back to it's original position. */1398 /* And swap the argument back to its original position. */
1329 tmp = vtop[0];1399 tmp = vtop[0];
1330 vtop[0] = vtop[-i];1400 vtop[0] = vtop[-i];
1331 vtop[-i] = tmp;1401 vtop[-i] = tmp;
1332 1402
1333 if (arg_stored) {1403 vrotb(i+1);
1334 vrotb(i+1);1404 assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));
1335 assert((vtop->type.t == tmp.type.t) && (vtop->r == tmp.r));1405 vpop();
1336 vpop();1406 memmove(reg_args + i, reg_args + i + 1, (nb_args - i - 1) * sizeof *reg_args);
1337 --nb_args;1407 --nb_args;
1338 --run_end;1408 --run_end;
1339 } else {
1340 ++i;
1341 }
1342 }1409 }
1343 1410
1344 /* handle 16 byte aligned arguments at end of run */1411 /* handle 16 byte aligned arguments at end of run */
1345 run_start = i = run_end;1412 run_start = i = run_end;
1346 while (i < nb_args) {1413 while (i < nb_args) {
1347 /* Rotate argument to top since it will always be popped */1414 /* Rotate argument to top since it will always be popped */
1348 mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, &reg_count);1415 mode = classify_x86_64_arg(&vtop[-i].type, NULL, &size, &align, NULL);
1349 if (align != 16)1416 if (align != 16)
1350 break;1417 break;
1351 1418
@@ -1375,13 +1442,24 @@ void gfunc_call(int nb_args) · 23 unmodified lines
1375 }1442 }
1376 1443
1377 vpop();1444 vpop();
1445 memmove(reg_args + i, reg_args + i + 1, (nb_args - i - 1) * sizeof *reg_args);
1378 --nb_args;1446 --nb_args;
1379 }1447 }
1380 }1448 }
1381 1449
1382 /* XXX This should be superfluous. */1450 /* XXX This should be superfluous. */
1383 save_regs(0); /* save used temporary registers */1451 save_regs(0); /* save used temporary registers */
1384 1452
1453 /* recalculate the number of register arguments there actually
1454 * are. This is slow but more obviously correct than using the
1455 * old counts. */
1456 gen_reg = 0;
1457 sse_reg = 0;
1458 for(i = 0; i < nb_args; i++) {
1459 gen_reg += regargs_iregs(&reg_args[i]);
1460 sse_reg += regargs_fregs(&reg_args[i]);
1461 }
1462
1385 /* then, we prepare register passing arguments.1463 /* then, we prepare register passing arguments.
1386 Note that we cannot set RDX and RCX in this loop because gv()1464 Note that we cannot set RDX and RCX in this loop because gv()
1387 may break these temporary registers. Let's use R10 and R111465 may break these temporary registers. Let's use R10 and R11
@@ -1389,40 +1467,62 @@ void gfunc_call(int nb_args) · 1 unmodified line
1389 assert(gen_reg <= REGN);1467 assert(gen_reg <= REGN);
1390 assert(sse_reg <= 8);1468 assert(sse_reg <= 8);
1391 for(i = 0; i < nb_args; i++) {1469 for(i = 0; i < nb_args; i++) {
1392 mode = classify_x86_64_arg(&vtop->type, &type, &size, &align, &reg_count);1470 RegArgs args;
1471
1472 args = reg_args[i];
1473
1393 /* Alter stack entry type so that gv() knows how to treat it */1474 /* Alter stack entry type so that gv() knows how to treat it */
1394 vtop->type = type;1475 if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
1395 if (mode == x86_64_mode_sse) {1476 int k;
1396 if (reg_count == 2) {1477
1397 sse_reg -= 2;1478 for(k=REG_ARGS_MAX-1; k>=0; k--) {
1398 gv(RC_FRET); /* Use pair load into xmm0 & xmm1 */1479 if (args.freg[k] == -1)
1399 if (sse_reg) { /* avoid redundant movaps %xmm0, %xmm0 */1480 continue;
1400 /* movaps %xmm0, %xmmN */1481
1401 o(0x280f);1482 sse_reg--;
1402 o(0xc0 + (sse_reg << 3));1483 assert(sse_reg >= 0);
1403 /* movaps %xmm1, %xmmN */1484
1404 o(0x280f);1485 vdup();
1405 o(0xc1 + ((sse_reg+1) << 3));1486 vtop->type.t = VT_DOUBLE;
1406 }1487 vtop->c.ull += args.freg[k];
1407 } else {1488 gv(RC_XMM0 << sse_reg);
1408 assert(reg_count == 1);1489 vpop();
1490 }
1491 for(k=REG_ARGS_MAX-1; k>=0; k--) {
1492 int d;
1493 if (args.ireg[k] == -1)
1494 continue;
1495
1496 gen_reg--;
1497
1498 vdup();
1499 vtop->type.t = VT_LLONG;
1500 vtop->c.ull += args.ireg[k];
1501 r = gv(RC_INT);
1502 d = arg_prepare_reg(gen_reg);
1503 orex(1,d,r,0x89); /* mov */
1504 o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
1505 vpop();
1506 }
1507 } else {
1508 /* XXX is it really necessary to set vtop->type? */
1509 classify_x86_64_arg(&vtop->type, &type, &size, &align, NULL);
1510 vtop->type = type;
1511 if (args.freg[0] != -1) {
1409 --sse_reg;1512 --sse_reg;
1410 /* Load directly to register */1513 /* Load directly to register */
1411 gv(RC_XMM0 << sse_reg);1514 gv(RC_XMM0 << sse_reg);
1412 }1515 } else if (args.ireg[0] != -1) {
1413 } else if (mode == x86_64_mode_integer) {1516 int d;
1414 /* simple type */1517 /* simple type */
1415 /* XXX: implicit cast ? */1518 /* XXX: implicit cast ? */
1416 int d;1519 gen_reg--;
1417 gen_reg -= reg_count;1520 r = gv(RC_INT);
1418 r = gv(RC_INT);1521 d = arg_prepare_reg(gen_reg);
1419 d = arg_prepare_reg(gen_reg);1522 orex(1,d,r,0x89); /* mov */
1420 orex(1,d,r,0x89); /* mov */1523 o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
1421 o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));1524 } else {
1422 if (reg_count == 2) {1525 assert(0);
1423 d = arg_prepare_reg(gen_reg+1);
1424 orex(1,d,vtop->r2,0x89); /* mov */
1425 o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));
1426 }1526 }
1427 }1527 }
1428 vtop--;1528 vtop--;
@@ -1463,7 +1563,7 @@ static void push_arg_reg(int i) { · 34 unmodified lines
1463void gfunc_prolog(CType *func_type)1563void gfunc_prolog(CType *func_type)
1464{1564{
1465 X86_64_Mode mode;1565 X86_64_Mode mode;
1466 int i, addr, align, size, reg_count;1566 int i, addr, align, size;
1467 int param_addr = 0, reg_param_index, sse_param_index;1567 int param_addr = 0, reg_param_index, sse_param_index;
1468 Sym *sym;1568 Sym *sym;
1469 CType *type;1569 CType *type;
@@ -1483,32 +1583,38 @@ void gfunc_prolog(CType *func_type) · 13 unmodified lines
1483 /* count the number of seen parameters */1583 /* count the number of seen parameters */
1484 sym = func_type->ref;1584 sym = func_type->ref;
1485 while ((sym = sym->next) != NULL) {1585 while ((sym = sym->next) != NULL) {
1586 RegArgs args;
1587
1486 type = &sym->type;1588 type = &sym->type;
1487 mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);1589 mode = classify_x86_64_arg(type, NULL, &size, &align, &args);
1590
1488 switch (mode) {1591 switch (mode) {
1489 default:1592 default:
1490 stack_arg:1593 stack_arg:
1491 seen_stack_size = ((seen_stack_size + align - 1) & -align) + size;1594 seen_stack_size = ((seen_stack_size + align - 1) & -align) + size;
1492 break;1595 break;
1493 1596
1494 case x86_64_mode_integer:1597 case x86_64_mode_integer:
1495 if (seen_reg_num + reg_count <= 8) {1598 case x86_64_mode_sse: {
1496 seen_reg_num += reg_count;1599 int stack = 0;
1497 } else {1600
1601 seen_sse_num += regargs_fregs(&args);
1602 seen_reg_num += regargs_iregs(&args);
1603
1604 if (seen_reg_num > 8) {
1498 seen_reg_num = 8;1605 seen_reg_num = 8;
1499 goto stack_arg;1606 stack = 1;
1500 }1607 }
1501 break;1608 if (seen_sse_num > 8) {
1502
1503 case x86_64_mode_sse:
1504 if (seen_sse_num + reg_count <= 8) {
1505 seen_sse_num += reg_count;
1506 } else {
1507 seen_sse_num = 8;1609 seen_sse_num = 8;
1508 goto stack_arg;1610 stack = 1;
1509 }1611 }
1612
1613 if (stack)
1614 goto stack_arg;
1510 break;1615 break;
1511 }1616 }
1617 }
1512 }1618 }
1513 1619
1514 loc -= 16;1620 loc -= 16;
@@ -1544,7 +1650,7 @@ void gfunc_prolog(CType *func_type) · 29 unmodified lines
1544 /* if the function returns a structure, then add an1650 /* if the function returns a structure, then add an
1545 implicit pointer parameter */1651 implicit pointer parameter */
1546 func_vt = sym->type;1652 func_vt = sym->type;
1547 mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, &reg_count);1653 mode = classify_x86_64_arg(&func_vt, NULL, &size, &align, NULL);
1548 if (mode == x86_64_mode_memory) {1654 if (mode == x86_64_mode_memory) {
1549 push_arg_reg(reg_param_index);1655 push_arg_reg(reg_param_index);
1550 func_vc = loc;1656 func_vc = loc;
@@ -1552,19 +1658,40 @@ void gfunc_prolog(CType *func_type) · 1 unmodified line
1552 }1658 }
1553 /* define parameters */1659 /* define parameters */
1554 while ((sym = sym->next) != NULL) {1660 while ((sym = sym->next) != NULL) {
1661 RegArgs args;
1662 int reg_count_integer = 0;
1663 int reg_count_sse = 0;
1664 int arg_stored = 1;
1665
1555 type = &sym->type;1666 type = &sym->type;
1556 mode = classify_x86_64_arg(type, NULL, &size, &align, &reg_count);1667 mode = classify_x86_64_arg(type, NULL, &size, &align, &args);
1668 reg_count_integer = regargs_iregs(&args);
1669 reg_count_sse = regargs_fregs(&args);
1670
1557 switch (mode) {1671 switch (mode) {
1672 case x86_64_mode_integer:
1558 case x86_64_mode_sse:1673 case x86_64_mode_sse:
1559 if (sse_param_index + reg_count <= 8) {1674 if (reg_count_integer || reg_count_sse) {
1675 if ((reg_count_sse == 0 || sse_param_index + reg_count_sse <= 8) &&
1676 (reg_count_integer == 0 || reg_param_index + reg_count_integer <= REGN)) {
1677 /* argument fits into registers */
1678 arg_stored = 0;
1679 }
1680 }
1681
1682 if (!arg_stored) {
1560 /* save arguments passed by register */1683 /* save arguments passed by register */
1561 loc -= reg_count * 8;1684 loc -= (reg_count_sse + reg_count_integer) * 8;
1562 param_addr = loc;1685 param_addr = loc;
1563 for (i = 0; i < reg_count; ++i) {1686 for (i = 0; i < reg_count_sse; ++i) {
1564 o(0xd60f66); /* movq */1687 o(0xd60f66); /* movq */
1565 gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + i*8);1688 gen_modrm(sse_param_index, VT_LOCAL, NULL, param_addr + args.freg[i]);
1566 ++sse_param_index;1689 ++sse_param_index;
1567 }1690 }
1691 for (i = 0; i < reg_count_integer; ++i) {
1692 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + args.ireg[i]);
1693 ++reg_param_index;
1694 }
1568 } else {1695 } else {
1569 addr = (addr + align - 1) & -align;1696 addr = (addr + align - 1) & -align;
1570 param_addr = addr;1697 param_addr = addr;
@@ -1578,23 +1705,6 @@ void gfunc_prolog(CType *func_type) · 7 unmodified lines
1578 param_addr = addr;1705 param_addr = addr;
1579 addr += size;1706 addr += size;
1580 break;1707 break;
1581
1582 case x86_64_mode_integer: {
1583 if (reg_param_index + reg_count <= REGN) {
1584 /* save arguments passed by register */
1585 loc -= reg_count * 8;
1586 param_addr = loc;
1587 for (i = 0; i < reg_count; ++i) {
1588 gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, param_addr + i*8);
1589 ++reg_param_index;
1590 }
1591 } else {
1592 addr = (addr + align - 1) & -align;
1593 param_addr = addr;
1594 addr += size;
1595 }
1596 break;
1597 }
1598 default: break; /* nothing to be done for x86_64_mode_none */1708 default: break; /* nothing to be done for x86_64_mode_none */
1599 }1709 }
1600 sym_push(sym->v & ~SYM_FIELD, type,1710 sym_push(sym->v & ~SYM_FIELD, type,
@@ -1631,7 +1741,7 @@ void gfunc_epilog(void) · 30 unmodified lines
1631 *bounds_ptr = 0;1741 *bounds_ptr = 0;
1632 1742
1633 /* generate bound local allocation */1743 /* generate bound local allocation */
1634 sym_data = get_sym_ref(&char_pointer_type, lbounds_section, 1744 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
1635 func_bound_offset, lbounds_section->data_offset);1745 func_bound_offset, lbounds_section->data_offset);
1636 saved_ind = ind;1746 saved_ind = ind;
1637 ind = func_bound_ind;1747 ind = func_bound_ind;
@@ -2233,8 +2343,7 @@ ST_FUNC void gen_vla_alloc(CType *type, int align) { · 595 unmodified lines
2233 gfunc_call(1);2343 gfunc_call(1);
2234 vset(type, REG_IRET, 0);2344 vset(type, REG_IRET, 0);
2235#else2345#else
2236 int r;2346 int r = gv(RC_INT); /* allocation size */
2237 r = gv(RC_INT); /* allocation size */
2238 /* sub r,%rsp */2347 /* sub r,%rsp */
2239 o(0x2b48);2348 o(0x2b48);
2240 o(0xe0 | REG_VALUE(r));2349 o(0xe0 | REG_VALUE(r));

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t