Improved variable length array support.
VLA storage is now freed when it goes out of scope. This makes it possible to use a VLA inside a loop without consuming an unlimited amount of memory. Combining VLAs with alloca() should work as in GCC - when a VLA is freed, memory allocated by alloca() after the VLA was created is also freed. There are some exceptions to this rule when using goto: if a VLA is in scope at the goto, jumping to a label will reset the stack pointer to where it was immediately after the last VLA was created prior to the label, or to what it was before the first VLA was created if the label is outside the scope of any VLA. This means that in some cases combining alloca() and VLAs will free alloca() memory where GCC would not.
This commit is contained in:
78
tccgen.c
78
tccgen.c
@ -55,6 +55,11 @@ ST_DATA Sym *define_stack;
|
||||
ST_DATA Sym *global_label_stack;
|
||||
ST_DATA Sym *local_label_stack;
|
||||
|
||||
ST_DATA int vla_sp_loc_tmp; /* vla_sp_loc is set to this when the value won't be needed later */
|
||||
ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */
|
||||
ST_DATA int *vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */
|
||||
ST_DATA int vla_flags; /* VLA_* flags */
|
||||
|
||||
ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop;
|
||||
|
||||
ST_DATA int const_wanted; /* true if constant wanted */
|
||||
@ -81,6 +86,7 @@ static int decl0(int l, int is_for_loop_init);
|
||||
static void expr_eq(void);
|
||||
static void unary_type(CType *type);
|
||||
static void vla_runtime_type_size(CType *type, int *a);
|
||||
static void vla_sp_save(void);
|
||||
static int is_compatible_parameter_types(CType *type1, CType *type2);
|
||||
static void expr_type(CType *type);
|
||||
|
||||
@ -2109,6 +2115,17 @@ 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_flags |= VLA_SP_LOC_SET;
|
||||
}
|
||||
if (!(vla_flags & VLA_SP_SAVED)) {
|
||||
gen_vla_sp_save(*vla_sp_loc);
|
||||
vla_flags |= VLA_SP_SAVED;
|
||||
}
|
||||
}
|
||||
|
||||
/* return the pointed type of t */
|
||||
static inline CType *pointed_type(CType *type)
|
||||
{
|
||||
@ -4484,6 +4501,16 @@ 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;
|
||||
|
||||
/* save VLA state */
|
||||
int block_vla_sp_loc = *vla_sp_loc;
|
||||
int *saved_vla_sp_loc = vla_sp_loc;
|
||||
if (saved_vla_sp_loc != &vla_sp_root_loc)
|
||||
vla_sp_loc = &block_vla_sp_loc;
|
||||
|
||||
int saved_vla_flags = vla_flags;
|
||||
vla_flags |= VLA_NEED_NEW_FRAME;
|
||||
|
||||
/* handle local labels declarations */
|
||||
if (tok == TOK_LABEL) {
|
||||
next();
|
||||
@ -4527,6 +4554,16 @@ 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);
|
||||
|
||||
/* 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;
|
||||
if (vla_sp_loc != (saved_vla_sp_loc == &vla_sp_root_loc ? &vla_sp_root_loc : &block_vla_sp_loc)) {
|
||||
vla_sp_loc = saved_vla_sp_loc;
|
||||
gen_vla_sp_restore(*vla_sp_loc);
|
||||
}
|
||||
vla_flags = (vla_flags & ~VLA_SCOPE_FLAGS) | (saved_vla_flags & VLA_SCOPE_FLAGS);
|
||||
|
||||
next();
|
||||
} else if (tok == TOK_RETURN) {
|
||||
next();
|
||||
@ -4731,6 +4768,13 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
s->r = LABEL_FORWARD;
|
||||
}
|
||||
/* label already defined */
|
||||
if (vla_flags & VLA_IN_SCOPE) {
|
||||
/* If VLAs are in use, save the current stack pointer and
|
||||
reset the stack pointer to what it was at function entry
|
||||
(label will restore stack pointer in inner scopes) */
|
||||
vla_sp_save();
|
||||
gen_vla_sp_restore(vla_sp_root_loc);
|
||||
}
|
||||
if (s->r & LABEL_FORWARD)
|
||||
s->jnext = gjmp(s->jnext);
|
||||
else
|
||||
@ -4746,6 +4790,12 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
b = is_label();
|
||||
if (b) {
|
||||
/* label case */
|
||||
if (vla_flags & VLA_IN_SCOPE) {
|
||||
/* save/restore stack pointer across label
|
||||
this is a no-op when combined with the load immediately
|
||||
after the label unless we arrive via goto */
|
||||
vla_sp_save();
|
||||
}
|
||||
s = label_find(b);
|
||||
if (s) {
|
||||
if (s->r == LABEL_DEFINED)
|
||||
@ -4756,6 +4806,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
|
||||
s = label_push(&global_label_stack, b, LABEL_DEFINED);
|
||||
}
|
||||
s->jnext = ind;
|
||||
if (vla_flags & VLA_IN_SCOPE) {
|
||||
gen_vla_sp_restore(*vla_sp_loc);
|
||||
vla_flags |= VLA_NEED_NEW_FRAME;
|
||||
}
|
||||
/* we accept this, but it is a mistake */
|
||||
block_after_label:
|
||||
if (tok == '}') {
|
||||
@ -5026,24 +5080,21 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
||||
CType *t1;
|
||||
|
||||
if (type->t & VT_VLA) {
|
||||
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
|
||||
int a;
|
||||
CValue retcval;
|
||||
|
||||
vpush_global_sym(&func_old_type, TOK_alloca);
|
||||
|
||||
/* save current stack pointer */
|
||||
if (vla_flags & VLA_NEED_NEW_FRAME) {
|
||||
vla_sp_save();
|
||||
vla_flags = VLA_IN_SCOPE;
|
||||
vla_sp_loc = &vla_sp_loc_tmp;
|
||||
}
|
||||
|
||||
vla_runtime_type_size(type, &a);
|
||||
gfunc_call(1);
|
||||
|
||||
/* return value */
|
||||
retcval.i = 0;
|
||||
vsetc(type, REG_IRET, &retcval);
|
||||
gen_vla_alloc(type, a);
|
||||
vset(type, VT_LOCAL|VT_LVAL, c);
|
||||
vswap();
|
||||
vstore();
|
||||
vpop();
|
||||
#else
|
||||
tcc_error("variable length arrays unsupported for this target");
|
||||
#endif
|
||||
} else if (type->t & VT_ARRAY) {
|
||||
s = type->ref;
|
||||
n = s->c;
|
||||
@ -5585,6 +5636,9 @@ static void gen_function(Sym *sym)
|
||||
put_extern_sym(sym, cur_text_section, ind, 0);
|
||||
funcname = get_tok_str(sym->v, NULL);
|
||||
func_ind = ind;
|
||||
/* Initialize VLA state */
|
||||
vla_sp_loc = &vla_sp_root_loc;
|
||||
vla_flags = VLA_NEED_NEW_FRAME;
|
||||
/* put debug symbol */
|
||||
if (tcc_state->do_debug)
|
||||
put_func_debug(sym);
|
||||
|
||||
Reference in New Issue
Block a user