diff options
author | Thomas Preud'homme <robotux@celest.fr> | 2012-01-05 12:34:51 +0100 |
---|---|---|
committer | Thomas Preud'homme <robotux@celest.fr> | 2012-01-05 12:34:51 +0100 |
commit | d178eb7650ef7356ca4e6d9d64ac242dcff64811 (patch) | |
tree | 9f2084d9f6ace2c57691d8efd9ea2cc9bff8d197 /x86_64-gen.c | |
parent | cfef8921f4b5dfa31fd2336484d86e24e3beb2f3 (diff) |
Imported Upstream version 0.9.26~git20120104.83d57c0
Diffstat (limited to 'x86_64-gen.c')
-rw-r--r-- | x86_64-gen.c | 79 |
1 files changed, 42 insertions, 37 deletions
diff --git a/x86_64-gen.c b/x86_64-gen.c index 7c64f3b..4d2521d 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -592,22 +592,16 @@ void gen_offs_sp(int b, int r, int d) void gfunc_call(int nb_args) { - int size, align, r, args_size, i, d, j, bt; + int size, align, r, args_size, i, d, j, bt, struct_size; int nb_reg_args, gen_reg; - /* calculate the number of integer/float arguments */ - nb_reg_args = 0; - for(i = 0; i < nb_args; i++) { - bt = (vtop[-i].type.t & VT_BTYPE); - if (bt != VT_STRUCT && bt != VT_LDOUBLE) - nb_reg_args++; - } - + nb_reg_args = nb_args; args_size = (nb_reg_args < REGN ? REGN : nb_reg_args) * PTR_SIZE; /* for struct arguments, we need to call memcpy and the function call breaks register passing arguments we are preparing. So, we process arguments which will be passed by stack first. */ + struct_size = args_size; for(i = 0; i < nb_args; i++) { SValue *sv = &vtop[-i]; bt = (sv->type.t & VT_BTYPE); @@ -617,8 +611,8 @@ void gfunc_call(int nb_args) size = (size + 15) & ~15; /* generate structure store */ r = get_reg(RC_INT); - gen_offs_sp(0x8d, r, args_size); - args_size += size; + gen_offs_sp(0x8d, r, struct_size); + struct_size += size; /* generate memcpy call */ vset(&sv->type, r | VT_LVAL, 0); @@ -629,23 +623,43 @@ void gfunc_call(int nb_args) } else if (bt == VT_LDOUBLE) { gv(RC_ST0); - gen_offs_sp(0xdb, 0x107, args_size); - args_size += 16; + gen_offs_sp(0xdb, 0x107, struct_size); + struct_size += 16; } } - if (func_scratch < args_size) - func_scratch = args_size; - + if (func_scratch < struct_size) + func_scratch = struct_size; +#if 1 for (i = 0; i < REGN; ++i) save_reg(arg_regs[i]); - + save_reg(TREG_RAX); +#endif gen_reg = nb_reg_args; + struct_size = args_size; + for(i = 0; i < nb_args; i++) { bt = (vtop->type.t & VT_BTYPE); + if (bt == VT_STRUCT || bt == VT_LDOUBLE) { - ; /* done */ + if (bt == VT_LDOUBLE) + size = 16; + else + size = type_size(&vtop->type, &align); + /* align to stack align size */ + size = (size + 15) & ~15; + j = --gen_reg; + if (j >= REGN) { + d = TREG_RAX; + gen_offs_sp(0x8d, d, struct_size); + gen_offs_sp(0x89, d, j*8); + } else { + d = arg_regs[j]; + gen_offs_sp(0x8d, d, struct_size); + } + struct_size += size; + } else if (is_sse_float(vtop->type.t)) { gv(RC_FLOAT); /* only one float register */ j = --gen_reg; @@ -694,7 +708,7 @@ void gfunc_call(int nb_args) /* generate function prolog of type 't' */ void gfunc_prolog(CType *func_type) { - int addr, align, size, reg_param_index, bt; + int addr, reg_param_index, bt; Sym *sym; CType *type; @@ -722,13 +736,15 @@ void gfunc_prolog(CType *func_type) while ((sym = sym->next) != NULL) { type = &sym->type; bt = type->t & VT_BTYPE; - if (bt == VT_STRUCT || bt == VT_LDOUBLE) - continue; if (reg_param_index < REGN) { /* save arguments passed by register */ gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr); } - sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); + if (bt == VT_STRUCT || bt == VT_LDOUBLE) { + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL | VT_REF, addr); + } else { + sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); + } reg_param_index++; addr += PTR_SIZE; } @@ -739,18 +755,6 @@ void gfunc_prolog(CType *func_type) reg_param_index++; addr += PTR_SIZE; } - - sym = func_type->ref; - while ((sym = sym->next) != NULL) { - type = &sym->type; - bt = type->t & VT_BTYPE; - if (bt == VT_STRUCT || bt == VT_LDOUBLE) { - size = type_size(type, &align); - size = (size + 15) & -16; - sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); - addr += size; - } - } } /* generate function epilog */ @@ -772,8 +776,6 @@ void gfunc_epilog(void) /* align local size to word & save local variables */ v = (func_scratch + -loc + 15) & -16; - pe_add_unwind_data(ind, saved_ind, v); - if (v >= 4096) { Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); oad(0xb8, v); /* mov stacksize, %eax */ @@ -785,7 +787,10 @@ void gfunc_epilog(void) o(0xec8148); /* sub rsp, stacksize */ gen_le32(v); } - ind = saved_ind; + + cur_text_section->data_offset = saved_ind; + pe_add_unwind_data(ind, saved_ind, v); + ind = cur_text_section->data_offset; } #else |