/* * 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. Load more
/* * 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_parser static void init_prec(void); #endif /********************************************************/ #ifndef CONFIG_TCC_ASM ST_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 0 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); } } #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;