aboutsummaryrefslogtreecommitdiff
path: root/x86_64-gen.c
diff options
context:
space:
mode:
authorgrischka <grischka>2017-07-09 12:07:40 +0200
committergrischka <grischka>2017-07-09 12:07:40 +0200
commit9f79b62ec4d84d07cf4a2fba969cb67c8f6ed8e5 (patch)
tree2ed2cab29b41d9b17c434d4a15565fb3e8387345 /x86_64-gen.c
parent6c468c10f70d74e962591a0584765e42ce1bcaf2 (diff)
downloadtinycc-9f79b62ec4d84d07cf4a2fba969cb67c8f6ed8e5.tar.gz
tinycc-9f79b62ec4d84d07cf4a2fba969cb67c8f6ed8e5.tar.bz2
unsorted adjustments
- configure * use aarch64 instead of arm64 - Makefile * rename the custom include file to "config-extra.mak" * Also avoid "rm -r /*" if $(tccdir) is empty - pp/Makefile * fix .expect generation with gcc - tcc.h * cleanup #defines for _MSC_VER - tccgen.c: * fix const-propagation for &,| * fix anonymous named struct (ms-extension) and enable -fms-extension by default - i386-gen.c * clear VT_DEFSIGN - x86_64-gen.c/win64: * fix passing structs in registers * fix alloca (need to keep "func_scratch" below each alloca area on stack) (This allows to compile a working gnu-make on win64) - tccpp.c * alternative approach to 37999a4fbf3487b363fd0c2f9b7ab622401b202a This is to avoid some slowdown with ## token pasting. * get_tok_str() : return <eof> for TOK_EOF * -funsigned-char: apply to "string" literals as well - tccpe/tools.c: -impdef: support both 32 and 64 bit dlls anyway
Diffstat (limited to 'x86_64-gen.c')
-rw-r--r--x86_64-gen.c35
1 files changed, 27 insertions, 8 deletions
diff --git a/x86_64-gen.c b/x86_64-gen.c
index 19d5dd7..1873a9d 100644
--- a/x86_64-gen.c
+++ b/x86_64-gen.c
@@ -728,13 +728,13 @@ static int arg_prepare_reg(int idx) {
return arg_regs[idx];
}
-static int func_scratch;
+static int func_scratch, func_alloca;
/* Generate function call. The function address is pushed first, then
all the parameters in call order. This functions pops all the
parameters and the function address. */
-void gen_offs_sp(int b, int r, int d)
+static void gen_offs_sp(int b, int r, int d)
{
orex(1,0,r & 0x100 ? 0 : r, b);
if (d == (char)d) {
@@ -746,6 +746,11 @@ void gen_offs_sp(int b, int r, int d)
}
}
+static int using_regs(int size)
+{
+ return !(size > 8 || (size & (size - 1)));
+}
+
/* Return the number of registers needed to return the struct, or 0 if
returning via struct pointer. */
ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
@@ -754,7 +759,7 @@ ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int
*ret_align = 1; // Never have to re-align return values for x86-64
*regsize = 8;
size = type_size(vt, &align);
- if (size > 8 || (size & (size - 1)))
+ if (!using_regs(size))
return 0;
if (size == 8)
ret->t = VT_LLONG;
@@ -774,7 +779,7 @@ static int is_sse_float(int t) {
return bt == VT_DOUBLE || bt == VT_FLOAT;
}
-int gfunc_arg_size(CType *type) {
+static int gfunc_arg_size(CType *type) {
int align;
if (type->t & (VT_ARRAY|VT_BITFIELD))
return 8;
@@ -801,7 +806,7 @@ void gfunc_call(int nb_args)
bt = (sv->type.t & VT_BTYPE);
size = gfunc_arg_size(&sv->type);
- if (size <= 8)
+ if (using_regs(size))
continue; /* arguments smaller than 8 bytes passed in registers or on stack */
if (bt == VT_STRUCT) {
@@ -835,7 +840,7 @@ void gfunc_call(int nb_args)
bt = (vtop->type.t & VT_BTYPE);
size = gfunc_arg_size(&vtop->type);
- if (size > 8) {
+ if (!using_regs(size)) {
/* align to stack align size */
size = (size + 15) & ~15;
if (arg >= REGN) {
@@ -895,6 +900,12 @@ void gfunc_call(int nb_args)
}
gcall_or_jmp(0);
+
+ if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
+ /* need to add the "func_scratch" area after alloca */
+ o(0x0548), gen_le32(func_alloca), func_alloca = ind - 4;
+ }
+
/* other compilers don't clear the upper bits when returning char/short */
bt = vtop->type.ref->type.t & (VT_BTYPE | VT_UNSIGNED);
if (bt == (VT_BYTE | VT_UNSIGNED))
@@ -926,6 +937,7 @@ void gfunc_prolog(CType *func_type)
func_ret_sub = 0;
func_scratch = 0;
+ func_alloca = 0;
loc = 0;
addr = PTR_SIZE * 2;
@@ -940,7 +952,7 @@ void gfunc_prolog(CType *func_type)
func_vt = sym->type;
func_var = (sym->c == FUNC_ELLIPSIS);
size = gfunc_arg_size(&func_vt);
- if (size > 8) {
+ if (!using_regs(size)) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
func_vc = addr;
reg_param_index++;
@@ -952,7 +964,7 @@ void gfunc_prolog(CType *func_type)
type = &sym->type;
bt = type->t & VT_BTYPE;
size = gfunc_arg_size(type);
- if (size > 8) {
+ if (!using_regs(size)) {
if (reg_param_index < REGN) {
gen_modrm64(0x89, arg_regs[reg_param_index], VT_LOCAL, NULL, addr);
}
@@ -1015,6 +1027,13 @@ void gfunc_epilog(void)
gen_le32(v);
}
+ /* add the "func_scratch" area after each alloca seen */
+ while (func_alloca) {
+ unsigned char *ptr = cur_text_section->data + func_alloca;
+ func_alloca = read32le(ptr);
+ write32le(ptr, func_scratch);
+ }
+
cur_text_section->data_offset = saved_ind;
pe_add_unwind_data(ind, saved_ind, v);
ind = cur_text_section->data_offset;