changeset 322:55984df89dbe

[project @ 2004-10-23 22:52:05 by bellard] do not generate code for unused inline functions - fixed long long code gen bug - added --oformat linker option
author bellard
date Sat, 23 Oct 2004 22:52:05 +0000
parents ed195f657414
children 164e85dc9987
files tcc.c
diffstat 1 files changed, 185 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/tcc.c	Sat Oct 23 22:49:08 2004 +0000
+++ b/tcc.c	Sat Oct 23 22:52:05 2004 +0000
@@ -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 @@
 #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 @@
     /* 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 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 @@
 
 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_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 @@
 
 /* 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 @@
     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 @@
 {
     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 @@
                     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 @@
                         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 @@
     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 @@
     }
 }
 
+/* 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 @@
             }
 
             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 @@
                 /* 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 @@
                     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);
+
+                /* 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);
                 }
-                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
                 break;
             } else {
                 if (btype.t & VT_TYPEDEF) {
@@ -9015,6 +9036,8 @@
        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 @@
     fprintf(stderr, "\n");
 }
 
-#ifndef WIN32
+#if !defined(WIN32) && !defined(CONFIG_TCCBOOT)
 
 #ifdef __i386__
 
@@ -9406,7 +9429,7 @@
     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 @@
                     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;