Fix x86-64 vla

For example, it should look like this
High stack
-------------
----- Func_ret_sub
------------
---- Vla stack
-------------
---- Known loc
--------------
Low

Increased loc_stack () function is used for temporary stack management, call save_reg (), released by load ()
Like this
Before use
High
----- Known loc
----
---
----
---- Pop_stack
Low
loc_stack (size, 1)
After use
High
----- Known loc
---- Pop_stack
---
----
----
Low
master
jiang 2014-05-02 23:45:48 +08:00
parent 6c8207633f
commit e647c3137d
3 changed files with 322 additions and 191 deletions

4
tcc.h
View File

@ -761,7 +761,7 @@ struct TCCState {
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED) #define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the #define VT_BOUNDED 0x8000 /* value is bounded. The address of the
bounding function call point is in vc */ bounding function call point is in vc */
#define VT_TMP 0x10000 #define VT_TMP 0x10000 /* luck or tmp stack */
/* types */ /* types */
#define VT_BTYPE 0x000f /* mask for basic type */ #define VT_BTYPE 0x000f /* mask for basic type */
@ -1212,6 +1212,7 @@ ST_FUNC int ieee_finite(double d);
ST_FUNC void test_lvalue(void); ST_FUNC void test_lvalue(void);
ST_FUNC void swap(int *p, int *q); ST_FUNC void swap(int *p, int *q);
ST_FUNC void vpushi(int v); ST_FUNC void vpushi(int v);
ST_FUNC void vpushs(addr_t v);
ST_FUNC Sym *external_global_sym(int v, CType *type, int r); ST_FUNC Sym *external_global_sym(int v, CType *type, int r);
ST_FUNC void vset(CType *type, int r, int v); ST_FUNC void vset(CType *type, int r, int v);
ST_FUNC void vswap(void); ST_FUNC void vswap(void);
@ -1247,6 +1248,7 @@ ST_FUNC void gen_inline_functions(void);
ST_FUNC void decl(int l); ST_FUNC void decl(int l);
ST_FUNC void vdup(void); ST_FUNC void vdup(void);
ST_FUNC void gaddrof(void); ST_FUNC void gaddrof(void);
ST_FUNC int loc_stack(int size, int is_sub);
#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67 #if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_C67
ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size); ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size);
#endif #endif

458
tccgen.c
View File

@ -370,7 +370,7 @@ ST_FUNC void vpushi(int v)
} }
/* push a pointer sized constant */ /* push a pointer sized constant */
static void vpushs(addr_t v) ST_FUNC void vpushs(addr_t v)
{ {
CValue cval; CValue cval;
cval.ptr_offset = v; cval.ptr_offset = v;
@ -525,6 +525,41 @@ ST_FUNC void vdup(void)
vpushv(vtop); 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 */ /* save r to the memory stack, and mark it as being free */
ST_FUNC void save_reg(int r) ST_FUNC void save_reg(int r)
{ {
@ -533,57 +568,76 @@ ST_FUNC void save_reg(int r)
CType *type; CType *type;
/* modify all stack values */ /* modify all stack values */
saved = 0; l = saved = 0;
l = 0; for(p = vstack; p <= vtop; p++) {
for(p=vstack;p<=vtop;p++) { #ifdef TCC_TARGET_X86_64
if ((p->r & VT_VALMASK) == r || if ((p->r & VT_VALMASK) == r ||
((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) { ((((p->type.t & VT_BTYPE) == VT_QLONG) || ((p->type.t & VT_BTYPE) == VT_QFLOAT)) &&
((p->r2 & VT_VALMASK) == r)))
#else
if ((p->r & VT_VALMASK) == r || ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r))
#endif
{
/* must save value on stack if not already done */ /* must save value on stack if not already done */
if (!saved) { if (!saved) {
/* NOTE: must reload 'r' because r might be equal to r2 */ /* NOTE: must reload 'r' because r might be equal to r2 */
r = p->r & VT_VALMASK; r = p->r & VT_VALMASK;
/* store register in the stack */ /* store register in the stack */
type = &p->type; type = &p->type;
if ((p->r & VT_LVAL) || if((type->t & VT_BTYPE) == VT_STRUCT){
(!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) int ret_align;
SValue ret;
gfunc_sret(type, func_var, &ret.type, &ret_align);
type = &ret.type;
}
if ((p->r & VT_LVAL) || ((type->t & VT_BTYPE) == VT_FUNC))
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
type = &char_pointer_type; type = &char_pointer_type;
#else #else
type = &int_type; type = &int_type;
#endif #endif
size = type_size(type, &align); size = type_size(type, &align);
loc = (loc - size) & -align; l = loc_stack(size, 1);
sv.type.t = type->t;
sv.r = VT_LOCAL | VT_LVAL; sv.r = VT_LOCAL | VT_LVAL;
sv.c.ul = loc; sv.c.ul = l;
store(r, &sv); #ifdef TCC_TARGET_X86_64
if (((type->t & VT_BTYPE) == VT_QLONG) || ((type->t & VT_BTYPE) == VT_QFLOAT))
#else
if ((type->t & VT_BTYPE) == VT_LLONG)
#endif
{
#ifdef TCC_TARGET_X86_64
int load_size = 8, load_type = ((type->t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE;
#else
int load_size = 4, load_type = VT_INT;
#endif
sv.type.t = load_type;
store(r, &sv);
sv.c.ul += load_size;
store(p->r2, &sv);
}else{
sv.type.t = type->t;
store(r, &sv);
}
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
/* x86 specific: need to pop fp register ST0 if saved */ /* x86 specific: need to pop fp register ST0 if saved */
if (r == TREG_ST0) { if (r == TREG_ST0) {
o(0xd8dd); /* fstp %st(0) */ o(0xd8dd); /* fstp %st(0) */
} }
#endif #endif
#ifndef TCC_TARGET_X86_64 saved = 1;
/* special long long case */
if ((type->t & VT_BTYPE) == VT_LLONG) {
sv.c.ul += 4;
store(p->r2, &sv);
}
#endif
l = loc;
saved = 1;
} }
/* mark that stack entry as being saved on the stack */ /* mark that stack entry as being saved on the stack */
if (p->r & VT_LVAL) { if (p->r & VT_LVAL) {
/* also clear the bounded flag because the /* also clear the bounded flag because the
relocation address of the function was stored in relocation address of the function was stored in
p->c.ul */ p->c.ul */
p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL;
} else { } else {
p->r = lvalue_type(p->type.t) | VT_LOCAL; p->r = lvalue_type(p->type.t) | VT_LOCAL | VT_TMP;
} }
p->r2 = VT_CONST; p->r2 = VT_CONST;
p->c.ul = l; p->c.ul = l;
} }
} }
} }
@ -613,42 +667,57 @@ ST_FUNC int get_reg_ex(int rc, int rc2)
} }
#endif #endif
/* find a free register of class 'rc'. If none, save one register */ static int for_reg(int rc)
ST_FUNC int get_reg(int rc)
{ {
int r; int r;
SValue *p;
if(rc){
for(r = 0; r < NB_REGS; r++) {
if (reg_classes[r] & rc) {
for(p = vstack; p <= vtop; p++) {
if ((p->r & VT_VALMASK) == r || (p->r2 & VT_VALMASK) == r)
goto notfound;
}
goto found;
}
notfound:;
}
}
r = -1;
found:
return r;
}
/* find a free register of class 'rc'. If none, save one register */
int get_reg(int rc)
{
int r;
SValue *p; SValue *p;
/* find a free register */ /* find a free register */
for(r=0;r<NB_REGS;r++) { r = for_reg(rc);
if (reg_classes[r] & rc) { if (r != -1)
for(p=vstack;p<=vtop;p++) { return r;
if ((p->r & VT_VALMASK) == r ||
(p->r2 & VT_VALMASK) == r)
goto notfound;
}
return r;
}
notfound: ;
}
/* no register left : free the first one on the stack (VERY /* no register left : free the first one on the stack (VERY
IMPORTANT to start from the bottom to ensure that we don't IMPORTANT to start from the bottom to ensure that we don't
spill registers used in gen_opi()) */ spill registers used in gen_opi()) */
for(p=vstack;p<=vtop;p++) { for(p = vstack; p <= vtop; p++) {
/* look at second register (if long long) */ /* look at second register (if long long) */
if(p->r & VT_TMP)
continue;
r = p->r2 & VT_VALMASK; r = p->r2 & VT_VALMASK;
if (r < VT_CONST && (reg_classes[r] & rc)) if (r < VT_CONST && (reg_classes[r] & rc))
goto save_found; goto save_found;
r = p->r & VT_VALMASK; r = p->r & VT_VALMASK;
if (r < VT_CONST && (reg_classes[r] & rc)) { if (r < VT_CONST && (reg_classes[r] & rc)) {
save_found: save_found:
save_reg(r); save_reg(r);
return r; return r;
} }
} }
/* Should never comes here */ /* Should never comes here */
return -1; assert(0);
return -1;
} }
/* save registers up to (vtop - n) stack entry */ /* save registers up to (vtop - n) stack entry */
@ -689,9 +758,7 @@ ST_FUNC void gaddrof(void)
vtop->r &= ~VT_LVAL; vtop->r &= ~VT_LVAL;
/* tricky: if saved lvalue, then we can go back to lvalue */ /* tricky: if saved lvalue, then we can go back to lvalue */
if ((vtop->r & VT_VALMASK) == VT_LLOCAL) if ((vtop->r & VT_VALMASK) == VT_LLOCAL)
vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL| VT_TMP;
} }
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
@ -1067,8 +1134,9 @@ ST_FUNC void vrott(int n)
/* pop stack value */ /* pop stack value */
ST_FUNC void vpop(void) ST_FUNC void vpop(void)
{ {
int v; int v, fr;
v = vtop->r & VT_VALMASK; fr = vtop->r;
v = fr & VT_VALMASK;
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
/* for x86, we need to pop the FP stack */ /* for x86, we need to pop the FP stack */
if (v == TREG_ST0 && !nocode_wanted) { if (v == TREG_ST0 && !nocode_wanted) {
@ -1079,6 +1147,17 @@ ST_FUNC void vpop(void)
/* need to put correct jump if && or || without test */ /* need to put correct jump if && or || without test */
gsym(vtop->c.ul); gsym(vtop->c.ul);
} }
if(fr & VT_TMP){
int size, align;
SValue ret;
if((vtop->type.t & VT_BTYPE) == VT_FUNC)
size = 8;
else{
gfunc_sret(&vtop->type, func_var, &ret.type, &align);
size = type_size(&ret.type, &align);
}
loc_stack(size, 0);
}
vtop--; vtop--;
} }
@ -2154,7 +2233,7 @@ ST_FUNC void vla_runtime_type_size(CType *type, int *a)
static void vla_sp_save(void) { static void vla_sp_save(void) {
if (!(vla_flags & VLA_SP_LOC_SET)) { if (!(vla_flags & VLA_SP_LOC_SET)) {
*vla_sp_loc = (loc -= PTR_SIZE); *vla_sp_loc = loc_stack(PTR_SIZE, 1);
vla_flags |= VLA_SP_LOC_SET; vla_flags |= VLA_SP_LOC_SET;
} }
if (!(vla_flags & VLA_SP_SAVED)) { if (!(vla_flags & VLA_SP_SAVED)) {
@ -2423,6 +2502,8 @@ static void gen_assign_cast(CType *dt)
if (sbt == VT_PTR || sbt == VT_FUNC) { if (sbt == VT_PTR || sbt == VT_FUNC) {
tcc_warning("assignment makes integer from pointer without a cast"); tcc_warning("assignment makes integer from pointer without a cast");
} }
if (sbt == VT_STRUCT)
goto error;
/* XXX: more tests */ /* XXX: more tests */
break; break;
case VT_STRUCT: case VT_STRUCT:
@ -2466,7 +2547,7 @@ static void vstore_im(){
#else #else
sv.type.t = VT_INT; sv.type.t = VT_INT;
#endif #endif
sv.r = VT_LOCAL | VT_LVAL; sv.r = VT_LOCAL | VT_LVAL | VT_TMP;
sv.c.ul = vtop[-1].c.ul; sv.c.ul = vtop[-1].c.ul;
load(t, &sv); load(t, &sv);
vtop[-1].r = t | VT_LVAL; vtop[-1].r = t | VT_LVAL;
@ -2534,7 +2615,7 @@ ST_FUNC void vstore(void)
SValue ret; SValue ret;
int ret_nregs, ret_align; int ret_nregs, ret_align;
ret_nregs = gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align); ret_nregs = gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align);
if(0){ if(ret_nregs){
vswap(); vswap();
vpushv(vtop - 1); vpushv(vtop - 1);
vtop[0].type = ret.type; vtop[0].type = ret.type;
@ -2565,7 +2646,7 @@ ST_FUNC void vstore(void)
vtop->type.t = VT_PTR; vtop->type.t = VT_PTR;
gaddrof(); gaddrof();
/* type size */ /* type size */
vpushi(size); vpushs(size);
gfunc_call(3); gfunc_call(3);
#else #else
/* destination */ /* destination */
@ -2577,7 +2658,7 @@ ST_FUNC void vstore(void)
vtop->type.t = VT_PTR; vtop->type.t = VT_PTR;
gaddrof(); gaddrof();
/* size */ /* size */
vpushi(size); vpushs(size);
struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); struct_copy(&vtop[-2], &vtop[-1], &vtop[0]);
vtop -=3; vtop -=3;
#endif #endif
@ -3298,7 +3379,7 @@ static void asm_label_instr(CString *astr)
static void post_type(CType *type, AttributeDef *ad) static void post_type(CType *type, AttributeDef *ad)
{ {
int n, l, t1, arg_size, align; int n, l, t1, arg_size, size, align;
Sym **plast, *s, *first; Sym **plast, *s, *first;
AttributeDef ad1; AttributeDef ad1;
CType pt; CType pt;
@ -3402,13 +3483,12 @@ static void post_type(CType *type, AttributeDef *ad)
t1 |= type->t & VT_VLA; t1 |= type->t & VT_VLA;
if (t1 & VT_VLA) { if (t1 & VT_VLA) {
loc -= type_size(&int_type, &align); size = type_size(&int_type, &align);
loc &= -align; n = loc_stack(size, 1);
n = loc;
vla_runtime_type_size(type, &align); vla_runtime_type_size(type, &align);
gen_op('*'); gen_op('*');
vset(&int_type, VT_LOCAL|VT_LVAL, loc); vset(&int_type, VT_LOCAL|VT_LVAL, n);
vswap(); vswap();
vstore(); vstore();
} }
@ -4004,47 +4084,94 @@ ST_FUNC void unary(void)
/* post operations */ /* post operations */
while (1) { while (1) {
SValue ret;
int ret_nregs, ret_align;
if (tok == TOK_INC || tok == TOK_DEC) { if (tok == TOK_INC || tok == TOK_DEC) {
inc(1, tok); inc(1, tok);
next(); next();
} else if (tok == '.' || tok == TOK_ARROW) { } else if (tok == '.' || tok == TOK_ARROW) {
int qualifiers; int qualifiers, add, is_lval;
/* field */ /* field */
if (tok == TOK_ARROW) qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE);
indir(); add = 0;
qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); if (tok == TOK_ARROW)
test_lvalue(); indir();
gaddrof();
next(); type = vtop->type;
/* expect pointer on structure */ is_lval = (vtop->r & (VT_VALMASK | VT_LVAL)) >= VT_CONST;
if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) if(is_lval){
expect("struct or union"); test_lvalue();
s = vtop->type.ref; gaddrof();
/* find field */ vtop->type = char_pointer_type; /* change type to 'char *' */
tok |= SYM_FIELD; }else
while ((s = s->next) != NULL) { gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align);
if (s->v == tok) do{
break; next();
} /* expect pointer on structure */
if (!s) if ((type.t & VT_BTYPE) != VT_STRUCT)
tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL)); expect("struct or union");
/* add field offset to pointer */ s = type.ref;
vtop->type = char_pointer_type; /* change type to 'char *' */ /* find field */
vpushi(s->c); tok |= SYM_FIELD;
gen_op('+'); while ((s = s->next) != NULL) {
/* change type to field type, and set to lvalue */ if (s->v == tok)
vtop->type = s->type; break;
vtop->type.t |= qualifiers; }
/* an array is never an lvalue */ if (!s)
if (!(vtop->type.t & VT_ARRAY)) { tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL));
vtop->r |= lvalue_type(vtop->type.t); /* add bit */
#ifdef CONFIG_TCC_BCHECK add += s->c;
/* if bound checking, the referenced pointer must be checked */ /* change type to field type, and set to lvalue */
if (tcc_state->do_bounds_check) type = s->type;
vtop->r |= VT_MUSTBOUND; next();
}while(tok == '.');
type.t |= qualifiers;
if (is_lval){
p_lval:
vpushi(add);
gen_op('+');
/* an array is never an lvalue */
if (!(type.t & VT_ARRAY)) {
vtop->r |= lvalue_type(type.t);
#ifdef CONFIG_TCC_BCHECK
/* if bound checking, the referenced pointer must be checked */
if (tcc_state->do_bounds_check)
vtop->r |= VT_MUSTBOUND;
#endif
}
}else{
gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align);
if(is_float(ret.type.t) || (type.t & VT_ARRAY)){
#ifdef TCC_TARGET_X86_64
if((ret.type.t & VT_BTYPE) != VT_LDOUBLE)
#endif #endif
} {
next(); save_reg(vtop->r);
vtop->r &= ~VT_TMP;
gaddrof();
vtop->type = char_pointer_type; /* change type to 'char *' */
goto p_lval;
}
}else{
#ifdef TCC_TARGET_X86_64
int load_size = 8;
#else
int load_size = 4;
#endif
if(add & load_size){
add -= load_size;
vtop->r = vtop->r2;
vtop->r2 = VT_CONST;
}
if(add){
vtop->type.t = VT_LLONG;
vpushi(add*8);
gen_op(TOK_SAR);
}
}
}
vtop->type = type;
} else if (tok == '[') { } else if (tok == '[') {
next(); next();
gexpr(); gexpr();
@ -4052,9 +4179,8 @@ ST_FUNC void unary(void)
indir(); indir();
skip(']'); skip(']');
} else if (tok == '(') { } else if (tok == '(') {
SValue ret;
Sym *sa; Sym *sa;
int nb_args, ret_nregs, ret_align, variadic; int nb_args, variadic, addr;
/* function call */ /* function call */
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@ -4072,7 +4198,6 @@ ST_FUNC void unary(void)
} }
/* get return type */ /* get return type */
s = vtop->type.ref; s = vtop->type.ref;
next();
sa = s->next; /* first parameter */ sa = s->next; /* first parameter */
nb_args = 0; nb_args = 0;
ret.r2 = VT_CONST; ret.r2 = VT_CONST;
@ -4084,12 +4209,12 @@ ST_FUNC void unary(void)
if (!ret_nregs) { if (!ret_nregs) {
/* get some space for the returned structure */ /* get some space for the returned structure */
size = type_size(&s->type, &align); size = type_size(&s->type, &align);
loc = (loc - size) & -align; addr = loc_stack(size, 1);
ret.type = s->type; ret.type = s->type;
ret.r = VT_LOCAL | VT_LVAL; ret.r = VT_LOCAL | VT_LVAL;
/* pass it as 'int' to avoid structure arg passing /* pass it as 'int' to avoid structure arg passing
problems */ problems */
vseti(VT_LOCAL, loc); vseti(VT_LOCAL, addr);
ret.c = vtop->c; ret.c = vtop->c;
nb_args++; nb_args++;
} }
@ -4117,6 +4242,7 @@ ST_FUNC void unary(void)
} }
ret.c.i = 0; ret.c.i = 0;
} }
next();
if (tok != ')') { if (tok != ')') {
for(;;) { for(;;) {
expr_eq(); expr_eq();
@ -4145,25 +4271,8 @@ ST_FUNC void unary(void)
} }
/* handle packed struct return */ /* handle packed struct return */
if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs)
int addr, offset; vtop->type = s->type;
size = type_size(&s->type, &align);
loc = (loc - size) & -align;
addr = loc;
offset = 0;
for (;;) {
vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset);
vswap();
vstore();
vtop--;
if (--ret_nregs == 0)
break;
/* XXX: compatible with arm only: ret_align == register_size */
offset += ret_align;
}
vset(&s->type, VT_LOCAL | VT_LVAL, addr);
}
} else { } else {
break; break;
} }
@ -4332,8 +4441,8 @@ static void expr_lor(void)
/* XXX: better constant handling */ /* XXX: better constant handling */
static void expr_cond(void) static void expr_cond(void)
{ {
int tt, u, r1, r2, rc, t1, t2, bt1, bt2; int tt, u, r, rc, t1, t2, bt1, bt2, ret_nregs, ret_align;
SValue sv; SValue sv, ret;
CType type, type1, type2; CType type, type1, type2;
if (const_wanted) { if (const_wanted) {
@ -4375,8 +4484,7 @@ static void expr_cond(void)
} }
else else
rc = RC_INT; rc = RC_INT;
gv(rc); save_regs(1);
save_regs(1);
} }
if (tok == ':' && gnu_ext) { if (tok == ':' && gnu_ext) {
gv_dup(); gv_dup();
@ -4415,16 +4523,14 @@ static void expr_cond(void)
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
type.t |= VT_UNSIGNED; type.t |= VT_UNSIGNED;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) { } else if (bt1 == VT_PTR || bt2 == VT_PTR) {
/* If one is a null ptr constant the result type /* If one is a null ptr constant the result type is the other. */
is the other. */ if (is_null_pointer (vtop))
if (is_null_pointer (vtop)) type = type1;
type = type1; else if (is_null_pointer (&sv))
else if (is_null_pointer (&sv)) type = type2;
type = type2; /* XXX: test pointer compatibility, C99 has more elaborate rules here. */
/* XXX: test pointer compatibility, C99 has more elaborate else
rules here. */ type = type1;
else
type = type1;
} else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
/* XXX: test function pointer compatibility */ /* XXX: test function pointer compatibility */
type = bt1 == VT_FUNC ? type1 : type2; type = bt1 == VT_FUNC ? type1 : type2;
@ -4442,26 +4548,35 @@ static void expr_cond(void)
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
type.t |= VT_UNSIGNED; type.t |= VT_UNSIGNED;
} }
/* now we convert second operand */ /* now we convert second operand */
gen_cast(&type); gen_cast(&type);
if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) ret_nregs = 0;
gaddrof(); if (VT_STRUCT == (type.t & VT_BTYPE)){
rc = RC_INT; ret_nregs = gfunc_sret(&type, func_var, &ret.type, &ret_align);
if (is_float(type.t)) { if(ret_nregs)
vtop->type = ret.type;
else
gaddrof();
}
if (is_float(vtop->type.t)) {
rc = RC_FLOAT; rc = RC_FLOAT;
#ifdef TCC_TARGET_X86_64 #ifdef TCC_TARGET_X86_64
if ((type.t & VT_BTYPE) == VT_LDOUBLE) { if ((type.t & VT_BTYPE) == VT_LDOUBLE) {
rc = RC_ST0; rc = RC_ST0;
} }
#endif #endif
} else if ((type.t & VT_BTYPE) == VT_LLONG) { } else
/* for long longs, we use fixed registers to avoid having rc = RC_INT;
to handle a complicated move */ r = gv(rc);
rc = RC_IRET; rc = reg_classes[r] & ~RC_MASK;
} #ifdef TCC_TARGET_X86_64
if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT))
r2 = gv(rc); #else
if ((vtop->type.t & VT_BTYPE) == VT_LLONG)
#endif
ex_rc = reg_classes[vtop->r2] & ~RC_MASK;
/* this is horrible, but we must also convert first /* this is horrible, but we must also convert first
operand */ operand */
tt = gjmp(0); tt = gjmp(0);
@ -4469,12 +4584,21 @@ static void expr_cond(void)
/* put again first value and cast it */ /* put again first value and cast it */
*vtop = sv; *vtop = sv;
gen_cast(&type); gen_cast(&type);
if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) if (VT_STRUCT == (type.t & VT_BTYPE)){
gaddrof(); if(ret_nregs)
r1 = gv(rc); vtop->type = ret.type;
move_reg(r2, r1, type.t); else
vtop->r = r2; gaddrof();
}
gv(rc);
gsym(tt); gsym(tt);
if (VT_STRUCT == (type.t & VT_BTYPE)){
if(ret_nregs)
vtop->type = type;
else
vtop->r |= VT_LVAL;
}
} }
} }
} }
@ -4747,18 +4871,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
vstore(); vstore();
} else { } else {
/* returning structure packed into registers */ /* returning structure packed into registers */
int rc, size, addr, align; int rc;
size = type_size(&func_vt,&align);
if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1)))
&& (align & (ret_align-1))) {
loc = (loc - size) & -align;
addr = loc;
type = func_vt;
vset(&type, VT_LOCAL | VT_LVAL, addr);
vswap();
vstore();
vset(&ret_type, VT_LOCAL | VT_LVAL, addr);
}
vtop->type = ret_type; vtop->type = ret_type;
if (is_float(ret_type.t)) if (is_float(ret_type.t))
rc = rc_fret(ret_type.t); rc = rc_fret(ret_type.t);
@ -5606,11 +5719,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
sec = NULL; sec = NULL;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
loc--; loc_stack(1, 1);
} }
#endif #endif
loc = (loc - size) & -align; addr = loc_stack(size, 1);
addr = loc;
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
/* handles bounds */ /* handles bounds */
/* XXX: currently, since we do only one pass, we cannot track /* XXX: currently, since we do only one pass, we cannot track
@ -5618,7 +5730,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
unsigned long *bounds_ptr; unsigned long *bounds_ptr;
/* add padding between regions */ /* add padding between regions */
loc--; loc_stack(1, 1);
/* then add local bound info */ /* then add local bound info */
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long)); bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long));
bounds_ptr[0] = addr; bounds_ptr[0] = addr;

View File

@ -405,6 +405,14 @@ void load(int r, SValue *sv)
v = fr & VT_VALMASK; v = fr & VT_VALMASK;
if (fr & VT_LVAL) { if (fr & VT_LVAL) {
if(fr & VT_TMP){
int size, align;
if((ft & VT_BTYPE) == VT_FUNC)
size = 8;
else
size = type_size(&sv->type, &align);
loc_stack(size, 0);
}
if (v == VT_LLOCAL) { if (v == VT_LLOCAL) {
v1.type.t = VT_PTR; v1.type.t = VT_PTR;
v1.r = VT_LOCAL | VT_LVAL; v1.r = VT_LOCAL | VT_LVAL;
@ -602,6 +610,24 @@ static void gcall_or_jmp(int is_jmp)
} }
} }
static int func_scratch;
static int r_loc;
int reloc_add(int inds)
{
return psym(0, inds);
}
void reloc_use(int t, int data)
{
int *ptr;
while (t) {
ptr = (int *)(cur_text_section->data + t);
t = *ptr; /* next value */
*ptr = data;
}
}
void struct_copy(SValue *d, SValue *s, SValue *c) void struct_copy(SValue *d, SValue *s, SValue *c)
{ {
if(!c->c.i) if(!c->c.i)
@ -647,9 +673,6 @@ void gen_offs_sp(int b, int r, int off)
} }
} }
static int func_scratch;
static int r_loc;
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
#define REGN 4 #define REGN 4
@ -905,7 +928,7 @@ void gfunc_epilog(void)
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
/* align local size to word & save local variables */ /* align local size to word & save local variables */
v = (func_scratch + -loc + 15) & -16; v = (func_scratch + -loc + 15) & -16;
reloc_use(r_loc, func_scratch);
if (v >= 4096) { if (v >= 4096) {
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
oad(0xb8, v); /* mov stacksize, %eax */ oad(0xb8, v); /* mov stacksize, %eax */
@ -1210,6 +1233,7 @@ doing:
/* Must ensure TREG_ST0 only */ /* Must ensure TREG_ST0 only */
if((vtop->type.t & VT_BTYPE) == VT_STRUCT){ if((vtop->type.t & VT_BTYPE) == VT_STRUCT){
vdup(); vdup();
vtop[-1].r = VT_CONST;
vtop->type = type; vtop->type = type;
gv(RC_ST0); gv(RC_ST0);
args_size -= size; args_size -= size;
@ -1228,7 +1252,7 @@ doing:
vpushv(&vtop[-1]); vpushv(&vtop[-1]);
vtop->type = char_pointer_type; vtop->type = char_pointer_type;
gaddrof(); gaddrof();
vpushi(size); vpushs(size);
struct_copy(&vtop[-2], &vtop[-1], &vtop[0]); struct_copy(&vtop[-2], &vtop[-1], &vtop[0]);
vtop -= 3; vtop -= 3;
break; break;
@ -1474,6 +1498,7 @@ void gfunc_epilog(void)
} }
/* align local size to word & save local variables */ /* align local size to word & save local variables */
v = (func_scratch -loc + 15) & -16; v = (func_scratch -loc + 15) & -16;
reloc_use(r_loc, func_scratch);
saved_ind = ind; saved_ind = ind;
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
o(0xe5894855); /* push %rbp, mov %rsp, %rbp */ o(0xe5894855); /* push %rbp, mov %rsp, %rbp */
@ -2043,27 +2068,19 @@ ST_FUNC void gen_vla_sp_restore(int addr) {
/* Subtract from the stack pointer, and push the resulting value onto the stack */ /* Subtract from the stack pointer, and push the resulting value onto the stack */
ST_FUNC void gen_vla_alloc(CType *type, int align) { ST_FUNC void gen_vla_alloc(CType *type, int align) {
#ifdef TCC_TARGET_PE
/* alloca does more than just adjust %rsp on Windows */
vpush_global_sym(&func_old_type, TOK_alloca);
vswap(); /* Move alloca ref past allocation size */
gfunc_call(1);
vset(type, REG_IRET, 0);
#else
int r; int r;
r = gv(RC_INT); /* allocation size */ r = gv(RC_INT); /* allocation size */
/* sub r,%rsp */ /* sub r,%rsp */
o(0x2b48); o(0x2b48);
o(0xe0 | REG_VALUE(r)); o(0xe0 | REG_VALUE(r));
/* We align to 16 bytes rather than align */ /* and ~15, %rsp */
/* and ~15, %rsp */
o(0xf0e48348); o(0xf0e48348);
/* mov %rsp, r */ /* mov %rsp, r */
o(0x8948); orex(1, 0, r, 0x8d);
o(0xe0 | REG_VALUE(r)); o(0x2484 | (REG_VALUE(r)*8));
r_loc = reloc_add(r_loc);
vpop(); vpop();
vset(type, r, 0); vset(type, r, 0);
#endif
} }