Alien-TinyCC
view release on metacpan or search on metacpan
src/tccgen.c view on Meta::CPAN
/*
* TCC - Tiny C Compiler
*
* Copyright (c) 2001-2004 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tcc.h"
/********************************************************/
/* global variables */
/* loc : local variable index
ind : output code index
rsym: return symbol
anon_sym: anonymous symbol index
*/
ST_DATA int rsym, anon_sym, ind, loc;
ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */
ST_DATA Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_ASM
ST_DATA Section *last_text_section; /* to handle .previous asm directive */
#endif
#ifdef CONFIG_TCC_BCHECK
/* bound check related sections */
ST_DATA Section *bounds_section; /* contains global data bound description */
ST_DATA Section *lbounds_section; /* contains local data bound description */
#endif
/* symbol sections */
ST_DATA Section *symtab_section, *strtab_section;
/* debug sections */
ST_DATA Section *stab_section, *stabstr_section;
ST_DATA Sym *sym_free_first;
ST_DATA void **sym_pools;
ST_DATA int nb_sym_pools;
ST_DATA Sym *global_stack;
ST_DATA Sym *local_stack;
ST_DATA Sym *scope_stack_bottom;
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 */
ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */
ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */
ST_DATA CType func_vt; /* current function return type (used by return instruction) */
ST_DATA int func_vc;
ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */
ST_DATA char *funcname;
ST_DATA CType char_pointer_type, func_old_type, int_type, size_type;
/* ------------------------------------------------------------------------- */
static void gen_cast(CType *type);
static inline CType *pointed_type(CType *type);
static int is_compatible_types(CType *type1, CType *type2);
static int parse_btype(CType *type, AttributeDef *ad);
static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
static void parse_expr_type(CType *type);
static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only);
static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg, int is_expr);
static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, char *asm_label, int scope);
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);
ST_INLN int is_float(int t)
{
int bt;
bt = t & VT_BTYPE;
return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT;
}
/* we use our own 'finite' function to avoid potential problems with
non standard math libs */
/* XXX: endianness dependent */
ST_FUNC int ieee_finite(double d)
{
int *p = (int *)&d;
return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;
}
ST_FUNC void test_lvalue(void)
{
if (!(vtop->r & VT_LVAL))
expect("lvalue");
}
/* ------------------------------------------------------------------------- */
/* symbol allocator */
static Sym *__sym_malloc(void)
{
Sym *sym_pool, *sym, *last_sym;
int i;
sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym));
dynarray_add(&sym_pools, &nb_sym_pools, sym_pool);
last_sym = sym_free_first;
sym = sym_pool;
for(i = 0; i < SYM_POOL_NB; i++) {
sym->next = last_sym;
last_sym = sym;
sym++;
src/tccgen.c view on Meta::CPAN
/* parse an integer constant and return its value. */
ST_FUNC int expr_const(void)
{
int c;
expr_const1();
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
expect("constant expression");
c = vtop->c.i;
vpop();
return c;
}
/* return the label token if current token is a label, otherwise
return zero */
static int is_label(void)
{
int last_tok;
/* fast test first */
if (tok < TOK_UIDENT)
return 0;
/* no need to save tokc because tok is an identifier */
last_tok = tok;
next();
if (tok == ':') {
next();
return last_tok;
} else {
unget_tok(last_tok);
return 0;
}
}
static void label_or_decl(int l)
{
int last_tok;
/* fast test first */
if (tok >= TOK_UIDENT)
{
/* no need to save tokc because tok is an identifier */
last_tok = tok;
next();
if (tok == ':') {
unget_tok(last_tok);
return;
}
unget_tok(last_tok);
}
decl(l);
}
static void block(int *bsym, int *csym, int *case_sym, int *def_sym,
int case_reg, int is_expr)
{
int a, b, c, d;
Sym *s, *frame_bottom;
/* generate line number info */
if (tcc_state->do_debug &&
(last_line_num != file->line_num || last_ind != ind)) {
put_stabn(N_SLINE, 0, file->line_num, ind - func_ind);
last_ind = ind;
last_line_num = file->line_num;
}
if (is_expr) {
/* default return value is (void) */
vpushi(0);
vtop->type.t = VT_VOID;
}
if (tok == TOK_IF) {
/* if test */
next();
skip('(');
gexpr();
skip(')');
a = gtst(1, 0);
block(bsym, csym, case_sym, def_sym, case_reg, 0);
c = tok;
if (c == TOK_ELSE) {
next();
d = gjmp(0);
gsym(a);
block(bsym, csym, case_sym, def_sym, case_reg, 0);
gsym(d); /* patch else jmp */
} else
gsym(a);
} else if (tok == TOK_WHILE) {
next();
d = ind;
skip('(');
gexpr();
skip(')');
a = gtst(1, 0);
b = 0;
block(&a, &b, case_sym, def_sym, case_reg, 0);
gjmp_addr(d);
gsym(a);
gsym_addr(b, d);
} else if (tok == '{') {
Sym *llabel;
int block_vla_sp_loc, *saved_vla_sp_loc, saved_vla_flags;
next();
/* record local declaration stack position */
s = local_stack;
frame_bottom = sym_push2(&local_stack, SYM_FIELD, 0, 0);
frame_bottom->next = scope_stack_bottom;
scope_stack_bottom = frame_bottom;
llabel = local_label_stack;
/* save VLA state */
block_vla_sp_loc = *(saved_vla_sp_loc = vla_sp_loc);
if (saved_vla_sp_loc != &vla_sp_root_loc)
vla_sp_loc = &block_vla_sp_loc;
saved_vla_flags = vla_flags;
vla_flags |= VLA_NEED_NEW_FRAME;
src/tccgen.c view on Meta::CPAN
addr = 0; /* avoid warning */
}
if (v) {
if (scope != VT_CONST || !sym) {
sym = sym_push(v, type, r | VT_SYM, 0);
sym->asm_label = asm_label;
}
/* update symbol definition */
if (sec) {
put_extern_sym(sym, sec, addr, size);
} else {
ElfW(Sym) *esym;
/* put a common area */
put_extern_sym(sym, NULL, align, size);
/* XXX: find a nicer way */
esym = &((ElfW(Sym) *)symtab_section->data)[sym->c];
esym->st_shndx = SHN_COMMON;
}
} else {
CValue cval;
/* push global reference */
sym = get_sym_ref(type, sec, addr, size);
cval.ul = 0;
vsetc(type, VT_CONST | VT_SYM, &cval);
vtop->sym = sym;
}
/* patch symbol weakness */
if (type->t & VT_WEAK)
weaken_symbol(sym);
#ifdef CONFIG_TCC_BCHECK
/* handles bounds now because the symbol must be defined
before for the relocation */
if (tcc_state->do_bounds_check) {
unsigned long *bounds_ptr;
greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR);
/* then add global bound info */
bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long));
bounds_ptr[0] = 0; /* relocated */
bounds_ptr[1] = size;
}
#endif
}
if (has_init || (type->t & VT_VLA)) {
decl_initializer(type, sec, addr, 1, 0);
/* restore parse state if needed */
if (init_str.str) {
tok_str_free(init_str.str);
restore_parse_state(&saved_parse_state);
}
/* patch flexible array member size back to -1, */
/* for possible subsequent similar declarations */
if (flexible_array)
flexible_array->type.ref->c = -1;
}
no_alloc: ;
}
static void put_func_debug(Sym *sym)
{
char buf[512];
/* stabs info */
/* XXX: we put here a dummy type */
snprintf(buf, sizeof(buf), "%s:%c1",
funcname, sym->type.t & VT_STATIC ? 'f' : 'F');
put_stabs_r(buf, N_FUN, 0, file->line_num, 0,
cur_text_section, sym->c);
/* //gr gdb wants a line at the function */
put_stabn(N_SLINE, 0, file->line_num, 0);
last_ind = 0;
last_line_num = 0;
}
/* parse an old style function declaration list */
/* XXX: check multiple parameter */
static void func_decl_list(Sym *func_sym)
{
AttributeDef ad;
int v;
Sym *s;
CType btype, type;
/* parse each declaration */
while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF &&
tok != TOK_ASM1 && tok != TOK_ASM2 && tok != TOK_ASM3) {
if (!parse_btype(&btype, &ad))
expect("declaration list");
if (((btype.t & VT_BTYPE) == VT_ENUM ||
(btype.t & VT_BTYPE) == VT_STRUCT) &&
tok == ';') {
/* we accept no variable after */
} else {
for(;;) {
type = btype;
type_decl(&type, &ad, &v, TYPE_DIRECT);
/* find parameter in function parameter list */
s = func_sym->next;
while (s != NULL) {
if ((s->v & ~SYM_FIELD) == v)
goto found;
s = s->next;
}
tcc_error("declaration for parameter '%s' but no such parameter",
get_tok_str(v, NULL));
found:
/* check that no storage specifier except 'register' was given */
if (type.t & VT_STORAGE)
tcc_error("storage class specified for '%s'", get_tok_str(v, NULL));
convert_parameter_type(&type);
/* we can add the type (NOTE: it could be local to the function) */
s->type = type;
/* accept other parameters */
if (tok == ',')
next();
else
break;
}
}
skip(';');
}
}
/* parse a function defined by symbol 'sym' and generate its code in
'cur_text_section' */
static void gen_function(Sym *sym)
{
int saved_nocode_wanted = nocode_wanted;
nocode_wanted = 0;
ind = cur_text_section->data_offset;
/* NOTE: we patch the symbol size later */
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);
/* push a dummy symbol to enable local sym storage */
sym_push2(&local_stack, SYM_FIELD, 0, 0);
gfunc_prolog(&sym->type);
rsym = 0;
block(NULL, NULL, NULL, NULL, 0, 0);
gsym(rsym);
gfunc_epilog();
cur_text_section->data_offset = ind;
label_pop(&global_label_stack, NULL);
/* reset local stack */
scope_stack_bottom = NULL;
sym_pop(&local_stack, NULL);
/* end of function */
/* patch symbol size */
((ElfW(Sym) *)symtab_section->data)[sym->c].st_size =
ind - func_ind;
/* patch symbol weakness (this definition overrules any prototype) */
if (sym->type.t & VT_WEAK)
weaken_symbol(sym);
if (tcc_state->do_debug) {
put_stabn(N_FUN, 0, 0, ind - func_ind);
}
/* It's better to crash than to generate wrong code */
cur_text_section = NULL;
funcname = ""; /* for safety */
func_vt.t = VT_VOID; /* for safety */
ind = 0; /* for safety */
nocode_wanted = saved_nocode_wanted;
}
ST_FUNC void gen_inline_functions(void)
{
Sym *sym;
int *str, inline_generated, i;
struct InlineFunc *fn;
/* iterate while inline function are referenced */
for(;;) {
inline_generated = 0;
for (i = 0; i < tcc_state->nb_inline_fns; ++i) {
fn = tcc_state->inline_fns[i];
sym = fn->sym;
if (sym && sym->c) {
/* the function was used: generate its code and
convert it to a normal function */
str = fn->token_str;
fn->sym = NULL;
if (file)
pstrcpy(file->filename, sizeof file->filename, fn->filename);
sym->r = VT_SYM | VT_CONST;
sym->type.t &= ~VT_INLINE;
macro_ptr = str;
next();
cur_text_section = text_section;
gen_function(sym);
macro_ptr = NULL; /* fail safe */
inline_generated = 1;
}
}
if (!inline_generated)
break;
}
for (i = 0; i < tcc_state->nb_inline_fns; ++i) {
fn = tcc_state->inline_fns[i];
str = fn->token_str;
tok_str_free(str);
}
dynarray_reset(&tcc_state->inline_fns, &tcc_state->nb_inline_fns);
}
/* 'l' is VT_LOCAL or VT_CONST to define default storage type */
static int decl0(int l, int is_for_loop_init)
{
int v, has_init, r;
CType type, btype;
Sym *sym;
AttributeDef ad;
( run in 0.553 second using v1.01-cache-2.11-cpan-02777c243ea )