8583 lines · 248.7 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;static int in_sizeof;static int in_generic;static int section_sym; ST_DATA SValue *vtop;static SValue _vstack[1 + VSTACK_SIZE];#define vstack (_vstack + 1) ST_DATA int const_wanted; /* true if constant wanted */ST_DATA int nocode_wanted; /* no code generation wanted */#define unevalmask 0xffff /* unevaluated subexpression */#define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */#define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */ /* Automagical code suppression ----> */#define CODE_OFF() (nocode_wanted |= 0x20000000)#define CODE_ON() (nocode_wanted &= ~0x20000000) /* Clear 'nocode_wanted' at label if it was used */ST_FUNC void gsym(int t) { if (t) { gsym_addr(t, ind); CODE_ON(); }}static int gind(void) { CODE_ON(); return ind; } /* Set 'nocode_wanted' after unconditional jumps */static void gjmp_addr_acs(int t) { gjmp_addr(t); CODE_OFF(); }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_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;static int last_line_num, new_file, func_ind; /* debug info control */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 ST_DATA struct switch_t {    struct case_t {        int64_t v1, v2;	int sym;    } **p; int n; /* list of case ranges */    int def_sym; /* default symbol */    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. */ST_DATA 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];short nb_temp_local_vars; static struct scope {    struct scope *prev;    struct { int loc, 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; /********************************************************//* stab debug support */ static const struct {  int type;  const char *name;} default_debug[] = {    {   VT_INT, "int:t1=r1;-2147483648;2147483647;" },    {   VT_BYTE, "char:t2=r2;0;127;" },#if LONG_SIZE == 4    {   VT_LONG | VT_INT, "long int:t3=r3;-2147483648;2147483647;" },#else    {   VT_LLONG | VT_LONG, "long int:t3=r3;-9223372036854775808;9223372036854775807;" },#endif    {   VT_INT | VT_UNSIGNED, "unsigned int:t4=r4;0;037777777777;" },#if LONG_SIZE == 4    {   VT_LONG | VT_INT | VT_UNSIGNED, "long unsigned int:t5=r5;0;037777777777;" },#else    /* use octal instead of -1 so size_t works (-gstabs+ in gcc) */    {   VT_LLONG | VT_LONG | VT_UNSIGNED, "long unsigned int:t5=r5;0;01777777777777777777777;" },#endif    {   VT_QLONG, "__int128:t6=r6;0;-1;" },    {   VT_QLONG | VT_UNSIGNED, "__int128 unsigned:t7=r7;0;-1;" },    {   VT_LLONG, "long long int:t8=r8;-9223372036854775808;9223372036854775807;" },    {   VT_LLONG | VT_UNSIGNED, "long long unsigned int:t9=r9;0;01777777777777777777777;" },    {   VT_SHORT, "short int:t10=r10;-32768;32767;" },    {   VT_SHORT | VT_UNSIGNED, "short unsigned int:t11=r11;0;65535;" },    {   VT_BYTE | VT_DEFSIGN, "signed char:t12=r12;-128;127;" },    {   VT_BYTE | VT_DEFSIGN | VT_UNSIGNED, "unsigned char:t13=r13;0;255;" },    {   VT_FLOAT, "float:t14=r1;4;0;" },    {   VT_DOUBLE, "double:t15=r1;8;0;" },    {   VT_LDOUBLE, "long double:t16=r1;16;0;" },    {   -1, "_Float32:t17=r1;4;0;" },    {   -1, "_Float64:t18=r1;8;0;" },    {   -1, "_Float128:t19=r1;16;0;" },    {   -1, "_Float32x:t20=r1;8;0;" },    {   -1, "_Float64x:t21=r1;16;0;" },    {   -1, "_Decimal32:t22=r1;4;0;" },    {   -1, "_Decimal64:t23=r1;8;0;" },    {   -1, "_Decimal128:t24=r1;16;0;" },    /* if default char is unsigned */    {   VT_BYTE | VT_UNSIGNED, "unsigned char:t25=r25;0;255;" },    /* boolean type */    {   VT_BOOL, "bool:t26=r26;0;255;" },    {   VT_VOID, "void:t27=27" },}; static int debug_next_type; static struct debug_hash {    int debug_type;    Sym *type;} *debug_hash; static int n_debug_hash; static struct debug_info {    int start;    int end;    int n_sym;    struct debug_sym {        int type;        unsigned long value;        char *str;        Section *sec;        int sym_index;    } *sym;    struct debug_info *child, *next, *last, *parent;} *debug_info, *debug_info_root; /********************************************************/#if 1#define precedence_parserstatic void init_prec(void);#endif/********************************************************/#ifndef CONFIG_TCC_ASMST_FUNC void asm_instr(void){    tcc_error("inline asm() not supported");}ST_FUNC void asm_global_instr(void){    tcc_error("inline asm() not supported");}#endif /* ------------------------------------------------------------------------- */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);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 block(int is_expr);static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope);static void decl(int l);static int decl0(int l, int is_for_loop_init, Sym *);static void expr_eq(void);static void vla_runtime_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);static void clear_temp_local_var_list();static void cast_error(CType *st, CType *dt); 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;} /* compiling intel long double natively */#if (defined __i386__ || defined __x86_64__) \    && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64)# define TCC_IS_NATIVE_387#endif 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));} /* ------------------------------------------------------------------------- *//* vstack debugging aid */ #if 0void 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);    }}#endif /* ------------------------------------------------------------------------- *//* start of translation unit info */ST_FUNC void tcc_debug_start(TCCState *s1){    if (s1->do_debug) {        int i;        char buf[512];         /* file info: full path + filename */        section_sym = put_elf_sym(symtab_section, 0, 0,                                  ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,                                  text_section->sh_num, NULL);        getcwd(buf, sizeof(buf));#ifdef _WIN32        normalize_slashes(buf);#endif        pstrcat(buf, sizeof(buf), "/");        put_stabs_r(s1, buf, N_SO, 0, 0,                    text_section->data_offset, text_section, section_sym);        put_stabs_r(s1, file->prev ? file->prev->filename : file->filename,                    N_SO, 0, 0,                    text_section->data_offset, text_section, section_sym);        for (i = 0; i < sizeof (default_debug) / sizeof (default_debug[0]); i++)            put_stabs(s1, default_debug[i].name, N_LSYM, 0, 0, 0);         new_file = last_line_num = 0;        func_ind = -1;        debug_next_type = sizeof(default_debug) / sizeof(default_debug[0]);        debug_hash = NULL;        n_debug_hash = 0;         /* we're currently 'including' the <command line> */        tcc_debug_bincl(s1);    }     /* an elf symbol of type STT_FILE must be put so that STB_LOCAL       symbols can be safely used */    put_elf_sym(symtab_section, 0, 0,                ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,                SHN_ABS, file->filename);} static void tcc_debug_stabs (TCCState *s1, const char *str, int type, unsigned long value,                             Section *sec, int sym_index){    struct debug_sym *s;     if (debug_info) {        debug_info->sym =            (struct debug_sym *)tcc_realloc (debug_info->sym,                                             sizeof(struct debug_sym) *                                             (debug_info->n_sym + 1));        s = debug_info->sym + debug_info->n_sym++;        s->type = type;        s->value = value;        s->str = tcc_strdup(str);        s->sec = sec;        s->sym_index = sym_index;    }    else if (sec)        put_stabs_r (s1, str, type, 0, 0, value, sec, sym_index);    else        put_stabs (s1, str, type, 0, 0, value);} static void tcc_debug_stabn(int type, int value){    if (type == N_LBRAC) {        struct debug_info *info =            (struct debug_info *) tcc_mallocz(sizeof (*info));         info->start = value;        info->parent = debug_info;        if (debug_info) {            if (debug_info->child) {                if (debug_info->child->last)                    debug_info->child->last->next = info;                else                    debug_info->child->next = info;                debug_info->child->last = info;            }            else                debug_info->child = info;        }        else            debug_info_root = info;        debug_info = info;    }    else {        debug_info->end = value;        debug_info = debug_info->parent;    }} static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result){    int type;    int n = 0;

Lines 1–500 of 8583.