summaryrefslogtreecommitdiff
path: root/x86_64-gen.c
diff options
context:
space:
mode:
authorThomas Preud'homme <robotux@celest.fr>2012-01-05 12:34:51 +0100
committerThomas Preud'homme <robotux@celest.fr>2012-01-05 12:34:51 +0100
commitd178eb7650ef7356ca4e6d9d64ac242dcff64811 (patch)
tree9f2084d9f6ace2c57691d8efd9ea2cc9bff8d197 /x86_64-gen.c
parentcfef8921f4b5dfa31fd2336484d86e24e3beb2f3 (diff)
Imported Upstream version 0.9.26~git20120104.83d57c0
Diffstat (limited to 'x86_64-gen.c')
-rw-r--r--x86_64-gen.c79
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