9001 lines · 260.9 KB · C
RawDownload
/* *  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 */ #define USING_GLOBALS#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 Sym *global_stack;ST_DATA Sym *local_stack;ST_DATA Sym *define_stack;ST_DATA Sym *global_label_stack;ST_DATA Sym *local_label_stack; static Sym *sym_free_first;static void **sym_pools;static int nb_sym_pools; static Sym *all_cleanups, *pending_gotos;static int local_scope;ST_DATA char debug_modes; ST_DATA SValue *vtop;static SValue _vstack[1 + VSTACK_SIZE];#define vstack (_vstack + 1) ST_DATA int nocode_wanted; /* no code generation wanted */#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */#define DATA_ONLY_WANTED 0x80000000 /* ON outside of functions and for static initializers */ /* no code output after unconditional jumps such as with if (0) ... */#define CODE_OFF_BIT 0x20000000#define CODE_OFF() if(!nocode_wanted)(nocode_wanted |= CODE_OFF_BIT)#define CODE_ON() (nocode_wanted &= ~CODE_OFF_BIT) /* no code output when parsing sizeof()/typeof() etc. (using nocode_wanted++/--) */#define NOEVAL_MASK 0x0000FFFF#define NOEVAL_WANTED (nocode_wanted & NOEVAL_MASK) /* no code output when parsing constant expressions */#define CONST_WANTED_BIT  0x00010000#define CONST_WANTED_MASK 0x0FFF0000#define CONST_WANTED  (nocode_wanted & CONST_WANTED_MASK) 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_var; /* true if current function is variadic (used by return instruction) */ST_DATA int func_vc; /* stack address for implicit struct return storage */ST_DATA int func_ind; /* function start address */static int func_old;ST_DATA const char *funcname;ST_DATA CType int_type, func_old_type, char_type, char_pointer_type;static CString initstr; #if PTR_SIZE == 4#define VT_SIZE_T (VT_INT | VT_UNSIGNED)#define VT_PTRDIFF_T VT_INT#elif LONG_SIZE == 4#define VT_SIZE_T (VT_LLONG | VT_UNSIGNED)#define VT_PTRDIFF_T VT_LLONG#else#define VT_SIZE_T (VT_LONG | VT_LLONG | VT_UNSIGNED)#define VT_PTRDIFF_T (VT_LONG | VT_LLONG)#endif static struct switch_t {    struct case_t {        int64_t v1, v2;        int ind, line;    } **p; int n; /* list of case ranges */    int def_sym; /* default symbol */    int nocode_wanted;    int *bsym;    struct scope *scope;    struct switch_t *prev;    SValue sv;} *cur_switch; /* current switch */ #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8/*list of temporary local variables on the stack in current function. */static struct temp_local_variable {	int location; //offset on stack. Svalue.c.i	short size;	short align;} arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER];static int nb_temp_local_vars; static struct scope {    struct scope *prev;    struct { int loc, locorig, num; } vla;    struct { Sym *s; int n; } cl;    int *bsym, *csym;    Sym *lstk, *llstk;} *cur_scope, *loop_scope, *root_scope; typedef struct {    Section *sec;    int local_offset;    Sym *flex_array_ref;} init_params; #if 1#define precedence_parserstatic void init_prec(void);#endif static void block(int flags);#define STMT_EXPR 1#define STMT_COMPOUND 2 static void gen_cast(CType *type);static void gen_cast_s(int t);static inline CType *pointed_type(CType *type);static int is_compatible_types(CType *type1, CType *type2);static int parse_btype(CType *type, AttributeDef *ad, int ignore_label);static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td);static void parse_expr_type(CType *type);static void init_putv(init_params *p, CType *type, unsigned long c);static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags);static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);static int decl(int l);static void expr_eq(void);static void vpush_type_size(CType *type, int *a);static int is_compatible_unqualified_types(CType *type1, CType *type2);static inline int64_t expr_const64(void);static void vpush64(int ty, unsigned long long v);static void vpush(CType *type);static int gvtst(int inv, int t);static void gen_inline_functions(TCCState *s);static void free_inline_functions(TCCState *s);static void skip_or_save_block(TokenString **str);static void gv_dup(void);static int get_temp_local_var(int size,int align,int *r2);static void cast_error(CType *st, CType *dt);static void end_switch(void);static void do_Static_assert(void); /* ------------------------------------------------------------------------- *//* Automagical code suppression */ /* Clear 'nocode_wanted' at forward label if it was used */ST_FUNC void gsym(int t){  if (t) {    gsym_addr(t, ind);    CODE_ON();  }} /* Clear 'nocode_wanted' if current pc is a label */static int gind(){  int t = ind;  CODE_ON();  if (debug_modes)    tcc_tcov_block_begin(tcc_state);  return t;} /* Set 'nocode_wanted' after unconditional (backwards) jump */static void gjmp_addr_acs(int t){  gjmp_addr(t);  CODE_OFF();} /* Set 'nocode_wanted' after unconditional (forwards) jump */static int gjmp_acs(int t){  t = gjmp(t);  CODE_OFF();  return t;} /* These are #undef'd at the end of this file */#define gjmp_addr gjmp_addr_acs#define gjmp gjmp_acs/* ------------------------------------------------------------------------- */ ST_INLN int is_float(int t){    int bt = t & VT_BTYPE;    return bt == VT_LDOUBLE        || bt == VT_DOUBLE        || bt == VT_FLOAT        || bt == VT_QFLOAT;} static inline int is_integer_btype(int bt){    return bt == VT_BYTE        || bt == VT_BOOL        || bt == VT_SHORT        || bt == VT_INT        || bt == VT_LLONG;} static int btype_size(int bt){    return bt == VT_BYTE || bt == VT_BOOL ? 1 :        bt == VT_SHORT ? 2 :        bt == VT_INT ? 4 :        bt == VT_LLONG ? 8 :        bt == VT_PTR ? PTR_SIZE : 0;} /* returns function return register from type */static int R_RET(int t){    if (!is_float(t))        return REG_IRET;#ifdef TCC_TARGET_X86_64    if ((t & VT_BTYPE) == VT_LDOUBLE)        return TREG_ST0;#elif defined TCC_TARGET_RISCV64    if ((t & VT_BTYPE) == VT_LDOUBLE)        return REG_IRET;#endif    return REG_FRET;} /* returns 2nd function return register, if any */static int R2_RET(int t){    t &= VT_BTYPE;#if PTR_SIZE == 4    if (t == VT_LLONG)        return REG_IRE2;#elif defined TCC_TARGET_X86_64    if (t == VT_QLONG)        return REG_IRE2;    if (t == VT_QFLOAT)        return REG_FRE2;#elif defined TCC_TARGET_RISCV64    if (t == VT_LDOUBLE)        return REG_IRE2;#endif    return VT_CONST;} /* returns true for two-word types */#define USING_TWO_WORDS(t) (R2_RET(t) != VT_CONST) /* put function return registers to stack value */static void PUT_R_RET(SValue *sv, int t){    sv->r = R_RET(t), sv->r2 = R2_RET(t);} /* returns function return register class for type t */static int RC_RET(int t){    return reg_classes[R_RET(t)] & ~(RC_FLOAT | RC_INT);} /* returns generic register class for type t */static int RC_TYPE(int t){    if (!is_float(t))        return RC_INT;#ifdef TCC_TARGET_X86_64    if ((t & VT_BTYPE) == VT_LDOUBLE)        return RC_ST0;    if ((t & VT_BTYPE) == VT_QFLOAT)        return RC_FRET;#elif defined TCC_TARGET_RISCV64    if ((t & VT_BTYPE) == VT_LDOUBLE)        return RC_INT;#endif    return RC_FLOAT;} /* returns 2nd register class corresponding to t and rc */static int RC2_TYPE(int t, int rc){    if (!USING_TWO_WORDS(t))        return 0;#ifdef RC_IRE2    if (rc == RC_IRET)        return RC_IRE2;#endif#ifdef RC_FRE2    if (rc == RC_FRET)        return RC_FRE2;#endif    if (rc & RC_FLOAT)        return RC_FLOAT;    return RC_INT;} /* 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[4];    memcpy(p, &d, sizeof(double));    return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31;} ST_FUNC void test_lvalue(void){    if (!(vtop->r & VT_LVAL))        expect("lvalue");} ST_FUNC void check_vstack(void){    if (vtop != vstack - 1)        tcc_error("internal compiler error: vstack leak (%d)",                  (int)(vtop - vstack + 1));} #if 0/* dump 'b' vstack entries starting with 'a'  */void pv (const char *lbl, int a, int b){    int i;    for (i = a; i < a + b; ++i) {        SValue *p = &vtop[-i];        printf("%s vtop[-%d] : type.t:%04x  r:%04x  r2:%04x  c.i:%d\n",            lbl, i, p->type.t, p->r, p->r2, (int)p->c.i);    }} /* dump symbols on stack from s ... last */static inline void psyms(const char *msg, Sym *s, Sym *last){    printf("%-8s scope         v        c        r   type.t\n", msg);    while (s && s != last) {        printf("      %8x  %08x %08x %08x %08x %s\n",            s->sym_scope, s->v, s->c, s->r, s->type.t, get_tok_str(s->v, 0));        s = s->prev;    }} static void type_to_str(char *buf, int buf_size, CType *type, const char *varstr); /* print type */static void ptype(const char *msg, CType *type, int v){    char buf[500];    type_to_str(buf, sizeof(buf), type,        (v & ~SYM_FIELD) ? get_tok_str(v, NULL) : NULL);    printf("%s : %s;\n", msg, buf);}#endif /* ------------------------------------------------------------------------- *//* initialize vstack and types.  This must be done also for tcc -E */ST_FUNC void tccgen_init(TCCState *s1){    vtop = vstack - 1;    memset(vtop, 0, sizeof *vtop);     /* define some often used types */    int_type.t = VT_INT;     char_type.t = VT_BYTE;    if (s1->char_is_unsigned)        char_type.t |= VT_UNSIGNED;    char_pointer_type = char_type;    mk_pointer(&char_pointer_type);     func_old_type.t = VT_FUNC;    func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0);    func_old_type.ref->f.func_call = FUNC_CDECL;    func_old_type.ref->f.func_type = FUNC_OLD;#ifdef precedence_parser    init_prec();#endif    cstr_new(&initstr);} ST_FUNC int tccgen_compile(TCCState *s1){    funcname = "";    func_ind = -1;    anon_sym = SYM_FIRST_ANOM;    nocode_wanted = DATA_ONLY_WANTED; /* no code outside of functions */    debug_modes = (s1->do_debug ? 1 : 0) | s1->test_coverage << 1;    global_expr = 0;     tcc_debug_start(s1);    tcc_tcov_start (s1);#ifdef TCC_TARGET_ARM    arm_init(s1);#endif#ifdef INC_DEBUG    printf("%s: **** new file\n", file->filename);#endif    parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR;    next();    decl(VT_CONST);    gen_inline_functions(s1);    check_vstack();    /* end of translation unit info */#if TCC_EH_FRAME    tcc_eh_frame_end(s1);#endif    tcc_debug_end(s1);    tcc_tcov_end(s1);    return 0;} ST_FUNC void tccgen_finish(TCCState *s1){    tcc_debug_end(s1); /* just in case of errors: free memory */    free_inline_functions(s1);    sym_pop(&global_stack, NULL, 0);    sym_pop(&local_stack, NULL, 0);    /* free preprocessor macros */    free_defines(NULL);    /* free sym_pools */    dynarray_reset(&sym_pools, &nb_sym_pools);    cstr_free(&initstr);    dynarray_reset(&stk_data, &nb_stk_data);    while (cur_switch)        end_switch();    local_scope = 0;    loop_scope = NULL;    all_cleanups = NULL;    pending_gotos = NULL;    nb_temp_local_vars = 0;    global_label_stack = NULL;    local_label_stack = NULL;    cur_text_section = NULL;    sym_free_first = NULL;} /* ------------------------------------------------------------------------- */ST_FUNC ElfSym *elfsym(Sym *s){  if (!s || !s->c)    return NULL;  return &((ElfSym *)symtab_section->data)[s->c];} /* apply storage attributes to Elf symbol */ST_FUNC void update_storage(Sym *sym){    ElfSym *esym;    int sym_bind, old_sym_bind;     esym = elfsym(sym);    if (!esym)        return;     if (sym->a.visibility)        esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))            | sym->a.visibility;     if (sym->type.t & (VT_STATIC | VT_INLINE))        sym_bind = STB_LOCAL;    else if (sym->a.weak)        sym_bind = STB_WEAK;    else        sym_bind = STB_GLOBAL;    old_sym_bind = ELFW(ST_BIND)(esym->st_info);    if (sym_bind != old_sym_bind) {        esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info));    } #ifdef TCC_TARGET_PE    if (sym->a.dllimport)        esym->st_other |= ST_PE_IMPORT;    if (sym->a.dllexport)        esym->st_other |= ST_PE_EXPORT;#endif #if 0    printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n",        get_tok_str(sym->v, NULL),        sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g',        sym->a.visibility,

Lines 1–500 of 9001.