do not generate code for unused inline functions - fixed long long code gen bug - added --oformat linker option
This commit is contained in:
		
							parent
							
								
									45466d2df6
								
							
						
					
					
						commit
						59c3563827
					
				
					 1 changed files with 185 additions and 148 deletions
				
			
		
							
								
								
									
										333
									
								
								tcc.c
									
										
									
									
									
								
							
							
						
						
									
										333
									
								
								tcc.c
									
										
									
									
									
								
							|  | @ -20,6 +20,13 @@ | |||
| #define _GNU_SOURCE | ||||
| #include "config.h" | ||||
| 
 | ||||
| #ifdef CONFIG_TCCBOOT | ||||
| 
 | ||||
| #include "tccboot.h" | ||||
| #define CONFIG_TCC_STATIC | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <stdarg.h> | ||||
|  | @ -40,11 +47,17 @@ | |||
| #include <sys/time.h> | ||||
| #include <sys/ucontext.h> | ||||
| #endif | ||||
| 
 | ||||
| #endif /* !CONFIG_TCCBOOT */ | ||||
| 
 | ||||
| #include "elf.h" | ||||
| #include "stab.h" | ||||
| #ifndef CONFIG_TCC_STATIC | ||||
| #include <dlfcn.h> | ||||
| #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; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue