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
This commit is contained in:
parent
6c8207633f
commit
e647c3137d
3 changed files with 322 additions and 191 deletions
4
tcc.h
4
tcc.h
|
@ -761,7 +761,7 @@ struct TCCState {
|
|||
#define VT_LVAL_TYPE (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
|
||||
#define VT_BOUNDED 0x8000 /* value is bounded. The address of the
|
||||
bounding function call point is in vc */
|
||||
#define VT_TMP 0x10000
|
||||
#define VT_TMP 0x10000 /* luck or tmp stack */
|
||||
|
||||
/* types */
|
||||
#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 swap(int *p, int *q);
|
||||
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 void vset(CType *type, int r, int v);
|
||||
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 vdup(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
|
||||
ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size);
|
||||
#endif
|
||||
|
|
458
tccgen.c
458
tccgen.c
|
@ -370,7 +370,7 @@ ST_FUNC void vpushi(int v)
|
|||
}
|
||||
|
||||
/* push a pointer sized constant */
|
||||
static void vpushs(addr_t v)
|
||||
ST_FUNC void vpushs(addr_t v)
|
||||
{
|
||||
CValue cval;
|
||||
cval.ptr_offset = v;
|
||||
|
@ -525,6 +525,41 @@ ST_FUNC 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)
|
||||
{
|
||||
|
@ -533,57 +568,76 @@ ST_FUNC void save_reg(int r)
|
|||
CType *type;
|
||||
|
||||
/* modify all stack values */
|
||||
saved = 0;
|
||||
l = 0;
|
||||
for(p=vstack;p<=vtop;p++) {
|
||||
if ((p->r & VT_VALMASK) == r ||
|
||||
((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) {
|
||||
l = saved = 0;
|
||||
for(p = vstack; p <= vtop; p++) {
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
if ((p->r & 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 */
|
||||
if (!saved) {
|
||||
/* NOTE: must reload 'r' because r might be equal to r2 */
|
||||
r = p->r & VT_VALMASK;
|
||||
/* store register in the stack */
|
||||
type = &p->type;
|
||||
if ((p->r & VT_LVAL) ||
|
||||
(!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG))
|
||||
if((type->t & VT_BTYPE) == VT_STRUCT){
|
||||
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
|
||||
type = &char_pointer_type;
|
||||
#else
|
||||
type = &int_type;
|
||||
#endif
|
||||
size = type_size(type, &align);
|
||||
loc = (loc - size) & -align;
|
||||
sv.type.t = type->t;
|
||||
size = type_size(type, &align);
|
||||
l = loc_stack(size, 1);
|
||||
sv.r = VT_LOCAL | VT_LVAL;
|
||||
sv.c.ul = loc;
|
||||
store(r, &sv);
|
||||
sv.c.ul = l;
|
||||
#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)
|
||||
/* x86 specific: need to pop fp register ST0 if saved */
|
||||
if (r == TREG_ST0) {
|
||||
o(0xd8dd); /* fstp %st(0) */
|
||||
}
|
||||
#endif
|
||||
#ifndef TCC_TARGET_X86_64
|
||||
/* special long long case */
|
||||
if ((type->t & VT_BTYPE) == VT_LLONG) {
|
||||
sv.c.ul += 4;
|
||||
store(p->r2, &sv);
|
||||
}
|
||||
#endif
|
||||
l = loc;
|
||||
saved = 1;
|
||||
saved = 1;
|
||||
}
|
||||
/* mark that stack entry as being saved on the stack */
|
||||
if (p->r & VT_LVAL) {
|
||||
/* also clear the bounded flag because the
|
||||
relocation address of the function was stored in
|
||||
p->c.ul */
|
||||
p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL;
|
||||
} else {
|
||||
p->r = lvalue_type(p->type.t) | VT_LOCAL;
|
||||
}
|
||||
p->r2 = VT_CONST;
|
||||
p->c.ul = l;
|
||||
/* mark that stack entry as being saved on the stack */
|
||||
if (p->r & VT_LVAL) {
|
||||
/* also clear the bounded flag because the
|
||||
relocation address of the function was stored in
|
||||
p->c.ul */
|
||||
p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL;
|
||||
} else {
|
||||
p->r = lvalue_type(p->type.t) | VT_LOCAL | VT_TMP;
|
||||
}
|
||||
p->r2 = VT_CONST;
|
||||
p->c.ul = l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -613,42 +667,57 @@ ST_FUNC int get_reg_ex(int rc, int rc2)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* find a free register of class 'rc'. If none, save one register */
|
||||
ST_FUNC int get_reg(int rc)
|
||||
static int for_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;
|
||||
|
||||
/* find a free register */
|
||||
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;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
notfound: ;
|
||||
}
|
||||
|
||||
r = for_reg(rc);
|
||||
if (r != -1)
|
||||
return r;
|
||||
/* no register left : free the first one on the stack (VERY
|
||||
IMPORTANT to start from the bottom to ensure that we don't
|
||||
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) */
|
||||
if(p->r & VT_TMP)
|
||||
continue;
|
||||
r = p->r2 & VT_VALMASK;
|
||||
if (r < VT_CONST && (reg_classes[r] & rc))
|
||||
goto save_found;
|
||||
r = p->r & VT_VALMASK;
|
||||
if (r < VT_CONST && (reg_classes[r] & rc)) {
|
||||
save_found:
|
||||
save_reg(r);
|
||||
save_found:
|
||||
save_reg(r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
/* Should never comes here */
|
||||
return -1;
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save registers up to (vtop - n) stack entry */
|
||||
|
@ -689,9 +758,7 @@ ST_FUNC void gaddrof(void)
|
|||
vtop->r &= ~VT_LVAL;
|
||||
/* tricky: if saved lvalue, then we can go back to lvalue */
|
||||
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
|
||||
|
@ -1067,8 +1134,9 @@ ST_FUNC void vrott(int n)
|
|||
/* pop stack value */
|
||||
ST_FUNC void vpop(void)
|
||||
{
|
||||
int v;
|
||||
v = vtop->r & VT_VALMASK;
|
||||
int v, fr;
|
||||
fr = vtop->r;
|
||||
v = fr & VT_VALMASK;
|
||||
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64)
|
||||
/* for x86, we need to pop the FP stack */
|
||||
if (v == TREG_ST0 && !nocode_wanted) {
|
||||
|
@ -1079,6 +1147,17 @@ ST_FUNC void vpop(void)
|
|||
/* need to put correct jump if && or || without test */
|
||||
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--;
|
||||
}
|
||||
|
||||
|
@ -2154,7 +2233,7 @@ ST_FUNC void vla_runtime_type_size(CType *type, int *a)
|
|||
|
||||
static void vla_sp_save(void) {
|
||||
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;
|
||||
}
|
||||
if (!(vla_flags & VLA_SP_SAVED)) {
|
||||
|
@ -2423,6 +2502,8 @@ static void gen_assign_cast(CType *dt)
|
|||
if (sbt == VT_PTR || sbt == VT_FUNC) {
|
||||
tcc_warning("assignment makes integer from pointer without a cast");
|
||||
}
|
||||
if (sbt == VT_STRUCT)
|
||||
goto error;
|
||||
/* XXX: more tests */
|
||||
break;
|
||||
case VT_STRUCT:
|
||||
|
@ -2466,7 +2547,7 @@ static void vstore_im(){
|
|||
#else
|
||||
sv.type.t = VT_INT;
|
||||
#endif
|
||||
sv.r = VT_LOCAL | VT_LVAL;
|
||||
sv.r = VT_LOCAL | VT_LVAL | VT_TMP;
|
||||
sv.c.ul = vtop[-1].c.ul;
|
||||
load(t, &sv);
|
||||
vtop[-1].r = t | VT_LVAL;
|
||||
|
@ -2534,7 +2615,7 @@ ST_FUNC void vstore(void)
|
|||
SValue ret;
|
||||
int ret_nregs, ret_align;
|
||||
ret_nregs = gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align);
|
||||
if(0){
|
||||
if(ret_nregs){
|
||||
vswap();
|
||||
vpushv(vtop - 1);
|
||||
vtop[0].type = ret.type;
|
||||
|
@ -2565,7 +2646,7 @@ ST_FUNC void vstore(void)
|
|||
vtop->type.t = VT_PTR;
|
||||
gaddrof();
|
||||
/* type size */
|
||||
vpushi(size);
|
||||
vpushs(size);
|
||||
gfunc_call(3);
|
||||
#else
|
||||
/* destination */
|
||||
|
@ -2577,7 +2658,7 @@ ST_FUNC void vstore(void)
|
|||
vtop->type.t = VT_PTR;
|
||||
gaddrof();
|
||||
/* size */
|
||||
vpushi(size);
|
||||
vpushs(size);
|
||||
struct_copy(&vtop[-2], &vtop[-1], &vtop[0]);
|
||||
vtop -=3;
|
||||
#endif
|
||||
|
@ -3298,7 +3379,7 @@ static void asm_label_instr(CString *astr)
|
|||
|
||||
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;
|
||||
AttributeDef ad1;
|
||||
CType pt;
|
||||
|
@ -3402,13 +3483,12 @@ static void post_type(CType *type, AttributeDef *ad)
|
|||
t1 |= type->t & VT_VLA;
|
||||
|
||||
if (t1 & VT_VLA) {
|
||||
loc -= type_size(&int_type, &align);
|
||||
loc &= -align;
|
||||
n = loc;
|
||||
size = type_size(&int_type, &align);
|
||||
n = loc_stack(size, 1);
|
||||
|
||||
vla_runtime_type_size(type, &align);
|
||||
gen_op('*');
|
||||
vset(&int_type, VT_LOCAL|VT_LVAL, loc);
|
||||
vset(&int_type, VT_LOCAL|VT_LVAL, n);
|
||||
vswap();
|
||||
vstore();
|
||||
}
|
||||
|
@ -4004,47 +4084,94 @@ ST_FUNC void unary(void)
|
|||
|
||||
/* post operations */
|
||||
while (1) {
|
||||
SValue ret;
|
||||
int ret_nregs, ret_align;
|
||||
if (tok == TOK_INC || tok == TOK_DEC) {
|
||||
inc(1, tok);
|
||||
next();
|
||||
} else if (tok == '.' || tok == TOK_ARROW) {
|
||||
int qualifiers;
|
||||
int qualifiers, add, is_lval;
|
||||
/* field */
|
||||
if (tok == TOK_ARROW)
|
||||
indir();
|
||||
qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE);
|
||||
test_lvalue();
|
||||
gaddrof();
|
||||
next();
|
||||
/* expect pointer on structure */
|
||||
if ((vtop->type.t & VT_BTYPE) != VT_STRUCT)
|
||||
expect("struct or union");
|
||||
s = vtop->type.ref;
|
||||
/* find field */
|
||||
tok |= SYM_FIELD;
|
||||
while ((s = s->next) != NULL) {
|
||||
if (s->v == tok)
|
||||
break;
|
||||
}
|
||||
if (!s)
|
||||
tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL));
|
||||
/* add field offset to pointer */
|
||||
vtop->type = char_pointer_type; /* change type to 'char *' */
|
||||
vpushi(s->c);
|
||||
gen_op('+');
|
||||
/* change type to field type, and set to lvalue */
|
||||
vtop->type = s->type;
|
||||
vtop->type.t |= qualifiers;
|
||||
/* an array is never an lvalue */
|
||||
if (!(vtop->type.t & VT_ARRAY)) {
|
||||
vtop->r |= lvalue_type(vtop->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;
|
||||
qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE);
|
||||
add = 0;
|
||||
if (tok == TOK_ARROW)
|
||||
indir();
|
||||
|
||||
type = vtop->type;
|
||||
is_lval = (vtop->r & (VT_VALMASK | VT_LVAL)) >= VT_CONST;
|
||||
if(is_lval){
|
||||
test_lvalue();
|
||||
gaddrof();
|
||||
vtop->type = char_pointer_type; /* change type to 'char *' */
|
||||
}else
|
||||
gfunc_sret(&vtop->type, func_var, &ret.type, &ret_align);
|
||||
do{
|
||||
next();
|
||||
/* expect pointer on structure */
|
||||
if ((type.t & VT_BTYPE) != VT_STRUCT)
|
||||
expect("struct or union");
|
||||
s = type.ref;
|
||||
/* find field */
|
||||
tok |= SYM_FIELD;
|
||||
while ((s = s->next) != NULL) {
|
||||
if (s->v == tok)
|
||||
break;
|
||||
}
|
||||
if (!s)
|
||||
tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, NULL));
|
||||
/* add bit */
|
||||
add += s->c;
|
||||
/* change type to field type, and set to lvalue */
|
||||
type = s->type;
|
||||
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
|
||||
}
|
||||
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 == '[') {
|
||||
next();
|
||||
gexpr();
|
||||
|
@ -4052,9 +4179,8 @@ ST_FUNC void unary(void)
|
|||
indir();
|
||||
skip(']');
|
||||
} else if (tok == '(') {
|
||||
SValue ret;
|
||||
Sym *sa;
|
||||
int nb_args, ret_nregs, ret_align, variadic;
|
||||
int nb_args, variadic, addr;
|
||||
|
||||
/* function call */
|
||||
if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
|
||||
|
@ -4072,7 +4198,6 @@ ST_FUNC void unary(void)
|
|||
}
|
||||
/* get return type */
|
||||
s = vtop->type.ref;
|
||||
next();
|
||||
sa = s->next; /* first parameter */
|
||||
nb_args = 0;
|
||||
ret.r2 = VT_CONST;
|
||||
|
@ -4084,12 +4209,12 @@ ST_FUNC void unary(void)
|
|||
if (!ret_nregs) {
|
||||
/* get some space for the returned structure */
|
||||
size = type_size(&s->type, &align);
|
||||
loc = (loc - size) & -align;
|
||||
addr = loc_stack(size, 1);
|
||||
ret.type = s->type;
|
||||
ret.r = VT_LOCAL | VT_LVAL;
|
||||
/* pass it as 'int' to avoid structure arg passing
|
||||
problems */
|
||||
vseti(VT_LOCAL, loc);
|
||||
vseti(VT_LOCAL, addr);
|
||||
ret.c = vtop->c;
|
||||
nb_args++;
|
||||
}
|
||||
|
@ -4117,6 +4242,7 @@ ST_FUNC void unary(void)
|
|||
}
|
||||
ret.c.i = 0;
|
||||
}
|
||||
next();
|
||||
if (tok != ')') {
|
||||
for(;;) {
|
||||
expr_eq();
|
||||
|
@ -4145,25 +4271,8 @@ ST_FUNC void unary(void)
|
|||
}
|
||||
|
||||
/* handle packed struct return */
|
||||
if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) {
|
||||
int addr, offset;
|
||||
|
||||
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);
|
||||
}
|
||||
if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs)
|
||||
vtop->type = s->type;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
@ -4332,8 +4441,8 @@ static void expr_lor(void)
|
|||
/* XXX: better constant handling */
|
||||
static void expr_cond(void)
|
||||
{
|
||||
int tt, u, r1, r2, rc, t1, t2, bt1, bt2;
|
||||
SValue sv;
|
||||
int tt, u, r, rc, t1, t2, bt1, bt2, ret_nregs, ret_align;
|
||||
SValue sv, ret;
|
||||
CType type, type1, type2;
|
||||
|
||||
if (const_wanted) {
|
||||
|
@ -4375,8 +4484,7 @@ static void expr_cond(void)
|
|||
}
|
||||
else
|
||||
rc = RC_INT;
|
||||
gv(rc);
|
||||
save_regs(1);
|
||||
save_regs(1);
|
||||
}
|
||||
if (tok == ':' && gnu_ext) {
|
||||
gv_dup();
|
||||
|
@ -4415,16 +4523,14 @@ static void expr_cond(void)
|
|||
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
|
||||
type.t |= VT_UNSIGNED;
|
||||
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
|
||||
/* If one is a null ptr constant the result type
|
||||
is the other. */
|
||||
if (is_null_pointer (vtop))
|
||||
type = type1;
|
||||
else if (is_null_pointer (&sv))
|
||||
type = type2;
|
||||
/* XXX: test pointer compatibility, C99 has more elaborate
|
||||
rules here. */
|
||||
else
|
||||
type = type1;
|
||||
/* If one is a null ptr constant the result type is the other. */
|
||||
if (is_null_pointer (vtop))
|
||||
type = type1;
|
||||
else if (is_null_pointer (&sv))
|
||||
type = type2;
|
||||
/* XXX: test pointer compatibility, C99 has more elaborate rules here. */
|
||||
else
|
||||
type = type1;
|
||||
} else if (bt1 == VT_FUNC || bt2 == VT_FUNC) {
|
||||
/* XXX: test function pointer compatibility */
|
||||
type = bt1 == VT_FUNC ? type1 : type2;
|
||||
|
@ -4442,26 +4548,35 @@ static void expr_cond(void)
|
|||
(t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
|
||||
type.t |= VT_UNSIGNED;
|
||||
}
|
||||
|
||||
|
||||
/* now we convert second operand */
|
||||
gen_cast(&type);
|
||||
if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
||||
gaddrof();
|
||||
rc = RC_INT;
|
||||
if (is_float(type.t)) {
|
||||
ret_nregs = 0;
|
||||
if (VT_STRUCT == (type.t & VT_BTYPE)){
|
||||
ret_nregs = gfunc_sret(&type, func_var, &ret.type, &ret_align);
|
||||
if(ret_nregs)
|
||||
vtop->type = ret.type;
|
||||
else
|
||||
gaddrof();
|
||||
}
|
||||
|
||||
if (is_float(vtop->type.t)) {
|
||||
rc = RC_FLOAT;
|
||||
#ifdef TCC_TARGET_X86_64
|
||||
if ((type.t & VT_BTYPE) == VT_LDOUBLE) {
|
||||
rc = RC_ST0;
|
||||
}
|
||||
#endif
|
||||
} else if ((type.t & VT_BTYPE) == VT_LLONG) {
|
||||
/* for long longs, we use fixed registers to avoid having
|
||||
to handle a complicated move */
|
||||
rc = RC_IRET;
|
||||
}
|
||||
|
||||
r2 = gv(rc);
|
||||
} else
|
||||
rc = RC_INT;
|
||||
r = gv(rc);
|
||||
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))
|
||||
#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
|
||||
operand */
|
||||
tt = gjmp(0);
|
||||
|
@ -4469,12 +4584,21 @@ static void expr_cond(void)
|
|||
/* put again first value and cast it */
|
||||
*vtop = sv;
|
||||
gen_cast(&type);
|
||||
if (VT_STRUCT == (vtop->type.t & VT_BTYPE))
|
||||
gaddrof();
|
||||
r1 = gv(rc);
|
||||
move_reg(r2, r1, type.t);
|
||||
vtop->r = r2;
|
||||
if (VT_STRUCT == (type.t & VT_BTYPE)){
|
||||
if(ret_nregs)
|
||||
vtop->type = ret.type;
|
||||
else
|
||||
gaddrof();
|
||||
}
|
||||
gv(rc);
|
||||
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();
|
||||
} else {
|
||||
/* returning structure packed into registers */
|
||||
int rc, size, addr, align;
|
||||
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);
|
||||
}
|
||||
int rc;
|
||||
vtop->type = ret_type;
|
||||
if (is_float(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;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) {
|
||||
loc--;
|
||||
loc_stack(1, 1);
|
||||
}
|
||||
#endif
|
||||
loc = (loc - size) & -align;
|
||||
addr = loc;
|
||||
addr = loc_stack(size, 1);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* handles bounds */
|
||||
/* 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)) {
|
||||
unsigned long *bounds_ptr;
|
||||
/* add padding between regions */
|
||||
loc--;
|
||||
loc_stack(1, 1);
|
||||
/* then add local bound info */
|
||||
bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(unsigned long));
|
||||
bounds_ptr[0] = addr;
|
||||
|
|
51
x86_64-gen.c
51
x86_64-gen.c
|
@ -405,6 +405,14 @@ void load(int r, SValue *sv)
|
|||
|
||||
v = fr & VT_VALMASK;
|
||||
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) {
|
||||
v1.type.t = VT_PTR;
|
||||
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)
|
||||
{
|
||||
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
|
||||
|
||||
#define REGN 4
|
||||
|
@ -905,7 +928,7 @@ void gfunc_epilog(void)
|
|||
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
|
||||
/* align local size to word & save local variables */
|
||||
v = (func_scratch + -loc + 15) & -16;
|
||||
|
||||
reloc_use(r_loc, func_scratch);
|
||||
if (v >= 4096) {
|
||||
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
|
||||
oad(0xb8, v); /* mov stacksize, %eax */
|
||||
|
@ -1210,6 +1233,7 @@ doing:
|
|||
/* Must ensure TREG_ST0 only */
|
||||
if((vtop->type.t & VT_BTYPE) == VT_STRUCT){
|
||||
vdup();
|
||||
vtop[-1].r = VT_CONST;
|
||||
vtop->type = type;
|
||||
gv(RC_ST0);
|
||||
args_size -= size;
|
||||
|
@ -1228,7 +1252,7 @@ doing:
|
|||
vpushv(&vtop[-1]);
|
||||
vtop->type = char_pointer_type;
|
||||
gaddrof();
|
||||
vpushi(size);
|
||||
vpushs(size);
|
||||
struct_copy(&vtop[-2], &vtop[-1], &vtop[0]);
|
||||
vtop -= 3;
|
||||
break;
|
||||
|
@ -1474,6 +1498,7 @@ void gfunc_epilog(void)
|
|||
}
|
||||
/* align local size to word & save local variables */
|
||||
v = (func_scratch -loc + 15) & -16;
|
||||
reloc_use(r_loc, func_scratch);
|
||||
saved_ind = ind;
|
||||
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
|
||||
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 */
|
||||
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;
|
||||
r = gv(RC_INT); /* allocation size */
|
||||
/* sub r,%rsp */
|
||||
o(0x2b48);
|
||||
o(0xe0 | REG_VALUE(r));
|
||||
/* We align to 16 bytes rather than align */
|
||||
/* and ~15, %rsp */
|
||||
/* and ~15, %rsp */
|
||||
o(0xf0e48348);
|
||||
/* mov %rsp, r */
|
||||
o(0x8948);
|
||||
o(0xe0 | REG_VALUE(r));
|
||||
orex(1, 0, r, 0x8d);
|
||||
o(0x2484 | (REG_VALUE(r)*8));
|
||||
r_loc = reloc_add(r_loc);
|
||||
vpop();
|
||||
vset(type, r, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue