From 59c35638276435872ef797e3241f8da439c66a44 Mon Sep 17 00:00:00 2001 From: bellard Date: Sat, 23 Oct 2004 22:52:05 +0000 Subject: [PATCH] do not generate code for unused inline functions - fixed long long code gen bug - added --oformat linker option --- tcc.c | 333 +++++++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 185 insertions(+), 148 deletions(-) diff --git a/tcc.c b/tcc.c index 0d5d6307..c7ab87cc 100644 --- a/tcc.c +++ b/tcc.c @@ -20,6 +20,13 @@ #define _GNU_SOURCE #include "config.h" +#ifdef CONFIG_TCCBOOT + +#include "tccboot.h" +#define CONFIG_TCC_STATIC + +#else + #include #include #include @@ -40,11 +47,17 @@ #include #include #endif + +#endif /* !CONFIG_TCCBOOT */ + #include "elf.h" #include "stab.h" #ifndef CONFIG_TCC_STATIC #include #endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif #include "libtcc.h" @@ -101,10 +114,8 @@ typedef int BOOL; #define VSTACK_SIZE 64 #define STRING_MAX_SIZE 1024 -#define TOK_HASH_SIZE 2048 /* must be a power of two */ +#define TOK_HASH_SIZE 8192 /* must be a power of two */ #define TOK_ALLOC_INCR 512 /* must be a power of two */ -#define TOK_STR_ALLOC_INCR_BITS 6 -#define TOK_STR_ALLOC_INCR (1 << TOK_STR_ALLOC_INCR_BITS) #define TOK_MAX_SIZE 4 /* token max size in int unit when stored in string */ /* token symbol management */ @@ -432,6 +443,9 @@ struct TCCState { /* address of text section */ unsigned long text_addr; int has_text_addr; + + /* output format, see TCC_OUTPUT_FORMAT_xxx */ + int output_format; /* C language options */ int char_is_unsigned; @@ -704,6 +718,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, static int expr_const(void); static void expr_eq(void); static void gexpr(void); +static void gen_inline_functions(void); static void decl(int l); static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); @@ -722,7 +737,6 @@ int get_reg_ex(int rc,int rc2); static void macro_subst(TokenString *tok_str, Sym **nested_list, const int *macro_str, int can_read_stream); -int save_reg_forced(int r); void gen_op(int op); void force_charshort_cast(int t); static void gen_cast(CType *type); @@ -781,7 +795,7 @@ static int tcc_add_dll(TCCState *s, const char *filename, int flags); static int tcc_add_file_internal(TCCState *s, const char *filename, int flags); /* tcccoff.c */ -int tcc_output_coff(TCCState *s1, const char *OutFile); +int tcc_output_coff(TCCState *s1, FILE *f); /* tccasm.c */ @@ -867,10 +881,12 @@ typedef struct TCCSyms { /* add the symbol you want here if no dynamic linking is done */ static TCCSyms tcc_syms[] = { +#if !defined(CONFIG_TCCBOOT) TCCSYM(printf) TCCSYM(fprintf) TCCSYM(fopen) TCCSYM(fclose) +#endif { NULL, NULL }, }; @@ -1722,7 +1738,7 @@ BufferedFile *tcc_open(TCCState *s1, const char *filename) int fd; BufferedFile *bf; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return NULL; bf = tcc_malloc(sizeof(BufferedFile)); @@ -2254,7 +2270,11 @@ static int *tok_str_realloc(TokenString *s) { int *str, len; - len = s->allocated_len + TOK_STR_ALLOC_INCR; + if (s->allocated_len == 0) { + len = 8; + } else { + len = s->allocated_len * 2; + } str = tcc_realloc(s->str, len * sizeof(int)); if (!str) error("memory full"); @@ -4630,8 +4650,13 @@ int gv(int rc) load(r, vtop); vtop->r = r; /* save register value */ vpushi(ll >> 32); /* second word */ - } else if (r >= VT_CONST || + } else if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ (vtop->r & VT_LVAL)) { + /* We do not want to modifier the long long + pointer here, so the safest (and less + efficient) is to save all the other registers + in the stack. XXX: totally inefficient. */ + save_regs(1); /* load from memory */ load(r, vtop); vdup(); @@ -7119,7 +7144,20 @@ static void unary(void) get_tok_str(t, NULL)); s = external_global_sym(t, &func_old_type, 0); } - vset(&s->type, s->r, s->c); + if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == + (VT_STATIC | VT_INLINE | VT_FUNC)) { + /* if referencing an inline function, then we generate a + symbol to it if not already done. It will have the + effect to generate code for it at the end of the + compilation unit. Inline function as always + generated in the text section. */ + if (!s->c) + put_extern_sym(s, text_section, 0, 0); + r = VT_SYM | VT_CONST; + } else { + r = s->r; + } + vset(&s->type, r, s->c); /* if forward reference, we must point to s */ if (vtop->r & VT_SYM) { vtop->sym = s; @@ -8594,65 +8632,6 @@ void put_func_debug(Sym *sym) last_line_num = 0; } -/* not finished : try to put some local vars in registers */ -//#define CONFIG_REG_VARS - -#ifdef CONFIG_REG_VARS -void add_var_ref(int t) -{ - printf("%s:%d: &%s\n", - file->filename, file->line_num, - get_tok_str(t, NULL)); -} - -/* first pass on a function with heuristic to extract variable usage - and pointer references to local variables for register allocation */ -void analyse_function(void) -{ - int level, t; - - for(;;) { - if (tok == -1) - break; - /* any symbol coming after '&' is considered as being a - variable whose reference is taken. It is highly unaccurate - but it is difficult to do better without a complete parse */ - if (tok == '&') { - next(); - /* if '& number', then no need to examine next tokens */ - if (tok == TOK_CINT || - tok == TOK_CUINT || - tok == TOK_CLLONG || - tok == TOK_CULLONG) { - continue; - } else if (tok >= TOK_UIDENT) { - /* if '& ident [' or '& ident ->', then ident address - is not needed */ - t = tok; - next(); - if (tok != '[' && tok != TOK_ARROW) - add_var_ref(t); - } else { - level = 0; - while (tok != '}' && tok != ';' && - !((tok == ',' || tok == ')') && level == 0)) { - if (tok >= TOK_UIDENT) { - add_var_ref(tok); - } else if (tok == '(') { - level++; - } else if (tok == ')') { - level--; - } - next(); - } - } - } else { - next(); - } - } -} -#endif - /* parse an old style function declaration list */ /* XXX: check multiple parameter */ static void func_decl_list(Sym *func_sym) @@ -8701,6 +8680,88 @@ static void func_decl_list(Sym *func_sym) } } +/* parse a function defined by symbol 'sym' and generate its code in + 'cur_text_section' */ +static void gen_function(Sym *sym) +{ + 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; + /* put debug symbol */ + if (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); + sym_pop(&local_stack, NULL); /* reset local stack */ + /* end of function */ + /* patch symbol size */ + ((Elf32_Sym *)symtab_section->data)[sym->c].st_size = + ind - func_ind; + if (do_debug) { + put_stabn(N_FUN, 0, 0, ind - func_ind); + } + funcname = ""; /* for safety */ + func_vt.t = VT_VOID; /* for safety */ + ind = 0; /* for safety */ +} + +static void gen_inline_functions(void) +{ + Sym *sym; + CType *type; + int *str, inline_generated; + + /* iterate while inline function are referenced */ + for(;;) { + inline_generated = 0; + for(sym = global_stack; sym != NULL; sym = sym->prev) { + type = &sym->type; + if (((type->t & VT_BTYPE) == VT_FUNC) && + (type->t & (VT_STATIC | VT_INLINE)) == + (VT_STATIC | VT_INLINE) && + sym->c != 0) { + /* the function was used: generate its code and + convert it to a normal function */ + str = (int *)sym->r; + sym->r = VT_SYM | VT_CONST; + type->t &= ~VT_INLINE; + + macro_ptr = str; + next(); + cur_text_section = text_section; + gen_function(sym); + macro_ptr = NULL; /* fail safe */ + + tok_str_free(str); + inline_generated = 1; + } + } + if (!inline_generated) + break; + } + + /* free all remaining inline function tokens */ + for(sym = global_stack; sym != NULL; sym = sym->prev) { + type = &sym->type; + if (((type->t & VT_BTYPE) == VT_FUNC) && + (type->t & (VT_STATIC | VT_INLINE)) == + (VT_STATIC | VT_INLINE)) { + str = (int *)sym->r; + tok_str_free(str); + sym->r = 0; /* fail safe */ + } + } +} + /* 'l' is VT_LOCAL or VT_CONST to define default storage type */ static void decl(int l) { @@ -8755,11 +8816,6 @@ static void decl(int l) } if (tok == '{') { -#ifdef CONFIG_REG_VARS - TokenString func_str; - ParseState saved_parse_state; - int block_level; -#endif if (l == VT_LOCAL) error("cannot use local functions"); if (!(type.t & VT_FUNC)) @@ -8774,44 +8830,7 @@ static void decl(int l) /* XXX: cannot do better now: convert extern line to static inline */ if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) type.t = (type.t & ~VT_EXTERN) | VT_STATIC; - -#ifdef CONFIG_REG_VARS - /* parse all function code and record it */ - - tok_str_new(&func_str); - block_level = 0; - for(;;) { - int t; - if (tok == -1) - error("unexpected end of file"); - tok_str_add_tok(&func_str); - t = tok; - next(); - if (t == '{') { - block_level++; - } else if (t == '}') { - block_level--; - if (block_level == 0) - break; - } - } - tok_str_add(&func_str, -1); - tok_str_add(&func_str, 0); - - save_parse_state(&saved_parse_state); - - macro_ptr = func_str.str; - next(); - analyse_function(); -#endif - - /* compute text section */ - cur_text_section = ad.section; - if (!cur_text_section) - cur_text_section = text_section; - ind = cur_text_section->data_offset; - funcname = get_tok_str(v, NULL); sym = sym_find(v); if (sym) { if ((sym->type.t & VT_BTYPE) != VT_FUNC) @@ -8834,42 +8853,44 @@ static void decl(int l) sym = global_identifier_push(v, type.t, 0); sym->type.ref = type.ref; } - /* NOTE: we patch the symbol size later */ - put_extern_sym(sym, cur_text_section, ind, 0); - func_ind = ind; - sym->r = VT_SYM | VT_CONST; - /* put debug symbol */ - if (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(&type); - rsym = 0; -#ifdef CONFIG_REG_VARS - macro_ptr = func_str.str; - next(); -#endif - block(NULL, NULL, NULL, NULL, 0, 0); - gsym(rsym); - gfunc_epilog(); - cur_text_section->data_offset = ind; - label_pop(&global_label_stack, NULL); - sym_pop(&local_stack, NULL); /* reset local stack */ - /* end of function */ - /* patch symbol size */ - ((Elf32_Sym *)symtab_section->data)[sym->c].st_size = - ind - func_ind; - if (do_debug) { - put_stabn(N_FUN, 0, 0, ind - func_ind); - } - funcname = ""; /* for safety */ - func_vt.t = VT_VOID; /* for safety */ - ind = 0; /* for safety */ -#ifdef CONFIG_REG_VARS - tok_str_free(func_str.str); - restore_parse_state(&saved_parse_state); -#endif + /* static inline functions are just recorded as a kind + of macro. Their code will be emitted at the end of + the compilation unit only if they are used */ + if ((type.t & (VT_INLINE | VT_STATIC)) == + (VT_INLINE | VT_STATIC)) { + TokenString func_str; + int block_level; + + tok_str_new(&func_str); + + block_level = 0; + for(;;) { + int t; + if (tok == TOK_EOF) + error("unexpected end of file"); + tok_str_add_tok(&func_str); + t = tok; + next(); + if (t == '{') { + block_level++; + } else if (t == '}') { + block_level--; + if (block_level == 0) + break; + } + } + tok_str_add(&func_str, -1); + tok_str_add(&func_str, 0); + sym->r = (int)func_str.str; + } else { + /* compute text section */ + cur_text_section = ad.section; + if (!cur_text_section) + cur_text_section = text_section; + sym->r = VT_SYM | VT_CONST; + gen_function(sym); + } break; } else { if (btype.t & VT_TYPEDEF) { @@ -9015,6 +9036,8 @@ static int tcc_compile(TCCState *s1) they are undefined) */ free_defines(define_start); + gen_inline_functions(); + sym_pop(&global_stack, NULL); return s1->nb_errors != 0 ? -1 : 0; @@ -9239,7 +9262,7 @@ static void rt_printline(unsigned long wanted_pc) fprintf(stderr, "\n"); } -#ifndef WIN32 +#if !defined(WIN32) && !defined(CONFIG_TCCBOOT) #ifdef __i386__ @@ -9406,7 +9429,7 @@ int tcc_run(TCCState *s1, int argc, char **argv) prog_main = tcc_get_symbol_err(s1, "main"); if (do_debug) { -#ifdef WIN32 +#if defined(WIN32) || defined(CONFIG_TCCBOOT) error("debug mode currently not available for Windows"); #else struct sigaction sigact; @@ -10249,8 +10272,22 @@ int parse_args(TCCState *s, int argc, char **argv) if (strstart(optarg, "-Ttext,", &p)) { s->text_addr = strtoul(p, NULL, 16); s->has_text_addr = 1; + } else if (strstart(optarg, "--oformat,", &p)) { + if (strstart(p, "elf32-", NULL)) { + s->output_format = TCC_OUTPUT_FORMAT_ELF; + } else if (!strcmp(p, "binary")) { + s->output_format = TCC_OUTPUT_FORMAT_BINARY; + } else +#ifdef TCC_TARGET_COFF + if (!strcmp(p, "coff")) { + s->output_format = TCC_OUTPUT_FORMAT_COFF; + } else +#endif + { + error("target %s not found", p); + } } else { - error("unsupported ld option '%s'", optarg); + error("unsupported linker option '%s'", optarg); } } break; -- 2.11.4.GIT