| 1 | /* |
| 2 | * TCC - Tiny C Compiler |
| 3 | * |
| 4 | * Copyright (c) 2001-2004 Fabrice Bellard |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 19 | */ |
| 20 | |
| 21 | #define USING_GLOBALS |
| 22 | #include "tcc.h" |
| 23 | |
| 24 | /********************************************************/ |
| 25 | /* global variables */ |
| 26 | |
| 27 | /* loc : local variable index |
| 28 | ind : output code index |
| 29 | rsym: return symbol |
| 30 | anon_sym: anonymous symbol index |
| 31 | */ |
| 32 | ST_DATA int rsym, anon_sym, ind, loc; |
| 33 | |
| 34 | ST_DATA Sym *global_stack; |
| 35 | ST_DATA Sym *local_stack; |
| 36 | ST_DATA Sym *define_stack; |
| 37 | ST_DATA Sym *global_label_stack; |
| 38 | ST_DATA Sym *local_label_stack; |
| 39 | |
| 40 | static Sym *sym_free_first; |
| 41 | static void **sym_pools; |
| 42 | static int nb_sym_pools; |
| 43 | |
| 44 | static Sym *all_cleanups, *pending_gotos; |
| 45 | static int local_scope; |
| 46 | static int in_sizeof; |
| 47 | static int in_generic; |
| 48 | static int section_sym; |
| 49 | |
| 50 | ST_DATA SValue *vtop; |
| 51 | static SValue _vstack[1 + VSTACK_SIZE]; |
| 52 | #define vstack (_vstack + 1) |
| 53 | |
| 54 | ST_DATA int const_wanted; /* true if constant wanted */ |
| 55 | ST_DATA int nocode_wanted; /* no code generation wanted */ |
| 56 | #define unevalmask 0xffff /* unevaluated subexpression */ |
| 57 | #define NODATA_WANTED (nocode_wanted > 0) /* no static data output wanted either */ |
| 58 | #define STATIC_DATA_WANTED (nocode_wanted & 0xC0000000) /* only static data output */ |
| 59 | |
| 60 | /* Automagical code suppression ----> */ |
| 61 | #define CODE_OFF() (nocode_wanted |= 0x20000000) |
| 62 | #define CODE_ON() (nocode_wanted &= ~0x20000000) |
| 63 | |
| 64 | /* Clear 'nocode_wanted' at label if it was used */ |
| 65 | ST_FUNC void gsym(int t) { if (t) { gsym_addr(t, ind); CODE_ON(); }} |
| 66 | static int gind(void) { CODE_ON(); return ind; } |
| 67 | |
| 68 | /* Set 'nocode_wanted' after unconditional jumps */ |
| 69 | static void gjmp_addr_acs(int t) { gjmp_addr(t); CODE_OFF(); } |
| 70 | static int gjmp_acs(int t) { t = gjmp(t); CODE_OFF(); return t; } |
| 71 | |
| 72 | /* These are #undef'd at the end of this file */ |
| 73 | #define gjmp_addr gjmp_addr_acs |
| 74 | #define gjmp gjmp_acs |
| 75 | /* <---- */ |
| 76 | |
| 77 | ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ |
| 78 | ST_DATA CType func_vt; /* current function return type (used by return instruction) */ |
| 79 | ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ |
| 80 | ST_DATA int func_vc; |
| 81 | static int last_line_num, new_file, func_ind; /* debug info control */ |
| 82 | ST_DATA const char *funcname; |
| 83 | ST_DATA CType int_type, func_old_type, char_type, char_pointer_type; |
| 84 | static CString initstr; |
| 85 | |
| 86 | #if PTR_SIZE == 4 |
| 87 | #define VT_SIZE_T (VT_INT | VT_UNSIGNED) |
| 88 | #define VT_PTRDIFF_T VT_INT |
| 89 | #elif LONG_SIZE == 4 |
| 90 | #define VT_SIZE_T (VT_LLONG | VT_UNSIGNED) |
| 91 | #define VT_PTRDIFF_T VT_LLONG |
| 92 | #else |
| 93 | #define VT_SIZE_T (VT_LONG | VT_LLONG | VT_UNSIGNED) |
| 94 | #define VT_PTRDIFF_T (VT_LONG | VT_LLONG) |
| 95 | #endif |
| 96 | |
| 97 | ST_DATA struct switch_t { |
| 98 | struct case_t { |
| 99 | int64_t v1, v2; |
| 100 | int sym; |
| 101 | } **p; int n; /* list of case ranges */ |
| 102 | int def_sym; /* default symbol */ |
| 103 | int *bsym; |
| 104 | struct scope *scope; |
| 105 | struct switch_t *prev; |
| 106 | SValue sv; |
| 107 | } *cur_switch; /* current switch */ |
| 108 | |
| 109 | #define MAX_TEMP_LOCAL_VARIABLE_NUMBER 8 |
| 110 | /*list of temporary local variables on the stack in current function. */ |
| 111 | ST_DATA struct temp_local_variable { |
| 112 | int location; //offset on stack. Svalue.c.i |
| 113 | short size; |
| 114 | short align; |
| 115 | } arr_temp_local_vars[MAX_TEMP_LOCAL_VARIABLE_NUMBER]; |
| 116 | short nb_temp_local_vars; |
| 117 | |
| 118 | static struct scope { |
| 119 | struct scope *prev; |
| 120 | struct { int loc, num; } vla; |
| 121 | struct { Sym *s; int n; } cl; |
| 122 | int *bsym, *csym; |
| 123 | Sym *lstk, *llstk; |
| 124 | } *cur_scope, *loop_scope, *root_scope; |
| 125 | |
| 126 | typedef struct { |
| 127 | Section *sec; |
| 128 | int local_offset; |
| 129 | Sym *flex_array_ref; |
| 130 | } init_params; |
| 131 | |
| 132 | /********************************************************/ |
| 133 | /* stab debug support */ |
| 134 | |
| 135 | static const struct { |
| 136 | int type; |
| 137 | const char *name; |
| 138 | } default_debug[] = { |
| 139 | { VT_INT, "int:t1=r1;-2147483648;2147483647;" }, |
| 140 | { VT_BYTE, "char:t2=r2;0;127;" }, |
| 141 | #if LONG_SIZE == 4 |
| 142 | { VT_LONG | VT_INT, "long int:t3=r3;-2147483648;2147483647;" }, |
| 143 | #else |
| 144 | { VT_LLONG | VT_LONG, "long int:t3=r3;-9223372036854775808;9223372036854775807;" }, |
| 145 | #endif |
| 146 | { VT_INT | VT_UNSIGNED, "unsigned int:t4=r4;0;037777777777;" }, |
| 147 | #if LONG_SIZE == 4 |
| 148 | { VT_LONG | VT_INT | VT_UNSIGNED, "long unsigned int:t5=r5;0;037777777777;" }, |
| 149 | #else |
| 150 | /* use octal instead of -1 so size_t works (-gstabs+ in gcc) */ |
| 151 | { VT_LLONG | VT_LONG | VT_UNSIGNED, "long unsigned int:t5=r5;0;01777777777777777777777;" }, |
| 152 | #endif |
| 153 | { VT_QLONG, "__int128:t6=r6;0;-1;" }, |
| 154 | { VT_QLONG | VT_UNSIGNED, "__int128 unsigned:t7=r7;0;-1;" }, |
| 155 | { VT_LLONG, "long long int:t8=r8;-9223372036854775808;9223372036854775807;" }, |
| 156 | { VT_LLONG | VT_UNSIGNED, "long long unsigned int:t9=r9;0;01777777777777777777777;" }, |
| 157 | { VT_SHORT, "short int:t10=r10;-32768;32767;" }, |
| 158 | { VT_SHORT | VT_UNSIGNED, "short unsigned int:t11=r11;0;65535;" }, |
| 159 | { VT_BYTE | VT_DEFSIGN, "signed char:t12=r12;-128;127;" }, |
| 160 | { VT_BYTE | VT_DEFSIGN | VT_UNSIGNED, "unsigned char:t13=r13;0;255;" }, |
| 161 | { VT_FLOAT, "float:t14=r1;4;0;" }, |
| 162 | { VT_DOUBLE, "double:t15=r1;8;0;" }, |
| 163 | { VT_LDOUBLE, "long double:t16=r1;16;0;" }, |
| 164 | { -1, "_Float32:t17=r1;4;0;" }, |
| 165 | { -1, "_Float64:t18=r1;8;0;" }, |
| 166 | { -1, "_Float128:t19=r1;16;0;" }, |
| 167 | { -1, "_Float32x:t20=r1;8;0;" }, |
| 168 | { -1, "_Float64x:t21=r1;16;0;" }, |
| 169 | { -1, "_Decimal32:t22=r1;4;0;" }, |
| 170 | { -1, "_Decimal64:t23=r1;8;0;" }, |
| 171 | { -1, "_Decimal128:t24=r1;16;0;" }, |
| 172 | /* if default char is unsigned */ |
| 173 | { VT_BYTE | VT_UNSIGNED, "unsigned char:t25=r25;0;255;" }, |
| 174 | /* boolean type */ |
| 175 | { VT_BOOL, "bool:t26=r26;0;255;" }, |
| 176 | { VT_VOID, "void:t27=27" }, |
| 177 | }; |
| 178 | |
| 179 | static int debug_next_type; |
| 180 | |
| 181 | static struct debug_hash { |
| 182 | int debug_type; |
| 183 | Sym *type; |
| 184 | } *debug_hash; |
| 185 | |
| 186 | static int n_debug_hash; |
| 187 | |
| 188 | static struct debug_info { |
| 189 | int start; |
| 190 | int end; |
| 191 | int n_sym; |
| 192 | struct debug_sym { |
| 193 | int type; |
| 194 | unsigned long value; |
| 195 | char *str; |
| 196 | Section *sec; |
| 197 | int sym_index; |
| 198 | } *sym; |
| 199 | struct debug_info *child, *next, *last, *parent; |
| 200 | } *debug_info, *debug_info_root; |
| 201 | |
| 202 | /********************************************************/ |
| 203 | #if 1 |
| 204 | #define precedence_parser |
| 205 | static void init_prec(void); |
| 206 | #endif |
| 207 | /********************************************************/ |
| 208 | #ifndef CONFIG_TCC_ASM |
| 209 | ST_FUNC void asm_instr(void) |
| 210 | { |
| 211 | tcc_error("inline asm() not supported" ); |
| 212 | } |
| 213 | ST_FUNC void asm_global_instr(void) |
| 214 | { |
| 215 | tcc_error("inline asm() not supported" ); |
| 216 | } |
| 217 | #endif |
| 218 | |
| 219 | /* ------------------------------------------------------------------------- */ |
| 220 | static void gen_cast(CType *type); |
| 221 | static void gen_cast_s(int t); |
| 222 | static inline CType *pointed_type(CType *type); |
| 223 | static int is_compatible_types(CType *type1, CType *type2); |
| 224 | static int parse_btype(CType *type, AttributeDef *ad); |
| 225 | static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td); |
| 226 | static void parse_expr_type(CType *type); |
| 227 | static void init_putv(init_params *p, CType *type, unsigned long c); |
| 228 | static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags); |
| 229 | static void block(int is_expr); |
| 230 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); |
| 231 | static void decl(int l); |
| 232 | static int decl0(int l, int is_for_loop_init, Sym *); |
| 233 | static void expr_eq(void); |
| 234 | static void vla_runtime_type_size(CType *type, int *a); |
| 235 | static int is_compatible_unqualified_types(CType *type1, CType *type2); |
| 236 | static inline int64_t expr_const64(void); |
| 237 | static void vpush64(int ty, unsigned long long v); |
| 238 | static void vpush(CType *type); |
| 239 | static int gvtst(int inv, int t); |
| 240 | static void gen_inline_functions(TCCState *s); |
| 241 | static void free_inline_functions(TCCState *s); |
| 242 | static void skip_or_save_block(TokenString **str); |
| 243 | static void gv_dup(void); |
| 244 | static int get_temp_local_var(int size,int align); |
| 245 | static void clear_temp_local_var_list(); |
| 246 | static void cast_error(CType *st, CType *dt); |
| 247 | |
| 248 | ST_INLN int is_float(int t) |
| 249 | { |
| 250 | int bt = t & VT_BTYPE; |
| 251 | return bt == VT_LDOUBLE |
| 252 | || bt == VT_DOUBLE |
| 253 | || bt == VT_FLOAT |
| 254 | || bt == VT_QFLOAT; |
| 255 | } |
| 256 | |
| 257 | static inline int is_integer_btype(int bt) |
| 258 | { |
| 259 | return bt == VT_BYTE |
| 260 | || bt == VT_BOOL |
| 261 | || bt == VT_SHORT |
| 262 | || bt == VT_INT |
| 263 | || bt == VT_LLONG; |
| 264 | } |
| 265 | |
| 266 | static int btype_size(int bt) |
| 267 | { |
| 268 | return bt == VT_BYTE || bt == VT_BOOL ? 1 : |
| 269 | bt == VT_SHORT ? 2 : |
| 270 | bt == VT_INT ? 4 : |
| 271 | bt == VT_LLONG ? 8 : |
| 272 | bt == VT_PTR ? PTR_SIZE : 0; |
| 273 | } |
| 274 | |
| 275 | /* returns function return register from type */ |
| 276 | static int R_RET(int t) |
| 277 | { |
| 278 | if (!is_float(t)) |
| 279 | return REG_IRET; |
| 280 | #ifdef TCC_TARGET_X86_64 |
| 281 | if ((t & VT_BTYPE) == VT_LDOUBLE) |
| 282 | return TREG_ST0; |
| 283 | #elif defined TCC_TARGET_RISCV64 |
| 284 | if ((t & VT_BTYPE) == VT_LDOUBLE) |
| 285 | return REG_IRET; |
| 286 | #endif |
| 287 | return REG_FRET; |
| 288 | } |
| 289 | |
| 290 | /* returns 2nd function return register, if any */ |
| 291 | static int R2_RET(int t) |
| 292 | { |
| 293 | t &= VT_BTYPE; |
| 294 | #if PTR_SIZE == 4 |
| 295 | if (t == VT_LLONG) |
| 296 | return REG_IRE2; |
| 297 | #elif defined TCC_TARGET_X86_64 |
| 298 | if (t == VT_QLONG) |
| 299 | return REG_IRE2; |
| 300 | if (t == VT_QFLOAT) |
| 301 | return REG_FRE2; |
| 302 | #elif defined TCC_TARGET_RISCV64 |
| 303 | if (t == VT_LDOUBLE) |
| 304 | return REG_IRE2; |
| 305 | #endif |
| 306 | return VT_CONST; |
| 307 | } |
| 308 | |
| 309 | /* returns true for two-word types */ |
| 310 | #define USING_TWO_WORDS(t) (R2_RET(t) != VT_CONST) |
| 311 | |
| 312 | /* put function return registers to stack value */ |
| 313 | static void PUT_R_RET(SValue *sv, int t) |
| 314 | { |
| 315 | sv->r = R_RET(t), sv->r2 = R2_RET(t); |
| 316 | } |
| 317 | |
| 318 | /* returns function return register class for type t */ |
| 319 | static int RC_RET(int t) |
| 320 | { |
| 321 | return reg_classes[R_RET(t)] & ~(RC_FLOAT | RC_INT); |
| 322 | } |
| 323 | |
| 324 | /* returns generic register class for type t */ |
| 325 | static int RC_TYPE(int t) |
| 326 | { |
| 327 | if (!is_float(t)) |
| 328 | return RC_INT; |
| 329 | #ifdef TCC_TARGET_X86_64 |
| 330 | if ((t & VT_BTYPE) == VT_LDOUBLE) |
| 331 | return RC_ST0; |
| 332 | if ((t & VT_BTYPE) == VT_QFLOAT) |
| 333 | return RC_FRET; |
| 334 | #elif defined TCC_TARGET_RISCV64 |
| 335 | if ((t & VT_BTYPE) == VT_LDOUBLE) |
| 336 | return RC_INT; |
| 337 | #endif |
| 338 | return RC_FLOAT; |
| 339 | } |
| 340 | |
| 341 | /* returns 2nd register class corresponding to t and rc */ |
| 342 | static int RC2_TYPE(int t, int rc) |
| 343 | { |
| 344 | if (!USING_TWO_WORDS(t)) |
| 345 | return 0; |
| 346 | #ifdef RC_IRE2 |
| 347 | if (rc == RC_IRET) |
| 348 | return RC_IRE2; |
| 349 | #endif |
| 350 | #ifdef RC_FRE2 |
| 351 | if (rc == RC_FRET) |
| 352 | return RC_FRE2; |
| 353 | #endif |
| 354 | if (rc & RC_FLOAT) |
| 355 | return RC_FLOAT; |
| 356 | return RC_INT; |
| 357 | } |
| 358 | |
| 359 | /* we use our own 'finite' function to avoid potential problems with |
| 360 | non standard math libs */ |
| 361 | /* XXX: endianness dependent */ |
| 362 | ST_FUNC int ieee_finite(double d) |
| 363 | { |
| 364 | int p[4]; |
| 365 | memcpy(p, &d, sizeof(double)); |
| 366 | return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; |
| 367 | } |
| 368 | |
| 369 | /* compiling intel long double natively */ |
| 370 | #if (defined __i386__ || defined __x86_64__) \ |
| 371 | && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) |
| 372 | # define TCC_IS_NATIVE_387 |
| 373 | #endif |
| 374 | |
| 375 | ST_FUNC void test_lvalue(void) |
| 376 | { |
| 377 | if (!(vtop->r & VT_LVAL)) |
| 378 | expect("lvalue" ); |
| 379 | } |
| 380 | |
| 381 | ST_FUNC void check_vstack(void) |
| 382 | { |
| 383 | if (vtop != vstack - 1) |
| 384 | tcc_error("internal compiler error: vstack leak (%d)" , |
| 385 | (int)(vtop - vstack + 1)); |
| 386 | } |
| 387 | |
| 388 | /* ------------------------------------------------------------------------- */ |
| 389 | /* vstack debugging aid */ |
| 390 | |
| 391 | #if 0 |
| 392 | void pv (const char *lbl, int a, int b) |
| 393 | { |
| 394 | int i; |
| 395 | for (i = a; i < a + b; ++i) { |
| 396 | SValue *p = &vtop[-i]; |
| 397 | printf("%s vtop[-%d] : type.t:%04x r:%04x r2:%04x c.i:%d\n" , |
| 398 | lbl, i, p->type.t, p->r, p->r2, (int)p->c.i); |
| 399 | } |
| 400 | } |
| 401 | #endif |
| 402 | |
| 403 | /* ------------------------------------------------------------------------- */ |
| 404 | /* start of translation unit info */ |
| 405 | ST_FUNC void tcc_debug_start(TCCState *s1) |
| 406 | { |
| 407 | if (s1->do_debug) { |
| 408 | int i; |
| 409 | char buf[512]; |
| 410 | |
| 411 | /* file info: full path + filename */ |
| 412 | section_sym = put_elf_sym(symtab_section, 0, 0, |
| 413 | ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0, |
| 414 | text_section->sh_num, NULL); |
| 415 | getcwd(buf, sizeof(buf)); |
| 416 | #ifdef _WIN32 |
| 417 | normalize_slashes(buf); |
| 418 | #endif |
| 419 | pstrcat(buf, sizeof(buf), "/" ); |
| 420 | put_stabs_r(s1, buf, N_SO, 0, 0, |
| 421 | text_section->data_offset, text_section, section_sym); |
| 422 | put_stabs_r(s1, file->prev ? file->prev->filename : file->filename, |
| 423 | N_SO, 0, 0, |
| 424 | text_section->data_offset, text_section, section_sym); |
| 425 | for (i = 0; i < sizeof (default_debug) / sizeof (default_debug[0]); i++) |
| 426 | put_stabs(s1, default_debug[i].name, N_LSYM, 0, 0, 0); |
| 427 | |
| 428 | new_file = last_line_num = 0; |
| 429 | func_ind = -1; |
| 430 | debug_next_type = sizeof(default_debug) / sizeof(default_debug[0]); |
| 431 | debug_hash = NULL; |
| 432 | n_debug_hash = 0; |
| 433 | |
| 434 | /* we're currently 'including' the <command line> */ |
| 435 | tcc_debug_bincl(s1); |
| 436 | } |
| 437 | |
| 438 | /* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
| 439 | symbols can be safely used */ |
| 440 | put_elf_sym(symtab_section, 0, 0, |
| 441 | ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, |
| 442 | SHN_ABS, file->filename); |
| 443 | } |
| 444 | |
| 445 | static void tcc_debug_stabs (TCCState *s1, const char *str, int type, unsigned long value, |
| 446 | Section *sec, int sym_index) |
| 447 | { |
| 448 | struct debug_sym *s; |
| 449 | |
| 450 | if (debug_info) { |
| 451 | debug_info->sym = |
| 452 | (struct debug_sym *)tcc_realloc (debug_info->sym, |
| 453 | sizeof(struct debug_sym) * |
| 454 | (debug_info->n_sym + 1)); |
| 455 | s = debug_info->sym + debug_info->n_sym++; |
| 456 | s->type = type; |
| 457 | s->value = value; |
| 458 | s->str = tcc_strdup(str); |
| 459 | s->sec = sec; |
| 460 | s->sym_index = sym_index; |
| 461 | } |
| 462 | else if (sec) |
| 463 | put_stabs_r (s1, str, type, 0, 0, value, sec, sym_index); |
| 464 | else |
| 465 | put_stabs (s1, str, type, 0, 0, value); |
| 466 | } |
| 467 | |
| 468 | static void tcc_debug_stabn(int type, int value) |
| 469 | { |
| 470 | if (type == N_LBRAC) { |
| 471 | struct debug_info *info = |
| 472 | (struct debug_info *) tcc_mallocz(sizeof (*info)); |
| 473 | |
| 474 | info->start = value; |
| 475 | info->parent = debug_info; |
| 476 | if (debug_info) { |
| 477 | if (debug_info->child) { |
| 478 | if (debug_info->child->last) |
| 479 | debug_info->child->last->next = info; |
| 480 | else |
| 481 | debug_info->child->next = info; |
| 482 | debug_info->child->last = info; |
| 483 | } |
| 484 | else |
| 485 | debug_info->child = info; |
| 486 | } |
| 487 | else |
| 488 | debug_info_root = info; |
| 489 | debug_info = info; |
| 490 | } |
| 491 | else { |
| 492 | debug_info->end = value; |
| 493 | debug_info = debug_info->parent; |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result) |
| 498 | { |
| 499 | int type; |
| 500 | int n = 0; |
| 501 | int debug_type = -1; |
| 502 | Sym *t = s; |
| 503 | CString str; |
| 504 | |
| 505 | for (;;) { |
| 506 | type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE); |
| 507 | if ((type & VT_BTYPE) != VT_BYTE) |
| 508 | type &= ~VT_DEFSIGN; |
| 509 | if (type == VT_PTR || type == (VT_PTR | VT_ARRAY)) |
| 510 | n++, t = t->type.ref; |
| 511 | else |
| 512 | break; |
| 513 | } |
| 514 | if ((type & VT_BTYPE) == VT_STRUCT) { |
| 515 | int i; |
| 516 | |
| 517 | t = t->type.ref; |
| 518 | for (i = 0; i < n_debug_hash; i++) { |
| 519 | if (t == debug_hash[i].type) { |
| 520 | debug_type = debug_hash[i].debug_type; |
| 521 | break; |
| 522 | } |
| 523 | } |
| 524 | if (debug_type == -1) { |
| 525 | debug_type = ++debug_next_type; |
| 526 | debug_hash = (struct debug_hash *) |
| 527 | tcc_realloc (debug_hash, |
| 528 | (n_debug_hash + 1) * sizeof(*debug_hash)); |
| 529 | debug_hash[n_debug_hash].debug_type = debug_type; |
| 530 | debug_hash[n_debug_hash++].type = t; |
| 531 | cstr_new (&str); |
| 532 | cstr_printf (&str, "%s:T%d=%c%d" , |
| 533 | (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM |
| 534 | ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL), |
| 535 | debug_type, |
| 536 | IS_UNION (t->type.t) ? 'u' : 's', |
| 537 | t->c); |
| 538 | while (t->next) { |
| 539 | int pos, size, align; |
| 540 | |
| 541 | t = t->next; |
| 542 | cstr_printf (&str, "%s:" , |
| 543 | (t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM |
| 544 | ? "" : get_tok_str(t->v & ~SYM_FIELD, NULL)); |
| 545 | tcc_get_debug_info (s1, t, &str); |
| 546 | if (t->type.t & VT_BITFIELD) { |
| 547 | pos = t->c * 8 + BIT_POS(t->type.t); |
| 548 | size = BIT_SIZE(t->type.t); |
| 549 | } |
| 550 | else { |
| 551 | pos = t->c * 8; |
| 552 | size = type_size(&t->type, &align) * 8; |
| 553 | } |
| 554 | cstr_printf (&str, ",%d,%d;" , pos, size); |
| 555 | } |
| 556 | cstr_printf (&str, ";" ); |
| 557 | tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0); |
| 558 | cstr_free (&str); |
| 559 | } |
| 560 | } |
| 561 | else if (IS_ENUM(type)) { |
| 562 | Sym *e = t = t->type.ref; |
| 563 | |
| 564 | debug_type = ++debug_next_type; |
| 565 | cstr_new (&str); |
| 566 | cstr_printf (&str, "%s:T%d=e" , |
| 567 | (t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM |
| 568 | ? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL), |
| 569 | debug_type); |
| 570 | while (t->next) { |
| 571 | t = t->next; |
| 572 | cstr_printf (&str, "%s:" , |
| 573 | (t->v & ~SYM_FIELD) >= SYM_FIRST_ANOM |
| 574 | ? "" : get_tok_str(t->v & ~SYM_FIELD, NULL)); |
| 575 | cstr_printf (&str, e->type.t & VT_UNSIGNED ? "%u," : "%d," , |
| 576 | (int)t->enum_val); |
| 577 | } |
| 578 | cstr_printf (&str, ";" ); |
| 579 | tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0); |
| 580 | cstr_free (&str); |
| 581 | } |
| 582 | else if ((type & VT_BTYPE) != VT_FUNC) { |
| 583 | type &= ~VT_STRUCT_MASK; |
| 584 | for (debug_type = 1; |
| 585 | debug_type <= sizeof(default_debug) / sizeof(default_debug[0]); |
| 586 | debug_type++) |
| 587 | if (default_debug[debug_type - 1].type == type) |
| 588 | break; |
| 589 | if (debug_type > sizeof(default_debug) / sizeof(default_debug[0])) |
| 590 | return; |
| 591 | } |
| 592 | if (n > 0) |
| 593 | cstr_printf (result, "%d=" , ++debug_next_type); |
| 594 | t = s; |
| 595 | for (;;) { |
| 596 | type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE); |
| 597 | if ((type & VT_BTYPE) != VT_BYTE) |
| 598 | type &= ~VT_DEFSIGN; |
| 599 | if (type == VT_PTR) |
| 600 | cstr_printf (result, "%d=*" , ++debug_next_type); |
| 601 | else if (type == (VT_PTR | VT_ARRAY)) |
| 602 | cstr_printf (result, "%d=ar1;0;%d;" , |
| 603 | ++debug_next_type, t->type.ref->c - 1); |
| 604 | else if (type == VT_FUNC) { |
| 605 | cstr_printf (result, "%d=f" , ++debug_next_type); |
| 606 | tcc_get_debug_info (s1, t->type.ref, result); |
| 607 | return; |
| 608 | } |
| 609 | else |
| 610 | break; |
| 611 | t = t->type.ref; |
| 612 | } |
| 613 | cstr_printf (result, "%d" , debug_type); |
| 614 | } |
| 615 | |
| 616 | static void tcc_debug_finish (TCCState *s1, struct debug_info *cur) |
| 617 | { |
| 618 | while (cur) { |
| 619 | int i; |
| 620 | struct debug_info *next = cur->next; |
| 621 | |
| 622 | for (i = 0; i < cur->n_sym; i++) { |
| 623 | struct debug_sym *s = &cur->sym[i]; |
| 624 | |
| 625 | if (s->sec) |
| 626 | put_stabs_r(s1, s->str, s->type, 0, 0, s->value, |
| 627 | s->sec, s->sym_index); |
| 628 | else |
| 629 | put_stabs(s1, s->str, s->type, 0, 0, s->value); |
| 630 | tcc_free (s->str); |
| 631 | } |
| 632 | tcc_free (cur->sym); |
| 633 | put_stabn(s1, N_LBRAC, 0, 0, cur->start); |
| 634 | tcc_debug_finish (s1, cur->child); |
| 635 | put_stabn(s1, N_RBRAC, 0, 0, cur->end); |
| 636 | tcc_free (cur); |
| 637 | cur = next; |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | static void tcc_add_debug_info(TCCState *s1, int param, Sym *s, Sym *e) |
| 642 | { |
| 643 | CString debug_str; |
| 644 | cstr_new (&debug_str); |
| 645 | for (; s != e; s = s->prev) { |
| 646 | if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL) |
| 647 | continue; |
| 648 | cstr_reset (&debug_str); |
| 649 | cstr_printf (&debug_str, "%s:%s" , get_tok_str(s->v, NULL), param ? "p" : "" ); |
| 650 | tcc_get_debug_info(s1, s, &debug_str); |
| 651 | tcc_debug_stabs(s1, debug_str.data, param ? N_PSYM : N_LSYM, s->c, NULL, 0); |
| 652 | } |
| 653 | cstr_free (&debug_str); |
| 654 | } |
| 655 | |
| 656 | static void tcc_debug_extern_sym(TCCState *s1, Sym *sym, int sh_num, int sym_bind) |
| 657 | { |
| 658 | Section *s = s1->sections[sh_num]; |
| 659 | CString str; |
| 660 | |
| 661 | cstr_new (&str); |
| 662 | cstr_printf (&str, "%s:%c" , |
| 663 | get_tok_str(sym->v, NULL), |
| 664 | sym_bind == STB_GLOBAL ? 'G' : local_scope ? 'V' : 'S' |
| 665 | ); |
| 666 | tcc_get_debug_info(s1, sym, &str); |
| 667 | if (sym_bind == STB_GLOBAL) |
| 668 | tcc_debug_stabs(s1, str.data, N_GSYM, 0, NULL, 0); |
| 669 | else |
| 670 | tcc_debug_stabs(s1, str.data, |
| 671 | (sym->type.t & VT_STATIC) && data_section == s |
| 672 | ? N_STSYM : N_LCSYM, 0, s, sym->c); |
| 673 | cstr_free (&str); |
| 674 | } |
| 675 | |
| 676 | static void tcc_debug_typedef(TCCState *s1, Sym *sym) |
| 677 | { |
| 678 | CString str; |
| 679 | |
| 680 | cstr_new (&str); |
| 681 | cstr_printf (&str, "%s:t" , |
| 682 | (sym->v & ~SYM_FIELD) >= SYM_FIRST_ANOM |
| 683 | ? "" : get_tok_str(sym->v & ~SYM_FIELD, NULL)); |
| 684 | tcc_get_debug_info(s1, sym, &str); |
| 685 | tcc_debug_stabs(s1, str.data, N_LSYM, 0, NULL, 0); |
| 686 | cstr_free (&str); |
| 687 | } |
| 688 | |
| 689 | /* put end of translation unit info */ |
| 690 | ST_FUNC void tcc_debug_end(TCCState *s1) |
| 691 | { |
| 692 | if (!s1->do_debug) |
| 693 | return; |
| 694 | put_stabs_r(s1, NULL, N_SO, 0, 0, |
| 695 | text_section->data_offset, text_section, section_sym); |
| 696 | tcc_free(debug_hash); |
| 697 | } |
| 698 | |
| 699 | static BufferedFile* put_new_file(TCCState *s1) |
| 700 | { |
| 701 | BufferedFile *f = file; |
| 702 | /* use upper file if from inline ":asm:" */ |
| 703 | if (f->filename[0] == ':') |
| 704 | f = f->prev; |
| 705 | if (f && new_file) { |
| 706 | put_stabs_r(s1, f->filename, N_SOL, 0, 0, ind, text_section, section_sym); |
| 707 | new_file = last_line_num = 0; |
| 708 | } |
| 709 | return f; |
| 710 | } |
| 711 | |
| 712 | /* generate line number info */ |
| 713 | ST_FUNC void tcc_debug_line(TCCState *s1) |
| 714 | { |
| 715 | BufferedFile *f; |
| 716 | if (!s1->do_debug |
| 717 | || cur_text_section != text_section |
| 718 | || !(f = put_new_file(s1)) |
| 719 | || last_line_num == f->line_num) |
| 720 | return; |
| 721 | if (func_ind != -1) { |
| 722 | put_stabn(s1, N_SLINE, 0, f->line_num, ind - func_ind); |
| 723 | } else { |
| 724 | /* from tcc_assemble */ |
| 725 | put_stabs_r(s1, NULL, N_SLINE, 0, f->line_num, ind, text_section, section_sym); |
| 726 | } |
| 727 | last_line_num = f->line_num; |
| 728 | } |
| 729 | |
| 730 | /* put function symbol */ |
| 731 | ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym) |
| 732 | { |
| 733 | CString debug_str; |
| 734 | BufferedFile *f; |
| 735 | if (!s1->do_debug) |
| 736 | return; |
| 737 | debug_info_root = NULL; |
| 738 | debug_info = NULL; |
| 739 | tcc_debug_stabn(N_LBRAC, ind - func_ind); |
| 740 | if (!(f = put_new_file(s1))) |
| 741 | return; |
| 742 | cstr_new (&debug_str); |
| 743 | cstr_printf(&debug_str, "%s:%c" , funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); |
| 744 | tcc_get_debug_info(s1, sym->type.ref, &debug_str); |
| 745 | put_stabs_r(s1, debug_str.data, N_FUN, 0, f->line_num, 0, cur_text_section, sym->c); |
| 746 | cstr_free (&debug_str); |
| 747 | |
| 748 | tcc_debug_line(s1); |
| 749 | } |
| 750 | |
| 751 | /* put function size */ |
| 752 | ST_FUNC void tcc_debug_funcend(TCCState *s1, int size) |
| 753 | { |
| 754 | if (!s1->do_debug) |
| 755 | return; |
| 756 | tcc_debug_stabn(N_RBRAC, size); |
| 757 | tcc_debug_finish (s1, debug_info_root); |
| 758 | } |
| 759 | |
| 760 | /* put alternative filename */ |
| 761 | ST_FUNC void tcc_debug_putfile(TCCState *s1, const char *filename) |
| 762 | { |
| 763 | if (0 == strcmp(file->filename, filename)) |
| 764 | return; |
| 765 | pstrcpy(file->filename, sizeof(file->filename), filename); |
| 766 | new_file = 1; |
| 767 | } |
| 768 | |
| 769 | /* begin of #include */ |
| 770 | ST_FUNC void tcc_debug_bincl(TCCState *s1) |
| 771 | { |
| 772 | if (!s1->do_debug) |
| 773 | return; |
| 774 | put_stabs(s1, file->filename, N_BINCL, 0, 0, 0); |
| 775 | new_file = 1; |
| 776 | } |
| 777 | |
| 778 | /* end of #include */ |
| 779 | ST_FUNC void tcc_debug_eincl(TCCState *s1) |
| 780 | { |
| 781 | if (!s1->do_debug) |
| 782 | return; |
| 783 | put_stabn(s1, N_EINCL, 0, 0, 0); |
| 784 | new_file = 1; |
| 785 | } |
| 786 | |
| 787 | /* ------------------------------------------------------------------------- */ |
| 788 | /* initialize vstack and types. This must be done also for tcc -E */ |
| 789 | ST_FUNC void tccgen_init(TCCState *s1) |
| 790 | { |
| 791 | vtop = vstack - 1; |
| 792 | memset(vtop, 0, sizeof *vtop); |
| 793 | |
| 794 | /* define some often used types */ |
| 795 | int_type.t = VT_INT; |
| 796 | |
| 797 | char_type.t = VT_BYTE; |
| 798 | if (s1->char_is_unsigned) |
| 799 | char_type.t |= VT_UNSIGNED; |
| 800 | char_pointer_type = char_type; |
| 801 | mk_pointer(&char_pointer_type); |
| 802 | |
| 803 | func_old_type.t = VT_FUNC; |
| 804 | func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); |
| 805 | func_old_type.ref->f.func_call = FUNC_CDECL; |
| 806 | func_old_type.ref->f.func_type = FUNC_OLD; |
| 807 | #ifdef precedence_parser |
| 808 | init_prec(); |
| 809 | #endif |
| 810 | cstr_new(&initstr); |
| 811 | } |
| 812 | |
| 813 | ST_FUNC int tccgen_compile(TCCState *s1) |
| 814 | { |
| 815 | cur_text_section = NULL; |
| 816 | funcname = "" ; |
| 817 | anon_sym = SYM_FIRST_ANOM; |
| 818 | section_sym = 0; |
| 819 | const_wanted = 0; |
| 820 | nocode_wanted = 0x80000000; |
| 821 | local_scope = 0; |
| 822 | |
| 823 | tcc_debug_start(s1); |
| 824 | #ifdef TCC_TARGET_ARM |
| 825 | arm_init(s1); |
| 826 | #endif |
| 827 | #ifdef INC_DEBUG |
| 828 | printf("%s: **** new file\n" , file->filename); |
| 829 | #endif |
| 830 | parse_flags = PARSE_FLAG_PREPROCESS | PARSE_FLAG_TOK_NUM | PARSE_FLAG_TOK_STR; |
| 831 | next(); |
| 832 | decl(VT_CONST); |
| 833 | gen_inline_functions(s1); |
| 834 | check_vstack(); |
| 835 | /* end of translation unit info */ |
| 836 | tcc_debug_end(s1); |
| 837 | return 0; |
| 838 | } |
| 839 | |
| 840 | ST_FUNC void tccgen_finish(TCCState *s1) |
| 841 | { |
| 842 | cstr_free(&initstr); |
| 843 | free_inline_functions(s1); |
| 844 | sym_pop(&global_stack, NULL, 0); |
| 845 | sym_pop(&local_stack, NULL, 0); |
| 846 | /* free preprocessor macros */ |
| 847 | free_defines(NULL); |
| 848 | /* free sym_pools */ |
| 849 | dynarray_reset(&sym_pools, &nb_sym_pools); |
| 850 | sym_free_first = NULL; |
| 851 | } |
| 852 | |
| 853 | /* ------------------------------------------------------------------------- */ |
| 854 | ST_FUNC ElfSym *elfsym(Sym *s) |
| 855 | { |
| 856 | if (!s || !s->c) |
| 857 | return NULL; |
| 858 | return &((ElfSym *)symtab_section->data)[s->c]; |
| 859 | } |
| 860 | |
| 861 | /* apply storage attributes to Elf symbol */ |
| 862 | ST_FUNC void update_storage(Sym *sym) |
| 863 | { |
| 864 | ElfSym *esym; |
| 865 | int sym_bind, old_sym_bind; |
| 866 | |
| 867 | esym = elfsym(sym); |
| 868 | if (!esym) |
| 869 | return; |
| 870 | |
| 871 | if (sym->a.visibility) |
| 872 | esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) |
| 873 | | sym->a.visibility; |
| 874 | |
| 875 | if (sym->type.t & (VT_STATIC | VT_INLINE)) |
| 876 | sym_bind = STB_LOCAL; |
| 877 | else if (sym->a.weak) |
| 878 | sym_bind = STB_WEAK; |
| 879 | else |
| 880 | sym_bind = STB_GLOBAL; |
| 881 | old_sym_bind = ELFW(ST_BIND)(esym->st_info); |
| 882 | if (sym_bind != old_sym_bind) { |
| 883 | esym->st_info = ELFW(ST_INFO)(sym_bind, ELFW(ST_TYPE)(esym->st_info)); |
| 884 | } |
| 885 | |
| 886 | #ifdef TCC_TARGET_PE |
| 887 | if (sym->a.dllimport) |
| 888 | esym->st_other |= ST_PE_IMPORT; |
| 889 | if (sym->a.dllexport) |
| 890 | esym->st_other |= ST_PE_EXPORT; |
| 891 | #endif |
| 892 | |
| 893 | #if 0 |
| 894 | printf("storage %s: bind=%c vis=%d exp=%d imp=%d\n" , |
| 895 | get_tok_str(sym->v, NULL), |
| 896 | sym_bind == STB_WEAK ? 'w' : sym_bind == STB_LOCAL ? 'l' : 'g', |
| 897 | sym->a.visibility, |
| 898 | sym->a.dllexport, |
| 899 | sym->a.dllimport |
| 900 | ); |
| 901 | #endif |
| 902 | } |
| 903 | |
| 904 | /* ------------------------------------------------------------------------- */ |
| 905 | /* update sym->c so that it points to an external symbol in section |
| 906 | 'section' with value 'value' */ |
| 907 | |
| 908 | ST_FUNC void put_extern_sym2(Sym *sym, int sh_num, |
| 909 | addr_t value, unsigned long size, |
| 910 | int can_add_underscore) |
| 911 | { |
| 912 | int sym_type, sym_bind, info, other, t; |
| 913 | ElfSym *esym; |
| 914 | const char *name; |
| 915 | char buf1[256]; |
| 916 | |
| 917 | if (!sym->c) { |
| 918 | name = get_tok_str(sym->v, NULL); |
| 919 | t = sym->type.t; |
| 920 | if ((t & VT_BTYPE) == VT_FUNC) { |
| 921 | sym_type = STT_FUNC; |
| 922 | } else if ((t & VT_BTYPE) == VT_VOID) { |
| 923 | sym_type = STT_NOTYPE; |
| 924 | } else { |
| 925 | sym_type = STT_OBJECT; |
| 926 | } |
| 927 | if (t & (VT_STATIC | VT_INLINE)) |
| 928 | sym_bind = STB_LOCAL; |
| 929 | else |
| 930 | sym_bind = STB_GLOBAL; |
| 931 | other = 0; |
| 932 | |
| 933 | #ifdef TCC_TARGET_PE |
| 934 | if (sym_type == STT_FUNC && sym->type.ref) { |
| 935 | Sym *ref = sym->type.ref; |
| 936 | if (ref->a.nodecorate) { |
| 937 | can_add_underscore = 0; |
| 938 | } |
| 939 | if (ref->f.func_call == FUNC_STDCALL && can_add_underscore) { |
| 940 | sprintf(buf1, "_%s@%d" , name, ref->f.func_args * PTR_SIZE); |
| 941 | name = buf1; |
| 942 | other |= ST_PE_STDCALL; |
| 943 | can_add_underscore = 0; |
| 944 | } |
| 945 | } |
| 946 | #endif |
| 947 | |
| 948 | if (sym->asm_label) { |
| 949 | name = get_tok_str(sym->asm_label, NULL); |
| 950 | can_add_underscore = 0; |
| 951 | } |
| 952 | |
| 953 | if (tcc_state->leading_underscore && can_add_underscore) { |
| 954 | buf1[0] = '_'; |
| 955 | pstrcpy(buf1 + 1, sizeof(buf1) - 1, name); |
| 956 | name = buf1; |
| 957 | } |
| 958 | |
| 959 | info = ELFW(ST_INFO)(sym_bind, sym_type); |
| 960 | sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num, name); |
| 961 | |
| 962 | if (tcc_state->do_debug |
| 963 | && sym_type != STT_FUNC |
| 964 | && sym->v < SYM_FIRST_ANOM) |
| 965 | tcc_debug_extern_sym(tcc_state, sym, sh_num, sym_bind); |
| 966 | |
| 967 | } else { |
| 968 | esym = elfsym(sym); |
| 969 | esym->st_value = value; |
| 970 | esym->st_size = size; |
| 971 | esym->st_shndx = sh_num; |
| 972 | } |
| 973 | update_storage(sym); |
| 974 | } |
| 975 | |
| 976 | ST_FUNC void put_extern_sym(Sym *sym, Section *section, |
| 977 | addr_t value, unsigned long size) |
| 978 | { |
| 979 | int sh_num = section ? section->sh_num : SHN_UNDEF; |
| 980 | put_extern_sym2(sym, sh_num, value, size, 1); |
| 981 | } |
| 982 | |
| 983 | /* add a new relocation entry to symbol 'sym' in section 's' */ |
| 984 | ST_FUNC void greloca(Section *s, Sym *sym, unsigned long offset, int type, |
| 985 | addr_t addend) |
| 986 | { |
| 987 | int c = 0; |
| 988 | |
| 989 | if (nocode_wanted && s == cur_text_section) |
| 990 | return; |
| 991 | |
| 992 | if (sym) { |
| 993 | if (0 == sym->c) |
| 994 | put_extern_sym(sym, NULL, 0, 0); |
| 995 | c = sym->c; |
| 996 | } |
| 997 | |
| 998 | /* now we can add ELF relocation info */ |
| 999 | put_elf_reloca(symtab_section, s, offset, type, c, addend); |
| 1000 | } |
| 1001 | |
| 1002 | #if PTR_SIZE == 4 |
| 1003 | ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type) |
| 1004 | { |
| 1005 | greloca(s, sym, offset, type, 0); |
| 1006 | } |
| 1007 | #endif |
| 1008 | |
| 1009 | /* ------------------------------------------------------------------------- */ |
| 1010 | /* symbol allocator */ |
| 1011 | static Sym *__sym_malloc(void) |
| 1012 | { |
| 1013 | Sym *sym_pool, *sym, *last_sym; |
| 1014 | int i; |
| 1015 | |
| 1016 | sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); |
| 1017 | dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); |
| 1018 | |
| 1019 | last_sym = sym_free_first; |
| 1020 | sym = sym_pool; |
| 1021 | for(i = 0; i < SYM_POOL_NB; i++) { |
| 1022 | sym->next = last_sym; |
| 1023 | last_sym = sym; |
| 1024 | sym++; |
| 1025 | } |
| 1026 | sym_free_first = last_sym; |
| 1027 | return last_sym; |
| 1028 | } |
| 1029 | |
| 1030 | static inline Sym *sym_malloc(void) |
| 1031 | { |
| 1032 | Sym *sym; |
| 1033 | #ifndef SYM_DEBUG |
| 1034 | sym = sym_free_first; |
| 1035 | if (!sym) |
| 1036 | sym = __sym_malloc(); |
| 1037 | sym_free_first = sym->next; |
| 1038 | return sym; |
| 1039 | #else |
| 1040 | sym = tcc_malloc(sizeof(Sym)); |
| 1041 | return sym; |
| 1042 | #endif |
| 1043 | } |
| 1044 | |
| 1045 | ST_INLN void sym_free(Sym *sym) |
| 1046 | { |
| 1047 | #ifndef SYM_DEBUG |
| 1048 | sym->next = sym_free_first; |
| 1049 | sym_free_first = sym; |
| 1050 | #else |
| 1051 | tcc_free(sym); |
| 1052 | #endif |
| 1053 | } |
| 1054 | |
| 1055 | /* push, without hashing */ |
| 1056 | ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, int c) |
| 1057 | { |
| 1058 | Sym *s; |
| 1059 | |
| 1060 | s = sym_malloc(); |
| 1061 | memset(s, 0, sizeof *s); |
| 1062 | s->v = v; |
| 1063 | s->type.t = t; |
| 1064 | s->c = c; |
| 1065 | /* add in stack */ |
| 1066 | s->prev = *ps; |
| 1067 | *ps = s; |
| 1068 | return s; |
| 1069 | } |
| 1070 | |
| 1071 | /* find a symbol and return its associated structure. 's' is the top |
| 1072 | of the symbol stack */ |
| 1073 | ST_FUNC Sym *sym_find2(Sym *s, int v) |
| 1074 | { |
| 1075 | while (s) { |
| 1076 | if (s->v == v) |
| 1077 | return s; |
| 1078 | else if (s->v == -1) |
| 1079 | return NULL; |
| 1080 | s = s->prev; |
| 1081 | } |
| 1082 | return NULL; |
| 1083 | } |
| 1084 | |
| 1085 | /* structure lookup */ |
| 1086 | ST_INLN Sym *struct_find(int v) |
| 1087 | { |
| 1088 | v -= TOK_IDENT; |
| 1089 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
| 1090 | return NULL; |
| 1091 | return table_ident[v]->sym_struct; |
| 1092 | } |
| 1093 | |
| 1094 | /* find an identifier */ |
| 1095 | ST_INLN Sym *sym_find(int v) |
| 1096 | { |
| 1097 | v -= TOK_IDENT; |
| 1098 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
| 1099 | return NULL; |
| 1100 | return table_ident[v]->sym_identifier; |
| 1101 | } |
| 1102 | |
| 1103 | static int sym_scope(Sym *s) |
| 1104 | { |
| 1105 | if (IS_ENUM_VAL (s->type.t)) |
| 1106 | return s->type.ref->sym_scope; |
| 1107 | else |
| 1108 | return s->sym_scope; |
| 1109 | } |
| 1110 | |
| 1111 | /* push a given symbol on the symbol stack */ |
| 1112 | ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) |
| 1113 | { |
| 1114 | Sym *s, **ps; |
| 1115 | TokenSym *ts; |
| 1116 | |
| 1117 | if (local_stack) |
| 1118 | ps = &local_stack; |
| 1119 | else |
| 1120 | ps = &global_stack; |
| 1121 | s = sym_push2(ps, v, type->t, c); |
| 1122 | s->type.ref = type->ref; |
| 1123 | s->r = r; |
| 1124 | /* don't record fields or anonymous symbols */ |
| 1125 | /* XXX: simplify */ |
| 1126 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
| 1127 | /* record symbol in token array */ |
| 1128 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
| 1129 | if (v & SYM_STRUCT) |
| 1130 | ps = &ts->sym_struct; |
| 1131 | else |
| 1132 | ps = &ts->sym_identifier; |
| 1133 | s->prev_tok = *ps; |
| 1134 | *ps = s; |
| 1135 | s->sym_scope = local_scope; |
| 1136 | if (s->prev_tok && sym_scope(s->prev_tok) == s->sym_scope) |
| 1137 | tcc_error("redeclaration of '%s'" , |
| 1138 | get_tok_str(v & ~SYM_STRUCT, NULL)); |
| 1139 | } |
| 1140 | return s; |
| 1141 | } |
| 1142 | |
| 1143 | /* push a global identifier */ |
| 1144 | ST_FUNC Sym *global_identifier_push(int v, int t, int c) |
| 1145 | { |
| 1146 | Sym *s, **ps; |
| 1147 | s = sym_push2(&global_stack, v, t, c); |
| 1148 | s->r = VT_CONST | VT_SYM; |
| 1149 | /* don't record anonymous symbol */ |
| 1150 | if (v < SYM_FIRST_ANOM) { |
| 1151 | ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
| 1152 | /* modify the top most local identifier, so that sym_identifier will |
| 1153 | point to 's' when popped; happens when called from inline asm */ |
| 1154 | while (*ps != NULL && (*ps)->sym_scope) |
| 1155 | ps = &(*ps)->prev_tok; |
| 1156 | s->prev_tok = *ps; |
| 1157 | *ps = s; |
| 1158 | } |
| 1159 | return s; |
| 1160 | } |
| 1161 | |
| 1162 | /* pop symbols until top reaches 'b'. If KEEP is non-zero don't really |
| 1163 | pop them yet from the list, but do remove them from the token array. */ |
| 1164 | ST_FUNC void sym_pop(Sym **ptop, Sym *b, int keep) |
| 1165 | { |
| 1166 | Sym *s, *ss, **ps; |
| 1167 | TokenSym *ts; |
| 1168 | int v; |
| 1169 | |
| 1170 | s = *ptop; |
| 1171 | while(s != b) { |
| 1172 | ss = s->prev; |
| 1173 | v = s->v; |
| 1174 | /* remove symbol in token array */ |
| 1175 | /* XXX: simplify */ |
| 1176 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
| 1177 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
| 1178 | if (v & SYM_STRUCT) |
| 1179 | ps = &ts->sym_struct; |
| 1180 | else |
| 1181 | ps = &ts->sym_identifier; |
| 1182 | *ps = s->prev_tok; |
| 1183 | } |
| 1184 | if (!keep) |
| 1185 | sym_free(s); |
| 1186 | s = ss; |
| 1187 | } |
| 1188 | if (!keep) |
| 1189 | *ptop = b; |
| 1190 | } |
| 1191 | |
| 1192 | /* ------------------------------------------------------------------------- */ |
| 1193 | static void vcheck_cmp(void) |
| 1194 | { |
| 1195 | /* cannot let cpu flags if other instruction are generated. Also |
| 1196 | avoid leaving VT_JMP anywhere except on the top of the stack |
| 1197 | because it would complicate the code generator. |
| 1198 | |
| 1199 | Don't do this when nocode_wanted. vtop might come from |
| 1200 | !nocode_wanted regions (see 88_codeopt.c) and transforming |
| 1201 | it to a register without actually generating code is wrong |
| 1202 | as their value might still be used for real. All values |
| 1203 | we push under nocode_wanted will eventually be popped |
| 1204 | again, so that the VT_CMP/VT_JMP value will be in vtop |
| 1205 | when code is unsuppressed again. */ |
| 1206 | |
| 1207 | if (vtop->r == VT_CMP && !nocode_wanted) |
| 1208 | gv(RC_INT); |
| 1209 | } |
| 1210 | |
| 1211 | static void vsetc(CType *type, int r, CValue *vc) |
| 1212 | { |
| 1213 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
| 1214 | tcc_error("memory full (vstack)" ); |
| 1215 | vcheck_cmp(); |
| 1216 | vtop++; |
| 1217 | vtop->type = *type; |
| 1218 | vtop->r = r; |
| 1219 | vtop->r2 = VT_CONST; |
| 1220 | vtop->c = *vc; |
| 1221 | vtop->sym = NULL; |
| 1222 | } |
| 1223 | |
| 1224 | ST_FUNC void vswap(void) |
| 1225 | { |
| 1226 | SValue tmp; |
| 1227 | |
| 1228 | vcheck_cmp(); |
| 1229 | tmp = vtop[0]; |
| 1230 | vtop[0] = vtop[-1]; |
| 1231 | vtop[-1] = tmp; |
| 1232 | } |
| 1233 | |
| 1234 | /* pop stack value */ |
| 1235 | ST_FUNC void vpop(void) |
| 1236 | { |
| 1237 | int v; |
| 1238 | v = vtop->r & VT_VALMASK; |
| 1239 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
| 1240 | /* for x86, we need to pop the FP stack */ |
| 1241 | if (v == TREG_ST0) { |
| 1242 | o(0xd8dd); /* fstp %st(0) */ |
| 1243 | } else |
| 1244 | #endif |
| 1245 | if (v == VT_CMP) { |
| 1246 | /* need to put correct jump if && or || without test */ |
| 1247 | gsym(vtop->jtrue); |
| 1248 | gsym(vtop->jfalse); |
| 1249 | } |
| 1250 | vtop--; |
| 1251 | } |
| 1252 | |
| 1253 | /* push constant of type "type" with useless value */ |
| 1254 | static void vpush(CType *type) |
| 1255 | { |
| 1256 | vset(type, VT_CONST, 0); |
| 1257 | } |
| 1258 | |
| 1259 | /* push arbitrary 64bit constant */ |
| 1260 | static void vpush64(int ty, unsigned long long v) |
| 1261 | { |
| 1262 | CValue cval; |
| 1263 | CType ctype; |
| 1264 | ctype.t = ty; |
| 1265 | ctype.ref = NULL; |
| 1266 | cval.i = v; |
| 1267 | vsetc(&ctype, VT_CONST, &cval); |
| 1268 | } |
| 1269 | |
| 1270 | /* push integer constant */ |
| 1271 | ST_FUNC void vpushi(int v) |
| 1272 | { |
| 1273 | vpush64(VT_INT, v); |
| 1274 | } |
| 1275 | |
| 1276 | /* push a pointer sized constant */ |
| 1277 | static void vpushs(addr_t v) |
| 1278 | { |
| 1279 | vpush64(VT_SIZE_T, v); |
| 1280 | } |
| 1281 | |
| 1282 | /* push long long constant */ |
| 1283 | static inline void vpushll(long long v) |
| 1284 | { |
| 1285 | vpush64(VT_LLONG, v); |
| 1286 | } |
| 1287 | |
| 1288 | ST_FUNC void vset(CType *type, int r, int v) |
| 1289 | { |
| 1290 | CValue cval; |
| 1291 | cval.i = v; |
| 1292 | vsetc(type, r, &cval); |
| 1293 | } |
| 1294 | |
| 1295 | static void vseti(int r, int v) |
| 1296 | { |
| 1297 | CType type; |
| 1298 | type.t = VT_INT; |
| 1299 | type.ref = NULL; |
| 1300 | vset(&type, r, v); |
| 1301 | } |
| 1302 | |
| 1303 | ST_FUNC void vpushv(SValue *v) |
| 1304 | { |
| 1305 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
| 1306 | tcc_error("memory full (vstack)" ); |
| 1307 | vtop++; |
| 1308 | *vtop = *v; |
| 1309 | } |
| 1310 | |
| 1311 | static void vdup(void) |
| 1312 | { |
| 1313 | vpushv(vtop); |
| 1314 | } |
| 1315 | |
| 1316 | /* rotate n first stack elements to the bottom |
| 1317 | I1 ... In -> I2 ... In I1 [top is right] |
| 1318 | */ |
| 1319 | ST_FUNC void vrotb(int n) |
| 1320 | { |
| 1321 | int i; |
| 1322 | SValue tmp; |
| 1323 | |
| 1324 | vcheck_cmp(); |
| 1325 | tmp = vtop[-n + 1]; |
| 1326 | for(i=-n+1;i!=0;i++) |
| 1327 | vtop[i] = vtop[i+1]; |
| 1328 | vtop[0] = tmp; |
| 1329 | } |
| 1330 | |
| 1331 | /* rotate the n elements before entry e towards the top |
| 1332 | I1 ... In ... -> In I1 ... I(n-1) ... [top is right] |
| 1333 | */ |
| 1334 | ST_FUNC void vrote(SValue *e, int n) |
| 1335 | { |
| 1336 | int i; |
| 1337 | SValue tmp; |
| 1338 | |
| 1339 | vcheck_cmp(); |
| 1340 | tmp = *e; |
| 1341 | for(i = 0;i < n - 1; i++) |
| 1342 | e[-i] = e[-i - 1]; |
| 1343 | e[-n + 1] = tmp; |
| 1344 | } |
| 1345 | |
| 1346 | /* rotate n first stack elements to the top |
| 1347 | I1 ... In -> In I1 ... I(n-1) [top is right] |
| 1348 | */ |
| 1349 | ST_FUNC void vrott(int n) |
| 1350 | { |
| 1351 | vrote(vtop, n); |
| 1352 | } |
| 1353 | |
| 1354 | /* ------------------------------------------------------------------------- */ |
| 1355 | /* vtop->r = VT_CMP means CPU-flags have been set from comparison or test. */ |
| 1356 | |
| 1357 | /* called from generators to set the result from relational ops */ |
| 1358 | ST_FUNC void vset_VT_CMP(int op) |
| 1359 | { |
| 1360 | vtop->r = VT_CMP; |
| 1361 | vtop->cmp_op = op; |
| 1362 | vtop->jfalse = 0; |
| 1363 | vtop->jtrue = 0; |
| 1364 | } |
| 1365 | |
| 1366 | /* called once before asking generators to load VT_CMP to a register */ |
| 1367 | static void vset_VT_JMP(void) |
| 1368 | { |
| 1369 | int op = vtop->cmp_op; |
| 1370 | |
| 1371 | if (vtop->jtrue || vtop->jfalse) { |
| 1372 | /* we need to jump to 'mov $0,%R' or 'mov $1,%R' */ |
| 1373 | int inv = op & (op < 2); /* small optimization */ |
| 1374 | vseti(VT_JMP+inv, gvtst(inv, 0)); |
| 1375 | } else { |
| 1376 | /* otherwise convert flags (rsp. 0/1) to register */ |
| 1377 | vtop->c.i = op; |
| 1378 | if (op < 2) /* doesn't seem to happen */ |
| 1379 | vtop->r = VT_CONST; |
| 1380 | } |
| 1381 | } |
| 1382 | |
| 1383 | /* Set CPU Flags, doesn't yet jump */ |
| 1384 | static void gvtst_set(int inv, int t) |
| 1385 | { |
| 1386 | int *p; |
| 1387 | |
| 1388 | if (vtop->r != VT_CMP) { |
| 1389 | vpushi(0); |
| 1390 | gen_op(TOK_NE); |
| 1391 | if (vtop->r != VT_CMP) /* must be VT_CONST then */ |
| 1392 | vset_VT_CMP(vtop->c.i != 0); |
| 1393 | } |
| 1394 | |
| 1395 | p = inv ? &vtop->jfalse : &vtop->jtrue; |
| 1396 | *p = gjmp_append(*p, t); |
| 1397 | } |
| 1398 | |
| 1399 | /* Generate value test |
| 1400 | * |
| 1401 | * Generate a test for any value (jump, comparison and integers) */ |
| 1402 | static int gvtst(int inv, int t) |
| 1403 | { |
| 1404 | int op, x, u; |
| 1405 | |
| 1406 | gvtst_set(inv, t); |
| 1407 | t = vtop->jtrue, u = vtop->jfalse; |
| 1408 | if (inv) |
| 1409 | x = u, u = t, t = x; |
| 1410 | op = vtop->cmp_op; |
| 1411 | |
| 1412 | /* jump to the wanted target */ |
| 1413 | if (op > 1) |
| 1414 | t = gjmp_cond(op ^ inv, t); |
| 1415 | else if (op != inv) |
| 1416 | t = gjmp(t); |
| 1417 | /* resolve complementary jumps to here */ |
| 1418 | gsym(u); |
| 1419 | |
| 1420 | vtop--; |
| 1421 | return t; |
| 1422 | } |
| 1423 | |
| 1424 | /* generate a zero or nozero test */ |
| 1425 | static void gen_test_zero(int op) |
| 1426 | { |
| 1427 | if (vtop->r == VT_CMP) { |
| 1428 | int j; |
| 1429 | if (op == TOK_EQ) { |
| 1430 | j = vtop->jfalse; |
| 1431 | vtop->jfalse = vtop->jtrue; |
| 1432 | vtop->jtrue = j; |
| 1433 | vtop->cmp_op ^= 1; |
| 1434 | } |
| 1435 | } else { |
| 1436 | vpushi(0); |
| 1437 | gen_op(op); |
| 1438 | } |
| 1439 | } |
| 1440 | |
| 1441 | /* ------------------------------------------------------------------------- */ |
| 1442 | /* push a symbol value of TYPE */ |
| 1443 | static inline void vpushsym(CType *type, Sym *sym) |
| 1444 | { |
| 1445 | CValue cval; |
| 1446 | cval.i = 0; |
| 1447 | vsetc(type, VT_CONST | VT_SYM, &cval); |
| 1448 | vtop->sym = sym; |
| 1449 | } |
| 1450 | |
| 1451 | /* Return a static symbol pointing to a section */ |
| 1452 | ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
| 1453 | { |
| 1454 | int v; |
| 1455 | Sym *sym; |
| 1456 | |
| 1457 | v = anon_sym++; |
| 1458 | sym = sym_push(v, type, VT_CONST | VT_SYM, 0); |
| 1459 | sym->type.t |= VT_STATIC; |
| 1460 | put_extern_sym(sym, sec, offset, size); |
| 1461 | return sym; |
| 1462 | } |
| 1463 | |
| 1464 | /* push a reference to a section offset by adding a dummy symbol */ |
| 1465 | static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
| 1466 | { |
| 1467 | vpushsym(type, get_sym_ref(type, sec, offset, size)); |
| 1468 | } |
| 1469 | |
| 1470 | /* define a new external reference to a symbol 'v' of type 'u' */ |
| 1471 | ST_FUNC Sym *external_global_sym(int v, CType *type) |
| 1472 | { |
| 1473 | Sym *s; |
| 1474 | |
| 1475 | s = sym_find(v); |
| 1476 | if (!s) { |
| 1477 | /* push forward reference */ |
| 1478 | s = global_identifier_push(v, type->t | VT_EXTERN, 0); |
| 1479 | s->type.ref = type->ref; |
| 1480 | } else if (IS_ASM_SYM(s)) { |
| 1481 | s->type.t = type->t | (s->type.t & VT_EXTERN); |
| 1482 | s->type.ref = type->ref; |
| 1483 | update_storage(s); |
| 1484 | } |
| 1485 | return s; |
| 1486 | } |
| 1487 | |
| 1488 | /* Merge symbol attributes. */ |
| 1489 | static void merge_symattr(struct SymAttr *sa, struct SymAttr *sa1) |
| 1490 | { |
| 1491 | if (sa1->aligned && !sa->aligned) |
| 1492 | sa->aligned = sa1->aligned; |
| 1493 | sa->packed |= sa1->packed; |
| 1494 | sa->weak |= sa1->weak; |
| 1495 | if (sa1->visibility != STV_DEFAULT) { |
| 1496 | int vis = sa->visibility; |
| 1497 | if (vis == STV_DEFAULT |
| 1498 | || vis > sa1->visibility) |
| 1499 | vis = sa1->visibility; |
| 1500 | sa->visibility = vis; |
| 1501 | } |
| 1502 | sa->dllexport |= sa1->dllexport; |
| 1503 | sa->nodecorate |= sa1->nodecorate; |
| 1504 | sa->dllimport |= sa1->dllimport; |
| 1505 | } |
| 1506 | |
| 1507 | /* Merge function attributes. */ |
| 1508 | static void merge_funcattr(struct FuncAttr *fa, struct FuncAttr *fa1) |
| 1509 | { |
| 1510 | if (fa1->func_call && !fa->func_call) |
| 1511 | fa->func_call = fa1->func_call; |
| 1512 | if (fa1->func_type && !fa->func_type) |
| 1513 | fa->func_type = fa1->func_type; |
| 1514 | if (fa1->func_args && !fa->func_args) |
| 1515 | fa->func_args = fa1->func_args; |
| 1516 | if (fa1->func_noreturn) |
| 1517 | fa->func_noreturn = 1; |
| 1518 | if (fa1->func_ctor) |
| 1519 | fa->func_ctor = 1; |
| 1520 | if (fa1->func_dtor) |
| 1521 | fa->func_dtor = 1; |
| 1522 | } |
| 1523 | |
| 1524 | /* Merge attributes. */ |
| 1525 | static void merge_attr(AttributeDef *ad, AttributeDef *ad1) |
| 1526 | { |
| 1527 | merge_symattr(&ad->a, &ad1->a); |
| 1528 | merge_funcattr(&ad->f, &ad1->f); |
| 1529 | |
| 1530 | if (ad1->section) |
| 1531 | ad->section = ad1->section; |
| 1532 | if (ad1->alias_target) |
| 1533 | ad->alias_target = ad1->alias_target; |
| 1534 | if (ad1->asm_label) |
| 1535 | ad->asm_label = ad1->asm_label; |
| 1536 | if (ad1->attr_mode) |
| 1537 | ad->attr_mode = ad1->attr_mode; |
| 1538 | } |
| 1539 | |
| 1540 | /* Merge some type attributes. */ |
| 1541 | static void patch_type(Sym *sym, CType *type) |
| 1542 | { |
| 1543 | if (!(type->t & VT_EXTERN) || IS_ENUM_VAL(sym->type.t)) { |
| 1544 | if (!(sym->type.t & VT_EXTERN)) |
| 1545 | tcc_error("redefinition of '%s'" , get_tok_str(sym->v, NULL)); |
| 1546 | sym->type.t &= ~VT_EXTERN; |
| 1547 | } |
| 1548 | |
| 1549 | if (IS_ASM_SYM(sym)) { |
| 1550 | /* stay static if both are static */ |
| 1551 | sym->type.t = type->t & (sym->type.t | ~VT_STATIC); |
| 1552 | sym->type.ref = type->ref; |
| 1553 | } |
| 1554 | |
| 1555 | if (!is_compatible_types(&sym->type, type)) { |
| 1556 | tcc_error("incompatible types for redefinition of '%s'" , |
| 1557 | get_tok_str(sym->v, NULL)); |
| 1558 | |
| 1559 | } else if ((sym->type.t & VT_BTYPE) == VT_FUNC) { |
| 1560 | int static_proto = sym->type.t & VT_STATIC; |
| 1561 | /* warn if static follows non-static function declaration */ |
| 1562 | if ((type->t & VT_STATIC) && !static_proto |
| 1563 | /* XXX this test for inline shouldn't be here. Until we |
| 1564 | implement gnu-inline mode again it silences a warning for |
| 1565 | mingw caused by our workarounds. */ |
| 1566 | && !((type->t | sym->type.t) & VT_INLINE)) |
| 1567 | tcc_warning("static storage ignored for redefinition of '%s'" , |
| 1568 | get_tok_str(sym->v, NULL)); |
| 1569 | |
| 1570 | /* set 'inline' if both agree or if one has static */ |
| 1571 | if ((type->t | sym->type.t) & VT_INLINE) { |
| 1572 | if (!((type->t ^ sym->type.t) & VT_INLINE) |
| 1573 | || ((type->t | sym->type.t) & VT_STATIC)) |
| 1574 | static_proto |= VT_INLINE; |
| 1575 | } |
| 1576 | |
| 1577 | if (0 == (type->t & VT_EXTERN)) { |
| 1578 | struct FuncAttr f = sym->type.ref->f; |
| 1579 | /* put complete type, use static from prototype */ |
| 1580 | sym->type.t = (type->t & ~(VT_STATIC|VT_INLINE)) | static_proto; |
| 1581 | sym->type.ref = type->ref; |
| 1582 | merge_funcattr(&sym->type.ref->f, &f); |
| 1583 | } else { |
| 1584 | sym->type.t &= ~VT_INLINE | static_proto; |
| 1585 | } |
| 1586 | |
| 1587 | if (sym->type.ref->f.func_type == FUNC_OLD |
| 1588 | && type->ref->f.func_type != FUNC_OLD) { |
| 1589 | sym->type.ref = type->ref; |
| 1590 | } |
| 1591 | |
| 1592 | } else { |
| 1593 | if ((sym->type.t & VT_ARRAY) && type->ref->c >= 0) { |
| 1594 | /* set array size if it was omitted in extern declaration */ |
| 1595 | sym->type.ref->c = type->ref->c; |
| 1596 | } |
| 1597 | if ((type->t ^ sym->type.t) & VT_STATIC) |
| 1598 | tcc_warning("storage mismatch for redefinition of '%s'" , |
| 1599 | get_tok_str(sym->v, NULL)); |
| 1600 | } |
| 1601 | } |
| 1602 | |
| 1603 | /* Merge some storage attributes. */ |
| 1604 | static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) |
| 1605 | { |
| 1606 | if (type) |
| 1607 | patch_type(sym, type); |
| 1608 | |
| 1609 | #ifdef TCC_TARGET_PE |
| 1610 | if (sym->a.dllimport != ad->a.dllimport) |
| 1611 | tcc_error("incompatible dll linkage for redefinition of '%s'" , |
| 1612 | get_tok_str(sym->v, NULL)); |
| 1613 | #endif |
| 1614 | merge_symattr(&sym->a, &ad->a); |
| 1615 | if (ad->asm_label) |
| 1616 | sym->asm_label = ad->asm_label; |
| 1617 | update_storage(sym); |
| 1618 | } |
| 1619 | |
| 1620 | /* copy sym to other stack */ |
| 1621 | static Sym *sym_copy(Sym *s0, Sym **ps) |
| 1622 | { |
| 1623 | Sym *s; |
| 1624 | s = sym_malloc(), *s = *s0; |
| 1625 | s->prev = *ps, *ps = s; |
| 1626 | if (s->v < SYM_FIRST_ANOM) { |
| 1627 | ps = &table_ident[s->v - TOK_IDENT]->sym_identifier; |
| 1628 | s->prev_tok = *ps, *ps = s; |
| 1629 | } |
| 1630 | return s; |
| 1631 | } |
| 1632 | |
| 1633 | /* copy s->type.ref to stack 'ps' for VT_FUNC and VT_PTR */ |
| 1634 | static void sym_copy_ref(Sym *s, Sym **ps) |
| 1635 | { |
| 1636 | int bt = s->type.t & VT_BTYPE; |
| 1637 | if (bt == VT_FUNC || bt == VT_PTR) { |
| 1638 | Sym **sp = &s->type.ref; |
| 1639 | for (s = *sp, *sp = NULL; s; s = s->next) { |
| 1640 | Sym *s2 = sym_copy(s, ps); |
| 1641 | sp = &(*sp = s2)->next; |
| 1642 | sym_copy_ref(s2, ps); |
| 1643 | } |
| 1644 | } |
| 1645 | } |
| 1646 | |
| 1647 | /* define a new external reference to a symbol 'v' */ |
| 1648 | static Sym *external_sym(int v, CType *type, int r, AttributeDef *ad) |
| 1649 | { |
| 1650 | Sym *s; |
| 1651 | |
| 1652 | /* look for global symbol */ |
| 1653 | s = sym_find(v); |
| 1654 | while (s && s->sym_scope) |
| 1655 | s = s->prev_tok; |
| 1656 | |
| 1657 | if (!s) { |
| 1658 | /* push forward reference */ |
| 1659 | s = global_identifier_push(v, type->t, 0); |
| 1660 | s->r |= r; |
| 1661 | s->a = ad->a; |
| 1662 | s->asm_label = ad->asm_label; |
| 1663 | s->type.ref = type->ref; |
| 1664 | /* copy type to the global stack */ |
| 1665 | if (local_stack) |
| 1666 | sym_copy_ref(s, &global_stack); |
| 1667 | } else { |
| 1668 | patch_storage(s, ad, type); |
| 1669 | } |
| 1670 | /* push variables on local_stack if any */ |
| 1671 | if (local_stack && (s->type.t & VT_BTYPE) != VT_FUNC) |
| 1672 | s = sym_copy(s, &local_stack); |
| 1673 | return s; |
| 1674 | } |
| 1675 | |
| 1676 | /* push a reference to global symbol v */ |
| 1677 | ST_FUNC void vpush_global_sym(CType *type, int v) |
| 1678 | { |
| 1679 | vpushsym(type, external_global_sym(v, type)); |
| 1680 | } |
| 1681 | |
| 1682 | /* save registers up to (vtop - n) stack entry */ |
| 1683 | ST_FUNC void save_regs(int n) |
| 1684 | { |
| 1685 | SValue *p, *p1; |
| 1686 | for(p = vstack, p1 = vtop - n; p <= p1; p++) |
| 1687 | save_reg(p->r); |
| 1688 | } |
| 1689 | |
| 1690 | /* save r to the memory stack, and mark it as being free */ |
| 1691 | ST_FUNC void save_reg(int r) |
| 1692 | { |
| 1693 | save_reg_upstack(r, 0); |
| 1694 | } |
| 1695 | |
| 1696 | /* save r to the memory stack, and mark it as being free, |
| 1697 | if seen up to (vtop - n) stack entry */ |
| 1698 | ST_FUNC void save_reg_upstack(int r, int n) |
| 1699 | { |
| 1700 | int l, size, align, bt; |
| 1701 | SValue *p, *p1, sv; |
| 1702 | |
| 1703 | if ((r &= VT_VALMASK) >= VT_CONST) |
| 1704 | return; |
| 1705 | if (nocode_wanted) |
| 1706 | return; |
| 1707 | l = 0; |
| 1708 | for(p = vstack, p1 = vtop - n; p <= p1; p++) { |
| 1709 | if ((p->r & VT_VALMASK) == r || p->r2 == r) { |
| 1710 | /* must save value on stack if not already done */ |
| 1711 | if (!l) { |
| 1712 | bt = p->type.t & VT_BTYPE; |
| 1713 | if (bt == VT_VOID) |
| 1714 | continue; |
| 1715 | if ((p->r & VT_LVAL) || bt == VT_FUNC) |
| 1716 | bt = VT_PTR; |
| 1717 | sv.type.t = bt; |
| 1718 | size = type_size(&sv.type, &align); |
| 1719 | l = get_temp_local_var(size,align); |
| 1720 | sv.r = VT_LOCAL | VT_LVAL; |
| 1721 | sv.c.i = l; |
| 1722 | store(p->r & VT_VALMASK, &sv); |
| 1723 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
| 1724 | /* x86 specific: need to pop fp register ST0 if saved */ |
| 1725 | if (r == TREG_ST0) { |
| 1726 | o(0xd8dd); /* fstp %st(0) */ |
| 1727 | } |
| 1728 | #endif |
| 1729 | /* special long long case */ |
| 1730 | if (p->r2 < VT_CONST && USING_TWO_WORDS(bt)) { |
| 1731 | sv.c.i += PTR_SIZE; |
| 1732 | store(p->r2, &sv); |
| 1733 | } |
| 1734 | } |
| 1735 | /* mark that stack entry as being saved on the stack */ |
| 1736 | if (p->r & VT_LVAL) { |
| 1737 | /* also clear the bounded flag because the |
| 1738 | relocation address of the function was stored in |
| 1739 | p->c.i */ |
| 1740 | p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; |
| 1741 | } else { |
| 1742 | p->r = VT_LVAL | VT_LOCAL; |
| 1743 | } |
| 1744 | p->r2 = VT_CONST; |
| 1745 | p->c.i = l; |
| 1746 | } |
| 1747 | } |
| 1748 | } |
| 1749 | |
| 1750 | #ifdef TCC_TARGET_ARM |
| 1751 | /* find a register of class 'rc2' with at most one reference on stack. |
| 1752 | * If none, call get_reg(rc) */ |
| 1753 | ST_FUNC int get_reg_ex(int rc, int rc2) |
| 1754 | { |
| 1755 | int r; |
| 1756 | SValue *p; |
| 1757 | |
| 1758 | for(r=0;r<NB_REGS;r++) { |
| 1759 | if (reg_classes[r] & rc2) { |
| 1760 | int n; |
| 1761 | n=0; |
| 1762 | for(p = vstack; p <= vtop; p++) { |
| 1763 | if ((p->r & VT_VALMASK) == r || |
| 1764 | p->r2 == r) |
| 1765 | n++; |
| 1766 | } |
| 1767 | if (n <= 1) |
| 1768 | return r; |
| 1769 | } |
| 1770 | } |
| 1771 | return get_reg(rc); |
| 1772 | } |
| 1773 | #endif |
| 1774 | |
| 1775 | /* find a free register of class 'rc'. If none, save one register */ |
| 1776 | ST_FUNC int get_reg(int rc) |
| 1777 | { |
| 1778 | int r; |
| 1779 | SValue *p; |
| 1780 | |
| 1781 | /* find a free register */ |
| 1782 | for(r=0;r<NB_REGS;r++) { |
| 1783 | if (reg_classes[r] & rc) { |
| 1784 | if (nocode_wanted) |
| 1785 | return r; |
| 1786 | for(p=vstack;p<=vtop;p++) { |
| 1787 | if ((p->r & VT_VALMASK) == r || |
| 1788 | p->r2 == r) |
| 1789 | goto notfound; |
| 1790 | } |
| 1791 | return r; |
| 1792 | } |
| 1793 | notfound: ; |
| 1794 | } |
| 1795 | |
| 1796 | /* no register left : free the first one on the stack (VERY |
| 1797 | IMPORTANT to start from the bottom to ensure that we don't |
| 1798 | spill registers used in gen_opi()) */ |
| 1799 | for(p=vstack;p<=vtop;p++) { |
| 1800 | /* look at second register (if long long) */ |
| 1801 | r = p->r2; |
| 1802 | if (r < VT_CONST && (reg_classes[r] & rc)) |
| 1803 | goto save_found; |
| 1804 | r = p->r & VT_VALMASK; |
| 1805 | if (r < VT_CONST && (reg_classes[r] & rc)) { |
| 1806 | save_found: |
| 1807 | save_reg(r); |
| 1808 | return r; |
| 1809 | } |
| 1810 | } |
| 1811 | /* Should never comes here */ |
| 1812 | return -1; |
| 1813 | } |
| 1814 | |
| 1815 | /* find a free temporary local variable (return the offset on stack) match the size and align. If none, add new temporary stack variable*/ |
| 1816 | static int get_temp_local_var(int size,int align){ |
| 1817 | int i; |
| 1818 | struct temp_local_variable *temp_var; |
| 1819 | int found_var; |
| 1820 | SValue *p; |
| 1821 | int r; |
| 1822 | char free; |
| 1823 | char found; |
| 1824 | found=0; |
| 1825 | for(i=0;i<nb_temp_local_vars;i++){ |
| 1826 | temp_var=&arr_temp_local_vars[i]; |
| 1827 | if(temp_var->size<size||align!=temp_var->align){ |
| 1828 | continue; |
| 1829 | } |
| 1830 | /*check if temp_var is free*/ |
| 1831 | free=1; |
| 1832 | for(p=vstack;p<=vtop;p++) { |
| 1833 | r=p->r&VT_VALMASK; |
| 1834 | if(r==VT_LOCAL||r==VT_LLOCAL){ |
| 1835 | if(p->c.i==temp_var->location){ |
| 1836 | free=0; |
| 1837 | break; |
| 1838 | } |
| 1839 | } |
| 1840 | } |
| 1841 | if(free){ |
| 1842 | found_var=temp_var->location; |
| 1843 | found=1; |
| 1844 | break; |
| 1845 | } |
| 1846 | } |
| 1847 | if(!found){ |
| 1848 | loc = (loc - size) & -align; |
| 1849 | if(nb_temp_local_vars<MAX_TEMP_LOCAL_VARIABLE_NUMBER){ |
| 1850 | temp_var=&arr_temp_local_vars[i]; |
| 1851 | temp_var->location=loc; |
| 1852 | temp_var->size=size; |
| 1853 | temp_var->align=align; |
| 1854 | nb_temp_local_vars++; |
| 1855 | } |
| 1856 | found_var=loc; |
| 1857 | } |
| 1858 | return found_var; |
| 1859 | } |
| 1860 | |
| 1861 | static void clear_temp_local_var_list(){ |
| 1862 | nb_temp_local_vars=0; |
| 1863 | } |
| 1864 | |
| 1865 | /* move register 's' (of type 't') to 'r', and flush previous value of r to memory |
| 1866 | if needed */ |
| 1867 | static void move_reg(int r, int s, int t) |
| 1868 | { |
| 1869 | SValue sv; |
| 1870 | |
| 1871 | if (r != s) { |
| 1872 | save_reg(r); |
| 1873 | sv.type.t = t; |
| 1874 | sv.type.ref = NULL; |
| 1875 | sv.r = s; |
| 1876 | sv.c.i = 0; |
| 1877 | load(r, &sv); |
| 1878 | } |
| 1879 | } |
| 1880 | |
| 1881 | /* get address of vtop (vtop MUST BE an lvalue) */ |
| 1882 | ST_FUNC void gaddrof(void) |
| 1883 | { |
| 1884 | vtop->r &= ~VT_LVAL; |
| 1885 | /* tricky: if saved lvalue, then we can go back to lvalue */ |
| 1886 | if ((vtop->r & VT_VALMASK) == VT_LLOCAL) |
| 1887 | vtop->r = (vtop->r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL; |
| 1888 | } |
| 1889 | |
| 1890 | #ifdef CONFIG_TCC_BCHECK |
| 1891 | /* generate a bounded pointer addition */ |
| 1892 | static void gen_bounded_ptr_add(void) |
| 1893 | { |
| 1894 | int save = (vtop[-1].r & VT_VALMASK) == VT_LOCAL; |
| 1895 | if (save) { |
| 1896 | vpushv(&vtop[-1]); |
| 1897 | vrott(3); |
| 1898 | } |
| 1899 | vpush_global_sym(&func_old_type, TOK___bound_ptr_add); |
| 1900 | vrott(3); |
| 1901 | gfunc_call(2); |
| 1902 | vtop -= save; |
| 1903 | vpushi(0); |
| 1904 | /* returned pointer is in REG_IRET */ |
| 1905 | vtop->r = REG_IRET | VT_BOUNDED; |
| 1906 | if (nocode_wanted) |
| 1907 | return; |
| 1908 | /* relocation offset of the bounding function call point */ |
| 1909 | vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW_Rel)); |
| 1910 | } |
| 1911 | |
| 1912 | /* patch pointer addition in vtop so that pointer dereferencing is |
| 1913 | also tested */ |
| 1914 | static void gen_bounded_ptr_deref(void) |
| 1915 | { |
| 1916 | addr_t func; |
| 1917 | int size, align; |
| 1918 | ElfW_Rel *rel; |
| 1919 | Sym *sym; |
| 1920 | |
| 1921 | if (nocode_wanted) |
| 1922 | return; |
| 1923 | |
| 1924 | size = type_size(&vtop->type, &align); |
| 1925 | switch(size) { |
| 1926 | case 1: func = TOK___bound_ptr_indir1; break; |
| 1927 | case 2: func = TOK___bound_ptr_indir2; break; |
| 1928 | case 4: func = TOK___bound_ptr_indir4; break; |
| 1929 | case 8: func = TOK___bound_ptr_indir8; break; |
| 1930 | case 12: func = TOK___bound_ptr_indir12; break; |
| 1931 | case 16: func = TOK___bound_ptr_indir16; break; |
| 1932 | default: |
| 1933 | /* may happen with struct member access */ |
| 1934 | return; |
| 1935 | } |
| 1936 | sym = external_global_sym(func, &func_old_type); |
| 1937 | if (!sym->c) |
| 1938 | put_extern_sym(sym, NULL, 0, 0); |
| 1939 | /* patch relocation */ |
| 1940 | /* XXX: find a better solution ? */ |
| 1941 | rel = (ElfW_Rel *)(cur_text_section->reloc->data + vtop->c.i); |
| 1942 | rel->r_info = ELFW(R_INFO)(sym->c, ELFW(R_TYPE)(rel->r_info)); |
| 1943 | } |
| 1944 | |
| 1945 | /* generate lvalue bound code */ |
| 1946 | static void gbound(void) |
| 1947 | { |
| 1948 | CType type1; |
| 1949 | |
| 1950 | vtop->r &= ~VT_MUSTBOUND; |
| 1951 | /* if lvalue, then use checking code before dereferencing */ |
| 1952 | if (vtop->r & VT_LVAL) { |
| 1953 | /* if not VT_BOUNDED value, then make one */ |
| 1954 | if (!(vtop->r & VT_BOUNDED)) { |
| 1955 | /* must save type because we must set it to int to get pointer */ |
| 1956 | type1 = vtop->type; |
| 1957 | vtop->type.t = VT_PTR; |
| 1958 | gaddrof(); |
| 1959 | vpushi(0); |
| 1960 | gen_bounded_ptr_add(); |
| 1961 | vtop->r |= VT_LVAL; |
| 1962 | vtop->type = type1; |
| 1963 | } |
| 1964 | /* then check for dereferencing */ |
| 1965 | gen_bounded_ptr_deref(); |
| 1966 | } |
| 1967 | } |
| 1968 | |
| 1969 | /* we need to call __bound_ptr_add before we start to load function |
| 1970 | args into registers */ |
| 1971 | ST_FUNC void gbound_args(int nb_args) |
| 1972 | { |
| 1973 | int i, v; |
| 1974 | SValue *sv; |
| 1975 | |
| 1976 | for (i = 1; i <= nb_args; ++i) |
| 1977 | if (vtop[1 - i].r & VT_MUSTBOUND) { |
| 1978 | vrotb(i); |
| 1979 | gbound(); |
| 1980 | vrott(i); |
| 1981 | } |
| 1982 | |
| 1983 | sv = vtop - nb_args; |
| 1984 | if (sv->r & VT_SYM) { |
| 1985 | v = sv->sym->v; |
| 1986 | if (v == TOK_setjmp |
| 1987 | || v == TOK__setjmp |
| 1988 | #ifndef TCC_TARGET_PE |
| 1989 | || v == TOK_sigsetjmp |
| 1990 | || v == TOK___sigsetjmp |
| 1991 | #endif |
| 1992 | ) { |
| 1993 | vpush_global_sym(&func_old_type, TOK___bound_setjmp); |
| 1994 | vpushv(sv + 1); |
| 1995 | gfunc_call(1); |
| 1996 | func_bound_add_epilog = 1; |
| 1997 | } |
| 1998 | #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 |
| 1999 | if (v == TOK_alloca) |
| 2000 | func_bound_add_epilog = 1; |
| 2001 | #endif |
| 2002 | } |
| 2003 | } |
| 2004 | |
| 2005 | /* Add bounds for local symbols from S to E (via ->prev) */ |
| 2006 | static void add_local_bounds(Sym *s, Sym *e) |
| 2007 | { |
| 2008 | for (; s != e; s = s->prev) { |
| 2009 | if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL) |
| 2010 | continue; |
| 2011 | /* Add arrays/structs/unions because we always take address */ |
| 2012 | if ((s->type.t & VT_ARRAY) |
| 2013 | || (s->type.t & VT_BTYPE) == VT_STRUCT |
| 2014 | || s->a.addrtaken) { |
| 2015 | /* add local bound info */ |
| 2016 | int align, size = type_size(&s->type, &align); |
| 2017 | addr_t *bounds_ptr = section_ptr_add(lbounds_section, |
| 2018 | 2 * sizeof(addr_t)); |
| 2019 | bounds_ptr[0] = s->c; |
| 2020 | bounds_ptr[1] = size; |
| 2021 | } |
| 2022 | } |
| 2023 | } |
| 2024 | #endif |
| 2025 | |
| 2026 | /* Wrapper around sym_pop, that potentially also registers local bounds. */ |
| 2027 | static void pop_local_syms(Sym **ptop, Sym *b, int keep, int ellipsis) |
| 2028 | { |
| 2029 | #ifdef CONFIG_TCC_BCHECK |
| 2030 | if (tcc_state->do_bounds_check && !ellipsis && !keep) |
| 2031 | add_local_bounds(*ptop, b); |
| 2032 | #endif |
| 2033 | if (tcc_state->do_debug) |
| 2034 | tcc_add_debug_info (tcc_state, !local_scope, *ptop, b); |
| 2035 | sym_pop(ptop, b, keep); |
| 2036 | } |
| 2037 | |
| 2038 | static void incr_bf_adr(int o) |
| 2039 | { |
| 2040 | vtop->type = char_pointer_type; |
| 2041 | gaddrof(); |
| 2042 | vpushs(o); |
| 2043 | gen_op('+'); |
| 2044 | vtop->type.t = VT_BYTE | VT_UNSIGNED; |
| 2045 | vtop->r |= VT_LVAL; |
| 2046 | } |
| 2047 | |
| 2048 | /* single-byte load mode for packed or otherwise unaligned bitfields */ |
| 2049 | static void load_packed_bf(CType *type, int bit_pos, int bit_size) |
| 2050 | { |
| 2051 | int n, o, bits; |
| 2052 | save_reg_upstack(vtop->r, 1); |
| 2053 | vpush64(type->t & VT_BTYPE, 0); // B X |
| 2054 | bits = 0, o = bit_pos >> 3, bit_pos &= 7; |
| 2055 | do { |
| 2056 | vswap(); // X B |
| 2057 | incr_bf_adr(o); |
| 2058 | vdup(); // X B B |
| 2059 | n = 8 - bit_pos; |
| 2060 | if (n > bit_size) |
| 2061 | n = bit_size; |
| 2062 | if (bit_pos) |
| 2063 | vpushi(bit_pos), gen_op(TOK_SHR), bit_pos = 0; // X B Y |
| 2064 | if (n < 8) |
| 2065 | vpushi((1 << n) - 1), gen_op('&'); |
| 2066 | gen_cast(type); |
| 2067 | if (bits) |
| 2068 | vpushi(bits), gen_op(TOK_SHL); |
| 2069 | vrotb(3); // B Y X |
| 2070 | gen_op('|'); // B X |
| 2071 | bits += n, bit_size -= n, o = 1; |
| 2072 | } while (bit_size); |
| 2073 | vswap(), vpop(); |
| 2074 | if (!(type->t & VT_UNSIGNED)) { |
| 2075 | n = ((type->t & VT_BTYPE) == VT_LLONG ? 64 : 32) - bits; |
| 2076 | vpushi(n), gen_op(TOK_SHL); |
| 2077 | vpushi(n), gen_op(TOK_SAR); |
| 2078 | } |
| 2079 | } |
| 2080 | |
| 2081 | /* single-byte store mode for packed or otherwise unaligned bitfields */ |
| 2082 | static void store_packed_bf(int bit_pos, int bit_size) |
| 2083 | { |
| 2084 | int bits, n, o, m, c; |
| 2085 | |
| 2086 | c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2087 | vswap(); // X B |
| 2088 | save_reg_upstack(vtop->r, 1); |
| 2089 | bits = 0, o = bit_pos >> 3, bit_pos &= 7; |
| 2090 | do { |
| 2091 | incr_bf_adr(o); // X B |
| 2092 | vswap(); //B X |
| 2093 | c ? vdup() : gv_dup(); // B V X |
| 2094 | vrott(3); // X B V |
| 2095 | if (bits) |
| 2096 | vpushi(bits), gen_op(TOK_SHR); |
| 2097 | if (bit_pos) |
| 2098 | vpushi(bit_pos), gen_op(TOK_SHL); |
| 2099 | n = 8 - bit_pos; |
| 2100 | if (n > bit_size) |
| 2101 | n = bit_size; |
| 2102 | if (n < 8) { |
| 2103 | m = ((1 << n) - 1) << bit_pos; |
| 2104 | vpushi(m), gen_op('&'); // X B V1 |
| 2105 | vpushv(vtop-1); // X B V1 B |
| 2106 | vpushi(m & 0x80 ? ~m & 0x7f : ~m); |
| 2107 | gen_op('&'); // X B V1 B1 |
| 2108 | gen_op('|'); // X B V2 |
| 2109 | } |
| 2110 | vdup(), vtop[-1] = vtop[-2]; // X B B V2 |
| 2111 | vstore(), vpop(); // X B |
| 2112 | bits += n, bit_size -= n, bit_pos = 0, o = 1; |
| 2113 | } while (bit_size); |
| 2114 | vpop(), vpop(); |
| 2115 | } |
| 2116 | |
| 2117 | static int adjust_bf(SValue *sv, int bit_pos, int bit_size) |
| 2118 | { |
| 2119 | int t; |
| 2120 | if (0 == sv->type.ref) |
| 2121 | return 0; |
| 2122 | t = sv->type.ref->auxtype; |
| 2123 | if (t != -1 && t != VT_STRUCT) { |
| 2124 | sv->type.t = (sv->type.t & ~(VT_BTYPE | VT_LONG)) | t; |
| 2125 | sv->r |= VT_LVAL; |
| 2126 | } |
| 2127 | return t; |
| 2128 | } |
| 2129 | |
| 2130 | /* store vtop a register belonging to class 'rc'. lvalues are |
| 2131 | converted to values. Cannot be used if cannot be converted to |
| 2132 | register value (such as structures). */ |
| 2133 | ST_FUNC int gv(int rc) |
| 2134 | { |
| 2135 | int r, r2, r_ok, r2_ok, rc2, bt; |
| 2136 | int bit_pos, bit_size, size, align; |
| 2137 | |
| 2138 | /* NOTE: get_reg can modify vstack[] */ |
| 2139 | if (vtop->type.t & VT_BITFIELD) { |
| 2140 | CType type; |
| 2141 | |
| 2142 | bit_pos = BIT_POS(vtop->type.t); |
| 2143 | bit_size = BIT_SIZE(vtop->type.t); |
| 2144 | /* remove bit field info to avoid loops */ |
| 2145 | vtop->type.t &= ~VT_STRUCT_MASK; |
| 2146 | |
| 2147 | type.ref = NULL; |
| 2148 | type.t = vtop->type.t & VT_UNSIGNED; |
| 2149 | if ((vtop->type.t & VT_BTYPE) == VT_BOOL) |
| 2150 | type.t |= VT_UNSIGNED; |
| 2151 | |
| 2152 | r = adjust_bf(vtop, bit_pos, bit_size); |
| 2153 | |
| 2154 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) |
| 2155 | type.t |= VT_LLONG; |
| 2156 | else |
| 2157 | type.t |= VT_INT; |
| 2158 | |
| 2159 | if (r == VT_STRUCT) { |
| 2160 | load_packed_bf(&type, bit_pos, bit_size); |
| 2161 | } else { |
| 2162 | int bits = (type.t & VT_BTYPE) == VT_LLONG ? 64 : 32; |
| 2163 | /* cast to int to propagate signedness in following ops */ |
| 2164 | gen_cast(&type); |
| 2165 | /* generate shifts */ |
| 2166 | vpushi(bits - (bit_pos + bit_size)); |
| 2167 | gen_op(TOK_SHL); |
| 2168 | vpushi(bits - bit_size); |
| 2169 | /* NOTE: transformed to SHR if unsigned */ |
| 2170 | gen_op(TOK_SAR); |
| 2171 | } |
| 2172 | r = gv(rc); |
| 2173 | } else { |
| 2174 | if (is_float(vtop->type.t) && |
| 2175 | (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
| 2176 | /* CPUs usually cannot use float constants, so we store them |
| 2177 | generically in data segment */ |
| 2178 | init_params p = { data_section }; |
| 2179 | unsigned long offset; |
| 2180 | size = type_size(&vtop->type, &align); |
| 2181 | if (NODATA_WANTED) |
| 2182 | size = 0, align = 1; |
| 2183 | offset = section_add(p.sec, size, align); |
| 2184 | vpush_ref(&vtop->type, p.sec, offset, size); |
| 2185 | vswap(); |
| 2186 | init_putv(&p, &vtop->type, offset); |
| 2187 | vtop->r |= VT_LVAL; |
| 2188 | } |
| 2189 | #ifdef CONFIG_TCC_BCHECK |
| 2190 | if (vtop->r & VT_MUSTBOUND) |
| 2191 | gbound(); |
| 2192 | #endif |
| 2193 | |
| 2194 | bt = vtop->type.t & VT_BTYPE; |
| 2195 | |
| 2196 | #ifdef TCC_TARGET_RISCV64 |
| 2197 | /* XXX mega hack */ |
| 2198 | if (bt == VT_LDOUBLE && rc == RC_FLOAT) |
| 2199 | rc = RC_INT; |
| 2200 | #endif |
| 2201 | rc2 = RC2_TYPE(bt, rc); |
| 2202 | |
| 2203 | /* need to reload if: |
| 2204 | - constant |
| 2205 | - lvalue (need to dereference pointer) |
| 2206 | - already a register, but not in the right class */ |
| 2207 | r = vtop->r & VT_VALMASK; |
| 2208 | r_ok = !(vtop->r & VT_LVAL) && (r < VT_CONST) && (reg_classes[r] & rc); |
| 2209 | r2_ok = !rc2 || ((vtop->r2 < VT_CONST) && (reg_classes[vtop->r2] & rc2)); |
| 2210 | |
| 2211 | if (!r_ok || !r2_ok) { |
| 2212 | if (!r_ok) |
| 2213 | r = get_reg(rc); |
| 2214 | if (rc2) { |
| 2215 | int load_type = (bt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T; |
| 2216 | int original_type = vtop->type.t; |
| 2217 | |
| 2218 | /* two register type load : |
| 2219 | expand to two words temporarily */ |
| 2220 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
| 2221 | /* load constant */ |
| 2222 | unsigned long long ll = vtop->c.i; |
| 2223 | vtop->c.i = ll; /* first word */ |
| 2224 | load(r, vtop); |
| 2225 | vtop->r = r; /* save register value */ |
| 2226 | vpushi(ll >> 32); /* second word */ |
| 2227 | } else if (vtop->r & VT_LVAL) { |
| 2228 | /* We do not want to modifier the long long pointer here. |
| 2229 | So we save any other instances down the stack */ |
| 2230 | save_reg_upstack(vtop->r, 1); |
| 2231 | /* load from memory */ |
| 2232 | vtop->type.t = load_type; |
| 2233 | load(r, vtop); |
| 2234 | vdup(); |
| 2235 | vtop[-1].r = r; /* save register value */ |
| 2236 | /* increment pointer to get second word */ |
| 2237 | vtop->type.t = VT_PTRDIFF_T; |
| 2238 | gaddrof(); |
| 2239 | vpushs(PTR_SIZE); |
| 2240 | gen_op('+'); |
| 2241 | vtop->r |= VT_LVAL; |
| 2242 | vtop->type.t = load_type; |
| 2243 | } else { |
| 2244 | /* move registers */ |
| 2245 | if (!r_ok) |
| 2246 | load(r, vtop); |
| 2247 | if (r2_ok && vtop->r2 < VT_CONST) |
| 2248 | goto done; |
| 2249 | vdup(); |
| 2250 | vtop[-1].r = r; /* save register value */ |
| 2251 | vtop->r = vtop[-1].r2; |
| 2252 | } |
| 2253 | /* Allocate second register. Here we rely on the fact that |
| 2254 | get_reg() tries first to free r2 of an SValue. */ |
| 2255 | r2 = get_reg(rc2); |
| 2256 | load(r2, vtop); |
| 2257 | vpop(); |
| 2258 | /* write second register */ |
| 2259 | vtop->r2 = r2; |
| 2260 | done: |
| 2261 | vtop->type.t = original_type; |
| 2262 | } else { |
| 2263 | if (vtop->r == VT_CMP) |
| 2264 | vset_VT_JMP(); |
| 2265 | /* one register type load */ |
| 2266 | load(r, vtop); |
| 2267 | } |
| 2268 | } |
| 2269 | vtop->r = r; |
| 2270 | #ifdef TCC_TARGET_C67 |
| 2271 | /* uses register pairs for doubles */ |
| 2272 | if (bt == VT_DOUBLE) |
| 2273 | vtop->r2 = r+1; |
| 2274 | #endif |
| 2275 | } |
| 2276 | return r; |
| 2277 | } |
| 2278 | |
| 2279 | /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
| 2280 | ST_FUNC void gv2(int rc1, int rc2) |
| 2281 | { |
| 2282 | /* generate more generic register first. But VT_JMP or VT_CMP |
| 2283 | values must be generated first in all cases to avoid possible |
| 2284 | reload errors */ |
| 2285 | if (vtop->r != VT_CMP && rc1 <= rc2) { |
| 2286 | vswap(); |
| 2287 | gv(rc1); |
| 2288 | vswap(); |
| 2289 | gv(rc2); |
| 2290 | /* test if reload is needed for first register */ |
| 2291 | if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { |
| 2292 | vswap(); |
| 2293 | gv(rc1); |
| 2294 | vswap(); |
| 2295 | } |
| 2296 | } else { |
| 2297 | gv(rc2); |
| 2298 | vswap(); |
| 2299 | gv(rc1); |
| 2300 | vswap(); |
| 2301 | /* test if reload is needed for first register */ |
| 2302 | if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { |
| 2303 | gv(rc2); |
| 2304 | } |
| 2305 | } |
| 2306 | } |
| 2307 | |
| 2308 | #if PTR_SIZE == 4 |
| 2309 | /* expand 64bit on stack in two ints */ |
| 2310 | ST_FUNC void lexpand(void) |
| 2311 | { |
| 2312 | int u, v; |
| 2313 | u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); |
| 2314 | v = vtop->r & (VT_VALMASK | VT_LVAL); |
| 2315 | if (v == VT_CONST) { |
| 2316 | vdup(); |
| 2317 | vtop[0].c.i >>= 32; |
| 2318 | } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { |
| 2319 | vdup(); |
| 2320 | vtop[0].c.i += 4; |
| 2321 | } else { |
| 2322 | gv(RC_INT); |
| 2323 | vdup(); |
| 2324 | vtop[0].r = vtop[-1].r2; |
| 2325 | vtop[0].r2 = vtop[-1].r2 = VT_CONST; |
| 2326 | } |
| 2327 | vtop[0].type.t = vtop[-1].type.t = VT_INT | u; |
| 2328 | } |
| 2329 | #endif |
| 2330 | |
| 2331 | #if PTR_SIZE == 4 |
| 2332 | /* build a long long from two ints */ |
| 2333 | static void lbuild(int t) |
| 2334 | { |
| 2335 | gv2(RC_INT, RC_INT); |
| 2336 | vtop[-1].r2 = vtop[0].r; |
| 2337 | vtop[-1].type.t = t; |
| 2338 | vpop(); |
| 2339 | } |
| 2340 | #endif |
| 2341 | |
| 2342 | /* convert stack entry to register and duplicate its value in another |
| 2343 | register */ |
| 2344 | static void gv_dup(void) |
| 2345 | { |
| 2346 | int t, rc, r; |
| 2347 | |
| 2348 | t = vtop->type.t; |
| 2349 | #if PTR_SIZE == 4 |
| 2350 | if ((t & VT_BTYPE) == VT_LLONG) { |
| 2351 | if (t & VT_BITFIELD) { |
| 2352 | gv(RC_INT); |
| 2353 | t = vtop->type.t; |
| 2354 | } |
| 2355 | lexpand(); |
| 2356 | gv_dup(); |
| 2357 | vswap(); |
| 2358 | vrotb(3); |
| 2359 | gv_dup(); |
| 2360 | vrotb(4); |
| 2361 | /* stack: H L L1 H1 */ |
| 2362 | lbuild(t); |
| 2363 | vrotb(3); |
| 2364 | vrotb(3); |
| 2365 | vswap(); |
| 2366 | lbuild(t); |
| 2367 | vswap(); |
| 2368 | return; |
| 2369 | } |
| 2370 | #endif |
| 2371 | /* duplicate value */ |
| 2372 | rc = RC_TYPE(t); |
| 2373 | gv(rc); |
| 2374 | r = get_reg(rc); |
| 2375 | vdup(); |
| 2376 | load(r, vtop); |
| 2377 | vtop->r = r; |
| 2378 | } |
| 2379 | |
| 2380 | #if PTR_SIZE == 4 |
| 2381 | /* generate CPU independent (unsigned) long long operations */ |
| 2382 | static void gen_opl(int op) |
| 2383 | { |
| 2384 | int t, a, b, op1, c, i; |
| 2385 | int func; |
| 2386 | unsigned short reg_iret = REG_IRET; |
| 2387 | unsigned short reg_lret = REG_IRE2; |
| 2388 | SValue tmp; |
| 2389 | |
| 2390 | switch(op) { |
| 2391 | case '/': |
| 2392 | case TOK_PDIV: |
| 2393 | func = TOK___divdi3; |
| 2394 | goto gen_func; |
| 2395 | case TOK_UDIV: |
| 2396 | func = TOK___udivdi3; |
| 2397 | goto gen_func; |
| 2398 | case '%': |
| 2399 | func = TOK___moddi3; |
| 2400 | goto gen_mod_func; |
| 2401 | case TOK_UMOD: |
| 2402 | func = TOK___umoddi3; |
| 2403 | gen_mod_func: |
| 2404 | #ifdef TCC_ARM_EABI |
| 2405 | reg_iret = TREG_R2; |
| 2406 | reg_lret = TREG_R3; |
| 2407 | #endif |
| 2408 | gen_func: |
| 2409 | /* call generic long long function */ |
| 2410 | vpush_global_sym(&func_old_type, func); |
| 2411 | vrott(3); |
| 2412 | gfunc_call(2); |
| 2413 | vpushi(0); |
| 2414 | vtop->r = reg_iret; |
| 2415 | vtop->r2 = reg_lret; |
| 2416 | break; |
| 2417 | case '^': |
| 2418 | case '&': |
| 2419 | case '|': |
| 2420 | case '*': |
| 2421 | case '+': |
| 2422 | case '-': |
| 2423 | //pv("gen_opl A",0,2); |
| 2424 | t = vtop->type.t; |
| 2425 | vswap(); |
| 2426 | lexpand(); |
| 2427 | vrotb(3); |
| 2428 | lexpand(); |
| 2429 | /* stack: L1 H1 L2 H2 */ |
| 2430 | tmp = vtop[0]; |
| 2431 | vtop[0] = vtop[-3]; |
| 2432 | vtop[-3] = tmp; |
| 2433 | tmp = vtop[-2]; |
| 2434 | vtop[-2] = vtop[-3]; |
| 2435 | vtop[-3] = tmp; |
| 2436 | vswap(); |
| 2437 | /* stack: H1 H2 L1 L2 */ |
| 2438 | //pv("gen_opl B",0,4); |
| 2439 | if (op == '*') { |
| 2440 | vpushv(vtop - 1); |
| 2441 | vpushv(vtop - 1); |
| 2442 | gen_op(TOK_UMULL); |
| 2443 | lexpand(); |
| 2444 | /* stack: H1 H2 L1 L2 ML MH */ |
| 2445 | for(i=0;i<4;i++) |
| 2446 | vrotb(6); |
| 2447 | /* stack: ML MH H1 H2 L1 L2 */ |
| 2448 | tmp = vtop[0]; |
| 2449 | vtop[0] = vtop[-2]; |
| 2450 | vtop[-2] = tmp; |
| 2451 | /* stack: ML MH H1 L2 H2 L1 */ |
| 2452 | gen_op('*'); |
| 2453 | vrotb(3); |
| 2454 | vrotb(3); |
| 2455 | gen_op('*'); |
| 2456 | /* stack: ML MH M1 M2 */ |
| 2457 | gen_op('+'); |
| 2458 | gen_op('+'); |
| 2459 | } else if (op == '+' || op == '-') { |
| 2460 | /* XXX: add non carry method too (for MIPS or alpha) */ |
| 2461 | if (op == '+') |
| 2462 | op1 = TOK_ADDC1; |
| 2463 | else |
| 2464 | op1 = TOK_SUBC1; |
| 2465 | gen_op(op1); |
| 2466 | /* stack: H1 H2 (L1 op L2) */ |
| 2467 | vrotb(3); |
| 2468 | vrotb(3); |
| 2469 | gen_op(op1 + 1); /* TOK_xxxC2 */ |
| 2470 | } else { |
| 2471 | gen_op(op); |
| 2472 | /* stack: H1 H2 (L1 op L2) */ |
| 2473 | vrotb(3); |
| 2474 | vrotb(3); |
| 2475 | /* stack: (L1 op L2) H1 H2 */ |
| 2476 | gen_op(op); |
| 2477 | /* stack: (L1 op L2) (H1 op H2) */ |
| 2478 | } |
| 2479 | /* stack: L H */ |
| 2480 | lbuild(t); |
| 2481 | break; |
| 2482 | case TOK_SAR: |
| 2483 | case TOK_SHR: |
| 2484 | case TOK_SHL: |
| 2485 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
| 2486 | t = vtop[-1].type.t; |
| 2487 | vswap(); |
| 2488 | lexpand(); |
| 2489 | vrotb(3); |
| 2490 | /* stack: L H shift */ |
| 2491 | c = (int)vtop->c.i; |
| 2492 | /* constant: simpler */ |
| 2493 | /* NOTE: all comments are for SHL. the other cases are |
| 2494 | done by swapping words */ |
| 2495 | vpop(); |
| 2496 | if (op != TOK_SHL) |
| 2497 | vswap(); |
| 2498 | if (c >= 32) { |
| 2499 | /* stack: L H */ |
| 2500 | vpop(); |
| 2501 | if (c > 32) { |
| 2502 | vpushi(c - 32); |
| 2503 | gen_op(op); |
| 2504 | } |
| 2505 | if (op != TOK_SAR) { |
| 2506 | vpushi(0); |
| 2507 | } else { |
| 2508 | gv_dup(); |
| 2509 | vpushi(31); |
| 2510 | gen_op(TOK_SAR); |
| 2511 | } |
| 2512 | vswap(); |
| 2513 | } else { |
| 2514 | vswap(); |
| 2515 | gv_dup(); |
| 2516 | /* stack: H L L */ |
| 2517 | vpushi(c); |
| 2518 | gen_op(op); |
| 2519 | vswap(); |
| 2520 | vpushi(32 - c); |
| 2521 | if (op == TOK_SHL) |
| 2522 | gen_op(TOK_SHR); |
| 2523 | else |
| 2524 | gen_op(TOK_SHL); |
| 2525 | vrotb(3); |
| 2526 | /* stack: L L H */ |
| 2527 | vpushi(c); |
| 2528 | if (op == TOK_SHL) |
| 2529 | gen_op(TOK_SHL); |
| 2530 | else |
| 2531 | gen_op(TOK_SHR); |
| 2532 | gen_op('|'); |
| 2533 | } |
| 2534 | if (op != TOK_SHL) |
| 2535 | vswap(); |
| 2536 | lbuild(t); |
| 2537 | } else { |
| 2538 | /* XXX: should provide a faster fallback on x86 ? */ |
| 2539 | switch(op) { |
| 2540 | case TOK_SAR: |
| 2541 | func = TOK___ashrdi3; |
| 2542 | goto gen_func; |
| 2543 | case TOK_SHR: |
| 2544 | func = TOK___lshrdi3; |
| 2545 | goto gen_func; |
| 2546 | case TOK_SHL: |
| 2547 | func = TOK___ashldi3; |
| 2548 | goto gen_func; |
| 2549 | } |
| 2550 | } |
| 2551 | break; |
| 2552 | default: |
| 2553 | /* compare operations */ |
| 2554 | t = vtop->type.t; |
| 2555 | vswap(); |
| 2556 | lexpand(); |
| 2557 | vrotb(3); |
| 2558 | lexpand(); |
| 2559 | /* stack: L1 H1 L2 H2 */ |
| 2560 | tmp = vtop[-1]; |
| 2561 | vtop[-1] = vtop[-2]; |
| 2562 | vtop[-2] = tmp; |
| 2563 | /* stack: L1 L2 H1 H2 */ |
| 2564 | save_regs(4); |
| 2565 | /* compare high */ |
| 2566 | op1 = op; |
| 2567 | /* when values are equal, we need to compare low words. since |
| 2568 | the jump is inverted, we invert the test too. */ |
| 2569 | if (op1 == TOK_LT) |
| 2570 | op1 = TOK_LE; |
| 2571 | else if (op1 == TOK_GT) |
| 2572 | op1 = TOK_GE; |
| 2573 | else if (op1 == TOK_ULT) |
| 2574 | op1 = TOK_ULE; |
| 2575 | else if (op1 == TOK_UGT) |
| 2576 | op1 = TOK_UGE; |
| 2577 | a = 0; |
| 2578 | b = 0; |
| 2579 | gen_op(op1); |
| 2580 | if (op == TOK_NE) { |
| 2581 | b = gvtst(0, 0); |
| 2582 | } else { |
| 2583 | a = gvtst(1, 0); |
| 2584 | if (op != TOK_EQ) { |
| 2585 | /* generate non equal test */ |
| 2586 | vpushi(0); |
| 2587 | vset_VT_CMP(TOK_NE); |
| 2588 | b = gvtst(0, 0); |
| 2589 | } |
| 2590 | } |
| 2591 | /* compare low. Always unsigned */ |
| 2592 | op1 = op; |
| 2593 | if (op1 == TOK_LT) |
| 2594 | op1 = TOK_ULT; |
| 2595 | else if (op1 == TOK_LE) |
| 2596 | op1 = TOK_ULE; |
| 2597 | else if (op1 == TOK_GT) |
| 2598 | op1 = TOK_UGT; |
| 2599 | else if (op1 == TOK_GE) |
| 2600 | op1 = TOK_UGE; |
| 2601 | gen_op(op1); |
| 2602 | #if 0//def TCC_TARGET_I386 |
| 2603 | if (op == TOK_NE) { gsym(b); break; } |
| 2604 | if (op == TOK_EQ) { gsym(a); break; } |
| 2605 | #endif |
| 2606 | gvtst_set(1, a); |
| 2607 | gvtst_set(0, b); |
| 2608 | break; |
| 2609 | } |
| 2610 | } |
| 2611 | #endif |
| 2612 | |
| 2613 | static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) |
| 2614 | { |
| 2615 | uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); |
| 2616 | return (a ^ b) >> 63 ? -x : x; |
| 2617 | } |
| 2618 | |
| 2619 | static int gen_opic_lt(uint64_t a, uint64_t b) |
| 2620 | { |
| 2621 | return (a ^ (uint64_t)1 << 63) < (b ^ (uint64_t)1 << 63); |
| 2622 | } |
| 2623 | |
| 2624 | /* handle integer constant optimizations and various machine |
| 2625 | independent opt */ |
| 2626 | static void gen_opic(int op) |
| 2627 | { |
| 2628 | SValue *v1 = vtop - 1; |
| 2629 | SValue *v2 = vtop; |
| 2630 | int t1 = v1->type.t & VT_BTYPE; |
| 2631 | int t2 = v2->type.t & VT_BTYPE; |
| 2632 | int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2633 | int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2634 | uint64_t l1 = c1 ? v1->c.i : 0; |
| 2635 | uint64_t l2 = c2 ? v2->c.i : 0; |
| 2636 | int shm = (t1 == VT_LLONG) ? 63 : 31; |
| 2637 | |
| 2638 | if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) |
| 2639 | l1 = ((uint32_t)l1 | |
| 2640 | (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); |
| 2641 | if (t2 != VT_LLONG && (PTR_SIZE != 8 || t2 != VT_PTR)) |
| 2642 | l2 = ((uint32_t)l2 | |
| 2643 | (v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000))); |
| 2644 | |
| 2645 | if (c1 && c2) { |
| 2646 | switch(op) { |
| 2647 | case '+': l1 += l2; break; |
| 2648 | case '-': l1 -= l2; break; |
| 2649 | case '&': l1 &= l2; break; |
| 2650 | case '^': l1 ^= l2; break; |
| 2651 | case '|': l1 |= l2; break; |
| 2652 | case '*': l1 *= l2; break; |
| 2653 | |
| 2654 | case TOK_PDIV: |
| 2655 | case '/': |
| 2656 | case '%': |
| 2657 | case TOK_UDIV: |
| 2658 | case TOK_UMOD: |
| 2659 | /* if division by zero, generate explicit division */ |
| 2660 | if (l2 == 0) { |
| 2661 | if (const_wanted && !(nocode_wanted & unevalmask)) |
| 2662 | tcc_error("division by zero in constant" ); |
| 2663 | goto general_case; |
| 2664 | } |
| 2665 | switch(op) { |
| 2666 | default: l1 = gen_opic_sdiv(l1, l2); break; |
| 2667 | case '%': l1 = l1 - l2 * gen_opic_sdiv(l1, l2); break; |
| 2668 | case TOK_UDIV: l1 = l1 / l2; break; |
| 2669 | case TOK_UMOD: l1 = l1 % l2; break; |
| 2670 | } |
| 2671 | break; |
| 2672 | case TOK_SHL: l1 <<= (l2 & shm); break; |
| 2673 | case TOK_SHR: l1 >>= (l2 & shm); break; |
| 2674 | case TOK_SAR: |
| 2675 | l1 = (l1 >> 63) ? ~(~l1 >> (l2 & shm)) : l1 >> (l2 & shm); |
| 2676 | break; |
| 2677 | /* tests */ |
| 2678 | case TOK_ULT: l1 = l1 < l2; break; |
| 2679 | case TOK_UGE: l1 = l1 >= l2; break; |
| 2680 | case TOK_EQ: l1 = l1 == l2; break; |
| 2681 | case TOK_NE: l1 = l1 != l2; break; |
| 2682 | case TOK_ULE: l1 = l1 <= l2; break; |
| 2683 | case TOK_UGT: l1 = l1 > l2; break; |
| 2684 | case TOK_LT: l1 = gen_opic_lt(l1, l2); break; |
| 2685 | case TOK_GE: l1 = !gen_opic_lt(l1, l2); break; |
| 2686 | case TOK_LE: l1 = !gen_opic_lt(l2, l1); break; |
| 2687 | case TOK_GT: l1 = gen_opic_lt(l2, l1); break; |
| 2688 | /* logical */ |
| 2689 | case TOK_LAND: l1 = l1 && l2; break; |
| 2690 | case TOK_LOR: l1 = l1 || l2; break; |
| 2691 | default: |
| 2692 | goto general_case; |
| 2693 | } |
| 2694 | if (t1 != VT_LLONG && (PTR_SIZE != 8 || t1 != VT_PTR)) |
| 2695 | l1 = ((uint32_t)l1 | |
| 2696 | (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); |
| 2697 | v1->c.i = l1; |
| 2698 | vtop--; |
| 2699 | } else { |
| 2700 | /* if commutative ops, put c2 as constant */ |
| 2701 | if (c1 && (op == '+' || op == '&' || op == '^' || |
| 2702 | op == '|' || op == '*' || op == TOK_EQ || op == TOK_NE)) { |
| 2703 | vswap(); |
| 2704 | c2 = c1; //c = c1, c1 = c2, c2 = c; |
| 2705 | l2 = l1; //l = l1, l1 = l2, l2 = l; |
| 2706 | } |
| 2707 | if (!const_wanted && |
| 2708 | c1 && ((l1 == 0 && |
| 2709 | (op == TOK_SHL || op == TOK_SHR || op == TOK_SAR)) || |
| 2710 | (l1 == -1 && op == TOK_SAR))) { |
| 2711 | /* treat (0 << x), (0 >> x) and (-1 >> x) as constant */ |
| 2712 | vtop--; |
| 2713 | } else if (!const_wanted && |
| 2714 | c2 && ((l2 == 0 && (op == '&' || op == '*')) || |
| 2715 | (op == '|' && |
| 2716 | (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))) || |
| 2717 | (l2 == 1 && (op == '%' || op == TOK_UMOD)))) { |
| 2718 | /* treat (x & 0), (x * 0), (x | -1) and (x % 1) as constant */ |
| 2719 | if (l2 == 1) |
| 2720 | vtop->c.i = 0; |
| 2721 | vswap(); |
| 2722 | vtop--; |
| 2723 | } else if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || |
| 2724 | op == TOK_PDIV) && |
| 2725 | l2 == 1) || |
| 2726 | ((op == '+' || op == '-' || op == '|' || op == '^' || |
| 2727 | op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && |
| 2728 | l2 == 0) || |
| 2729 | (op == '&' && |
| 2730 | (l2 == -1 || (l2 == 0xFFFFFFFF && t2 != VT_LLONG))))) { |
| 2731 | /* filter out NOP operations like x*1, x-0, x&-1... */ |
| 2732 | vtop--; |
| 2733 | } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { |
| 2734 | /* try to use shifts instead of muls or divs */ |
| 2735 | if (l2 > 0 && (l2 & (l2 - 1)) == 0) { |
| 2736 | int n = -1; |
| 2737 | while (l2) { |
| 2738 | l2 >>= 1; |
| 2739 | n++; |
| 2740 | } |
| 2741 | vtop->c.i = n; |
| 2742 | if (op == '*') |
| 2743 | op = TOK_SHL; |
| 2744 | else if (op == TOK_PDIV) |
| 2745 | op = TOK_SAR; |
| 2746 | else |
| 2747 | op = TOK_SHR; |
| 2748 | } |
| 2749 | goto general_case; |
| 2750 | } else if (c2 && (op == '+' || op == '-') && |
| 2751 | (((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM)) |
| 2752 | || (vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_LOCAL)) { |
| 2753 | /* symbol + constant case */ |
| 2754 | if (op == '-') |
| 2755 | l2 = -l2; |
| 2756 | l2 += vtop[-1].c.i; |
| 2757 | /* The backends can't always deal with addends to symbols |
| 2758 | larger than +-1<<31. Don't construct such. */ |
| 2759 | if ((int)l2 != l2) |
| 2760 | goto general_case; |
| 2761 | vtop--; |
| 2762 | vtop->c.i = l2; |
| 2763 | } else { |
| 2764 | general_case: |
| 2765 | /* call low level op generator */ |
| 2766 | if (t1 == VT_LLONG || t2 == VT_LLONG || |
| 2767 | (PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR))) |
| 2768 | gen_opl(op); |
| 2769 | else |
| 2770 | gen_opi(op); |
| 2771 | } |
| 2772 | } |
| 2773 | } |
| 2774 | |
| 2775 | /* generate a floating point operation with constant propagation */ |
| 2776 | static void gen_opif(int op) |
| 2777 | { |
| 2778 | int c1, c2; |
| 2779 | SValue *v1, *v2; |
| 2780 | #if defined _MSC_VER && defined __x86_64__ |
| 2781 | /* avoid bad optimization with f1 -= f2 for f1:-0.0, f2:0.0 */ |
| 2782 | volatile |
| 2783 | #endif |
| 2784 | long double f1, f2; |
| 2785 | |
| 2786 | v1 = vtop - 1; |
| 2787 | v2 = vtop; |
| 2788 | /* currently, we cannot do computations with forward symbols */ |
| 2789 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2790 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 2791 | if (c1 && c2) { |
| 2792 | if (v1->type.t == VT_FLOAT) { |
| 2793 | f1 = v1->c.f; |
| 2794 | f2 = v2->c.f; |
| 2795 | } else if (v1->type.t == VT_DOUBLE) { |
| 2796 | f1 = v1->c.d; |
| 2797 | f2 = v2->c.d; |
| 2798 | } else { |
| 2799 | f1 = v1->c.ld; |
| 2800 | f2 = v2->c.ld; |
| 2801 | } |
| 2802 | |
| 2803 | /* NOTE: we only do constant propagation if finite number (not |
| 2804 | NaN or infinity) (ANSI spec) */ |
| 2805 | if (!ieee_finite(f1) || !ieee_finite(f2)) |
| 2806 | goto general_case; |
| 2807 | |
| 2808 | switch(op) { |
| 2809 | case '+': f1 += f2; break; |
| 2810 | case '-': f1 -= f2; break; |
| 2811 | case '*': f1 *= f2; break; |
| 2812 | case '/': |
| 2813 | if (f2 == 0.0) { |
| 2814 | /* If not in initializer we need to potentially generate |
| 2815 | FP exceptions at runtime, otherwise we want to fold. */ |
| 2816 | if (!const_wanted) |
| 2817 | goto general_case; |
| 2818 | } |
| 2819 | f1 /= f2; |
| 2820 | break; |
| 2821 | /* XXX: also handles tests ? */ |
| 2822 | default: |
| 2823 | goto general_case; |
| 2824 | } |
| 2825 | /* XXX: overflow test ? */ |
| 2826 | if (v1->type.t == VT_FLOAT) { |
| 2827 | v1->c.f = f1; |
| 2828 | } else if (v1->type.t == VT_DOUBLE) { |
| 2829 | v1->c.d = f1; |
| 2830 | } else { |
| 2831 | v1->c.ld = f1; |
| 2832 | } |
| 2833 | vtop--; |
| 2834 | } else { |
| 2835 | general_case: |
| 2836 | gen_opf(op); |
| 2837 | } |
| 2838 | } |
| 2839 | |
| 2840 | /* print a type. If 'varstr' is not NULL, then the variable is also |
| 2841 | printed in the type */ |
| 2842 | /* XXX: union */ |
| 2843 | /* XXX: add array and function pointers */ |
| 2844 | static void type_to_str(char *buf, int buf_size, |
| 2845 | CType *type, const char *varstr) |
| 2846 | { |
| 2847 | int bt, v, t; |
| 2848 | Sym *s, *sa; |
| 2849 | char buf1[256]; |
| 2850 | const char *tstr; |
| 2851 | |
| 2852 | t = type->t; |
| 2853 | bt = t & VT_BTYPE; |
| 2854 | buf[0] = '\0'; |
| 2855 | |
| 2856 | if (t & VT_EXTERN) |
| 2857 | pstrcat(buf, buf_size, "extern " ); |
| 2858 | if (t & VT_STATIC) |
| 2859 | pstrcat(buf, buf_size, "static " ); |
| 2860 | if (t & VT_TYPEDEF) |
| 2861 | pstrcat(buf, buf_size, "typedef " ); |
| 2862 | if (t & VT_INLINE) |
| 2863 | pstrcat(buf, buf_size, "inline " ); |
| 2864 | if (t & VT_VOLATILE) |
| 2865 | pstrcat(buf, buf_size, "volatile " ); |
| 2866 | if (t & VT_CONSTANT) |
| 2867 | pstrcat(buf, buf_size, "const " ); |
| 2868 | |
| 2869 | if (((t & VT_DEFSIGN) && bt == VT_BYTE) |
| 2870 | || ((t & VT_UNSIGNED) |
| 2871 | && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG) |
| 2872 | && !IS_ENUM(t) |
| 2873 | )) |
| 2874 | pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed " ); |
| 2875 | |
| 2876 | buf_size -= strlen(buf); |
| 2877 | buf += strlen(buf); |
| 2878 | |
| 2879 | switch(bt) { |
| 2880 | case VT_VOID: |
| 2881 | tstr = "void" ; |
| 2882 | goto add_tstr; |
| 2883 | case VT_BOOL: |
| 2884 | tstr = "_Bool" ; |
| 2885 | goto add_tstr; |
| 2886 | case VT_BYTE: |
| 2887 | tstr = "char" ; |
| 2888 | goto add_tstr; |
| 2889 | case VT_SHORT: |
| 2890 | tstr = "short" ; |
| 2891 | goto add_tstr; |
| 2892 | case VT_INT: |
| 2893 | tstr = "int" ; |
| 2894 | goto maybe_long; |
| 2895 | case VT_LLONG: |
| 2896 | tstr = "long long" ; |
| 2897 | maybe_long: |
| 2898 | if (t & VT_LONG) |
| 2899 | tstr = "long" ; |
| 2900 | if (!IS_ENUM(t)) |
| 2901 | goto add_tstr; |
| 2902 | tstr = "enum " ; |
| 2903 | goto tstruct; |
| 2904 | case VT_FLOAT: |
| 2905 | tstr = "float" ; |
| 2906 | goto add_tstr; |
| 2907 | case VT_DOUBLE: |
| 2908 | tstr = "double" ; |
| 2909 | if (!(t & VT_LONG)) |
| 2910 | goto add_tstr; |
| 2911 | case VT_LDOUBLE: |
| 2912 | tstr = "long double" ; |
| 2913 | add_tstr: |
| 2914 | pstrcat(buf, buf_size, tstr); |
| 2915 | break; |
| 2916 | case VT_STRUCT: |
| 2917 | tstr = "struct " ; |
| 2918 | if (IS_UNION(t)) |
| 2919 | tstr = "union " ; |
| 2920 | tstruct: |
| 2921 | pstrcat(buf, buf_size, tstr); |
| 2922 | v = type->ref->v & ~SYM_STRUCT; |
| 2923 | if (v >= SYM_FIRST_ANOM) |
| 2924 | pstrcat(buf, buf_size, "<anonymous>" ); |
| 2925 | else |
| 2926 | pstrcat(buf, buf_size, get_tok_str(v, NULL)); |
| 2927 | break; |
| 2928 | case VT_FUNC: |
| 2929 | s = type->ref; |
| 2930 | buf1[0]=0; |
| 2931 | if (varstr && '*' == *varstr) { |
| 2932 | pstrcat(buf1, sizeof(buf1), "(" ); |
| 2933 | pstrcat(buf1, sizeof(buf1), varstr); |
| 2934 | pstrcat(buf1, sizeof(buf1), ")" ); |
| 2935 | } |
| 2936 | pstrcat(buf1, buf_size, "(" ); |
| 2937 | sa = s->next; |
| 2938 | while (sa != NULL) { |
| 2939 | char buf2[256]; |
| 2940 | type_to_str(buf2, sizeof(buf2), &sa->type, NULL); |
| 2941 | pstrcat(buf1, sizeof(buf1), buf2); |
| 2942 | sa = sa->next; |
| 2943 | if (sa) |
| 2944 | pstrcat(buf1, sizeof(buf1), ", " ); |
| 2945 | } |
| 2946 | if (s->f.func_type == FUNC_ELLIPSIS) |
| 2947 | pstrcat(buf1, sizeof(buf1), ", ..." ); |
| 2948 | pstrcat(buf1, sizeof(buf1), ")" ); |
| 2949 | type_to_str(buf, buf_size, &s->type, buf1); |
| 2950 | goto no_var; |
| 2951 | case VT_PTR: |
| 2952 | s = type->ref; |
| 2953 | if (t & VT_ARRAY) { |
| 2954 | if (varstr && '*' == *varstr) |
| 2955 | snprintf(buf1, sizeof(buf1), "(%s)[%d]" , varstr, s->c); |
| 2956 | else |
| 2957 | snprintf(buf1, sizeof(buf1), "%s[%d]" , varstr ? varstr : "" , s->c); |
| 2958 | type_to_str(buf, buf_size, &s->type, buf1); |
| 2959 | goto no_var; |
| 2960 | } |
| 2961 | pstrcpy(buf1, sizeof(buf1), "*" ); |
| 2962 | if (t & VT_CONSTANT) |
| 2963 | pstrcat(buf1, buf_size, "const " ); |
| 2964 | if (t & VT_VOLATILE) |
| 2965 | pstrcat(buf1, buf_size, "volatile " ); |
| 2966 | if (varstr) |
| 2967 | pstrcat(buf1, sizeof(buf1), varstr); |
| 2968 | type_to_str(buf, buf_size, &s->type, buf1); |
| 2969 | goto no_var; |
| 2970 | } |
| 2971 | if (varstr) { |
| 2972 | pstrcat(buf, buf_size, " " ); |
| 2973 | pstrcat(buf, buf_size, varstr); |
| 2974 | } |
| 2975 | no_var: ; |
| 2976 | } |
| 2977 | |
| 2978 | static void type_incompatibility_error(CType* st, CType* dt, const char* fmt) |
| 2979 | { |
| 2980 | char buf1[256], buf2[256]; |
| 2981 | type_to_str(buf1, sizeof(buf1), st, NULL); |
| 2982 | type_to_str(buf2, sizeof(buf2), dt, NULL); |
| 2983 | tcc_error(fmt, buf1, buf2); |
| 2984 | } |
| 2985 | |
| 2986 | static void type_incompatibility_warning(CType* st, CType* dt, const char* fmt) |
| 2987 | { |
| 2988 | char buf1[256], buf2[256]; |
| 2989 | type_to_str(buf1, sizeof(buf1), st, NULL); |
| 2990 | type_to_str(buf2, sizeof(buf2), dt, NULL); |
| 2991 | tcc_warning(fmt, buf1, buf2); |
| 2992 | } |
| 2993 | |
| 2994 | static int pointed_size(CType *type) |
| 2995 | { |
| 2996 | int align; |
| 2997 | return type_size(pointed_type(type), &align); |
| 2998 | } |
| 2999 | |
| 3000 | static void vla_runtime_pointed_size(CType *type) |
| 3001 | { |
| 3002 | int align; |
| 3003 | vla_runtime_type_size(pointed_type(type), &align); |
| 3004 | } |
| 3005 | |
| 3006 | static inline int is_null_pointer(SValue *p) |
| 3007 | { |
| 3008 | if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
| 3009 | return 0; |
| 3010 | return ((p->type.t & VT_BTYPE) == VT_INT && (uint32_t)p->c.i == 0) || |
| 3011 | ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.i == 0) || |
| 3012 | ((p->type.t & VT_BTYPE) == VT_PTR && |
| 3013 | (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0) && |
| 3014 | ((pointed_type(&p->type)->t & VT_BTYPE) == VT_VOID) && |
| 3015 | 0 == (pointed_type(&p->type)->t & (VT_CONSTANT | VT_VOLATILE)) |
| 3016 | ); |
| 3017 | } |
| 3018 | |
| 3019 | /* compare function types. OLD functions match any new functions */ |
| 3020 | static int is_compatible_func(CType *type1, CType *type2) |
| 3021 | { |
| 3022 | Sym *s1, *s2; |
| 3023 | |
| 3024 | s1 = type1->ref; |
| 3025 | s2 = type2->ref; |
| 3026 | if (s1->f.func_call != s2->f.func_call) |
| 3027 | return 0; |
| 3028 | if (s1->f.func_type != s2->f.func_type |
| 3029 | && s1->f.func_type != FUNC_OLD |
| 3030 | && s2->f.func_type != FUNC_OLD) |
| 3031 | return 0; |
| 3032 | /* we should check the function return type for FUNC_OLD too |
| 3033 | but that causes problems with the internally used support |
| 3034 | functions such as TOK_memmove */ |
| 3035 | if (s1->f.func_type == FUNC_OLD && !s1->next) |
| 3036 | return 1; |
| 3037 | if (s2->f.func_type == FUNC_OLD && !s2->next) |
| 3038 | return 1; |
| 3039 | for (;;) { |
| 3040 | if (!is_compatible_unqualified_types(&s1->type, &s2->type)) |
| 3041 | return 0; |
| 3042 | s1 = s1->next; |
| 3043 | s2 = s2->next; |
| 3044 | if (!s1) |
| 3045 | return !s2; |
| 3046 | if (!s2) |
| 3047 | return 0; |
| 3048 | } |
| 3049 | } |
| 3050 | |
| 3051 | /* return true if type1 and type2 are the same. If unqualified is |
| 3052 | true, qualifiers on the types are ignored. |
| 3053 | */ |
| 3054 | static int compare_types(CType *type1, CType *type2, int unqualified) |
| 3055 | { |
| 3056 | int bt1, t1, t2; |
| 3057 | |
| 3058 | t1 = type1->t & VT_TYPE; |
| 3059 | t2 = type2->t & VT_TYPE; |
| 3060 | if (unqualified) { |
| 3061 | /* strip qualifiers before comparing */ |
| 3062 | t1 &= ~(VT_CONSTANT | VT_VOLATILE); |
| 3063 | t2 &= ~(VT_CONSTANT | VT_VOLATILE); |
| 3064 | } |
| 3065 | |
| 3066 | /* Default Vs explicit signedness only matters for char */ |
| 3067 | if ((t1 & VT_BTYPE) != VT_BYTE) { |
| 3068 | t1 &= ~VT_DEFSIGN; |
| 3069 | t2 &= ~VT_DEFSIGN; |
| 3070 | } |
| 3071 | /* XXX: bitfields ? */ |
| 3072 | if (t1 != t2) |
| 3073 | return 0; |
| 3074 | |
| 3075 | if ((t1 & VT_ARRAY) |
| 3076 | && !(type1->ref->c < 0 |
| 3077 | || type2->ref->c < 0 |
| 3078 | || type1->ref->c == type2->ref->c)) |
| 3079 | return 0; |
| 3080 | |
| 3081 | /* test more complicated cases */ |
| 3082 | bt1 = t1 & VT_BTYPE; |
| 3083 | if (bt1 == VT_PTR) { |
| 3084 | type1 = pointed_type(type1); |
| 3085 | type2 = pointed_type(type2); |
| 3086 | return is_compatible_types(type1, type2); |
| 3087 | } else if (bt1 == VT_STRUCT) { |
| 3088 | return (type1->ref == type2->ref); |
| 3089 | } else if (bt1 == VT_FUNC) { |
| 3090 | return is_compatible_func(type1, type2); |
| 3091 | } else if (IS_ENUM(type1->t) && IS_ENUM(type2->t)) { |
| 3092 | /* If both are enums then they must be the same, if only one is then |
| 3093 | t1 and t2 must be equal, which was checked above already. */ |
| 3094 | return type1->ref == type2->ref; |
| 3095 | } else { |
| 3096 | return 1; |
| 3097 | } |
| 3098 | } |
| 3099 | |
| 3100 | /* Check if OP1 and OP2 can be "combined" with operation OP, the combined |
| 3101 | type is stored in DEST if non-null (except for pointer plus/minus) . */ |
| 3102 | static int combine_types(CType *dest, SValue *op1, SValue *op2, int op) |
| 3103 | { |
| 3104 | CType *type1 = &op1->type, *type2 = &op2->type, type; |
| 3105 | int t1 = type1->t, t2 = type2->t, bt1 = t1 & VT_BTYPE, bt2 = t2 & VT_BTYPE; |
| 3106 | int ret = 1; |
| 3107 | |
| 3108 | type.t = VT_VOID; |
| 3109 | type.ref = NULL; |
| 3110 | |
| 3111 | if (bt1 == VT_VOID || bt2 == VT_VOID) { |
| 3112 | ret = op == '?' ? 1 : 0; |
| 3113 | /* NOTE: as an extension, we accept void on only one side */ |
| 3114 | type.t = VT_VOID; |
| 3115 | } else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
| 3116 | if (op == '+') ; /* Handled in caller */ |
| 3117 | /* http://port70.net/~nsz/c/c99/n1256.html#6.5.15p6 */ |
| 3118 | /* If one is a null ptr constant the result type is the other. */ |
| 3119 | else if (is_null_pointer (op2)) type = *type1; |
| 3120 | else if (is_null_pointer (op1)) type = *type2; |
| 3121 | else if (bt1 != bt2) { |
| 3122 | /* accept comparison or cond-expr between pointer and integer |
| 3123 | with a warning */ |
| 3124 | if ((op == '?' || TOK_ISCOND(op)) |
| 3125 | && (is_integer_btype(bt1) || is_integer_btype(bt2))) |
| 3126 | tcc_warning("pointer/integer mismatch in %s" , |
| 3127 | op == '?' ? "conditional expression" : "comparison" ); |
| 3128 | else if (op != '-' || !is_integer_btype(bt2)) |
| 3129 | ret = 0; |
| 3130 | type = *(bt1 == VT_PTR ? type1 : type2); |
| 3131 | } else { |
| 3132 | CType *pt1 = pointed_type(type1); |
| 3133 | CType *pt2 = pointed_type(type2); |
| 3134 | int pbt1 = pt1->t & VT_BTYPE; |
| 3135 | int pbt2 = pt2->t & VT_BTYPE; |
| 3136 | int newquals, copied = 0; |
| 3137 | if (pbt1 != VT_VOID && pbt2 != VT_VOID |
| 3138 | && !compare_types(pt1, pt2, 1/*unqualif*/)) { |
| 3139 | if (op != '?' && !TOK_ISCOND(op)) |
| 3140 | ret = 0; |
| 3141 | else |
| 3142 | type_incompatibility_warning(type1, type2, |
| 3143 | op == '?' |
| 3144 | ? "pointer type mismatch in conditional expression ('%s' and '%s')" |
| 3145 | : "pointer type mismatch in comparison('%s' and '%s')" ); |
| 3146 | } |
| 3147 | if (op == '?') { |
| 3148 | /* pointers to void get preferred, otherwise the |
| 3149 | pointed to types minus qualifs should be compatible */ |
| 3150 | type = *((pbt1 == VT_VOID) ? type1 : type2); |
| 3151 | /* combine qualifs */ |
| 3152 | newquals = ((pt1->t | pt2->t) & (VT_CONSTANT | VT_VOLATILE)); |
| 3153 | if ((~pointed_type(&type)->t & (VT_CONSTANT | VT_VOLATILE)) |
| 3154 | & newquals) |
| 3155 | { |
| 3156 | /* copy the pointer target symbol */ |
| 3157 | type.ref = sym_push(SYM_FIELD, &type.ref->type, |
| 3158 | 0, type.ref->c); |
| 3159 | copied = 1; |
| 3160 | pointed_type(&type)->t |= newquals; |
| 3161 | } |
| 3162 | /* pointers to incomplete arrays get converted to |
| 3163 | pointers to completed ones if possible */ |
| 3164 | if (pt1->t & VT_ARRAY |
| 3165 | && pt2->t & VT_ARRAY |
| 3166 | && pointed_type(&type)->ref->c < 0 |
| 3167 | && (pt1->ref->c > 0 || pt2->ref->c > 0)) |
| 3168 | { |
| 3169 | if (!copied) |
| 3170 | type.ref = sym_push(SYM_FIELD, &type.ref->type, |
| 3171 | 0, type.ref->c); |
| 3172 | pointed_type(&type)->ref = |
| 3173 | sym_push(SYM_FIELD, &pointed_type(&type)->ref->type, |
| 3174 | 0, pointed_type(&type)->ref->c); |
| 3175 | pointed_type(&type)->ref->c = |
| 3176 | 0 < pt1->ref->c ? pt1->ref->c : pt2->ref->c; |
| 3177 | } |
| 3178 | } |
| 3179 | } |
| 3180 | if (TOK_ISCOND(op)) |
| 3181 | type.t = VT_SIZE_T; |
| 3182 | } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
| 3183 | if (op != '?' || !compare_types(type1, type2, 1)) |
| 3184 | ret = 0; |
| 3185 | type = *type1; |
| 3186 | } else if (is_float(bt1) || is_float(bt2)) { |
| 3187 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
| 3188 | type.t = VT_LDOUBLE; |
| 3189 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
| 3190 | type.t = VT_DOUBLE; |
| 3191 | } else { |
| 3192 | type.t = VT_FLOAT; |
| 3193 | } |
| 3194 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
| 3195 | /* cast to biggest op */ |
| 3196 | type.t = VT_LLONG | VT_LONG; |
| 3197 | if (bt1 == VT_LLONG) |
| 3198 | type.t &= t1; |
| 3199 | if (bt2 == VT_LLONG) |
| 3200 | type.t &= t2; |
| 3201 | /* convert to unsigned if it does not fit in a long long */ |
| 3202 | if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || |
| 3203 | (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) |
| 3204 | type.t |= VT_UNSIGNED; |
| 3205 | } else { |
| 3206 | /* integer operations */ |
| 3207 | type.t = VT_INT | (VT_LONG & (t1 | t2)); |
| 3208 | /* convert to unsigned if it does not fit in an integer */ |
| 3209 | if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || |
| 3210 | (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) |
| 3211 | type.t |= VT_UNSIGNED; |
| 3212 | } |
| 3213 | if (dest) |
| 3214 | *dest = type; |
| 3215 | return ret; |
| 3216 | } |
| 3217 | |
| 3218 | /* generic gen_op: handles types problems */ |
| 3219 | ST_FUNC void gen_op(int op) |
| 3220 | { |
| 3221 | int u, t1, t2, bt1, bt2, t; |
| 3222 | CType type1, combtype; |
| 3223 | |
| 3224 | redo: |
| 3225 | t1 = vtop[-1].type.t; |
| 3226 | t2 = vtop[0].type.t; |
| 3227 | bt1 = t1 & VT_BTYPE; |
| 3228 | bt2 = t2 & VT_BTYPE; |
| 3229 | |
| 3230 | if (bt1 == VT_FUNC || bt2 == VT_FUNC) { |
| 3231 | if (bt2 == VT_FUNC) { |
| 3232 | mk_pointer(&vtop->type); |
| 3233 | gaddrof(); |
| 3234 | } |
| 3235 | if (bt1 == VT_FUNC) { |
| 3236 | vswap(); |
| 3237 | mk_pointer(&vtop->type); |
| 3238 | gaddrof(); |
| 3239 | vswap(); |
| 3240 | } |
| 3241 | goto redo; |
| 3242 | } else if (!combine_types(&combtype, vtop - 1, vtop, op)) { |
| 3243 | tcc_error_noabort("invalid operand types for binary operation" ); |
| 3244 | vpop(); |
| 3245 | } else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
| 3246 | /* at least one operand is a pointer */ |
| 3247 | /* relational op: must be both pointers */ |
| 3248 | if (TOK_ISCOND(op)) |
| 3249 | goto std_op; |
| 3250 | /* if both pointers, then it must be the '-' op */ |
| 3251 | if (bt1 == VT_PTR && bt2 == VT_PTR) { |
| 3252 | if (op != '-') |
| 3253 | tcc_error("cannot use pointers here" ); |
| 3254 | if (vtop[-1].type.t & VT_VLA) { |
| 3255 | vla_runtime_pointed_size(&vtop[-1].type); |
| 3256 | } else { |
| 3257 | vpushi(pointed_size(&vtop[-1].type)); |
| 3258 | } |
| 3259 | vrott(3); |
| 3260 | gen_opic(op); |
| 3261 | vtop->type.t = VT_PTRDIFF_T; |
| 3262 | vswap(); |
| 3263 | gen_op(TOK_PDIV); |
| 3264 | } else { |
| 3265 | /* exactly one pointer : must be '+' or '-'. */ |
| 3266 | if (op != '-' && op != '+') |
| 3267 | tcc_error("cannot use pointers here" ); |
| 3268 | /* Put pointer as first operand */ |
| 3269 | if (bt2 == VT_PTR) { |
| 3270 | vswap(); |
| 3271 | t = t1, t1 = t2, t2 = t; |
| 3272 | } |
| 3273 | #if PTR_SIZE == 4 |
| 3274 | if ((vtop[0].type.t & VT_BTYPE) == VT_LLONG) |
| 3275 | /* XXX: truncate here because gen_opl can't handle ptr + long long */ |
| 3276 | gen_cast_s(VT_INT); |
| 3277 | #endif |
| 3278 | type1 = vtop[-1].type; |
| 3279 | if (vtop[-1].type.t & VT_VLA) |
| 3280 | vla_runtime_pointed_size(&vtop[-1].type); |
| 3281 | else { |
| 3282 | u = pointed_size(&vtop[-1].type); |
| 3283 | if (u < 0) |
| 3284 | tcc_error("unknown array element size" ); |
| 3285 | #if PTR_SIZE == 8 |
| 3286 | vpushll(u); |
| 3287 | #else |
| 3288 | /* XXX: cast to int ? (long long case) */ |
| 3289 | vpushi(u); |
| 3290 | #endif |
| 3291 | } |
| 3292 | gen_op('*'); |
| 3293 | #ifdef CONFIG_TCC_BCHECK |
| 3294 | if (tcc_state->do_bounds_check && !const_wanted) { |
| 3295 | /* if bounded pointers, we generate a special code to |
| 3296 | test bounds */ |
| 3297 | if (op == '-') { |
| 3298 | vpushi(0); |
| 3299 | vswap(); |
| 3300 | gen_op('-'); |
| 3301 | } |
| 3302 | gen_bounded_ptr_add(); |
| 3303 | } else |
| 3304 | #endif |
| 3305 | { |
| 3306 | gen_opic(op); |
| 3307 | } |
| 3308 | type1.t &= ~VT_ARRAY; |
| 3309 | /* put again type if gen_opic() swaped operands */ |
| 3310 | vtop->type = type1; |
| 3311 | } |
| 3312 | } else { |
| 3313 | /* floats can only be used for a few operations */ |
| 3314 | if (is_float(combtype.t) |
| 3315 | && op != '+' && op != '-' && op != '*' && op != '/' |
| 3316 | && !TOK_ISCOND(op)) |
| 3317 | tcc_error("invalid operands for binary operation" ); |
| 3318 | else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) { |
| 3319 | t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; |
| 3320 | if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) |
| 3321 | t |= VT_UNSIGNED; |
| 3322 | t |= (VT_LONG & t1); |
| 3323 | combtype.t = t; |
| 3324 | } |
| 3325 | std_op: |
| 3326 | t = t2 = combtype.t; |
| 3327 | /* XXX: currently, some unsigned operations are explicit, so |
| 3328 | we modify them here */ |
| 3329 | if (t & VT_UNSIGNED) { |
| 3330 | if (op == TOK_SAR) |
| 3331 | op = TOK_SHR; |
| 3332 | else if (op == '/') |
| 3333 | op = TOK_UDIV; |
| 3334 | else if (op == '%') |
| 3335 | op = TOK_UMOD; |
| 3336 | else if (op == TOK_LT) |
| 3337 | op = TOK_ULT; |
| 3338 | else if (op == TOK_GT) |
| 3339 | op = TOK_UGT; |
| 3340 | else if (op == TOK_LE) |
| 3341 | op = TOK_ULE; |
| 3342 | else if (op == TOK_GE) |
| 3343 | op = TOK_UGE; |
| 3344 | } |
| 3345 | vswap(); |
| 3346 | gen_cast_s(t); |
| 3347 | vswap(); |
| 3348 | /* special case for shifts and long long: we keep the shift as |
| 3349 | an integer */ |
| 3350 | if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) |
| 3351 | t2 = VT_INT; |
| 3352 | gen_cast_s(t2); |
| 3353 | if (is_float(t)) |
| 3354 | gen_opif(op); |
| 3355 | else |
| 3356 | gen_opic(op); |
| 3357 | if (TOK_ISCOND(op)) { |
| 3358 | /* relational op: the result is an int */ |
| 3359 | vtop->type.t = VT_INT; |
| 3360 | } else { |
| 3361 | vtop->type.t = t; |
| 3362 | } |
| 3363 | } |
| 3364 | // Make sure that we have converted to an rvalue: |
| 3365 | if (vtop->r & VT_LVAL) |
| 3366 | gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT); |
| 3367 | } |
| 3368 | |
| 3369 | #if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 || defined TCC_TARGET_ARM |
| 3370 | #define gen_cvt_itof1 gen_cvt_itof |
| 3371 | #else |
| 3372 | /* generic itof for unsigned long long case */ |
| 3373 | static void gen_cvt_itof1(int t) |
| 3374 | { |
| 3375 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
| 3376 | (VT_LLONG | VT_UNSIGNED)) { |
| 3377 | |
| 3378 | if (t == VT_FLOAT) |
| 3379 | vpush_global_sym(&func_old_type, TOK___floatundisf); |
| 3380 | #if LDOUBLE_SIZE != 8 |
| 3381 | else if (t == VT_LDOUBLE) |
| 3382 | vpush_global_sym(&func_old_type, TOK___floatundixf); |
| 3383 | #endif |
| 3384 | else |
| 3385 | vpush_global_sym(&func_old_type, TOK___floatundidf); |
| 3386 | vrott(2); |
| 3387 | gfunc_call(1); |
| 3388 | vpushi(0); |
| 3389 | PUT_R_RET(vtop, t); |
| 3390 | } else { |
| 3391 | gen_cvt_itof(t); |
| 3392 | } |
| 3393 | } |
| 3394 | #endif |
| 3395 | |
| 3396 | #if defined TCC_TARGET_ARM64 || defined TCC_TARGET_RISCV64 |
| 3397 | #define gen_cvt_ftoi1 gen_cvt_ftoi |
| 3398 | #else |
| 3399 | /* generic ftoi for unsigned long long case */ |
| 3400 | static void gen_cvt_ftoi1(int t) |
| 3401 | { |
| 3402 | int st; |
| 3403 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
| 3404 | /* not handled natively */ |
| 3405 | st = vtop->type.t & VT_BTYPE; |
| 3406 | if (st == VT_FLOAT) |
| 3407 | vpush_global_sym(&func_old_type, TOK___fixunssfdi); |
| 3408 | #if LDOUBLE_SIZE != 8 |
| 3409 | else if (st == VT_LDOUBLE) |
| 3410 | vpush_global_sym(&func_old_type, TOK___fixunsxfdi); |
| 3411 | #endif |
| 3412 | else |
| 3413 | vpush_global_sym(&func_old_type, TOK___fixunsdfdi); |
| 3414 | vrott(2); |
| 3415 | gfunc_call(1); |
| 3416 | vpushi(0); |
| 3417 | PUT_R_RET(vtop, t); |
| 3418 | } else { |
| 3419 | gen_cvt_ftoi(t); |
| 3420 | } |
| 3421 | } |
| 3422 | #endif |
| 3423 | |
| 3424 | /* special delayed cast for char/short */ |
| 3425 | static void force_charshort_cast(void) |
| 3426 | { |
| 3427 | int sbt = BFGET(vtop->r, VT_MUSTCAST) == 2 ? VT_LLONG : VT_INT; |
| 3428 | int dbt = vtop->type.t; |
| 3429 | vtop->r &= ~VT_MUSTCAST; |
| 3430 | vtop->type.t = sbt; |
| 3431 | gen_cast_s(dbt == VT_BOOL ? VT_BYTE|VT_UNSIGNED : dbt); |
| 3432 | vtop->type.t = dbt; |
| 3433 | } |
| 3434 | |
| 3435 | static void gen_cast_s(int t) |
| 3436 | { |
| 3437 | CType type; |
| 3438 | type.t = t; |
| 3439 | type.ref = NULL; |
| 3440 | gen_cast(&type); |
| 3441 | } |
| 3442 | |
| 3443 | /* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ |
| 3444 | static void gen_cast(CType *type) |
| 3445 | { |
| 3446 | int sbt, dbt, sf, df, c; |
| 3447 | int dbt_bt, sbt_bt, ds, ss, bits, trunc; |
| 3448 | |
| 3449 | /* special delayed cast for char/short */ |
| 3450 | if (vtop->r & VT_MUSTCAST) |
| 3451 | force_charshort_cast(); |
| 3452 | |
| 3453 | /* bitfields first get cast to ints */ |
| 3454 | if (vtop->type.t & VT_BITFIELD) |
| 3455 | gv(RC_INT); |
| 3456 | |
| 3457 | dbt = type->t & (VT_BTYPE | VT_UNSIGNED); |
| 3458 | sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
| 3459 | if (sbt == VT_FUNC) |
| 3460 | sbt = VT_PTR; |
| 3461 | |
| 3462 | again: |
| 3463 | if (sbt != dbt) { |
| 3464 | sf = is_float(sbt); |
| 3465 | df = is_float(dbt); |
| 3466 | dbt_bt = dbt & VT_BTYPE; |
| 3467 | sbt_bt = sbt & VT_BTYPE; |
| 3468 | |
| 3469 | c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
| 3470 | #if !defined TCC_IS_NATIVE && !defined TCC_IS_NATIVE_387 |
| 3471 | c &= (dbt != VT_LDOUBLE) | !!nocode_wanted; |
| 3472 | #endif |
| 3473 | if (c) { |
| 3474 | /* constant case: we can do it now */ |
| 3475 | /* XXX: in ISOC, cannot do it if error in convert */ |
| 3476 | if (sbt == VT_FLOAT) |
| 3477 | vtop->c.ld = vtop->c.f; |
| 3478 | else if (sbt == VT_DOUBLE) |
| 3479 | vtop->c.ld = vtop->c.d; |
| 3480 | |
| 3481 | if (df) { |
| 3482 | if (sbt_bt == VT_LLONG) { |
| 3483 | if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63)) |
| 3484 | vtop->c.ld = vtop->c.i; |
| 3485 | else |
| 3486 | vtop->c.ld = -(long double)-vtop->c.i; |
| 3487 | } else if(!sf) { |
| 3488 | if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 31)) |
| 3489 | vtop->c.ld = (uint32_t)vtop->c.i; |
| 3490 | else |
| 3491 | vtop->c.ld = -(long double)-(uint32_t)vtop->c.i; |
| 3492 | } |
| 3493 | |
| 3494 | if (dbt == VT_FLOAT) |
| 3495 | vtop->c.f = (float)vtop->c.ld; |
| 3496 | else if (dbt == VT_DOUBLE) |
| 3497 | vtop->c.d = (double)vtop->c.ld; |
| 3498 | } else if (sf && dbt == VT_BOOL) { |
| 3499 | vtop->c.i = (vtop->c.ld != 0); |
| 3500 | } else { |
| 3501 | if(sf) |
| 3502 | vtop->c.i = vtop->c.ld; |
| 3503 | else if (sbt_bt == VT_LLONG || (PTR_SIZE == 8 && sbt == VT_PTR)) |
| 3504 | ; |
| 3505 | else if (sbt & VT_UNSIGNED) |
| 3506 | vtop->c.i = (uint32_t)vtop->c.i; |
| 3507 | else |
| 3508 | vtop->c.i = ((uint32_t)vtop->c.i | -(vtop->c.i & 0x80000000)); |
| 3509 | |
| 3510 | if (dbt_bt == VT_LLONG || (PTR_SIZE == 8 && dbt == VT_PTR)) |
| 3511 | ; |
| 3512 | else if (dbt == VT_BOOL) |
| 3513 | vtop->c.i = (vtop->c.i != 0); |
| 3514 | else { |
| 3515 | uint32_t m = dbt_bt == VT_BYTE ? 0xff : |
| 3516 | dbt_bt == VT_SHORT ? 0xffff : |
| 3517 | 0xffffffff; |
| 3518 | vtop->c.i &= m; |
| 3519 | if (!(dbt & VT_UNSIGNED)) |
| 3520 | vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1)); |
| 3521 | } |
| 3522 | } |
| 3523 | goto done; |
| 3524 | |
| 3525 | } else if (dbt == VT_BOOL |
| 3526 | && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) |
| 3527 | == (VT_CONST | VT_SYM)) { |
| 3528 | /* addresses are considered non-zero (see tcctest.c:sinit23) */ |
| 3529 | vtop->r = VT_CONST; |
| 3530 | vtop->c.i = 1; |
| 3531 | goto done; |
| 3532 | } |
| 3533 | |
| 3534 | /* cannot generate code for global or static initializers */ |
| 3535 | if (STATIC_DATA_WANTED) |
| 3536 | goto done; |
| 3537 | |
| 3538 | /* non constant case: generate code */ |
| 3539 | if (dbt == VT_BOOL) { |
| 3540 | gen_test_zero(TOK_NE); |
| 3541 | goto done; |
| 3542 | } |
| 3543 | |
| 3544 | if (sf || df) { |
| 3545 | if (sf && df) { |
| 3546 | /* convert from fp to fp */ |
| 3547 | gen_cvt_ftof(dbt); |
| 3548 | } else if (df) { |
| 3549 | /* convert int to fp */ |
| 3550 | gen_cvt_itof1(dbt); |
| 3551 | } else { |
| 3552 | /* convert fp to int */ |
| 3553 | sbt = dbt; |
| 3554 | if (dbt_bt != VT_LLONG && dbt_bt != VT_INT) |
| 3555 | sbt = VT_INT; |
| 3556 | gen_cvt_ftoi1(sbt); |
| 3557 | goto again; /* may need char/short cast */ |
| 3558 | } |
| 3559 | goto done; |
| 3560 | } |
| 3561 | |
| 3562 | ds = btype_size(dbt_bt); |
| 3563 | ss = btype_size(sbt_bt); |
| 3564 | if (ds == 0 || ss == 0) { |
| 3565 | if (dbt_bt == VT_VOID) |
| 3566 | goto done; |
| 3567 | cast_error(&vtop->type, type); |
| 3568 | } |
| 3569 | if (IS_ENUM(type->t) && type->ref->c < 0) |
| 3570 | tcc_error("cast to incomplete type" ); |
| 3571 | |
| 3572 | /* same size and no sign conversion needed */ |
| 3573 | if (ds == ss && ds >= 4) |
| 3574 | goto done; |
| 3575 | if (dbt_bt == VT_PTR || sbt_bt == VT_PTR) { |
| 3576 | tcc_warning("cast between pointer and integer of different size" ); |
| 3577 | if (sbt_bt == VT_PTR) { |
| 3578 | /* put integer type to allow logical operations below */ |
| 3579 | vtop->type.t = (PTR_SIZE == 8 ? VT_LLONG : VT_INT); |
| 3580 | } |
| 3581 | } |
| 3582 | |
| 3583 | /* processor allows { int a = 0, b = *(char*)&a; } |
| 3584 | That means that if we cast to less width, we can just |
| 3585 | change the type and read it still later. */ |
| 3586 | #define ALLOW_SUBTYPE_ACCESS 1 |
| 3587 | |
| 3588 | if (ALLOW_SUBTYPE_ACCESS && (vtop->r & VT_LVAL)) { |
| 3589 | /* value still in memory */ |
| 3590 | if (ds <= ss) |
| 3591 | goto done; |
| 3592 | /* ss <= 4 here */ |
| 3593 | if (ds <= 4 && !(dbt == (VT_SHORT | VT_UNSIGNED) && sbt == VT_BYTE)) { |
| 3594 | gv(RC_INT); |
| 3595 | goto done; /* no 64bit envolved */ |
| 3596 | } |
| 3597 | } |
| 3598 | gv(RC_INT); |
| 3599 | |
| 3600 | trunc = 0; |
| 3601 | #if PTR_SIZE == 4 |
| 3602 | if (ds == 8) { |
| 3603 | /* generate high word */ |
| 3604 | if (sbt & VT_UNSIGNED) { |
| 3605 | vpushi(0); |
| 3606 | gv(RC_INT); |
| 3607 | } else { |
| 3608 | gv_dup(); |
| 3609 | vpushi(31); |
| 3610 | gen_op(TOK_SAR); |
| 3611 | } |
| 3612 | lbuild(dbt); |
| 3613 | } else if (ss == 8) { |
| 3614 | /* from long long: just take low order word */ |
| 3615 | lexpand(); |
| 3616 | vpop(); |
| 3617 | } |
| 3618 | ss = 4; |
| 3619 | |
| 3620 | #elif PTR_SIZE == 8 |
| 3621 | if (ds == 8) { |
| 3622 | /* need to convert from 32bit to 64bit */ |
| 3623 | if (sbt & VT_UNSIGNED) { |
| 3624 | #if defined(TCC_TARGET_RISCV64) |
| 3625 | /* RISC-V keeps 32bit vals in registers sign-extended. |
| 3626 | So here we need a zero-extension. */ |
| 3627 | trunc = 32; |
| 3628 | #else |
| 3629 | goto done; |
| 3630 | #endif |
| 3631 | } else { |
| 3632 | gen_cvt_sxtw(); |
| 3633 | goto done; |
| 3634 | } |
| 3635 | ss = ds, ds = 4, dbt = sbt; |
| 3636 | } else if (ss == 8) { |
| 3637 | /* RISC-V keeps 32bit vals in registers sign-extended. |
| 3638 | So here we need a sign-extension for signed types and |
| 3639 | zero-extension. for unsigned types. */ |
| 3640 | #if !defined(TCC_TARGET_RISCV64) |
| 3641 | trunc = 32; /* zero upper 32 bits for non RISC-V targets */ |
| 3642 | #endif |
| 3643 | } else { |
| 3644 | ss = 4; |
| 3645 | } |
| 3646 | #endif |
| 3647 | |
| 3648 | if (ds >= ss) |
| 3649 | goto done; |
| 3650 | #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM64 |
| 3651 | if (ss == 4) { |
| 3652 | gen_cvt_csti(dbt); |
| 3653 | goto done; |
| 3654 | } |
| 3655 | #endif |
| 3656 | bits = (ss - ds) * 8; |
| 3657 | /* for unsigned, gen_op will convert SAR to SHR */ |
| 3658 | vtop->type.t = (ss == 8 ? VT_LLONG : VT_INT) | (dbt & VT_UNSIGNED); |
| 3659 | vpushi(bits); |
| 3660 | gen_op(TOK_SHL); |
| 3661 | vpushi(bits - trunc); |
| 3662 | gen_op(TOK_SAR); |
| 3663 | vpushi(trunc); |
| 3664 | gen_op(TOK_SHR); |
| 3665 | } |
| 3666 | done: |
| 3667 | vtop->type = *type; |
| 3668 | vtop->type.t &= ~ ( VT_CONSTANT | VT_VOLATILE | VT_ARRAY ); |
| 3669 | } |
| 3670 | |
| 3671 | /* return type size as known at compile time. Put alignment at 'a' */ |
| 3672 | ST_FUNC int type_size(CType *type, int *a) |
| 3673 | { |
| 3674 | Sym *s; |
| 3675 | int bt; |
| 3676 | |
| 3677 | bt = type->t & VT_BTYPE; |
| 3678 | if (bt == VT_STRUCT) { |
| 3679 | /* struct/union */ |
| 3680 | s = type->ref; |
| 3681 | *a = s->r; |
| 3682 | return s->c; |
| 3683 | } else if (bt == VT_PTR) { |
| 3684 | if (type->t & VT_ARRAY) { |
| 3685 | int ts; |
| 3686 | |
| 3687 | s = type->ref; |
| 3688 | ts = type_size(&s->type, a); |
| 3689 | |
| 3690 | if (ts < 0 && s->c < 0) |
| 3691 | ts = -ts; |
| 3692 | |
| 3693 | return ts * s->c; |
| 3694 | } else { |
| 3695 | *a = PTR_SIZE; |
| 3696 | return PTR_SIZE; |
| 3697 | } |
| 3698 | } else if (IS_ENUM(type->t) && type->ref->c < 0) { |
| 3699 | return -1; /* incomplete enum */ |
| 3700 | } else if (bt == VT_LDOUBLE) { |
| 3701 | *a = LDOUBLE_ALIGN; |
| 3702 | return LDOUBLE_SIZE; |
| 3703 | } else if (bt == VT_DOUBLE || bt == VT_LLONG) { |
| 3704 | #ifdef TCC_TARGET_I386 |
| 3705 | #ifdef TCC_TARGET_PE |
| 3706 | *a = 8; |
| 3707 | #else |
| 3708 | *a = 4; |
| 3709 | #endif |
| 3710 | #elif defined(TCC_TARGET_ARM) |
| 3711 | #ifdef TCC_ARM_EABI |
| 3712 | *a = 8; |
| 3713 | #else |
| 3714 | *a = 4; |
| 3715 | #endif |
| 3716 | #else |
| 3717 | *a = 8; |
| 3718 | #endif |
| 3719 | return 8; |
| 3720 | } else if (bt == VT_INT || bt == VT_FLOAT) { |
| 3721 | *a = 4; |
| 3722 | return 4; |
| 3723 | } else if (bt == VT_SHORT) { |
| 3724 | *a = 2; |
| 3725 | return 2; |
| 3726 | } else if (bt == VT_QLONG || bt == VT_QFLOAT) { |
| 3727 | *a = 8; |
| 3728 | return 16; |
| 3729 | } else { |
| 3730 | /* char, void, function, _Bool */ |
| 3731 | *a = 1; |
| 3732 | return 1; |
| 3733 | } |
| 3734 | } |
| 3735 | |
| 3736 | /* push type size as known at runtime time on top of value stack. Put |
| 3737 | alignment at 'a' */ |
| 3738 | ST_FUNC void vla_runtime_type_size(CType *type, int *a) |
| 3739 | { |
| 3740 | if (type->t & VT_VLA) { |
| 3741 | type_size(&type->ref->type, a); |
| 3742 | vset(&int_type, VT_LOCAL|VT_LVAL, type->ref->c); |
| 3743 | } else { |
| 3744 | vpushi(type_size(type, a)); |
| 3745 | } |
| 3746 | } |
| 3747 | |
| 3748 | /* return the pointed type of t */ |
| 3749 | static inline CType *pointed_type(CType *type) |
| 3750 | { |
| 3751 | return &type->ref->type; |
| 3752 | } |
| 3753 | |
| 3754 | /* modify type so that its it is a pointer to type. */ |
| 3755 | ST_FUNC void mk_pointer(CType *type) |
| 3756 | { |
| 3757 | Sym *s; |
| 3758 | s = sym_push(SYM_FIELD, type, 0, -1); |
| 3759 | type->t = VT_PTR | (type->t & VT_STORAGE); |
| 3760 | type->ref = s; |
| 3761 | } |
| 3762 | |
| 3763 | /* return true if type1 and type2 are exactly the same (including |
| 3764 | qualifiers). |
| 3765 | */ |
| 3766 | static int is_compatible_types(CType *type1, CType *type2) |
| 3767 | { |
| 3768 | return compare_types(type1,type2,0); |
| 3769 | } |
| 3770 | |
| 3771 | /* return true if type1 and type2 are the same (ignoring qualifiers). |
| 3772 | */ |
| 3773 | static int is_compatible_unqualified_types(CType *type1, CType *type2) |
| 3774 | { |
| 3775 | return compare_types(type1,type2,1); |
| 3776 | } |
| 3777 | |
| 3778 | static void cast_error(CType *st, CType *dt) |
| 3779 | { |
| 3780 | type_incompatibility_error(st, dt, "cannot convert '%s' to '%s'" ); |
| 3781 | } |
| 3782 | |
| 3783 | /* verify type compatibility to store vtop in 'dt' type */ |
| 3784 | static void verify_assign_cast(CType *dt) |
| 3785 | { |
| 3786 | CType *st, *type1, *type2; |
| 3787 | int dbt, sbt, qualwarn, lvl; |
| 3788 | |
| 3789 | st = &vtop->type; /* source type */ |
| 3790 | dbt = dt->t & VT_BTYPE; |
| 3791 | sbt = st->t & VT_BTYPE; |
| 3792 | if (dt->t & VT_CONSTANT) |
| 3793 | tcc_warning("assignment of read-only location" ); |
| 3794 | switch(dbt) { |
| 3795 | case VT_VOID: |
| 3796 | if (sbt != dbt) |
| 3797 | tcc_error("assignment to void expression" ); |
| 3798 | break; |
| 3799 | case VT_PTR: |
| 3800 | /* special cases for pointers */ |
| 3801 | /* '0' can also be a pointer */ |
| 3802 | if (is_null_pointer(vtop)) |
| 3803 | break; |
| 3804 | /* accept implicit pointer to integer cast with warning */ |
| 3805 | if (is_integer_btype(sbt)) { |
| 3806 | tcc_warning("assignment makes pointer from integer without a cast" ); |
| 3807 | break; |
| 3808 | } |
| 3809 | type1 = pointed_type(dt); |
| 3810 | if (sbt == VT_PTR) |
| 3811 | type2 = pointed_type(st); |
| 3812 | else if (sbt == VT_FUNC) |
| 3813 | type2 = st; /* a function is implicitly a function pointer */ |
| 3814 | else |
| 3815 | goto error; |
| 3816 | if (is_compatible_types(type1, type2)) |
| 3817 | break; |
| 3818 | for (qualwarn = lvl = 0;; ++lvl) { |
| 3819 | if (((type2->t & VT_CONSTANT) && !(type1->t & VT_CONSTANT)) || |
| 3820 | ((type2->t & VT_VOLATILE) && !(type1->t & VT_VOLATILE))) |
| 3821 | qualwarn = 1; |
| 3822 | dbt = type1->t & (VT_BTYPE|VT_LONG); |
| 3823 | sbt = type2->t & (VT_BTYPE|VT_LONG); |
| 3824 | if (dbt != VT_PTR || sbt != VT_PTR) |
| 3825 | break; |
| 3826 | type1 = pointed_type(type1); |
| 3827 | type2 = pointed_type(type2); |
| 3828 | } |
| 3829 | if (!is_compatible_unqualified_types(type1, type2)) { |
| 3830 | if ((dbt == VT_VOID || sbt == VT_VOID) && lvl == 0) { |
| 3831 | /* void * can match anything */ |
| 3832 | } else if (dbt == sbt |
| 3833 | && is_integer_btype(sbt & VT_BTYPE) |
| 3834 | && IS_ENUM(type1->t) + IS_ENUM(type2->t) |
| 3835 | + !!((type1->t ^ type2->t) & VT_UNSIGNED) < 2) { |
| 3836 | /* Like GCC don't warn by default for merely changes |
| 3837 | in pointer target signedness. Do warn for different |
| 3838 | base types, though, in particular for unsigned enums |
| 3839 | and signed int targets. */ |
| 3840 | } else { |
| 3841 | tcc_warning("assignment from incompatible pointer type" ); |
| 3842 | break; |
| 3843 | } |
| 3844 | } |
| 3845 | if (qualwarn) |
| 3846 | tcc_warning("assignment discards qualifiers from pointer target type" ); |
| 3847 | break; |
| 3848 | case VT_BYTE: |
| 3849 | case VT_SHORT: |
| 3850 | case VT_INT: |
| 3851 | case VT_LLONG: |
| 3852 | if (sbt == VT_PTR || sbt == VT_FUNC) { |
| 3853 | tcc_warning("assignment makes integer from pointer without a cast" ); |
| 3854 | } else if (sbt == VT_STRUCT) { |
| 3855 | goto case_VT_STRUCT; |
| 3856 | } |
| 3857 | /* XXX: more tests */ |
| 3858 | break; |
| 3859 | case VT_STRUCT: |
| 3860 | case_VT_STRUCT: |
| 3861 | if (!is_compatible_unqualified_types(dt, st)) { |
| 3862 | error: |
| 3863 | cast_error(st, dt); |
| 3864 | } |
| 3865 | break; |
| 3866 | } |
| 3867 | } |
| 3868 | |
| 3869 | static void gen_assign_cast(CType *dt) |
| 3870 | { |
| 3871 | verify_assign_cast(dt); |
| 3872 | gen_cast(dt); |
| 3873 | } |
| 3874 | |
| 3875 | /* store vtop in lvalue pushed on stack */ |
| 3876 | ST_FUNC void vstore(void) |
| 3877 | { |
| 3878 | int sbt, dbt, ft, r, size, align, bit_size, bit_pos, delayed_cast; |
| 3879 | |
| 3880 | ft = vtop[-1].type.t; |
| 3881 | sbt = vtop->type.t & VT_BTYPE; |
| 3882 | dbt = ft & VT_BTYPE; |
| 3883 | |
| 3884 | verify_assign_cast(&vtop[-1].type); |
| 3885 | |
| 3886 | if (sbt == VT_STRUCT) { |
| 3887 | /* if structure, only generate pointer */ |
| 3888 | /* structure assignment : generate memcpy */ |
| 3889 | /* XXX: optimize if small size */ |
| 3890 | size = type_size(&vtop->type, &align); |
| 3891 | |
| 3892 | /* destination */ |
| 3893 | vswap(); |
| 3894 | #ifdef CONFIG_TCC_BCHECK |
| 3895 | if (vtop->r & VT_MUSTBOUND) |
| 3896 | gbound(); /* check would be wrong after gaddrof() */ |
| 3897 | #endif |
| 3898 | vtop->type.t = VT_PTR; |
| 3899 | gaddrof(); |
| 3900 | |
| 3901 | /* address of memcpy() */ |
| 3902 | #ifdef TCC_ARM_EABI |
| 3903 | if(!(align & 7)) |
| 3904 | vpush_global_sym(&func_old_type, TOK_memmove8); |
| 3905 | else if(!(align & 3)) |
| 3906 | vpush_global_sym(&func_old_type, TOK_memmove4); |
| 3907 | else |
| 3908 | #endif |
| 3909 | /* Use memmove, rather than memcpy, as dest and src may be same: */ |
| 3910 | vpush_global_sym(&func_old_type, TOK_memmove); |
| 3911 | |
| 3912 | vswap(); |
| 3913 | /* source */ |
| 3914 | vpushv(vtop - 2); |
| 3915 | #ifdef CONFIG_TCC_BCHECK |
| 3916 | if (vtop->r & VT_MUSTBOUND) |
| 3917 | gbound(); |
| 3918 | #endif |
| 3919 | vtop->type.t = VT_PTR; |
| 3920 | gaddrof(); |
| 3921 | /* type size */ |
| 3922 | vpushi(size); |
| 3923 | gfunc_call(3); |
| 3924 | /* leave source on stack */ |
| 3925 | |
| 3926 | } else if (ft & VT_BITFIELD) { |
| 3927 | /* bitfield store handling */ |
| 3928 | |
| 3929 | /* save lvalue as expression result (example: s.b = s.a = n;) */ |
| 3930 | vdup(), vtop[-1] = vtop[-2]; |
| 3931 | |
| 3932 | bit_pos = BIT_POS(ft); |
| 3933 | bit_size = BIT_SIZE(ft); |
| 3934 | /* remove bit field info to avoid loops */ |
| 3935 | vtop[-1].type.t = ft & ~VT_STRUCT_MASK; |
| 3936 | |
| 3937 | if (dbt == VT_BOOL) { |
| 3938 | gen_cast(&vtop[-1].type); |
| 3939 | vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); |
| 3940 | } |
| 3941 | r = adjust_bf(vtop - 1, bit_pos, bit_size); |
| 3942 | if (dbt != VT_BOOL) { |
| 3943 | gen_cast(&vtop[-1].type); |
| 3944 | dbt = vtop[-1].type.t & VT_BTYPE; |
| 3945 | } |
| 3946 | if (r == VT_STRUCT) { |
| 3947 | store_packed_bf(bit_pos, bit_size); |
| 3948 | } else { |
| 3949 | unsigned long long mask = (1ULL << bit_size) - 1; |
| 3950 | if (dbt != VT_BOOL) { |
| 3951 | /* mask source */ |
| 3952 | if (dbt == VT_LLONG) |
| 3953 | vpushll(mask); |
| 3954 | else |
| 3955 | vpushi((unsigned)mask); |
| 3956 | gen_op('&'); |
| 3957 | } |
| 3958 | /* shift source */ |
| 3959 | vpushi(bit_pos); |
| 3960 | gen_op(TOK_SHL); |
| 3961 | vswap(); |
| 3962 | /* duplicate destination */ |
| 3963 | vdup(); |
| 3964 | vrott(3); |
| 3965 | /* load destination, mask and or with source */ |
| 3966 | if (dbt == VT_LLONG) |
| 3967 | vpushll(~(mask << bit_pos)); |
| 3968 | else |
| 3969 | vpushi(~((unsigned)mask << bit_pos)); |
| 3970 | gen_op('&'); |
| 3971 | gen_op('|'); |
| 3972 | /* store result */ |
| 3973 | vstore(); |
| 3974 | /* ... and discard */ |
| 3975 | vpop(); |
| 3976 | } |
| 3977 | } else if (dbt == VT_VOID) { |
| 3978 | --vtop; |
| 3979 | } else { |
| 3980 | /* optimize char/short casts */ |
| 3981 | delayed_cast = 0; |
| 3982 | if ((dbt == VT_BYTE || dbt == VT_SHORT) |
| 3983 | && is_integer_btype(sbt) |
| 3984 | ) { |
| 3985 | if ((vtop->r & VT_MUSTCAST) |
| 3986 | && btype_size(dbt) > btype_size(sbt) |
| 3987 | ) |
| 3988 | force_charshort_cast(); |
| 3989 | delayed_cast = 1; |
| 3990 | } else { |
| 3991 | gen_cast(&vtop[-1].type); |
| 3992 | } |
| 3993 | |
| 3994 | #ifdef CONFIG_TCC_BCHECK |
| 3995 | /* bound check case */ |
| 3996 | if (vtop[-1].r & VT_MUSTBOUND) { |
| 3997 | vswap(); |
| 3998 | gbound(); |
| 3999 | vswap(); |
| 4000 | } |
| 4001 | #endif |
| 4002 | gv(RC_TYPE(dbt)); /* generate value */ |
| 4003 | |
| 4004 | if (delayed_cast) { |
| 4005 | vtop->r |= BFVAL(VT_MUSTCAST, (sbt == VT_LLONG) + 1); |
| 4006 | //tcc_warning("deley cast %x -> %x", sbt, dbt); |
| 4007 | vtop->type.t = ft & VT_TYPE; |
| 4008 | } |
| 4009 | |
| 4010 | /* if lvalue was saved on stack, must read it */ |
| 4011 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
| 4012 | SValue sv; |
| 4013 | r = get_reg(RC_INT); |
| 4014 | sv.type.t = VT_PTRDIFF_T; |
| 4015 | sv.r = VT_LOCAL | VT_LVAL; |
| 4016 | sv.c.i = vtop[-1].c.i; |
| 4017 | load(r, &sv); |
| 4018 | vtop[-1].r = r | VT_LVAL; |
| 4019 | } |
| 4020 | |
| 4021 | r = vtop->r & VT_VALMASK; |
| 4022 | /* two word case handling : |
| 4023 | store second register at word + 4 (or +8 for x86-64) */ |
| 4024 | if (USING_TWO_WORDS(dbt)) { |
| 4025 | int load_type = (dbt == VT_QFLOAT) ? VT_DOUBLE : VT_PTRDIFF_T; |
| 4026 | vtop[-1].type.t = load_type; |
| 4027 | store(r, vtop - 1); |
| 4028 | vswap(); |
| 4029 | /* convert to int to increment easily */ |
| 4030 | vtop->type.t = VT_PTRDIFF_T; |
| 4031 | gaddrof(); |
| 4032 | vpushs(PTR_SIZE); |
| 4033 | gen_op('+'); |
| 4034 | vtop->r |= VT_LVAL; |
| 4035 | vswap(); |
| 4036 | vtop[-1].type.t = load_type; |
| 4037 | /* XXX: it works because r2 is spilled last ! */ |
| 4038 | store(vtop->r2, vtop - 1); |
| 4039 | } else { |
| 4040 | /* single word */ |
| 4041 | store(r, vtop - 1); |
| 4042 | } |
| 4043 | vswap(); |
| 4044 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
| 4045 | } |
| 4046 | } |
| 4047 | |
| 4048 | /* post defines POST/PRE add. c is the token ++ or -- */ |
| 4049 | ST_FUNC void inc(int post, int c) |
| 4050 | { |
| 4051 | test_lvalue(); |
| 4052 | vdup(); /* save lvalue */ |
| 4053 | if (post) { |
| 4054 | gv_dup(); /* duplicate value */ |
| 4055 | vrotb(3); |
| 4056 | vrotb(3); |
| 4057 | } |
| 4058 | /* add constant */ |
| 4059 | vpushi(c - TOK_MID); |
| 4060 | gen_op('+'); |
| 4061 | vstore(); /* store value */ |
| 4062 | if (post) |
| 4063 | vpop(); /* if post op, return saved value */ |
| 4064 | } |
| 4065 | |
| 4066 | ST_FUNC void parse_mult_str (CString *astr, const char *msg) |
| 4067 | { |
| 4068 | /* read the string */ |
| 4069 | if (tok != TOK_STR) |
| 4070 | expect(msg); |
| 4071 | cstr_new(astr); |
| 4072 | while (tok == TOK_STR) { |
| 4073 | /* XXX: add \0 handling too ? */ |
| 4074 | cstr_cat(astr, tokc.str.data, -1); |
| 4075 | next(); |
| 4076 | } |
| 4077 | cstr_ccat(astr, '\0'); |
| 4078 | } |
| 4079 | |
| 4080 | /* If I is >= 1 and a power of two, returns log2(i)+1. |
| 4081 | If I is 0 returns 0. */ |
| 4082 | ST_FUNC int exact_log2p1(int i) |
| 4083 | { |
| 4084 | int ret; |
| 4085 | if (!i) |
| 4086 | return 0; |
| 4087 | for (ret = 1; i >= 1 << 8; ret += 8) |
| 4088 | i >>= 8; |
| 4089 | if (i >= 1 << 4) |
| 4090 | ret += 4, i >>= 4; |
| 4091 | if (i >= 1 << 2) |
| 4092 | ret += 2, i >>= 2; |
| 4093 | if (i >= 1 << 1) |
| 4094 | ret++; |
| 4095 | return ret; |
| 4096 | } |
| 4097 | |
| 4098 | /* Parse __attribute__((...)) GNUC extension. */ |
| 4099 | static void parse_attribute(AttributeDef *ad) |
| 4100 | { |
| 4101 | int t, n; |
| 4102 | CString astr; |
| 4103 | |
| 4104 | redo: |
| 4105 | if (tok != TOK_ATTRIBUTE1 && tok != TOK_ATTRIBUTE2) |
| 4106 | return; |
| 4107 | next(); |
| 4108 | skip('('); |
| 4109 | skip('('); |
| 4110 | while (tok != ')') { |
| 4111 | if (tok < TOK_IDENT) |
| 4112 | expect("attribute name" ); |
| 4113 | t = tok; |
| 4114 | next(); |
| 4115 | switch(t) { |
| 4116 | case TOK_CLEANUP1: |
| 4117 | case TOK_CLEANUP2: |
| 4118 | { |
| 4119 | Sym *s; |
| 4120 | |
| 4121 | skip('('); |
| 4122 | s = sym_find(tok); |
| 4123 | if (!s) { |
| 4124 | tcc_warning("implicit declaration of function '%s'" , |
| 4125 | get_tok_str(tok, &tokc)); |
| 4126 | s = external_global_sym(tok, &func_old_type); |
| 4127 | } else if ((s->type.t & VT_BTYPE) != VT_FUNC) |
| 4128 | tcc_error("'%s' is not declared as function" , get_tok_str(tok, &tokc)); |
| 4129 | ad->cleanup_func = s; |
| 4130 | next(); |
| 4131 | skip(')'); |
| 4132 | break; |
| 4133 | } |
| 4134 | case TOK_CONSTRUCTOR1: |
| 4135 | case TOK_CONSTRUCTOR2: |
| 4136 | ad->f.func_ctor = 1; |
| 4137 | break; |
| 4138 | case TOK_DESTRUCTOR1: |
| 4139 | case TOK_DESTRUCTOR2: |
| 4140 | ad->f.func_dtor = 1; |
| 4141 | break; |
| 4142 | case TOK_ALWAYS_INLINE1: |
| 4143 | case TOK_ALWAYS_INLINE2: |
| 4144 | ad->f.func_alwinl = 1; |
| 4145 | break; |
| 4146 | case TOK_SECTION1: |
| 4147 | case TOK_SECTION2: |
| 4148 | skip('('); |
| 4149 | parse_mult_str(&astr, "section name" ); |
| 4150 | ad->section = find_section(tcc_state, (char *)astr.data); |
| 4151 | skip(')'); |
| 4152 | cstr_free(&astr); |
| 4153 | break; |
| 4154 | case TOK_ALIAS1: |
| 4155 | case TOK_ALIAS2: |
| 4156 | skip('('); |
| 4157 | parse_mult_str(&astr, "alias(\"target\")" ); |
| 4158 | ad->alias_target = /* save string as token, for later */ |
| 4159 | tok_alloc((char*)astr.data, astr.size-1)->tok; |
| 4160 | skip(')'); |
| 4161 | cstr_free(&astr); |
| 4162 | break; |
| 4163 | case TOK_VISIBILITY1: |
| 4164 | case TOK_VISIBILITY2: |
| 4165 | skip('('); |
| 4166 | parse_mult_str(&astr, |
| 4167 | "visibility(\"default|hidden|internal|protected\")" ); |
| 4168 | if (!strcmp (astr.data, "default" )) |
| 4169 | ad->a.visibility = STV_DEFAULT; |
| 4170 | else if (!strcmp (astr.data, "hidden" )) |
| 4171 | ad->a.visibility = STV_HIDDEN; |
| 4172 | else if (!strcmp (astr.data, "internal" )) |
| 4173 | ad->a.visibility = STV_INTERNAL; |
| 4174 | else if (!strcmp (astr.data, "protected" )) |
| 4175 | ad->a.visibility = STV_PROTECTED; |
| 4176 | else |
| 4177 | expect("visibility(\"default|hidden|internal|protected\")" ); |
| 4178 | skip(')'); |
| 4179 | cstr_free(&astr); |
| 4180 | break; |
| 4181 | case TOK_ALIGNED1: |
| 4182 | case TOK_ALIGNED2: |
| 4183 | if (tok == '(') { |
| 4184 | next(); |
| 4185 | n = expr_const(); |
| 4186 | if (n <= 0 || (n & (n - 1)) != 0) |
| 4187 | tcc_error("alignment must be a positive power of two" ); |
| 4188 | skip(')'); |
| 4189 | } else { |
| 4190 | n = MAX_ALIGN; |
| 4191 | } |
| 4192 | ad->a.aligned = exact_log2p1(n); |
| 4193 | if (n != 1 << (ad->a.aligned - 1)) |
| 4194 | tcc_error("alignment of %d is larger than implemented" , n); |
| 4195 | break; |
| 4196 | case TOK_PACKED1: |
| 4197 | case TOK_PACKED2: |
| 4198 | ad->a.packed = 1; |
| 4199 | break; |
| 4200 | case TOK_WEAK1: |
| 4201 | case TOK_WEAK2: |
| 4202 | ad->a.weak = 1; |
| 4203 | break; |
| 4204 | case TOK_UNUSED1: |
| 4205 | case TOK_UNUSED2: |
| 4206 | /* currently, no need to handle it because tcc does not |
| 4207 | track unused objects */ |
| 4208 | break; |
| 4209 | case TOK_NORETURN1: |
| 4210 | case TOK_NORETURN2: |
| 4211 | ad->f.func_noreturn = 1; |
| 4212 | break; |
| 4213 | case TOK_CDECL1: |
| 4214 | case TOK_CDECL2: |
| 4215 | case TOK_CDECL3: |
| 4216 | ad->f.func_call = FUNC_CDECL; |
| 4217 | break; |
| 4218 | case TOK_STDCALL1: |
| 4219 | case TOK_STDCALL2: |
| 4220 | case TOK_STDCALL3: |
| 4221 | ad->f.func_call = FUNC_STDCALL; |
| 4222 | break; |
| 4223 | #ifdef TCC_TARGET_I386 |
| 4224 | case TOK_REGPARM1: |
| 4225 | case TOK_REGPARM2: |
| 4226 | skip('('); |
| 4227 | n = expr_const(); |
| 4228 | if (n > 3) |
| 4229 | n = 3; |
| 4230 | else if (n < 0) |
| 4231 | n = 0; |
| 4232 | if (n > 0) |
| 4233 | ad->f.func_call = FUNC_FASTCALL1 + n - 1; |
| 4234 | skip(')'); |
| 4235 | break; |
| 4236 | case TOK_FASTCALL1: |
| 4237 | case TOK_FASTCALL2: |
| 4238 | case TOK_FASTCALL3: |
| 4239 | ad->f.func_call = FUNC_FASTCALLW; |
| 4240 | break; |
| 4241 | #endif |
| 4242 | case TOK_MODE: |
| 4243 | skip('('); |
| 4244 | switch(tok) { |
| 4245 | case TOK_MODE_DI: |
| 4246 | ad->attr_mode = VT_LLONG + 1; |
| 4247 | break; |
| 4248 | case TOK_MODE_QI: |
| 4249 | ad->attr_mode = VT_BYTE + 1; |
| 4250 | break; |
| 4251 | case TOK_MODE_HI: |
| 4252 | ad->attr_mode = VT_SHORT + 1; |
| 4253 | break; |
| 4254 | case TOK_MODE_SI: |
| 4255 | case TOK_MODE_word: |
| 4256 | ad->attr_mode = VT_INT + 1; |
| 4257 | break; |
| 4258 | default: |
| 4259 | tcc_warning("__mode__(%s) not supported\n" , get_tok_str(tok, NULL)); |
| 4260 | break; |
| 4261 | } |
| 4262 | next(); |
| 4263 | skip(')'); |
| 4264 | break; |
| 4265 | case TOK_DLLEXPORT: |
| 4266 | ad->a.dllexport = 1; |
| 4267 | break; |
| 4268 | case TOK_NODECORATE: |
| 4269 | ad->a.nodecorate = 1; |
| 4270 | break; |
| 4271 | case TOK_DLLIMPORT: |
| 4272 | ad->a.dllimport = 1; |
| 4273 | break; |
| 4274 | default: |
| 4275 | if (tcc_state->warn_unsupported) |
| 4276 | tcc_warning("'%s' attribute ignored" , get_tok_str(t, NULL)); |
| 4277 | /* skip parameters */ |
| 4278 | if (tok == '(') { |
| 4279 | int parenthesis = 0; |
| 4280 | do { |
| 4281 | if (tok == '(') |
| 4282 | parenthesis++; |
| 4283 | else if (tok == ')') |
| 4284 | parenthesis--; |
| 4285 | next(); |
| 4286 | } while (parenthesis && tok != -1); |
| 4287 | } |
| 4288 | break; |
| 4289 | } |
| 4290 | if (tok != ',') |
| 4291 | break; |
| 4292 | next(); |
| 4293 | } |
| 4294 | skip(')'); |
| 4295 | skip(')'); |
| 4296 | goto redo; |
| 4297 | } |
| 4298 | |
| 4299 | static Sym * find_field (CType *type, int v, int *cumofs) |
| 4300 | { |
| 4301 | Sym *s = type->ref; |
| 4302 | v |= SYM_FIELD; |
| 4303 | while ((s = s->next) != NULL) { |
| 4304 | if ((s->v & SYM_FIELD) && |
| 4305 | (s->type.t & VT_BTYPE) == VT_STRUCT && |
| 4306 | (s->v & ~SYM_FIELD) >= SYM_FIRST_ANOM) { |
| 4307 | Sym *ret = find_field (&s->type, v, cumofs); |
| 4308 | if (ret) { |
| 4309 | *cumofs += s->c; |
| 4310 | return ret; |
| 4311 | } |
| 4312 | } |
| 4313 | if (s->v == v) |
| 4314 | break; |
| 4315 | } |
| 4316 | return s; |
| 4317 | } |
| 4318 | |
| 4319 | static void struct_layout(CType *type, AttributeDef *ad) |
| 4320 | { |
| 4321 | int size, align, maxalign, offset, c, bit_pos, bit_size; |
| 4322 | int packed, a, bt, prevbt, prev_bit_size; |
| 4323 | int pcc = !tcc_state->ms_bitfields; |
| 4324 | int pragma_pack = *tcc_state->pack_stack_ptr; |
| 4325 | Sym *f; |
| 4326 | |
| 4327 | maxalign = 1; |
| 4328 | offset = 0; |
| 4329 | c = 0; |
| 4330 | bit_pos = 0; |
| 4331 | prevbt = VT_STRUCT; /* make it never match */ |
| 4332 | prev_bit_size = 0; |
| 4333 | |
| 4334 | //#define BF_DEBUG |
| 4335 | |
| 4336 | for (f = type->ref->next; f; f = f->next) { |
| 4337 | if (f->type.t & VT_BITFIELD) |
| 4338 | bit_size = BIT_SIZE(f->type.t); |
| 4339 | else |
| 4340 | bit_size = -1; |
| 4341 | size = type_size(&f->type, &align); |
| 4342 | a = f->a.aligned ? 1 << (f->a.aligned - 1) : 0; |
| 4343 | packed = 0; |
| 4344 | |
| 4345 | if (pcc && bit_size == 0) { |
| 4346 | /* in pcc mode, packing does not affect zero-width bitfields */ |
| 4347 | |
| 4348 | } else { |
| 4349 | /* in pcc mode, attribute packed overrides if set. */ |
| 4350 | if (pcc && (f->a.packed || ad->a.packed)) |
| 4351 | align = packed = 1; |
| 4352 | |
| 4353 | /* pragma pack overrides align if lesser and packs bitfields always */ |
| 4354 | if (pragma_pack) { |
| 4355 | packed = 1; |
| 4356 | if (pragma_pack < align) |
| 4357 | align = pragma_pack; |
| 4358 | /* in pcc mode pragma pack also overrides individual align */ |
| 4359 | if (pcc && pragma_pack < a) |
| 4360 | a = 0; |
| 4361 | } |
| 4362 | } |
| 4363 | /* some individual align was specified */ |
| 4364 | if (a) |
| 4365 | align = a; |
| 4366 | |
| 4367 | if (type->ref->type.t == VT_UNION) { |
| 4368 | if (pcc && bit_size >= 0) |
| 4369 | size = (bit_size + 7) >> 3; |
| 4370 | offset = 0; |
| 4371 | if (size > c) |
| 4372 | c = size; |
| 4373 | |
| 4374 | } else if (bit_size < 0) { |
| 4375 | if (pcc) |
| 4376 | c += (bit_pos + 7) >> 3; |
| 4377 | c = (c + align - 1) & -align; |
| 4378 | offset = c; |
| 4379 | if (size > 0) |
| 4380 | c += size; |
| 4381 | bit_pos = 0; |
| 4382 | prevbt = VT_STRUCT; |
| 4383 | prev_bit_size = 0; |
| 4384 | |
| 4385 | } else { |
| 4386 | /* A bit-field. Layout is more complicated. There are two |
| 4387 | options: PCC (GCC) compatible and MS compatible */ |
| 4388 | if (pcc) { |
| 4389 | /* In PCC layout a bit-field is placed adjacent to the |
| 4390 | preceding bit-fields, except if: |
| 4391 | - it has zero-width |
| 4392 | - an individual alignment was given |
| 4393 | - it would overflow its base type container and |
| 4394 | there is no packing */ |
| 4395 | if (bit_size == 0) { |
| 4396 | new_field: |
| 4397 | c = (c + ((bit_pos + 7) >> 3) + align - 1) & -align; |
| 4398 | bit_pos = 0; |
| 4399 | } else if (f->a.aligned) { |
| 4400 | goto new_field; |
| 4401 | } else if (!packed) { |
| 4402 | int a8 = align * 8; |
| 4403 | int ofs = ((c * 8 + bit_pos) % a8 + bit_size + a8 - 1) / a8; |
| 4404 | if (ofs > size / align) |
| 4405 | goto new_field; |
| 4406 | } |
| 4407 | |
| 4408 | /* in pcc mode, long long bitfields have type int if they fit */ |
| 4409 | if (size == 8 && bit_size <= 32) |
| 4410 | f->type.t = (f->type.t & ~VT_BTYPE) | VT_INT, size = 4; |
| 4411 | |
| 4412 | while (bit_pos >= align * 8) |
| 4413 | c += align, bit_pos -= align * 8; |
| 4414 | offset = c; |
| 4415 | |
| 4416 | /* In PCC layout named bit-fields influence the alignment |
| 4417 | of the containing struct using the base types alignment, |
| 4418 | except for packed fields (which here have correct align). */ |
| 4419 | if (f->v & SYM_FIRST_ANOM |
| 4420 | // && bit_size // ??? gcc on ARM/rpi does that |
| 4421 | ) |
| 4422 | align = 1; |
| 4423 | |
| 4424 | } else { |
| 4425 | bt = f->type.t & VT_BTYPE; |
| 4426 | if ((bit_pos + bit_size > size * 8) |
| 4427 | || (bit_size > 0) == (bt != prevbt) |
| 4428 | ) { |
| 4429 | c = (c + align - 1) & -align; |
| 4430 | offset = c; |
| 4431 | bit_pos = 0; |
| 4432 | /* In MS bitfield mode a bit-field run always uses |
| 4433 | at least as many bits as the underlying type. |
| 4434 | To start a new run it's also required that this |
| 4435 | or the last bit-field had non-zero width. */ |
| 4436 | if (bit_size || prev_bit_size) |
| 4437 | c += size; |
| 4438 | } |
| 4439 | /* In MS layout the records alignment is normally |
| 4440 | influenced by the field, except for a zero-width |
| 4441 | field at the start of a run (but by further zero-width |
| 4442 | fields it is again). */ |
| 4443 | if (bit_size == 0 && prevbt != bt) |
| 4444 | align = 1; |
| 4445 | prevbt = bt; |
| 4446 | prev_bit_size = bit_size; |
| 4447 | } |
| 4448 | |
| 4449 | f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) |
| 4450 | | (bit_pos << VT_STRUCT_SHIFT); |
| 4451 | bit_pos += bit_size; |
| 4452 | } |
| 4453 | if (align > maxalign) |
| 4454 | maxalign = align; |
| 4455 | |
| 4456 | #ifdef BF_DEBUG |
| 4457 | printf("set field %s offset %-2d size %-2d align %-2d" , |
| 4458 | get_tok_str(f->v & ~SYM_FIELD, NULL), offset, size, align); |
| 4459 | if (f->type.t & VT_BITFIELD) { |
| 4460 | printf(" pos %-2d bits %-2d" , |
| 4461 | BIT_POS(f->type.t), |
| 4462 | BIT_SIZE(f->type.t) |
| 4463 | ); |
| 4464 | } |
| 4465 | printf("\n" ); |
| 4466 | #endif |
| 4467 | |
| 4468 | f->c = offset; |
| 4469 | f->r = 0; |
| 4470 | } |
| 4471 | |
| 4472 | if (pcc) |
| 4473 | c += (bit_pos + 7) >> 3; |
| 4474 | |
| 4475 | /* store size and alignment */ |
| 4476 | a = bt = ad->a.aligned ? 1 << (ad->a.aligned - 1) : 1; |
| 4477 | if (a < maxalign) |
| 4478 | a = maxalign; |
| 4479 | type->ref->r = a; |
| 4480 | if (pragma_pack && pragma_pack < maxalign && 0 == pcc) { |
| 4481 | /* can happen if individual align for some member was given. In |
| 4482 | this case MSVC ignores maxalign when aligning the size */ |
| 4483 | a = pragma_pack; |
| 4484 | if (a < bt) |
| 4485 | a = bt; |
| 4486 | } |
| 4487 | c = (c + a - 1) & -a; |
| 4488 | type->ref->c = c; |
| 4489 | |
| 4490 | #ifdef BF_DEBUG |
| 4491 | printf("struct size %-2d align %-2d\n\n" , c, a), fflush(stdout); |
| 4492 | #endif |
| 4493 | |
| 4494 | /* check whether we can access bitfields by their type */ |
| 4495 | for (f = type->ref->next; f; f = f->next) { |
| 4496 | int s, px, cx, c0; |
| 4497 | CType t; |
| 4498 | |
| 4499 | if (0 == (f->type.t & VT_BITFIELD)) |
| 4500 | continue; |
| 4501 | f->type.ref = f; |
| 4502 | f->auxtype = -1; |
| 4503 | bit_size = BIT_SIZE(f->type.t); |
| 4504 | if (bit_size == 0) |
| 4505 | continue; |
| 4506 | bit_pos = BIT_POS(f->type.t); |
| 4507 | size = type_size(&f->type, &align); |
| 4508 | if (bit_pos + bit_size <= size * 8 && f->c + size <= c) |
| 4509 | continue; |
| 4510 | |
| 4511 | /* try to access the field using a different type */ |
| 4512 | c0 = -1, s = align = 1; |
| 4513 | t.t = VT_BYTE; |
| 4514 | for (;;) { |
| 4515 | px = f->c * 8 + bit_pos; |
| 4516 | cx = (px >> 3) & -align; |
| 4517 | px = px - (cx << 3); |
| 4518 | if (c0 == cx) |
| 4519 | break; |
| 4520 | s = (px + bit_size + 7) >> 3; |
| 4521 | if (s > 4) { |
| 4522 | t.t = VT_LLONG; |
| 4523 | } else if (s > 2) { |
| 4524 | t.t = VT_INT; |
| 4525 | } else if (s > 1) { |
| 4526 | t.t = VT_SHORT; |
| 4527 | } else { |
| 4528 | t.t = VT_BYTE; |
| 4529 | } |
| 4530 | s = type_size(&t, &align); |
| 4531 | c0 = cx; |
| 4532 | } |
| 4533 | |
| 4534 | if (px + bit_size <= s * 8 && cx + s <= c) { |
| 4535 | /* update offset and bit position */ |
| 4536 | f->c = cx; |
| 4537 | bit_pos = px; |
| 4538 | f->type.t = (f->type.t & ~(0x3f << VT_STRUCT_SHIFT)) |
| 4539 | | (bit_pos << VT_STRUCT_SHIFT); |
| 4540 | if (s != size) |
| 4541 | f->auxtype = t.t; |
| 4542 | #ifdef BF_DEBUG |
| 4543 | printf("FIX field %s offset %-2d size %-2d align %-2d " |
| 4544 | "pos %-2d bits %-2d\n" , |
| 4545 | get_tok_str(f->v & ~SYM_FIELD, NULL), |
| 4546 | cx, s, align, px, bit_size); |
| 4547 | #endif |
| 4548 | } else { |
| 4549 | /* fall back to load/store single-byte wise */ |
| 4550 | f->auxtype = VT_STRUCT; |
| 4551 | #ifdef BF_DEBUG |
| 4552 | printf("FIX field %s : load byte-wise\n" , |
| 4553 | get_tok_str(f->v & ~SYM_FIELD, NULL)); |
| 4554 | #endif |
| 4555 | } |
| 4556 | } |
| 4557 | } |
| 4558 | |
| 4559 | /* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */ |
| 4560 | static void struct_decl(CType *type, int u) |
| 4561 | { |
| 4562 | int v, c, size, align, flexible; |
| 4563 | int bit_size, bsize, bt; |
| 4564 | Sym *s, *ss, **ps; |
| 4565 | AttributeDef ad, ad1; |
| 4566 | CType type1, btype; |
| 4567 | |
| 4568 | memset(&ad, 0, sizeof ad); |
| 4569 | next(); |
| 4570 | parse_attribute(&ad); |
| 4571 | if (tok != '{') { |
| 4572 | v = tok; |
| 4573 | next(); |
| 4574 | /* struct already defined ? return it */ |
| 4575 | if (v < TOK_IDENT) |
| 4576 | expect("struct/union/enum name" ); |
| 4577 | s = struct_find(v); |
| 4578 | if (s && (s->sym_scope == local_scope || tok != '{')) { |
| 4579 | if (u == s->type.t) |
| 4580 | goto do_decl; |
| 4581 | if (u == VT_ENUM && IS_ENUM(s->type.t)) |
| 4582 | goto do_decl; |
| 4583 | tcc_error("redefinition of '%s'" , get_tok_str(v, NULL)); |
| 4584 | } |
| 4585 | } else { |
| 4586 | v = anon_sym++; |
| 4587 | } |
| 4588 | /* Record the original enum/struct/union token. */ |
| 4589 | type1.t = u == VT_ENUM ? u | VT_INT | VT_UNSIGNED : u; |
| 4590 | type1.ref = NULL; |
| 4591 | /* we put an undefined size for struct/union */ |
| 4592 | s = sym_push(v | SYM_STRUCT, &type1, 0, -1); |
| 4593 | s->r = 0; /* default alignment is zero as gcc */ |
| 4594 | do_decl: |
| 4595 | type->t = s->type.t; |
| 4596 | type->ref = s; |
| 4597 | |
| 4598 | if (tok == '{') { |
| 4599 | next(); |
| 4600 | if (s->c != -1) |
| 4601 | tcc_error("struct/union/enum already defined" ); |
| 4602 | s->c = -2; |
| 4603 | /* cannot be empty */ |
| 4604 | /* non empty enums are not allowed */ |
| 4605 | ps = &s->next; |
| 4606 | if (u == VT_ENUM) { |
| 4607 | long long ll = 0, pl = 0, nl = 0; |
| 4608 | CType t; |
| 4609 | t.ref = s; |
| 4610 | /* enum symbols have static storage */ |
| 4611 | t.t = VT_INT|VT_STATIC|VT_ENUM_VAL; |
| 4612 | for(;;) { |
| 4613 | v = tok; |
| 4614 | if (v < TOK_UIDENT) |
| 4615 | expect("identifier" ); |
| 4616 | ss = sym_find(v); |
| 4617 | if (ss && !local_stack) |
| 4618 | tcc_error("redefinition of enumerator '%s'" , |
| 4619 | get_tok_str(v, NULL)); |
| 4620 | next(); |
| 4621 | if (tok == '=') { |
| 4622 | next(); |
| 4623 | ll = expr_const64(); |
| 4624 | } |
| 4625 | ss = sym_push(v, &t, VT_CONST, 0); |
| 4626 | ss->enum_val = ll; |
| 4627 | *ps = ss, ps = &ss->next; |
| 4628 | if (ll < nl) |
| 4629 | nl = ll; |
| 4630 | if (ll > pl) |
| 4631 | pl = ll; |
| 4632 | if (tok != ',') |
| 4633 | break; |
| 4634 | next(); |
| 4635 | ll++; |
| 4636 | /* NOTE: we accept a trailing comma */ |
| 4637 | if (tok == '}') |
| 4638 | break; |
| 4639 | } |
| 4640 | skip('}'); |
| 4641 | /* set integral type of the enum */ |
| 4642 | t.t = VT_INT; |
| 4643 | if (nl >= 0) { |
| 4644 | if (pl != (unsigned)pl) |
| 4645 | t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); |
| 4646 | t.t |= VT_UNSIGNED; |
| 4647 | } else if (pl != (int)pl || nl != (int)nl) |
| 4648 | t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); |
| 4649 | s->type.t = type->t = t.t | VT_ENUM; |
| 4650 | s->c = 0; |
| 4651 | /* set type for enum members */ |
| 4652 | for (ss = s->next; ss; ss = ss->next) { |
| 4653 | ll = ss->enum_val; |
| 4654 | if (ll == (int)ll) /* default is int if it fits */ |
| 4655 | continue; |
| 4656 | if (t.t & VT_UNSIGNED) { |
| 4657 | ss->type.t |= VT_UNSIGNED; |
| 4658 | if (ll == (unsigned)ll) |
| 4659 | continue; |
| 4660 | } |
| 4661 | ss->type.t = (ss->type.t & ~VT_BTYPE) |
| 4662 | | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); |
| 4663 | } |
| 4664 | } else { |
| 4665 | c = 0; |
| 4666 | flexible = 0; |
| 4667 | while (tok != '}') { |
| 4668 | if (!parse_btype(&btype, &ad1)) { |
| 4669 | skip(';'); |
| 4670 | continue; |
| 4671 | } |
| 4672 | while (1) { |
| 4673 | if (flexible) |
| 4674 | tcc_error("flexible array member '%s' not at the end of struct" , |
| 4675 | get_tok_str(v, NULL)); |
| 4676 | bit_size = -1; |
| 4677 | v = 0; |
| 4678 | type1 = btype; |
| 4679 | if (tok != ':') { |
| 4680 | if (tok != ';') |
| 4681 | type_decl(&type1, &ad1, &v, TYPE_DIRECT); |
| 4682 | if (v == 0) { |
| 4683 | if ((type1.t & VT_BTYPE) != VT_STRUCT) |
| 4684 | expect("identifier" ); |
| 4685 | else { |
| 4686 | int v = btype.ref->v; |
| 4687 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
| 4688 | if (tcc_state->ms_extensions == 0) |
| 4689 | expect("identifier" ); |
| 4690 | } |
| 4691 | } |
| 4692 | } |
| 4693 | if (type_size(&type1, &align) < 0) { |
| 4694 | if ((u == VT_STRUCT) && (type1.t & VT_ARRAY) && c) |
| 4695 | flexible = 1; |
| 4696 | else |
| 4697 | tcc_error("field '%s' has incomplete type" , |
| 4698 | get_tok_str(v, NULL)); |
| 4699 | } |
| 4700 | if ((type1.t & VT_BTYPE) == VT_FUNC || |
| 4701 | (type1.t & VT_BTYPE) == VT_VOID || |
| 4702 | (type1.t & VT_STORAGE)) |
| 4703 | tcc_error("invalid type for '%s'" , |
| 4704 | get_tok_str(v, NULL)); |
| 4705 | } |
| 4706 | if (tok == ':') { |
| 4707 | next(); |
| 4708 | bit_size = expr_const(); |
| 4709 | /* XXX: handle v = 0 case for messages */ |
| 4710 | if (bit_size < 0) |
| 4711 | tcc_error("negative width in bit-field '%s'" , |
| 4712 | get_tok_str(v, NULL)); |
| 4713 | if (v && bit_size == 0) |
| 4714 | tcc_error("zero width for bit-field '%s'" , |
| 4715 | get_tok_str(v, NULL)); |
| 4716 | parse_attribute(&ad1); |
| 4717 | } |
| 4718 | size = type_size(&type1, &align); |
| 4719 | if (bit_size >= 0) { |
| 4720 | bt = type1.t & VT_BTYPE; |
| 4721 | if (bt != VT_INT && |
| 4722 | bt != VT_BYTE && |
| 4723 | bt != VT_SHORT && |
| 4724 | bt != VT_BOOL && |
| 4725 | bt != VT_LLONG) |
| 4726 | tcc_error("bitfields must have scalar type" ); |
| 4727 | bsize = size * 8; |
| 4728 | if (bit_size > bsize) { |
| 4729 | tcc_error("width of '%s' exceeds its type" , |
| 4730 | get_tok_str(v, NULL)); |
| 4731 | } else if (bit_size == bsize |
| 4732 | && !ad.a.packed && !ad1.a.packed) { |
| 4733 | /* no need for bit fields */ |
| 4734 | ; |
| 4735 | } else if (bit_size == 64) { |
| 4736 | tcc_error("field width 64 not implemented" ); |
| 4737 | } else { |
| 4738 | type1.t = (type1.t & ~VT_STRUCT_MASK) |
| 4739 | | VT_BITFIELD |
| 4740 | | (bit_size << (VT_STRUCT_SHIFT + 6)); |
| 4741 | } |
| 4742 | } |
| 4743 | if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { |
| 4744 | /* Remember we've seen a real field to check |
| 4745 | for placement of flexible array member. */ |
| 4746 | c = 1; |
| 4747 | } |
| 4748 | /* If member is a struct or bit-field, enforce |
| 4749 | placing into the struct (as anonymous). */ |
| 4750 | if (v == 0 && |
| 4751 | ((type1.t & VT_BTYPE) == VT_STRUCT || |
| 4752 | bit_size >= 0)) { |
| 4753 | v = anon_sym++; |
| 4754 | } |
| 4755 | if (v) { |
| 4756 | ss = sym_push(v | SYM_FIELD, &type1, 0, 0); |
| 4757 | ss->a = ad1.a; |
| 4758 | *ps = ss; |
| 4759 | ps = &ss->next; |
| 4760 | } |
| 4761 | if (tok == ';' || tok == TOK_EOF) |
| 4762 | break; |
| 4763 | skip(','); |
| 4764 | } |
| 4765 | skip(';'); |
| 4766 | } |
| 4767 | skip('}'); |
| 4768 | parse_attribute(&ad); |
| 4769 | if (ad.cleanup_func) { |
| 4770 | tcc_warning("attribute '__cleanup__' ignored on type" ); |
| 4771 | } |
| 4772 | struct_layout(type, &ad); |
| 4773 | } |
| 4774 | } |
| 4775 | } |
| 4776 | |
| 4777 | static void sym_to_attr(AttributeDef *ad, Sym *s) |
| 4778 | { |
| 4779 | merge_symattr(&ad->a, &s->a); |
| 4780 | merge_funcattr(&ad->f, &s->f); |
| 4781 | } |
| 4782 | |
| 4783 | /* Add type qualifiers to a type. If the type is an array then the qualifiers |
| 4784 | are added to the element type, copied because it could be a typedef. */ |
| 4785 | static void parse_btype_qualify(CType *type, int qualifiers) |
| 4786 | { |
| 4787 | while (type->t & VT_ARRAY) { |
| 4788 | type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c); |
| 4789 | type = &type->ref->type; |
| 4790 | } |
| 4791 | type->t |= qualifiers; |
| 4792 | } |
| 4793 | |
| 4794 | /* return 0 if no type declaration. otherwise, return the basic type |
| 4795 | and skip it. |
| 4796 | */ |
| 4797 | static int parse_btype(CType *type, AttributeDef *ad) |
| 4798 | { |
| 4799 | int t, u, bt, st, type_found, typespec_found, g, n; |
| 4800 | Sym *s; |
| 4801 | CType type1; |
| 4802 | |
| 4803 | memset(ad, 0, sizeof(AttributeDef)); |
| 4804 | type_found = 0; |
| 4805 | typespec_found = 0; |
| 4806 | t = VT_INT; |
| 4807 | bt = st = -1; |
| 4808 | type->ref = NULL; |
| 4809 | |
| 4810 | while(1) { |
| 4811 | switch(tok) { |
| 4812 | case TOK_EXTENSION: |
| 4813 | /* currently, we really ignore extension */ |
| 4814 | next(); |
| 4815 | continue; |
| 4816 | |
| 4817 | /* basic types */ |
| 4818 | case TOK_CHAR: |
| 4819 | u = VT_BYTE; |
| 4820 | basic_type: |
| 4821 | next(); |
| 4822 | basic_type1: |
| 4823 | if (u == VT_SHORT || u == VT_LONG) { |
| 4824 | if (st != -1 || (bt != -1 && bt != VT_INT)) |
| 4825 | tmbt: tcc_error("too many basic types" ); |
| 4826 | st = u; |
| 4827 | } else { |
| 4828 | if (bt != -1 || (st != -1 && u != VT_INT)) |
| 4829 | goto tmbt; |
| 4830 | bt = u; |
| 4831 | } |
| 4832 | if (u != VT_INT) |
| 4833 | t = (t & ~(VT_BTYPE|VT_LONG)) | u; |
| 4834 | typespec_found = 1; |
| 4835 | break; |
| 4836 | case TOK_VOID: |
| 4837 | u = VT_VOID; |
| 4838 | goto basic_type; |
| 4839 | case TOK_SHORT: |
| 4840 | u = VT_SHORT; |
| 4841 | goto basic_type; |
| 4842 | case TOK_INT: |
| 4843 | u = VT_INT; |
| 4844 | goto basic_type; |
| 4845 | case TOK_ALIGNAS: |
| 4846 | { int n; |
| 4847 | AttributeDef ad1; |
| 4848 | next(); |
| 4849 | skip('('); |
| 4850 | memset(&ad1, 0, sizeof(AttributeDef)); |
| 4851 | if (parse_btype(&type1, &ad1)) { |
| 4852 | type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
| 4853 | if (ad1.a.aligned) |
| 4854 | n = 1 << (ad1.a.aligned - 1); |
| 4855 | else |
| 4856 | type_size(&type1, &n); |
| 4857 | } else { |
| 4858 | n = expr_const(); |
| 4859 | if (n <= 0 || (n & (n - 1)) != 0) |
| 4860 | tcc_error("alignment must be a positive power of two" ); |
| 4861 | } |
| 4862 | skip(')'); |
| 4863 | ad->a.aligned = exact_log2p1(n); |
| 4864 | } |
| 4865 | continue; |
| 4866 | case TOK_LONG: |
| 4867 | if ((t & VT_BTYPE) == VT_DOUBLE) { |
| 4868 | t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; |
| 4869 | } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { |
| 4870 | t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG; |
| 4871 | } else { |
| 4872 | u = VT_LONG; |
| 4873 | goto basic_type; |
| 4874 | } |
| 4875 | next(); |
| 4876 | break; |
| 4877 | #ifdef TCC_TARGET_ARM64 |
| 4878 | case TOK_UINT128: |
| 4879 | /* GCC's __uint128_t appears in some Linux header files. Make it a |
| 4880 | synonym for long double to get the size and alignment right. */ |
| 4881 | u = VT_LDOUBLE; |
| 4882 | goto basic_type; |
| 4883 | #endif |
| 4884 | case TOK_BOOL: |
| 4885 | u = VT_BOOL; |
| 4886 | goto basic_type; |
| 4887 | case TOK_FLOAT: |
| 4888 | u = VT_FLOAT; |
| 4889 | goto basic_type; |
| 4890 | case TOK_DOUBLE: |
| 4891 | if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { |
| 4892 | t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; |
| 4893 | } else { |
| 4894 | u = VT_DOUBLE; |
| 4895 | goto basic_type; |
| 4896 | } |
| 4897 | next(); |
| 4898 | break; |
| 4899 | case TOK_ENUM: |
| 4900 | struct_decl(&type1, VT_ENUM); |
| 4901 | basic_type2: |
| 4902 | u = type1.t; |
| 4903 | type->ref = type1.ref; |
| 4904 | goto basic_type1; |
| 4905 | case TOK_STRUCT: |
| 4906 | struct_decl(&type1, VT_STRUCT); |
| 4907 | goto basic_type2; |
| 4908 | case TOK_UNION: |
| 4909 | struct_decl(&type1, VT_UNION); |
| 4910 | goto basic_type2; |
| 4911 | |
| 4912 | /* type modifiers */ |
| 4913 | case TOK_CONST1: |
| 4914 | case TOK_CONST2: |
| 4915 | case TOK_CONST3: |
| 4916 | type->t = t; |
| 4917 | parse_btype_qualify(type, VT_CONSTANT); |
| 4918 | t = type->t; |
| 4919 | next(); |
| 4920 | break; |
| 4921 | case TOK_VOLATILE1: |
| 4922 | case TOK_VOLATILE2: |
| 4923 | case TOK_VOLATILE3: |
| 4924 | type->t = t; |
| 4925 | parse_btype_qualify(type, VT_VOLATILE); |
| 4926 | t = type->t; |
| 4927 | next(); |
| 4928 | break; |
| 4929 | case TOK_SIGNED1: |
| 4930 | case TOK_SIGNED2: |
| 4931 | case TOK_SIGNED3: |
| 4932 | if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == (VT_DEFSIGN|VT_UNSIGNED)) |
| 4933 | tcc_error("signed and unsigned modifier" ); |
| 4934 | t |= VT_DEFSIGN; |
| 4935 | next(); |
| 4936 | typespec_found = 1; |
| 4937 | break; |
| 4938 | case TOK_REGISTER: |
| 4939 | case TOK_AUTO: |
| 4940 | case TOK_RESTRICT1: |
| 4941 | case TOK_RESTRICT2: |
| 4942 | case TOK_RESTRICT3: |
| 4943 | next(); |
| 4944 | break; |
| 4945 | case TOK_UNSIGNED: |
| 4946 | if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == VT_DEFSIGN) |
| 4947 | tcc_error("signed and unsigned modifier" ); |
| 4948 | t |= VT_DEFSIGN | VT_UNSIGNED; |
| 4949 | next(); |
| 4950 | typespec_found = 1; |
| 4951 | break; |
| 4952 | |
| 4953 | /* storage */ |
| 4954 | case TOK_EXTERN: |
| 4955 | g = VT_EXTERN; |
| 4956 | goto storage; |
| 4957 | case TOK_STATIC: |
| 4958 | g = VT_STATIC; |
| 4959 | goto storage; |
| 4960 | case TOK_TYPEDEF: |
| 4961 | g = VT_TYPEDEF; |
| 4962 | goto storage; |
| 4963 | storage: |
| 4964 | if (t & (VT_EXTERN|VT_STATIC|VT_TYPEDEF) & ~g) |
| 4965 | tcc_error("multiple storage classes" ); |
| 4966 | t |= g; |
| 4967 | next(); |
| 4968 | break; |
| 4969 | case TOK_INLINE1: |
| 4970 | case TOK_INLINE2: |
| 4971 | case TOK_INLINE3: |
| 4972 | t |= VT_INLINE; |
| 4973 | next(); |
| 4974 | break; |
| 4975 | case TOK_NORETURN3: |
| 4976 | next(); |
| 4977 | ad->f.func_noreturn = 1; |
| 4978 | break; |
| 4979 | /* GNUC attribute */ |
| 4980 | case TOK_ATTRIBUTE1: |
| 4981 | case TOK_ATTRIBUTE2: |
| 4982 | parse_attribute(ad); |
| 4983 | if (ad->attr_mode) { |
| 4984 | u = ad->attr_mode -1; |
| 4985 | t = (t & ~(VT_BTYPE|VT_LONG)) | u; |
| 4986 | } |
| 4987 | continue; |
| 4988 | /* GNUC typeof */ |
| 4989 | case TOK_TYPEOF1: |
| 4990 | case TOK_TYPEOF2: |
| 4991 | case TOK_TYPEOF3: |
| 4992 | next(); |
| 4993 | parse_expr_type(&type1); |
| 4994 | /* remove all storage modifiers except typedef */ |
| 4995 | type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); |
| 4996 | if (type1.ref) |
| 4997 | sym_to_attr(ad, type1.ref); |
| 4998 | goto basic_type2; |
| 4999 | default: |
| 5000 | if (typespec_found) |
| 5001 | goto the_end; |
| 5002 | s = sym_find(tok); |
| 5003 | if (!s || !(s->type.t & VT_TYPEDEF)) |
| 5004 | goto the_end; |
| 5005 | |
| 5006 | n = tok, next(); |
| 5007 | if (tok == ':' && !in_generic) { |
| 5008 | /* ignore if it's a label */ |
| 5009 | unget_tok(n); |
| 5010 | goto the_end; |
| 5011 | } |
| 5012 | |
| 5013 | t &= ~(VT_BTYPE|VT_LONG); |
| 5014 | u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; |
| 5015 | type->t = (s->type.t & ~VT_TYPEDEF) | u; |
| 5016 | type->ref = s->type.ref; |
| 5017 | if (t) |
| 5018 | parse_btype_qualify(type, t); |
| 5019 | t = type->t; |
| 5020 | /* get attributes from typedef */ |
| 5021 | sym_to_attr(ad, s); |
| 5022 | typespec_found = 1; |
| 5023 | st = bt = -2; |
| 5024 | break; |
| 5025 | } |
| 5026 | type_found = 1; |
| 5027 | } |
| 5028 | the_end: |
| 5029 | if (tcc_state->char_is_unsigned) { |
| 5030 | if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) |
| 5031 | t |= VT_UNSIGNED; |
| 5032 | } |
| 5033 | /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */ |
| 5034 | bt = t & (VT_BTYPE|VT_LONG); |
| 5035 | if (bt == VT_LONG) |
| 5036 | t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT; |
| 5037 | #if defined TCC_TARGET_PE || (defined _WIN32 && defined _MSC_VER) |
| 5038 | if (bt == VT_LDOUBLE) |
| 5039 | t = (t & ~(VT_BTYPE|VT_LONG)) | (VT_DOUBLE|VT_LONG); |
| 5040 | #endif |
| 5041 | type->t = t; |
| 5042 | return type_found; |
| 5043 | } |
| 5044 | |
| 5045 | /* convert a function parameter type (array to pointer and function to |
| 5046 | function pointer) */ |
| 5047 | static inline void convert_parameter_type(CType *pt) |
| 5048 | { |
| 5049 | /* remove const and volatile qualifiers (XXX: const could be used |
| 5050 | to indicate a const function parameter */ |
| 5051 | pt->t &= ~(VT_CONSTANT | VT_VOLATILE); |
| 5052 | /* array must be transformed to pointer according to ANSI C */ |
| 5053 | pt->t &= ~VT_ARRAY; |
| 5054 | if ((pt->t & VT_BTYPE) == VT_FUNC) { |
| 5055 | mk_pointer(pt); |
| 5056 | } |
| 5057 | } |
| 5058 | |
| 5059 | ST_FUNC void parse_asm_str(CString *astr) |
| 5060 | { |
| 5061 | skip('('); |
| 5062 | parse_mult_str(astr, "string constant" ); |
| 5063 | } |
| 5064 | |
| 5065 | /* Parse an asm label and return the token */ |
| 5066 | static int asm_label_instr(void) |
| 5067 | { |
| 5068 | int v; |
| 5069 | CString astr; |
| 5070 | |
| 5071 | next(); |
| 5072 | parse_asm_str(&astr); |
| 5073 | skip(')'); |
| 5074 | #ifdef ASM_DEBUG |
| 5075 | printf("asm_alias: \"%s\"\n" , (char *)astr.data); |
| 5076 | #endif |
| 5077 | v = tok_alloc(astr.data, astr.size - 1)->tok; |
| 5078 | cstr_free(&astr); |
| 5079 | return v; |
| 5080 | } |
| 5081 | |
| 5082 | static int post_type(CType *type, AttributeDef *ad, int storage, int td) |
| 5083 | { |
| 5084 | int n, l, t1, arg_size, align, unused_align; |
| 5085 | Sym **plast, *s, *first; |
| 5086 | AttributeDef ad1; |
| 5087 | CType pt; |
| 5088 | |
| 5089 | if (tok == '(') { |
| 5090 | /* function type, or recursive declarator (return if so) */ |
| 5091 | next(); |
| 5092 | if (td && !(td & TYPE_ABSTRACT)) |
| 5093 | return 0; |
| 5094 | if (tok == ')') |
| 5095 | l = 0; |
| 5096 | else if (parse_btype(&pt, &ad1)) |
| 5097 | l = FUNC_NEW; |
| 5098 | else if (td) { |
| 5099 | merge_attr (ad, &ad1); |
| 5100 | return 0; |
| 5101 | } else |
| 5102 | l = FUNC_OLD; |
| 5103 | first = NULL; |
| 5104 | plast = &first; |
| 5105 | arg_size = 0; |
| 5106 | if (l) { |
| 5107 | for(;;) { |
| 5108 | /* read param name and compute offset */ |
| 5109 | if (l != FUNC_OLD) { |
| 5110 | if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') |
| 5111 | break; |
| 5112 | type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); |
| 5113 | if ((pt.t & VT_BTYPE) == VT_VOID) |
| 5114 | tcc_error("parameter declared as void" ); |
| 5115 | } else { |
| 5116 | n = tok; |
| 5117 | if (n < TOK_UIDENT) |
| 5118 | expect("identifier" ); |
| 5119 | pt.t = VT_VOID; /* invalid type */ |
| 5120 | pt.ref = NULL; |
| 5121 | next(); |
| 5122 | } |
| 5123 | convert_parameter_type(&pt); |
| 5124 | arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; |
| 5125 | s = sym_push(n | SYM_FIELD, &pt, 0, 0); |
| 5126 | *plast = s; |
| 5127 | plast = &s->next; |
| 5128 | if (tok == ')') |
| 5129 | break; |
| 5130 | skip(','); |
| 5131 | if (l == FUNC_NEW && tok == TOK_DOTS) { |
| 5132 | l = FUNC_ELLIPSIS; |
| 5133 | next(); |
| 5134 | break; |
| 5135 | } |
| 5136 | if (l == FUNC_NEW && !parse_btype(&pt, &ad1)) |
| 5137 | tcc_error("invalid type" ); |
| 5138 | } |
| 5139 | } else |
| 5140 | /* if no parameters, then old type prototype */ |
| 5141 | l = FUNC_OLD; |
| 5142 | skip(')'); |
| 5143 | /* NOTE: const is ignored in returned type as it has a special |
| 5144 | meaning in gcc / C++ */ |
| 5145 | type->t &= ~VT_CONSTANT; |
| 5146 | /* some ancient pre-K&R C allows a function to return an array |
| 5147 | and the array brackets to be put after the arguments, such |
| 5148 | that "int c()[]" means something like "int[] c()" */ |
| 5149 | if (tok == '[') { |
| 5150 | next(); |
| 5151 | skip(']'); /* only handle simple "[]" */ |
| 5152 | mk_pointer(type); |
| 5153 | } |
| 5154 | /* we push a anonymous symbol which will contain the function prototype */ |
| 5155 | ad->f.func_args = arg_size; |
| 5156 | ad->f.func_type = l; |
| 5157 | s = sym_push(SYM_FIELD, type, 0, 0); |
| 5158 | s->a = ad->a; |
| 5159 | s->f = ad->f; |
| 5160 | s->next = first; |
| 5161 | type->t = VT_FUNC; |
| 5162 | type->ref = s; |
| 5163 | } else if (tok == '[') { |
| 5164 | int saved_nocode_wanted = nocode_wanted; |
| 5165 | /* array definition */ |
| 5166 | next(); |
| 5167 | while (1) { |
| 5168 | /* XXX The optional type-quals and static should only be accepted |
| 5169 | in parameter decls. The '*' as well, and then even only |
| 5170 | in prototypes (not function defs). */ |
| 5171 | switch (tok) { |
| 5172 | case TOK_RESTRICT1: case TOK_RESTRICT2: case TOK_RESTRICT3: |
| 5173 | case TOK_CONST1: |
| 5174 | case TOK_VOLATILE1: |
| 5175 | case TOK_STATIC: |
| 5176 | case '*': |
| 5177 | next(); |
| 5178 | continue; |
| 5179 | default: |
| 5180 | break; |
| 5181 | } |
| 5182 | break; |
| 5183 | } |
| 5184 | n = -1; |
| 5185 | t1 = 0; |
| 5186 | if (tok != ']') { |
| 5187 | if (!local_stack || (storage & VT_STATIC)) |
| 5188 | vpushi(expr_const()); |
| 5189 | else { |
| 5190 | /* VLAs (which can only happen with local_stack && !VT_STATIC) |
| 5191 | length must always be evaluated, even under nocode_wanted, |
| 5192 | so that its size slot is initialized (e.g. under sizeof |
| 5193 | or typeof). */ |
| 5194 | nocode_wanted = 0; |
| 5195 | gexpr(); |
| 5196 | } |
| 5197 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
| 5198 | n = vtop->c.i; |
| 5199 | if (n < 0) |
| 5200 | tcc_error("invalid array size" ); |
| 5201 | } else { |
| 5202 | if (!is_integer_btype(vtop->type.t & VT_BTYPE)) |
| 5203 | tcc_error("size of variable length array should be an integer" ); |
| 5204 | n = 0; |
| 5205 | t1 = VT_VLA; |
| 5206 | } |
| 5207 | } |
| 5208 | skip(']'); |
| 5209 | /* parse next post type */ |
| 5210 | post_type(type, ad, storage, 0); |
| 5211 | |
| 5212 | if ((type->t & VT_BTYPE) == VT_FUNC) |
| 5213 | tcc_error("declaration of an array of functions" ); |
| 5214 | if ((type->t & VT_BTYPE) == VT_VOID |
| 5215 | || type_size(type, &unused_align) < 0) |
| 5216 | tcc_error("declaration of an array of incomplete type elements" ); |
| 5217 | |
| 5218 | t1 |= type->t & VT_VLA; |
| 5219 | |
| 5220 | if (t1 & VT_VLA) { |
| 5221 | if (n < 0) |
| 5222 | tcc_error("need explicit inner array size in VLAs" ); |
| 5223 | loc -= type_size(&int_type, &align); |
| 5224 | loc &= -align; |
| 5225 | n = loc; |
| 5226 | |
| 5227 | vla_runtime_type_size(type, &align); |
| 5228 | gen_op('*'); |
| 5229 | vset(&int_type, VT_LOCAL|VT_LVAL, n); |
| 5230 | vswap(); |
| 5231 | vstore(); |
| 5232 | } |
| 5233 | if (n != -1) |
| 5234 | vpop(); |
| 5235 | nocode_wanted = saved_nocode_wanted; |
| 5236 | |
| 5237 | /* we push an anonymous symbol which will contain the array |
| 5238 | element type */ |
| 5239 | s = sym_push(SYM_FIELD, type, 0, n); |
| 5240 | type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; |
| 5241 | type->ref = s; |
| 5242 | } |
| 5243 | return 1; |
| 5244 | } |
| 5245 | |
| 5246 | /* Parse a type declarator (except basic type), and return the type |
| 5247 | in 'type'. 'td' is a bitmask indicating which kind of type decl is |
| 5248 | expected. 'type' should contain the basic type. 'ad' is the |
| 5249 | attribute definition of the basic type. It can be modified by |
| 5250 | type_decl(). If this (possibly abstract) declarator is a pointer chain |
| 5251 | it returns the innermost pointed to type (equals *type, but is a different |
| 5252 | pointer), otherwise returns type itself, that's used for recursive calls. */ |
| 5253 | static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td) |
| 5254 | { |
| 5255 | CType *post, *ret; |
| 5256 | int qualifiers, storage; |
| 5257 | |
| 5258 | /* recursive type, remove storage bits first, apply them later again */ |
| 5259 | storage = type->t & VT_STORAGE; |
| 5260 | type->t &= ~VT_STORAGE; |
| 5261 | post = ret = type; |
| 5262 | |
| 5263 | while (tok == '*') { |
| 5264 | qualifiers = 0; |
| 5265 | redo: |
| 5266 | next(); |
| 5267 | switch(tok) { |
| 5268 | case TOK_CONST1: |
| 5269 | case TOK_CONST2: |
| 5270 | case TOK_CONST3: |
| 5271 | qualifiers |= VT_CONSTANT; |
| 5272 | goto redo; |
| 5273 | case TOK_VOLATILE1: |
| 5274 | case TOK_VOLATILE2: |
| 5275 | case TOK_VOLATILE3: |
| 5276 | qualifiers |= VT_VOLATILE; |
| 5277 | goto redo; |
| 5278 | case TOK_RESTRICT1: |
| 5279 | case TOK_RESTRICT2: |
| 5280 | case TOK_RESTRICT3: |
| 5281 | goto redo; |
| 5282 | /* XXX: clarify attribute handling */ |
| 5283 | case TOK_ATTRIBUTE1: |
| 5284 | case TOK_ATTRIBUTE2: |
| 5285 | parse_attribute(ad); |
| 5286 | break; |
| 5287 | } |
| 5288 | mk_pointer(type); |
| 5289 | type->t |= qualifiers; |
| 5290 | if (ret == type) |
| 5291 | /* innermost pointed to type is the one for the first derivation */ |
| 5292 | ret = pointed_type(type); |
| 5293 | } |
| 5294 | |
| 5295 | if (tok == '(') { |
| 5296 | /* This is possibly a parameter type list for abstract declarators |
| 5297 | ('int ()'), use post_type for testing this. */ |
| 5298 | if (!post_type(type, ad, 0, td)) { |
| 5299 | /* It's not, so it's a nested declarator, and the post operations |
| 5300 | apply to the innermost pointed to type (if any). */ |
| 5301 | /* XXX: this is not correct to modify 'ad' at this point, but |
| 5302 | the syntax is not clear */ |
| 5303 | parse_attribute(ad); |
| 5304 | post = type_decl(type, ad, v, td); |
| 5305 | skip(')'); |
| 5306 | } else |
| 5307 | goto abstract; |
| 5308 | } else if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { |
| 5309 | /* type identifier */ |
| 5310 | *v = tok; |
| 5311 | next(); |
| 5312 | } else { |
| 5313 | abstract: |
| 5314 | if (!(td & TYPE_ABSTRACT)) |
| 5315 | expect("identifier" ); |
| 5316 | *v = 0; |
| 5317 | } |
| 5318 | post_type(post, ad, storage, 0); |
| 5319 | parse_attribute(ad); |
| 5320 | type->t |= storage; |
| 5321 | return ret; |
| 5322 | } |
| 5323 | |
| 5324 | /* indirection with full error checking and bound check */ |
| 5325 | ST_FUNC void indir(void) |
| 5326 | { |
| 5327 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) { |
| 5328 | if ((vtop->type.t & VT_BTYPE) == VT_FUNC) |
| 5329 | return; |
| 5330 | expect("pointer" ); |
| 5331 | } |
| 5332 | if (vtop->r & VT_LVAL) |
| 5333 | gv(RC_INT); |
| 5334 | vtop->type = *pointed_type(&vtop->type); |
| 5335 | /* Arrays and functions are never lvalues */ |
| 5336 | if (!(vtop->type.t & (VT_ARRAY | VT_VLA)) |
| 5337 | && (vtop->type.t & VT_BTYPE) != VT_FUNC) { |
| 5338 | vtop->r |= VT_LVAL; |
| 5339 | /* if bound checking, the referenced pointer must be checked */ |
| 5340 | #ifdef CONFIG_TCC_BCHECK |
| 5341 | if (tcc_state->do_bounds_check) |
| 5342 | vtop->r |= VT_MUSTBOUND; |
| 5343 | #endif |
| 5344 | } |
| 5345 | } |
| 5346 | |
| 5347 | /* pass a parameter to a function and do type checking and casting */ |
| 5348 | static void gfunc_param_typed(Sym *func, Sym *arg) |
| 5349 | { |
| 5350 | int func_type; |
| 5351 | CType type; |
| 5352 | |
| 5353 | func_type = func->f.func_type; |
| 5354 | if (func_type == FUNC_OLD || |
| 5355 | (func_type == FUNC_ELLIPSIS && arg == NULL)) { |
| 5356 | /* default casting : only need to convert float to double */ |
| 5357 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { |
| 5358 | gen_cast_s(VT_DOUBLE); |
| 5359 | } else if (vtop->type.t & VT_BITFIELD) { |
| 5360 | type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
| 5361 | type.ref = vtop->type.ref; |
| 5362 | gen_cast(&type); |
| 5363 | } else if (vtop->r & VT_MUSTCAST) { |
| 5364 | force_charshort_cast(); |
| 5365 | } |
| 5366 | } else if (arg == NULL) { |
| 5367 | tcc_error("too many arguments to function" ); |
| 5368 | } else { |
| 5369 | type = arg->type; |
| 5370 | type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
| 5371 | gen_assign_cast(&type); |
| 5372 | } |
| 5373 | } |
| 5374 | |
| 5375 | /* parse an expression and return its type without any side effect. */ |
| 5376 | static void expr_type(CType *type, void (*expr_fn)(void)) |
| 5377 | { |
| 5378 | nocode_wanted++; |
| 5379 | expr_fn(); |
| 5380 | *type = vtop->type; |
| 5381 | vpop(); |
| 5382 | nocode_wanted--; |
| 5383 | } |
| 5384 | |
| 5385 | /* parse an expression of the form '(type)' or '(expr)' and return its |
| 5386 | type */ |
| 5387 | static void parse_expr_type(CType *type) |
| 5388 | { |
| 5389 | int n; |
| 5390 | AttributeDef ad; |
| 5391 | |
| 5392 | skip('('); |
| 5393 | if (parse_btype(type, &ad)) { |
| 5394 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
| 5395 | } else { |
| 5396 | expr_type(type, gexpr); |
| 5397 | } |
| 5398 | skip(')'); |
| 5399 | } |
| 5400 | |
| 5401 | static void parse_type(CType *type) |
| 5402 | { |
| 5403 | AttributeDef ad; |
| 5404 | int n; |
| 5405 | |
| 5406 | if (!parse_btype(type, &ad)) { |
| 5407 | expect("type" ); |
| 5408 | } |
| 5409 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
| 5410 | } |
| 5411 | |
| 5412 | static void parse_builtin_params(int nc, const char *args) |
| 5413 | { |
| 5414 | char c, sep = '('; |
| 5415 | CType type; |
| 5416 | if (nc) |
| 5417 | nocode_wanted++; |
| 5418 | next(); |
| 5419 | if (*args == 0) |
| 5420 | skip(sep); |
| 5421 | while ((c = *args++)) { |
| 5422 | skip(sep); |
| 5423 | sep = ','; |
| 5424 | if (c == 't') { |
| 5425 | parse_type(&type); |
| 5426 | vpush(&type); |
| 5427 | continue; |
| 5428 | } |
| 5429 | expr_eq(); |
| 5430 | type.ref = NULL; |
| 5431 | type.t = 0; |
| 5432 | switch (c) { |
| 5433 | case 'e': |
| 5434 | continue; |
| 5435 | case 'V': |
| 5436 | type.t = VT_CONSTANT; |
| 5437 | case 'v': |
| 5438 | type.t |= VT_VOID; |
| 5439 | mk_pointer (&type); |
| 5440 | break; |
| 5441 | case 'S': |
| 5442 | type.t = VT_CONSTANT; |
| 5443 | case 's': |
| 5444 | type.t |= char_type.t; |
| 5445 | mk_pointer (&type); |
| 5446 | break; |
| 5447 | case 'i': |
| 5448 | type.t = VT_INT; |
| 5449 | break; |
| 5450 | case 'l': |
| 5451 | type.t = VT_SIZE_T; |
| 5452 | break; |
| 5453 | default: |
| 5454 | break; |
| 5455 | } |
| 5456 | gen_assign_cast(&type); |
| 5457 | } |
| 5458 | skip(')'); |
| 5459 | if (nc) |
| 5460 | nocode_wanted--; |
| 5461 | } |
| 5462 | |
| 5463 | ST_FUNC void unary(void) |
| 5464 | { |
| 5465 | int n, t, align, size, r, sizeof_caller; |
| 5466 | CType type; |
| 5467 | Sym *s; |
| 5468 | AttributeDef ad; |
| 5469 | |
| 5470 | /* generate line number info */ |
| 5471 | if (tcc_state->do_debug) |
| 5472 | tcc_debug_line(tcc_state); |
| 5473 | |
| 5474 | sizeof_caller = in_sizeof; |
| 5475 | in_sizeof = 0; |
| 5476 | type.ref = NULL; |
| 5477 | /* XXX: GCC 2.95.3 does not generate a table although it should be |
| 5478 | better here */ |
| 5479 | tok_next: |
| 5480 | switch(tok) { |
| 5481 | case TOK_EXTENSION: |
| 5482 | next(); |
| 5483 | goto tok_next; |
| 5484 | case TOK_LCHAR: |
| 5485 | #ifdef TCC_TARGET_PE |
| 5486 | t = VT_SHORT|VT_UNSIGNED; |
| 5487 | goto push_tokc; |
| 5488 | #endif |
| 5489 | case TOK_CINT: |
| 5490 | case TOK_CCHAR: |
| 5491 | t = VT_INT; |
| 5492 | push_tokc: |
| 5493 | type.t = t; |
| 5494 | vsetc(&type, VT_CONST, &tokc); |
| 5495 | next(); |
| 5496 | break; |
| 5497 | case TOK_CUINT: |
| 5498 | t = VT_INT | VT_UNSIGNED; |
| 5499 | goto push_tokc; |
| 5500 | case TOK_CLLONG: |
| 5501 | t = VT_LLONG; |
| 5502 | goto push_tokc; |
| 5503 | case TOK_CULLONG: |
| 5504 | t = VT_LLONG | VT_UNSIGNED; |
| 5505 | goto push_tokc; |
| 5506 | case TOK_CFLOAT: |
| 5507 | t = VT_FLOAT; |
| 5508 | goto push_tokc; |
| 5509 | case TOK_CDOUBLE: |
| 5510 | t = VT_DOUBLE; |
| 5511 | goto push_tokc; |
| 5512 | case TOK_CLDOUBLE: |
| 5513 | t = VT_LDOUBLE; |
| 5514 | goto push_tokc; |
| 5515 | case TOK_CLONG: |
| 5516 | t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG; |
| 5517 | goto push_tokc; |
| 5518 | case TOK_CULONG: |
| 5519 | t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED; |
| 5520 | goto push_tokc; |
| 5521 | case TOK___FUNCTION__: |
| 5522 | if (!gnu_ext) |
| 5523 | goto tok_identifier; |
| 5524 | /* fall thru */ |
| 5525 | case TOK___FUNC__: |
| 5526 | { |
| 5527 | void *ptr; |
| 5528 | int len; |
| 5529 | /* special function name identifier */ |
| 5530 | len = strlen(funcname) + 1; |
| 5531 | /* generate char[len] type */ |
| 5532 | type.t = VT_BYTE; |
| 5533 | mk_pointer(&type); |
| 5534 | type.t |= VT_ARRAY; |
| 5535 | type.ref->c = len; |
| 5536 | vpush_ref(&type, data_section, data_section->data_offset, len); |
| 5537 | if (!NODATA_WANTED) { |
| 5538 | ptr = section_ptr_add(data_section, len); |
| 5539 | memcpy(ptr, funcname, len); |
| 5540 | } |
| 5541 | next(); |
| 5542 | } |
| 5543 | break; |
| 5544 | case TOK_LSTR: |
| 5545 | #ifdef TCC_TARGET_PE |
| 5546 | t = VT_SHORT | VT_UNSIGNED; |
| 5547 | #else |
| 5548 | t = VT_INT; |
| 5549 | #endif |
| 5550 | goto str_init; |
| 5551 | case TOK_STR: |
| 5552 | /* string parsing */ |
| 5553 | t = VT_BYTE; |
| 5554 | if (tcc_state->char_is_unsigned) |
| 5555 | t = VT_BYTE | VT_UNSIGNED; |
| 5556 | str_init: |
| 5557 | if (tcc_state->warn_write_strings) |
| 5558 | t |= VT_CONSTANT; |
| 5559 | type.t = t; |
| 5560 | mk_pointer(&type); |
| 5561 | type.t |= VT_ARRAY; |
| 5562 | memset(&ad, 0, sizeof(AttributeDef)); |
| 5563 | decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); |
| 5564 | break; |
| 5565 | case '(': |
| 5566 | next(); |
| 5567 | /* cast ? */ |
| 5568 | if (parse_btype(&type, &ad)) { |
| 5569 | type_decl(&type, &ad, &n, TYPE_ABSTRACT); |
| 5570 | skip(')'); |
| 5571 | /* check ISOC99 compound literal */ |
| 5572 | if (tok == '{') { |
| 5573 | /* data is allocated locally by default */ |
| 5574 | if (global_expr) |
| 5575 | r = VT_CONST; |
| 5576 | else |
| 5577 | r = VT_LOCAL; |
| 5578 | /* all except arrays are lvalues */ |
| 5579 | if (!(type.t & VT_ARRAY)) |
| 5580 | r |= VT_LVAL; |
| 5581 | memset(&ad, 0, sizeof(AttributeDef)); |
| 5582 | decl_initializer_alloc(&type, &ad, r, 1, 0, 0); |
| 5583 | } else { |
| 5584 | if (sizeof_caller) { |
| 5585 | vpush(&type); |
| 5586 | return; |
| 5587 | } |
| 5588 | unary(); |
| 5589 | gen_cast(&type); |
| 5590 | } |
| 5591 | } else if (tok == '{') { |
| 5592 | int saved_nocode_wanted = nocode_wanted; |
| 5593 | if (const_wanted && !(nocode_wanted & unevalmask)) |
| 5594 | tcc_error("expected constant" ); |
| 5595 | /* save all registers */ |
| 5596 | save_regs(0); |
| 5597 | /* statement expression : we do not accept break/continue |
| 5598 | inside as GCC does. We do retain the nocode_wanted state, |
| 5599 | as statement expressions can't ever be entered from the |
| 5600 | outside, so any reactivation of code emission (from labels |
| 5601 | or loop heads) can be disabled again after the end of it. */ |
| 5602 | block(1); |
| 5603 | nocode_wanted = saved_nocode_wanted; |
| 5604 | skip(')'); |
| 5605 | } else { |
| 5606 | gexpr(); |
| 5607 | skip(')'); |
| 5608 | } |
| 5609 | break; |
| 5610 | case '*': |
| 5611 | next(); |
| 5612 | unary(); |
| 5613 | indir(); |
| 5614 | break; |
| 5615 | case '&': |
| 5616 | next(); |
| 5617 | unary(); |
| 5618 | /* functions names must be treated as function pointers, |
| 5619 | except for unary '&' and sizeof. Since we consider that |
| 5620 | functions are not lvalues, we only have to handle it |
| 5621 | there and in function calls. */ |
| 5622 | /* arrays can also be used although they are not lvalues */ |
| 5623 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC && |
| 5624 | !(vtop->type.t & VT_ARRAY)) |
| 5625 | test_lvalue(); |
| 5626 | if (vtop->sym) |
| 5627 | vtop->sym->a.addrtaken = 1; |
| 5628 | mk_pointer(&vtop->type); |
| 5629 | gaddrof(); |
| 5630 | break; |
| 5631 | case '!': |
| 5632 | next(); |
| 5633 | unary(); |
| 5634 | gen_test_zero(TOK_EQ); |
| 5635 | break; |
| 5636 | case '~': |
| 5637 | next(); |
| 5638 | unary(); |
| 5639 | vpushi(-1); |
| 5640 | gen_op('^'); |
| 5641 | break; |
| 5642 | case '+': |
| 5643 | next(); |
| 5644 | unary(); |
| 5645 | if ((vtop->type.t & VT_BTYPE) == VT_PTR) |
| 5646 | tcc_error("pointer not accepted for unary plus" ); |
| 5647 | /* In order to force cast, we add zero, except for floating point |
| 5648 | where we really need an noop (otherwise -0.0 will be transformed |
| 5649 | into +0.0). */ |
| 5650 | if (!is_float(vtop->type.t)) { |
| 5651 | vpushi(0); |
| 5652 | gen_op('+'); |
| 5653 | } |
| 5654 | break; |
| 5655 | case TOK_SIZEOF: |
| 5656 | case TOK_ALIGNOF1: |
| 5657 | case TOK_ALIGNOF2: |
| 5658 | case TOK_ALIGNOF3: |
| 5659 | t = tok; |
| 5660 | next(); |
| 5661 | in_sizeof++; |
| 5662 | expr_type(&type, unary); /* Perform a in_sizeof = 0; */ |
| 5663 | s = NULL; |
| 5664 | if (vtop[1].r & VT_SYM) |
| 5665 | s = vtop[1].sym; /* hack: accessing previous vtop */ |
| 5666 | size = type_size(&type, &align); |
| 5667 | if (s && s->a.aligned) |
| 5668 | align = 1 << (s->a.aligned - 1); |
| 5669 | if (t == TOK_SIZEOF) { |
| 5670 | if (!(type.t & VT_VLA)) { |
| 5671 | if (size < 0) |
| 5672 | tcc_error("sizeof applied to an incomplete type" ); |
| 5673 | vpushs(size); |
| 5674 | } else { |
| 5675 | vla_runtime_type_size(&type, &align); |
| 5676 | } |
| 5677 | } else { |
| 5678 | vpushs(align); |
| 5679 | } |
| 5680 | vtop->type.t |= VT_UNSIGNED; |
| 5681 | break; |
| 5682 | |
| 5683 | case TOK_builtin_expect: |
| 5684 | /* __builtin_expect is a no-op for now */ |
| 5685 | parse_builtin_params(0, "ee" ); |
| 5686 | vpop(); |
| 5687 | break; |
| 5688 | case TOK_builtin_types_compatible_p: |
| 5689 | parse_builtin_params(0, "tt" ); |
| 5690 | vtop[-1].type.t &= ~(VT_CONSTANT | VT_VOLATILE); |
| 5691 | vtop[0].type.t &= ~(VT_CONSTANT | VT_VOLATILE); |
| 5692 | n = is_compatible_types(&vtop[-1].type, &vtop[0].type); |
| 5693 | vtop -= 2; |
| 5694 | vpushi(n); |
| 5695 | break; |
| 5696 | case TOK_builtin_choose_expr: |
| 5697 | { |
| 5698 | int64_t c; |
| 5699 | next(); |
| 5700 | skip('('); |
| 5701 | c = expr_const64(); |
| 5702 | skip(','); |
| 5703 | if (!c) { |
| 5704 | nocode_wanted++; |
| 5705 | } |
| 5706 | expr_eq(); |
| 5707 | if (!c) { |
| 5708 | vpop(); |
| 5709 | nocode_wanted--; |
| 5710 | } |
| 5711 | skip(','); |
| 5712 | if (c) { |
| 5713 | nocode_wanted++; |
| 5714 | } |
| 5715 | expr_eq(); |
| 5716 | if (c) { |
| 5717 | vpop(); |
| 5718 | nocode_wanted--; |
| 5719 | } |
| 5720 | skip(')'); |
| 5721 | } |
| 5722 | break; |
| 5723 | case TOK_builtin_constant_p: |
| 5724 | parse_builtin_params(1, "e" ); |
| 5725 | n = (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && |
| 5726 | !((vtop->r & VT_SYM) && vtop->sym->a.addrtaken); |
| 5727 | vtop--; |
| 5728 | vpushi(n); |
| 5729 | break; |
| 5730 | case TOK_builtin_frame_address: |
| 5731 | case TOK_builtin_return_address: |
| 5732 | { |
| 5733 | int tok1 = tok; |
| 5734 | int level; |
| 5735 | next(); |
| 5736 | skip('('); |
| 5737 | if (tok != TOK_CINT) { |
| 5738 | tcc_error("%s only takes positive integers" , |
| 5739 | tok1 == TOK_builtin_return_address ? |
| 5740 | "__builtin_return_address" : |
| 5741 | "__builtin_frame_address" ); |
| 5742 | } |
| 5743 | level = (uint32_t)tokc.i; |
| 5744 | next(); |
| 5745 | skip(')'); |
| 5746 | type.t = VT_VOID; |
| 5747 | mk_pointer(&type); |
| 5748 | vset(&type, VT_LOCAL, 0); /* local frame */ |
| 5749 | while (level--) { |
| 5750 | #ifdef TCC_TARGET_RISCV64 |
| 5751 | vpushi(2*PTR_SIZE); |
| 5752 | gen_op('-'); |
| 5753 | #endif |
| 5754 | mk_pointer(&vtop->type); |
| 5755 | indir(); /* -> parent frame */ |
| 5756 | } |
| 5757 | if (tok1 == TOK_builtin_return_address) { |
| 5758 | // assume return address is just above frame pointer on stack |
| 5759 | #ifdef TCC_TARGET_ARM |
| 5760 | vpushi(2*PTR_SIZE); |
| 5761 | gen_op('+'); |
| 5762 | #elif defined TCC_TARGET_RISCV64 |
| 5763 | vpushi(PTR_SIZE); |
| 5764 | gen_op('-'); |
| 5765 | #else |
| 5766 | vpushi(PTR_SIZE); |
| 5767 | gen_op('+'); |
| 5768 | #endif |
| 5769 | mk_pointer(&vtop->type); |
| 5770 | indir(); |
| 5771 | } |
| 5772 | } |
| 5773 | break; |
| 5774 | #ifdef TCC_TARGET_RISCV64 |
| 5775 | case TOK_builtin_va_start: |
| 5776 | parse_builtin_params(0, "ee" ); |
| 5777 | r = vtop->r & VT_VALMASK; |
| 5778 | if (r == VT_LLOCAL) |
| 5779 | r = VT_LOCAL; |
| 5780 | if (r != VT_LOCAL) |
| 5781 | tcc_error("__builtin_va_start expects a local variable" ); |
| 5782 | gen_va_start(); |
| 5783 | vstore(); |
| 5784 | break; |
| 5785 | #endif |
| 5786 | #ifdef TCC_TARGET_X86_64 |
| 5787 | #ifdef TCC_TARGET_PE |
| 5788 | case TOK_builtin_va_start: |
| 5789 | parse_builtin_params(0, "ee" ); |
| 5790 | r = vtop->r & VT_VALMASK; |
| 5791 | if (r == VT_LLOCAL) |
| 5792 | r = VT_LOCAL; |
| 5793 | if (r != VT_LOCAL) |
| 5794 | tcc_error("__builtin_va_start expects a local variable" ); |
| 5795 | vtop->r = r; |
| 5796 | vtop->type = char_pointer_type; |
| 5797 | vtop->c.i += 8; |
| 5798 | vstore(); |
| 5799 | break; |
| 5800 | #else |
| 5801 | case TOK_builtin_va_arg_types: |
| 5802 | parse_builtin_params(0, "t" ); |
| 5803 | vpushi(classify_x86_64_va_arg(&vtop->type)); |
| 5804 | vswap(); |
| 5805 | vpop(); |
| 5806 | break; |
| 5807 | #endif |
| 5808 | #endif |
| 5809 | |
| 5810 | #ifdef TCC_TARGET_ARM64 |
| 5811 | case TOK_builtin_va_start: { |
| 5812 | parse_builtin_params(0, "ee" ); |
| 5813 | //xx check types |
| 5814 | gen_va_start(); |
| 5815 | vpushi(0); |
| 5816 | vtop->type.t = VT_VOID; |
| 5817 | break; |
| 5818 | } |
| 5819 | case TOK_builtin_va_arg: { |
| 5820 | parse_builtin_params(0, "et" ); |
| 5821 | type = vtop->type; |
| 5822 | vpop(); |
| 5823 | //xx check types |
| 5824 | gen_va_arg(&type); |
| 5825 | vtop->type = type; |
| 5826 | break; |
| 5827 | } |
| 5828 | case TOK___arm64_clear_cache: { |
| 5829 | parse_builtin_params(0, "ee" ); |
| 5830 | gen_clear_cache(); |
| 5831 | vpushi(0); |
| 5832 | vtop->type.t = VT_VOID; |
| 5833 | break; |
| 5834 | } |
| 5835 | #endif |
| 5836 | |
| 5837 | /* pre operations */ |
| 5838 | case TOK_INC: |
| 5839 | case TOK_DEC: |
| 5840 | t = tok; |
| 5841 | next(); |
| 5842 | unary(); |
| 5843 | inc(0, t); |
| 5844 | break; |
| 5845 | case '-': |
| 5846 | next(); |
| 5847 | unary(); |
| 5848 | t = vtop->type.t & VT_BTYPE; |
| 5849 | if (is_float(t)) { |
| 5850 | /* In IEEE negate(x) isn't subtract(0,x), but rather |
| 5851 | subtract(-0, x). */ |
| 5852 | vpush(&vtop->type); |
| 5853 | if (t == VT_FLOAT) |
| 5854 | vtop->c.f = -1.0 * 0.0; |
| 5855 | else if (t == VT_DOUBLE) |
| 5856 | vtop->c.d = -1.0 * 0.0; |
| 5857 | else |
| 5858 | vtop->c.ld = -1.0 * 0.0; |
| 5859 | } else |
| 5860 | vpushi(0); |
| 5861 | vswap(); |
| 5862 | gen_op('-'); |
| 5863 | break; |
| 5864 | case TOK_LAND: |
| 5865 | if (!gnu_ext) |
| 5866 | goto tok_identifier; |
| 5867 | next(); |
| 5868 | /* allow to take the address of a label */ |
| 5869 | if (tok < TOK_UIDENT) |
| 5870 | expect("label identifier" ); |
| 5871 | s = label_find(tok); |
| 5872 | if (!s) { |
| 5873 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
| 5874 | } else { |
| 5875 | if (s->r == LABEL_DECLARED) |
| 5876 | s->r = LABEL_FORWARD; |
| 5877 | } |
| 5878 | if (!s->type.t) { |
| 5879 | s->type.t = VT_VOID; |
| 5880 | mk_pointer(&s->type); |
| 5881 | s->type.t |= VT_STATIC; |
| 5882 | } |
| 5883 | vpushsym(&s->type, s); |
| 5884 | next(); |
| 5885 | break; |
| 5886 | |
| 5887 | case TOK_GENERIC: |
| 5888 | { |
| 5889 | CType controlling_type; |
| 5890 | int has_default = 0; |
| 5891 | int has_match = 0; |
| 5892 | int learn = 0; |
| 5893 | TokenString *str = NULL; |
| 5894 | int saved_const_wanted = const_wanted; |
| 5895 | |
| 5896 | next(); |
| 5897 | skip('('); |
| 5898 | const_wanted = 0; |
| 5899 | expr_type(&controlling_type, expr_eq); |
| 5900 | controlling_type.t &= ~(VT_CONSTANT | VT_VOLATILE | VT_ARRAY); |
| 5901 | if ((controlling_type.t & VT_BTYPE) == VT_FUNC) |
| 5902 | mk_pointer(&controlling_type); |
| 5903 | const_wanted = saved_const_wanted; |
| 5904 | for (;;) { |
| 5905 | learn = 0; |
| 5906 | skip(','); |
| 5907 | if (tok == TOK_DEFAULT) { |
| 5908 | if (has_default) |
| 5909 | tcc_error("too many 'default'" ); |
| 5910 | has_default = 1; |
| 5911 | if (!has_match) |
| 5912 | learn = 1; |
| 5913 | next(); |
| 5914 | } else { |
| 5915 | AttributeDef ad_tmp; |
| 5916 | int itmp; |
| 5917 | CType cur_type; |
| 5918 | |
| 5919 | in_generic++; |
| 5920 | parse_btype(&cur_type, &ad_tmp); |
| 5921 | in_generic--; |
| 5922 | |
| 5923 | type_decl(&cur_type, &ad_tmp, &itmp, TYPE_ABSTRACT); |
| 5924 | if (compare_types(&controlling_type, &cur_type, 0)) { |
| 5925 | if (has_match) { |
| 5926 | tcc_error("type match twice" ); |
| 5927 | } |
| 5928 | has_match = 1; |
| 5929 | learn = 1; |
| 5930 | } |
| 5931 | } |
| 5932 | skip(':'); |
| 5933 | if (learn) { |
| 5934 | if (str) |
| 5935 | tok_str_free(str); |
| 5936 | skip_or_save_block(&str); |
| 5937 | } else { |
| 5938 | skip_or_save_block(NULL); |
| 5939 | } |
| 5940 | if (tok == ')') |
| 5941 | break; |
| 5942 | } |
| 5943 | if (!str) { |
| 5944 | char buf[60]; |
| 5945 | type_to_str(buf, sizeof buf, &controlling_type, NULL); |
| 5946 | tcc_error("type '%s' does not match any association" , buf); |
| 5947 | } |
| 5948 | begin_macro(str, 1); |
| 5949 | next(); |
| 5950 | expr_eq(); |
| 5951 | if (tok != TOK_EOF) |
| 5952 | expect("," ); |
| 5953 | end_macro(); |
| 5954 | next(); |
| 5955 | break; |
| 5956 | } |
| 5957 | // special qnan , snan and infinity values |
| 5958 | case TOK___NAN__: |
| 5959 | n = 0x7fc00000; |
| 5960 | special_math_val: |
| 5961 | vpushi(n); |
| 5962 | vtop->type.t = VT_FLOAT; |
| 5963 | next(); |
| 5964 | break; |
| 5965 | case TOK___SNAN__: |
| 5966 | n = 0x7f800001; |
| 5967 | goto special_math_val; |
| 5968 | case TOK___INF__: |
| 5969 | n = 0x7f800000; |
| 5970 | goto special_math_val; |
| 5971 | |
| 5972 | default: |
| 5973 | tok_identifier: |
| 5974 | t = tok; |
| 5975 | next(); |
| 5976 | if (t < TOK_UIDENT) |
| 5977 | expect("identifier" ); |
| 5978 | s = sym_find(t); |
| 5979 | if (!s || IS_ASM_SYM(s)) { |
| 5980 | const char *name = get_tok_str(t, NULL); |
| 5981 | if (tok != '(') |
| 5982 | tcc_error("'%s' undeclared" , name); |
| 5983 | /* for simple function calls, we tolerate undeclared |
| 5984 | external reference to int() function */ |
| 5985 | if (tcc_state->warn_implicit_function_declaration |
| 5986 | #ifdef TCC_TARGET_PE |
| 5987 | /* people must be warned about using undeclared WINAPI functions |
| 5988 | (which usually start with uppercase letter) */ |
| 5989 | || (name[0] >= 'A' && name[0] <= 'Z') |
| 5990 | #endif |
| 5991 | ) |
| 5992 | tcc_warning("implicit declaration of function '%s'" , name); |
| 5993 | s = external_global_sym(t, &func_old_type); |
| 5994 | } |
| 5995 | |
| 5996 | r = s->r; |
| 5997 | /* A symbol that has a register is a local register variable, |
| 5998 | which starts out as VT_LOCAL value. */ |
| 5999 | if ((r & VT_VALMASK) < VT_CONST) |
| 6000 | r = (r & ~VT_VALMASK) | VT_LOCAL; |
| 6001 | |
| 6002 | vset(&s->type, r, s->c); |
| 6003 | /* Point to s as backpointer (even without r&VT_SYM). |
| 6004 | Will be used by at least the x86 inline asm parser for |
| 6005 | regvars. */ |
| 6006 | vtop->sym = s; |
| 6007 | |
| 6008 | if (r & VT_SYM) { |
| 6009 | vtop->c.i = 0; |
| 6010 | } else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) { |
| 6011 | vtop->c.i = s->enum_val; |
| 6012 | } |
| 6013 | break; |
| 6014 | } |
| 6015 | |
| 6016 | /* post operations */ |
| 6017 | while (1) { |
| 6018 | if (tok == TOK_INC || tok == TOK_DEC) { |
| 6019 | inc(1, tok); |
| 6020 | next(); |
| 6021 | } else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) { |
| 6022 | int qualifiers, cumofs = 0; |
| 6023 | /* field */ |
| 6024 | if (tok == TOK_ARROW) |
| 6025 | indir(); |
| 6026 | qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); |
| 6027 | test_lvalue(); |
| 6028 | gaddrof(); |
| 6029 | /* expect pointer on structure */ |
| 6030 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
| 6031 | expect("struct or union" ); |
| 6032 | if (tok == TOK_CDOUBLE) |
| 6033 | expect("field name" ); |
| 6034 | next(); |
| 6035 | if (tok == TOK_CINT || tok == TOK_CUINT) |
| 6036 | expect("field name" ); |
| 6037 | s = find_field(&vtop->type, tok, &cumofs); |
| 6038 | if (!s) |
| 6039 | tcc_error("field not found: %s" , get_tok_str(tok & ~SYM_FIELD, &tokc)); |
| 6040 | /* add field offset to pointer */ |
| 6041 | vtop->type = char_pointer_type; /* change type to 'char *' */ |
| 6042 | vpushi(cumofs + s->c); |
| 6043 | gen_op('+'); |
| 6044 | /* change type to field type, and set to lvalue */ |
| 6045 | vtop->type = s->type; |
| 6046 | vtop->type.t |= qualifiers; |
| 6047 | /* an array is never an lvalue */ |
| 6048 | if (!(vtop->type.t & VT_ARRAY)) { |
| 6049 | vtop->r |= VT_LVAL; |
| 6050 | #ifdef CONFIG_TCC_BCHECK |
| 6051 | /* if bound checking, the referenced pointer must be checked */ |
| 6052 | if (tcc_state->do_bounds_check) |
| 6053 | vtop->r |= VT_MUSTBOUND; |
| 6054 | #endif |
| 6055 | } |
| 6056 | next(); |
| 6057 | } else if (tok == '[') { |
| 6058 | next(); |
| 6059 | gexpr(); |
| 6060 | gen_op('+'); |
| 6061 | indir(); |
| 6062 | skip(']'); |
| 6063 | } else if (tok == '(') { |
| 6064 | SValue ret; |
| 6065 | Sym *sa; |
| 6066 | int nb_args, ret_nregs, ret_align, regsize, variadic; |
| 6067 | |
| 6068 | /* function call */ |
| 6069 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { |
| 6070 | /* pointer test (no array accepted) */ |
| 6071 | if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { |
| 6072 | vtop->type = *pointed_type(&vtop->type); |
| 6073 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) |
| 6074 | goto error_func; |
| 6075 | } else { |
| 6076 | error_func: |
| 6077 | expect("function pointer" ); |
| 6078 | } |
| 6079 | } else { |
| 6080 | vtop->r &= ~VT_LVAL; /* no lvalue */ |
| 6081 | } |
| 6082 | /* get return type */ |
| 6083 | s = vtop->type.ref; |
| 6084 | next(); |
| 6085 | sa = s->next; /* first parameter */ |
| 6086 | nb_args = regsize = 0; |
| 6087 | ret.r2 = VT_CONST; |
| 6088 | /* compute first implicit argument if a structure is returned */ |
| 6089 | if ((s->type.t & VT_BTYPE) == VT_STRUCT) { |
| 6090 | variadic = (s->f.func_type == FUNC_ELLIPSIS); |
| 6091 | ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, |
| 6092 | &ret_align, ®size); |
| 6093 | if (ret_nregs <= 0) { |
| 6094 | /* get some space for the returned structure */ |
| 6095 | size = type_size(&s->type, &align); |
| 6096 | #ifdef TCC_TARGET_ARM64 |
| 6097 | /* On arm64, a small struct is return in registers. |
| 6098 | It is much easier to write it to memory if we know |
| 6099 | that we are allowed to write some extra bytes, so |
| 6100 | round the allocated space up to a power of 2: */ |
| 6101 | if (size < 16) |
| 6102 | while (size & (size - 1)) |
| 6103 | size = (size | (size - 1)) + 1; |
| 6104 | #endif |
| 6105 | loc = (loc - size) & -align; |
| 6106 | ret.type = s->type; |
| 6107 | ret.r = VT_LOCAL | VT_LVAL; |
| 6108 | /* pass it as 'int' to avoid structure arg passing |
| 6109 | problems */ |
| 6110 | vseti(VT_LOCAL, loc); |
| 6111 | #ifdef CONFIG_TCC_BCHECK |
| 6112 | if (tcc_state->do_bounds_check) |
| 6113 | --loc; |
| 6114 | #endif |
| 6115 | ret.c = vtop->c; |
| 6116 | if (ret_nregs < 0) |
| 6117 | vtop--; |
| 6118 | else |
| 6119 | nb_args++; |
| 6120 | } |
| 6121 | } else { |
| 6122 | ret_nregs = 1; |
| 6123 | ret.type = s->type; |
| 6124 | } |
| 6125 | |
| 6126 | if (ret_nregs > 0) { |
| 6127 | /* return in register */ |
| 6128 | ret.c.i = 0; |
| 6129 | PUT_R_RET(&ret, ret.type.t); |
| 6130 | } |
| 6131 | if (tok != ')') { |
| 6132 | for(;;) { |
| 6133 | expr_eq(); |
| 6134 | gfunc_param_typed(s, sa); |
| 6135 | nb_args++; |
| 6136 | if (sa) |
| 6137 | sa = sa->next; |
| 6138 | if (tok == ')') |
| 6139 | break; |
| 6140 | skip(','); |
| 6141 | } |
| 6142 | } |
| 6143 | if (sa) |
| 6144 | tcc_error("too few arguments to function" ); |
| 6145 | skip(')'); |
| 6146 | gfunc_call(nb_args); |
| 6147 | |
| 6148 | if (ret_nregs < 0) { |
| 6149 | vsetc(&ret.type, ret.r, &ret.c); |
| 6150 | #ifdef TCC_TARGET_RISCV64 |
| 6151 | arch_transfer_ret_regs(1); |
| 6152 | #endif |
| 6153 | } else { |
| 6154 | /* return value */ |
| 6155 | for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { |
| 6156 | vsetc(&ret.type, r, &ret.c); |
| 6157 | vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */ |
| 6158 | } |
| 6159 | |
| 6160 | /* handle packed struct return */ |
| 6161 | if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { |
| 6162 | int addr, offset; |
| 6163 | |
| 6164 | size = type_size(&s->type, &align); |
| 6165 | /* We're writing whole regs often, make sure there's enough |
| 6166 | space. Assume register size is power of 2. */ |
| 6167 | if (regsize > align) |
| 6168 | align = regsize; |
| 6169 | loc = (loc - size) & -align; |
| 6170 | addr = loc; |
| 6171 | offset = 0; |
| 6172 | for (;;) { |
| 6173 | vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); |
| 6174 | vswap(); |
| 6175 | vstore(); |
| 6176 | vtop--; |
| 6177 | if (--ret_nregs == 0) |
| 6178 | break; |
| 6179 | offset += regsize; |
| 6180 | } |
| 6181 | vset(&s->type, VT_LOCAL | VT_LVAL, addr); |
| 6182 | } |
| 6183 | |
| 6184 | /* Promote char/short return values. This is matters only |
| 6185 | for calling function that were not compiled by TCC and |
| 6186 | only on some architectures. For those where it doesn't |
| 6187 | matter we expect things to be already promoted to int, |
| 6188 | but not larger. */ |
| 6189 | t = s->type.t & VT_BTYPE; |
| 6190 | if (t == VT_BYTE || t == VT_SHORT || t == VT_BOOL) { |
| 6191 | #ifdef PROMOTE_RET |
| 6192 | vtop->r |= BFVAL(VT_MUSTCAST, 1); |
| 6193 | #else |
| 6194 | vtop->type.t = VT_INT; |
| 6195 | #endif |
| 6196 | } |
| 6197 | } |
| 6198 | if (s->f.func_noreturn) |
| 6199 | CODE_OFF(); |
| 6200 | } else { |
| 6201 | break; |
| 6202 | } |
| 6203 | } |
| 6204 | } |
| 6205 | |
| 6206 | #ifndef precedence_parser /* original top-down parser */ |
| 6207 | |
| 6208 | static void expr_prod(void) |
| 6209 | { |
| 6210 | int t; |
| 6211 | |
| 6212 | unary(); |
| 6213 | while ((t = tok) == '*' || t == '/' || t == '%') { |
| 6214 | next(); |
| 6215 | unary(); |
| 6216 | gen_op(t); |
| 6217 | } |
| 6218 | } |
| 6219 | |
| 6220 | static void expr_sum(void) |
| 6221 | { |
| 6222 | int t; |
| 6223 | |
| 6224 | expr_prod(); |
| 6225 | while ((t = tok) == '+' || t == '-') { |
| 6226 | next(); |
| 6227 | expr_prod(); |
| 6228 | gen_op(t); |
| 6229 | } |
| 6230 | } |
| 6231 | |
| 6232 | static void expr_shift(void) |
| 6233 | { |
| 6234 | int t; |
| 6235 | |
| 6236 | expr_sum(); |
| 6237 | while ((t = tok) == TOK_SHL || t == TOK_SAR) { |
| 6238 | next(); |
| 6239 | expr_sum(); |
| 6240 | gen_op(t); |
| 6241 | } |
| 6242 | } |
| 6243 | |
| 6244 | static void expr_cmp(void) |
| 6245 | { |
| 6246 | int t; |
| 6247 | |
| 6248 | expr_shift(); |
| 6249 | while (((t = tok) >= TOK_ULE && t <= TOK_GT) || |
| 6250 | t == TOK_ULT || t == TOK_UGE) { |
| 6251 | next(); |
| 6252 | expr_shift(); |
| 6253 | gen_op(t); |
| 6254 | } |
| 6255 | } |
| 6256 | |
| 6257 | static void expr_cmpeq(void) |
| 6258 | { |
| 6259 | int t; |
| 6260 | |
| 6261 | expr_cmp(); |
| 6262 | while ((t = tok) == TOK_EQ || t == TOK_NE) { |
| 6263 | next(); |
| 6264 | expr_cmp(); |
| 6265 | gen_op(t); |
| 6266 | } |
| 6267 | } |
| 6268 | |
| 6269 | static void expr_and(void) |
| 6270 | { |
| 6271 | expr_cmpeq(); |
| 6272 | while (tok == '&') { |
| 6273 | next(); |
| 6274 | expr_cmpeq(); |
| 6275 | gen_op('&'); |
| 6276 | } |
| 6277 | } |
| 6278 | |
| 6279 | static void expr_xor(void) |
| 6280 | { |
| 6281 | expr_and(); |
| 6282 | while (tok == '^') { |
| 6283 | next(); |
| 6284 | expr_and(); |
| 6285 | gen_op('^'); |
| 6286 | } |
| 6287 | } |
| 6288 | |
| 6289 | static void expr_or(void) |
| 6290 | { |
| 6291 | expr_xor(); |
| 6292 | while (tok == '|') { |
| 6293 | next(); |
| 6294 | expr_xor(); |
| 6295 | gen_op('|'); |
| 6296 | } |
| 6297 | } |
| 6298 | |
| 6299 | static void expr_landor(int op); |
| 6300 | |
| 6301 | static void expr_land(void) |
| 6302 | { |
| 6303 | expr_or(); |
| 6304 | if (tok == TOK_LAND) |
| 6305 | expr_landor(tok); |
| 6306 | } |
| 6307 | |
| 6308 | static void expr_lor(void) |
| 6309 | { |
| 6310 | expr_land(); |
| 6311 | if (tok == TOK_LOR) |
| 6312 | expr_landor(tok); |
| 6313 | } |
| 6314 | |
| 6315 | # define expr_landor_next(op) op == TOK_LAND ? expr_or() : expr_land() |
| 6316 | #else /* defined precedence_parser */ |
| 6317 | # define expr_landor_next(op) unary(), expr_infix(precedence(op) + 1) |
| 6318 | # define expr_lor() unary(), expr_infix(1) |
| 6319 | |
| 6320 | static int precedence(int tok) |
| 6321 | { |
| 6322 | switch (tok) { |
| 6323 | case TOK_LOR: return 1; |
| 6324 | case TOK_LAND: return 2; |
| 6325 | case '|': return 3; |
| 6326 | case '^': return 4; |
| 6327 | case '&': return 5; |
| 6328 | case TOK_EQ: case TOK_NE: return 6; |
| 6329 | relat: case TOK_ULT: case TOK_UGE: return 7; |
| 6330 | case TOK_SHL: case TOK_SAR: return 8; |
| 6331 | case '+': case '-': return 9; |
| 6332 | case '*': case '/': case '%': return 10; |
| 6333 | default: |
| 6334 | if (tok >= TOK_ULE && tok <= TOK_GT) |
| 6335 | goto relat; |
| 6336 | return 0; |
| 6337 | } |
| 6338 | } |
| 6339 | static unsigned char prec[256]; |
| 6340 | static void init_prec(void) |
| 6341 | { |
| 6342 | int i; |
| 6343 | for (i = 0; i < 256; i++) |
| 6344 | prec[i] = precedence(i); |
| 6345 | } |
| 6346 | #define precedence(i) ((unsigned)i < 256 ? prec[i] : 0) |
| 6347 | |
| 6348 | static void expr_landor(int op); |
| 6349 | |
| 6350 | static void expr_infix(int p) |
| 6351 | { |
| 6352 | int t = tok, p2; |
| 6353 | while ((p2 = precedence(t)) >= p) { |
| 6354 | if (t == TOK_LOR || t == TOK_LAND) { |
| 6355 | expr_landor(t); |
| 6356 | } else { |
| 6357 | next(); |
| 6358 | unary(); |
| 6359 | if (precedence(tok) > p2) |
| 6360 | expr_infix(p2 + 1); |
| 6361 | gen_op(t); |
| 6362 | } |
| 6363 | t = tok; |
| 6364 | } |
| 6365 | } |
| 6366 | #endif |
| 6367 | |
| 6368 | /* Assuming vtop is a value used in a conditional context |
| 6369 | (i.e. compared with zero) return 0 if it's false, 1 if |
| 6370 | true and -1 if it can't be statically determined. */ |
| 6371 | static int condition_3way(void) |
| 6372 | { |
| 6373 | int c = -1; |
| 6374 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST && |
| 6375 | (!(vtop->r & VT_SYM) || !vtop->sym->a.weak)) { |
| 6376 | vdup(); |
| 6377 | gen_cast_s(VT_BOOL); |
| 6378 | c = vtop->c.i; |
| 6379 | vpop(); |
| 6380 | } |
| 6381 | return c; |
| 6382 | } |
| 6383 | |
| 6384 | static void expr_landor(int op) |
| 6385 | { |
| 6386 | int t = 0, cc = 1, f = 0, i = op == TOK_LAND, c; |
| 6387 | for(;;) { |
| 6388 | c = f ? i : condition_3way(); |
| 6389 | if (c < 0) |
| 6390 | save_regs(1), cc = 0; |
| 6391 | else if (c != i) |
| 6392 | nocode_wanted++, f = 1; |
| 6393 | if (tok != op) |
| 6394 | break; |
| 6395 | if (c < 0) |
| 6396 | t = gvtst(i, t); |
| 6397 | else |
| 6398 | vpop(); |
| 6399 | next(); |
| 6400 | expr_landor_next(op); |
| 6401 | } |
| 6402 | if (cc || f) { |
| 6403 | vpop(); |
| 6404 | vpushi(i ^ f); |
| 6405 | gsym(t); |
| 6406 | nocode_wanted -= f; |
| 6407 | } else { |
| 6408 | gvtst_set(i, t); |
| 6409 | } |
| 6410 | } |
| 6411 | |
| 6412 | static int is_cond_bool(SValue *sv) |
| 6413 | { |
| 6414 | if ((sv->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST |
| 6415 | && (sv->type.t & VT_BTYPE) == VT_INT) |
| 6416 | return (unsigned)sv->c.i < 2; |
| 6417 | if (sv->r == VT_CMP) |
| 6418 | return 1; |
| 6419 | return 0; |
| 6420 | } |
| 6421 | |
| 6422 | static void expr_cond(void) |
| 6423 | { |
| 6424 | int tt, u, r1, r2, rc, t1, t2, islv, c, g; |
| 6425 | SValue sv; |
| 6426 | CType type; |
| 6427 | int ncw_prev; |
| 6428 | |
| 6429 | expr_lor(); |
| 6430 | if (tok == '?') { |
| 6431 | next(); |
| 6432 | c = condition_3way(); |
| 6433 | g = (tok == ':' && gnu_ext); |
| 6434 | tt = 0; |
| 6435 | if (!g) { |
| 6436 | if (c < 0) { |
| 6437 | save_regs(1); |
| 6438 | tt = gvtst(1, 0); |
| 6439 | } else { |
| 6440 | vpop(); |
| 6441 | } |
| 6442 | } else if (c < 0) { |
| 6443 | /* needed to avoid having different registers saved in |
| 6444 | each branch */ |
| 6445 | save_regs(1); |
| 6446 | gv_dup(); |
| 6447 | tt = gvtst(0, 0); |
| 6448 | } |
| 6449 | |
| 6450 | ncw_prev = nocode_wanted; |
| 6451 | if (c == 0) |
| 6452 | nocode_wanted++; |
| 6453 | if (!g) |
| 6454 | gexpr(); |
| 6455 | |
| 6456 | if (c < 0 && vtop->r == VT_CMP) { |
| 6457 | t1 = gvtst(0, 0); |
| 6458 | vpushi(0); |
| 6459 | gvtst_set(0, t1); |
| 6460 | gv(RC_INT); |
| 6461 | } |
| 6462 | |
| 6463 | if ((vtop->type.t & VT_BTYPE) == VT_FUNC) |
| 6464 | mk_pointer(&vtop->type); |
| 6465 | sv = *vtop; /* save value to handle it later */ |
| 6466 | vtop--; /* no vpop so that FP stack is not flushed */ |
| 6467 | |
| 6468 | if (g) { |
| 6469 | u = tt; |
| 6470 | } else if (c < 0) { |
| 6471 | u = gjmp(0); |
| 6472 | gsym(tt); |
| 6473 | } else |
| 6474 | u = 0; |
| 6475 | |
| 6476 | nocode_wanted = ncw_prev; |
| 6477 | if (c == 1) |
| 6478 | nocode_wanted++; |
| 6479 | skip(':'); |
| 6480 | expr_cond(); |
| 6481 | |
| 6482 | if (c < 0 && is_cond_bool(vtop) && is_cond_bool(&sv)) { |
| 6483 | if (sv.r == VT_CMP) { |
| 6484 | t1 = sv.jtrue; |
| 6485 | t2 = u; |
| 6486 | } else { |
| 6487 | t1 = gvtst(0, 0); |
| 6488 | t2 = gjmp(0); |
| 6489 | gsym(u); |
| 6490 | vpushv(&sv); |
| 6491 | } |
| 6492 | gvtst_set(0, t1); |
| 6493 | gvtst_set(1, t2); |
| 6494 | nocode_wanted = ncw_prev; |
| 6495 | // tcc_warning("two conditions expr_cond"); |
| 6496 | return; |
| 6497 | } |
| 6498 | |
| 6499 | if ((vtop->type.t & VT_BTYPE) == VT_FUNC) |
| 6500 | mk_pointer(&vtop->type); |
| 6501 | |
| 6502 | /* cast operands to correct type according to ISOC rules */ |
| 6503 | if (!combine_types(&type, &sv, vtop, '?')) |
| 6504 | type_incompatibility_error(&sv.type, &vtop->type, |
| 6505 | "type mismatch in conditional expression (have '%s' and '%s')" ); |
| 6506 | /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so |
| 6507 | that `(expr ? a : b).mem` does not error with "lvalue expected" */ |
| 6508 | islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE); |
| 6509 | |
| 6510 | /* now we convert second operand */ |
| 6511 | if (c != 1) { |
| 6512 | gen_cast(&type); |
| 6513 | if (islv) { |
| 6514 | mk_pointer(&vtop->type); |
| 6515 | gaddrof(); |
| 6516 | } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) |
| 6517 | gaddrof(); |
| 6518 | } |
| 6519 | |
| 6520 | rc = RC_TYPE(type.t); |
| 6521 | /* for long longs, we use fixed registers to avoid having |
| 6522 | to handle a complicated move */ |
| 6523 | if (USING_TWO_WORDS(type.t)) |
| 6524 | rc = RC_RET(type.t); |
| 6525 | |
| 6526 | tt = r2 = 0; |
| 6527 | if (c < 0) { |
| 6528 | r2 = gv(rc); |
| 6529 | tt = gjmp(0); |
| 6530 | } |
| 6531 | gsym(u); |
| 6532 | nocode_wanted = ncw_prev; |
| 6533 | |
| 6534 | /* this is horrible, but we must also convert first |
| 6535 | operand */ |
| 6536 | if (c != 0) { |
| 6537 | *vtop = sv; |
| 6538 | gen_cast(&type); |
| 6539 | if (islv) { |
| 6540 | mk_pointer(&vtop->type); |
| 6541 | gaddrof(); |
| 6542 | } else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) |
| 6543 | gaddrof(); |
| 6544 | } |
| 6545 | |
| 6546 | if (c < 0) { |
| 6547 | r1 = gv(rc); |
| 6548 | move_reg(r2, r1, islv ? VT_PTR : type.t); |
| 6549 | vtop->r = r2; |
| 6550 | gsym(tt); |
| 6551 | } |
| 6552 | |
| 6553 | if (islv) |
| 6554 | indir(); |
| 6555 | } |
| 6556 | } |
| 6557 | |
| 6558 | static void expr_eq(void) |
| 6559 | { |
| 6560 | int t; |
| 6561 | |
| 6562 | expr_cond(); |
| 6563 | if ((t = tok) == '=' || TOK_ASSIGN(t)) { |
| 6564 | test_lvalue(); |
| 6565 | next(); |
| 6566 | if (t == '=') { |
| 6567 | expr_eq(); |
| 6568 | } else { |
| 6569 | vdup(); |
| 6570 | expr_eq(); |
| 6571 | gen_op(TOK_ASSIGN_OP(t)); |
| 6572 | } |
| 6573 | vstore(); |
| 6574 | } |
| 6575 | } |
| 6576 | |
| 6577 | ST_FUNC void gexpr(void) |
| 6578 | { |
| 6579 | while (1) { |
| 6580 | expr_eq(); |
| 6581 | if (tok != ',') |
| 6582 | break; |
| 6583 | vpop(); |
| 6584 | next(); |
| 6585 | } |
| 6586 | } |
| 6587 | |
| 6588 | /* parse a constant expression and return value in vtop. */ |
| 6589 | static void expr_const1(void) |
| 6590 | { |
| 6591 | const_wanted++; |
| 6592 | nocode_wanted += unevalmask + 1; |
| 6593 | expr_cond(); |
| 6594 | nocode_wanted -= unevalmask + 1; |
| 6595 | const_wanted--; |
| 6596 | } |
| 6597 | |
| 6598 | /* parse an integer constant and return its value. */ |
| 6599 | static inline int64_t expr_const64(void) |
| 6600 | { |
| 6601 | int64_t c; |
| 6602 | expr_const1(); |
| 6603 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
| 6604 | expect("constant expression" ); |
| 6605 | c = vtop->c.i; |
| 6606 | vpop(); |
| 6607 | return c; |
| 6608 | } |
| 6609 | |
| 6610 | /* parse an integer constant and return its value. |
| 6611 | Complain if it doesn't fit 32bit (signed or unsigned). */ |
| 6612 | ST_FUNC int expr_const(void) |
| 6613 | { |
| 6614 | int c; |
| 6615 | int64_t wc = expr_const64(); |
| 6616 | c = wc; |
| 6617 | if (c != wc && (unsigned)c != wc) |
| 6618 | tcc_error("constant exceeds 32 bit" ); |
| 6619 | return c; |
| 6620 | } |
| 6621 | |
| 6622 | /* ------------------------------------------------------------------------- */ |
| 6623 | /* return from function */ |
| 6624 | |
| 6625 | #ifndef TCC_TARGET_ARM64 |
| 6626 | static void gfunc_return(CType *func_type) |
| 6627 | { |
| 6628 | if ((func_type->t & VT_BTYPE) == VT_STRUCT) { |
| 6629 | CType type, ret_type; |
| 6630 | int ret_align, ret_nregs, regsize; |
| 6631 | ret_nregs = gfunc_sret(func_type, func_var, &ret_type, |
| 6632 | &ret_align, ®size); |
| 6633 | if (ret_nregs < 0) { |
| 6634 | #ifdef TCC_TARGET_RISCV64 |
| 6635 | arch_transfer_ret_regs(0); |
| 6636 | #endif |
| 6637 | } else if (0 == ret_nregs) { |
| 6638 | /* if returning structure, must copy it to implicit |
| 6639 | first pointer arg location */ |
| 6640 | type = *func_type; |
| 6641 | mk_pointer(&type); |
| 6642 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
| 6643 | indir(); |
| 6644 | vswap(); |
| 6645 | /* copy structure value to pointer */ |
| 6646 | vstore(); |
| 6647 | } else { |
| 6648 | /* returning structure packed into registers */ |
| 6649 | int size, addr, align, rc; |
| 6650 | size = type_size(func_type,&align); |
| 6651 | if ((vtop->r != (VT_LOCAL | VT_LVAL) || |
| 6652 | (vtop->c.i & (ret_align-1))) |
| 6653 | && (align & (ret_align-1))) { |
| 6654 | loc = (loc - size) & -ret_align; |
| 6655 | addr = loc; |
| 6656 | type = *func_type; |
| 6657 | vset(&type, VT_LOCAL | VT_LVAL, addr); |
| 6658 | vswap(); |
| 6659 | vstore(); |
| 6660 | vpop(); |
| 6661 | vset(&ret_type, VT_LOCAL | VT_LVAL, addr); |
| 6662 | } |
| 6663 | vtop->type = ret_type; |
| 6664 | rc = RC_RET(ret_type.t); |
| 6665 | if (ret_nregs == 1) |
| 6666 | gv(rc); |
| 6667 | else { |
| 6668 | for (;;) { |
| 6669 | vdup(); |
| 6670 | gv(rc); |
| 6671 | vpop(); |
| 6672 | if (--ret_nregs == 0) |
| 6673 | break; |
| 6674 | /* We assume that when a structure is returned in multiple |
| 6675 | registers, their classes are consecutive values of the |
| 6676 | suite s(n) = 2^n */ |
| 6677 | rc <<= 1; |
| 6678 | vtop->c.i += regsize; |
| 6679 | } |
| 6680 | } |
| 6681 | } |
| 6682 | } else { |
| 6683 | gv(RC_RET(func_type->t)); |
| 6684 | } |
| 6685 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
| 6686 | } |
| 6687 | #endif |
| 6688 | |
| 6689 | static void check_func_return(void) |
| 6690 | { |
| 6691 | if ((func_vt.t & VT_BTYPE) == VT_VOID) |
| 6692 | return; |
| 6693 | if (!strcmp (funcname, "main" ) |
| 6694 | && (func_vt.t & VT_BTYPE) == VT_INT) { |
| 6695 | /* main returns 0 by default */ |
| 6696 | vpushi(0); |
| 6697 | gen_assign_cast(&func_vt); |
| 6698 | gfunc_return(&func_vt); |
| 6699 | } else { |
| 6700 | tcc_warning("function might return no value: '%s'" , funcname); |
| 6701 | } |
| 6702 | } |
| 6703 | |
| 6704 | /* ------------------------------------------------------------------------- */ |
| 6705 | /* switch/case */ |
| 6706 | |
| 6707 | static int case_cmpi(const void *pa, const void *pb) |
| 6708 | { |
| 6709 | int64_t a = (*(struct case_t**) pa)->v1; |
| 6710 | int64_t b = (*(struct case_t**) pb)->v1; |
| 6711 | return a < b ? -1 : a > b; |
| 6712 | } |
| 6713 | |
| 6714 | static int case_cmpu(const void *pa, const void *pb) |
| 6715 | { |
| 6716 | uint64_t a = (uint64_t)(*(struct case_t**) pa)->v1; |
| 6717 | uint64_t b = (uint64_t)(*(struct case_t**) pb)->v1; |
| 6718 | return a < b ? -1 : a > b; |
| 6719 | } |
| 6720 | |
| 6721 | static void gtst_addr(int t, int a) |
| 6722 | { |
| 6723 | gsym_addr(gvtst(0, t), a); |
| 6724 | } |
| 6725 | |
| 6726 | static void gcase(struct case_t **base, int len, int *bsym) |
| 6727 | { |
| 6728 | struct case_t *p; |
| 6729 | int e; |
| 6730 | int ll = (vtop->type.t & VT_BTYPE) == VT_LLONG; |
| 6731 | while (len > 8) { |
| 6732 | /* binary search */ |
| 6733 | p = base[len/2]; |
| 6734 | vdup(); |
| 6735 | if (ll) |
| 6736 | vpushll(p->v2); |
| 6737 | else |
| 6738 | vpushi(p->v2); |
| 6739 | gen_op(TOK_LE); |
| 6740 | e = gvtst(1, 0); |
| 6741 | vdup(); |
| 6742 | if (ll) |
| 6743 | vpushll(p->v1); |
| 6744 | else |
| 6745 | vpushi(p->v1); |
| 6746 | gen_op(TOK_GE); |
| 6747 | gtst_addr(0, p->sym); /* v1 <= x <= v2 */ |
| 6748 | /* x < v1 */ |
| 6749 | gcase(base, len/2, bsym); |
| 6750 | /* x > v2 */ |
| 6751 | gsym(e); |
| 6752 | e = len/2 + 1; |
| 6753 | base += e; len -= e; |
| 6754 | } |
| 6755 | /* linear scan */ |
| 6756 | while (len--) { |
| 6757 | p = *base++; |
| 6758 | vdup(); |
| 6759 | if (ll) |
| 6760 | vpushll(p->v2); |
| 6761 | else |
| 6762 | vpushi(p->v2); |
| 6763 | if (p->v1 == p->v2) { |
| 6764 | gen_op(TOK_EQ); |
| 6765 | gtst_addr(0, p->sym); |
| 6766 | } else { |
| 6767 | gen_op(TOK_LE); |
| 6768 | e = gvtst(1, 0); |
| 6769 | vdup(); |
| 6770 | if (ll) |
| 6771 | vpushll(p->v1); |
| 6772 | else |
| 6773 | vpushi(p->v1); |
| 6774 | gen_op(TOK_GE); |
| 6775 | gtst_addr(0, p->sym); |
| 6776 | gsym(e); |
| 6777 | } |
| 6778 | } |
| 6779 | *bsym = gjmp(*bsym); |
| 6780 | } |
| 6781 | |
| 6782 | /* ------------------------------------------------------------------------- */ |
| 6783 | /* __attribute__((cleanup(fn))) */ |
| 6784 | |
| 6785 | static void try_call_scope_cleanup(Sym *stop) |
| 6786 | { |
| 6787 | Sym *cls = cur_scope->cl.s; |
| 6788 | |
| 6789 | for (; cls != stop; cls = cls->ncl) { |
| 6790 | Sym *fs = cls->next; |
| 6791 | Sym *vs = cls->prev_tok; |
| 6792 | |
| 6793 | vpushsym(&fs->type, fs); |
| 6794 | vset(&vs->type, vs->r, vs->c); |
| 6795 | vtop->sym = vs; |
| 6796 | mk_pointer(&vtop->type); |
| 6797 | gaddrof(); |
| 6798 | gfunc_call(1); |
| 6799 | } |
| 6800 | } |
| 6801 | |
| 6802 | static void try_call_cleanup_goto(Sym *cleanupstate) |
| 6803 | { |
| 6804 | Sym *oc, *cc; |
| 6805 | int ocd, ccd; |
| 6806 | |
| 6807 | if (!cur_scope->cl.s) |
| 6808 | return; |
| 6809 | |
| 6810 | /* search NCA of both cleanup chains given parents and initial depth */ |
| 6811 | ocd = cleanupstate ? cleanupstate->v & ~SYM_FIELD : 0; |
| 6812 | for (ccd = cur_scope->cl.n, oc = cleanupstate; ocd > ccd; --ocd, oc = oc->ncl) |
| 6813 | ; |
| 6814 | for (cc = cur_scope->cl.s; ccd > ocd; --ccd, cc = cc->ncl) |
| 6815 | ; |
| 6816 | for (; cc != oc; cc = cc->ncl, oc = oc->ncl, --ccd) |
| 6817 | ; |
| 6818 | |
| 6819 | try_call_scope_cleanup(cc); |
| 6820 | } |
| 6821 | |
| 6822 | /* call 'func' for each __attribute__((cleanup(func))) */ |
| 6823 | static void block_cleanup(struct scope *o) |
| 6824 | { |
| 6825 | int jmp = 0; |
| 6826 | Sym *g, **pg; |
| 6827 | for (pg = &pending_gotos; (g = *pg) && g->c > o->cl.n;) { |
| 6828 | if (g->prev_tok->r & LABEL_FORWARD) { |
| 6829 | Sym *pcl = g->next; |
| 6830 | if (!jmp) |
| 6831 | jmp = gjmp(0); |
| 6832 | gsym(pcl->jnext); |
| 6833 | try_call_scope_cleanup(o->cl.s); |
| 6834 | pcl->jnext = gjmp(0); |
| 6835 | if (!o->cl.n) |
| 6836 | goto remove_pending; |
| 6837 | g->c = o->cl.n; |
| 6838 | pg = &g->prev; |
| 6839 | } else { |
| 6840 | remove_pending: |
| 6841 | *pg = g->prev; |
| 6842 | sym_free(g); |
| 6843 | } |
| 6844 | } |
| 6845 | gsym(jmp); |
| 6846 | try_call_scope_cleanup(o->cl.s); |
| 6847 | } |
| 6848 | |
| 6849 | /* ------------------------------------------------------------------------- */ |
| 6850 | /* VLA */ |
| 6851 | |
| 6852 | static void vla_restore(int loc) |
| 6853 | { |
| 6854 | if (loc) |
| 6855 | gen_vla_sp_restore(loc); |
| 6856 | } |
| 6857 | |
| 6858 | static void vla_leave(struct scope *o) |
| 6859 | { |
| 6860 | if (o->vla.num < cur_scope->vla.num) |
| 6861 | vla_restore(o->vla.loc); |
| 6862 | } |
| 6863 | |
| 6864 | /* ------------------------------------------------------------------------- */ |
| 6865 | /* local scopes */ |
| 6866 | |
| 6867 | void new_scope(struct scope *o) |
| 6868 | { |
| 6869 | /* copy and link previous scope */ |
| 6870 | *o = *cur_scope; |
| 6871 | o->prev = cur_scope; |
| 6872 | cur_scope = o; |
| 6873 | |
| 6874 | /* record local declaration stack position */ |
| 6875 | o->lstk = local_stack; |
| 6876 | o->llstk = local_label_stack; |
| 6877 | |
| 6878 | ++local_scope; |
| 6879 | |
| 6880 | if (tcc_state->do_debug) |
| 6881 | tcc_debug_stabn(N_LBRAC, ind - func_ind); |
| 6882 | } |
| 6883 | |
| 6884 | void prev_scope(struct scope *o, int is_expr) |
| 6885 | { |
| 6886 | vla_leave(o->prev); |
| 6887 | |
| 6888 | if (o->cl.s != o->prev->cl.s) |
| 6889 | block_cleanup(o->prev); |
| 6890 | |
| 6891 | /* pop locally defined labels */ |
| 6892 | label_pop(&local_label_stack, o->llstk, is_expr); |
| 6893 | |
| 6894 | /* In the is_expr case (a statement expression is finished here), |
| 6895 | vtop might refer to symbols on the local_stack. Either via the |
| 6896 | type or via vtop->sym. We can't pop those nor any that in turn |
| 6897 | might be referred to. To make it easier we don't roll back |
| 6898 | any symbols in that case; some upper level call to block() will |
| 6899 | do that. We do have to remove such symbols from the lookup |
| 6900 | tables, though. sym_pop will do that. */ |
| 6901 | |
| 6902 | /* pop locally defined symbols */ |
| 6903 | pop_local_syms(&local_stack, o->lstk, is_expr, 0); |
| 6904 | cur_scope = o->prev; |
| 6905 | --local_scope; |
| 6906 | |
| 6907 | if (tcc_state->do_debug) |
| 6908 | tcc_debug_stabn(N_RBRAC, ind - func_ind); |
| 6909 | } |
| 6910 | |
| 6911 | /* leave a scope via break/continue(/goto) */ |
| 6912 | void leave_scope(struct scope *o) |
| 6913 | { |
| 6914 | if (!o) |
| 6915 | return; |
| 6916 | try_call_scope_cleanup(o->cl.s); |
| 6917 | vla_leave(o); |
| 6918 | } |
| 6919 | |
| 6920 | /* ------------------------------------------------------------------------- */ |
| 6921 | /* call block from 'for do while' loops */ |
| 6922 | |
| 6923 | static void lblock(int *bsym, int *csym) |
| 6924 | { |
| 6925 | struct scope *lo = loop_scope, *co = cur_scope; |
| 6926 | int *b = co->bsym, *c = co->csym; |
| 6927 | if (csym) { |
| 6928 | co->csym = csym; |
| 6929 | loop_scope = co; |
| 6930 | } |
| 6931 | co->bsym = bsym; |
| 6932 | block(0); |
| 6933 | co->bsym = b; |
| 6934 | if (csym) { |
| 6935 | co->csym = c; |
| 6936 | loop_scope = lo; |
| 6937 | } |
| 6938 | } |
| 6939 | |
| 6940 | static void block(int is_expr) |
| 6941 | { |
| 6942 | int a, b, c, d, e, t; |
| 6943 | struct scope o; |
| 6944 | Sym *s; |
| 6945 | |
| 6946 | if (is_expr) { |
| 6947 | /* default return value is (void) */ |
| 6948 | vpushi(0); |
| 6949 | vtop->type.t = VT_VOID; |
| 6950 | } |
| 6951 | |
| 6952 | again: |
| 6953 | t = tok, next(); |
| 6954 | |
| 6955 | if (t == TOK_IF) { |
| 6956 | skip('('); |
| 6957 | gexpr(); |
| 6958 | skip(')'); |
| 6959 | a = gvtst(1, 0); |
| 6960 | block(0); |
| 6961 | if (tok == TOK_ELSE) { |
| 6962 | d = gjmp(0); |
| 6963 | gsym(a); |
| 6964 | next(); |
| 6965 | block(0); |
| 6966 | gsym(d); /* patch else jmp */ |
| 6967 | } else { |
| 6968 | gsym(a); |
| 6969 | } |
| 6970 | |
| 6971 | } else if (t == TOK_WHILE) { |
| 6972 | d = gind(); |
| 6973 | skip('('); |
| 6974 | gexpr(); |
| 6975 | skip(')'); |
| 6976 | a = gvtst(1, 0); |
| 6977 | b = 0; |
| 6978 | lblock(&a, &b); |
| 6979 | gjmp_addr(d); |
| 6980 | gsym_addr(b, d); |
| 6981 | gsym(a); |
| 6982 | |
| 6983 | } else if (t == '{') { |
| 6984 | new_scope(&o); |
| 6985 | |
| 6986 | /* handle local labels declarations */ |
| 6987 | while (tok == TOK_LABEL) { |
| 6988 | do { |
| 6989 | next(); |
| 6990 | if (tok < TOK_UIDENT) |
| 6991 | expect("label identifier" ); |
| 6992 | label_push(&local_label_stack, tok, LABEL_DECLARED); |
| 6993 | next(); |
| 6994 | } while (tok == ','); |
| 6995 | skip(';'); |
| 6996 | } |
| 6997 | |
| 6998 | while (tok != '}') { |
| 6999 | decl(VT_LOCAL); |
| 7000 | if (tok != '}') { |
| 7001 | if (is_expr) |
| 7002 | vpop(); |
| 7003 | block(is_expr); |
| 7004 | } |
| 7005 | } |
| 7006 | |
| 7007 | prev_scope(&o, is_expr); |
| 7008 | if (local_scope) |
| 7009 | next(); |
| 7010 | else if (!nocode_wanted) |
| 7011 | check_func_return(); |
| 7012 | |
| 7013 | } else if (t == TOK_RETURN) { |
| 7014 | b = (func_vt.t & VT_BTYPE) != VT_VOID; |
| 7015 | if (tok != ';') { |
| 7016 | gexpr(); |
| 7017 | if (b) { |
| 7018 | gen_assign_cast(&func_vt); |
| 7019 | } else { |
| 7020 | if (vtop->type.t != VT_VOID) |
| 7021 | tcc_warning("void function returns a value" ); |
| 7022 | vtop--; |
| 7023 | } |
| 7024 | } else if (b) { |
| 7025 | tcc_warning("'return' with no value" ); |
| 7026 | b = 0; |
| 7027 | } |
| 7028 | leave_scope(root_scope); |
| 7029 | if (b) |
| 7030 | gfunc_return(&func_vt); |
| 7031 | skip(';'); |
| 7032 | /* jump unless last stmt in top-level block */ |
| 7033 | if (tok != '}' || local_scope != 1) |
| 7034 | rsym = gjmp(rsym); |
| 7035 | CODE_OFF(); |
| 7036 | |
| 7037 | } else if (t == TOK_BREAK) { |
| 7038 | /* compute jump */ |
| 7039 | if (!cur_scope->bsym) |
| 7040 | tcc_error("cannot break" ); |
| 7041 | if (cur_switch && cur_scope->bsym == cur_switch->bsym) |
| 7042 | leave_scope(cur_switch->scope); |
| 7043 | else |
| 7044 | leave_scope(loop_scope); |
| 7045 | *cur_scope->bsym = gjmp(*cur_scope->bsym); |
| 7046 | skip(';'); |
| 7047 | |
| 7048 | } else if (t == TOK_CONTINUE) { |
| 7049 | /* compute jump */ |
| 7050 | if (!cur_scope->csym) |
| 7051 | tcc_error("cannot continue" ); |
| 7052 | leave_scope(loop_scope); |
| 7053 | *cur_scope->csym = gjmp(*cur_scope->csym); |
| 7054 | skip(';'); |
| 7055 | |
| 7056 | } else if (t == TOK_FOR) { |
| 7057 | new_scope(&o); |
| 7058 | |
| 7059 | skip('('); |
| 7060 | if (tok != ';') { |
| 7061 | /* c99 for-loop init decl? */ |
| 7062 | if (!decl0(VT_LOCAL, 1, NULL)) { |
| 7063 | /* no, regular for-loop init expr */ |
| 7064 | gexpr(); |
| 7065 | vpop(); |
| 7066 | } |
| 7067 | } |
| 7068 | skip(';'); |
| 7069 | a = b = 0; |
| 7070 | c = d = gind(); |
| 7071 | if (tok != ';') { |
| 7072 | gexpr(); |
| 7073 | a = gvtst(1, 0); |
| 7074 | } |
| 7075 | skip(';'); |
| 7076 | if (tok != ')') { |
| 7077 | e = gjmp(0); |
| 7078 | d = gind(); |
| 7079 | gexpr(); |
| 7080 | vpop(); |
| 7081 | gjmp_addr(c); |
| 7082 | gsym(e); |
| 7083 | } |
| 7084 | skip(')'); |
| 7085 | lblock(&a, &b); |
| 7086 | gjmp_addr(d); |
| 7087 | gsym_addr(b, d); |
| 7088 | gsym(a); |
| 7089 | prev_scope(&o, 0); |
| 7090 | |
| 7091 | } else if (t == TOK_DO) { |
| 7092 | a = b = 0; |
| 7093 | d = gind(); |
| 7094 | lblock(&a, &b); |
| 7095 | gsym(b); |
| 7096 | skip(TOK_WHILE); |
| 7097 | skip('('); |
| 7098 | gexpr(); |
| 7099 | skip(')'); |
| 7100 | skip(';'); |
| 7101 | c = gvtst(0, 0); |
| 7102 | gsym_addr(c, d); |
| 7103 | gsym(a); |
| 7104 | |
| 7105 | } else if (t == TOK_SWITCH) { |
| 7106 | struct switch_t *sw; |
| 7107 | |
| 7108 | sw = tcc_mallocz(sizeof *sw); |
| 7109 | sw->bsym = &a; |
| 7110 | sw->scope = cur_scope; |
| 7111 | sw->prev = cur_switch; |
| 7112 | cur_switch = sw; |
| 7113 | |
| 7114 | skip('('); |
| 7115 | gexpr(); |
| 7116 | skip(')'); |
| 7117 | sw->sv = *vtop--; /* save switch value */ |
| 7118 | |
| 7119 | a = 0; |
| 7120 | b = gjmp(0); /* jump to first case */ |
| 7121 | lblock(&a, NULL); |
| 7122 | a = gjmp(a); /* add implicit break */ |
| 7123 | /* case lookup */ |
| 7124 | gsym(b); |
| 7125 | |
| 7126 | if (sw->sv.type.t & VT_UNSIGNED) |
| 7127 | qsort(sw->p, sw->n, sizeof(void*), case_cmpu); |
| 7128 | else |
| 7129 | qsort(sw->p, sw->n, sizeof(void*), case_cmpi); |
| 7130 | |
| 7131 | for (b = 1; b < sw->n; b++) |
| 7132 | if (sw->sv.type.t & VT_UNSIGNED |
| 7133 | ? (uint64_t)sw->p[b - 1]->v2 >= (uint64_t)sw->p[b]->v1 |
| 7134 | : sw->p[b - 1]->v2 >= sw->p[b]->v1) |
| 7135 | tcc_error("duplicate case value" ); |
| 7136 | |
| 7137 | vpushv(&sw->sv); |
| 7138 | gv(RC_INT); |
| 7139 | d = 0, gcase(sw->p, sw->n, &d); |
| 7140 | vpop(); |
| 7141 | if (sw->def_sym) |
| 7142 | gsym_addr(d, sw->def_sym); |
| 7143 | else |
| 7144 | gsym(d); |
| 7145 | /* break label */ |
| 7146 | gsym(a); |
| 7147 | |
| 7148 | dynarray_reset(&sw->p, &sw->n); |
| 7149 | cur_switch = sw->prev; |
| 7150 | tcc_free(sw); |
| 7151 | |
| 7152 | } else if (t == TOK_CASE) { |
| 7153 | struct case_t *cr = tcc_malloc(sizeof(struct case_t)); |
| 7154 | if (!cur_switch) |
| 7155 | expect("switch" ); |
| 7156 | cr->v1 = cr->v2 = expr_const64(); |
| 7157 | if (gnu_ext && tok == TOK_DOTS) { |
| 7158 | next(); |
| 7159 | cr->v2 = expr_const64(); |
| 7160 | if ((!(cur_switch->sv.type.t & VT_UNSIGNED) && cr->v2 < cr->v1) |
| 7161 | || (cur_switch->sv.type.t & VT_UNSIGNED && (uint64_t)cr->v2 < (uint64_t)cr->v1)) |
| 7162 | tcc_warning("empty case range" ); |
| 7163 | } |
| 7164 | cr->sym = gind(); |
| 7165 | dynarray_add(&cur_switch->p, &cur_switch->n, cr); |
| 7166 | skip(':'); |
| 7167 | is_expr = 0; |
| 7168 | goto block_after_label; |
| 7169 | |
| 7170 | } else if (t == TOK_DEFAULT) { |
| 7171 | if (!cur_switch) |
| 7172 | expect("switch" ); |
| 7173 | if (cur_switch->def_sym) |
| 7174 | tcc_error("too many 'default'" ); |
| 7175 | cur_switch->def_sym = gind(); |
| 7176 | skip(':'); |
| 7177 | is_expr = 0; |
| 7178 | goto block_after_label; |
| 7179 | |
| 7180 | } else if (t == TOK_GOTO) { |
| 7181 | vla_restore(root_scope->vla.loc); |
| 7182 | if (tok == '*' && gnu_ext) { |
| 7183 | /* computed goto */ |
| 7184 | next(); |
| 7185 | gexpr(); |
| 7186 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
| 7187 | expect("pointer" ); |
| 7188 | ggoto(); |
| 7189 | |
| 7190 | } else if (tok >= TOK_UIDENT) { |
| 7191 | s = label_find(tok); |
| 7192 | /* put forward definition if needed */ |
| 7193 | if (!s) |
| 7194 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
| 7195 | else if (s->r == LABEL_DECLARED) |
| 7196 | s->r = LABEL_FORWARD; |
| 7197 | |
| 7198 | if (s->r & LABEL_FORWARD) { |
| 7199 | /* start new goto chain for cleanups, linked via label->next */ |
| 7200 | if (cur_scope->cl.s && !nocode_wanted) { |
| 7201 | sym_push2(&pending_gotos, SYM_FIELD, 0, cur_scope->cl.n); |
| 7202 | pending_gotos->prev_tok = s; |
| 7203 | s = sym_push2(&s->next, SYM_FIELD, 0, 0); |
| 7204 | pending_gotos->next = s; |
| 7205 | } |
| 7206 | s->jnext = gjmp(s->jnext); |
| 7207 | } else { |
| 7208 | try_call_cleanup_goto(s->cleanupstate); |
| 7209 | gjmp_addr(s->jnext); |
| 7210 | } |
| 7211 | next(); |
| 7212 | |
| 7213 | } else { |
| 7214 | expect("label identifier" ); |
| 7215 | } |
| 7216 | skip(';'); |
| 7217 | |
| 7218 | } else if (t == TOK_ASM1 || t == TOK_ASM2 || t == TOK_ASM3) { |
| 7219 | asm_instr(); |
| 7220 | |
| 7221 | } else { |
| 7222 | if (tok == ':' && t >= TOK_UIDENT) { |
| 7223 | /* label case */ |
| 7224 | next(); |
| 7225 | s = label_find(t); |
| 7226 | if (s) { |
| 7227 | if (s->r == LABEL_DEFINED) |
| 7228 | tcc_error("duplicate label '%s'" , get_tok_str(s->v, NULL)); |
| 7229 | s->r = LABEL_DEFINED; |
| 7230 | if (s->next) { |
| 7231 | Sym *pcl; /* pending cleanup goto */ |
| 7232 | for (pcl = s->next; pcl; pcl = pcl->prev) |
| 7233 | gsym(pcl->jnext); |
| 7234 | sym_pop(&s->next, NULL, 0); |
| 7235 | } else |
| 7236 | gsym(s->jnext); |
| 7237 | } else { |
| 7238 | s = label_push(&global_label_stack, t, LABEL_DEFINED); |
| 7239 | } |
| 7240 | s->jnext = gind(); |
| 7241 | s->cleanupstate = cur_scope->cl.s; |
| 7242 | |
| 7243 | block_after_label: |
| 7244 | vla_restore(cur_scope->vla.loc); |
| 7245 | /* we accept this, but it is a mistake */ |
| 7246 | if (tok == '}') { |
| 7247 | tcc_warning("deprecated use of label at end of compound statement" ); |
| 7248 | } else { |
| 7249 | goto again; |
| 7250 | } |
| 7251 | |
| 7252 | } else { |
| 7253 | /* expression case */ |
| 7254 | if (t != ';') { |
| 7255 | unget_tok(t); |
| 7256 | if (is_expr) { |
| 7257 | vpop(); |
| 7258 | gexpr(); |
| 7259 | } else { |
| 7260 | gexpr(); |
| 7261 | vpop(); |
| 7262 | } |
| 7263 | skip(';'); |
| 7264 | } |
| 7265 | } |
| 7266 | } |
| 7267 | } |
| 7268 | |
| 7269 | /* This skips over a stream of tokens containing balanced {} and () |
| 7270 | pairs, stopping at outer ',' ';' and '}' (or matching '}' if we started |
| 7271 | with a '{'). If STR then allocates and stores the skipped tokens |
| 7272 | in *STR. This doesn't check if () and {} are nested correctly, |
| 7273 | i.e. "({)}" is accepted. */ |
| 7274 | static void skip_or_save_block(TokenString **str) |
| 7275 | { |
| 7276 | int braces = tok == '{'; |
| 7277 | int level = 0; |
| 7278 | if (str) |
| 7279 | *str = tok_str_alloc(); |
| 7280 | |
| 7281 | while ((level > 0 || (tok != '}' && tok != ',' && tok != ';' && tok != ')'))) { |
| 7282 | int t; |
| 7283 | if (tok == TOK_EOF) { |
| 7284 | if (str || level > 0) |
| 7285 | tcc_error("unexpected end of file" ); |
| 7286 | else |
| 7287 | break; |
| 7288 | } |
| 7289 | if (str) |
| 7290 | tok_str_add_tok(*str); |
| 7291 | t = tok; |
| 7292 | next(); |
| 7293 | if (t == '{' || t == '(') { |
| 7294 | level++; |
| 7295 | } else if (t == '}' || t == ')') { |
| 7296 | level--; |
| 7297 | if (level == 0 && braces && t == '}') |
| 7298 | break; |
| 7299 | } |
| 7300 | } |
| 7301 | if (str) { |
| 7302 | tok_str_add(*str, -1); |
| 7303 | tok_str_add(*str, 0); |
| 7304 | } |
| 7305 | } |
| 7306 | |
| 7307 | #define EXPR_CONST 1 |
| 7308 | #define EXPR_ANY 2 |
| 7309 | |
| 7310 | static void parse_init_elem(int expr_type) |
| 7311 | { |
| 7312 | int saved_global_expr; |
| 7313 | switch(expr_type) { |
| 7314 | case EXPR_CONST: |
| 7315 | /* compound literals must be allocated globally in this case */ |
| 7316 | saved_global_expr = global_expr; |
| 7317 | global_expr = 1; |
| 7318 | expr_const1(); |
| 7319 | global_expr = saved_global_expr; |
| 7320 | /* NOTE: symbols are accepted, as well as lvalue for anon symbols |
| 7321 | (compound literals). */ |
| 7322 | if (((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST |
| 7323 | && ((vtop->r & (VT_SYM|VT_LVAL)) != (VT_SYM|VT_LVAL) |
| 7324 | || vtop->sym->v < SYM_FIRST_ANOM)) |
| 7325 | #ifdef TCC_TARGET_PE |
| 7326 | || ((vtop->r & VT_SYM) && vtop->sym->a.dllimport) |
| 7327 | #endif |
| 7328 | ) |
| 7329 | tcc_error("initializer element is not constant" ); |
| 7330 | break; |
| 7331 | case EXPR_ANY: |
| 7332 | expr_eq(); |
| 7333 | break; |
| 7334 | } |
| 7335 | } |
| 7336 | |
| 7337 | #if 1 |
| 7338 | static void init_assert(init_params *p, int offset) |
| 7339 | { |
| 7340 | if (p->sec ? !NODATA_WANTED && offset > p->sec->data_offset |
| 7341 | : !nocode_wanted && offset > p->local_offset) |
| 7342 | tcc_internal_error("initializer overflow" ); |
| 7343 | } |
| 7344 | #else |
| 7345 | #define init_assert(sec, offset) |
| 7346 | #endif |
| 7347 | |
| 7348 | /* put zeros for variable based init */ |
| 7349 | static void init_putz(init_params *p, unsigned long c, int size) |
| 7350 | { |
| 7351 | init_assert(p, c + size); |
| 7352 | if (p->sec) { |
| 7353 | /* nothing to do because globals are already set to zero */ |
| 7354 | } else { |
| 7355 | vpush_global_sym(&func_old_type, TOK_memset); |
| 7356 | vseti(VT_LOCAL, c); |
| 7357 | #ifdef TCC_TARGET_ARM |
| 7358 | vpushs(size); |
| 7359 | vpushi(0); |
| 7360 | #else |
| 7361 | vpushi(0); |
| 7362 | vpushs(size); |
| 7363 | #endif |
| 7364 | gfunc_call(3); |
| 7365 | } |
| 7366 | } |
| 7367 | |
| 7368 | #define DIF_FIRST 1 |
| 7369 | #define DIF_SIZE_ONLY 2 |
| 7370 | #define DIF_HAVE_ELEM 4 |
| 7371 | #define DIF_CLEAR 8 |
| 7372 | |
| 7373 | /* delete relocations for specified range c ... c + size. Unfortunatly |
| 7374 | in very special cases, relocations may occur unordered */ |
| 7375 | static void decl_design_delrels(Section *sec, int c, int size) |
| 7376 | { |
| 7377 | ElfW_Rel *rel, *rel2, *rel_end; |
| 7378 | if (!sec || !sec->reloc) |
| 7379 | return; |
| 7380 | rel = rel2 = (ElfW_Rel*)sec->reloc->data; |
| 7381 | rel_end = (ElfW_Rel*)(sec->reloc->data + sec->reloc->data_offset); |
| 7382 | while (rel < rel_end) { |
| 7383 | if (rel->r_offset >= c && rel->r_offset < c + size) { |
| 7384 | sec->reloc->data_offset -= sizeof *rel; |
| 7385 | } else { |
| 7386 | if (rel2 != rel) |
| 7387 | memcpy(rel2, rel, sizeof *rel); |
| 7388 | ++rel2; |
| 7389 | } |
| 7390 | ++rel; |
| 7391 | } |
| 7392 | } |
| 7393 | |
| 7394 | static void decl_design_flex(init_params *p, Sym *ref, int index) |
| 7395 | { |
| 7396 | if (ref == p->flex_array_ref) { |
| 7397 | if (index >= ref->c) |
| 7398 | ref->c = index + 1; |
| 7399 | } else if (ref->c < 0) |
| 7400 | tcc_error("flexible array has zero size in this context" ); |
| 7401 | } |
| 7402 | |
| 7403 | /* t is the array or struct type. c is the array or struct |
| 7404 | address. cur_field is the pointer to the current |
| 7405 | field, for arrays the 'c' member contains the current start |
| 7406 | index. 'flags' is as in decl_initializer. |
| 7407 | 'al' contains the already initialized length of the |
| 7408 | current container (starting at c). This returns the new length of that. */ |
| 7409 | static int decl_designator(init_params *p, CType *type, unsigned long c, |
| 7410 | Sym **cur_field, int flags, int al) |
| 7411 | { |
| 7412 | Sym *s, *f; |
| 7413 | int index, index_last, align, l, nb_elems, elem_size; |
| 7414 | unsigned long corig = c; |
| 7415 | |
| 7416 | elem_size = 0; |
| 7417 | nb_elems = 1; |
| 7418 | |
| 7419 | if (flags & DIF_HAVE_ELEM) |
| 7420 | goto no_designator; |
| 7421 | |
| 7422 | if (gnu_ext && tok >= TOK_UIDENT) { |
| 7423 | l = tok, next(); |
| 7424 | if (tok == ':') |
| 7425 | goto struct_field; |
| 7426 | unget_tok(l); |
| 7427 | } |
| 7428 | |
| 7429 | /* NOTE: we only support ranges for last designator */ |
| 7430 | while (nb_elems == 1 && (tok == '[' || tok == '.')) { |
| 7431 | if (tok == '[') { |
| 7432 | if (!(type->t & VT_ARRAY)) |
| 7433 | expect("array type" ); |
| 7434 | next(); |
| 7435 | index = index_last = expr_const(); |
| 7436 | if (tok == TOK_DOTS && gnu_ext) { |
| 7437 | next(); |
| 7438 | index_last = expr_const(); |
| 7439 | } |
| 7440 | skip(']'); |
| 7441 | s = type->ref; |
| 7442 | decl_design_flex(p, s, index_last); |
| 7443 | if (index < 0 || index_last >= s->c || index_last < index) |
| 7444 | tcc_error("index exceeds array bounds or range is empty" ); |
| 7445 | if (cur_field) |
| 7446 | (*cur_field)->c = index_last; |
| 7447 | type = pointed_type(type); |
| 7448 | elem_size = type_size(type, &align); |
| 7449 | c += index * elem_size; |
| 7450 | nb_elems = index_last - index + 1; |
| 7451 | } else { |
| 7452 | int cumofs; |
| 7453 | next(); |
| 7454 | l = tok; |
| 7455 | struct_field: |
| 7456 | next(); |
| 7457 | if ((type->t & VT_BTYPE) != VT_STRUCT) |
| 7458 | expect("struct/union type" ); |
| 7459 | cumofs = 0; |
| 7460 | f = find_field(type, l, &cumofs); |
| 7461 | if (!f) |
| 7462 | expect("field" ); |
| 7463 | if (cur_field) |
| 7464 | *cur_field = f; |
| 7465 | type = &f->type; |
| 7466 | c += cumofs + f->c; |
| 7467 | } |
| 7468 | cur_field = NULL; |
| 7469 | } |
| 7470 | if (!cur_field) { |
| 7471 | if (tok == '=') { |
| 7472 | next(); |
| 7473 | } else if (!gnu_ext) { |
| 7474 | expect("=" ); |
| 7475 | } |
| 7476 | } else { |
| 7477 | no_designator: |
| 7478 | if (type->t & VT_ARRAY) { |
| 7479 | index = (*cur_field)->c; |
| 7480 | s = type->ref; |
| 7481 | decl_design_flex(p, s, index); |
| 7482 | if (index >= s->c) |
| 7483 | tcc_error("too many initializers" ); |
| 7484 | type = pointed_type(type); |
| 7485 | elem_size = type_size(type, &align); |
| 7486 | c += index * elem_size; |
| 7487 | } else { |
| 7488 | f = *cur_field; |
| 7489 | while (f && (f->v & SYM_FIRST_ANOM) && (f->type.t & VT_BITFIELD)) |
| 7490 | *cur_field = f = f->next; |
| 7491 | if (!f) |
| 7492 | tcc_error("too many initializers" ); |
| 7493 | type = &f->type; |
| 7494 | c += f->c; |
| 7495 | } |
| 7496 | } |
| 7497 | |
| 7498 | if (!elem_size) /* for structs */ |
| 7499 | elem_size = type_size(type, &align); |
| 7500 | |
| 7501 | /* Using designators the same element can be initialized more |
| 7502 | than once. In that case we need to delete possibly already |
| 7503 | existing relocations. */ |
| 7504 | if (!(flags & DIF_SIZE_ONLY) && c - corig < al) { |
| 7505 | decl_design_delrels(p->sec, c, elem_size * nb_elems); |
| 7506 | flags &= ~DIF_CLEAR; /* mark stack dirty too */ |
| 7507 | } |
| 7508 | |
| 7509 | decl_initializer(p, type, c, flags & ~DIF_FIRST); |
| 7510 | |
| 7511 | if (!(flags & DIF_SIZE_ONLY) && nb_elems > 1) { |
| 7512 | Sym aref = {0}; |
| 7513 | CType t1; |
| 7514 | int i; |
| 7515 | if (p->sec || (type->t & VT_ARRAY)) { |
| 7516 | /* make init_putv/vstore believe it were a struct */ |
| 7517 | aref.c = elem_size; |
| 7518 | t1.t = VT_STRUCT, t1.ref = &aref; |
| 7519 | type = &t1; |
| 7520 | } |
| 7521 | if (p->sec) |
| 7522 | vpush_ref(type, p->sec, c, elem_size); |
| 7523 | else |
| 7524 | vset(type, VT_LOCAL|VT_LVAL, c); |
| 7525 | for (i = 1; i < nb_elems; i++) { |
| 7526 | vdup(); |
| 7527 | init_putv(p, type, c + elem_size * i); |
| 7528 | } |
| 7529 | vpop(); |
| 7530 | } |
| 7531 | |
| 7532 | c += nb_elems * elem_size; |
| 7533 | if (c - corig > al) |
| 7534 | al = c - corig; |
| 7535 | return al; |
| 7536 | } |
| 7537 | |
| 7538 | /* store a value or an expression directly in global data or in local array */ |
| 7539 | static void init_putv(init_params *p, CType *type, unsigned long c) |
| 7540 | { |
| 7541 | int bt; |
| 7542 | void *ptr; |
| 7543 | CType dtype; |
| 7544 | int size, align; |
| 7545 | Section *sec = p->sec; |
| 7546 | |
| 7547 | dtype = *type; |
| 7548 | dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
| 7549 | |
| 7550 | size = type_size(type, &align); |
| 7551 | if (type->t & VT_BITFIELD) |
| 7552 | size = (BIT_POS(type->t) + BIT_SIZE(type->t) + 7) / 8; |
| 7553 | init_assert(p, c + size); |
| 7554 | |
| 7555 | if (sec) { |
| 7556 | /* XXX: not portable */ |
| 7557 | /* XXX: generate error if incorrect relocation */ |
| 7558 | gen_assign_cast(&dtype); |
| 7559 | bt = type->t & VT_BTYPE; |
| 7560 | |
| 7561 | if ((vtop->r & VT_SYM) |
| 7562 | && bt != VT_PTR |
| 7563 | && bt != VT_FUNC |
| 7564 | && (bt != (PTR_SIZE == 8 ? VT_LLONG : VT_INT) |
| 7565 | || (type->t & VT_BITFIELD)) |
| 7566 | && !((vtop->r & VT_CONST) && vtop->sym->v >= SYM_FIRST_ANOM) |
| 7567 | ) |
| 7568 | tcc_error("initializer element is not computable at load time" ); |
| 7569 | |
| 7570 | if (NODATA_WANTED) { |
| 7571 | vtop--; |
| 7572 | return; |
| 7573 | } |
| 7574 | |
| 7575 | ptr = sec->data + c; |
| 7576 | |
| 7577 | /* XXX: make code faster ? */ |
| 7578 | if ((vtop->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST) && |
| 7579 | vtop->sym->v >= SYM_FIRST_ANOM && |
| 7580 | /* XXX This rejects compound literals like |
| 7581 | '(void *){ptr}'. The problem is that '&sym' is |
| 7582 | represented the same way, which would be ruled out |
| 7583 | by the SYM_FIRST_ANOM check above, but also '"string"' |
| 7584 | in 'char *p = "string"' is represented the same |
| 7585 | with the type being VT_PTR and the symbol being an |
| 7586 | anonymous one. That is, there's no difference in vtop |
| 7587 | between '(void *){x}' and '&(void *){x}'. Ignore |
| 7588 | pointer typed entities here. Hopefully no real code |
| 7589 | will ever use compound literals with scalar type. */ |
| 7590 | (vtop->type.t & VT_BTYPE) != VT_PTR) { |
| 7591 | /* These come from compound literals, memcpy stuff over. */ |
| 7592 | Section *ssec; |
| 7593 | ElfSym *esym; |
| 7594 | ElfW_Rel *rel; |
| 7595 | esym = elfsym(vtop->sym); |
| 7596 | ssec = tcc_state->sections[esym->st_shndx]; |
| 7597 | memmove (ptr, ssec->data + esym->st_value + (int)vtop->c.i, size); |
| 7598 | if (ssec->reloc) { |
| 7599 | /* We need to copy over all memory contents, and that |
| 7600 | includes relocations. Use the fact that relocs are |
| 7601 | created it order, so look from the end of relocs |
| 7602 | until we hit one before the copied region. */ |
| 7603 | int num_relocs = ssec->reloc->data_offset / sizeof(*rel); |
| 7604 | rel = (ElfW_Rel*)(ssec->reloc->data + ssec->reloc->data_offset); |
| 7605 | while (num_relocs--) { |
| 7606 | rel--; |
| 7607 | if (rel->r_offset >= esym->st_value + size) |
| 7608 | continue; |
| 7609 | if (rel->r_offset < esym->st_value) |
| 7610 | break; |
| 7611 | put_elf_reloca(symtab_section, sec, |
| 7612 | c + rel->r_offset - esym->st_value, |
| 7613 | ELFW(R_TYPE)(rel->r_info), |
| 7614 | ELFW(R_SYM)(rel->r_info), |
| 7615 | #if PTR_SIZE == 8 |
| 7616 | rel->r_addend |
| 7617 | #else |
| 7618 | 0 |
| 7619 | #endif |
| 7620 | ); |
| 7621 | } |
| 7622 | } |
| 7623 | } else { |
| 7624 | if (type->t & VT_BITFIELD) { |
| 7625 | int bit_pos, bit_size, bits, n; |
| 7626 | unsigned char *p, v, m; |
| 7627 | bit_pos = BIT_POS(vtop->type.t); |
| 7628 | bit_size = BIT_SIZE(vtop->type.t); |
| 7629 | p = (unsigned char*)ptr + (bit_pos >> 3); |
| 7630 | bit_pos &= 7, bits = 0; |
| 7631 | while (bit_size) { |
| 7632 | n = 8 - bit_pos; |
| 7633 | if (n > bit_size) |
| 7634 | n = bit_size; |
| 7635 | v = vtop->c.i >> bits << bit_pos; |
| 7636 | m = ((1 << n) - 1) << bit_pos; |
| 7637 | *p = (*p & ~m) | (v & m); |
| 7638 | bits += n, bit_size -= n, bit_pos = 0, ++p; |
| 7639 | } |
| 7640 | } else |
| 7641 | switch(bt) { |
| 7642 | /* XXX: when cross-compiling we assume that each type has the |
| 7643 | same representation on host and target, which is likely to |
| 7644 | be wrong in the case of long double */ |
| 7645 | case VT_BOOL: |
| 7646 | vtop->c.i = vtop->c.i != 0; |
| 7647 | case VT_BYTE: |
| 7648 | *(char *)ptr = vtop->c.i; |
| 7649 | break; |
| 7650 | case VT_SHORT: |
| 7651 | *(short *)ptr = vtop->c.i; |
| 7652 | break; |
| 7653 | case VT_FLOAT: |
| 7654 | *(float*)ptr = vtop->c.f; |
| 7655 | break; |
| 7656 | case VT_DOUBLE: |
| 7657 | *(double *)ptr = vtop->c.d; |
| 7658 | break; |
| 7659 | case VT_LDOUBLE: |
| 7660 | #if defined TCC_IS_NATIVE_387 |
| 7661 | if (sizeof (long double) >= 10) /* zero pad ten-byte LD */ |
| 7662 | memcpy(ptr, &vtop->c.ld, 10); |
| 7663 | #ifdef __TINYC__ |
| 7664 | else if (sizeof (long double) == sizeof (double)) |
| 7665 | __asm__("fldl %1\nfstpt %0\n" : "=m" (*ptr) : "m" (vtop->c.ld)); |
| 7666 | #endif |
| 7667 | else if (vtop->c.ld == 0.0) |
| 7668 | ; |
| 7669 | else |
| 7670 | #endif |
| 7671 | if (sizeof(long double) == LDOUBLE_SIZE) |
| 7672 | *(long double*)ptr = vtop->c.ld; |
| 7673 | else if (sizeof(double) == LDOUBLE_SIZE) |
| 7674 | *(double *)ptr = (double)vtop->c.ld; |
| 7675 | else |
| 7676 | tcc_error("can't cross compile long double constants" ); |
| 7677 | break; |
| 7678 | #if PTR_SIZE != 8 |
| 7679 | case VT_LLONG: |
| 7680 | *(long long *)ptr = vtop->c.i; |
| 7681 | break; |
| 7682 | #else |
| 7683 | case VT_LLONG: |
| 7684 | #endif |
| 7685 | case VT_PTR: |
| 7686 | { |
| 7687 | addr_t val = vtop->c.i; |
| 7688 | #if PTR_SIZE == 8 |
| 7689 | if (vtop->r & VT_SYM) |
| 7690 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
| 7691 | else |
| 7692 | *(addr_t *)ptr = val; |
| 7693 | #else |
| 7694 | if (vtop->r & VT_SYM) |
| 7695 | greloc(sec, vtop->sym, c, R_DATA_PTR); |
| 7696 | *(addr_t *)ptr = val; |
| 7697 | #endif |
| 7698 | break; |
| 7699 | } |
| 7700 | default: |
| 7701 | { |
| 7702 | int val = vtop->c.i; |
| 7703 | #if PTR_SIZE == 8 |
| 7704 | if (vtop->r & VT_SYM) |
| 7705 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
| 7706 | else |
| 7707 | *(int *)ptr = val; |
| 7708 | #else |
| 7709 | if (vtop->r & VT_SYM) |
| 7710 | greloc(sec, vtop->sym, c, R_DATA_PTR); |
| 7711 | *(int *)ptr = val; |
| 7712 | #endif |
| 7713 | break; |
| 7714 | } |
| 7715 | } |
| 7716 | } |
| 7717 | vtop--; |
| 7718 | } else { |
| 7719 | vset(&dtype, VT_LOCAL|VT_LVAL, c); |
| 7720 | vswap(); |
| 7721 | vstore(); |
| 7722 | vpop(); |
| 7723 | } |
| 7724 | } |
| 7725 | |
| 7726 | /* 't' contains the type and storage info. 'c' is the offset of the |
| 7727 | object in section 'sec'. If 'sec' is NULL, it means stack based |
| 7728 | allocation. 'flags & DIF_FIRST' is true if array '{' must be read (multi |
| 7729 | dimension implicit array init handling). 'flags & DIF_SIZE_ONLY' is true if |
| 7730 | size only evaluation is wanted (only for arrays). */ |
| 7731 | static void decl_initializer(init_params *p, CType *type, unsigned long c, int flags) |
| 7732 | { |
| 7733 | int len, n, no_oblock, i; |
| 7734 | int size1, align1; |
| 7735 | Sym *s, *f; |
| 7736 | Sym indexsym; |
| 7737 | CType *t1; |
| 7738 | |
| 7739 | /* generate line number info */ |
| 7740 | if (!p->sec && tcc_state->do_debug) |
| 7741 | tcc_debug_line(tcc_state); |
| 7742 | |
| 7743 | if (!(flags & DIF_HAVE_ELEM) && tok != '{' && |
| 7744 | /* In case of strings we have special handling for arrays, so |
| 7745 | don't consume them as initializer value (which would commit them |
| 7746 | to some anonymous symbol). */ |
| 7747 | tok != TOK_LSTR && tok != TOK_STR && |
| 7748 | !(flags & DIF_SIZE_ONLY)) { |
| 7749 | parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST); |
| 7750 | flags |= DIF_HAVE_ELEM; |
| 7751 | } |
| 7752 | |
| 7753 | if ((flags & DIF_HAVE_ELEM) && |
| 7754 | !(type->t & VT_ARRAY) && |
| 7755 | /* Use i_c_parameter_t, to strip toplevel qualifiers. |
| 7756 | The source type might have VT_CONSTANT set, which is |
| 7757 | of course assignable to non-const elements. */ |
| 7758 | is_compatible_unqualified_types(type, &vtop->type)) { |
| 7759 | goto init_putv; |
| 7760 | |
| 7761 | } else if (type->t & VT_ARRAY) { |
| 7762 | no_oblock = 1; |
| 7763 | if (((flags & DIF_FIRST) && tok != TOK_LSTR && tok != TOK_STR) || |
| 7764 | tok == '{') { |
| 7765 | skip('{'); |
| 7766 | no_oblock = 0; |
| 7767 | } |
| 7768 | |
| 7769 | s = type->ref; |
| 7770 | n = s->c; |
| 7771 | t1 = pointed_type(type); |
| 7772 | size1 = type_size(t1, &align1); |
| 7773 | |
| 7774 | /* only parse strings here if correct type (otherwise: handle |
| 7775 | them as ((w)char *) expressions */ |
| 7776 | if ((tok == TOK_LSTR && |
| 7777 | #ifdef TCC_TARGET_PE |
| 7778 | (t1->t & VT_BTYPE) == VT_SHORT && (t1->t & VT_UNSIGNED) |
| 7779 | #else |
| 7780 | (t1->t & VT_BTYPE) == VT_INT |
| 7781 | #endif |
| 7782 | ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) { |
| 7783 | len = 0; |
| 7784 | cstr_reset(&initstr); |
| 7785 | if (size1 != (tok == TOK_STR ? 1 : sizeof(nwchar_t))) |
| 7786 | tcc_error("unhandled string literal merging" ); |
| 7787 | while (tok == TOK_STR || tok == TOK_LSTR) { |
| 7788 | if (initstr.size) |
| 7789 | initstr.size -= size1; |
| 7790 | if (tok == TOK_STR) |
| 7791 | len += tokc.str.size; |
| 7792 | else |
| 7793 | len += tokc.str.size / sizeof(nwchar_t); |
| 7794 | len--; |
| 7795 | cstr_cat(&initstr, tokc.str.data, tokc.str.size); |
| 7796 | next(); |
| 7797 | } |
| 7798 | if (tok != ')' && tok != '}' && tok != ',' && tok != ';' |
| 7799 | && tok != TOK_EOF) { |
| 7800 | /* Not a lone literal but part of a bigger expression. */ |
| 7801 | unget_tok(size1 == 1 ? TOK_STR : TOK_LSTR); |
| 7802 | tokc.str.size = initstr.size; |
| 7803 | tokc.str.data = initstr.data; |
| 7804 | goto do_init_array; |
| 7805 | } |
| 7806 | |
| 7807 | if (!(flags & DIF_SIZE_ONLY)) { |
| 7808 | int nb = n; |
| 7809 | if (len < nb) |
| 7810 | nb = len; |
| 7811 | if (len > nb) |
| 7812 | tcc_warning("initializer-string for array is too long" ); |
| 7813 | /* in order to go faster for common case (char |
| 7814 | string in global variable, we handle it |
| 7815 | specifically */ |
| 7816 | if (p->sec && size1 == 1) { |
| 7817 | init_assert(p, c + nb); |
| 7818 | if (!NODATA_WANTED) |
| 7819 | memcpy(p->sec->data + c, initstr.data, nb); |
| 7820 | } else { |
| 7821 | for(i=0;i<n;i++) { |
| 7822 | if (i >= nb) { |
| 7823 | /* only add trailing zero if enough storage (no |
| 7824 | warning in this case since it is standard) */ |
| 7825 | if (flags & DIF_CLEAR) |
| 7826 | break; |
| 7827 | if (n - i >= 4) { |
| 7828 | init_putz(p, c + i * size1, (n - i) * size1); |
| 7829 | break; |
| 7830 | } |
| 7831 | ch = 0; |
| 7832 | } else if (size1 == 1) |
| 7833 | ch = ((unsigned char *)initstr.data)[i]; |
| 7834 | else |
| 7835 | ch = ((nwchar_t *)initstr.data)[i]; |
| 7836 | vpushi(ch); |
| 7837 | init_putv(p, t1, c + i * size1); |
| 7838 | } |
| 7839 | } |
| 7840 | } else { |
| 7841 | decl_design_flex(p, s, len); |
| 7842 | } |
| 7843 | } else { |
| 7844 | |
| 7845 | do_init_array: |
| 7846 | indexsym.c = 0; |
| 7847 | f = &indexsym; |
| 7848 | |
| 7849 | do_init_list: |
| 7850 | /* zero memory once in advance */ |
| 7851 | if (!(flags & (DIF_CLEAR | DIF_SIZE_ONLY))) { |
| 7852 | init_putz(p, c, n*size1); |
| 7853 | flags |= DIF_CLEAR; |
| 7854 | } |
| 7855 | |
| 7856 | len = 0; |
| 7857 | while (tok != '}' || (flags & DIF_HAVE_ELEM)) { |
| 7858 | len = decl_designator(p, type, c, &f, flags, len); |
| 7859 | flags &= ~DIF_HAVE_ELEM; |
| 7860 | if (type->t & VT_ARRAY) { |
| 7861 | ++indexsym.c; |
| 7862 | /* special test for multi dimensional arrays (may not |
| 7863 | be strictly correct if designators are used at the |
| 7864 | same time) */ |
| 7865 | if (no_oblock && len >= n*size1) |
| 7866 | break; |
| 7867 | } else { |
| 7868 | if (s->type.t == VT_UNION) |
| 7869 | f = NULL; |
| 7870 | else |
| 7871 | f = f->next; |
| 7872 | if (no_oblock && f == NULL) |
| 7873 | break; |
| 7874 | } |
| 7875 | |
| 7876 | if (tok == '}') |
| 7877 | break; |
| 7878 | skip(','); |
| 7879 | } |
| 7880 | } |
| 7881 | if (!no_oblock) |
| 7882 | skip('}'); |
| 7883 | } else if ((type->t & VT_BTYPE) == VT_STRUCT) { |
| 7884 | no_oblock = 1; |
| 7885 | if ((flags & DIF_FIRST) || tok == '{') { |
| 7886 | skip('{'); |
| 7887 | no_oblock = 0; |
| 7888 | } |
| 7889 | s = type->ref; |
| 7890 | f = s->next; |
| 7891 | n = s->c; |
| 7892 | size1 = 1; |
| 7893 | goto do_init_list; |
| 7894 | } else if (tok == '{') { |
| 7895 | if (flags & DIF_HAVE_ELEM) |
| 7896 | skip(';'); |
| 7897 | next(); |
| 7898 | decl_initializer(p, type, c, flags & ~DIF_HAVE_ELEM); |
| 7899 | skip('}'); |
| 7900 | } else if ((flags & DIF_SIZE_ONLY)) { |
| 7901 | /* If we supported only ISO C we wouldn't have to accept calling |
| 7902 | this on anything than an array if DIF_SIZE_ONLY (and even then |
| 7903 | only on the outermost level, so no recursion would be needed), |
| 7904 | because initializing a flex array member isn't supported. |
| 7905 | But GNU C supports it, so we need to recurse even into |
| 7906 | subfields of structs and arrays when DIF_SIZE_ONLY is set. */ |
| 7907 | /* just skip expression */ |
| 7908 | skip_or_save_block(NULL); |
| 7909 | } else { |
| 7910 | if (!(flags & DIF_HAVE_ELEM)) { |
| 7911 | /* This should happen only when we haven't parsed |
| 7912 | the init element above for fear of committing a |
| 7913 | string constant to memory too early. */ |
| 7914 | if (tok != TOK_STR && tok != TOK_LSTR) |
| 7915 | expect("string constant" ); |
| 7916 | parse_init_elem(!p->sec ? EXPR_ANY : EXPR_CONST); |
| 7917 | } |
| 7918 | init_putv: |
| 7919 | if (!p->sec && (flags & DIF_CLEAR) /* container was already zero'd */ |
| 7920 | && (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST |
| 7921 | && vtop->c.i == 0 |
| 7922 | && btype_size(type->t & VT_BTYPE) /* not for fp constants */ |
| 7923 | ) |
| 7924 | vpop(); |
| 7925 | else |
| 7926 | init_putv(p, type, c); |
| 7927 | } |
| 7928 | } |
| 7929 | |
| 7930 | /* parse an initializer for type 't' if 'has_init' is non zero, and |
| 7931 | allocate space in local or global data space ('r' is either |
| 7932 | VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated |
| 7933 | variable 'v' of scope 'scope' is declared before initializers |
| 7934 | are parsed. If 'v' is zero, then a reference to the new object |
| 7935 | is put in the value stack. If 'has_init' is 2, a special parsing |
| 7936 | is done to handle string constants. */ |
| 7937 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
| 7938 | int has_init, int v, int scope) |
| 7939 | { |
| 7940 | int size, align, addr; |
| 7941 | TokenString *init_str = NULL; |
| 7942 | |
| 7943 | Section *sec; |
| 7944 | Sym *flexible_array; |
| 7945 | Sym *sym = NULL; |
| 7946 | int saved_nocode_wanted = nocode_wanted; |
| 7947 | #ifdef CONFIG_TCC_BCHECK |
| 7948 | int bcheck = tcc_state->do_bounds_check && !NODATA_WANTED; |
| 7949 | #endif |
| 7950 | init_params p = {0}; |
| 7951 | |
| 7952 | /* Always allocate static or global variables */ |
| 7953 | if (v && (r & VT_VALMASK) == VT_CONST) |
| 7954 | nocode_wanted |= 0x80000000; |
| 7955 | |
| 7956 | flexible_array = NULL; |
| 7957 | size = type_size(type, &align); |
| 7958 | |
| 7959 | /* exactly one flexible array may be initialized, either the |
| 7960 | toplevel array or the last member of the toplevel struct */ |
| 7961 | |
| 7962 | if (size < 0) { |
| 7963 | /* If the base type itself was an array type of unspecified size |
| 7964 | (like in 'typedef int arr[]; arr x = {1};') then we will |
| 7965 | overwrite the unknown size by the real one for this decl. |
| 7966 | We need to unshare the ref symbol holding that size. */ |
| 7967 | type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c); |
| 7968 | p.flex_array_ref = type->ref; |
| 7969 | |
| 7970 | } else if (has_init && (type->t & VT_BTYPE) == VT_STRUCT) { |
| 7971 | Sym *field = type->ref->next; |
| 7972 | if (field) { |
| 7973 | while (field->next) |
| 7974 | field = field->next; |
| 7975 | if (field->type.t & VT_ARRAY && field->type.ref->c < 0) { |
| 7976 | flexible_array = field; |
| 7977 | p.flex_array_ref = field->type.ref; |
| 7978 | size = -1; |
| 7979 | } |
| 7980 | } |
| 7981 | } |
| 7982 | |
| 7983 | if (size < 0) { |
| 7984 | /* If unknown size, do a dry-run 1st pass */ |
| 7985 | if (!has_init) |
| 7986 | tcc_error("unknown type size" ); |
| 7987 | if (has_init == 2) { |
| 7988 | /* only get strings */ |
| 7989 | init_str = tok_str_alloc(); |
| 7990 | while (tok == TOK_STR || tok == TOK_LSTR) { |
| 7991 | tok_str_add_tok(init_str); |
| 7992 | next(); |
| 7993 | } |
| 7994 | tok_str_add(init_str, -1); |
| 7995 | tok_str_add(init_str, 0); |
| 7996 | } else |
| 7997 | skip_or_save_block(&init_str); |
| 7998 | unget_tok(0); |
| 7999 | |
| 8000 | /* compute size */ |
| 8001 | begin_macro(init_str, 1); |
| 8002 | next(); |
| 8003 | decl_initializer(&p, type, 0, DIF_FIRST | DIF_SIZE_ONLY); |
| 8004 | /* prepare second initializer parsing */ |
| 8005 | macro_ptr = init_str->str; |
| 8006 | next(); |
| 8007 | |
| 8008 | /* if still unknown size, error */ |
| 8009 | size = type_size(type, &align); |
| 8010 | if (size < 0) |
| 8011 | tcc_error("unknown type size" ); |
| 8012 | |
| 8013 | /* If there's a flex member and it was used in the initializer |
| 8014 | adjust size. */ |
| 8015 | if (flexible_array && flexible_array->type.ref->c > 0) |
| 8016 | size += flexible_array->type.ref->c |
| 8017 | * pointed_size(&flexible_array->type); |
| 8018 | } |
| 8019 | |
| 8020 | /* take into account specified alignment if bigger */ |
| 8021 | if (ad->a.aligned) { |
| 8022 | int speca = 1 << (ad->a.aligned - 1); |
| 8023 | if (speca > align) |
| 8024 | align = speca; |
| 8025 | } else if (ad->a.packed) { |
| 8026 | align = 1; |
| 8027 | } |
| 8028 | |
| 8029 | if (!v && NODATA_WANTED) |
| 8030 | size = 0, align = 1; |
| 8031 | |
| 8032 | if ((r & VT_VALMASK) == VT_LOCAL) { |
| 8033 | sec = NULL; |
| 8034 | #ifdef CONFIG_TCC_BCHECK |
| 8035 | if (bcheck && v) { |
| 8036 | /* add padding between stack variables for bound checking */ |
| 8037 | loc--; |
| 8038 | } |
| 8039 | #endif |
| 8040 | loc = (loc - size) & -align; |
| 8041 | addr = loc; |
| 8042 | p.local_offset = addr + size; |
| 8043 | #ifdef CONFIG_TCC_BCHECK |
| 8044 | if (bcheck && v) { |
| 8045 | /* add padding between stack variables for bound checking */ |
| 8046 | loc--; |
| 8047 | } |
| 8048 | #endif |
| 8049 | if (v) { |
| 8050 | /* local variable */ |
| 8051 | #ifdef CONFIG_TCC_ASM |
| 8052 | if (ad->asm_label) { |
| 8053 | int reg = asm_parse_regvar(ad->asm_label); |
| 8054 | if (reg >= 0) |
| 8055 | r = (r & ~VT_VALMASK) | reg; |
| 8056 | } |
| 8057 | #endif |
| 8058 | sym = sym_push(v, type, r, addr); |
| 8059 | if (ad->cleanup_func) { |
| 8060 | Sym *cls = sym_push2(&all_cleanups, |
| 8061 | SYM_FIELD | ++cur_scope->cl.n, 0, 0); |
| 8062 | cls->prev_tok = sym; |
| 8063 | cls->next = ad->cleanup_func; |
| 8064 | cls->ncl = cur_scope->cl.s; |
| 8065 | cur_scope->cl.s = cls; |
| 8066 | } |
| 8067 | |
| 8068 | sym->a = ad->a; |
| 8069 | } else { |
| 8070 | /* push local reference */ |
| 8071 | vset(type, r, addr); |
| 8072 | } |
| 8073 | } else { |
| 8074 | if (v && scope == VT_CONST) { |
| 8075 | /* see if the symbol was already defined */ |
| 8076 | sym = sym_find(v); |
| 8077 | if (sym) { |
| 8078 | patch_storage(sym, ad, type); |
| 8079 | /* we accept several definitions of the same global variable. */ |
| 8080 | if (!has_init && sym->c && elfsym(sym)->st_shndx != SHN_UNDEF) |
| 8081 | goto no_alloc; |
| 8082 | } |
| 8083 | } |
| 8084 | |
| 8085 | /* allocate symbol in corresponding section */ |
| 8086 | sec = ad->section; |
| 8087 | if (!sec) { |
| 8088 | if (has_init) |
| 8089 | sec = data_section; |
| 8090 | else if (tcc_state->nocommon) |
| 8091 | sec = bss_section; |
| 8092 | } |
| 8093 | |
| 8094 | if (sec) { |
| 8095 | addr = section_add(sec, size, align); |
| 8096 | #ifdef CONFIG_TCC_BCHECK |
| 8097 | /* add padding if bound check */ |
| 8098 | if (bcheck) |
| 8099 | section_add(sec, 1, 1); |
| 8100 | #endif |
| 8101 | } else { |
| 8102 | addr = align; /* SHN_COMMON is special, symbol value is align */ |
| 8103 | sec = common_section; |
| 8104 | } |
| 8105 | |
| 8106 | if (v) { |
| 8107 | if (!sym) { |
| 8108 | sym = sym_push(v, type, r | VT_SYM, 0); |
| 8109 | patch_storage(sym, ad, NULL); |
| 8110 | } |
| 8111 | /* update symbol definition */ |
| 8112 | put_extern_sym(sym, sec, addr, size); |
| 8113 | } else { |
| 8114 | /* push global reference */ |
| 8115 | vpush_ref(type, sec, addr, size); |
| 8116 | sym = vtop->sym; |
| 8117 | vtop->r |= r; |
| 8118 | } |
| 8119 | |
| 8120 | #ifdef CONFIG_TCC_BCHECK |
| 8121 | /* handles bounds now because the symbol must be defined |
| 8122 | before for the relocation */ |
| 8123 | if (bcheck) { |
| 8124 | addr_t *bounds_ptr; |
| 8125 | |
| 8126 | greloca(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR, 0); |
| 8127 | /* then add global bound info */ |
| 8128 | bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(addr_t)); |
| 8129 | bounds_ptr[0] = 0; /* relocated */ |
| 8130 | bounds_ptr[1] = size; |
| 8131 | } |
| 8132 | #endif |
| 8133 | } |
| 8134 | |
| 8135 | if (type->t & VT_VLA) { |
| 8136 | int a; |
| 8137 | |
| 8138 | if (NODATA_WANTED) |
| 8139 | goto no_alloc; |
| 8140 | |
| 8141 | /* save current stack pointer */ |
| 8142 | if (root_scope->vla.loc == 0) { |
| 8143 | struct scope *v = cur_scope; |
| 8144 | gen_vla_sp_save(loc -= PTR_SIZE); |
| 8145 | do v->vla.loc = loc; while ((v = v->prev)); |
| 8146 | } |
| 8147 | |
| 8148 | vla_runtime_type_size(type, &a); |
| 8149 | gen_vla_alloc(type, a); |
| 8150 | #if defined TCC_TARGET_PE && defined TCC_TARGET_X86_64 |
| 8151 | /* on _WIN64, because of the function args scratch area, the |
| 8152 | result of alloca differs from RSP and is returned in RAX. */ |
| 8153 | gen_vla_result(addr), addr = (loc -= PTR_SIZE); |
| 8154 | #endif |
| 8155 | gen_vla_sp_save(addr); |
| 8156 | cur_scope->vla.loc = addr; |
| 8157 | cur_scope->vla.num++; |
| 8158 | } else if (has_init) { |
| 8159 | p.sec = sec; |
| 8160 | decl_initializer(&p, type, addr, DIF_FIRST); |
| 8161 | /* patch flexible array member size back to -1, */ |
| 8162 | /* for possible subsequent similar declarations */ |
| 8163 | if (flexible_array) |
| 8164 | flexible_array->type.ref->c = -1; |
| 8165 | } |
| 8166 | |
| 8167 | no_alloc: |
| 8168 | /* restore parse state if needed */ |
| 8169 | if (init_str) { |
| 8170 | end_macro(); |
| 8171 | next(); |
| 8172 | } |
| 8173 | |
| 8174 | nocode_wanted = saved_nocode_wanted; |
| 8175 | } |
| 8176 | |
| 8177 | /* parse a function defined by symbol 'sym' and generate its code in |
| 8178 | 'cur_text_section' */ |
| 8179 | static void gen_function(Sym *sym) |
| 8180 | { |
| 8181 | struct scope f = { 0 }; |
| 8182 | cur_scope = root_scope = &f; |
| 8183 | nocode_wanted = 0; |
| 8184 | ind = cur_text_section->data_offset; |
| 8185 | if (sym->a.aligned) { |
| 8186 | size_t newoff = section_add(cur_text_section, 0, |
| 8187 | 1 << (sym->a.aligned - 1)); |
| 8188 | gen_fill_nops(newoff - ind); |
| 8189 | } |
| 8190 | /* NOTE: we patch the symbol size later */ |
| 8191 | put_extern_sym(sym, cur_text_section, ind, 0); |
| 8192 | if (sym->type.ref->f.func_ctor) |
| 8193 | add_array (tcc_state, ".init_array" , sym->c); |
| 8194 | if (sym->type.ref->f.func_dtor) |
| 8195 | add_array (tcc_state, ".fini_array" , sym->c); |
| 8196 | |
| 8197 | funcname = get_tok_str(sym->v, NULL); |
| 8198 | func_ind = ind; |
| 8199 | func_vt = sym->type.ref->type; |
| 8200 | func_var = sym->type.ref->f.func_type == FUNC_ELLIPSIS; |
| 8201 | |
| 8202 | /* put debug symbol */ |
| 8203 | tcc_debug_funcstart(tcc_state, sym); |
| 8204 | /* push a dummy symbol to enable local sym storage */ |
| 8205 | sym_push2(&local_stack, SYM_FIELD, 0, 0); |
| 8206 | local_scope = 1; /* for function parameters */ |
| 8207 | gfunc_prolog(sym); |
| 8208 | local_scope = 0; |
| 8209 | rsym = 0; |
| 8210 | clear_temp_local_var_list(); |
| 8211 | block(0); |
| 8212 | gsym(rsym); |
| 8213 | nocode_wanted = 0; |
| 8214 | /* reset local stack */ |
| 8215 | pop_local_syms(&local_stack, NULL, 0, func_var); |
| 8216 | gfunc_epilog(); |
| 8217 | cur_text_section->data_offset = ind; |
| 8218 | local_scope = 0; |
| 8219 | label_pop(&global_label_stack, NULL, 0); |
| 8220 | sym_pop(&all_cleanups, NULL, 0); |
| 8221 | /* patch symbol size */ |
| 8222 | elfsym(sym)->st_size = ind - func_ind; |
| 8223 | /* end of function */ |
| 8224 | tcc_debug_funcend(tcc_state, ind - func_ind); |
| 8225 | /* It's better to crash than to generate wrong code */ |
| 8226 | cur_text_section = NULL; |
| 8227 | funcname = "" ; /* for safety */ |
| 8228 | func_vt.t = VT_VOID; /* for safety */ |
| 8229 | func_var = 0; /* for safety */ |
| 8230 | ind = 0; /* for safety */ |
| 8231 | nocode_wanted = 0x80000000; |
| 8232 | check_vstack(); |
| 8233 | /* do this after funcend debug info */ |
| 8234 | next(); |
| 8235 | } |
| 8236 | |
| 8237 | static void gen_inline_functions(TCCState *s) |
| 8238 | { |
| 8239 | Sym *sym; |
| 8240 | int inline_generated, i; |
| 8241 | struct InlineFunc *fn; |
| 8242 | |
| 8243 | tcc_open_bf(s, ":inline:" , 0); |
| 8244 | /* iterate while inline function are referenced */ |
| 8245 | do { |
| 8246 | inline_generated = 0; |
| 8247 | for (i = 0; i < s->nb_inline_fns; ++i) { |
| 8248 | fn = s->inline_fns[i]; |
| 8249 | sym = fn->sym; |
| 8250 | if (sym && (sym->c || !(sym->type.t & VT_INLINE))) { |
| 8251 | /* the function was used or forced (and then not internal): |
| 8252 | generate its code and convert it to a normal function */ |
| 8253 | fn->sym = NULL; |
| 8254 | tcc_debug_putfile(s, fn->filename); |
| 8255 | begin_macro(fn->func_str, 1); |
| 8256 | next(); |
| 8257 | cur_text_section = text_section; |
| 8258 | gen_function(sym); |
| 8259 | end_macro(); |
| 8260 | |
| 8261 | inline_generated = 1; |
| 8262 | } |
| 8263 | } |
| 8264 | } while (inline_generated); |
| 8265 | tcc_close(); |
| 8266 | } |
| 8267 | |
| 8268 | static void free_inline_functions(TCCState *s) |
| 8269 | { |
| 8270 | int i; |
| 8271 | /* free tokens of unused inline functions */ |
| 8272 | for (i = 0; i < s->nb_inline_fns; ++i) { |
| 8273 | struct InlineFunc *fn = s->inline_fns[i]; |
| 8274 | if (fn->sym) |
| 8275 | tok_str_free(fn->func_str); |
| 8276 | } |
| 8277 | dynarray_reset(&s->inline_fns, &s->nb_inline_fns); |
| 8278 | } |
| 8279 | |
| 8280 | /* 'l' is VT_LOCAL or VT_CONST to define default storage type, or VT_CMP |
| 8281 | if parsing old style parameter decl list (and FUNC_SYM is set then) */ |
| 8282 | static int decl0(int l, int is_for_loop_init, Sym *func_sym) |
| 8283 | { |
| 8284 | int v, has_init, r; |
| 8285 | CType type, btype; |
| 8286 | Sym *sym; |
| 8287 | AttributeDef ad, adbase; |
| 8288 | |
| 8289 | while (1) { |
| 8290 | if (tok == TOK_STATIC_ASSERT) { |
| 8291 | CString error_str; |
| 8292 | int c; |
| 8293 | |
| 8294 | next(); |
| 8295 | skip('('); |
| 8296 | c = expr_const(); |
| 8297 | |
| 8298 | if (tok == ')') { |
| 8299 | if (!c) |
| 8300 | tcc_error("_Static_assert fail" ); |
| 8301 | next(); |
| 8302 | goto static_assert_out; |
| 8303 | } |
| 8304 | |
| 8305 | skip(','); |
| 8306 | parse_mult_str(&error_str, "string constant" ); |
| 8307 | if (c == 0) |
| 8308 | tcc_error("%s" , (char *)error_str.data); |
| 8309 | cstr_free(&error_str); |
| 8310 | skip(')'); |
| 8311 | static_assert_out: |
| 8312 | skip(';'); |
| 8313 | continue; |
| 8314 | } |
| 8315 | if (!parse_btype(&btype, &adbase)) { |
| 8316 | if (is_for_loop_init) |
| 8317 | return 0; |
| 8318 | /* skip redundant ';' if not in old parameter decl scope */ |
| 8319 | if (tok == ';' && l != VT_CMP) { |
| 8320 | next(); |
| 8321 | continue; |
| 8322 | } |
| 8323 | if (l != VT_CONST) |
| 8324 | break; |
| 8325 | if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { |
| 8326 | /* global asm block */ |
| 8327 | asm_global_instr(); |
| 8328 | continue; |
| 8329 | } |
| 8330 | if (tok >= TOK_UIDENT) { |
| 8331 | /* special test for old K&R protos without explicit int |
| 8332 | type. Only accepted when defining global data */ |
| 8333 | btype.t = VT_INT; |
| 8334 | } else { |
| 8335 | if (tok != TOK_EOF) |
| 8336 | expect("declaration" ); |
| 8337 | break; |
| 8338 | } |
| 8339 | } |
| 8340 | if (tok == ';') { |
| 8341 | if ((btype.t & VT_BTYPE) == VT_STRUCT) { |
| 8342 | int v = btype.ref->v; |
| 8343 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM) |
| 8344 | tcc_warning("unnamed struct/union that defines no instances" ); |
| 8345 | next(); |
| 8346 | continue; |
| 8347 | } |
| 8348 | if (IS_ENUM(btype.t)) { |
| 8349 | next(); |
| 8350 | continue; |
| 8351 | } |
| 8352 | } |
| 8353 | while (1) { /* iterate thru each declaration */ |
| 8354 | type = btype; |
| 8355 | ad = adbase; |
| 8356 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
| 8357 | #if 0 |
| 8358 | { |
| 8359 | char buf[500]; |
| 8360 | type_to_str(buf, sizeof(buf), &type, get_tok_str(v, NULL)); |
| 8361 | printf("type = '%s'\n" , buf); |
| 8362 | } |
| 8363 | #endif |
| 8364 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
| 8365 | if ((type.t & VT_STATIC) && (l == VT_LOCAL)) |
| 8366 | tcc_error("function without file scope cannot be static" ); |
| 8367 | /* if old style function prototype, we accept a |
| 8368 | declaration list */ |
| 8369 | sym = type.ref; |
| 8370 | if (sym->f.func_type == FUNC_OLD && l == VT_CONST) |
| 8371 | decl0(VT_CMP, 0, sym); |
| 8372 | #ifdef TCC_TARGET_MACHO |
| 8373 | if (sym->f.func_alwinl |
| 8374 | && ((type.t & (VT_EXTERN | VT_INLINE)) |
| 8375 | == (VT_EXTERN | VT_INLINE))) { |
| 8376 | /* always_inline functions must be handled as if they |
| 8377 | don't generate multiple global defs, even if extern |
| 8378 | inline, i.e. GNU inline semantics for those. Rewrite |
| 8379 | them into static inline. */ |
| 8380 | type.t &= ~VT_EXTERN; |
| 8381 | type.t |= VT_STATIC; |
| 8382 | } |
| 8383 | #endif |
| 8384 | /* always compile 'extern inline' */ |
| 8385 | if (type.t & VT_EXTERN) |
| 8386 | type.t &= ~VT_INLINE; |
| 8387 | } |
| 8388 | |
| 8389 | if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
| 8390 | ad.asm_label = asm_label_instr(); |
| 8391 | /* parse one last attribute list, after asm label */ |
| 8392 | parse_attribute(&ad); |
| 8393 | #if 0 |
| 8394 | /* gcc does not allow __asm__("label") with function definition, |
| 8395 | but why not ... */ |
| 8396 | if (tok == '{') |
| 8397 | expect(";" ); |
| 8398 | #endif |
| 8399 | } |
| 8400 | |
| 8401 | #ifdef TCC_TARGET_PE |
| 8402 | if (ad.a.dllimport || ad.a.dllexport) { |
| 8403 | if (type.t & VT_STATIC) |
| 8404 | tcc_error("cannot have dll linkage with static" ); |
| 8405 | if (type.t & VT_TYPEDEF) { |
| 8406 | tcc_warning("'%s' attribute ignored for typedef" , |
| 8407 | ad.a.dllimport ? (ad.a.dllimport = 0, "dllimport" ) : |
| 8408 | (ad.a.dllexport = 0, "dllexport" )); |
| 8409 | } else if (ad.a.dllimport) { |
| 8410 | if ((type.t & VT_BTYPE) == VT_FUNC) |
| 8411 | ad.a.dllimport = 0; |
| 8412 | else |
| 8413 | type.t |= VT_EXTERN; |
| 8414 | } |
| 8415 | } |
| 8416 | #endif |
| 8417 | if (tok == '{') { |
| 8418 | if (l != VT_CONST) |
| 8419 | tcc_error("cannot use local functions" ); |
| 8420 | if ((type.t & VT_BTYPE) != VT_FUNC) |
| 8421 | expect("function definition" ); |
| 8422 | |
| 8423 | /* reject abstract declarators in function definition |
| 8424 | make old style params without decl have int type */ |
| 8425 | sym = type.ref; |
| 8426 | while ((sym = sym->next) != NULL) { |
| 8427 | if (!(sym->v & ~SYM_FIELD)) |
| 8428 | expect("identifier" ); |
| 8429 | if (sym->type.t == VT_VOID) |
| 8430 | sym->type = int_type; |
| 8431 | } |
| 8432 | |
| 8433 | /* apply post-declaraton attributes */ |
| 8434 | merge_funcattr(&type.ref->f, &ad.f); |
| 8435 | |
| 8436 | /* put function symbol */ |
| 8437 | type.t &= ~VT_EXTERN; |
| 8438 | sym = external_sym(v, &type, 0, &ad); |
| 8439 | |
| 8440 | /* static inline functions are just recorded as a kind |
| 8441 | of macro. Their code will be emitted at the end of |
| 8442 | the compilation unit only if they are used */ |
| 8443 | if (sym->type.t & VT_INLINE) { |
| 8444 | struct InlineFunc *fn; |
| 8445 | fn = tcc_malloc(sizeof *fn + strlen(file->filename)); |
| 8446 | strcpy(fn->filename, file->filename); |
| 8447 | fn->sym = sym; |
| 8448 | skip_or_save_block(&fn->func_str); |
| 8449 | dynarray_add(&tcc_state->inline_fns, |
| 8450 | &tcc_state->nb_inline_fns, fn); |
| 8451 | } else { |
| 8452 | /* compute text section */ |
| 8453 | cur_text_section = ad.section; |
| 8454 | if (!cur_text_section) |
| 8455 | cur_text_section = text_section; |
| 8456 | gen_function(sym); |
| 8457 | } |
| 8458 | break; |
| 8459 | } else { |
| 8460 | if (l == VT_CMP) { |
| 8461 | /* find parameter in function parameter list */ |
| 8462 | for (sym = func_sym->next; sym; sym = sym->next) |
| 8463 | if ((sym->v & ~SYM_FIELD) == v) |
| 8464 | goto found; |
| 8465 | tcc_error("declaration for parameter '%s' but no such parameter" , |
| 8466 | get_tok_str(v, NULL)); |
| 8467 | found: |
| 8468 | if (type.t & VT_STORAGE) /* 'register' is okay */ |
| 8469 | tcc_error("storage class specified for '%s'" , |
| 8470 | get_tok_str(v, NULL)); |
| 8471 | if (sym->type.t != VT_VOID) |
| 8472 | tcc_error("redefinition of parameter '%s'" , |
| 8473 | get_tok_str(v, NULL)); |
| 8474 | convert_parameter_type(&type); |
| 8475 | sym->type = type; |
| 8476 | } else if (type.t & VT_TYPEDEF) { |
| 8477 | /* save typedefed type */ |
| 8478 | /* XXX: test storage specifiers ? */ |
| 8479 | sym = sym_find(v); |
| 8480 | if (sym && sym->sym_scope == local_scope) { |
| 8481 | if (!is_compatible_types(&sym->type, &type) |
| 8482 | || !(sym->type.t & VT_TYPEDEF)) |
| 8483 | tcc_error("incompatible redefinition of '%s'" , |
| 8484 | get_tok_str(v, NULL)); |
| 8485 | sym->type = type; |
| 8486 | } else { |
| 8487 | sym = sym_push(v, &type, 0, 0); |
| 8488 | } |
| 8489 | sym->a = ad.a; |
| 8490 | sym->f = ad.f; |
| 8491 | if (tcc_state->do_debug) |
| 8492 | tcc_debug_typedef (tcc_state, sym); |
| 8493 | } else if ((type.t & VT_BTYPE) == VT_VOID |
| 8494 | && !(type.t & VT_EXTERN)) { |
| 8495 | tcc_error("declaration of void object" ); |
| 8496 | } else { |
| 8497 | r = 0; |
| 8498 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
| 8499 | /* external function definition */ |
| 8500 | /* specific case for func_call attribute */ |
| 8501 | type.ref->f = ad.f; |
| 8502 | } else if (!(type.t & VT_ARRAY)) { |
| 8503 | /* not lvalue if array */ |
| 8504 | r |= VT_LVAL; |
| 8505 | } |
| 8506 | has_init = (tok == '='); |
| 8507 | if (has_init && (type.t & VT_VLA)) |
| 8508 | tcc_error("variable length array cannot be initialized" ); |
| 8509 | if (((type.t & VT_EXTERN) && (!has_init || l != VT_CONST)) |
| 8510 | || (type.t & VT_BTYPE) == VT_FUNC |
| 8511 | /* as with GCC, uninitialized global arrays with no size |
| 8512 | are considered extern: */ |
| 8513 | || ((type.t & VT_ARRAY) && !has_init |
| 8514 | && l == VT_CONST && type.ref->c < 0) |
| 8515 | ) { |
| 8516 | /* external variable or function */ |
| 8517 | type.t |= VT_EXTERN; |
| 8518 | sym = external_sym(v, &type, r, &ad); |
| 8519 | if (ad.alias_target) { |
| 8520 | /* Aliases need to be emitted when their target |
| 8521 | symbol is emitted, even if perhaps unreferenced. |
| 8522 | We only support the case where the base is |
| 8523 | already defined, otherwise we would need |
| 8524 | deferring to emit the aliases until the end of |
| 8525 | the compile unit. */ |
| 8526 | Sym *alias_target = sym_find(ad.alias_target); |
| 8527 | ElfSym *esym = elfsym(alias_target); |
| 8528 | if (!esym) |
| 8529 | tcc_error("unsupported forward __alias__ attribute" ); |
| 8530 | put_extern_sym2(sym, esym->st_shndx, |
| 8531 | esym->st_value, esym->st_size, 1); |
| 8532 | } |
| 8533 | } else { |
| 8534 | if (type.t & VT_STATIC) |
| 8535 | r |= VT_CONST; |
| 8536 | else |
| 8537 | r |= l; |
| 8538 | if (has_init) |
| 8539 | next(); |
| 8540 | else if (l == VT_CONST) |
| 8541 | /* uninitialized global variables may be overridden */ |
| 8542 | type.t |= VT_EXTERN; |
| 8543 | decl_initializer_alloc(&type, &ad, r, has_init, v, l); |
| 8544 | } |
| 8545 | } |
| 8546 | if (tok != ',') { |
| 8547 | if (is_for_loop_init) |
| 8548 | return 1; |
| 8549 | skip(';'); |
| 8550 | break; |
| 8551 | } |
| 8552 | next(); |
| 8553 | } |
| 8554 | } |
| 8555 | } |
| 8556 | return 0; |
| 8557 | } |
| 8558 | |
| 8559 | static void decl(int l) |
| 8560 | { |
| 8561 | decl0(l, 0, NULL); |
| 8562 | } |
| 8563 | |
| 8564 | /* ------------------------------------------------------------------------- */ |
| 8565 | #undef gjmp_addr |
| 8566 | #undef gjmp |
| 8567 | /* ------------------------------------------------------------------------- */ |
| 8568 | |