From 5af0ea7fb8d6b2b2a2d3833caad5eda4b43ef595 Mon Sep 17 00:00:00 2001 From: jiang <30155751@qq.com> Date: Wed, 30 Apr 2014 15:26:45 +0800 Subject: [PATCH] Fix va_arg bug, Fix type conversion bug, an increase of loc_stack () function is used to manage loc --- lib/libtcc1.c | 110 +++++++++++++------------- tcc.h | 1 + tccgen.c | 199 ++++++++++++++++++++++++++++++------------------ tests/tcctest.c | 23 ++++-- x86_64-gen.c | 57 ++++++++------ 5 files changed, 236 insertions(+), 154 deletions(-) diff --git a/lib/libtcc1.c b/lib/libtcc1.c index 284965e0..d7d895af 100644 --- a/lib/libtcc1.c +++ b/lib/libtcc1.c @@ -530,74 +530,77 @@ long double __floatundixf(unsigned long long a) unsigned long long __fixunssfdi (float a1) { - register union float_long fl1; - register int exp; - register unsigned long l; + register union float_long fl1; + register int exp; + register unsigned long l; + int s; + fl1.f = a1; - fl1.f = a1; + if (fl1.l == 0) + return 0; - if (fl1.l == 0) - return (0); + exp = EXP (fl1.l) - EXCESS - 24; - exp = EXP (fl1.l) - EXCESS - 24; - - l = MANT(fl1.l); - if (exp >= 41) - return (unsigned long long)-1; - else if (exp >= 0) - return (unsigned long long)l << exp; - else if (exp >= -23) - return l >> -exp; - else - return 0; + l = MANT(fl1.l); + s = SIGN(fl1.l)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return ((unsigned long long)l << exp)*s; + else if (exp >= -23) + return (l >> -exp)*s; + else + return 0; } unsigned long long __fixunsdfdi (double a1) { - register union double_long dl1; - register int exp; - register unsigned long long l; + register union double_long dl1; + register int exp; + register unsigned long long l; + int s; + dl1.d = a1; - dl1.d = a1; + if (dl1.ll == 0) + return (0); - if (dl1.ll == 0) - return (0); + exp = EXPD (dl1) - EXCESSD - 53; - exp = EXPD (dl1) - EXCESSD - 53; - - l = MANTD_LL(dl1); - - if (exp >= 12) - return (unsigned long long)-1; - else if (exp >= 0) - return l << exp; - else if (exp >= -52) - return l >> -exp; - else - return 0; + l = MANTD_LL(dl1); + s = SIGND(dl1)? -1: 1; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return (l << exp)*s; + else if (exp >= -52) + return (l >> -exp)*s; + else + return 0; } unsigned long long __fixunsxfdi (long double a1) { - register union ldouble_long dl1; - register int exp; - register unsigned long long l; + register union ldouble_long dl1; + register int exp; + register unsigned long long l; + int s; + dl1.ld = a1; - dl1.ld = a1; + if (dl1.l.lower == 0 && dl1.l.upper == 0) + return (0); - if (dl1.l.lower == 0 && dl1.l.upper == 0) - return (0); + exp = EXPLD (dl1) - EXCESSLD - 64; + s = SIGNLD(dl1)? -1: 1; + l = dl1.l.lower; - exp = EXPLD (dl1) - EXCESSLD - 64; - - l = dl1.l.lower; - - if (exp > 0) - return (unsigned long long)-1; - else if (exp >= -63) - return l >> -exp; - else - return 0; + if (exp >= 64) + return (unsigned long long)-1; + else if (exp >= 0) + return ((unsigned long long)l << exp)*s; + else if (exp >= -64) + return (l >> -exp)*s; + else + return 0; } long long __fixsfdi (float a1) @@ -637,7 +640,7 @@ extern void abort(void); #endif enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack + __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack }; //This should be in sync with the declaration on our include/stdarg.h @@ -688,10 +691,11 @@ void *__va_arg(__va_list_struct *ap, size = 8; goto use_overflow_area; + case __va_ld_reg: + ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align); case __va_stack: use_overflow_area: ap->overflow_arg_area += size; - ap->overflow_arg_area = (char*)((intptr_t)(ap->overflow_arg_area + align - 1) & -(intptr_t)align); return ap->overflow_arg_area - size; default: diff --git a/tcc.h b/tcc.h index 24b5b5aa..6a41137e 100644 --- a/tcc.h +++ b/tcc.h @@ -1194,6 +1194,7 @@ ST_DATA int func_var; /* true if current function is variadic */ ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; +ST_DATA int pop_stack; ST_INLN int is_float(int t); ST_FUNC int ieee_finite(double d); diff --git a/tccgen.c b/tccgen.c index f2e1de09..33240cfe 100644 --- a/tccgen.c +++ b/tccgen.c @@ -70,6 +70,7 @@ ST_DATA int func_var; /* true if current function is variadic (used by return in ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; +ST_DATA int pop_stack; ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; @@ -524,6 +525,41 @@ static void vdup(void) vpushv(vtop); } +static int align_size(int size) +{ +#ifdef TCC_TARGET_X86_64 + if(size > 4) + return 8; + else +#endif + if(size > 2) + return 4; + else if(size > 1) + return 2; + else + return 1; +} + +int loc_stack(int size, int is_sub){ + int l, align; + align = align_size(size); + size = (size + align - 1) & - align; + if(is_sub){ + pop_stack -= size; + if(pop_stack >= 0) + l = loc + pop_stack; + else{ + loc += pop_stack; + l = loc &= -align; + pop_stack = 0; + } + }else{ + pop_stack += size; + l = loc + pop_stack; + } + return l; +} + /* save r to the memory stack, and mark it as being free */ ST_FUNC void save_reg(int r) { @@ -924,13 +960,10 @@ ST_FUNC int gv(int rc) /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ ST_FUNC void gv2(int rc1, int rc2) { - int v; - /* generate more generic register first. But VT_JMP or VT_CMP values must be generated first in all cases to avoid possible reload errors */ - v = vtop[0].r & VT_VALMASK; - if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { + if (rc1 <= rc2) { vswap(); gv(rc1); vswap(); @@ -1018,6 +1051,7 @@ ST_FUNC void lexpand_nr(void) } #endif +#ifndef TCC_TARGET_X86_64 /* build a long long from two ints */ static void lbuild(int t) { @@ -1026,6 +1060,7 @@ static void lbuild(int t) vtop[-1].type.t = t; vpop(); } +#endif /* rotate n first stack elements to the bottom I1 ... In -> I2 ... In I1 [top is right] @@ -1087,8 +1122,8 @@ static void gv_dup(void) { int rc, t, r, r1; SValue sv; - t = vtop->type.t; +#ifndef TCC_TARGET_X86_64 if ((t & VT_BTYPE) == VT_LLONG) { lexpand(); gv_dup(); @@ -1098,15 +1133,14 @@ static void gv_dup(void) vrotb(4); /* stack: H L L1 H1 */ lbuild(t); - vrotb(3); - vrotb(3); + vrott(3); vswap(); lbuild(t); vswap(); - } else { + } else +#endif + { /* duplicate value */ - rc = RC_INT; - sv.type.t = VT_INT; if (is_float(t)) { rc = RC_FLOAT; #ifdef TCC_TARGET_X86_64 @@ -1114,8 +1148,9 @@ static void gv_dup(void) rc = RC_ST0; } #endif - sv.type.t = t; - } + }else + rc = RC_INT; + sv.type.t = t; r = gv(rc); r1 = get_reg(rc); sv.r = r; @@ -1127,7 +1162,6 @@ static void gv_dup(void) vtop->r = r1; } } - #ifndef TCC_TARGET_X86_64 /* generate CPU independent (unsigned) long long operations */ static void gen_opl(int op) @@ -2441,17 +2475,78 @@ static void gen_assign_cast(CType *dt) gen_cast(dt); } +static void vstore_im(){ + int rc, ft, sbt, dbt, t, r; + ft = vtop[-1].type.t; + sbt = vtop->type.t & VT_BTYPE; + dbt = ft & VT_BTYPE; + if (is_float(ft)) { + rc = RC_FLOAT; +#ifdef TCC_TARGET_X86_64 + if (dbt == VT_LDOUBLE) { + rc = RC_ST0; + } +#endif + }else + rc = RC_INT; + r = gv(rc); /* generate value */ + /* if lvalue was saved on stack, must read it */ + if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { + SValue sv; + t = get_reg(RC_INT); +#ifdef TCC_TARGET_X86_64 + sv.type.t = VT_PTR; +#else + sv.type.t = VT_INT; +#endif + sv.r = VT_LOCAL | VT_LVAL; + sv.c.ul = vtop[-1].c.ul; + load(t, &sv); + vtop[-1].r = t | VT_LVAL; + vtop[-1].c.ul = 0; + } + /* two word case handling : store second register at word + 4 */ +#ifdef TCC_TARGET_X86_64 + if ((dbt == VT_QLONG) || (dbt == VT_QFLOAT)) +#else + if (dbt == VT_LLONG) +#endif + { +#ifdef TCC_TARGET_X86_64 + int load_size = 8, load_type = (sbt == VT_QLONG) ? VT_LLONG : VT_DOUBLE; +#else + int load_size = 4, load_type = VT_INT; +#endif + vtop[-1].type.t = load_type; + store(r, vtop - 1); + vswap(); + /* convert to int to increment easily */ + vtop->type = char_pointer_type; + gaddrof(); + vpushi(load_size); + gen_op('+'); + vtop->r |= VT_LVAL; + vswap(); + vtop[-1].type.t = load_type; + /* XXX: it works because r2 is spilled last ! */ + store(vtop->r2, vtop - 1); + vtop->type.t = ft; + vtop[-1].type.t = ft; + } else { + store(r, vtop - 1); + } +} + /* store vtop in lvalue pushed on stack */ ST_FUNC void vstore(void) { - int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; + int sbt, dbt, ft, size, align, bit_size, bit_pos, delayed_cast; ft = vtop[-1].type.t; sbt = vtop->type.t & VT_BTYPE; dbt = ft & VT_BTYPE; if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || - (sbt == VT_INT && dbt == VT_SHORT)) - && !(vtop->type.t & VT_BITFIELD)) { + (sbt == VT_INT && dbt == VT_SHORT)) && !(vtop->type.t & VT_BITFIELD)) { /* optimize char/short casts */ delayed_cast = VT_MUSTCAST; vtop->type.t = ft & (VT_TYPE & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT))); @@ -2507,15 +2602,15 @@ ST_FUNC void vstore(void) vtop[-1].type.t = ft & ~(VT_BITFIELD | (-1 << VT_STRUCT_SHIFT)); /* duplicate source into other register */ - gv_dup(); - vswap(); - vrott(3); - if((ft & VT_BTYPE) == VT_BOOL) { gen_cast(&vtop[-1].type); vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); } + /* duplicate destination */ + vdup(); + vtop[-1] = vtop[-2]; + /* duplicate destination */ vdup(); vtop[-1] = vtop[-2]; @@ -2556,56 +2651,7 @@ ST_FUNC void vstore(void) } #endif if (!nocode_wanted) { - rc = RC_INT; - if (is_float(ft)) { - rc = RC_FLOAT; -#ifdef TCC_TARGET_X86_64 - if ((ft & VT_BTYPE) == VT_LDOUBLE) { - rc = RC_ST0; - } else if ((ft & VT_BTYPE) == VT_QFLOAT) { - rc = RC_FRET; - } -#endif - } - r = gv(rc); /* generate value */ - /* if lvalue was saved on stack, must read it */ - if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { - SValue sv; - t = get_reg(RC_INT); -#ifdef TCC_TARGET_X86_64 - sv.type.t = VT_PTR; -#else - sv.type.t = VT_INT; -#endif - sv.r = VT_LOCAL | VT_LVAL; - sv.c.ul = vtop[-1].c.ul; - load(t, &sv); - vtop[-1].r = t | VT_LVAL; - } - /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ -#ifdef TCC_TARGET_X86_64 - if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { - int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; -#else - if ((ft & VT_BTYPE) == VT_LLONG) { - int addr_type = VT_INT, load_size = 4, load_type = VT_INT; -#endif - vtop[-1].type.t = load_type; - store(r, vtop - 1); - vswap(); - /* convert to int to increment easily */ - vtop->type.t = addr_type; - gaddrof(); - vpushi(load_size); - gen_op('+'); - vtop->r |= VT_LVAL; - vswap(); - vtop[-1].type.t = load_type; - /* XXX: it works because r2 is spilled last ! */ - store(vtop->r2, vtop - 1); - } else { - store(r, vtop - 1); - } + vstore_im(); } vswap(); vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ @@ -4623,6 +4669,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, gsym_addr(b, d); } else if (tok == '{') { Sym *llabel; + int saved_loc, saved_pop_stack, size; int block_vla_sp_loc, *saved_vla_sp_loc, saved_vla_flags; next(); @@ -4632,7 +4679,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, frame_bottom->next = scope_stack_bottom; scope_stack_bottom = frame_bottom; llabel = local_label_stack; - + + saved_loc = loc; + saved_pop_stack = pop_stack; + /* save VLA state */ block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc); if (saved_vla_sp_loc != &vla_sp_root_loc) @@ -4684,7 +4734,12 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, /* pop locally defined symbols */ scope_stack_bottom = scope_stack_bottom->next; sym_pop(&local_stack, s); - + + size = -(loc - saved_loc); + pop_stack = saved_pop_stack; + if(size) + pop_stack += size; + /* Pop VLA frames and restore stack pointer if required */ if (saved_vla_sp_loc != &vla_sp_root_loc) *saved_vla_sp_loc = block_vla_sp_loc; diff --git a/tests/tcctest.c b/tests/tcctest.c index cc8ffd81..ca2ad0be 100644 --- a/tests/tcctest.c +++ b/tests/tcctest.c @@ -1680,7 +1680,6 @@ void prefix ## fcast(type a)\ printf("ftof: %f %f %Lf\n", fa, da, la);\ ia = (int)a;\ llia = (long long)a;\ - a = (a >= 0) ? a : -a;\ ua = (unsigned int)a;\ llua = (unsigned long long)a;\ printf("ftoi: %d %u %lld %llu\n", ia, ua, llia, llua);\ @@ -1710,6 +1709,18 @@ void prefix ## call(void)\ printf("strto%s: %f\n", #prefix, (double)strto ## prefix("1.2", NULL));\ }\ \ +void prefix ## calc(type x, type y)\ +{\ + x=x*x;y=y*y;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x-y;y=y-x;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x/y;y=y/x;\ + printf("%d, %d\n", (int)x, (int)y);\ + x=x+x;y=y+y;\ + printf("%d, %d\n", (int)x, (int)y);\ +}\ +\ void prefix ## signed_zeros(void) \ {\ type x = 0.0, y = -0.0, n, p;\ @@ -1732,7 +1743,7 @@ void prefix ## signed_zeros(void) \ 1.0 / x != 1.0 / p);\ else\ printf ("x != +y; this is wrong!\n");\ - p = -y;\ + p = -y;\ if (x == p)\ printf ("Test 1.0 / x != 1.0 / -y returns %d (should be 0).\n",\ 1.0 / x != 1.0 / p);\ @@ -1748,7 +1759,8 @@ void prefix ## test(void)\ prefix ## fcast(234.6);\ prefix ## fcast(-2334.6);\ prefix ## call();\ - prefix ## signed_zeros();\ + prefix ## calc(1, 1.0000000000000001);\ + prefix ## signed_zeros();\ } FTEST(f, float, float, "%f") @@ -2572,7 +2584,6 @@ int constant_p_var; void builtin_test(void) { -#if GCC_MAJOR >= 3 COMPAT_TYPE(int, int); COMPAT_TYPE(int, unsigned int); COMPAT_TYPE(int, char); @@ -2582,9 +2593,9 @@ void builtin_test(void) COMPAT_TYPE(int *, void *); COMPAT_TYPE(int *, const int *); COMPAT_TYPE(char *, unsigned char *); + COMPAT_TYPE(char, unsigned char); /* space is needed because tcc preprocessor introduces a space between each token */ - COMPAT_TYPE(char * *, void *); -#endif + COMPAT_TYPE(char **, void *); printf("res = %d\n", __builtin_constant_p(1)); printf("res = %d\n", __builtin_constant_p(1 + 2)); printf("res = %d\n", __builtin_constant_p(&constant_p_var)); diff --git a/x86_64-gen.c b/x86_64-gen.c index 72709bef..484da3f3 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -826,7 +826,7 @@ void gfunc_prolog(CType *func_type) func_ret_sub = 0; func_scratch = 0; - loc = 0; + pop_stack = loc = 0; addr = PTR_SIZE * 2; ind += FUNC_PROLOG_SIZE; @@ -968,12 +968,14 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) case VT_BYTE: case VT_SHORT: case VT_LLONG: + case VT_QLONG: case VT_BOOL: case VT_PTR: case VT_FUNC: case VT_ENUM: return x86_64_mode_integer; case VT_FLOAT: + case VT_QFLOAT: case VT_DOUBLE: return x86_64_mode_sse; case VT_LDOUBLE: return x86_64_mode_x87; @@ -984,7 +986,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) // Detect union if (f->next && (f->c == f->next->c)) return x86_64_mode_memory; - + mode = x86_64_mode_none; for (f = f->next; f; f = f->next) mode = classify_x86_64_merge(mode, classify_x86_64_inner(&f->type)); @@ -995,14 +997,14 @@ static X86_64_Mode classify_x86_64_inner(CType *ty) assert(0); } -static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count) +static int classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *palign, int *reg_count) { X86_64_Mode mode; int size, align, ret_t = 0; if (ty->t & (VT_BITFIELD|VT_ARRAY)) { *psize = 8; - *palign = 8; + *palign = 8; *reg_count = 1; ret_t = ty->t; mode = x86_64_mode_integer; @@ -1013,6 +1015,7 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p if (size > 16) { mode = x86_64_mode_memory; + ret_t = ty->t; } else { mode = classify_x86_64_inner(ty); switch (mode) { @@ -1021,16 +1024,22 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p *reg_count = 2; ret_t = VT_QLONG; } else { - *reg_count = 1; - ret_t = (size > 4) ? VT_LLONG : VT_INT; - } + *reg_count = 1; + if(size > 4) + ret_t = VT_LLONG; + else if(size > 2){ + ret_t = VT_INT; + }else if(size > 1) + ret_t = VT_SHORT; + else + ret_t = VT_BYTE; + } + ret_t |= (ty->t & VT_UNSIGNED); break; - case x86_64_mode_x87: *reg_count = 1; ret_t = VT_LDOUBLE; break; - case x86_64_mode_sse: if (size > 8) { *reg_count = 2; @@ -1040,13 +1049,15 @@ static X86_64_Mode classify_x86_64_arg(CType *ty, CType *ret, int *psize, int *p ret_t = (size > 4) ? VT_DOUBLE : VT_FLOAT; } break; - default: break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ + default: + ret_t = ty->t; + break; /* nothing to be done for x86_64_mode_memory and x86_64_mode_none*/ } } } if (ret) { - ret->ref = NULL; + ret->ref = ty->ref; ret->t = ret_t; } @@ -1057,12 +1068,13 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) { /* This definition must be synced with stdarg.h */ enum __va_arg_type { - __va_gen_reg, __va_float_reg, __va_stack - }; + __va_gen_reg, __va_float_reg, __va_ld_reg, __va_stack + }; int size, align, reg_count; X86_64_Mode mode = classify_x86_64_arg(ty, NULL, &size, &align, ®_count); switch (mode) { default: return __va_stack; + case x86_64_mode_x87: return __va_ld_reg; case x86_64_mode_integer: return __va_gen_reg; case x86_64_mode_sse: return __va_float_reg; } @@ -1387,7 +1399,7 @@ void gfunc_prolog(CType *func_type) sym = func_type->ref; addr = PTR_SIZE * 2; - loc = 0; + pop_stack = loc = 0; ind += FUNC_PROLOG_SIZE; func_sub_sp_offset = ind; func_ret_sub = 0; @@ -1398,7 +1410,6 @@ void gfunc_prolog(CType *func_type) /* frame pointer and return address */ seen_stack_size = PTR_SIZE * 2; /* count the number of seen parameters */ - sym = func_type->ref; while ((sym = sym->next) != NULL) { type = &sym->type; mode = classify_x86_64_arg(type, NULL, &size, &align, ®_count); @@ -1439,19 +1450,19 @@ void gfunc_prolog(CType *func_type) o(0xf845c7); gen_le32(seen_stack_size); + o(0xc084);/* test %al,%al */ + o(0x74);/* je */ + g(4*(8 - seen_sse_num) + 3); + /* save all register passing arguments */ for (i = 0; i < 8; i++) { loc -= 16; - o(0xd60f66); /* movq */ + o(0x290f);/* movaps %xmm1-7,-XXX(%rbp) */ gen_modrm(7 - i, VT_LOCAL, NULL, loc); - /* movq $0, loc+8(%rbp) */ - o(0x85c748); - gen_le32(loc + 8); - gen_le32(0); - } - for (i = 0; i < REGN; i++) { - push_arg_reg(REGN-1-i); } + for (i = 0; i < (REGN - seen_reg_num); i++) { + push_arg_reg(REGN-1 - i); + } } sym = func_type->ref;