mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-13 05:10:07 +08:00
introduce scopes for VLA & attribute cleanup
This commit is contained in:
parent
8227db3a23
commit
3d78918e63
401
tccgen.c
401
tccgen.c
@ -39,18 +39,12 @@ ST_DATA Sym *define_stack;
|
|||||||
ST_DATA Sym *global_label_stack;
|
ST_DATA Sym *global_label_stack;
|
||||||
ST_DATA Sym *local_label_stack;
|
ST_DATA Sym *local_label_stack;
|
||||||
|
|
||||||
static Sym *all_cleanups, *current_cleanups, *pending_gotos;
|
static Sym *all_cleanups, *pending_gotos;
|
||||||
static int ncleanups;
|
|
||||||
|
|
||||||
static int local_scope;
|
static int local_scope;
|
||||||
static int in_sizeof;
|
static int in_sizeof;
|
||||||
static int in_generic;
|
static int in_generic;
|
||||||
static int section_sym;
|
static int section_sym;
|
||||||
|
|
||||||
ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */
|
|
||||||
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 SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop;
|
ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop;
|
||||||
|
|
||||||
ST_DATA int const_wanted; /* true if constant wanted */
|
ST_DATA int const_wanted; /* true if constant wanted */
|
||||||
@ -91,6 +85,8 @@ ST_DATA struct switch_t {
|
|||||||
int sym;
|
int sym;
|
||||||
} **p; int n; /* list of case ranges */
|
} **p; int n; /* list of case ranges */
|
||||||
int def_sym; /* default symbol */
|
int def_sym; /* default symbol */
|
||||||
|
int *bsym;
|
||||||
|
struct scope *scope;
|
||||||
} *cur_switch; /* current switch */
|
} *cur_switch; /* current switch */
|
||||||
|
|
||||||
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4
|
#define MAX_TEMP_LOCAL_VARIABLE_NUMBER 0x4
|
||||||
@ -102,6 +98,14 @@ ST_DATA struct temp_local_variable {
|
|||||||
} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
|
} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];
|
||||||
short nb_temp_local_vars;
|
short nb_temp_local_vars;
|
||||||
|
|
||||||
|
static struct scope {
|
||||||
|
struct scope *prev;
|
||||||
|
struct { int loc, num; } vla;
|
||||||
|
struct { Sym *s; int n; } cl;
|
||||||
|
int *bsym, *csym;
|
||||||
|
Sym *lstk, *llstk;
|
||||||
|
} *cur_scope, *loop_scope, *root_scope;
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static void gen_cast(CType *type);
|
static void gen_cast(CType *type);
|
||||||
@ -113,14 +117,12 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);
|
|||||||
static void parse_expr_type(CType *type);
|
static void parse_expr_type(CType *type);
|
||||||
static void init_putv(CType *type, Section *sec, unsigned long c);
|
static void init_putv(CType *type, Section *sec, unsigned long c);
|
||||||
static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags);
|
static void decl_initializer(CType *type, Section *sec, unsigned long c, int flags);
|
||||||
static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr);
|
static void block(int is_expr);
|
||||||
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
|
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);
|
||||||
static void decl(int l);
|
static void decl(int l);
|
||||||
static int decl0(int l, int is_for_loop_init, Sym *);
|
static int decl0(int l, int is_for_loop_init, Sym *);
|
||||||
static void expr_eq(void);
|
static void expr_eq(void);
|
||||||
static void vla_runtime_type_size(CType *type, int *a);
|
static void vla_runtime_type_size(CType *type, int *a);
|
||||||
static void vla_sp_restore(void);
|
|
||||||
static void vla_sp_restore_root(void);
|
|
||||||
static int is_compatible_unqualified_types(CType *type1, CType *type2);
|
static int is_compatible_unqualified_types(CType *type1, CType *type2);
|
||||||
static inline int64_t expr_const64(void);
|
static inline int64_t expr_const64(void);
|
||||||
static void vpush64(int ty, unsigned long long v);
|
static void vpush64(int ty, unsigned long long v);
|
||||||
@ -132,15 +134,6 @@ static void gv_dup(void);
|
|||||||
static int get_temp_local_var(int size,int align);
|
static int get_temp_local_var(int size,int align);
|
||||||
static void clear_temp_local_var_list();
|
static void clear_temp_local_var_list();
|
||||||
|
|
||||||
|
|
||||||
static void reset_local_scope(void)
|
|
||||||
{
|
|
||||||
if (current_cleanups)
|
|
||||||
tcc_error("ICE current_cleanups");
|
|
||||||
sym_pop(&all_cleanups, NULL, 0);
|
|
||||||
local_scope = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_INLN int is_float(int t)
|
ST_INLN int is_float(int t)
|
||||||
{
|
{
|
||||||
int bt;
|
int bt;
|
||||||
@ -2937,18 +2930,6 @@ ST_FUNC void vla_runtime_type_size(CType *type, int *a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vla_sp_restore(void) {
|
|
||||||
if (vlas_in_scope) {
|
|
||||||
gen_vla_sp_restore(vla_sp_loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vla_sp_restore_root(void) {
|
|
||||||
if (vlas_in_scope) {
|
|
||||||
gen_vla_sp_restore(vla_sp_root_loc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return the pointed type of t */
|
/* return the pointed type of t */
|
||||||
static inline CType *pointed_type(CType *type)
|
static inline CType *pointed_type(CType *type)
|
||||||
{
|
{
|
||||||
@ -4843,43 +4824,6 @@ static void parse_builtin_params(int nc, const char *args)
|
|||||||
nocode_wanted--;
|
nocode_wanted--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void try_call_scope_cleanup(Sym *stop)
|
|
||||||
{
|
|
||||||
Sym *cls = current_cleanups;
|
|
||||||
|
|
||||||
for (; cls != stop; cls = cls->ncl) {
|
|
||||||
Sym *fs = cls->next;
|
|
||||||
Sym *vs = cls->prev_tok;
|
|
||||||
|
|
||||||
vpushsym(&fs->type, fs);
|
|
||||||
vset(&vs->type, vs->r, vs->c);
|
|
||||||
vtop->sym = vs;
|
|
||||||
mk_pointer(&vtop->type);
|
|
||||||
gaddrof();
|
|
||||||
gfunc_call(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void try_call_cleanup_goto(Sym *cleanupstate)
|
|
||||||
{
|
|
||||||
Sym *oc, *cc;
|
|
||||||
int ocd, ccd;
|
|
||||||
|
|
||||||
if (!current_cleanups)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* search NCA of both cleanup chains given parents and initial depth */
|
|
||||||
ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
|
|
||||||
for (ccd = ncleanups, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl)
|
|
||||||
;
|
|
||||||
for (cc = current_cleanups; ccd > ocd; --ccd, cc = cc->ncl)
|
|
||||||
;
|
|
||||||
for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)
|
|
||||||
;
|
|
||||||
|
|
||||||
try_call_scope_cleanup(cc);
|
|
||||||
}
|
|
||||||
|
|
||||||
ST_FUNC void unary(void)
|
ST_FUNC void unary(void)
|
||||||
{
|
{
|
||||||
int n, t, align, size, r, sizeof_caller;
|
int n, t, align, size, r, sizeof_caller;
|
||||||
@ -5015,7 +4959,7 @@ ST_FUNC void unary(void)
|
|||||||
as statement expressions can't ever be entered from the
|
as statement expressions can't ever be entered from the
|
||||||
outside, so any reactivation of code emission (from labels
|
outside, so any reactivation of code emission (from labels
|
||||||
or loop heads) can be disabled again after the end of it. */
|
or loop heads) can be disabled again after the end of it. */
|
||||||
block(NULL, NULL, NULL, NULL, 1);
|
block(1);
|
||||||
nocode_wanted = saved_nocode_wanted;
|
nocode_wanted = saved_nocode_wanted;
|
||||||
skip(')');
|
skip(')');
|
||||||
} else {
|
} else {
|
||||||
@ -6134,6 +6078,24 @@ static void gfunc_return(CType *func_type)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void check_func_return(void)
|
||||||
|
{
|
||||||
|
if ((func_vt.t & VT_BTYPE) == VT_VOID)
|
||||||
|
return;
|
||||||
|
if (!strcmp (funcname, "main")
|
||||||
|
&& (func_vt.t & VT_BTYPE) == VT_INT) {
|
||||||
|
/* main returns 0 by default */
|
||||||
|
vpushi(0);
|
||||||
|
gen_assign_cast(&func_vt);
|
||||||
|
gfunc_return(&func_vt);
|
||||||
|
} else {
|
||||||
|
tcc_warning("function might return no value: '%s'", funcname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* switch/case */
|
||||||
|
|
||||||
static int case_cmp(const void *pa, const void *pb)
|
static int case_cmp(const void *pa, const void *pb)
|
||||||
{
|
{
|
||||||
int64_t a = (*(struct case_t**) pa)->v1;
|
int64_t a = (*(struct case_t**) pa)->v1;
|
||||||
@ -6202,22 +6164,62 @@ static void gcase(struct case_t **base, int len, int *bsym)
|
|||||||
*bsym = gjmp(*bsym);
|
*bsym = gjmp(*bsym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* __attribute__((cleanup(fn))) */
|
||||||
|
|
||||||
|
static void try_call_scope_cleanup(Sym *stop)
|
||||||
|
{
|
||||||
|
Sym *cls = cur_scope->cl.s;
|
||||||
|
|
||||||
|
for (; cls != stop; cls = cls->ncl) {
|
||||||
|
Sym *fs = cls->next;
|
||||||
|
Sym *vs = cls->prev_tok;
|
||||||
|
|
||||||
|
vpushsym(&fs->type, fs);
|
||||||
|
vset(&vs->type, vs->r, vs->c);
|
||||||
|
vtop->sym = vs;
|
||||||
|
mk_pointer(&vtop->type);
|
||||||
|
gaddrof();
|
||||||
|
gfunc_call(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void try_call_cleanup_goto(Sym *cleanupstate)
|
||||||
|
{
|
||||||
|
Sym *oc, *cc;
|
||||||
|
int ocd, ccd;
|
||||||
|
|
||||||
|
if (!cur_scope->cl.s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* search NCA of both cleanup chains given parents and initial depth */
|
||||||
|
ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0;
|
||||||
|
for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl)
|
||||||
|
;
|
||||||
|
for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl)
|
||||||
|
;
|
||||||
|
for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd)
|
||||||
|
;
|
||||||
|
|
||||||
|
try_call_scope_cleanup(cc);
|
||||||
|
}
|
||||||
|
|
||||||
/* call 'func' for each __attribute__((cleanup(func))) */
|
/* call 'func' for each __attribute__((cleanup(func))) */
|
||||||
static void block_cleanup(Sym *lcleanup, int lncleanups)
|
static void block_cleanup(struct scope *o)
|
||||||
{
|
{
|
||||||
int jmp = 0;
|
int jmp = 0;
|
||||||
Sym *g, **pg;
|
Sym *g, **pg;
|
||||||
for (pg = &pending_gotos; (g = *pg) && g->c > lncleanups;) {
|
for (pg = &pending_gotos; (g = *pg) && g->c > o->cl.n;) {
|
||||||
if (g->prev_tok->r & LABEL_FORWARD) {
|
if (g->prev_tok->r & LABEL_FORWARD) {
|
||||||
Sym *pcl = g->next;
|
Sym *pcl = g->next;
|
||||||
if (!jmp)
|
if (!jmp)
|
||||||
jmp = gjmp(0);
|
jmp = gjmp(0);
|
||||||
gsym(pcl->jnext);
|
gsym(pcl->jnext);
|
||||||
try_call_scope_cleanup(lcleanup);
|
try_call_scope_cleanup(o->cl.s);
|
||||||
pcl->jnext = gjmp(0);
|
pcl->jnext = gjmp(0);
|
||||||
if (!lncleanups)
|
if (!o->cl.n)
|
||||||
goto remove_pending;
|
goto remove_pending;
|
||||||
g->c = lncleanups;
|
g->c = o->cl.n;
|
||||||
pg = &g->prev;
|
pg = &g->prev;
|
||||||
} else {
|
} else {
|
||||||
remove_pending:
|
remove_pending:
|
||||||
@ -6226,27 +6228,96 @@ static void block_cleanup(Sym *lcleanup, int lncleanups)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
gsym(jmp);
|
gsym(jmp);
|
||||||
try_call_scope_cleanup(lcleanup);
|
try_call_scope_cleanup(o->cl.s);
|
||||||
current_cleanups = lcleanup;
|
|
||||||
ncleanups = lncleanups;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_func_return(void)
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* VLA */
|
||||||
|
|
||||||
|
static void vla_restore(int loc)
|
||||||
{
|
{
|
||||||
if ((func_vt.t & VT_BTYPE) == VT_VOID)
|
if (loc)
|
||||||
|
gen_vla_sp_restore(loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vla_leave(struct scope *o)
|
||||||
|
{
|
||||||
|
if (o->vla.num < cur_scope->vla.num)
|
||||||
|
vla_restore(o->vla.loc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/* local scopes */
|
||||||
|
|
||||||
|
void new_scope(struct scope *o)
|
||||||
|
{
|
||||||
|
/* copy and link previous scope */
|
||||||
|
*o = *cur_scope;
|
||||||
|
o->prev = cur_scope;
|
||||||
|
cur_scope = o;
|
||||||
|
|
||||||
|
/* record local declaration stack position */
|
||||||
|
o->lstk = local_stack;
|
||||||
|
o->llstk = local_label_stack;
|
||||||
|
|
||||||
|
++local_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prev_scope(struct scope *o, int is_expr)
|
||||||
|
{
|
||||||
|
vla_leave(o->prev);
|
||||||
|
|
||||||
|
if (o->cl.s != o->prev->cl.s)
|
||||||
|
block_cleanup(o->prev);
|
||||||
|
|
||||||
|
/* pop locally defined labels */
|
||||||
|
label_pop(&local_label_stack, o->llstk, is_expr);
|
||||||
|
|
||||||
|
/* In the is_expr case (a statement expression is finished here),
|
||||||
|
vtop might refer to symbols on the local_stack. Either via the
|
||||||
|
type or via vtop->sym. We can't pop those nor any that in turn
|
||||||
|
might be referred to. To make it easier we don't roll back
|
||||||
|
any symbols in that case; some upper level call to block() will
|
||||||
|
do that. We do have to remove such symbols from the lookup
|
||||||
|
tables, though. sym_pop will do that. */
|
||||||
|
|
||||||
|
/* pop locally defined symbols */
|
||||||
|
sym_pop(&local_stack, o->lstk, is_expr);
|
||||||
|
|
||||||
|
cur_scope = o->prev;
|
||||||
|
--local_scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* leave a scope via break/continue(/goto) */
|
||||||
|
void leave_scope(struct scope *o)
|
||||||
|
{
|
||||||
|
if (!o)
|
||||||
return;
|
return;
|
||||||
if (!strcmp (funcname, "main")
|
try_call_scope_cleanup(o->cl.s);
|
||||||
&& (func_vt.t & VT_BTYPE) == VT_INT) {
|
vla_leave(o);
|
||||||
/* main returns 0 by default */
|
}
|
||||||
vpushi(0);
|
|
||||||
gen_assign_cast(&func_vt);
|
/* ------------------------------------------------------------------------- */
|
||||||
gfunc_return(&func_vt);
|
/* call block from 'for do while' loops */
|
||||||
} else {
|
|
||||||
tcc_warning("function might return no value: '%s'", funcname);
|
static void lblock(int *bsym, int *csym)
|
||||||
|
{
|
||||||
|
struct scope *lo = loop_scope, *co = cur_scope;
|
||||||
|
int *b = co->bsym, *c = co->csym;
|
||||||
|
if (csym) {
|
||||||
|
co->csym = csym;
|
||||||
|
loop_scope = co;
|
||||||
|
}
|
||||||
|
co->bsym = bsym;
|
||||||
|
block(0);
|
||||||
|
co->bsym = b;
|
||||||
|
if (csym) {
|
||||||
|
co->csym = c;
|
||||||
|
loop_scope = lo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
static void block(int is_expr)
|
||||||
{
|
{
|
||||||
int a, b, c, d, e, t;
|
int a, b, c, d, e, t;
|
||||||
Sym *s;
|
Sym *s;
|
||||||
@ -6257,6 +6328,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
vtop->type.t = VT_VOID;
|
vtop->type.t = VT_VOID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
again:
|
||||||
t = tok, next();
|
t = tok, next();
|
||||||
|
|
||||||
if (t == TOK_IF) {
|
if (t == TOK_IF) {
|
||||||
@ -6264,12 +6336,12 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
gexpr();
|
gexpr();
|
||||||
skip(')');
|
skip(')');
|
||||||
a = gvtst(1, 0);
|
a = gvtst(1, 0);
|
||||||
block(bsym, bcl, csym, ccl, 0);
|
block(0);
|
||||||
if (tok == TOK_ELSE) {
|
if (tok == TOK_ELSE) {
|
||||||
d = gjmp(0);
|
d = gjmp(0);
|
||||||
gsym(a);
|
gsym(a);
|
||||||
next();
|
next();
|
||||||
block(bsym, bcl, csym, ccl, 0);
|
block(0);
|
||||||
gsym(d); /* patch else jmp */
|
gsym(d); /* patch else jmp */
|
||||||
} else {
|
} else {
|
||||||
gsym(a);
|
gsym(a);
|
||||||
@ -6277,27 +6349,19 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
|
|
||||||
} else if (t == TOK_WHILE) {
|
} else if (t == TOK_WHILE) {
|
||||||
d = gind();
|
d = gind();
|
||||||
vla_sp_restore();
|
|
||||||
skip('(');
|
skip('(');
|
||||||
gexpr();
|
gexpr();
|
||||||
skip(')');
|
skip(')');
|
||||||
a = gvtst(1, 0);
|
a = gvtst(1, 0);
|
||||||
b = 0;
|
b = 0;
|
||||||
block(&a, current_cleanups, &b, current_cleanups, 0);
|
lblock(&a, &b);
|
||||||
gjmp_addr(d);
|
gjmp_addr(d);
|
||||||
gsym_addr(b, d);
|
gsym_addr(b, d);
|
||||||
gsym(a);
|
gsym(a);
|
||||||
|
|
||||||
} else if (t == '{') {
|
} else if (t == '{') {
|
||||||
Sym *llabel, *lcleanup;
|
struct scope o;
|
||||||
int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope;
|
new_scope(&o);
|
||||||
int lncleanups = ncleanups;
|
|
||||||
|
|
||||||
/* record local declaration stack position */
|
|
||||||
s = local_stack;
|
|
||||||
llabel = local_label_stack;
|
|
||||||
lcleanup = current_cleanups;
|
|
||||||
++local_scope;
|
|
||||||
|
|
||||||
/* handle local labels declarations */
|
/* handle local labels declarations */
|
||||||
while (tok == TOK_LABEL) {
|
while (tok == TOK_LABEL) {
|
||||||
@ -6316,35 +6380,13 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
if (tok != '}') {
|
if (tok != '}') {
|
||||||
if (is_expr)
|
if (is_expr)
|
||||||
vpop();
|
vpop();
|
||||||
block(bsym, bcl, csym, ccl, is_expr);
|
block(is_expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_cleanups != lcleanup)
|
prev_scope(&o, is_expr);
|
||||||
block_cleanup(lcleanup, lncleanups);
|
|
||||||
|
|
||||||
/* pop locally defined labels */
|
if (0 == local_scope && !nocode_wanted)
|
||||||
label_pop(&local_label_stack, llabel, is_expr);
|
|
||||||
|
|
||||||
/* In the is_expr case (a statement expression is finished here),
|
|
||||||
vtop might refer to symbols on the local_stack. Either via the
|
|
||||||
type or via vtop->sym. We can't pop those nor any that in turn
|
|
||||||
might be referred to. To make it easier we don't roll back
|
|
||||||
any symbols in that case; some upper level call to block() will
|
|
||||||
do that. We do have to remove such symbols from the lookup
|
|
||||||
tables, though. sym_pop will do that. */
|
|
||||||
|
|
||||||
/* pop locally defined symbols */
|
|
||||||
sym_pop(&local_stack, s, is_expr);
|
|
||||||
|
|
||||||
/* Pop VLA frames and restore stack pointer if required */
|
|
||||||
if (vlas_in_scope > saved_vlas_in_scope) {
|
|
||||||
vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc;
|
|
||||||
vla_sp_restore();
|
|
||||||
}
|
|
||||||
vlas_in_scope = saved_vlas_in_scope;
|
|
||||||
|
|
||||||
if (0 == --local_scope && !nocode_wanted)
|
|
||||||
check_func_return();
|
check_func_return();
|
||||||
next();
|
next();
|
||||||
|
|
||||||
@ -6353,7 +6395,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
b = (func_vt.t & VT_BTYPE) != VT_VOID;
|
b = (func_vt.t & VT_BTYPE) != VT_VOID;
|
||||||
if (a)
|
if (a)
|
||||||
gexpr(), gen_assign_cast(&func_vt);
|
gexpr(), gen_assign_cast(&func_vt);
|
||||||
try_call_scope_cleanup(NULL);
|
leave_scope(root_scope);
|
||||||
if (a && b)
|
if (a && b)
|
||||||
gfunc_return(&func_vt);
|
gfunc_return(&func_vt);
|
||||||
else if (a)
|
else if (a)
|
||||||
@ -6368,28 +6410,28 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
|
|
||||||
} else if (t == TOK_BREAK) {
|
} else if (t == TOK_BREAK) {
|
||||||
/* compute jump */
|
/* compute jump */
|
||||||
if (!bsym)
|
if (!cur_scope->bsym)
|
||||||
tcc_error("cannot break");
|
tcc_error("cannot break");
|
||||||
try_call_scope_cleanup(bcl);
|
if (!cur_switch || cur_scope->bsym != cur_switch->bsym)
|
||||||
*bsym = gjmp(*bsym);
|
leave_scope(loop_scope);
|
||||||
|
else
|
||||||
|
leave_scope(cur_switch->scope);
|
||||||
|
*cur_scope->bsym = gjmp(*cur_scope->bsym);
|
||||||
skip(';');
|
skip(';');
|
||||||
|
|
||||||
} else if (t == TOK_CONTINUE) {
|
} else if (t == TOK_CONTINUE) {
|
||||||
/* compute jump */
|
/* compute jump */
|
||||||
if (!csym)
|
if (!cur_scope->csym)
|
||||||
tcc_error("cannot continue");
|
tcc_error("cannot continue");
|
||||||
try_call_scope_cleanup(ccl);
|
leave_scope(loop_scope);
|
||||||
vla_sp_restore_root();
|
*cur_scope->csym = gjmp(*cur_scope->csym);
|
||||||
*csym = gjmp(*csym);
|
|
||||||
skip(';');
|
skip(';');
|
||||||
|
|
||||||
} else if (t == TOK_FOR) {
|
} else if (t == TOK_FOR) {
|
||||||
Sym *lcleanup = current_cleanups;
|
struct scope o;
|
||||||
int lncleanups = ncleanups;
|
new_scope(&o);
|
||||||
|
|
||||||
skip('(');
|
skip('(');
|
||||||
s = local_stack;
|
|
||||||
++local_scope;
|
|
||||||
if (tok != ';') {
|
if (tok != ';') {
|
||||||
/* c99 for-loop init decl? */
|
/* c99 for-loop init decl? */
|
||||||
if (!decl0(VT_LOCAL, 1, NULL)) {
|
if (!decl0(VT_LOCAL, 1, NULL)) {
|
||||||
@ -6401,7 +6443,6 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
skip(';');
|
skip(';');
|
||||||
a = b = 0;
|
a = b = 0;
|
||||||
c = d = gind();
|
c = d = gind();
|
||||||
vla_sp_restore();
|
|
||||||
if (tok != ';') {
|
if (tok != ';') {
|
||||||
gexpr();
|
gexpr();
|
||||||
a = gvtst(1, 0);
|
a = gvtst(1, 0);
|
||||||
@ -6410,28 +6451,22 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
if (tok != ')') {
|
if (tok != ')') {
|
||||||
e = gjmp(0);
|
e = gjmp(0);
|
||||||
d = gind();
|
d = gind();
|
||||||
vla_sp_restore();
|
|
||||||
gexpr();
|
gexpr();
|
||||||
vpop();
|
vpop();
|
||||||
gjmp_addr(c);
|
gjmp_addr(c);
|
||||||
gsym(e);
|
gsym(e);
|
||||||
}
|
}
|
||||||
skip(')');
|
skip(')');
|
||||||
block(&a, current_cleanups, &b, current_cleanups, 0);
|
lblock(&a, &b);
|
||||||
gjmp_addr(d);
|
gjmp_addr(d);
|
||||||
gsym_addr(b, d);
|
gsym_addr(b, d);
|
||||||
gsym(a);
|
gsym(a);
|
||||||
--local_scope;
|
prev_scope(&o, 0);
|
||||||
try_call_scope_cleanup(lcleanup);
|
|
||||||
ncleanups = lncleanups;
|
|
||||||
current_cleanups = lcleanup;
|
|
||||||
sym_pop(&local_stack, s, 0);
|
|
||||||
|
|
||||||
} else if (t == TOK_DO) {
|
} else if (t == TOK_DO) {
|
||||||
a = b = 0;
|
a = b = 0;
|
||||||
d = gind();
|
d = gind();
|
||||||
vla_sp_restore();
|
lblock(&a, &b);
|
||||||
block(&a, current_cleanups, &b, current_cleanups, 0);
|
|
||||||
gsym(b);
|
gsym(b);
|
||||||
skip(TOK_WHILE);
|
skip(TOK_WHILE);
|
||||||
skip('(');
|
skip('(');
|
||||||
@ -6446,17 +6481,23 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
struct switch_t *saved, sw;
|
struct switch_t *saved, sw;
|
||||||
SValue switchval;
|
SValue switchval;
|
||||||
|
|
||||||
|
sw.p = NULL;
|
||||||
|
sw.n = 0;
|
||||||
|
sw.def_sym = 0;
|
||||||
|
sw.bsym = &a;
|
||||||
|
sw.scope = cur_scope;
|
||||||
|
|
||||||
|
saved = cur_switch;
|
||||||
|
cur_switch = &sw;
|
||||||
|
|
||||||
skip('(');
|
skip('(');
|
||||||
gexpr();
|
gexpr();
|
||||||
skip(')');
|
skip(')');
|
||||||
switchval = *vtop--;
|
switchval = *vtop--;
|
||||||
|
|
||||||
sw.p = NULL; sw.n = 0; sw.def_sym = 0;
|
|
||||||
saved = cur_switch;
|
|
||||||
cur_switch = &sw;
|
|
||||||
a = 0;
|
a = 0;
|
||||||
b = gjmp(0); /* jump to first case */
|
b = gjmp(0); /* jump to first case */
|
||||||
block(&a, current_cleanups, csym, ccl, 0);
|
lblock(&a, NULL);
|
||||||
a = gjmp(a); /* add implicit break */
|
a = gjmp(a); /* add implicit break */
|
||||||
/* case lookup */
|
/* case lookup */
|
||||||
gsym(b);
|
gsym(b);
|
||||||
@ -6465,6 +6506,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
for (b = 1; b < sw.n; b++)
|
for (b = 1; b < sw.n; b++)
|
||||||
if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
|
if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
|
||||||
tcc_error("duplicate case value");
|
tcc_error("duplicate case value");
|
||||||
|
|
||||||
/* Our switch table sorting is signed, so the compared
|
/* Our switch table sorting is signed, so the compared
|
||||||
value needs to be as well when it's 64bit. */
|
value needs to be as well when it's 64bit. */
|
||||||
if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
|
if ((switchval.type.t & VT_BTYPE) == VT_LLONG)
|
||||||
@ -6479,6 +6521,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
gsym(d);
|
gsym(d);
|
||||||
/* break label */
|
/* break label */
|
||||||
gsym(a);
|
gsym(a);
|
||||||
|
|
||||||
dynarray_reset(&sw.p, &sw.n);
|
dynarray_reset(&sw.p, &sw.n);
|
||||||
cur_switch = saved;
|
cur_switch = saved;
|
||||||
|
|
||||||
@ -6510,6 +6553,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
goto block_after_label;
|
goto block_after_label;
|
||||||
|
|
||||||
} else if (t == TOK_GOTO) {
|
} else if (t == TOK_GOTO) {
|
||||||
|
vla_restore(root_scope->vla.loc);
|
||||||
if (tok == '*' && gnu_ext) {
|
if (tok == '*' && gnu_ext) {
|
||||||
/* computed goto */
|
/* computed goto */
|
||||||
next();
|
next();
|
||||||
@ -6517,6 +6561,7 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
if ((vtop->type.t & VT_BTYPE) != VT_PTR)
|
if ((vtop->type.t & VT_BTYPE) != VT_PTR)
|
||||||
expect("pointer");
|
expect("pointer");
|
||||||
ggoto();
|
ggoto();
|
||||||
|
|
||||||
} else if (tok >= TOK_UIDENT) {
|
} else if (tok >= TOK_UIDENT) {
|
||||||
s = label_find(tok);
|
s = label_find(tok);
|
||||||
/* put forward definition if needed */
|
/* put forward definition if needed */
|
||||||
@ -6525,11 +6570,10 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
else if (s->r == LABEL_DECLARED)
|
else if (s->r == LABEL_DECLARED)
|
||||||
s->r = LABEL_FORWARD;
|
s->r = LABEL_FORWARD;
|
||||||
|
|
||||||
vla_sp_restore_root();
|
|
||||||
if (s->r & LABEL_FORWARD) {
|
if (s->r & LABEL_FORWARD) {
|
||||||
/* start new goto chain for cleanups, linked via label->next */
|
/* start new goto chain for cleanups, linked via label->next */
|
||||||
if (current_cleanups) {
|
if (cur_scope->cl.s && !nocode_wanted) {
|
||||||
sym_push2(&pending_gotos, SYM_FIELD, 0, ncleanups);
|
sym_push2(&pending_gotos, SYM_FIELD, 0, cur_scope->cl.n);
|
||||||
pending_gotos->prev_tok = s;
|
pending_gotos->prev_tok = s;
|
||||||
s = sym_push2(&s->next, SYM_FIELD, 0, 0);
|
s = sym_push2(&s->next, SYM_FIELD, 0, 0);
|
||||||
pending_gotos->next = s;
|
pending_gotos->next = s;
|
||||||
@ -6569,17 +6613,15 @@ static void block(int *bsym, Sym *bcl, int *csym, Sym *ccl, int is_expr)
|
|||||||
s = label_push(&global_label_stack, t, LABEL_DEFINED);
|
s = label_push(&global_label_stack, t, LABEL_DEFINED);
|
||||||
}
|
}
|
||||||
s->jnext = gind();
|
s->jnext = gind();
|
||||||
s->cleanupstate = current_cleanups;
|
s->cleanupstate = cur_scope->cl.s;
|
||||||
|
|
||||||
block_after_label:
|
block_after_label:
|
||||||
vla_sp_restore();
|
vla_restore(cur_scope->vla.loc);
|
||||||
/* we accept this, but it is a mistake */
|
/* we accept this, but it is a mistake */
|
||||||
if (tok == '}') {
|
if (tok == '}') {
|
||||||
tcc_warning("deprecated use of label at end of compound statement");
|
tcc_warning("deprecated use of label at end of compound statement");
|
||||||
} else {
|
} else {
|
||||||
if (is_expr)
|
goto again;
|
||||||
vpop();
|
|
||||||
block(bsym, bcl, csym, ccl, is_expr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -7317,11 +7359,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
#endif
|
#endif
|
||||||
sym = sym_push(v, type, r, addr);
|
sym = sym_push(v, type, r, addr);
|
||||||
if (ad->cleanup_func) {
|
if (ad->cleanup_func) {
|
||||||
Sym *cls = sym_push2(&all_cleanups, SYM_FIELD | ++ncleanups, 0, 0);
|
Sym *cls = sym_push2(&all_cleanups,
|
||||||
|
SYM_FIELD | ++cur_scope->cl.n, 0, 0);
|
||||||
cls->prev_tok = sym;
|
cls->prev_tok = sym;
|
||||||
cls->next = ad->cleanup_func;
|
cls->next = ad->cleanup_func;
|
||||||
cls->ncl = current_cleanups;
|
cls->ncl = cur_scope->cl.s;
|
||||||
current_cleanups = cls;
|
cur_scope->cl.s = cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
sym->a = ad->a;
|
sym->a = ad->a;
|
||||||
@ -7398,10 +7441,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
goto no_alloc;
|
goto no_alloc;
|
||||||
|
|
||||||
/* save current stack pointer */
|
/* save current stack pointer */
|
||||||
if (vlas_in_scope == 0) {
|
if (root_scope->vla.loc == 0) {
|
||||||
if (vla_sp_root_loc == -1)
|
struct scope *v = cur_scope;
|
||||||
vla_sp_root_loc = (loc -= PTR_SIZE);
|
gen_vla_sp_save(loc -= PTR_SIZE);
|
||||||
gen_vla_sp_save(vla_sp_root_loc);
|
do v->vla.loc = loc; while ((v = v->prev));
|
||||||
}
|
}
|
||||||
|
|
||||||
vla_runtime_type_size(type, &a);
|
vla_runtime_type_size(type, &a);
|
||||||
@ -7412,8 +7455,8 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
gen_vla_result(addr), addr = (loc -= PTR_SIZE);
|
gen_vla_result(addr), addr = (loc -= PTR_SIZE);
|
||||||
#endif
|
#endif
|
||||||
gen_vla_sp_save(addr);
|
gen_vla_sp_save(addr);
|
||||||
vla_sp_loc = addr;
|
cur_scope->vla.loc = addr;
|
||||||
vlas_in_scope++;
|
cur_scope->vla.num++;
|
||||||
|
|
||||||
} else if (has_init) {
|
} else if (has_init) {
|
||||||
size_t oldreloc_offset = 0;
|
size_t oldreloc_offset = 0;
|
||||||
@ -7442,6 +7485,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
|
|||||||
'cur_text_section' */
|
'cur_text_section' */
|
||||||
static void gen_function(Sym *sym)
|
static void gen_function(Sym *sym)
|
||||||
{
|
{
|
||||||
|
/* Initialize VLA state */
|
||||||
|
struct scope f = { 0 };
|
||||||
|
cur_scope = root_scope = &f;
|
||||||
|
|
||||||
nocode_wanted = 0;
|
nocode_wanted = 0;
|
||||||
ind = cur_text_section->data_offset;
|
ind = cur_text_section->data_offset;
|
||||||
if (sym->a.aligned) {
|
if (sym->a.aligned) {
|
||||||
@ -7451,32 +7498,32 @@ static void gen_function(Sym *sym)
|
|||||||
}
|
}
|
||||||
/* NOTE: we patch the symbol size later */
|
/* NOTE: we patch the symbol size later */
|
||||||
put_extern_sym(sym, cur_text_section, ind, 0);
|
put_extern_sym(sym, cur_text_section, ind, 0);
|
||||||
|
|
||||||
funcname = get_tok_str(sym->v, NULL);
|
funcname = get_tok_str(sym->v, NULL);
|
||||||
func_ind = ind;
|
func_ind = ind;
|
||||||
/* Initialize VLA state */
|
|
||||||
vla_sp_loc = -1;
|
|
||||||
vla_sp_root_loc = -1;
|
|
||||||
/* put debug symbol */
|
/* put debug symbol */
|
||||||
tcc_debug_funcstart(tcc_state, sym);
|
tcc_debug_funcstart(tcc_state, sym);
|
||||||
/* push a dummy symbol to enable local sym storage */
|
/* push a dummy symbol to enable local sym storage */
|
||||||
sym_push2(&local_stack, SYM_FIELD, 0, 0);
|
sym_push2(&local_stack, SYM_FIELD, 0, 0);
|
||||||
local_scope = 1; /* for function parameters */
|
local_scope = 1; /* for function parameters */
|
||||||
gfunc_prolog(&sym->type);
|
gfunc_prolog(&sym->type);
|
||||||
reset_local_scope();
|
local_scope = 0;
|
||||||
rsym = 0;
|
rsym = 0;
|
||||||
clear_temp_local_var_list();
|
clear_temp_local_var_list();
|
||||||
block(NULL, NULL, NULL, NULL, 0);
|
block(0);
|
||||||
gsym(rsym);
|
gsym(rsym);
|
||||||
nocode_wanted = 0;
|
nocode_wanted = 0;
|
||||||
gfunc_epilog();
|
gfunc_epilog();
|
||||||
cur_text_section->data_offset = ind;
|
cur_text_section->data_offset = ind;
|
||||||
label_pop(&global_label_stack, NULL, 0);
|
|
||||||
/* reset local stack */
|
/* reset local stack */
|
||||||
reset_local_scope();
|
|
||||||
sym_pop(&local_stack, NULL, 0);
|
sym_pop(&local_stack, NULL, 0);
|
||||||
/* end of function */
|
local_scope = 0;
|
||||||
|
label_pop(&global_label_stack, NULL, 0);
|
||||||
|
sym_pop(&all_cleanups, NULL, 0);
|
||||||
/* patch symbol size */
|
/* patch symbol size */
|
||||||
elfsym(sym)->st_size = ind - func_ind;
|
elfsym(sym)->st_size = ind - func_ind;
|
||||||
|
/* end of function */
|
||||||
tcc_debug_funcend(tcc_state, ind - func_ind);
|
tcc_debug_funcend(tcc_state, ind - func_ind);
|
||||||
/* It's better to crash than to generate wrong code */
|
/* It's better to crash than to generate wrong code */
|
||||||
cur_text_section = NULL;
|
cur_text_section = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user