Rev 6429 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6429 | siemargl | 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 | #include "tcc.h" |
||
22 | |||
23 | /********************************************************/ |
||
24 | /* global variables */ |
||
25 | |||
26 | /* loc : local variable index |
||
27 | ind : output code index |
||
28 | rsym: return symbol |
||
29 | anon_sym: anonymous symbol index |
||
30 | */ |
||
31 | ST_DATA int rsym, anon_sym, ind, loc; |
||
32 | |||
33 | ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ |
||
34 | ST_DATA Section *cur_text_section; /* current section where function code is generated */ |
||
35 | #ifdef CONFIG_TCC_ASM |
||
36 | ST_DATA Section *last_text_section; /* to handle .previous asm directive */ |
||
37 | #endif |
||
38 | #ifdef CONFIG_TCC_BCHECK |
||
39 | /* bound check related sections */ |
||
40 | ST_DATA Section *bounds_section; /* contains global data bound description */ |
||
41 | ST_DATA Section *lbounds_section; /* contains local data bound description */ |
||
42 | #endif |
||
43 | /* symbol sections */ |
||
44 | ST_DATA Section *symtab_section, *strtab_section; |
||
45 | /* debug sections */ |
||
46 | ST_DATA Section *stab_section, *stabstr_section; |
||
47 | ST_DATA Sym *sym_free_first; |
||
48 | ST_DATA void **sym_pools; |
||
49 | ST_DATA int nb_sym_pools; |
||
50 | |||
51 | ST_DATA Sym *global_stack; |
||
52 | ST_DATA Sym *local_stack; |
||
53 | ST_DATA Sym *scope_stack_bottom; |
||
54 | ST_DATA Sym *define_stack; |
||
55 | ST_DATA Sym *global_label_stack; |
||
56 | ST_DATA Sym *local_label_stack; |
||
57 | |||
58 | ST_DATA int vlas_in_scope; /* number of VLAs that are currently in scope */ |
||
59 | ST_DATA int vla_sp_root_loc; /* vla_sp_loc for SP before any VLAs were pushed */ |
||
60 | ST_DATA int vla_sp_loc; /* Pointer to variable holding location to store stack pointer on the stack when modifying stack pointer */ |
||
61 | |||
62 | ST_DATA SValue __vstack[1+VSTACK_SIZE], *vtop, *pvtop; |
||
63 | |||
64 | ST_DATA int const_wanted; /* true if constant wanted */ |
||
65 | ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ |
||
66 | ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ |
||
67 | ST_DATA CType func_vt; /* current function return type (used by return instruction) */ |
||
68 | ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ |
||
69 | ST_DATA int func_vc; |
||
70 | ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ |
||
71 | ST_DATA const char *funcname; |
||
72 | |||
73 | ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; |
||
74 | |||
75 | /* ------------------------------------------------------------------------- */ |
||
76 | static void gen_cast(CType *type); |
||
77 | static inline CType *pointed_type(CType *type); |
||
78 | static int is_compatible_types(CType *type1, CType *type2); |
||
79 | static int parse_btype(CType *type, AttributeDef *ad); |
||
80 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td); |
||
81 | static void parse_expr_type(CType *type); |
||
82 | static void decl_initializer(CType *type, Section *sec, unsigned long c, int first, int size_only); |
||
83 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg, int is_expr); |
||
84 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, int has_init, int v, int scope); |
||
85 | static int decl0(int l, int is_for_loop_init); |
||
86 | static void expr_eq(void); |
||
87 | static void expr_lor_const(void); |
||
88 | static void unary_type(CType *type); |
||
89 | static void vla_runtime_type_size(CType *type, int *a); |
||
90 | static void vla_sp_restore(void); |
||
91 | static void vla_sp_restore_root(void); |
||
92 | static int is_compatible_parameter_types(CType *type1, CType *type2); |
||
93 | static void expr_type(CType *type); |
||
94 | ST_FUNC void vpush64(int ty, unsigned long long v); |
||
95 | ST_FUNC void vpush(CType *type); |
||
96 | ST_FUNC int gvtst(int inv, int t); |
||
97 | ST_FUNC int is_btype_size(int bt); |
||
98 | |||
99 | ST_INLN int is_float(int t) |
||
100 | { |
||
101 | int bt; |
||
102 | bt = t & VT_BTYPE; |
||
103 | return bt == VT_LDOUBLE || bt == VT_DOUBLE || bt == VT_FLOAT || bt == VT_QFLOAT; |
||
104 | } |
||
105 | |||
106 | /* we use our own 'finite' function to avoid potential problems with |
||
107 | non standard math libs */ |
||
108 | /* XXX: endianness dependent */ |
||
109 | ST_FUNC int ieee_finite(double d) |
||
110 | { |
||
111 | int p[4]; |
||
112 | memcpy(p, &d, sizeof(double)); |
||
113 | return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; |
||
114 | } |
||
115 | |||
116 | ST_FUNC void test_lvalue(void) |
||
117 | { |
||
118 | if (!(vtop->r & VT_LVAL)) |
||
119 | expect("lvalue"); |
||
120 | } |
||
121 | |||
122 | ST_FUNC void check_vstack(void) |
||
123 | { |
||
124 | if (pvtop != vtop) |
||
125 | tcc_error("internal compiler error: vstack leak (%d)", vtop - pvtop); |
||
126 | } |
||
127 | |||
128 | /* ------------------------------------------------------------------------- */ |
||
129 | /* symbol allocator */ |
||
130 | static Sym *__sym_malloc(void) |
||
131 | { |
||
132 | Sym *sym_pool, *sym, *last_sym; |
||
133 | int i; |
||
134 | |||
135 | sym_pool = tcc_malloc(SYM_POOL_NB * sizeof(Sym)); |
||
136 | dynarray_add(&sym_pools, &nb_sym_pools, sym_pool); |
||
137 | |||
138 | last_sym = sym_free_first; |
||
139 | sym = sym_pool; |
||
140 | for(i = 0; i < SYM_POOL_NB; i++) { |
||
141 | sym->next = last_sym; |
||
142 | last_sym = sym; |
||
143 | sym++; |
||
144 | } |
||
145 | sym_free_first = last_sym; |
||
146 | return last_sym; |
||
147 | } |
||
148 | |||
149 | static inline Sym *sym_malloc(void) |
||
150 | { |
||
151 | Sym *sym; |
||
152 | sym = sym_free_first; |
||
153 | if (!sym) |
||
154 | sym = __sym_malloc(); |
||
155 | sym_free_first = sym->next; |
||
156 | return sym; |
||
157 | } |
||
158 | |||
159 | ST_INLN void sym_free(Sym *sym) |
||
160 | { |
||
161 | sym->next = sym_free_first; |
||
162 | sym_free_first = sym; |
||
163 | } |
||
164 | |||
165 | /* push, without hashing */ |
||
166 | ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c) |
||
167 | { |
||
168 | Sym *s; |
||
169 | if (ps == &local_stack) { |
||
170 | for (s = *ps; s && s != scope_stack_bottom; s = s->prev) |
||
171 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM && s->v == v) |
||
172 | tcc_error("incompatible types for redefinition of '%s'", |
||
173 | get_tok_str(v, NULL)); |
||
174 | } |
||
175 | s = sym_malloc(); |
||
176 | s->asm_label = 0; |
||
177 | s->v = v; |
||
178 | s->type.t = t; |
||
179 | s->type.ref = NULL; |
||
180 | #ifdef _WIN64 |
||
181 | s->d = NULL; |
||
182 | #endif |
||
183 | s->c = c; |
||
184 | s->next = NULL; |
||
185 | /* add in stack */ |
||
186 | s->prev = *ps; |
||
187 | *ps = s; |
||
188 | return s; |
||
189 | } |
||
190 | |||
191 | /* find a symbol and return its associated structure. 's' is the top |
||
192 | of the symbol stack */ |
||
193 | ST_FUNC Sym *sym_find2(Sym *s, int v) |
||
194 | { |
||
195 | while (s) { |
||
196 | if (s->v == v) |
||
197 | return s; |
||
198 | else if (s->v == -1) |
||
199 | return NULL; |
||
200 | s = s->prev; |
||
201 | } |
||
202 | return NULL; |
||
203 | } |
||
204 | |||
205 | /* structure lookup */ |
||
206 | ST_INLN Sym *struct_find(int v) |
||
207 | { |
||
208 | v -= TOK_IDENT; |
||
209 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
210 | return NULL; |
||
211 | return table_ident[v]->sym_struct; |
||
212 | } |
||
213 | |||
214 | /* find an identifier */ |
||
215 | ST_INLN Sym *sym_find(int v) |
||
216 | { |
||
217 | v -= TOK_IDENT; |
||
218 | if ((unsigned)v >= (unsigned)(tok_ident - TOK_IDENT)) |
||
219 | return NULL; |
||
220 | return table_ident[v]->sym_identifier; |
||
221 | } |
||
222 | |||
223 | /* push a given symbol on the symbol stack */ |
||
224 | ST_FUNC Sym *sym_push(int v, CType *type, int r, int c) |
||
225 | { |
||
226 | Sym *s, **ps; |
||
227 | TokenSym *ts; |
||
228 | |||
229 | if (local_stack) |
||
230 | ps = &local_stack; |
||
231 | else |
||
232 | ps = &global_stack; |
||
233 | s = sym_push2(ps, v, type->t, c); |
||
234 | s->type.ref = type->ref; |
||
235 | s->r = r; |
||
236 | /* don't record fields or anonymous symbols */ |
||
237 | /* XXX: simplify */ |
||
238 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
239 | /* record symbol in token array */ |
||
240 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
241 | if (v & SYM_STRUCT) |
||
242 | ps = &ts->sym_struct; |
||
243 | else |
||
244 | ps = &ts->sym_identifier; |
||
245 | s->prev_tok = *ps; |
||
246 | *ps = s; |
||
247 | } |
||
248 | return s; |
||
249 | } |
||
250 | |||
251 | /* push a global identifier */ |
||
252 | ST_FUNC Sym *global_identifier_push(int v, int t, int c) |
||
253 | { |
||
254 | Sym *s, **ps; |
||
255 | s = sym_push2(&global_stack, v, t, c); |
||
256 | /* don't record anonymous symbol */ |
||
257 | if (v < SYM_FIRST_ANOM) { |
||
258 | ps = &table_ident[v - TOK_IDENT]->sym_identifier; |
||
259 | /* modify the top most local identifier, so that |
||
260 | sym_identifier will point to 's' when popped */ |
||
261 | while (*ps != NULL) |
||
262 | ps = &(*ps)->prev_tok; |
||
263 | s->prev_tok = NULL; |
||
264 | *ps = s; |
||
265 | } |
||
266 | return s; |
||
267 | } |
||
268 | |||
269 | /* pop symbols until top reaches 'b' */ |
||
270 | ST_FUNC void sym_pop(Sym **ptop, Sym *b) |
||
271 | { |
||
272 | Sym *s, *ss, **ps; |
||
273 | TokenSym *ts; |
||
274 | int v; |
||
275 | |||
276 | s = *ptop; |
||
277 | while(s != b) { |
||
278 | ss = s->prev; |
||
279 | v = s->v; |
||
280 | /* remove symbol in token array */ |
||
281 | /* XXX: simplify */ |
||
282 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
283 | ts = table_ident[(v & ~SYM_STRUCT) - TOK_IDENT]; |
||
284 | if (v & SYM_STRUCT) |
||
285 | ps = &ts->sym_struct; |
||
286 | else |
||
287 | ps = &ts->sym_identifier; |
||
288 | *ps = s->prev_tok; |
||
289 | } |
||
290 | sym_free(s); |
||
291 | s = ss; |
||
292 | } |
||
293 | *ptop = b; |
||
294 | } |
||
295 | |||
296 | static void weaken_symbol(Sym *sym) |
||
297 | { |
||
298 | sym->type.t |= VT_WEAK; |
||
299 | if (sym->c > 0) { |
||
300 | int esym_type; |
||
301 | ElfW(Sym) *esym; |
||
302 | |||
303 | esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; |
||
304 | esym_type = ELFW(ST_TYPE)(esym->st_info); |
||
305 | esym->st_info = ELFW(ST_INFO)(STB_WEAK, esym_type); |
||
306 | } |
||
307 | } |
||
308 | |||
309 | static void apply_visibility(Sym *sym, CType *type) |
||
310 | { |
||
311 | int vis = sym->type.t & VT_VIS_MASK; |
||
312 | int vis2 = type->t & VT_VIS_MASK; |
||
313 | if (vis == (STV_DEFAULT << VT_VIS_SHIFT)) |
||
314 | vis = vis2; |
||
315 | else if (vis2 == (STV_DEFAULT << VT_VIS_SHIFT)) |
||
316 | ; |
||
317 | else |
||
318 | vis = (vis < vis2) ? vis : vis2; |
||
319 | sym->type.t &= ~VT_VIS_MASK; |
||
320 | sym->type.t |= vis; |
||
321 | |||
322 | if (sym->c > 0) { |
||
323 | ElfW(Sym) *esym; |
||
324 | |||
325 | esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; |
||
326 | vis >>= VT_VIS_SHIFT; |
||
327 | esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | vis; |
||
328 | } |
||
329 | } |
||
330 | |||
331 | /* ------------------------------------------------------------------------- */ |
||
332 | |||
333 | ST_FUNC void swap(int *p, int *q) |
||
334 | { |
||
335 | int t; |
||
336 | t = *p; |
||
337 | *p = *q; |
||
338 | *q = t; |
||
339 | } |
||
340 | |||
341 | static void vsetc(CType *type, int r, CValue *vc) |
||
342 | { |
||
343 | int v; |
||
344 | |||
345 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
346 | tcc_error("memory full (vstack)"); |
||
347 | /* cannot let cpu flags if other instruction are generated. Also |
||
348 | avoid leaving VT_JMP anywhere except on the top of the stack |
||
349 | because it would complicate the code generator. */ |
||
350 | if (vtop >= vstack) { |
||
351 | v = vtop->r & VT_VALMASK; |
||
352 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
||
353 | gv(RC_INT); |
||
354 | } |
||
355 | vtop++; |
||
356 | vtop->type = *type; |
||
357 | vtop->r = r; |
||
358 | vtop->r2 = VT_CONST; |
||
359 | vtop->c = *vc; |
||
360 | } |
||
361 | |||
362 | /* push constant of type "type" with useless value */ |
||
363 | ST_FUNC void vpush(CType *type) |
||
364 | { |
||
365 | CValue cval; |
||
366 | vsetc(type, VT_CONST, &cval); |
||
367 | } |
||
368 | |||
369 | /* push integer constant */ |
||
370 | ST_FUNC void vpushi(int v) |
||
371 | { |
||
372 | CValue cval; |
||
373 | cval.i = v; |
||
374 | vsetc(&int_type, VT_CONST, &cval); |
||
375 | } |
||
376 | |||
377 | /* push a pointer sized constant */ |
||
378 | static void vpushs(addr_t v) |
||
379 | { |
||
380 | CValue cval; |
||
381 | cval.i = v; |
||
382 | vsetc(&size_type, VT_CONST, &cval); |
||
383 | } |
||
384 | |||
385 | /* push arbitrary 64bit constant */ |
||
386 | ST_FUNC void vpush64(int ty, unsigned long long v) |
||
387 | { |
||
388 | CValue cval; |
||
389 | CType ctype; |
||
390 | ctype.t = ty; |
||
391 | ctype.ref = NULL; |
||
392 | cval.i = v; |
||
393 | vsetc(&ctype, VT_CONST, &cval); |
||
394 | } |
||
395 | |||
396 | /* push long long constant */ |
||
397 | static inline void vpushll(long long v) |
||
398 | { |
||
399 | vpush64(VT_LLONG, v); |
||
400 | } |
||
401 | |||
402 | /* push a symbol value of TYPE */ |
||
403 | static inline void vpushsym(CType *type, Sym *sym) |
||
404 | { |
||
405 | CValue cval; |
||
406 | cval.i = 0; |
||
407 | vsetc(type, VT_CONST | VT_SYM, &cval); |
||
408 | vtop->sym = sym; |
||
409 | } |
||
410 | |||
411 | /* Return a static symbol pointing to a section */ |
||
412 | ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
||
413 | { |
||
414 | int v; |
||
415 | Sym *sym; |
||
416 | |||
417 | v = anon_sym++; |
||
418 | sym = global_identifier_push(v, type->t | VT_STATIC, 0); |
||
419 | sym->type.ref = type->ref; |
||
420 | sym->r = VT_CONST | VT_SYM; |
||
421 | put_extern_sym(sym, sec, offset, size); |
||
422 | return sym; |
||
423 | } |
||
424 | |||
425 | /* push a reference to a section offset by adding a dummy symbol */ |
||
426 | static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) |
||
427 | { |
||
428 | vpushsym(type, get_sym_ref(type, sec, offset, size)); |
||
429 | } |
||
430 | |||
431 | /* define a new external reference to a symbol 'v' of type 'u' */ |
||
432 | ST_FUNC Sym *external_global_sym(int v, CType *type, int r) |
||
433 | { |
||
434 | Sym *s; |
||
435 | |||
436 | s = sym_find(v); |
||
437 | if (!s) { |
||
438 | /* push forward reference */ |
||
439 | s = global_identifier_push(v, type->t | VT_EXTERN, 0); |
||
440 | s->type.ref = type->ref; |
||
441 | s->r = r | VT_CONST | VT_SYM; |
||
442 | } |
||
443 | return s; |
||
444 | } |
||
445 | |||
446 | /* define a new external reference to a symbol 'v' */ |
||
447 | static Sym *external_sym(int v, CType *type, int r) |
||
448 | { |
||
449 | Sym *s; |
||
450 | |||
451 | s = sym_find(v); |
||
452 | if (!s) { |
||
453 | /* push forward reference */ |
||
454 | s = sym_push(v, type, r | VT_CONST | VT_SYM, 0); |
||
455 | s->type.t |= VT_EXTERN; |
||
456 | } else if (s->type.ref == func_old_type.ref) { |
||
457 | s->type.ref = type->ref; |
||
458 | s->r = r | VT_CONST | VT_SYM; |
||
459 | s->type.t |= VT_EXTERN; |
||
460 | } else if (!is_compatible_types(&s->type, type)) { |
||
461 | tcc_error("incompatible types for redefinition of '%s'", |
||
462 | get_tok_str(v, NULL)); |
||
463 | } |
||
464 | /* Merge some storage attributes. */ |
||
465 | if (type->t & VT_WEAK) |
||
466 | weaken_symbol(s); |
||
467 | |||
468 | if (type->t & VT_VIS_MASK) |
||
469 | apply_visibility(s, type); |
||
470 | |||
471 | return s; |
||
472 | } |
||
473 | |||
474 | /* push a reference to global symbol v */ |
||
475 | ST_FUNC void vpush_global_sym(CType *type, int v) |
||
476 | { |
||
477 | vpushsym(type, external_global_sym(v, type, 0)); |
||
478 | } |
||
479 | |||
480 | ST_FUNC void vset(CType *type, int r, int v) |
||
481 | { |
||
482 | CValue cval; |
||
483 | |||
484 | cval.i = v; |
||
485 | vsetc(type, r, &cval); |
||
486 | } |
||
487 | |||
488 | static void vseti(int r, int v) |
||
489 | { |
||
490 | CType type; |
||
491 | type.t = VT_INT; |
||
492 | type.ref = 0; |
||
493 | vset(&type, r, v); |
||
494 | } |
||
495 | |||
496 | ST_FUNC void vswap(void) |
||
497 | { |
||
498 | SValue tmp; |
||
499 | /* cannot let cpu flags if other instruction are generated. Also |
||
500 | avoid leaving VT_JMP anywhere except on the top of the stack |
||
501 | because it would complicate the code generator. */ |
||
502 | if (vtop >= vstack) { |
||
503 | int v = vtop->r & VT_VALMASK; |
||
504 | if (v == VT_CMP || (v & ~1) == VT_JMP) |
||
505 | gv(RC_INT); |
||
506 | } |
||
507 | tmp = vtop[0]; |
||
508 | vtop[0] = vtop[-1]; |
||
509 | vtop[-1] = tmp; |
||
510 | |||
511 | /* XXX: +2% overall speed possible with optimized memswap |
||
512 | * |
||
513 | * memswap(&vtop[0], &vtop[1], sizeof *vtop); |
||
514 | */ |
||
515 | } |
||
516 | |||
517 | ST_FUNC void vpushv(SValue *v) |
||
518 | { |
||
519 | if (vtop >= vstack + (VSTACK_SIZE - 1)) |
||
520 | tcc_error("memory full (vstack)"); |
||
521 | vtop++; |
||
522 | *vtop = *v; |
||
523 | } |
||
524 | |||
525 | static void vdup(void) |
||
526 | { |
||
527 | vpushv(vtop); |
||
528 | } |
||
529 | |||
530 | /* save r to the memory stack, and mark it as being free */ |
||
531 | ST_FUNC void save_reg(int r) |
||
532 | { |
||
533 | int l, saved, size, align; |
||
534 | SValue *p, sv; |
||
535 | CType *type; |
||
536 | |||
537 | /* modify all stack values */ |
||
538 | saved = 0; |
||
539 | l = 0; |
||
540 | for(p=vstack;p<=vtop;p++) { |
||
541 | if ((p->r & VT_VALMASK) == r || |
||
542 | ((p->type.t & VT_BTYPE) == VT_LLONG && (p->r2 & VT_VALMASK) == r)) { |
||
543 | /* must save value on stack if not already done */ |
||
544 | if (!saved) { |
||
545 | /* NOTE: must reload 'r' because r might be equal to r2 */ |
||
546 | r = p->r & VT_VALMASK; |
||
547 | /* store register in the stack */ |
||
548 | type = &p->type; |
||
549 | if ((p->r & VT_LVAL) || |
||
550 | (!is_float(type->t) && (type->t & VT_BTYPE) != VT_LLONG)) |
||
551 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
552 | type = &char_pointer_type; |
||
553 | #else |
||
554 | type = &int_type; |
||
555 | #endif |
||
556 | size = type_size(type, &align); |
||
557 | loc = (loc - size) & -align; |
||
558 | sv.type.t = type->t; |
||
559 | sv.r = VT_LOCAL | VT_LVAL; |
||
560 | sv.c.i = loc; |
||
561 | store(r, &sv); |
||
562 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
||
563 | /* x86 specific: need to pop fp register ST0 if saved */ |
||
564 | if (r == TREG_ST0) { |
||
565 | o(0xd8dd); /* fstp %st(0) */ |
||
566 | } |
||
567 | #endif |
||
568 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
||
569 | /* special long long case */ |
||
570 | if ((type->t & VT_BTYPE) == VT_LLONG) { |
||
571 | sv.c.i += 4; |
||
572 | store(p->r2, &sv); |
||
573 | } |
||
574 | #endif |
||
575 | l = loc; |
||
576 | saved = 1; |
||
577 | } |
||
578 | /* mark that stack entry as being saved on the stack */ |
||
579 | if (p->r & VT_LVAL) { |
||
580 | /* also clear the bounded flag because the |
||
581 | relocation address of the function was stored in |
||
582 | p->c.i */ |
||
583 | p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL; |
||
584 | } else { |
||
585 | p->r = lvalue_type(p->type.t) | VT_LOCAL; |
||
586 | } |
||
587 | p->r2 = VT_CONST; |
||
588 | p->c.i = l; |
||
589 | } |
||
590 | } |
||
591 | } |
||
592 | |||
593 | #ifdef TCC_TARGET_ARM |
||
594 | /* find a register of class 'rc2' with at most one reference on stack. |
||
595 | * If none, call get_reg(rc) */ |
||
596 | ST_FUNC int get_reg_ex(int rc, int rc2) |
||
597 | { |
||
598 | int r; |
||
599 | SValue *p; |
||
600 | |||
601 | for(r=0;r |
||
602 | if (reg_classes[r] & rc2) { |
||
603 | int n; |
||
604 | n=0; |
||
605 | for(p = vstack; p <= vtop; p++) { |
||
606 | if ((p->r & VT_VALMASK) == r || |
||
607 | (p->r2 & VT_VALMASK) == r) |
||
608 | n++; |
||
609 | } |
||
610 | if (n <= 1) |
||
611 | return r; |
||
612 | } |
||
613 | } |
||
614 | return get_reg(rc); |
||
615 | } |
||
616 | #endif |
||
617 | |||
618 | /* find a free register of class 'rc'. If none, save one register */ |
||
619 | ST_FUNC int get_reg(int rc) |
||
620 | { |
||
621 | int r; |
||
622 | SValue *p; |
||
623 | |||
624 | /* find a free register */ |
||
625 | for(r=0;r |
||
626 | if (reg_classes[r] & rc) { |
||
627 | for(p=vstack;p<=vtop;p++) { |
||
628 | if ((p->r & VT_VALMASK) == r || |
||
629 | (p->r2 & VT_VALMASK) == r) |
||
630 | goto notfound; |
||
631 | } |
||
632 | return r; |
||
633 | } |
||
634 | notfound: ; |
||
635 | } |
||
636 | |||
637 | /* no register left : free the first one on the stack (VERY |
||
638 | IMPORTANT to start from the bottom to ensure that we don't |
||
639 | spill registers used in gen_opi()) */ |
||
640 | for(p=vstack;p<=vtop;p++) { |
||
641 | /* look at second register (if long long) */ |
||
642 | r = p->r2 & VT_VALMASK; |
||
643 | if (r < VT_CONST && (reg_classes[r] & rc)) |
||
644 | goto save_found; |
||
645 | r = p->r & VT_VALMASK; |
||
646 | if (r < VT_CONST && (reg_classes[r] & rc)) { |
||
647 | save_found: |
||
648 | save_reg(r); |
||
649 | return r; |
||
650 | } |
||
651 | } |
||
652 | /* Should never comes here */ |
||
653 | return -1; |
||
654 | } |
||
655 | |||
656 | /* save registers up to (vtop - n) stack entry */ |
||
657 | ST_FUNC void save_regs(int n) |
||
658 | { |
||
659 | int r; |
||
660 | SValue *p, *p1; |
||
661 | p1 = vtop - n; |
||
662 | for(p = vstack;p <= p1; p++) { |
||
663 | r = p->r & VT_VALMASK; |
||
664 | if (r < VT_CONST) { |
||
665 | save_reg(r); |
||
666 | } |
||
667 | } |
||
668 | } |
||
669 | |||
670 | /* move register 's' (of type 't') to 'r', and flush previous value of r to memory |
||
671 | if needed */ |
||
672 | static void move_reg(int r, int s, int t) |
||
673 | { |
||
674 | SValue sv; |
||
675 | |||
676 | if (r != s) { |
||
677 | save_reg(r); |
||
678 | sv.type.t = t; |
||
679 | sv.type.ref = NULL; |
||
680 | sv.r = s; |
||
681 | sv.c.i = 0; |
||
682 | load(r, &sv); |
||
683 | } |
||
684 | } |
||
685 | |||
686 | /* get address of vtop (vtop MUST BE an lvalue) */ |
||
687 | ST_FUNC void gaddrof(void) |
||
688 | { |
||
689 | if (vtop->r & VT_REF && !nocode_wanted) |
||
690 | gv(RC_INT); |
||
691 | vtop->r &= ~VT_LVAL; |
||
692 | /* tricky: if saved lvalue, then we can go back to lvalue */ |
||
693 | if ((vtop->r & VT_VALMASK) == VT_LLOCAL) |
||
694 | vtop->r = (vtop->r & ~(VT_VALMASK | VT_LVAL_TYPE)) | VT_LOCAL | VT_LVAL; |
||
695 | |||
696 | |||
697 | } |
||
698 | |||
699 | #ifdef CONFIG_TCC_BCHECK |
||
700 | /* generate lvalue bound code */ |
||
701 | static void gbound(void) |
||
702 | { |
||
703 | int lval_type; |
||
704 | CType type1; |
||
705 | |||
706 | vtop->r &= ~VT_MUSTBOUND; |
||
707 | /* if lvalue, then use checking code before dereferencing */ |
||
708 | if (vtop->r & VT_LVAL) { |
||
709 | /* if not VT_BOUNDED value, then make one */ |
||
710 | if (!(vtop->r & VT_BOUNDED)) { |
||
711 | lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL); |
||
712 | /* must save type because we must set it to int to get pointer */ |
||
713 | type1 = vtop->type; |
||
714 | vtop->type.t = VT_PTR; |
||
715 | gaddrof(); |
||
716 | vpushi(0); |
||
717 | gen_bounded_ptr_add(); |
||
718 | vtop->r |= lval_type; |
||
719 | vtop->type = type1; |
||
720 | } |
||
721 | /* then check for dereferencing */ |
||
722 | gen_bounded_ptr_deref(); |
||
723 | } |
||
724 | } |
||
725 | #endif |
||
726 | |||
727 | /* store vtop a register belonging to class 'rc'. lvalues are |
||
728 | converted to values. Cannot be used if cannot be converted to |
||
729 | register value (such as structures). */ |
||
730 | ST_FUNC int gv(int rc) |
||
731 | { |
||
732 | int r, bit_pos, bit_size, size, align, i; |
||
733 | int rc2; |
||
734 | |||
735 | /* NOTE: get_reg can modify vstack[] */ |
||
736 | if (vtop->type.t & VT_BITFIELD) { |
||
737 | CType type; |
||
738 | int bits = 32; |
||
739 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
740 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
741 | /* remove bit field info to avoid loops */ |
||
742 | vtop->type.t &= ~VT_BITFIELD & ((1 << VT_STRUCT_SHIFT) - 1); |
||
743 | /* cast to int to propagate signedness in following ops */ |
||
744 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
||
745 | type.t = VT_LLONG; |
||
746 | bits = 64; |
||
747 | } else |
||
748 | type.t = VT_INT; |
||
749 | if((vtop->type.t & VT_UNSIGNED) || |
||
750 | (vtop->type.t & VT_BTYPE) == VT_BOOL) |
||
751 | type.t |= VT_UNSIGNED; |
||
752 | gen_cast(&type); |
||
753 | /* generate shifts */ |
||
754 | vpushi(bits - (bit_pos + bit_size)); |
||
755 | gen_op(TOK_SHL); |
||
756 | vpushi(bits - bit_size); |
||
757 | /* NOTE: transformed to SHR if unsigned */ |
||
758 | gen_op(TOK_SAR); |
||
759 | r = gv(rc); |
||
760 | } else { |
||
761 | if (is_float(vtop->type.t) && |
||
762 | (vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
763 | Sym *sym; |
||
764 | int *ptr; |
||
765 | unsigned long offset; |
||
766 | #if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP) |
||
767 | CValue check; |
||
768 | #endif |
||
769 | |||
770 | /* XXX: unify with initializers handling ? */ |
||
771 | /* CPUs usually cannot use float constants, so we store them |
||
772 | generically in data segment */ |
||
773 | size = type_size(&vtop->type, &align); |
||
774 | offset = (data_section->data_offset + align - 1) & -align; |
||
775 | data_section->data_offset = offset; |
||
776 | /* XXX: not portable yet */ |
||
777 | #if defined(__i386__) || defined(__x86_64__) |
||
778 | /* Zero pad x87 tenbyte long doubles */ |
||
779 | if (size == LDOUBLE_SIZE) { |
||
780 | vtop->c.tab[2] &= 0xffff; |
||
781 | #if LDOUBLE_SIZE == 16 |
||
782 | vtop->c.tab[3] = 0; |
||
783 | #endif |
||
784 | } |
||
785 | #endif |
||
786 | ptr = section_ptr_add(data_section, size); |
||
787 | size = size >> 2; |
||
788 | #if defined(TCC_TARGET_ARM) && !defined(TCC_ARM_VFP) |
||
789 | check.d = 1; |
||
790 | if(check.tab[0]) |
||
791 | for(i=0;i |
||
792 | ptr[i] = vtop->c.tab[size-1-i]; |
||
793 | else |
||
794 | #endif |
||
795 | for(i=0;i |
||
796 | ptr[i] = vtop->c.tab[i]; |
||
797 | sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); |
||
798 | vtop->r |= VT_LVAL | VT_SYM; |
||
799 | vtop->sym = sym; |
||
800 | vtop->c.i = 0; |
||
801 | } |
||
802 | #ifdef CONFIG_TCC_BCHECK |
||
803 | if (vtop->r & VT_MUSTBOUND) |
||
804 | gbound(); |
||
805 | #endif |
||
806 | |||
807 | r = vtop->r & VT_VALMASK; |
||
808 | rc2 = (rc & RC_FLOAT) ? RC_FLOAT : RC_INT; |
||
809 | #ifndef TCC_TARGET_ARM64 |
||
810 | if (rc == RC_IRET) |
||
811 | rc2 = RC_LRET; |
||
812 | #ifdef TCC_TARGET_X86_64 |
||
813 | else if (rc == RC_FRET) |
||
814 | rc2 = RC_QRET; |
||
815 | #endif |
||
816 | #endif |
||
817 | |||
818 | /* need to reload if: |
||
819 | - constant |
||
820 | - lvalue (need to dereference pointer) |
||
821 | - already a register, but not in the right class */ |
||
822 | if (r >= VT_CONST |
||
823 | || (vtop->r & VT_LVAL) |
||
824 | || !(reg_classes[r] & rc) |
||
825 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
826 | || ((vtop->type.t & VT_BTYPE) == VT_QLONG && !(reg_classes[vtop->r2] & rc2)) |
||
827 | || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT && !(reg_classes[vtop->r2] & rc2)) |
||
828 | #else |
||
829 | || ((vtop->type.t & VT_BTYPE) == VT_LLONG && !(reg_classes[vtop->r2] & rc2)) |
||
830 | #endif |
||
831 | ) |
||
832 | { |
||
833 | r = get_reg(rc); |
||
834 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
835 | if (((vtop->type.t & VT_BTYPE) == VT_QLONG) || ((vtop->type.t & VT_BTYPE) == VT_QFLOAT)) { |
||
836 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
||
837 | #else |
||
838 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
||
839 | int addr_type = VT_INT, load_size = 4, load_type = VT_INT; |
||
840 | unsigned long long ll; |
||
841 | #endif |
||
842 | int r2, original_type; |
||
843 | original_type = vtop->type.t; |
||
844 | /* two register type load : expand to two words |
||
845 | temporarily */ |
||
846 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
||
847 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
||
848 | /* load constant */ |
||
849 | ll = vtop->c.i; |
||
850 | vtop->c.i = ll; /* first word */ |
||
851 | load(r, vtop); |
||
852 | vtop->r = r; /* save register value */ |
||
853 | vpushi(ll >> 32); /* second word */ |
||
854 | } else |
||
855 | #endif |
||
856 | if (r >= VT_CONST || /* XXX: test to VT_CONST incorrect ? */ |
||
857 | (vtop->r & VT_LVAL)) { |
||
858 | /* We do not want to modifier the long long |
||
859 | pointer here, so the safest (and less |
||
860 | efficient) is to save all the other registers |
||
861 | in the stack. XXX: totally inefficient. */ |
||
862 | save_regs(1); |
||
863 | /* load from memory */ |
||
864 | vtop->type.t = load_type; |
||
865 | load(r, vtop); |
||
866 | vdup(); |
||
867 | vtop[-1].r = r; /* save register value */ |
||
868 | /* increment pointer to get second word */ |
||
869 | vtop->type.t = addr_type; |
||
870 | gaddrof(); |
||
871 | vpushi(load_size); |
||
872 | gen_op('+'); |
||
873 | vtop->r |= VT_LVAL; |
||
874 | vtop->type.t = load_type; |
||
875 | } else { |
||
876 | /* move registers */ |
||
877 | load(r, vtop); |
||
878 | vdup(); |
||
879 | vtop[-1].r = r; /* save register value */ |
||
880 | vtop->r = vtop[-1].r2; |
||
881 | } |
||
882 | /* Allocate second register. Here we rely on the fact that |
||
883 | get_reg() tries first to free r2 of an SValue. */ |
||
884 | r2 = get_reg(rc2); |
||
885 | load(r2, vtop); |
||
886 | vpop(); |
||
887 | /* write second register */ |
||
888 | vtop->r2 = r2; |
||
889 | vtop->type.t = original_type; |
||
890 | } else if ((vtop->r & VT_LVAL) && !is_float(vtop->type.t)) { |
||
891 | int t1, t; |
||
892 | /* lvalue of scalar type : need to use lvalue type |
||
893 | because of possible cast */ |
||
894 | t = vtop->type.t; |
||
895 | t1 = t; |
||
896 | /* compute memory access type */ |
||
897 | if (vtop->r & VT_REF) |
||
898 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
899 | t = VT_PTR; |
||
900 | #else |
||
901 | t = VT_INT; |
||
902 | #endif |
||
903 | else if (vtop->r & VT_LVAL_BYTE) |
||
904 | t = VT_BYTE; |
||
905 | else if (vtop->r & VT_LVAL_SHORT) |
||
906 | t = VT_SHORT; |
||
907 | if (vtop->r & VT_LVAL_UNSIGNED) |
||
908 | t |= VT_UNSIGNED; |
||
909 | vtop->type.t = t; |
||
910 | load(r, vtop); |
||
911 | /* restore wanted type */ |
||
912 | vtop->type.t = t1; |
||
913 | } else { |
||
914 | /* one register type load */ |
||
915 | load(r, vtop); |
||
916 | } |
||
917 | } |
||
918 | vtop->r = r; |
||
919 | #ifdef TCC_TARGET_C67 |
||
920 | /* uses register pairs for doubles */ |
||
921 | if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
||
922 | vtop->r2 = r+1; |
||
923 | #endif |
||
924 | } |
||
925 | return r; |
||
926 | } |
||
927 | |||
928 | /* generate vtop[-1] and vtop[0] in resp. classes rc1 and rc2 */ |
||
929 | ST_FUNC void gv2(int rc1, int rc2) |
||
930 | { |
||
931 | int v; |
||
932 | |||
933 | /* generate more generic register first. But VT_JMP or VT_CMP |
||
934 | values must be generated first in all cases to avoid possible |
||
935 | reload errors */ |
||
936 | v = vtop[0].r & VT_VALMASK; |
||
937 | if (v != VT_CMP && (v & ~1) != VT_JMP && rc1 <= rc2) { |
||
938 | vswap(); |
||
939 | gv(rc1); |
||
940 | vswap(); |
||
941 | gv(rc2); |
||
942 | /* test if reload is needed for first register */ |
||
943 | if ((vtop[-1].r & VT_VALMASK) >= VT_CONST) { |
||
944 | vswap(); |
||
945 | gv(rc1); |
||
946 | vswap(); |
||
947 | } |
||
948 | } else { |
||
949 | gv(rc2); |
||
950 | vswap(); |
||
951 | gv(rc1); |
||
952 | vswap(); |
||
953 | /* test if reload is needed for first register */ |
||
954 | if ((vtop[0].r & VT_VALMASK) >= VT_CONST) { |
||
955 | gv(rc2); |
||
956 | } |
||
957 | } |
||
958 | } |
||
959 | |||
960 | #ifndef TCC_TARGET_ARM64 |
||
961 | /* wrapper around RC_FRET to return a register by type */ |
||
962 | static int rc_fret(int t) |
||
963 | { |
||
964 | #ifdef TCC_TARGET_X86_64 |
||
965 | if (t == VT_LDOUBLE) { |
||
966 | return RC_ST0; |
||
967 | } |
||
968 | #endif |
||
969 | return RC_FRET; |
||
970 | } |
||
971 | #endif |
||
972 | |||
973 | /* wrapper around REG_FRET to return a register by type */ |
||
974 | static int reg_fret(int t) |
||
975 | { |
||
976 | #ifdef TCC_TARGET_X86_64 |
||
977 | if (t == VT_LDOUBLE) { |
||
978 | return TREG_ST0; |
||
979 | } |
||
980 | #endif |
||
981 | return REG_FRET; |
||
982 | } |
||
983 | |||
984 | /* expand long long on stack in two int registers */ |
||
985 | static void lexpand(void) |
||
986 | { |
||
987 | int u; |
||
988 | |||
989 | u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); |
||
990 | gv(RC_INT); |
||
991 | vdup(); |
||
992 | vtop[0].r = vtop[-1].r2; |
||
993 | vtop[0].r2 = VT_CONST; |
||
994 | vtop[-1].r2 = VT_CONST; |
||
995 | vtop[0].type.t = VT_INT | u; |
||
996 | vtop[-1].type.t = VT_INT | u; |
||
997 | } |
||
998 | |||
999 | #ifdef TCC_TARGET_ARM |
||
1000 | /* expand long long on stack */ |
||
1001 | ST_FUNC void lexpand_nr(void) |
||
1002 | { |
||
1003 | int u,v; |
||
1004 | |||
1005 | u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); |
||
1006 | vdup(); |
||
1007 | vtop->r2 = VT_CONST; |
||
1008 | vtop->type.t = VT_INT | u; |
||
1009 | v=vtop[-1].r & (VT_VALMASK | VT_LVAL); |
||
1010 | if (v == VT_CONST) { |
||
1011 | vtop[-1].c.i = vtop->c.i; |
||
1012 | vtop->c.i = vtop->c.i >> 32; |
||
1013 | vtop->r = VT_CONST; |
||
1014 | } else if (v == (VT_LVAL|VT_CONST) || v == (VT_LVAL|VT_LOCAL)) { |
||
1015 | vtop->c.i += 4; |
||
1016 | vtop->r = vtop[-1].r; |
||
1017 | } else if (v > VT_CONST) { |
||
1018 | vtop--; |
||
1019 | lexpand(); |
||
1020 | } else |
||
1021 | vtop->r = vtop[-1].r2; |
||
1022 | vtop[-1].r2 = VT_CONST; |
||
1023 | vtop[-1].type.t = VT_INT | u; |
||
1024 | } |
||
1025 | #endif |
||
1026 | |||
1027 | /* build a long long from two ints */ |
||
1028 | static void lbuild(int t) |
||
1029 | { |
||
1030 | gv2(RC_INT, RC_INT); |
||
1031 | vtop[-1].r2 = vtop[0].r; |
||
1032 | vtop[-1].type.t = t; |
||
1033 | vpop(); |
||
1034 | } |
||
1035 | |||
1036 | /* rotate n first stack elements to the bottom |
||
1037 | I1 ... In -> I2 ... In I1 [top is right] |
||
1038 | */ |
||
1039 | ST_FUNC void vrotb(int n) |
||
1040 | { |
||
1041 | int i; |
||
1042 | SValue tmp; |
||
1043 | |||
1044 | tmp = vtop[-n + 1]; |
||
1045 | for(i=-n+1;i!=0;i++) |
||
1046 | vtop[i] = vtop[i+1]; |
||
1047 | vtop[0] = tmp; |
||
1048 | } |
||
1049 | |||
1050 | /* rotate the n elements before entry e towards the top |
||
1051 | I1 ... In ... -> In I1 ... I(n-1) ... [top is right] |
||
1052 | */ |
||
1053 | ST_FUNC void vrote(SValue *e, int n) |
||
1054 | { |
||
1055 | int i; |
||
1056 | SValue tmp; |
||
1057 | |||
1058 | tmp = *e; |
||
1059 | for(i = 0;i < n - 1; i++) |
||
1060 | e[-i] = e[-i - 1]; |
||
1061 | e[-n + 1] = tmp; |
||
1062 | } |
||
1063 | |||
1064 | /* rotate n first stack elements to the top |
||
1065 | I1 ... In -> In I1 ... I(n-1) [top is right] |
||
1066 | */ |
||
1067 | ST_FUNC void vrott(int n) |
||
1068 | { |
||
1069 | vrote(vtop, n); |
||
1070 | } |
||
1071 | |||
1072 | /* pop stack value */ |
||
1073 | ST_FUNC void vpop(void) |
||
1074 | { |
||
1075 | int v; |
||
1076 | v = vtop->r & VT_VALMASK; |
||
1077 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
||
1078 | /* for x86, we need to pop the FP stack */ |
||
1079 | if (v == TREG_ST0 && !nocode_wanted) { |
||
1080 | o(0xd8dd); /* fstp %st(0) */ |
||
1081 | } else |
||
1082 | #endif |
||
1083 | if (v == VT_JMP || v == VT_JMPI) { |
||
1084 | /* need to put correct jump if && or || without test */ |
||
1085 | gsym(vtop->c.i); |
||
1086 | } |
||
1087 | vtop--; |
||
1088 | } |
||
1089 | |||
1090 | /* convert stack entry to register and duplicate its value in another |
||
1091 | register */ |
||
1092 | static void gv_dup(void) |
||
1093 | { |
||
1094 | int rc, t, r, r1; |
||
1095 | SValue sv; |
||
1096 | |||
1097 | t = vtop->type.t; |
||
1098 | if ((t & VT_BTYPE) == VT_LLONG) { |
||
1099 | lexpand(); |
||
1100 | gv_dup(); |
||
1101 | vswap(); |
||
1102 | vrotb(3); |
||
1103 | gv_dup(); |
||
1104 | vrotb(4); |
||
1105 | /* stack: H L L1 H1 */ |
||
1106 | lbuild(t); |
||
1107 | vrotb(3); |
||
1108 | vrotb(3); |
||
1109 | vswap(); |
||
1110 | lbuild(t); |
||
1111 | vswap(); |
||
1112 | } else { |
||
1113 | /* duplicate value */ |
||
1114 | rc = RC_INT; |
||
1115 | sv.type.t = VT_INT; |
||
1116 | if (is_float(t)) { |
||
1117 | rc = RC_FLOAT; |
||
1118 | #ifdef TCC_TARGET_X86_64 |
||
1119 | if ((t & VT_BTYPE) == VT_LDOUBLE) { |
||
1120 | rc = RC_ST0; |
||
1121 | } |
||
1122 | #endif |
||
1123 | sv.type.t = t; |
||
1124 | } |
||
1125 | r = gv(rc); |
||
1126 | r1 = get_reg(rc); |
||
1127 | sv.r = r; |
||
1128 | sv.c.i = 0; |
||
1129 | load(r1, &sv); /* move r to r1 */ |
||
1130 | vdup(); |
||
1131 | /* duplicates value */ |
||
1132 | if (r != r1) |
||
1133 | vtop->r = r1; |
||
1134 | } |
||
1135 | } |
||
1136 | |||
1137 | /* Generate value test |
||
1138 | * |
||
1139 | * Generate a test for any value (jump, comparison and integers) */ |
||
1140 | ST_FUNC int gvtst(int inv, int t) |
||
1141 | { |
||
1142 | int v = vtop->r & VT_VALMASK; |
||
1143 | if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) { |
||
1144 | vpushi(0); |
||
1145 | gen_op(TOK_NE); |
||
1146 | } |
||
1147 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
1148 | /* constant jmp optimization */ |
||
1149 | if ((vtop->c.i != 0) != inv) |
||
1150 | t = gjmp(t); |
||
1151 | vtop--; |
||
1152 | return t; |
||
1153 | } |
||
1154 | return gtst(inv, t); |
||
1155 | } |
||
1156 | |||
1157 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
||
1158 | /* generate CPU independent (unsigned) long long operations */ |
||
1159 | static void gen_opl(int op) |
||
1160 | { |
||
1161 | int t, a, b, op1, c, i; |
||
1162 | int func; |
||
1163 | unsigned short reg_iret = REG_IRET; |
||
1164 | unsigned short reg_lret = REG_LRET; |
||
1165 | SValue tmp; |
||
1166 | |||
1167 | switch(op) { |
||
1168 | case '/': |
||
1169 | case TOK_PDIV: |
||
1170 | func = TOK___divdi3; |
||
1171 | goto gen_func; |
||
1172 | case TOK_UDIV: |
||
1173 | func = TOK___udivdi3; |
||
1174 | goto gen_func; |
||
1175 | case '%': |
||
1176 | func = TOK___moddi3; |
||
1177 | goto gen_mod_func; |
||
1178 | case TOK_UMOD: |
||
1179 | func = TOK___umoddi3; |
||
1180 | gen_mod_func: |
||
1181 | #ifdef TCC_ARM_EABI |
||
1182 | reg_iret = TREG_R2; |
||
1183 | reg_lret = TREG_R3; |
||
1184 | #endif |
||
1185 | gen_func: |
||
1186 | /* call generic long long function */ |
||
1187 | vpush_global_sym(&func_old_type, func); |
||
1188 | vrott(3); |
||
1189 | gfunc_call(2); |
||
1190 | vpushi(0); |
||
1191 | vtop->r = reg_iret; |
||
1192 | vtop->r2 = reg_lret; |
||
1193 | break; |
||
1194 | case '^': |
||
1195 | case '&': |
||
1196 | case '|': |
||
1197 | case '*': |
||
1198 | case '+': |
||
1199 | case '-': |
||
1200 | t = vtop->type.t; |
||
1201 | vswap(); |
||
1202 | lexpand(); |
||
1203 | vrotb(3); |
||
1204 | lexpand(); |
||
1205 | /* stack: L1 H1 L2 H2 */ |
||
1206 | tmp = vtop[0]; |
||
1207 | vtop[0] = vtop[-3]; |
||
1208 | vtop[-3] = tmp; |
||
1209 | tmp = vtop[-2]; |
||
1210 | vtop[-2] = vtop[-3]; |
||
1211 | vtop[-3] = tmp; |
||
1212 | vswap(); |
||
1213 | /* stack: H1 H2 L1 L2 */ |
||
1214 | if (op == '*') { |
||
1215 | vpushv(vtop - 1); |
||
1216 | vpushv(vtop - 1); |
||
1217 | gen_op(TOK_UMULL); |
||
1218 | lexpand(); |
||
1219 | /* stack: H1 H2 L1 L2 ML MH */ |
||
1220 | for(i=0;i<4;i++) |
||
1221 | vrotb(6); |
||
1222 | /* stack: ML MH H1 H2 L1 L2 */ |
||
1223 | tmp = vtop[0]; |
||
1224 | vtop[0] = vtop[-2]; |
||
1225 | vtop[-2] = tmp; |
||
1226 | /* stack: ML MH H1 L2 H2 L1 */ |
||
1227 | gen_op('*'); |
||
1228 | vrotb(3); |
||
1229 | vrotb(3); |
||
1230 | gen_op('*'); |
||
1231 | /* stack: ML MH M1 M2 */ |
||
1232 | gen_op('+'); |
||
1233 | gen_op('+'); |
||
1234 | } else if (op == '+' || op == '-') { |
||
1235 | /* XXX: add non carry method too (for MIPS or alpha) */ |
||
1236 | if (op == '+') |
||
1237 | op1 = TOK_ADDC1; |
||
1238 | else |
||
1239 | op1 = TOK_SUBC1; |
||
1240 | gen_op(op1); |
||
1241 | /* stack: H1 H2 (L1 op L2) */ |
||
1242 | vrotb(3); |
||
1243 | vrotb(3); |
||
1244 | gen_op(op1 + 1); /* TOK_xxxC2 */ |
||
1245 | } else { |
||
1246 | gen_op(op); |
||
1247 | /* stack: H1 H2 (L1 op L2) */ |
||
1248 | vrotb(3); |
||
1249 | vrotb(3); |
||
1250 | /* stack: (L1 op L2) H1 H2 */ |
||
1251 | gen_op(op); |
||
1252 | /* stack: (L1 op L2) (H1 op H2) */ |
||
1253 | } |
||
1254 | /* stack: L H */ |
||
1255 | lbuild(t); |
||
1256 | break; |
||
1257 | case TOK_SAR: |
||
1258 | case TOK_SHR: |
||
1259 | case TOK_SHL: |
||
1260 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
1261 | t = vtop[-1].type.t; |
||
1262 | vswap(); |
||
1263 | lexpand(); |
||
1264 | vrotb(3); |
||
1265 | /* stack: L H shift */ |
||
1266 | c = (int)vtop->c.i; |
||
1267 | /* constant: simpler */ |
||
1268 | /* NOTE: all comments are for SHL. the other cases are |
||
1269 | done by swaping words */ |
||
1270 | vpop(); |
||
1271 | if (op != TOK_SHL) |
||
1272 | vswap(); |
||
1273 | if (c >= 32) { |
||
1274 | /* stack: L H */ |
||
1275 | vpop(); |
||
1276 | if (c > 32) { |
||
1277 | vpushi(c - 32); |
||
1278 | gen_op(op); |
||
1279 | } |
||
1280 | if (op != TOK_SAR) { |
||
1281 | vpushi(0); |
||
1282 | } else { |
||
1283 | gv_dup(); |
||
1284 | vpushi(31); |
||
1285 | gen_op(TOK_SAR); |
||
1286 | } |
||
1287 | vswap(); |
||
1288 | } else { |
||
1289 | vswap(); |
||
1290 | gv_dup(); |
||
1291 | /* stack: H L L */ |
||
1292 | vpushi(c); |
||
1293 | gen_op(op); |
||
1294 | vswap(); |
||
1295 | vpushi(32 - c); |
||
1296 | if (op == TOK_SHL) |
||
1297 | gen_op(TOK_SHR); |
||
1298 | else |
||
1299 | gen_op(TOK_SHL); |
||
1300 | vrotb(3); |
||
1301 | /* stack: L L H */ |
||
1302 | vpushi(c); |
||
1303 | if (op == TOK_SHL) |
||
1304 | gen_op(TOK_SHL); |
||
1305 | else |
||
1306 | gen_op(TOK_SHR); |
||
1307 | gen_op('|'); |
||
1308 | } |
||
1309 | if (op != TOK_SHL) |
||
1310 | vswap(); |
||
1311 | lbuild(t); |
||
1312 | } else { |
||
1313 | /* XXX: should provide a faster fallback on x86 ? */ |
||
1314 | switch(op) { |
||
1315 | case TOK_SAR: |
||
1316 | func = TOK___ashrdi3; |
||
1317 | goto gen_func; |
||
1318 | case TOK_SHR: |
||
1319 | func = TOK___lshrdi3; |
||
1320 | goto gen_func; |
||
1321 | case TOK_SHL: |
||
1322 | func = TOK___ashldi3; |
||
1323 | goto gen_func; |
||
1324 | } |
||
1325 | } |
||
1326 | break; |
||
1327 | default: |
||
1328 | /* compare operations */ |
||
1329 | t = vtop->type.t; |
||
1330 | vswap(); |
||
1331 | lexpand(); |
||
1332 | vrotb(3); |
||
1333 | lexpand(); |
||
1334 | /* stack: L1 H1 L2 H2 */ |
||
1335 | tmp = vtop[-1]; |
||
1336 | vtop[-1] = vtop[-2]; |
||
1337 | vtop[-2] = tmp; |
||
1338 | /* stack: L1 L2 H1 H2 */ |
||
1339 | /* compare high */ |
||
1340 | op1 = op; |
||
1341 | /* when values are equal, we need to compare low words. since |
||
1342 | the jump is inverted, we invert the test too. */ |
||
1343 | if (op1 == TOK_LT) |
||
1344 | op1 = TOK_LE; |
||
1345 | else if (op1 == TOK_GT) |
||
1346 | op1 = TOK_GE; |
||
1347 | else if (op1 == TOK_ULT) |
||
1348 | op1 = TOK_ULE; |
||
1349 | else if (op1 == TOK_UGT) |
||
1350 | op1 = TOK_UGE; |
||
1351 | a = 0; |
||
1352 | b = 0; |
||
1353 | gen_op(op1); |
||
1354 | if (op1 != TOK_NE) { |
||
1355 | a = gvtst(1, 0); |
||
1356 | } |
||
1357 | if (op != TOK_EQ) { |
||
1358 | /* generate non equal test */ |
||
1359 | /* XXX: NOT PORTABLE yet */ |
||
1360 | if (a == 0) { |
||
1361 | b = gvtst(0, 0); |
||
1362 | } else { |
||
1363 | #if defined(TCC_TARGET_I386) |
||
1364 | b = psym(0x850f, 0); |
||
1365 | #elif defined(TCC_TARGET_ARM) |
||
1366 | b = ind; |
||
1367 | o(0x1A000000 | encbranch(ind, 0, 1)); |
||
1368 | #elif defined(TCC_TARGET_C67) || defined(TCC_TARGET_ARM64) |
||
1369 | tcc_error("not implemented"); |
||
1370 | #else |
||
1371 | #error not supported |
||
1372 | #endif |
||
1373 | } |
||
1374 | } |
||
1375 | /* compare low. Always unsigned */ |
||
1376 | op1 = op; |
||
1377 | if (op1 == TOK_LT) |
||
1378 | op1 = TOK_ULT; |
||
1379 | else if (op1 == TOK_LE) |
||
1380 | op1 = TOK_ULE; |
||
1381 | else if (op1 == TOK_GT) |
||
1382 | op1 = TOK_UGT; |
||
1383 | else if (op1 == TOK_GE) |
||
1384 | op1 = TOK_UGE; |
||
1385 | gen_op(op1); |
||
1386 | a = gvtst(1, a); |
||
1387 | gsym(b); |
||
1388 | vseti(VT_JMPI, a); |
||
1389 | break; |
||
1390 | } |
||
1391 | } |
||
1392 | #endif |
||
1393 | |||
1394 | static uint64_t gen_opic_sdiv(uint64_t a, uint64_t b) |
||
1395 | { |
||
1396 | uint64_t x = (a >> 63 ? -a : a) / (b >> 63 ? -b : b); |
||
1397 | return (a ^ b) >> 63 ? -x : x; |
||
1398 | } |
||
1399 | |||
1400 | static int gen_opic_lt(uint64_t a, uint64_t b) |
||
1401 | { |
||
1402 | return (a ^ (uint64_t)1 << 63) < (b ^ (uint64_t)1 << 63); |
||
1403 | } |
||
1404 | |||
1405 | /* handle integer constant optimizations and various machine |
||
1406 | independent opt */ |
||
1407 | static void gen_opic(int op) |
||
1408 | { |
||
1409 | SValue *v1 = vtop - 1; |
||
1410 | SValue *v2 = vtop; |
||
1411 | int t1 = v1->type.t & VT_BTYPE; |
||
1412 | int t2 = v2->type.t & VT_BTYPE; |
||
1413 | int c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
1414 | int c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
1415 | uint64_t l1 = c1 ? v1->c.i : 0; |
||
1416 | uint64_t l2 = c2 ? v2->c.i : 0; |
||
1417 | int shm = (t1 == VT_LLONG) ? 63 : 31; |
||
1418 | |||
1419 | if (t1 != VT_LLONG) |
||
1420 | l1 = ((uint32_t)l1 | |
||
1421 | (v1->type.t & VT_UNSIGNED ? 0 : -(l1 & 0x80000000))); |
||
1422 | if (t2 != VT_LLONG) |
||
1423 | l2 = ((uint32_t)l2 | |
||
1424 | (v2->type.t & VT_UNSIGNED ? 0 : -(l2 & 0x80000000))); |
||
1425 | |||
1426 | if (c1 && c2) { |
||
1427 | switch(op) { |
||
1428 | case '+': l1 += l2; break; |
||
1429 | case '-': l1 -= l2; break; |
||
1430 | case '&': l1 &= l2; break; |
||
1431 | case '^': l1 ^= l2; break; |
||
1432 | case '|': l1 |= l2; break; |
||
1433 | case '*': l1 *= l2; break; |
||
1434 | |||
1435 | case TOK_PDIV: |
||
1436 | case '/': |
||
1437 | case '%': |
||
1438 | case TOK_UDIV: |
||
1439 | case TOK_UMOD: |
||
1440 | /* if division by zero, generate explicit division */ |
||
1441 | if (l2 == 0) { |
||
1442 | if (const_wanted) |
||
1443 | tcc_error("division by zero in constant"); |
||
1444 | goto general_case; |
||
1445 | } |
||
1446 | switch(op) { |
||
1447 | default: l1 = gen_opic_sdiv(l1, l2); break; |
||
1448 | case '%': l1 = l1 - l2 * gen_opic_sdiv(l1, l2); break; |
||
1449 | case TOK_UDIV: l1 = l1 / l2; break; |
||
1450 | case TOK_UMOD: l1 = l1 % l2; break; |
||
1451 | } |
||
1452 | break; |
||
1453 | case TOK_SHL: l1 <<= (l2 & shm); break; |
||
1454 | case TOK_SHR: l1 >>= (l2 & shm); break; |
||
1455 | case TOK_SAR: |
||
1456 | l1 = (l1 >> 63) ? ~(~l1 >> (l2 & shm)) : l1 >> (l2 & shm); |
||
1457 | break; |
||
1458 | /* tests */ |
||
1459 | case TOK_ULT: l1 = l1 < l2; break; |
||
1460 | case TOK_UGE: l1 = l1 >= l2; break; |
||
1461 | case TOK_EQ: l1 = l1 == l2; break; |
||
1462 | case TOK_NE: l1 = l1 != l2; break; |
||
1463 | case TOK_ULE: l1 = l1 <= l2; break; |
||
1464 | case TOK_UGT: l1 = l1 > l2; break; |
||
1465 | case TOK_LT: l1 = gen_opic_lt(l1, l2); break; |
||
1466 | case TOK_GE: l1 = !gen_opic_lt(l1, l2); break; |
||
1467 | case TOK_LE: l1 = !gen_opic_lt(l2, l1); break; |
||
1468 | case TOK_GT: l1 = gen_opic_lt(l2, l1); break; |
||
1469 | /* logical */ |
||
1470 | case TOK_LAND: l1 = l1 && l2; break; |
||
1471 | case TOK_LOR: l1 = l1 || l2; break; |
||
1472 | default: |
||
1473 | goto general_case; |
||
1474 | } |
||
1475 | v1->c.i = l1; |
||
1476 | vtop--; |
||
1477 | } else { |
||
1478 | /* if commutative ops, put c2 as constant */ |
||
1479 | if (c1 && (op == '+' || op == '&' || op == '^' || |
||
1480 | op == '|' || op == '*')) { |
||
1481 | vswap(); |
||
1482 | c2 = c1; //c = c1, c1 = c2, c2 = c; |
||
1483 | l2 = l1; //l = l1, l1 = l2, l2 = l; |
||
1484 | } |
||
1485 | if (!const_wanted && |
||
1486 | c1 && ((l1 == 0 && |
||
1487 | (op == TOK_SHL || op == TOK_SHR || op == TOK_SAR)) || |
||
1488 | (l1 == -1 && op == TOK_SAR))) { |
||
1489 | /* treat (0 << x), (0 >> x) and (-1 >> x) as constant */ |
||
1490 | vtop--; |
||
1491 | } else if (!const_wanted && |
||
1492 | c2 && ((l2 == 0 && (op == '&' || op == '*')) || |
||
1493 | (l2 == -1 && op == '|') || |
||
1494 | (l2 == 0xffffffff && t2 != VT_LLONG && op == '|') || |
||
1495 | (l2 == 1 && (op == '%' || op == TOK_UMOD)))) { |
||
1496 | /* treat (x & 0), (x * 0), (x | -1) and (x % 1) as constant */ |
||
1497 | if (l2 == 1) |
||
1498 | vtop->c.i = 0; |
||
1499 | vswap(); |
||
1500 | vtop--; |
||
1501 | } else if (c2 && (((op == '*' || op == '/' || op == TOK_UDIV || |
||
1502 | op == TOK_PDIV) && |
||
1503 | l2 == 1) || |
||
1504 | ((op == '+' || op == '-' || op == '|' || op == '^' || |
||
1505 | op == TOK_SHL || op == TOK_SHR || op == TOK_SAR) && |
||
1506 | l2 == 0) || |
||
1507 | (op == '&' && |
||
1508 | l2 == -1))) { |
||
1509 | /* filter out NOP operations like x*1, x-0, x&-1... */ |
||
1510 | vtop--; |
||
1511 | } else if (c2 && (op == '*' || op == TOK_PDIV || op == TOK_UDIV)) { |
||
1512 | /* try to use shifts instead of muls or divs */ |
||
1513 | if (l2 > 0 && (l2 & (l2 - 1)) == 0) { |
||
1514 | int n = -1; |
||
1515 | while (l2) { |
||
1516 | l2 >>= 1; |
||
1517 | n++; |
||
1518 | } |
||
1519 | vtop->c.i = n; |
||
1520 | if (op == '*') |
||
1521 | op = TOK_SHL; |
||
1522 | else if (op == TOK_PDIV) |
||
1523 | op = TOK_SAR; |
||
1524 | else |
||
1525 | op = TOK_SHR; |
||
1526 | } |
||
1527 | goto general_case; |
||
1528 | } else if (c2 && (op == '+' || op == '-') && |
||
1529 | (((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM)) |
||
1530 | || (vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_LOCAL)) { |
||
1531 | /* symbol + constant case */ |
||
1532 | if (op == '-') |
||
1533 | l2 = -l2; |
||
1534 | vtop--; |
||
1535 | vtop->c.i += l2; |
||
1536 | } else { |
||
1537 | general_case: |
||
1538 | if (!nocode_wanted) { |
||
1539 | /* call low level op generator */ |
||
1540 | if (t1 == VT_LLONG || t2 == VT_LLONG || |
||
1541 | (PTR_SIZE == 8 && (t1 == VT_PTR || t2 == VT_PTR))) |
||
1542 | gen_opl(op); |
||
1543 | else |
||
1544 | gen_opi(op); |
||
1545 | } else { |
||
1546 | vtop--; |
||
1547 | } |
||
1548 | } |
||
1549 | } |
||
1550 | } |
||
1551 | |||
1552 | /* generate a floating point operation with constant propagation */ |
||
1553 | static void gen_opif(int op) |
||
1554 | { |
||
1555 | int c1, c2; |
||
1556 | SValue *v1, *v2; |
||
1557 | long double f1, f2; |
||
1558 | |||
1559 | v1 = vtop - 1; |
||
1560 | v2 = vtop; |
||
1561 | /* currently, we cannot do computations with forward symbols */ |
||
1562 | c1 = (v1->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
1563 | c2 = (v2->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
1564 | if (c1 && c2) { |
||
1565 | if (v1->type.t == VT_FLOAT) { |
||
1566 | f1 = v1->c.f; |
||
1567 | f2 = v2->c.f; |
||
1568 | } else if (v1->type.t == VT_DOUBLE) { |
||
1569 | f1 = v1->c.d; |
||
1570 | f2 = v2->c.d; |
||
1571 | } else { |
||
1572 | f1 = v1->c.ld; |
||
1573 | f2 = v2->c.ld; |
||
1574 | } |
||
1575 | |||
1576 | /* NOTE: we only do constant propagation if finite number (not |
||
1577 | NaN or infinity) (ANSI spec) */ |
||
1578 | if (!ieee_finite(f1) || !ieee_finite(f2)) |
||
1579 | goto general_case; |
||
1580 | |||
1581 | switch(op) { |
||
1582 | case '+': f1 += f2; break; |
||
1583 | case '-': f1 -= f2; break; |
||
1584 | case '*': f1 *= f2; break; |
||
1585 | case '/': |
||
1586 | if (f2 == 0.0) { |
||
1587 | if (const_wanted) |
||
1588 | tcc_error("division by zero in constant"); |
||
1589 | goto general_case; |
||
1590 | } |
||
1591 | f1 /= f2; |
||
1592 | break; |
||
1593 | /* XXX: also handles tests ? */ |
||
1594 | default: |
||
1595 | goto general_case; |
||
1596 | } |
||
1597 | /* XXX: overflow test ? */ |
||
1598 | if (v1->type.t == VT_FLOAT) { |
||
1599 | v1->c.f = f1; |
||
1600 | } else if (v1->type.t == VT_DOUBLE) { |
||
1601 | v1->c.d = f1; |
||
1602 | } else { |
||
1603 | v1->c.ld = f1; |
||
1604 | } |
||
1605 | vtop--; |
||
1606 | } else { |
||
1607 | general_case: |
||
1608 | if (!nocode_wanted) { |
||
1609 | gen_opf(op); |
||
1610 | } else { |
||
1611 | vtop--; |
||
1612 | } |
||
1613 | } |
||
1614 | } |
||
1615 | |||
1616 | static int pointed_size(CType *type) |
||
1617 | { |
||
1618 | int align; |
||
1619 | return type_size(pointed_type(type), &align); |
||
1620 | } |
||
1621 | |||
1622 | static void vla_runtime_pointed_size(CType *type) |
||
1623 | { |
||
1624 | int align; |
||
1625 | vla_runtime_type_size(pointed_type(type), &align); |
||
1626 | } |
||
1627 | |||
1628 | static inline int is_null_pointer(SValue *p) |
||
1629 | { |
||
1630 | if ((p->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
1631 | return 0; |
||
1632 | return ((p->type.t & VT_BTYPE) == VT_INT && (uint32_t)p->c.i == 0) || |
||
1633 | ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.i == 0) || |
||
1634 | ((p->type.t & VT_BTYPE) == VT_PTR && |
||
1635 | (PTR_SIZE == 4 ? (uint32_t)p->c.i == 0 : p->c.i == 0)); |
||
1636 | } |
||
1637 | |||
1638 | static inline int is_integer_btype(int bt) |
||
1639 | { |
||
1640 | return (bt == VT_BYTE || bt == VT_SHORT || |
||
1641 | bt == VT_INT || bt == VT_LLONG); |
||
1642 | } |
||
1643 | |||
1644 | /* check types for comparison or subtraction of pointers */ |
||
1645 | static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) |
||
1646 | { |
||
1647 | CType *type1, *type2, tmp_type1, tmp_type2; |
||
1648 | int bt1, bt2; |
||
1649 | |||
1650 | /* null pointers are accepted for all comparisons as gcc */ |
||
1651 | if (is_null_pointer(p1) || is_null_pointer(p2)) |
||
1652 | return; |
||
1653 | type1 = &p1->type; |
||
1654 | type2 = &p2->type; |
||
1655 | bt1 = type1->t & VT_BTYPE; |
||
1656 | bt2 = type2->t & VT_BTYPE; |
||
1657 | /* accept comparison between pointer and integer with a warning */ |
||
1658 | if ((is_integer_btype(bt1) || is_integer_btype(bt2)) && op != '-') { |
||
1659 | if (op != TOK_LOR && op != TOK_LAND ) |
||
1660 | tcc_warning("comparison between pointer and integer"); |
||
1661 | return; |
||
1662 | } |
||
1663 | |||
1664 | /* both must be pointers or implicit function pointers */ |
||
1665 | if (bt1 == VT_PTR) { |
||
1666 | type1 = pointed_type(type1); |
||
1667 | } else if (bt1 != VT_FUNC) |
||
1668 | goto invalid_operands; |
||
1669 | |||
1670 | if (bt2 == VT_PTR) { |
||
1671 | type2 = pointed_type(type2); |
||
1672 | } else if (bt2 != VT_FUNC) { |
||
1673 | invalid_operands: |
||
1674 | tcc_error("invalid operands to binary %s", get_tok_str(op, NULL)); |
||
1675 | } |
||
1676 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
1677 | (type2->t & VT_BTYPE) == VT_VOID) |
||
1678 | return; |
||
1679 | tmp_type1 = *type1; |
||
1680 | tmp_type2 = *type2; |
||
1681 | tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
1682 | tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); |
||
1683 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
1684 | /* gcc-like error if '-' is used */ |
||
1685 | if (op == '-') |
||
1686 | goto invalid_operands; |
||
1687 | else |
||
1688 | tcc_warning("comparison of distinct pointer types lacks a cast"); |
||
1689 | } |
||
1690 | } |
||
1691 | |||
1692 | /* generic gen_op: handles types problems */ |
||
1693 | ST_FUNC void gen_op(int op) |
||
1694 | { |
||
1695 | int u, t1, t2, bt1, bt2, t; |
||
1696 | CType type1; |
||
1697 | |||
1698 | t1 = vtop[-1].type.t; |
||
1699 | t2 = vtop[0].type.t; |
||
1700 | bt1 = t1 & VT_BTYPE; |
||
1701 | bt2 = t2 & VT_BTYPE; |
||
1702 | |||
1703 | if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
1704 | /* at least one operand is a pointer */ |
||
1705 | /* relationnal op: must be both pointers */ |
||
1706 | if (op >= TOK_ULT && op <= TOK_LOR) { |
||
1707 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
1708 | /* pointers are handled are unsigned */ |
||
1709 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
1710 | t = VT_LLONG | VT_UNSIGNED; |
||
1711 | #else |
||
1712 | t = VT_INT | VT_UNSIGNED; |
||
1713 | #endif |
||
1714 | goto std_op; |
||
1715 | } |
||
1716 | /* if both pointers, then it must be the '-' op */ |
||
1717 | if (bt1 == VT_PTR && bt2 == VT_PTR) { |
||
1718 | if (op != '-') |
||
1719 | tcc_error("cannot use pointers here"); |
||
1720 | check_comparison_pointer_types(vtop - 1, vtop, op); |
||
1721 | /* XXX: check that types are compatible */ |
||
1722 | if (vtop[-1].type.t & VT_VLA) { |
||
1723 | vla_runtime_pointed_size(&vtop[-1].type); |
||
1724 | } else { |
||
1725 | vpushi(pointed_size(&vtop[-1].type)); |
||
1726 | } |
||
1727 | vrott(3); |
||
1728 | gen_opic(op); |
||
1729 | /* set to integer type */ |
||
1730 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
1731 | vtop->type.t = VT_LLONG; |
||
1732 | #else |
||
1733 | vtop->type.t = VT_INT; |
||
1734 | #endif |
||
1735 | vswap(); |
||
1736 | gen_op(TOK_PDIV); |
||
1737 | } else { |
||
1738 | /* exactly one pointer : must be '+' or '-'. */ |
||
1739 | if (op != '-' && op != '+') |
||
1740 | tcc_error("cannot use pointers here"); |
||
1741 | /* Put pointer as first operand */ |
||
1742 | if (bt2 == VT_PTR) { |
||
1743 | vswap(); |
||
1744 | swap(&t1, &t2); |
||
1745 | } |
||
1746 | type1 = vtop[-1].type; |
||
1747 | type1.t &= ~VT_ARRAY; |
||
1748 | if (vtop[-1].type.t & VT_VLA) |
||
1749 | vla_runtime_pointed_size(&vtop[-1].type); |
||
1750 | else { |
||
1751 | u = pointed_size(&vtop[-1].type); |
||
1752 | if (u < 0) |
||
1753 | tcc_error("unknown array element size"); |
||
1754 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
1755 | vpushll(u); |
||
1756 | #else |
||
1757 | /* XXX: cast to int ? (long long case) */ |
||
1758 | vpushi(u); |
||
1759 | #endif |
||
1760 | } |
||
1761 | gen_op('*'); |
||
1762 | #if 0 |
||
1763 | /* #ifdef CONFIG_TCC_BCHECK |
||
1764 | The main reason to removing this code: |
||
1765 | #include |
||
1766 | int main () |
||
1767 | { |
||
1768 | int v[10]; |
||
1769 | int i = 10; |
||
1770 | int j = 9; |
||
1771 | fprintf(stderr, "v+i-j = %p\n", v+i-j); |
||
1772 | fprintf(stderr, "v+(i-j) = %p\n", v+(i-j)); |
||
1773 | } |
||
1774 | When this code is on. then the output looks like |
||
1775 | v+i-j = 0xfffffffe |
||
1776 | v+(i-j) = 0xbff84000 |
||
1777 | */ |
||
1778 | /* if evaluating constant expression, no code should be |
||
1779 | generated, so no bound check */ |
||
1780 | if (tcc_state->do_bounds_check && !const_wanted) { |
||
1781 | /* if bounded pointers, we generate a special code to |
||
1782 | test bounds */ |
||
1783 | if (op == '-') { |
||
1784 | vpushi(0); |
||
1785 | vswap(); |
||
1786 | gen_op('-'); |
||
1787 | } |
||
1788 | gen_bounded_ptr_add(); |
||
1789 | } else |
||
1790 | #endif |
||
1791 | { |
||
1792 | gen_opic(op); |
||
1793 | } |
||
1794 | /* put again type if gen_opic() swaped operands */ |
||
1795 | vtop->type = type1; |
||
1796 | } |
||
1797 | } else if (is_float(bt1) || is_float(bt2)) { |
||
1798 | /* compute bigger type and do implicit casts */ |
||
1799 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
1800 | t = VT_LDOUBLE; |
||
1801 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
1802 | t = VT_DOUBLE; |
||
1803 | } else { |
||
1804 | t = VT_FLOAT; |
||
1805 | } |
||
1806 | /* floats can only be used for a few operations */ |
||
1807 | if (op != '+' && op != '-' && op != '*' && op != '/' && |
||
1808 | (op < TOK_ULT || op > TOK_GT)) |
||
1809 | tcc_error("invalid operands for binary operation"); |
||
1810 | goto std_op; |
||
1811 | } else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) { |
||
1812 | t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; |
||
1813 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (t | VT_UNSIGNED)) |
||
1814 | t |= VT_UNSIGNED; |
||
1815 | goto std_op; |
||
1816 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
1817 | /* cast to biggest op */ |
||
1818 | t = VT_LLONG; |
||
1819 | /* convert to unsigned if it does not fit in a long long */ |
||
1820 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
1821 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
1822 | t |= VT_UNSIGNED; |
||
1823 | goto std_op; |
||
1824 | } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
||
1825 | tcc_error("comparison of struct"); |
||
1826 | } else { |
||
1827 | /* integer operations */ |
||
1828 | t = VT_INT; |
||
1829 | /* convert to unsigned if it does not fit in an integer */ |
||
1830 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
1831 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
1832 | t |= VT_UNSIGNED; |
||
1833 | std_op: |
||
1834 | /* XXX: currently, some unsigned operations are explicit, so |
||
1835 | we modify them here */ |
||
1836 | if (t & VT_UNSIGNED) { |
||
1837 | if (op == TOK_SAR) |
||
1838 | op = TOK_SHR; |
||
1839 | else if (op == '/') |
||
1840 | op = TOK_UDIV; |
||
1841 | else if (op == '%') |
||
1842 | op = TOK_UMOD; |
||
1843 | else if (op == TOK_LT) |
||
1844 | op = TOK_ULT; |
||
1845 | else if (op == TOK_GT) |
||
1846 | op = TOK_UGT; |
||
1847 | else if (op == TOK_LE) |
||
1848 | op = TOK_ULE; |
||
1849 | else if (op == TOK_GE) |
||
1850 | op = TOK_UGE; |
||
1851 | } |
||
1852 | vswap(); |
||
1853 | type1.t = t; |
||
1854 | gen_cast(&type1); |
||
1855 | vswap(); |
||
1856 | /* special case for shifts and long long: we keep the shift as |
||
1857 | an integer */ |
||
1858 | if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) |
||
1859 | type1.t = VT_INT; |
||
1860 | gen_cast(&type1); |
||
1861 | if (is_float(t)) |
||
1862 | gen_opif(op); |
||
1863 | else |
||
1864 | gen_opic(op); |
||
1865 | if (op >= TOK_ULT && op <= TOK_GT) { |
||
1866 | /* relationnal op: the result is an int */ |
||
1867 | vtop->type.t = VT_INT; |
||
1868 | } else { |
||
1869 | vtop->type.t = t; |
||
1870 | } |
||
1871 | } |
||
1872 | // Make sure that we have converted to an rvalue: |
||
1873 | if (vtop->r & VT_LVAL && !nocode_wanted) |
||
1874 | gv(is_float(vtop->type.t & VT_BTYPE) ? RC_FLOAT : RC_INT); |
||
1875 | } |
||
1876 | |||
1877 | #ifndef TCC_TARGET_ARM |
||
1878 | /* generic itof for unsigned long long case */ |
||
1879 | static void gen_cvt_itof1(int t) |
||
1880 | { |
||
1881 | #ifdef TCC_TARGET_ARM64 |
||
1882 | gen_cvt_itof(t); |
||
1883 | #else |
||
1884 | if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) == |
||
1885 | (VT_LLONG | VT_UNSIGNED)) { |
||
1886 | |||
1887 | if (t == VT_FLOAT) |
||
1888 | vpush_global_sym(&func_old_type, TOK___floatundisf); |
||
1889 | #if LDOUBLE_SIZE != 8 |
||
1890 | else if (t == VT_LDOUBLE) |
||
1891 | vpush_global_sym(&func_old_type, TOK___floatundixf); |
||
1892 | #endif |
||
1893 | else |
||
1894 | vpush_global_sym(&func_old_type, TOK___floatundidf); |
||
1895 | vrott(2); |
||
1896 | gfunc_call(1); |
||
1897 | vpushi(0); |
||
1898 | vtop->r = reg_fret(t); |
||
1899 | } else { |
||
1900 | gen_cvt_itof(t); |
||
1901 | } |
||
1902 | #endif |
||
1903 | } |
||
1904 | #endif |
||
1905 | |||
1906 | /* generic ftoi for unsigned long long case */ |
||
1907 | static void gen_cvt_ftoi1(int t) |
||
1908 | { |
||
1909 | #ifdef TCC_TARGET_ARM64 |
||
1910 | gen_cvt_ftoi(t); |
||
1911 | #else |
||
1912 | int st; |
||
1913 | |||
1914 | if (t == (VT_LLONG | VT_UNSIGNED)) { |
||
1915 | /* not handled natively */ |
||
1916 | st = vtop->type.t & VT_BTYPE; |
||
1917 | if (st == VT_FLOAT) |
||
1918 | vpush_global_sym(&func_old_type, TOK___fixunssfdi); |
||
1919 | #if LDOUBLE_SIZE != 8 |
||
1920 | else if (st == VT_LDOUBLE) |
||
1921 | vpush_global_sym(&func_old_type, TOK___fixunsxfdi); |
||
1922 | #endif |
||
1923 | else |
||
1924 | vpush_global_sym(&func_old_type, TOK___fixunsdfdi); |
||
1925 | vrott(2); |
||
1926 | gfunc_call(1); |
||
1927 | vpushi(0); |
||
1928 | vtop->r = REG_IRET; |
||
1929 | vtop->r2 = REG_LRET; |
||
1930 | } else { |
||
1931 | gen_cvt_ftoi(t); |
||
1932 | } |
||
1933 | #endif |
||
1934 | } |
||
1935 | |||
1936 | /* force char or short cast */ |
||
1937 | static void force_charshort_cast(int t) |
||
1938 | { |
||
1939 | int bits, dbt; |
||
1940 | dbt = t & VT_BTYPE; |
||
1941 | /* XXX: add optimization if lvalue : just change type and offset */ |
||
1942 | if (dbt == VT_BYTE) |
||
1943 | bits = 8; |
||
1944 | else |
||
1945 | bits = 16; |
||
1946 | if (t & VT_UNSIGNED) { |
||
1947 | vpushi((1 << bits) - 1); |
||
1948 | gen_op('&'); |
||
1949 | } else { |
||
1950 | bits = 32 - bits; |
||
1951 | vpushi(bits); |
||
1952 | gen_op(TOK_SHL); |
||
1953 | /* result must be signed or the SAR is converted to an SHL |
||
1954 | This was not the case when "t" was a signed short |
||
1955 | and the last value on the stack was an unsigned int */ |
||
1956 | vtop->type.t &= ~VT_UNSIGNED; |
||
1957 | vpushi(bits); |
||
1958 | gen_op(TOK_SAR); |
||
1959 | } |
||
1960 | } |
||
1961 | |||
1962 | /* cast 'vtop' to 'type'. Casting to bitfields is forbidden. */ |
||
1963 | static void gen_cast(CType *type) |
||
1964 | { |
||
1965 | int sbt, dbt, sf, df, c, p; |
||
1966 | |||
1967 | /* special delayed cast for char/short */ |
||
1968 | /* XXX: in some cases (multiple cascaded casts), it may still |
||
1969 | be incorrect */ |
||
1970 | if (vtop->r & VT_MUSTCAST) { |
||
1971 | vtop->r &= ~VT_MUSTCAST; |
||
1972 | force_charshort_cast(vtop->type.t); |
||
1973 | } |
||
1974 | |||
1975 | /* bitfields first get cast to ints */ |
||
1976 | if (vtop->type.t & VT_BITFIELD && !nocode_wanted) { |
||
1977 | gv(RC_INT); |
||
1978 | } |
||
1979 | |||
1980 | dbt = type->t & (VT_BTYPE | VT_UNSIGNED); |
||
1981 | sbt = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
||
1982 | |||
1983 | if (sbt != dbt) { |
||
1984 | sf = is_float(sbt); |
||
1985 | df = is_float(dbt); |
||
1986 | c = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
1987 | p = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM); |
||
1988 | if (c) { |
||
1989 | /* constant case: we can do it now */ |
||
1990 | /* XXX: in ISOC, cannot do it if error in convert */ |
||
1991 | if (sbt == VT_FLOAT) |
||
1992 | vtop->c.ld = vtop->c.f; |
||
1993 | else if (sbt == VT_DOUBLE) |
||
1994 | vtop->c.ld = vtop->c.d; |
||
1995 | |||
1996 | if (df) { |
||
1997 | if ((sbt & VT_BTYPE) == VT_LLONG) { |
||
1998 | if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 63)) |
||
1999 | vtop->c.ld = vtop->c.i; |
||
2000 | else |
||
2001 | vtop->c.ld = -(long double)-vtop->c.i; |
||
2002 | } else if(!sf) { |
||
2003 | if ((sbt & VT_UNSIGNED) || !(vtop->c.i >> 31)) |
||
2004 | vtop->c.ld = (uint32_t)vtop->c.i; |
||
2005 | else |
||
2006 | vtop->c.ld = -(long double)-(uint32_t)vtop->c.i; |
||
2007 | } |
||
2008 | |||
2009 | if (dbt == VT_FLOAT) |
||
2010 | vtop->c.f = (float)vtop->c.ld; |
||
2011 | else if (dbt == VT_DOUBLE) |
||
2012 | vtop->c.d = (double)vtop->c.ld; |
||
2013 | } else if (sf && dbt == (VT_LLONG|VT_UNSIGNED)) { |
||
2014 | vtop->c.i = vtop->c.ld; |
||
2015 | } else if (sf && dbt == VT_BOOL) { |
||
2016 | vtop->c.i = (vtop->c.ld != 0); |
||
2017 | } else { |
||
2018 | if(sf) |
||
2019 | vtop->c.i = vtop->c.ld; |
||
2020 | else if (sbt == (VT_LLONG|VT_UNSIGNED)) |
||
2021 | ; |
||
2022 | else if (sbt & VT_UNSIGNED) |
||
2023 | vtop->c.i = (uint32_t)vtop->c.i; |
||
2024 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
2025 | else if (sbt == VT_PTR) |
||
2026 | ; |
||
2027 | #endif |
||
2028 | else if (sbt != VT_LLONG) |
||
2029 | vtop->c.i = ((uint32_t)vtop->c.i | |
||
2030 | -(vtop->c.i & 0x80000000)); |
||
2031 | |||
2032 | if (dbt == (VT_LLONG|VT_UNSIGNED)) |
||
2033 | ; |
||
2034 | else if (dbt == VT_BOOL) |
||
2035 | vtop->c.i = (vtop->c.i != 0); |
||
2036 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
2037 | else if (dbt == VT_PTR) |
||
2038 | ; |
||
2039 | #endif |
||
2040 | else if (dbt != VT_LLONG) { |
||
2041 | uint32_t m = ((dbt & VT_BTYPE) == VT_BYTE ? 0xff : |
||
2042 | (dbt & VT_BTYPE) == VT_SHORT ? 0xffff : |
||
2043 | 0xffffffff); |
||
2044 | vtop->c.i &= m; |
||
2045 | if (!(dbt & VT_UNSIGNED)) |
||
2046 | vtop->c.i |= -(vtop->c.i & ((m >> 1) + 1)); |
||
2047 | } |
||
2048 | } |
||
2049 | } else if (p && dbt == VT_BOOL) { |
||
2050 | vtop->r = VT_CONST; |
||
2051 | vtop->c.i = 1; |
||
2052 | } else if (!nocode_wanted) { |
||
2053 | /* non constant case: generate code */ |
||
2054 | if (sf && df) { |
||
2055 | /* convert from fp to fp */ |
||
2056 | gen_cvt_ftof(dbt); |
||
2057 | } else if (df) { |
||
2058 | /* convert int to fp */ |
||
2059 | gen_cvt_itof1(dbt); |
||
2060 | } else if (sf) { |
||
2061 | /* convert fp to int */ |
||
2062 | if (dbt == VT_BOOL) { |
||
2063 | vpushi(0); |
||
2064 | gen_op(TOK_NE); |
||
2065 | } else { |
||
2066 | /* we handle char/short/etc... with generic code */ |
||
2067 | if (dbt != (VT_INT | VT_UNSIGNED) && |
||
2068 | dbt != (VT_LLONG | VT_UNSIGNED) && |
||
2069 | dbt != VT_LLONG) |
||
2070 | dbt = VT_INT; |
||
2071 | gen_cvt_ftoi1(dbt); |
||
2072 | if (dbt == VT_INT && (type->t & (VT_BTYPE | VT_UNSIGNED)) != dbt) { |
||
2073 | /* additional cast for char/short... */ |
||
2074 | vtop->type.t = dbt; |
||
2075 | gen_cast(type); |
||
2076 | } |
||
2077 | } |
||
2078 | #if !defined(TCC_TARGET_ARM64) && !defined(TCC_TARGET_X86_64) |
||
2079 | } else if ((dbt & VT_BTYPE) == VT_LLONG) { |
||
2080 | if ((sbt & VT_BTYPE) != VT_LLONG && !nocode_wanted) { |
||
2081 | /* scalar to long long */ |
||
2082 | /* machine independent conversion */ |
||
2083 | gv(RC_INT); |
||
2084 | /* generate high word */ |
||
2085 | if (sbt == (VT_INT | VT_UNSIGNED)) { |
||
2086 | vpushi(0); |
||
2087 | gv(RC_INT); |
||
2088 | } else { |
||
2089 | if (sbt == VT_PTR) { |
||
2090 | /* cast from pointer to int before we apply |
||
2091 | shift operation, which pointers don't support*/ |
||
2092 | gen_cast(&int_type); |
||
2093 | } |
||
2094 | gv_dup(); |
||
2095 | vpushi(31); |
||
2096 | gen_op(TOK_SAR); |
||
2097 | } |
||
2098 | /* patch second register */ |
||
2099 | vtop[-1].r2 = vtop->r; |
||
2100 | vpop(); |
||
2101 | } |
||
2102 | #else |
||
2103 | } else if ((dbt & VT_BTYPE) == VT_LLONG || |
||
2104 | (dbt & VT_BTYPE) == VT_PTR || |
||
2105 | (dbt & VT_BTYPE) == VT_FUNC) { |
||
2106 | if ((sbt & VT_BTYPE) != VT_LLONG && |
||
2107 | (sbt & VT_BTYPE) != VT_PTR && |
||
2108 | (sbt & VT_BTYPE) != VT_FUNC && !nocode_wanted) { |
||
2109 | /* need to convert from 32bit to 64bit */ |
||
2110 | gv(RC_INT); |
||
2111 | if (sbt != (VT_INT | VT_UNSIGNED)) { |
||
2112 | #if defined(TCC_TARGET_ARM64) |
||
2113 | gen_cvt_sxtw(); |
||
2114 | #elif defined(TCC_TARGET_X86_64) |
||
2115 | int r = gv(RC_INT); |
||
2116 | /* x86_64 specific: movslq */ |
||
2117 | o(0x6348); |
||
2118 | o(0xc0 + (REG_VALUE(r) << 3) + REG_VALUE(r)); |
||
2119 | #else |
||
2120 | #error |
||
2121 | #endif |
||
2122 | } |
||
2123 | } |
||
2124 | #endif |
||
2125 | } else if (dbt == VT_BOOL) { |
||
2126 | /* scalar to bool */ |
||
2127 | vpushi(0); |
||
2128 | gen_op(TOK_NE); |
||
2129 | } else if ((dbt & VT_BTYPE) == VT_BYTE || |
||
2130 | (dbt & VT_BTYPE) == VT_SHORT) { |
||
2131 | if (sbt == VT_PTR) { |
||
2132 | vtop->type.t = VT_INT; |
||
2133 | tcc_warning("nonportable conversion from pointer to char/short"); |
||
2134 | } |
||
2135 | force_charshort_cast(dbt); |
||
2136 | } else if ((dbt & VT_BTYPE) == VT_INT) { |
||
2137 | /* scalar to int */ |
||
2138 | if (sbt == VT_LLONG && !nocode_wanted) { |
||
2139 | /* from long long: just take low order word */ |
||
2140 | lexpand(); |
||
2141 | vpop(); |
||
2142 | } |
||
2143 | /* if lvalue and single word type, nothing to do because |
||
2144 | the lvalue already contains the real type size (see |
||
2145 | VT_LVAL_xxx constants) */ |
||
2146 | } |
||
2147 | } |
||
2148 | } else if ((dbt & VT_BTYPE) == VT_PTR && !(vtop->r & VT_LVAL)) { |
||
2149 | /* if we are casting between pointer types, |
||
2150 | we must update the VT_LVAL_xxx size */ |
||
2151 | vtop->r = (vtop->r & ~VT_LVAL_TYPE) |
||
2152 | | (lvalue_type(type->ref->type.t) & VT_LVAL_TYPE); |
||
2153 | } |
||
2154 | vtop->type = *type; |
||
2155 | } |
||
2156 | |||
2157 | /* return type size as known at compile time. Put alignment at 'a' */ |
||
2158 | ST_FUNC int type_size(CType *type, int *a) |
||
2159 | { |
||
2160 | Sym *s; |
||
2161 | int bt; |
||
2162 | |||
2163 | bt = type->t & VT_BTYPE; |
||
2164 | if (bt == VT_STRUCT) { |
||
2165 | /* struct/union */ |
||
2166 | s = type->ref; |
||
2167 | *a = s->r; |
||
2168 | return s->c; |
||
2169 | } else if (bt == VT_PTR) { |
||
2170 | if (type->t & VT_ARRAY) { |
||
2171 | int ts; |
||
2172 | |||
2173 | s = type->ref; |
||
2174 | ts = type_size(&s->type, a); |
||
2175 | |||
2176 | if (ts < 0 && s->c < 0) |
||
2177 | ts = -ts; |
||
2178 | |||
2179 | return ts * s->c; |
||
2180 | } else { |
||
2181 | *a = PTR_SIZE; |
||
2182 | return PTR_SIZE; |
||
2183 | } |
||
2184 | } else if (bt == VT_LDOUBLE) { |
||
2185 | *a = LDOUBLE_ALIGN; |
||
2186 | return LDOUBLE_SIZE; |
||
2187 | } else if (bt == VT_DOUBLE || bt == VT_LLONG) { |
||
2188 | #ifdef TCC_TARGET_I386 |
||
2189 | #ifdef TCC_TARGET_PE |
||
2190 | *a = 8; |
||
2191 | #else |
||
2192 | *a = 4; |
||
2193 | #endif |
||
2194 | #elif defined(TCC_TARGET_ARM) |
||
2195 | #ifdef TCC_ARM_EABI |
||
2196 | *a = 8; |
||
2197 | #else |
||
2198 | *a = 4; |
||
2199 | #endif |
||
2200 | #else |
||
2201 | *a = 8; |
||
2202 | #endif |
||
2203 | return 8; |
||
2204 | } else if (bt == VT_INT || bt == VT_FLOAT) { |
||
2205 | *a = 4; |
||
2206 | return 4; |
||
2207 | } else if (bt == VT_SHORT) { |
||
2208 | *a = 2; |
||
2209 | return 2; |
||
2210 | } else if (bt == VT_QLONG || bt == VT_QFLOAT) { |
||
2211 | *a = 8; |
||
2212 | return 16; |
||
2213 | } else if (bt == VT_ENUM) { |
||
2214 | *a = 4; |
||
2215 | /* Enums might be incomplete, so don't just return '4' here. */ |
||
2216 | return type->ref->c; |
||
2217 | } else { |
||
2218 | /* char, void, function, _Bool */ |
||
2219 | *a = 1; |
||
2220 | return 1; |
||
2221 | } |
||
2222 | } |
||
2223 | |||
2224 | /* push type size as known at runtime time on top of value stack. Put |
||
2225 | alignment at 'a' */ |
||
2226 | ST_FUNC void vla_runtime_type_size(CType *type, int *a) |
||
2227 | { |
||
2228 | if (type->t & VT_VLA) { |
||
2229 | vset(&int_type, VT_LOCAL|VT_LVAL, type->ref->c); |
||
2230 | } else { |
||
2231 | vpushi(type_size(type, a)); |
||
2232 | } |
||
2233 | } |
||
2234 | |||
2235 | static void vla_sp_restore(void) { |
||
2236 | if (vlas_in_scope) { |
||
2237 | gen_vla_sp_restore(vla_sp_loc); |
||
2238 | } |
||
2239 | } |
||
2240 | |||
2241 | static void vla_sp_restore_root(void) { |
||
2242 | if (vlas_in_scope) { |
||
2243 | gen_vla_sp_restore(vla_sp_root_loc); |
||
2244 | } |
||
2245 | } |
||
2246 | |||
2247 | /* return the pointed type of t */ |
||
2248 | static inline CType *pointed_type(CType *type) |
||
2249 | { |
||
2250 | return &type->ref->type; |
||
2251 | } |
||
2252 | |||
2253 | /* modify type so that its it is a pointer to type. */ |
||
2254 | ST_FUNC void mk_pointer(CType *type) |
||
2255 | { |
||
2256 | Sym *s; |
||
2257 | s = sym_push(SYM_FIELD, type, 0, -1); |
||
2258 | type->t = VT_PTR | (type->t & ~VT_TYPE); |
||
2259 | type->ref = s; |
||
2260 | } |
||
2261 | |||
2262 | /* compare function types. OLD functions match any new functions */ |
||
2263 | static int is_compatible_func(CType *type1, CType *type2) |
||
2264 | { |
||
2265 | Sym *s1, *s2; |
||
2266 | |||
2267 | s1 = type1->ref; |
||
2268 | s2 = type2->ref; |
||
2269 | if (!is_compatible_types(&s1->type, &s2->type)) |
||
2270 | return 0; |
||
2271 | /* check func_call */ |
||
2272 | if (s1->a.func_call != s2->a.func_call) |
||
2273 | return 0; |
||
2274 | /* XXX: not complete */ |
||
2275 | if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) |
||
2276 | return 1; |
||
2277 | if (s1->c != s2->c) |
||
2278 | return 0; |
||
2279 | while (s1 != NULL) { |
||
2280 | if (s2 == NULL) |
||
2281 | return 0; |
||
2282 | if (!is_compatible_parameter_types(&s1->type, &s2->type)) |
||
2283 | return 0; |
||
2284 | s1 = s1->next; |
||
2285 | s2 = s2->next; |
||
2286 | } |
||
2287 | if (s2) |
||
2288 | return 0; |
||
2289 | return 1; |
||
2290 | } |
||
2291 | |||
2292 | /* return true if type1 and type2 are the same. If unqualified is |
||
2293 | true, qualifiers on the types are ignored. |
||
2294 | |||
2295 | - enums are not checked as gcc __builtin_types_compatible_p () |
||
2296 | */ |
||
2297 | static int compare_types(CType *type1, CType *type2, int unqualified) |
||
2298 | { |
||
2299 | int bt1, t1, t2; |
||
2300 | |||
2301 | t1 = type1->t & VT_TYPE; |
||
2302 | t2 = type2->t & VT_TYPE; |
||
2303 | if (unqualified) { |
||
2304 | /* strip qualifiers before comparing */ |
||
2305 | t1 &= ~(VT_CONSTANT | VT_VOLATILE); |
||
2306 | t2 &= ~(VT_CONSTANT | VT_VOLATILE); |
||
2307 | } |
||
2308 | /* Default Vs explicit signedness only matters for char */ |
||
2309 | if ((t1 & VT_BTYPE) != VT_BYTE) { |
||
2310 | t1 &= ~VT_DEFSIGN; |
||
2311 | t2 &= ~VT_DEFSIGN; |
||
2312 | } |
||
2313 | /* XXX: bitfields ? */ |
||
2314 | if (t1 != t2) |
||
2315 | return 0; |
||
2316 | /* test more complicated cases */ |
||
2317 | bt1 = t1 & VT_BTYPE; |
||
2318 | if (bt1 == VT_PTR) { |
||
2319 | type1 = pointed_type(type1); |
||
2320 | type2 = pointed_type(type2); |
||
2321 | return is_compatible_types(type1, type2); |
||
2322 | } else if (bt1 == VT_STRUCT) { |
||
2323 | return (type1->ref == type2->ref); |
||
2324 | } else if (bt1 == VT_FUNC) { |
||
2325 | return is_compatible_func(type1, type2); |
||
2326 | } else { |
||
2327 | return 1; |
||
2328 | } |
||
2329 | } |
||
2330 | |||
2331 | /* return true if type1 and type2 are exactly the same (including |
||
2332 | qualifiers). |
||
2333 | */ |
||
2334 | static int is_compatible_types(CType *type1, CType *type2) |
||
2335 | { |
||
2336 | return compare_types(type1,type2,0); |
||
2337 | } |
||
2338 | |||
2339 | /* return true if type1 and type2 are the same (ignoring qualifiers). |
||
2340 | */ |
||
2341 | static int is_compatible_parameter_types(CType *type1, CType *type2) |
||
2342 | { |
||
2343 | return compare_types(type1,type2,1); |
||
2344 | } |
||
2345 | |||
2346 | /* print a type. If 'varstr' is not NULL, then the variable is also |
||
2347 | printed in the type */ |
||
2348 | /* XXX: union */ |
||
2349 | /* XXX: add array and function pointers */ |
||
2350 | static void type_to_str(char *buf, int buf_size, |
||
2351 | CType *type, const char *varstr) |
||
2352 | { |
||
2353 | int bt, v, t; |
||
2354 | Sym *s, *sa; |
||
2355 | char buf1[256]; |
||
2356 | const char *tstr; |
||
2357 | |||
2358 | t = type->t & VT_TYPE; |
||
2359 | bt = t & VT_BTYPE; |
||
2360 | buf[0] = '\0'; |
||
2361 | if (t & VT_CONSTANT) |
||
2362 | pstrcat(buf, buf_size, "const "); |
||
2363 | if (t & VT_VOLATILE) |
||
2364 | pstrcat(buf, buf_size, "volatile "); |
||
2365 | if ((t & (VT_DEFSIGN | VT_UNSIGNED)) == (VT_DEFSIGN | VT_UNSIGNED)) |
||
2366 | pstrcat(buf, buf_size, "unsigned "); |
||
2367 | else if (t & VT_DEFSIGN) |
||
2368 | pstrcat(buf, buf_size, "signed "); |
||
2369 | switch(bt) { |
||
2370 | case VT_VOID: |
||
2371 | tstr = "void"; |
||
2372 | goto add_tstr; |
||
2373 | case VT_BOOL: |
||
2374 | tstr = "_Bool"; |
||
2375 | goto add_tstr; |
||
2376 | case VT_BYTE: |
||
2377 | tstr = "char"; |
||
2378 | goto add_tstr; |
||
2379 | case VT_SHORT: |
||
2380 | tstr = "short"; |
||
2381 | goto add_tstr; |
||
2382 | case VT_INT: |
||
2383 | tstr = "int"; |
||
2384 | goto add_tstr; |
||
2385 | case VT_LONG: |
||
2386 | tstr = "long"; |
||
2387 | goto add_tstr; |
||
2388 | case VT_LLONG: |
||
2389 | tstr = "long long"; |
||
2390 | goto add_tstr; |
||
2391 | case VT_FLOAT: |
||
2392 | tstr = "float"; |
||
2393 | goto add_tstr; |
||
2394 | case VT_DOUBLE: |
||
2395 | tstr = "double"; |
||
2396 | goto add_tstr; |
||
2397 | case VT_LDOUBLE: |
||
2398 | tstr = "long double"; |
||
2399 | add_tstr: |
||
2400 | pstrcat(buf, buf_size, tstr); |
||
2401 | break; |
||
2402 | case VT_ENUM: |
||
2403 | case VT_STRUCT: |
||
2404 | if (bt == VT_STRUCT) |
||
2405 | tstr = "struct "; |
||
2406 | else |
||
2407 | tstr = "enum "; |
||
2408 | pstrcat(buf, buf_size, tstr); |
||
2409 | v = type->ref->v & ~SYM_STRUCT; |
||
2410 | if (v >= SYM_FIRST_ANOM) |
||
2411 | pstrcat(buf, buf_size, " |
||
2412 | else |
||
2413 | pstrcat(buf, buf_size, get_tok_str(v, NULL)); |
||
2414 | break; |
||
2415 | case VT_FUNC: |
||
2416 | s = type->ref; |
||
2417 | type_to_str(buf, buf_size, &s->type, varstr); |
||
2418 | pstrcat(buf, buf_size, "("); |
||
2419 | sa = s->next; |
||
2420 | while (sa != NULL) { |
||
2421 | type_to_str(buf1, sizeof(buf1), &sa->type, NULL); |
||
2422 | pstrcat(buf, buf_size, buf1); |
||
2423 | sa = sa->next; |
||
2424 | if (sa) |
||
2425 | pstrcat(buf, buf_size, ", "); |
||
2426 | } |
||
2427 | pstrcat(buf, buf_size, ")"); |
||
2428 | goto no_var; |
||
2429 | case VT_PTR: |
||
2430 | s = type->ref; |
||
2431 | if (t & VT_ARRAY) { |
||
2432 | snprintf(buf1, sizeof(buf1), "%s[%ld]", varstr ? varstr : "", s->c); |
||
2433 | type_to_str(buf, buf_size, &s->type, buf1); |
||
2434 | goto no_var; |
||
2435 | } |
||
2436 | pstrcpy(buf1, sizeof(buf1), "*"); |
||
2437 | if (t & VT_CONSTANT) |
||
2438 | pstrcat(buf1, buf_size, "const "); |
||
2439 | if (t & VT_VOLATILE) |
||
2440 | pstrcat(buf1, buf_size, "volatile "); |
||
2441 | if (varstr) |
||
2442 | pstrcat(buf1, sizeof(buf1), varstr); |
||
2443 | type_to_str(buf, buf_size, &s->type, buf1); |
||
2444 | goto no_var; |
||
2445 | } |
||
2446 | if (varstr) { |
||
2447 | pstrcat(buf, buf_size, " "); |
||
2448 | pstrcat(buf, buf_size, varstr); |
||
2449 | } |
||
2450 | no_var: ; |
||
2451 | } |
||
2452 | |||
2453 | /* verify type compatibility to store vtop in 'dt' type, and generate |
||
2454 | casts if needed. */ |
||
2455 | static void gen_assign_cast(CType *dt) |
||
2456 | { |
||
2457 | CType *st, *type1, *type2, tmp_type1, tmp_type2; |
||
2458 | char buf1[256], buf2[256]; |
||
2459 | int dbt, sbt; |
||
2460 | |||
2461 | st = &vtop->type; /* source type */ |
||
2462 | dbt = dt->t & VT_BTYPE; |
||
2463 | sbt = st->t & VT_BTYPE; |
||
2464 | if (sbt == VT_VOID || dbt == VT_VOID) { |
||
2465 | if (sbt == VT_VOID && dbt == VT_VOID) |
||
2466 | ; /* |
||
2467 | It is Ok if both are void |
||
2468 | A test program: |
||
2469 | void func1() {} |
||
2470 | void func2() { |
||
2471 | return func1(); |
||
2472 | } |
||
2473 | gcc accepts this program |
||
2474 | */ |
||
2475 | else |
||
2476 | tcc_error("cannot cast from/to void"); |
||
2477 | } |
||
2478 | if (dt->t & VT_CONSTANT) |
||
2479 | tcc_warning("assignment of read-only location"); |
||
2480 | switch(dbt) { |
||
2481 | case VT_PTR: |
||
2482 | /* special cases for pointers */ |
||
2483 | /* '0' can also be a pointer */ |
||
2484 | if (is_null_pointer(vtop)) |
||
2485 | goto type_ok; |
||
2486 | /* accept implicit pointer to integer cast with warning */ |
||
2487 | if (is_integer_btype(sbt)) { |
||
2488 | tcc_warning("assignment makes pointer from integer without a cast"); |
||
2489 | goto type_ok; |
||
2490 | } |
||
2491 | type1 = pointed_type(dt); |
||
2492 | /* a function is implicitely a function pointer */ |
||
2493 | if (sbt == VT_FUNC) { |
||
2494 | if ((type1->t & VT_BTYPE) != VT_VOID && |
||
2495 | !is_compatible_types(pointed_type(dt), st)) |
||
2496 | tcc_warning("assignment from incompatible pointer type"); |
||
2497 | goto type_ok; |
||
2498 | } |
||
2499 | if (sbt != VT_PTR) |
||
2500 | goto error; |
||
2501 | type2 = pointed_type(st); |
||
2502 | if ((type1->t & VT_BTYPE) == VT_VOID || |
||
2503 | (type2->t & VT_BTYPE) == VT_VOID) { |
||
2504 | /* void * can match anything */ |
||
2505 | } else { |
||
2506 | /* exact type match, except for unsigned */ |
||
2507 | tmp_type1 = *type1; |
||
2508 | tmp_type2 = *type2; |
||
2509 | tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | |
||
2510 | VT_VOLATILE); |
||
2511 | tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | |
||
2512 | VT_VOLATILE); |
||
2513 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) |
||
2514 | tcc_warning("assignment from incompatible pointer type"); |
||
2515 | } |
||
2516 | /* check const and volatile */ |
||
2517 | if ((!(type1->t & VT_CONSTANT) && (type2->t & VT_CONSTANT)) || |
||
2518 | (!(type1->t & VT_VOLATILE) && (type2->t & VT_VOLATILE))) |
||
2519 | tcc_warning("assignment discards qualifiers from pointer target type"); |
||
2520 | break; |
||
2521 | case VT_BYTE: |
||
2522 | case VT_SHORT: |
||
2523 | case VT_INT: |
||
2524 | case VT_LLONG: |
||
2525 | if (sbt == VT_PTR || sbt == VT_FUNC) { |
||
2526 | tcc_warning("assignment makes integer from pointer without a cast"); |
||
2527 | } |
||
2528 | /* XXX: more tests */ |
||
2529 | break; |
||
2530 | case VT_STRUCT: |
||
2531 | tmp_type1 = *dt; |
||
2532 | tmp_type2 = *st; |
||
2533 | tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
2534 | tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
2535 | if (!is_compatible_types(&tmp_type1, &tmp_type2)) { |
||
2536 | error: |
||
2537 | type_to_str(buf1, sizeof(buf1), st, NULL); |
||
2538 | type_to_str(buf2, sizeof(buf2), dt, NULL); |
||
2539 | tcc_error("cannot cast '%s' to '%s'", buf1, buf2); |
||
2540 | } |
||
2541 | break; |
||
2542 | } |
||
2543 | type_ok: |
||
2544 | gen_cast(dt); |
||
2545 | } |
||
2546 | |||
2547 | /* store vtop in lvalue pushed on stack */ |
||
2548 | ST_FUNC void vstore(void) |
||
2549 | { |
||
2550 | int sbt, dbt, ft, r, t, size, align, bit_size, bit_pos, rc, delayed_cast; |
||
2551 | |||
2552 | ft = vtop[-1].type.t; |
||
2553 | sbt = vtop->type.t & VT_BTYPE; |
||
2554 | dbt = ft & VT_BTYPE; |
||
2555 | if ((((sbt == VT_INT || sbt == VT_SHORT) && dbt == VT_BYTE) || |
||
2556 | (sbt == VT_INT && dbt == VT_SHORT)) |
||
2557 | && !(vtop->type.t & VT_BITFIELD)) { |
||
2558 | /* optimize char/short casts */ |
||
2559 | delayed_cast = VT_MUSTCAST; |
||
2560 | vtop->type.t = (ft & VT_TYPE & ~VT_BITFIELD & |
||
2561 | ((1 << VT_STRUCT_SHIFT) - 1)); |
||
2562 | /* XXX: factorize */ |
||
2563 | if (ft & VT_CONSTANT) |
||
2564 | tcc_warning("assignment of read-only location"); |
||
2565 | } else { |
||
2566 | delayed_cast = 0; |
||
2567 | if (!(ft & VT_BITFIELD)) |
||
2568 | gen_assign_cast(&vtop[-1].type); |
||
2569 | } |
||
2570 | |||
2571 | if (sbt == VT_STRUCT) { |
||
2572 | /* if structure, only generate pointer */ |
||
2573 | /* structure assignment : generate memcpy */ |
||
2574 | /* XXX: optimize if small size */ |
||
2575 | if (!nocode_wanted) { |
||
2576 | size = type_size(&vtop->type, &align); |
||
2577 | |||
2578 | /* destination */ |
||
2579 | vswap(); |
||
2580 | vtop->type.t = VT_PTR; |
||
2581 | gaddrof(); |
||
2582 | |||
2583 | /* address of memcpy() */ |
||
2584 | #ifdef TCC_ARM_EABI |
||
2585 | if(!(align & 7)) |
||
2586 | vpush_global_sym(&func_old_type, TOK_memcpy8); |
||
2587 | else if(!(align & 3)) |
||
2588 | vpush_global_sym(&func_old_type, TOK_memcpy4); |
||
2589 | else |
||
2590 | #endif |
||
2591 | /* Use memmove, rather than memcpy, as dest and src may be same: */ |
||
2592 | vpush_global_sym(&func_old_type, TOK_memmove); |
||
2593 | |||
2594 | vswap(); |
||
2595 | /* source */ |
||
2596 | vpushv(vtop - 2); |
||
2597 | vtop->type.t = VT_PTR; |
||
2598 | gaddrof(); |
||
2599 | /* type size */ |
||
2600 | vpushi(size); |
||
2601 | gfunc_call(3); |
||
2602 | } else { |
||
2603 | vswap(); |
||
2604 | vpop(); |
||
2605 | } |
||
2606 | /* leave source on stack */ |
||
2607 | } else if (ft & VT_BITFIELD) { |
||
2608 | /* bitfield store handling */ |
||
2609 | |||
2610 | /* save lvalue as expression result (example: s.b = s.a = n;) */ |
||
2611 | vdup(), vtop[-1] = vtop[-2]; |
||
2612 | |||
2613 | bit_pos = (ft >> VT_STRUCT_SHIFT) & 0x3f; |
||
2614 | bit_size = (ft >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
2615 | /* remove bit field info to avoid loops */ |
||
2616 | vtop[-1].type.t = ft & ~VT_BITFIELD & ((1 << VT_STRUCT_SHIFT) - 1); |
||
2617 | |||
2618 | if((ft & VT_BTYPE) == VT_BOOL) { |
||
2619 | gen_cast(&vtop[-1].type); |
||
2620 | vtop[-1].type.t = (vtop[-1].type.t & ~VT_BTYPE) | (VT_BYTE | VT_UNSIGNED); |
||
2621 | } |
||
2622 | |||
2623 | /* duplicate destination */ |
||
2624 | vdup(); |
||
2625 | vtop[-1] = vtop[-2]; |
||
2626 | |||
2627 | /* mask and shift source */ |
||
2628 | if((ft & VT_BTYPE) != VT_BOOL) { |
||
2629 | if((ft & VT_BTYPE) == VT_LLONG) { |
||
2630 | vpushll((1ULL << bit_size) - 1ULL); |
||
2631 | } else { |
||
2632 | vpushi((1 << bit_size) - 1); |
||
2633 | } |
||
2634 | gen_op('&'); |
||
2635 | } |
||
2636 | vpushi(bit_pos); |
||
2637 | gen_op(TOK_SHL); |
||
2638 | /* load destination, mask and or with source */ |
||
2639 | vswap(); |
||
2640 | if((ft & VT_BTYPE) == VT_LLONG) { |
||
2641 | vpushll(~(((1ULL << bit_size) - 1ULL) << bit_pos)); |
||
2642 | } else { |
||
2643 | vpushi(~(((1 << bit_size) - 1) << bit_pos)); |
||
2644 | } |
||
2645 | gen_op('&'); |
||
2646 | gen_op('|'); |
||
2647 | /* store result */ |
||
2648 | vstore(); |
||
2649 | /* ... and discard */ |
||
2650 | vpop(); |
||
2651 | |||
2652 | } else { |
||
2653 | if (!nocode_wanted) { |
||
2654 | #ifdef CONFIG_TCC_BCHECK |
||
2655 | /* bound check case */ |
||
2656 | if (vtop[-1].r & VT_MUSTBOUND) { |
||
2657 | vswap(); |
||
2658 | gbound(); |
||
2659 | vswap(); |
||
2660 | } |
||
2661 | #endif |
||
2662 | rc = RC_INT; |
||
2663 | if (is_float(ft)) { |
||
2664 | rc = RC_FLOAT; |
||
2665 | #ifdef TCC_TARGET_X86_64 |
||
2666 | if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
||
2667 | rc = RC_ST0; |
||
2668 | } else if ((ft & VT_BTYPE) == VT_QFLOAT) { |
||
2669 | rc = RC_FRET; |
||
2670 | } |
||
2671 | #endif |
||
2672 | } |
||
2673 | r = gv(rc); /* generate value */ |
||
2674 | /* if lvalue was saved on stack, must read it */ |
||
2675 | if ((vtop[-1].r & VT_VALMASK) == VT_LLOCAL) { |
||
2676 | SValue sv; |
||
2677 | t = get_reg(RC_INT); |
||
2678 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
2679 | sv.type.t = VT_PTR; |
||
2680 | #else |
||
2681 | sv.type.t = VT_INT; |
||
2682 | #endif |
||
2683 | sv.r = VT_LOCAL | VT_LVAL; |
||
2684 | sv.c.i = vtop[-1].c.i; |
||
2685 | load(t, &sv); |
||
2686 | vtop[-1].r = t | VT_LVAL; |
||
2687 | } |
||
2688 | /* two word case handling : store second register at word + 4 (or +8 for x86-64) */ |
||
2689 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
2690 | if (((ft & VT_BTYPE) == VT_QLONG) || ((ft & VT_BTYPE) == VT_QFLOAT)) { |
||
2691 | int addr_type = VT_LLONG, load_size = 8, load_type = ((vtop->type.t & VT_BTYPE) == VT_QLONG) ? VT_LLONG : VT_DOUBLE; |
||
2692 | #else |
||
2693 | if ((ft & VT_BTYPE) == VT_LLONG) { |
||
2694 | int addr_type = VT_INT, load_size = 4, load_type = VT_INT; |
||
2695 | #endif |
||
2696 | vtop[-1].type.t = load_type; |
||
2697 | store(r, vtop - 1); |
||
2698 | vswap(); |
||
2699 | /* convert to int to increment easily */ |
||
2700 | vtop->type.t = addr_type; |
||
2701 | gaddrof(); |
||
2702 | vpushi(load_size); |
||
2703 | gen_op('+'); |
||
2704 | vtop->r |= VT_LVAL; |
||
2705 | vswap(); |
||
2706 | vtop[-1].type.t = load_type; |
||
2707 | /* XXX: it works because r2 is spilled last ! */ |
||
2708 | store(vtop->r2, vtop - 1); |
||
2709 | } else { |
||
2710 | store(r, vtop - 1); |
||
2711 | } |
||
2712 | } |
||
2713 | vswap(); |
||
2714 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
2715 | vtop->r |= delayed_cast; |
||
2716 | } |
||
2717 | } |
||
2718 | |||
2719 | /* post defines POST/PRE add. c is the token ++ or -- */ |
||
2720 | ST_FUNC void inc(int post, int c) |
||
2721 | { |
||
2722 | test_lvalue(); |
||
2723 | vdup(); /* save lvalue */ |
||
2724 | if (post) { |
||
2725 | if (!nocode_wanted) |
||
2726 | gv_dup(); /* duplicate value */ |
||
2727 | else |
||
2728 | vdup(); /* duplicate value */ |
||
2729 | vrotb(3); |
||
2730 | vrotb(3); |
||
2731 | } |
||
2732 | /* add constant */ |
||
2733 | vpushi(c - TOK_MID); |
||
2734 | gen_op('+'); |
||
2735 | vstore(); /* store value */ |
||
2736 | if (post) |
||
2737 | vpop(); /* if post op, return saved value */ |
||
2738 | } |
||
2739 | |||
2740 | /* Parse GNUC __attribute__ extension. Currently, the following |
||
2741 | extensions are recognized: |
||
2742 | - aligned(n) : set data/function alignment. |
||
2743 | - packed : force data alignment to 1 |
||
2744 | - section(x) : generate data/code in this section. |
||
2745 | - unused : currently ignored, but may be used someday. |
||
2746 | - regparm(n) : pass function parameters in registers (i386 only) |
||
2747 | */ |
||
2748 | static void parse_attribute(AttributeDef *ad) |
||
2749 | { |
||
2750 | int t, n; |
||
2751 | |||
2752 | while (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { |
||
2753 | next(); |
||
2754 | skip('('); |
||
2755 | skip('('); |
||
2756 | while (tok != ')') { |
||
2757 | if (tok < TOK_IDENT) |
||
2758 | expect("attribute name"); |
||
2759 | t = tok; |
||
2760 | next(); |
||
2761 | switch(t) { |
||
2762 | case TOK_SECTION1: |
||
2763 | case TOK_SECTION2: |
||
2764 | skip('('); |
||
2765 | if (tok != TOK_STR) |
||
2766 | expect("section name"); |
||
2767 | ad->section = find_section(tcc_state, (char *)tokc.str.data); |
||
2768 | next(); |
||
2769 | skip(')'); |
||
2770 | break; |
||
2771 | case TOK_ALIAS1: |
||
2772 | case TOK_ALIAS2: |
||
2773 | skip('('); |
||
2774 | if (tok != TOK_STR) |
||
2775 | expect("alias(\"target\")"); |
||
2776 | ad->alias_target = /* save string as token, for later */ |
||
2777 | tok_alloc((char*)tokc.str.data, tokc.str.size-1)->tok; |
||
2778 | next(); |
||
2779 | skip(')'); |
||
2780 | break; |
||
2781 | case TOK_VISIBILITY1: |
||
2782 | case TOK_VISIBILITY2: |
||
2783 | skip('('); |
||
2784 | if (tok != TOK_STR) |
||
2785 | expect("visibility(\"default|hidden|internal|protected\")"); |
||
2786 | if (!strcmp (tokc.str.data, "default")) |
||
2787 | ad->a.visibility = STV_DEFAULT; |
||
2788 | else if (!strcmp (tokc.str.data, "hidden")) |
||
2789 | ad->a.visibility = STV_HIDDEN; |
||
2790 | else if (!strcmp (tokc.str.data, "internal")) |
||
2791 | ad->a.visibility = STV_INTERNAL; |
||
2792 | else if (!strcmp (tokc.str.data, "protected")) |
||
2793 | ad->a.visibility = STV_PROTECTED; |
||
2794 | else |
||
2795 | expect("visibility(\"default|hidden|internal|protected\")"); |
||
2796 | next(); |
||
2797 | skip(')'); |
||
2798 | break; |
||
2799 | case TOK_ALIGNED1: |
||
2800 | case TOK_ALIGNED2: |
||
2801 | if (tok == '(') { |
||
2802 | next(); |
||
2803 | n = expr_const(); |
||
2804 | if (n <= 0 || (n & (n - 1)) != 0) |
||
2805 | tcc_error("alignment must be a positive power of two"); |
||
2806 | skip(')'); |
||
2807 | } else { |
||
2808 | n = MAX_ALIGN; |
||
2809 | } |
||
2810 | ad->a.aligned = n; |
||
2811 | break; |
||
2812 | case TOK_PACKED1: |
||
2813 | case TOK_PACKED2: |
||
2814 | ad->a.packed = 1; |
||
2815 | break; |
||
2816 | case TOK_WEAK1: |
||
2817 | case TOK_WEAK2: |
||
2818 | ad->a.weak = 1; |
||
2819 | break; |
||
2820 | case TOK_UNUSED1: |
||
2821 | case TOK_UNUSED2: |
||
2822 | /* currently, no need to handle it because tcc does not |
||
2823 | track unused objects */ |
||
2824 | break; |
||
2825 | case TOK_NORETURN1: |
||
2826 | case TOK_NORETURN2: |
||
2827 | /* currently, no need to handle it because tcc does not |
||
2828 | track unused objects */ |
||
2829 | break; |
||
2830 | case TOK_CDECL1: |
||
2831 | case TOK_CDECL2: |
||
2832 | case TOK_CDECL3: |
||
2833 | ad->a.func_call = FUNC_CDECL; |
||
2834 | break; |
||
2835 | case TOK_STDCALL1: |
||
2836 | case TOK_STDCALL2: |
||
2837 | case TOK_STDCALL3: |
||
2838 | ad->a.func_call = FUNC_STDCALL; |
||
2839 | break; |
||
2840 | #ifdef TCC_TARGET_I386 |
||
2841 | case TOK_REGPARM1: |
||
2842 | case TOK_REGPARM2: |
||
2843 | skip('('); |
||
2844 | n = expr_const(); |
||
2845 | if (n > 3) |
||
2846 | n = 3; |
||
2847 | else if (n < 0) |
||
2848 | n = 0; |
||
2849 | if (n > 0) |
||
2850 | ad->a.func_call = FUNC_FASTCALL1 + n - 1; |
||
2851 | skip(')'); |
||
2852 | break; |
||
2853 | case TOK_FASTCALL1: |
||
2854 | case TOK_FASTCALL2: |
||
2855 | case TOK_FASTCALL3: |
||
2856 | ad->a.func_call = FUNC_FASTCALLW; |
||
2857 | break; |
||
2858 | #endif |
||
2859 | case TOK_MODE: |
||
2860 | skip('('); |
||
2861 | switch(tok) { |
||
2862 | case TOK_MODE_DI: |
||
2863 | ad->a.mode = VT_LLONG + 1; |
||
2864 | break; |
||
2865 | case TOK_MODE_HI: |
||
2866 | ad->a.mode = VT_SHORT + 1; |
||
2867 | break; |
||
2868 | case TOK_MODE_SI: |
||
2869 | ad->a.mode = VT_INT + 1; |
||
2870 | break; |
||
2871 | default: |
||
2872 | tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, NULL)); |
||
2873 | break; |
||
2874 | } |
||
2875 | next(); |
||
2876 | skip(')'); |
||
2877 | break; |
||
2878 | case TOK_DLLEXPORT: |
||
2879 | ad->a.func_export = 1; |
||
2880 | break; |
||
2881 | case TOK_DLLIMPORT: |
||
2882 | ad->a.func_import = 1; |
||
2883 | break; |
||
2884 | default: |
||
2885 | if (tcc_state->warn_unsupported) |
||
2886 | tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL)); |
||
2887 | /* skip parameters */ |
||
2888 | if (tok == '(') { |
||
2889 | int parenthesis = 0; |
||
2890 | do { |
||
2891 | if (tok == '(') |
||
2892 | parenthesis++; |
||
2893 | else if (tok == ')') |
||
2894 | parenthesis--; |
||
2895 | next(); |
||
2896 | } while (parenthesis && tok != -1); |
||
2897 | } |
||
2898 | break; |
||
2899 | } |
||
2900 | if (tok != ',') |
||
2901 | break; |
||
2902 | next(); |
||
2903 | } |
||
2904 | skip(')'); |
||
2905 | skip(')'); |
||
2906 | } |
||
2907 | } |
||
2908 | |||
2909 | /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ |
||
2910 | static void struct_decl(CType *type, AttributeDef *ad, int u) |
||
2911 | { |
||
2912 | int a, v, size, align, maxalign, c, offset, flexible; |
||
2913 | int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt; |
||
2914 | Sym *s, *ss, *ass, **ps; |
||
2915 | AttributeDef ad1; |
||
2916 | CType type1, btype; |
||
2917 | |||
2918 | a = tok; /* save decl type */ |
||
2919 | next(); |
||
2920 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) { |
||
2921 | parse_attribute(ad); |
||
2922 | next(); |
||
2923 | } |
||
2924 | if (tok != '{') { |
||
2925 | v = tok; |
||
2926 | next(); |
||
2927 | /* struct already defined ? return it */ |
||
2928 | if (v < TOK_IDENT) |
||
2929 | expect("struct/union/enum name"); |
||
2930 | s = struct_find(v); |
||
2931 | if (s) { |
||
2932 | if (s->type.t != a) |
||
2933 | tcc_error("invalid type"); |
||
2934 | goto do_decl; |
||
2935 | } |
||
2936 | } else { |
||
2937 | v = anon_sym++; |
||
2938 | } |
||
2939 | type1.t = a; |
||
2940 | type1.ref = NULL; |
||
2941 | /* we put an undefined size for struct/union */ |
||
2942 | s = sym_push(v | SYM_STRUCT, &type1, 0, -1); |
||
2943 | s->r = 0; /* default alignment is zero as gcc */ |
||
2944 | /* put struct/union/enum name in type */ |
||
2945 | do_decl: |
||
2946 | type->t = u; |
||
2947 | type->ref = s; |
||
2948 | |||
2949 | if (tok == '{') { |
||
2950 | next(); |
||
2951 | if (s->c != -1) |
||
2952 | tcc_error("struct/union/enum already defined"); |
||
2953 | /* cannot be empty */ |
||
2954 | c = 0; |
||
2955 | /* non empty enums are not allowed */ |
||
2956 | if (a == TOK_ENUM) { |
||
2957 | for(;;) { |
||
2958 | v = tok; |
||
2959 | if (v < TOK_UIDENT) |
||
2960 | expect("identifier"); |
||
2961 | ss = sym_find(v); |
||
2962 | if (ss && !local_stack) |
||
2963 | tcc_error("redefinition of enumerator '%s'", |
||
2964 | get_tok_str(v, NULL)); |
||
2965 | next(); |
||
2966 | if (tok == '=') { |
||
2967 | next(); |
||
2968 | c = expr_const(); |
||
2969 | } |
||
2970 | /* enum symbols have static storage */ |
||
2971 | ss = sym_push(v, &int_type, VT_CONST, c); |
||
2972 | ss->type.t |= VT_STATIC; |
||
2973 | if (tok != ',') |
||
2974 | break; |
||
2975 | next(); |
||
2976 | c++; |
||
2977 | /* NOTE: we accept a trailing comma */ |
||
2978 | if (tok == '}') |
||
2979 | break; |
||
2980 | } |
||
2981 | s->c = type_size(&int_type, &align); |
||
2982 | skip('}'); |
||
2983 | } else { |
||
2984 | maxalign = 1; |
||
2985 | ps = &s->next; |
||
2986 | prevbt = VT_INT; |
||
2987 | bit_pos = 0; |
||
2988 | offset = 0; |
||
2989 | flexible = 0; |
||
2990 | while (tok != '}') { |
||
2991 | parse_btype(&btype, &ad1); |
||
2992 | while (1) { |
||
2993 | if (flexible) |
||
2994 | tcc_error("flexible array member '%s' not at the end of struct", |
||
2995 | get_tok_str(v, NULL)); |
||
2996 | bit_size = -1; |
||
2997 | v = 0; |
||
2998 | type1 = btype; |
||
2999 | if (tok != ':') { |
||
3000 | type_decl(&type1, &ad1, &v, TYPE_DIRECT | TYPE_ABSTRACT); |
||
3001 | if (v == 0) { |
||
3002 | if ((type1.t & VT_BTYPE) != VT_STRUCT) |
||
3003 | expect("identifier"); |
||
3004 | else { |
||
3005 | int v = btype.ref->v; |
||
3006 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) < SYM_FIRST_ANOM) { |
||
3007 | if (tcc_state->ms_extensions == 0) |
||
3008 | expect("identifier"); |
||
3009 | } |
||
3010 | } |
||
3011 | } |
||
3012 | if (type_size(&type1, &align) < 0) { |
||
3013 | if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY) && c) |
||
3014 | flexible = 1; |
||
3015 | else |
||
3016 | tcc_error("field '%s' has incomplete type", |
||
3017 | get_tok_str(v, NULL)); |
||
3018 | } |
||
3019 | if ((type1.t & VT_BTYPE) == VT_FUNC || |
||
3020 | (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) |
||
3021 | tcc_error("invalid type for '%s'", |
||
3022 | get_tok_str(v, NULL)); |
||
3023 | } |
||
3024 | if (tok == ':') { |
||
3025 | next(); |
||
3026 | bit_size = expr_const(); |
||
3027 | /* XXX: handle v = 0 case for messages */ |
||
3028 | if (bit_size < 0) |
||
3029 | tcc_error("negative width in bit-field '%s'", |
||
3030 | get_tok_str(v, NULL)); |
||
3031 | if (v && bit_size == 0) |
||
3032 | tcc_error("zero width for bit-field '%s'", |
||
3033 | get_tok_str(v, NULL)); |
||
3034 | } |
||
3035 | size = type_size(&type1, &align); |
||
3036 | if (ad1.a.aligned) { |
||
3037 | if (align < ad1.a.aligned) |
||
3038 | align = ad1.a.aligned; |
||
3039 | } else if (ad1.a.packed) { |
||
3040 | align = 1; |
||
3041 | } else if (*tcc_state->pack_stack_ptr) { |
||
3042 | if (align > *tcc_state->pack_stack_ptr) |
||
3043 | align = *tcc_state->pack_stack_ptr; |
||
3044 | } |
||
3045 | lbit_pos = 0; |
||
3046 | if (bit_size >= 0) { |
||
3047 | bt = type1.t & VT_BTYPE; |
||
3048 | if (bt != VT_INT && |
||
3049 | bt != VT_BYTE && |
||
3050 | bt != VT_SHORT && |
||
3051 | bt != VT_BOOL && |
||
3052 | bt != VT_ENUM && |
||
3053 | bt != VT_LLONG) |
||
3054 | tcc_error("bitfields must have scalar type"); |
||
3055 | bsize = size * 8; |
||
3056 | if (bit_size > bsize) { |
||
3057 | tcc_error("width of '%s' exceeds its type", |
||
3058 | get_tok_str(v, NULL)); |
||
3059 | } else if (bit_size == bsize) { |
||
3060 | /* no need for bit fields */ |
||
3061 | bit_pos = 0; |
||
3062 | } else if (bit_size == 0) { |
||
3063 | /* XXX: what to do if only padding in a |
||
3064 | structure ? */ |
||
3065 | /* zero size: means to pad */ |
||
3066 | bit_pos = 0; |
||
3067 | } else { |
||
3068 | /* we do not have enough room ? |
||
3069 | did the type change? |
||
3070 | is it a union? */ |
||
3071 | if ((bit_pos + bit_size) > bsize || |
||
3072 | bt != prevbt || a == TOK_UNION) |
||
3073 | bit_pos = 0; |
||
3074 | lbit_pos = bit_pos; |
||
3075 | /* XXX: handle LSB first */ |
||
3076 | type1.t |= VT_BITFIELD | |
||
3077 | (bit_pos << VT_STRUCT_SHIFT) | |
||
3078 | (bit_size << (VT_STRUCT_SHIFT + 6)); |
||
3079 | bit_pos += bit_size; |
||
3080 | } |
||
3081 | prevbt = bt; |
||
3082 | } else { |
||
3083 | bit_pos = 0; |
||
3084 | } |
||
3085 | if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) { |
||
3086 | /* add new memory data only if starting |
||
3087 | bit field */ |
||
3088 | if (lbit_pos == 0) { |
||
3089 | if (a == TOK_STRUCT) { |
||
3090 | c = (c + align - 1) & -align; |
||
3091 | offset = c; |
||
3092 | if (size > 0) |
||
3093 | c += size; |
||
3094 | } else { |
||
3095 | offset = 0; |
||
3096 | if (size > c) |
||
3097 | c = size; |
||
3098 | } |
||
3099 | if (align > maxalign) |
||
3100 | maxalign = align; |
||
3101 | } |
||
3102 | #if 0 |
||
3103 | printf("add field %s offset=%d", |
||
3104 | get_tok_str(v, NULL), offset); |
||
3105 | if (type1.t & VT_BITFIELD) { |
||
3106 | printf(" pos=%d size=%d", |
||
3107 | (type1.t >> VT_STRUCT_SHIFT) & 0x3f, |
||
3108 | (type1.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f); |
||
3109 | } |
||
3110 | printf("\n"); |
||
3111 | #endif |
||
3112 | } |
||
3113 | if (v == 0 && (type1.t & VT_BTYPE) == VT_STRUCT) { |
||
3114 | ass = type1.ref; |
||
3115 | while ((ass = ass->next) != NULL) { |
||
3116 | ss = sym_push(ass->v, &ass->type, 0, offset + ass->c); |
||
3117 | *ps = ss; |
||
3118 | ps = &ss->next; |
||
3119 | } |
||
3120 | } else if (v) { |
||
3121 | ss = sym_push(v | SYM_FIELD, &type1, 0, offset); |
||
3122 | *ps = ss; |
||
3123 | ps = &ss->next; |
||
3124 | } |
||
3125 | if (tok == ';' || tok == TOK_EOF) |
||
3126 | break; |
||
3127 | skip(','); |
||
3128 | } |
||
3129 | skip(';'); |
||
3130 | } |
||
3131 | skip('}'); |
||
3132 | /* store size and alignment */ |
||
3133 | s->c = (c + maxalign - 1) & -maxalign; |
||
3134 | s->r = maxalign; |
||
3135 | } |
||
3136 | } |
||
3137 | } |
||
3138 | |||
3139 | /* return 1 if basic type is a type size (short, long, long long) */ |
||
3140 | ST_FUNC int is_btype_size(int bt) |
||
3141 | { |
||
3142 | return bt == VT_SHORT || bt == VT_LONG || bt == VT_LLONG; |
||
3143 | } |
||
3144 | |||
3145 | /* Add type qualifiers to a type. If the type is an array then the qualifiers |
||
3146 | are added to the element type, copied because it could be a typedef. */ |
||
3147 | static void parse_btype_qualify(CType *type, int qualifiers) |
||
3148 | { |
||
3149 | while (type->t & VT_ARRAY) { |
||
3150 | type->ref = sym_push(SYM_FIELD, &type->ref->type, 0, type->ref->c); |
||
3151 | type = &type->ref->type; |
||
3152 | } |
||
3153 | type->t |= qualifiers; |
||
3154 | } |
||
3155 | |||
3156 | /* return 0 if no type declaration. otherwise, return the basic type |
||
3157 | and skip it. |
||
3158 | */ |
||
3159 | static int parse_btype(CType *type, AttributeDef *ad) |
||
3160 | { |
||
3161 | int t, u, bt_size, complete, type_found, typespec_found; |
||
3162 | Sym *s; |
||
3163 | CType type1; |
||
3164 | |||
3165 | memset(ad, 0, sizeof(AttributeDef)); |
||
3166 | complete = 0; |
||
3167 | type_found = 0; |
||
3168 | typespec_found = 0; |
||
3169 | t = 0; |
||
3170 | while(1) { |
||
3171 | switch(tok) { |
||
3172 | case TOK_EXTENSION: |
||
3173 | /* currently, we really ignore extension */ |
||
3174 | next(); |
||
3175 | continue; |
||
3176 | |||
3177 | /* basic types */ |
||
3178 | case TOK_CHAR: |
||
3179 | u = VT_BYTE; |
||
3180 | basic_type: |
||
3181 | next(); |
||
3182 | basic_type1: |
||
3183 | if (complete) |
||
3184 | tcc_error("too many basic types"); |
||
3185 | t |= u; |
||
3186 | bt_size = is_btype_size (u & VT_BTYPE); |
||
3187 | if (u == VT_INT || (!bt_size && !(t & VT_TYPEDEF))) |
||
3188 | complete = 1; |
||
3189 | typespec_found = 1; |
||
3190 | break; |
||
3191 | case TOK_VOID: |
||
3192 | u = VT_VOID; |
||
3193 | goto basic_type; |
||
3194 | case TOK_SHORT: |
||
3195 | u = VT_SHORT; |
||
3196 | goto basic_type; |
||
3197 | case TOK_INT: |
||
3198 | u = VT_INT; |
||
3199 | goto basic_type; |
||
3200 | case TOK_LONG: |
||
3201 | next(); |
||
3202 | if ((t & VT_BTYPE) == VT_DOUBLE) { |
||
3203 | /* siemargl not sure, needed long double or will fail ? FAIL */ |
||
3204 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
||
3205 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
3206 | #endif |
||
3207 | } else if ((t & VT_BTYPE) == VT_LONG) { |
||
3208 | t = (t & ~VT_BTYPE) | VT_LLONG; |
||
3209 | } else { |
||
3210 | u = VT_LONG; |
||
3211 | goto basic_type1; |
||
3212 | } |
||
3213 | break; |
||
3214 | #ifdef TCC_TARGET_ARM64 |
||
3215 | case TOK_UINT128: |
||
3216 | /* GCC's __uint128_t appears in some Linux header files. Make it a |
||
3217 | synonym for long double to get the size and alignment right. */ |
||
3218 | u = VT_LDOUBLE; |
||
3219 | goto basic_type; |
||
3220 | #endif |
||
3221 | case TOK_BOOL: |
||
3222 | u = VT_BOOL; |
||
3223 | goto basic_type; |
||
3224 | case TOK_FLOAT: |
||
3225 | u = VT_FLOAT; |
||
3226 | goto basic_type; |
||
3227 | case TOK_DOUBLE: |
||
3228 | next(); |
||
3229 | if ((t & VT_BTYPE) == VT_LONG) { |
||
3230 | /* siemargl not sure, needed long double or will fail ? FAIL */ |
||
3231 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_MEOS) |
||
3232 | t = (t & ~VT_BTYPE) | VT_DOUBLE; |
||
3233 | #else |
||
3234 | t = (t & ~VT_BTYPE) | VT_LDOUBLE; |
||
3235 | #endif |
||
3236 | } else { |
||
3237 | u = VT_DOUBLE; |
||
3238 | goto basic_type1; |
||
3239 | } |
||
3240 | break; |
||
3241 | case TOK_ENUM: |
||
3242 | struct_decl(&type1, ad, VT_ENUM); |
||
3243 | basic_type2: |
||
3244 | u = type1.t; |
||
3245 | type->ref = type1.ref; |
||
3246 | goto basic_type1; |
||
3247 | case TOK_STRUCT: |
||
3248 | case TOK_UNION: |
||
3249 | struct_decl(&type1, ad, VT_STRUCT); |
||
3250 | goto basic_type2; |
||
3251 | |||
3252 | /* type modifiers */ |
||
3253 | case TOK_CONST1: |
||
3254 | case TOK_CONST2: |
||
3255 | case TOK_CONST3: |
||
3256 | type->t = t; |
||
3257 | parse_btype_qualify(type, VT_CONSTANT); |
||
3258 | t = type->t; |
||
3259 | next(); |
||
3260 | break; |
||
3261 | case TOK_VOLATILE1: |
||
3262 | case TOK_VOLATILE2: |
||
3263 | case TOK_VOLATILE3: |
||
3264 | type->t = t; |
||
3265 | parse_btype_qualify(type, VT_VOLATILE); |
||
3266 | t = type->t; |
||
3267 | next(); |
||
3268 | break; |
||
3269 | case TOK_SIGNED1: |
||
3270 | case TOK_SIGNED2: |
||
3271 | case TOK_SIGNED3: |
||
3272 | if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == (VT_DEFSIGN|VT_UNSIGNED)) |
||
3273 | tcc_error("signed and unsigned modifier"); |
||
3274 | typespec_found = 1; |
||
3275 | t |= VT_DEFSIGN; |
||
3276 | next(); |
||
3277 | break; |
||
3278 | case TOK_REGISTER: |
||
3279 | case TOK_AUTO: |
||
3280 | case TOK_RESTRICT1: |
||
3281 | case TOK_RESTRICT2: |
||
3282 | case TOK_RESTRICT3: |
||
3283 | next(); |
||
3284 | break; |
||
3285 | case TOK_UNSIGNED: |
||
3286 | if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == VT_DEFSIGN) |
||
3287 | tcc_error("signed and unsigned modifier"); |
||
3288 | t |= VT_DEFSIGN | VT_UNSIGNED; |
||
3289 | next(); |
||
3290 | typespec_found = 1; |
||
3291 | break; |
||
3292 | |||
3293 | /* storage */ |
||
3294 | case TOK_EXTERN: |
||
3295 | t |= VT_EXTERN; |
||
3296 | next(); |
||
3297 | break; |
||
3298 | case TOK_STATIC: |
||
3299 | t |= VT_STATIC; |
||
3300 | next(); |
||
3301 | break; |
||
3302 | case TOK_TYPEDEF: |
||
3303 | t |= VT_TYPEDEF; |
||
3304 | next(); |
||
3305 | break; |
||
3306 | case TOK_INLINE1: |
||
3307 | case TOK_INLINE2: |
||
3308 | case TOK_INLINE3: |
||
3309 | t |= VT_INLINE; |
||
3310 | next(); |
||
3311 | break; |
||
3312 | |||
3313 | /* GNUC attribute */ |
||
3314 | case TOK_ATTRIBUTE1: |
||
3315 | case TOK_ATTRIBUTE2: |
||
3316 | parse_attribute(ad); |
||
3317 | if (ad->a.mode) { |
||
3318 | u = ad->a.mode -1; |
||
3319 | t = (t & ~VT_BTYPE) | u; |
||
3320 | } |
||
3321 | break; |
||
3322 | /* GNUC typeof */ |
||
3323 | case TOK_TYPEOF1: |
||
3324 | case TOK_TYPEOF2: |
||
3325 | case TOK_TYPEOF3: |
||
3326 | next(); |
||
3327 | parse_expr_type(&type1); |
||
3328 | /* remove all storage modifiers except typedef */ |
||
3329 | type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); |
||
3330 | goto basic_type2; |
||
3331 | default: |
||
3332 | if (typespec_found) |
||
3333 | goto the_end; |
||
3334 | s = sym_find(tok); |
||
3335 | if (!s || !(s->type.t & VT_TYPEDEF)) |
||
3336 | goto the_end; |
||
3337 | |||
3338 | type->t = ((s->type.t & ~VT_TYPEDEF) | |
||
3339 | (t & ~(VT_CONSTANT | VT_VOLATILE))); |
||
3340 | type->ref = s->type.ref; |
||
3341 | if (t & (VT_CONSTANT | VT_VOLATILE)) |
||
3342 | parse_btype_qualify(type, t & (VT_CONSTANT | VT_VOLATILE)); |
||
3343 | t = type->t; |
||
3344 | |||
3345 | if (s->r) { |
||
3346 | /* get attributes from typedef */ |
||
3347 | if (0 == ad->a.aligned) |
||
3348 | ad->a.aligned = s->a.aligned; |
||
3349 | if (0 == ad->a.func_call) |
||
3350 | ad->a.func_call = s->a.func_call; |
||
3351 | ad->a.packed |= s->a.packed; |
||
3352 | } |
||
3353 | next(); |
||
3354 | typespec_found = 1; |
||
3355 | break; |
||
3356 | } |
||
3357 | type_found = 1; |
||
3358 | } |
||
3359 | the_end: |
||
3360 | if (tcc_state->char_is_unsigned) { |
||
3361 | if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) |
||
3362 | t |= VT_UNSIGNED; |
||
3363 | } |
||
3364 | |||
3365 | /* long is never used as type */ |
||
3366 | if ((t & VT_BTYPE) == VT_LONG) |
||
3367 | #if (!defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64) || \ |
||
3368 | defined TCC_TARGET_PE || defined TCC_TARGET_MEOS |
||
3369 | t = (t & ~VT_BTYPE) | VT_INT; |
||
3370 | #else |
||
3371 | t = (t & ~VT_BTYPE) | VT_LLONG; |
||
3372 | #endif |
||
3373 | type->t = t; |
||
3374 | return type_found; |
||
3375 | } |
||
3376 | |||
3377 | /* convert a function parameter type (array to pointer and function to |
||
3378 | function pointer) */ |
||
3379 | static inline void convert_parameter_type(CType *pt) |
||
3380 | { |
||
3381 | /* remove const and volatile qualifiers (XXX: const could be used |
||
3382 | to indicate a const function parameter */ |
||
3383 | pt->t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
3384 | /* array must be transformed to pointer according to ANSI C */ |
||
3385 | pt->t &= ~VT_ARRAY; |
||
3386 | if ((pt->t & VT_BTYPE) == VT_FUNC) { |
||
3387 | mk_pointer(pt); |
||
3388 | } |
||
3389 | } |
||
3390 | |||
3391 | ST_FUNC void parse_asm_str(CString *astr) |
||
3392 | { |
||
3393 | skip('('); |
||
3394 | /* read the string */ |
||
3395 | if (tok != TOK_STR) |
||
3396 | expect("string constant"); |
||
3397 | cstr_new(astr); |
||
3398 | while (tok == TOK_STR) { |
||
3399 | /* XXX: add \0 handling too ? */ |
||
3400 | cstr_cat(astr, tokc.str.data, -1); |
||
3401 | next(); |
||
3402 | } |
||
3403 | cstr_ccat(astr, '\0'); |
||
3404 | } |
||
3405 | |||
3406 | /* Parse an asm label and return the token */ |
||
3407 | static int asm_label_instr(void) |
||
3408 | { |
||
3409 | int v; |
||
3410 | CString astr; |
||
3411 | |||
3412 | next(); |
||
3413 | parse_asm_str(&astr); |
||
3414 | skip(')'); |
||
3415 | #ifdef ASM_DEBUG |
||
3416 | printf("asm_alias: \"%s\"\n", (char *)astr.data); |
||
3417 | #endif |
||
3418 | v = tok_alloc(astr.data, astr.size - 1)->tok; |
||
3419 | cstr_free(&astr); |
||
3420 | return v; |
||
3421 | } |
||
3422 | |||
3423 | static void post_type(CType *type, AttributeDef *ad) |
||
3424 | { |
||
3425 | int n, l, t1, arg_size, align; |
||
3426 | Sym **plast, *s, *first; |
||
3427 | AttributeDef ad1; |
||
3428 | CType pt; |
||
3429 | |||
3430 | if (tok == '(') { |
||
3431 | /* function declaration */ |
||
3432 | next(); |
||
3433 | l = 0; |
||
3434 | first = NULL; |
||
3435 | plast = &first; |
||
3436 | arg_size = 0; |
||
3437 | if (tok != ')') { |
||
3438 | for(;;) { |
||
3439 | /* read param name and compute offset */ |
||
3440 | if (l != FUNC_OLD) { |
||
3441 | if (!parse_btype(&pt, &ad1)) { |
||
3442 | if (l) { |
||
3443 | tcc_error("invalid type"); |
||
3444 | } else { |
||
3445 | l = FUNC_OLD; |
||
3446 | goto old_proto; |
||
3447 | } |
||
3448 | } |
||
3449 | l = FUNC_NEW; |
||
3450 | if ((pt.t & VT_BTYPE) == VT_VOID && tok == ')') |
||
3451 | break; |
||
3452 | type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); |
||
3453 | if ((pt.t & VT_BTYPE) == VT_VOID) |
||
3454 | tcc_error("parameter declared as void"); |
||
3455 | arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; |
||
3456 | } else { |
||
3457 | old_proto: |
||
3458 | n = tok; |
||
3459 | if (n < TOK_UIDENT) |
||
3460 | expect("identifier"); |
||
3461 | pt.t = VT_INT; |
||
3462 | next(); |
||
3463 | } |
||
3464 | convert_parameter_type(&pt); |
||
3465 | s = sym_push(n | SYM_FIELD, &pt, 0, 0); |
||
3466 | *plast = s; |
||
3467 | plast = &s->next; |
||
3468 | if (tok == ')') |
||
3469 | break; |
||
3470 | skip(','); |
||
3471 | if (l == FUNC_NEW && tok == TOK_DOTS) { |
||
3472 | l = FUNC_ELLIPSIS; |
||
3473 | next(); |
||
3474 | break; |
||
3475 | } |
||
3476 | } |
||
3477 | } |
||
3478 | /* if no parameters, then old type prototype */ |
||
3479 | if (l == 0) |
||
3480 | l = FUNC_OLD; |
||
3481 | skip(')'); |
||
3482 | /* NOTE: const is ignored in returned type as it has a special |
||
3483 | meaning in gcc / C++ */ |
||
3484 | type->t &= ~VT_CONSTANT; |
||
3485 | /* some ancient pre-K&R C allows a function to return an array |
||
3486 | and the array brackets to be put after the arguments, such |
||
3487 | that "int c()[]" means something like "int[] c()" */ |
||
3488 | if (tok == '[') { |
||
3489 | next(); |
||
3490 | skip(']'); /* only handle simple "[]" */ |
||
3491 | type->t |= VT_PTR; |
||
3492 | } |
||
3493 | /* we push a anonymous symbol which will contain the function prototype */ |
||
3494 | ad->a.func_args = arg_size; |
||
3495 | s = sym_push(SYM_FIELD, type, 0, l); |
||
3496 | s->a = ad->a; |
||
3497 | s->next = first; |
||
3498 | type->t = VT_FUNC; |
||
3499 | type->ref = s; |
||
3500 | } else if (tok == '[') { |
||
3501 | /* array definition */ |
||
3502 | next(); |
||
3503 | if (tok == TOK_RESTRICT1) |
||
3504 | next(); |
||
3505 | n = -1; |
||
3506 | t1 = 0; |
||
3507 | if (tok != ']') { |
||
3508 | if (!local_stack || nocode_wanted) |
||
3509 | vpushi(expr_const()); |
||
3510 | else gexpr(); |
||
3511 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
3512 | n = vtop->c.i; |
||
3513 | if (n < 0) |
||
3514 | tcc_error("invalid array size"); |
||
3515 | } else { |
||
3516 | if (!is_integer_btype(vtop->type.t & VT_BTYPE)) |
||
3517 | tcc_error("size of variable length array should be an integer"); |
||
3518 | t1 = VT_VLA; |
||
3519 | } |
||
3520 | } |
||
3521 | skip(']'); |
||
3522 | /* parse next post type */ |
||
3523 | post_type(type, ad); |
||
3524 | if (type->t == VT_FUNC) |
||
3525 | tcc_error("declaration of an array of functions"); |
||
3526 | t1 |= type->t & VT_VLA; |
||
3527 | |||
3528 | if (t1 & VT_VLA) { |
||
3529 | loc -= type_size(&int_type, &align); |
||
3530 | loc &= -align; |
||
3531 | n = loc; |
||
3532 | |||
3533 | vla_runtime_type_size(type, &align); |
||
3534 | gen_op('*'); |
||
3535 | vset(&int_type, VT_LOCAL|VT_LVAL, n); |
||
3536 | vswap(); |
||
3537 | vstore(); |
||
3538 | } |
||
3539 | if (n != -1) |
||
3540 | vpop(); |
||
3541 | |||
3542 | /* we push an anonymous symbol which will contain the array |
||
3543 | element type */ |
||
3544 | s = sym_push(SYM_FIELD, type, 0, n); |
||
3545 | type->t = (t1 ? VT_VLA : VT_ARRAY) | VT_PTR; |
||
3546 | type->ref = s; |
||
3547 | } |
||
3548 | } |
||
3549 | |||
3550 | /* Parse a type declaration (except basic type), and return the type |
||
3551 | in 'type'. 'td' is a bitmask indicating which kind of type decl is |
||
3552 | expected. 'type' should contain the basic type. 'ad' is the |
||
3553 | attribute definition of the basic type. It can be modified by |
||
3554 | type_decl(). |
||
3555 | */ |
||
3556 | static void type_decl(CType *type, AttributeDef *ad, int *v, int td) |
||
3557 | { |
||
3558 | Sym *s; |
||
3559 | CType type1, *type2; |
||
3560 | int qualifiers, storage; |
||
3561 | |||
3562 | while (tok == '*') { |
||
3563 | qualifiers = 0; |
||
3564 | redo: |
||
3565 | next(); |
||
3566 | switch(tok) { |
||
3567 | case TOK_CONST1: |
||
3568 | case TOK_CONST2: |
||
3569 | case TOK_CONST3: |
||
3570 | qualifiers |= VT_CONSTANT; |
||
3571 | goto redo; |
||
3572 | case TOK_VOLATILE1: |
||
3573 | case TOK_VOLATILE2: |
||
3574 | case TOK_VOLATILE3: |
||
3575 | qualifiers |= VT_VOLATILE; |
||
3576 | goto redo; |
||
3577 | case TOK_RESTRICT1: |
||
3578 | case TOK_RESTRICT2: |
||
3579 | case TOK_RESTRICT3: |
||
3580 | goto redo; |
||
3581 | } |
||
3582 | mk_pointer(type); |
||
3583 | type->t |= qualifiers; |
||
3584 | } |
||
3585 | |||
3586 | /* XXX: clarify attribute handling */ |
||
3587 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
3588 | parse_attribute(ad); |
||
3589 | |||
3590 | /* recursive type */ |
||
3591 | /* XXX: incorrect if abstract type for functions (e.g. 'int ()') */ |
||
3592 | type1.t = 0; /* XXX: same as int */ |
||
3593 | if (tok == '(') { |
||
3594 | next(); |
||
3595 | /* XXX: this is not correct to modify 'ad' at this point, but |
||
3596 | the syntax is not clear */ |
||
3597 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
3598 | parse_attribute(ad); |
||
3599 | type_decl(&type1, ad, v, td); |
||
3600 | skip(')'); |
||
3601 | } else { |
||
3602 | /* type identifier */ |
||
3603 | if (tok >= TOK_IDENT && (td & TYPE_DIRECT)) { |
||
3604 | *v = tok; |
||
3605 | next(); |
||
3606 | } else { |
||
3607 | if (!(td & TYPE_ABSTRACT)) |
||
3608 | expect("identifier"); |
||
3609 | *v = 0; |
||
3610 | } |
||
3611 | } |
||
3612 | storage = type->t & VT_STORAGE; |
||
3613 | type->t &= ~VT_STORAGE; |
||
3614 | if (storage & VT_STATIC) { |
||
3615 | int saved_nocode_wanted = nocode_wanted; |
||
3616 | nocode_wanted = 1; |
||
3617 | post_type(type, ad); |
||
3618 | nocode_wanted = saved_nocode_wanted; |
||
3619 | } else |
||
3620 | post_type(type, ad); |
||
3621 | type->t |= storage; |
||
3622 | if (tok == TOK_ATTRIBUTE1 || tok == TOK_ATTRIBUTE2) |
||
3623 | parse_attribute(ad); |
||
3624 | |||
3625 | if (!type1.t) |
||
3626 | return; |
||
3627 | /* append type at the end of type1 */ |
||
3628 | type2 = &type1; |
||
3629 | for(;;) { |
||
3630 | s = type2->ref; |
||
3631 | type2 = &s->type; |
||
3632 | if (!type2->t) { |
||
3633 | *type2 = *type; |
||
3634 | break; |
||
3635 | } |
||
3636 | } |
||
3637 | *type = type1; |
||
3638 | } |
||
3639 | |||
3640 | /* compute the lvalue VT_LVAL_xxx needed to match type t. */ |
||
3641 | ST_FUNC int lvalue_type(int t) |
||
3642 | { |
||
3643 | int bt, r; |
||
3644 | r = VT_LVAL; |
||
3645 | bt = t & VT_BTYPE; |
||
3646 | if (bt == VT_BYTE || bt == VT_BOOL) |
||
3647 | r |= VT_LVAL_BYTE; |
||
3648 | else if (bt == VT_SHORT) |
||
3649 | r |= VT_LVAL_SHORT; |
||
3650 | else |
||
3651 | return r; |
||
3652 | if (t & VT_UNSIGNED) |
||
3653 | r |= VT_LVAL_UNSIGNED; |
||
3654 | return r; |
||
3655 | } |
||
3656 | |||
3657 | /* indirection with full error checking and bound check */ |
||
3658 | ST_FUNC void indir(void) |
||
3659 | { |
||
3660 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) { |
||
3661 | if ((vtop->type.t & VT_BTYPE) == VT_FUNC) |
||
3662 | return; |
||
3663 | expect("pointer"); |
||
3664 | } |
||
3665 | if ((vtop->r & VT_LVAL) && !nocode_wanted) |
||
3666 | gv(RC_INT); |
||
3667 | vtop->type = *pointed_type(&vtop->type); |
||
3668 | /* Arrays and functions are never lvalues */ |
||
3669 | if (!(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_VLA) |
||
3670 | && (vtop->type.t & VT_BTYPE) != VT_FUNC) { |
||
3671 | vtop->r |= lvalue_type(vtop->type.t); |
||
3672 | /* if bound checking, the referenced pointer must be checked */ |
||
3673 | #ifdef CONFIG_TCC_BCHECK |
||
3674 | if (tcc_state->do_bounds_check) |
||
3675 | vtop->r |= VT_MUSTBOUND; |
||
3676 | #endif |
||
3677 | } |
||
3678 | } |
||
3679 | |||
3680 | /* pass a parameter to a function and do type checking and casting */ |
||
3681 | static void gfunc_param_typed(Sym *func, Sym *arg) |
||
3682 | { |
||
3683 | int func_type; |
||
3684 | CType type; |
||
3685 | |||
3686 | func_type = func->c; |
||
3687 | if (func_type == FUNC_OLD || |
||
3688 | (func_type == FUNC_ELLIPSIS && arg == NULL)) { |
||
3689 | /* default casting : only need to convert float to double */ |
||
3690 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { |
||
3691 | type.t = VT_DOUBLE; |
||
3692 | gen_cast(&type); |
||
3693 | } else if (vtop->type.t & VT_BITFIELD) { |
||
3694 | type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); |
||
3695 | gen_cast(&type); |
||
3696 | } |
||
3697 | } else if (arg == NULL) { |
||
3698 | tcc_error("too many arguments to function"); |
||
3699 | } else { |
||
3700 | type = arg->type; |
||
3701 | type.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
3702 | gen_assign_cast(&type); |
||
3703 | } |
||
3704 | } |
||
3705 | |||
3706 | /* parse an expression of the form '(type)' or '(expr)' and return its |
||
3707 | type */ |
||
3708 | static void parse_expr_type(CType *type) |
||
3709 | { |
||
3710 | int n; |
||
3711 | AttributeDef ad; |
||
3712 | |||
3713 | skip('('); |
||
3714 | if (parse_btype(type, &ad)) { |
||
3715 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
3716 | } else { |
||
3717 | expr_type(type); |
||
3718 | } |
||
3719 | skip(')'); |
||
3720 | } |
||
3721 | |||
3722 | static void parse_type(CType *type) |
||
3723 | { |
||
3724 | AttributeDef ad; |
||
3725 | int n; |
||
3726 | |||
3727 | if (!parse_btype(type, &ad)) { |
||
3728 | expect("type"); |
||
3729 | } |
||
3730 | type_decl(type, &ad, &n, TYPE_ABSTRACT); |
||
3731 | } |
||
3732 | |||
3733 | static void vpush_tokc(int t) |
||
3734 | { |
||
3735 | CType type; |
||
3736 | type.t = t; |
||
3737 | type.ref = 0; |
||
3738 | vsetc(&type, VT_CONST, &tokc); |
||
3739 | } |
||
3740 | |||
3741 | ST_FUNC void unary(void) |
||
3742 | { |
||
3743 | int n, t, align, size, r, sizeof_caller; |
||
3744 | CType type; |
||
3745 | Sym *s; |
||
3746 | AttributeDef ad; |
||
3747 | static int in_sizeof = 0; |
||
3748 | |||
3749 | sizeof_caller = in_sizeof; |
||
3750 | in_sizeof = 0; |
||
3751 | /* XXX: GCC 2.95.3 does not generate a table although it should be |
||
3752 | better here */ |
||
3753 | tok_next: |
||
3754 | switch(tok) { |
||
3755 | case TOK_EXTENSION: |
||
3756 | next(); |
||
3757 | goto tok_next; |
||
3758 | case TOK_CINT: |
||
3759 | case TOK_CCHAR: |
||
3760 | case TOK_LCHAR: |
||
3761 | vpushi(tokc.i); |
||
3762 | next(); |
||
3763 | break; |
||
3764 | case TOK_CUINT: |
||
3765 | vpush_tokc(VT_INT | VT_UNSIGNED); |
||
3766 | next(); |
||
3767 | break; |
||
3768 | case TOK_CLLONG: |
||
3769 | vpush_tokc(VT_LLONG); |
||
3770 | next(); |
||
3771 | break; |
||
3772 | case TOK_CULLONG: |
||
3773 | vpush_tokc(VT_LLONG | VT_UNSIGNED); |
||
3774 | next(); |
||
3775 | break; |
||
3776 | case TOK_CFLOAT: |
||
3777 | vpush_tokc(VT_FLOAT); |
||
3778 | next(); |
||
3779 | break; |
||
3780 | case TOK_CDOUBLE: |
||
3781 | vpush_tokc(VT_DOUBLE); |
||
3782 | next(); |
||
3783 | break; |
||
3784 | case TOK_CLDOUBLE: |
||
3785 | vpush_tokc(VT_LDOUBLE); |
||
3786 | next(); |
||
3787 | break; |
||
3788 | case TOK___FUNCTION__: |
||
3789 | if (!gnu_ext) |
||
3790 | goto tok_identifier; |
||
3791 | /* fall thru */ |
||
3792 | case TOK___FUNC__: |
||
3793 | { |
||
3794 | void *ptr; |
||
3795 | int len; |
||
3796 | /* special function name identifier */ |
||
3797 | len = strlen(funcname) + 1; |
||
3798 | /* generate char[len] type */ |
||
3799 | type.t = VT_BYTE; |
||
3800 | mk_pointer(&type); |
||
3801 | type.t |= VT_ARRAY; |
||
3802 | type.ref->c = len; |
||
3803 | vpush_ref(&type, data_section, data_section->data_offset, len); |
||
3804 | ptr = section_ptr_add(data_section, len); |
||
3805 | memcpy(ptr, funcname, len); |
||
3806 | next(); |
||
3807 | } |
||
3808 | break; |
||
3809 | case TOK_LSTR: |
||
3810 | #ifdef TCC_TARGET_PE |
||
3811 | t = VT_SHORT | VT_UNSIGNED; |
||
3812 | #else |
||
3813 | t = VT_INT; |
||
3814 | #endif |
||
3815 | goto str_init; |
||
3816 | case TOK_STR: |
||
3817 | /* string parsing */ |
||
3818 | t = VT_BYTE; |
||
3819 | str_init: |
||
3820 | if (tcc_state->warn_write_strings) |
||
3821 | t |= VT_CONSTANT; |
||
3822 | type.t = t; |
||
3823 | mk_pointer(&type); |
||
3824 | type.t |= VT_ARRAY; |
||
3825 | memset(&ad, 0, sizeof(AttributeDef)); |
||
3826 | decl_initializer_alloc(&type, &ad, VT_CONST, 2, 0, 0); |
||
3827 | break; |
||
3828 | case '(': |
||
3829 | next(); |
||
3830 | /* cast ? */ |
||
3831 | if (parse_btype(&type, &ad)) { |
||
3832 | type_decl(&type, &ad, &n, TYPE_ABSTRACT); |
||
3833 | skip(')'); |
||
3834 | /* check ISOC99 compound literal */ |
||
3835 | if (tok == '{') { |
||
3836 | /* data is allocated locally by default */ |
||
3837 | if (global_expr) |
||
3838 | r = VT_CONST; |
||
3839 | else |
||
3840 | r = VT_LOCAL; |
||
3841 | /* all except arrays are lvalues */ |
||
3842 | if (!(type.t & VT_ARRAY)) |
||
3843 | r |= lvalue_type(type.t); |
||
3844 | memset(&ad, 0, sizeof(AttributeDef)); |
||
3845 | decl_initializer_alloc(&type, &ad, r, 1, 0, 0); |
||
3846 | } else { |
||
3847 | if (sizeof_caller) { |
||
3848 | vpush(&type); |
||
3849 | return; |
||
3850 | } |
||
3851 | unary(); |
||
3852 | gen_cast(&type); |
||
3853 | } |
||
3854 | } else if (tok == '{') { |
||
3855 | if (const_wanted) |
||
3856 | tcc_error("expected constant"); |
||
3857 | /* save all registers */ |
||
3858 | if (!nocode_wanted) |
||
3859 | save_regs(0); |
||
3860 | /* statement expression : we do not accept break/continue |
||
3861 | inside as GCC does */ |
||
3862 | block(NULL, NULL, NULL, NULL, 0, 1); |
||
3863 | skip(')'); |
||
3864 | } else { |
||
3865 | gexpr(); |
||
3866 | skip(')'); |
||
3867 | } |
||
3868 | break; |
||
3869 | case '*': |
||
3870 | next(); |
||
3871 | unary(); |
||
3872 | indir(); |
||
3873 | break; |
||
3874 | case '&': |
||
3875 | next(); |
||
3876 | unary(); |
||
3877 | /* functions names must be treated as function pointers, |
||
3878 | except for unary '&' and sizeof. Since we consider that |
||
3879 | functions are not lvalues, we only have to handle it |
||
3880 | there and in function calls. */ |
||
3881 | /* arrays can also be used although they are not lvalues */ |
||
3882 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC && |
||
3883 | !(vtop->type.t & VT_ARRAY) && !(vtop->type.t & VT_LLOCAL)) |
||
3884 | test_lvalue(); |
||
3885 | mk_pointer(&vtop->type); |
||
3886 | gaddrof(); |
||
3887 | break; |
||
3888 | case '!': |
||
3889 | next(); |
||
3890 | unary(); |
||
3891 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
3892 | CType boolean; |
||
3893 | boolean.t = VT_BOOL; |
||
3894 | gen_cast(&boolean); |
||
3895 | vtop->c.i = !vtop->c.i; |
||
3896 | } else if ((vtop->r & VT_VALMASK) == VT_CMP) |
||
3897 | vtop->c.i ^= 1; |
||
3898 | else { |
||
3899 | save_regs(1); |
||
3900 | vseti(VT_JMP, gvtst(1, 0)); |
||
3901 | } |
||
3902 | break; |
||
3903 | case '~': |
||
3904 | next(); |
||
3905 | unary(); |
||
3906 | vpushi(-1); |
||
3907 | gen_op('^'); |
||
3908 | break; |
||
3909 | case '+': |
||
3910 | next(); |
||
3911 | unary(); |
||
3912 | if ((vtop->type.t & VT_BTYPE) == VT_PTR) |
||
3913 | tcc_error("pointer not accepted for unary plus"); |
||
3914 | /* In order to force cast, we add zero, except for floating point |
||
3915 | where we really need an noop (otherwise -0.0 will be transformed |
||
3916 | into +0.0). */ |
||
3917 | if (!is_float(vtop->type.t)) { |
||
3918 | vpushi(0); |
||
3919 | gen_op('+'); |
||
3920 | } |
||
3921 | break; |
||
3922 | case TOK_SIZEOF: |
||
3923 | case TOK_ALIGNOF1: |
||
3924 | case TOK_ALIGNOF2: |
||
3925 | t = tok; |
||
3926 | next(); |
||
3927 | in_sizeof++; |
||
3928 | unary_type(&type); // Perform a in_sizeof = 0; |
||
3929 | size = type_size(&type, &align); |
||
3930 | if (t == TOK_SIZEOF) { |
||
3931 | if (!(type.t & VT_VLA)) { |
||
3932 | if (size < 0) |
||
3933 | tcc_error("sizeof applied to an incomplete type"); |
||
3934 | vpushs(size); |
||
3935 | } else { |
||
3936 | vla_runtime_type_size(&type, &align); |
||
3937 | } |
||
3938 | } else { |
||
3939 | vpushs(align); |
||
3940 | } |
||
3941 | vtop->type.t |= VT_UNSIGNED; |
||
3942 | break; |
||
3943 | |||
3944 | case TOK_builtin_expect: |
||
3945 | { |
||
3946 | /* __builtin_expect is a no-op for now */ |
||
3947 | int saved_nocode_wanted; |
||
3948 | next(); |
||
3949 | skip('('); |
||
3950 | expr_eq(); |
||
3951 | skip(','); |
||
3952 | saved_nocode_wanted = nocode_wanted; |
||
3953 | nocode_wanted = 1; |
||
3954 | expr_lor_const(); |
||
3955 | vpop(); |
||
3956 | nocode_wanted = saved_nocode_wanted; |
||
3957 | skip(')'); |
||
3958 | } |
||
3959 | break; |
||
3960 | case TOK_builtin_types_compatible_p: |
||
3961 | { |
||
3962 | CType type1, type2; |
||
3963 | next(); |
||
3964 | skip('('); |
||
3965 | parse_type(&type1); |
||
3966 | skip(','); |
||
3967 | parse_type(&type2); |
||
3968 | skip(')'); |
||
3969 | type1.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
3970 | type2.t &= ~(VT_CONSTANT | VT_VOLATILE); |
||
3971 | vpushi(is_compatible_types(&type1, &type2)); |
||
3972 | } |
||
3973 | break; |
||
3974 | case TOK_builtin_constant_p: |
||
3975 | { |
||
3976 | int saved_nocode_wanted, res; |
||
3977 | next(); |
||
3978 | skip('('); |
||
3979 | saved_nocode_wanted = nocode_wanted; |
||
3980 | nocode_wanted = 1; |
||
3981 | gexpr(); |
||
3982 | res = (vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST; |
||
3983 | vpop(); |
||
3984 | nocode_wanted = saved_nocode_wanted; |
||
3985 | skip(')'); |
||
3986 | vpushi(res); |
||
3987 | } |
||
3988 | break; |
||
3989 | case TOK_builtin_frame_address: |
||
3990 | case TOK_builtin_return_address: |
||
3991 | { |
||
3992 | int tok1 = tok; |
||
3993 | int level; |
||
3994 | CType type; |
||
3995 | next(); |
||
3996 | skip('('); |
||
3997 | if (tok != TOK_CINT) { |
||
3998 | tcc_error("%s only takes positive integers", |
||
3999 | tok1 == TOK_builtin_return_address ? |
||
4000 | "__builtin_return_address" : |
||
4001 | "__builtin_frame_address"); |
||
4002 | } |
||
4003 | level = (uint32_t)tokc.i; |
||
4004 | next(); |
||
4005 | skip(')'); |
||
4006 | type.t = VT_VOID; |
||
4007 | mk_pointer(&type); |
||
4008 | vset(&type, VT_LOCAL, 0); /* local frame */ |
||
4009 | while (level--) { |
||
4010 | mk_pointer(&vtop->type); |
||
4011 | indir(); /* -> parent frame */ |
||
4012 | } |
||
4013 | if (tok1 == TOK_builtin_return_address) { |
||
4014 | // assume return address is just above frame pointer on stack |
||
4015 | vpushi(PTR_SIZE); |
||
4016 | gen_op('+'); |
||
4017 | mk_pointer(&vtop->type); |
||
4018 | indir(); |
||
4019 | } |
||
4020 | } |
||
4021 | break; |
||
4022 | #ifdef TCC_TARGET_X86_64 |
||
4023 | #ifdef TCC_TARGET_PE |
||
4024 | case TOK_builtin_va_start: |
||
4025 | { |
||
4026 | next(); |
||
4027 | skip('('); |
||
4028 | expr_eq(); |
||
4029 | skip(','); |
||
4030 | expr_eq(); |
||
4031 | skip(')'); |
||
4032 | if ((vtop->r & VT_VALMASK) != VT_LOCAL) |
||
4033 | tcc_error("__builtin_va_start expects a local variable"); |
||
4034 | vtop->r &= ~(VT_LVAL | VT_REF); |
||
4035 | vtop->type = char_pointer_type; |
||
4036 | vstore(); |
||
4037 | } |
||
4038 | break; |
||
4039 | #else |
||
4040 | case TOK_builtin_va_arg_types: |
||
4041 | { |
||
4042 | CType type; |
||
4043 | next(); |
||
4044 | skip('('); |
||
4045 | parse_type(&type); |
||
4046 | skip(')'); |
||
4047 | vpushi(classify_x86_64_va_arg(&type)); |
||
4048 | } |
||
4049 | break; |
||
4050 | #endif |
||
4051 | #endif |
||
4052 | |||
4053 | #ifdef TCC_TARGET_ARM64 |
||
4054 | case TOK___va_start: { |
||
4055 | if (nocode_wanted) |
||
4056 | tcc_error("statement in global scope"); |
||
4057 | next(); |
||
4058 | skip('('); |
||
4059 | expr_eq(); |
||
4060 | skip(','); |
||
4061 | expr_eq(); |
||
4062 | skip(')'); |
||
4063 | //xx check types |
||
4064 | gen_va_start(); |
||
4065 | vpushi(0); |
||
4066 | vtop->type.t = VT_VOID; |
||
4067 | break; |
||
4068 | } |
||
4069 | case TOK___va_arg: { |
||
4070 | CType type; |
||
4071 | if (nocode_wanted) |
||
4072 | tcc_error("statement in global scope"); |
||
4073 | next(); |
||
4074 | skip('('); |
||
4075 | expr_eq(); |
||
4076 | skip(','); |
||
4077 | parse_type(&type); |
||
4078 | skip(')'); |
||
4079 | //xx check types |
||
4080 | gen_va_arg(&type); |
||
4081 | vtop->type = type; |
||
4082 | break; |
||
4083 | } |
||
4084 | case TOK___arm64_clear_cache: { |
||
4085 | next(); |
||
4086 | skip('('); |
||
4087 | expr_eq(); |
||
4088 | skip(','); |
||
4089 | expr_eq(); |
||
4090 | skip(')'); |
||
4091 | gen_clear_cache(); |
||
4092 | vpushi(0); |
||
4093 | vtop->type.t = VT_VOID; |
||
4094 | break; |
||
4095 | } |
||
4096 | #endif |
||
4097 | /* pre operations */ |
||
4098 | case TOK_INC: |
||
4099 | case TOK_DEC: |
||
4100 | t = tok; |
||
4101 | next(); |
||
4102 | unary(); |
||
4103 | inc(0, t); |
||
4104 | break; |
||
4105 | case '-': |
||
4106 | next(); |
||
4107 | unary(); |
||
4108 | t = vtop->type.t & VT_BTYPE; |
||
4109 | if (is_float(t)) { |
||
4110 | /* In IEEE negate(x) isn't subtract(0,x), but rather |
||
4111 | subtract(-0, x). */ |
||
4112 | vpush(&vtop->type); |
||
4113 | if (t == VT_FLOAT) |
||
4114 | vtop->c.f = -0.0f; |
||
4115 | else if (t == VT_DOUBLE) |
||
4116 | vtop->c.d = -0.0; |
||
4117 | else |
||
4118 | vtop->c.ld = -0.0; |
||
4119 | } else |
||
4120 | vpushi(0); |
||
4121 | vswap(); |
||
4122 | gen_op('-'); |
||
4123 | break; |
||
4124 | case TOK_LAND: |
||
4125 | if (!gnu_ext) |
||
4126 | goto tok_identifier; |
||
4127 | next(); |
||
4128 | /* allow to take the address of a label */ |
||
4129 | if (tok < TOK_UIDENT) |
||
4130 | expect("label identifier"); |
||
4131 | s = label_find(tok); |
||
4132 | if (!s) { |
||
4133 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
4134 | } else { |
||
4135 | if (s->r == LABEL_DECLARED) |
||
4136 | s->r = LABEL_FORWARD; |
||
4137 | } |
||
4138 | if (!s->type.t) { |
||
4139 | s->type.t = VT_VOID; |
||
4140 | mk_pointer(&s->type); |
||
4141 | s->type.t |= VT_STATIC; |
||
4142 | } |
||
4143 | vpushsym(&s->type, s); |
||
4144 | next(); |
||
4145 | break; |
||
4146 | |||
4147 | // special qnan , snan and infinity values |
||
4148 | case TOK___NAN__: |
||
4149 | vpush64(VT_DOUBLE, 0x7ff8000000000000ULL); |
||
4150 | next(); |
||
4151 | break; |
||
4152 | case TOK___SNAN__: |
||
4153 | vpush64(VT_DOUBLE, 0x7ff0000000000001ULL); |
||
4154 | next(); |
||
4155 | break; |
||
4156 | case TOK___INF__: |
||
4157 | vpush64(VT_DOUBLE, 0x7ff0000000000000ULL); |
||
4158 | next(); |
||
4159 | break; |
||
4160 | |||
4161 | default: |
||
4162 | tok_identifier: |
||
4163 | t = tok; |
||
4164 | next(); |
||
4165 | if (t < TOK_UIDENT) |
||
4166 | expect("identifier"); |
||
4167 | s = sym_find(t); |
||
4168 | if (!s) { |
||
4169 | const char *name = get_tok_str(t, NULL); |
||
4170 | if (tok != '(') |
||
4171 | tcc_error("'%s' undeclared", name); |
||
4172 | /* for simple function calls, we tolerate undeclared |
||
4173 | external reference to int() function */ |
||
4174 | if (tcc_state->warn_implicit_function_declaration |
||
4175 | #ifdef TCC_TARGET_PE |
||
4176 | /* people must be warned about using undeclared WINAPI functions |
||
4177 | (which usually start with uppercase letter) */ |
||
4178 | || (name[0] >= 'A' && name[0] <= 'Z') |
||
4179 | #endif |
||
4180 | ) |
||
4181 | tcc_warning("implicit declaration of function '%s'", name); |
||
4182 | s = external_global_sym(t, &func_old_type, 0); |
||
4183 | } |
||
4184 | if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == |
||
4185 | (VT_STATIC | VT_INLINE | VT_FUNC)) { |
||
4186 | /* if referencing an inline function, then we generate a |
||
4187 | symbol to it if not already done. It will have the |
||
4188 | effect to generate code for it at the end of the |
||
4189 | compilation unit. Inline function as always |
||
4190 | generated in the text section. */ |
||
4191 | if (!s->c) |
||
4192 | put_extern_sym(s, text_section, 0, 0); |
||
4193 | r = VT_SYM | VT_CONST; |
||
4194 | } else { |
||
4195 | r = s->r; |
||
4196 | } |
||
4197 | vset(&s->type, r, s->c); |
||
4198 | /* if forward reference, we must point to s */ |
||
4199 | if (vtop->r & VT_SYM) { |
||
4200 | vtop->sym = s; |
||
4201 | vtop->c.i = 0; |
||
4202 | } |
||
4203 | break; |
||
4204 | } |
||
4205 | |||
4206 | /* post operations */ |
||
4207 | while (1) { |
||
4208 | if (tok == TOK_INC || tok == TOK_DEC) { |
||
4209 | inc(1, tok); |
||
4210 | next(); |
||
4211 | } else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) { |
||
4212 | int qualifiers; |
||
4213 | /* field */ |
||
4214 | if (tok == TOK_ARROW) |
||
4215 | indir(); |
||
4216 | qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); |
||
4217 | test_lvalue(); |
||
4218 | gaddrof(); |
||
4219 | /* expect pointer on structure */ |
||
4220 | if ((vtop->type.t & VT_BTYPE) != VT_STRUCT) |
||
4221 | expect("struct or union"); |
||
4222 | if (tok == TOK_CDOUBLE) |
||
4223 | expect("field name"); |
||
4224 | next(); |
||
4225 | if (tok == TOK_CINT || tok == TOK_CUINT) |
||
4226 | expect("field name"); |
||
4227 | s = vtop->type.ref; |
||
4228 | /* find field */ |
||
4229 | tok |= SYM_FIELD; |
||
4230 | while ((s = s->next) != NULL) { |
||
4231 | if (s->v == tok) |
||
4232 | break; |
||
4233 | } |
||
4234 | if (!s) |
||
4235 | tcc_error("field not found: %s", get_tok_str(tok & ~SYM_FIELD, &tokc)); |
||
4236 | /* add field offset to pointer */ |
||
4237 | vtop->type = char_pointer_type; /* change type to 'char *' */ |
||
4238 | vpushi(s->c); |
||
4239 | gen_op('+'); |
||
4240 | /* change type to field type, and set to lvalue */ |
||
4241 | vtop->type = s->type; |
||
4242 | vtop->type.t |= qualifiers; |
||
4243 | /* an array is never an lvalue */ |
||
4244 | if (!(vtop->type.t & VT_ARRAY)) { |
||
4245 | vtop->r |= lvalue_type(vtop->type.t); |
||
4246 | #ifdef CONFIG_TCC_BCHECK |
||
4247 | /* if bound checking, the referenced pointer must be checked */ |
||
4248 | if (tcc_state->do_bounds_check) |
||
4249 | vtop->r |= VT_MUSTBOUND; |
||
4250 | #endif |
||
4251 | } |
||
4252 | next(); |
||
4253 | } else if (tok == '[') { |
||
4254 | next(); |
||
4255 | gexpr(); |
||
4256 | gen_op('+'); |
||
4257 | indir(); |
||
4258 | skip(']'); |
||
4259 | } else if (tok == '(') { |
||
4260 | SValue ret; |
||
4261 | Sym *sa; |
||
4262 | int nb_args, ret_nregs, ret_align, regsize, variadic; |
||
4263 | |||
4264 | /* function call */ |
||
4265 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { |
||
4266 | /* pointer test (no array accepted) */ |
||
4267 | if ((vtop->type.t & (VT_BTYPE | VT_ARRAY)) == VT_PTR) { |
||
4268 | vtop->type = *pointed_type(&vtop->type); |
||
4269 | if ((vtop->type.t & VT_BTYPE) != VT_FUNC) |
||
4270 | goto error_func; |
||
4271 | } else { |
||
4272 | error_func: |
||
4273 | expect("function pointer"); |
||
4274 | } |
||
4275 | } else { |
||
4276 | vtop->r &= ~VT_LVAL; /* no lvalue */ |
||
4277 | } |
||
4278 | /* get return type */ |
||
4279 | s = vtop->type.ref; |
||
4280 | next(); |
||
4281 | sa = s->next; /* first parameter */ |
||
4282 | nb_args = 0; |
||
4283 | ret.r2 = VT_CONST; |
||
4284 | /* compute first implicit argument if a structure is returned */ |
||
4285 | if ((s->type.t & VT_BTYPE) == VT_STRUCT) { |
||
4286 | variadic = (s->c == FUNC_ELLIPSIS); |
||
4287 | ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, |
||
4288 | &ret_align, ®size); |
||
4289 | if (!ret_nregs) { |
||
4290 | /* get some space for the returned structure */ |
||
4291 | size = type_size(&s->type, &align); |
||
4292 | #ifdef TCC_TARGET_ARM64 |
||
4293 | /* On arm64, a small struct is return in registers. |
||
4294 | It is much easier to write it to memory if we know |
||
4295 | that we are allowed to write some extra bytes, so |
||
4296 | round the allocated space up to a power of 2: */ |
||
4297 | if (size < 16) |
||
4298 | while (size & (size - 1)) |
||
4299 | size = (size | (size - 1)) + 1; |
||
4300 | #endif |
||
4301 | loc = (loc - size) & -align; |
||
4302 | ret.type = s->type; |
||
4303 | ret.r = VT_LOCAL | VT_LVAL; |
||
4304 | /* pass it as 'int' to avoid structure arg passing |
||
4305 | problems */ |
||
4306 | vseti(VT_LOCAL, loc); |
||
4307 | ret.c = vtop->c; |
||
4308 | nb_args++; |
||
4309 | } |
||
4310 | } else { |
||
4311 | ret_nregs = 1; |
||
4312 | ret.type = s->type; |
||
4313 | } |
||
4314 | |||
4315 | if (ret_nregs) { |
||
4316 | /* return in register */ |
||
4317 | if (is_float(ret.type.t)) { |
||
4318 | ret.r = reg_fret(ret.type.t); |
||
4319 | #ifdef TCC_TARGET_X86_64 |
||
4320 | if ((ret.type.t & VT_BTYPE) == VT_QFLOAT) |
||
4321 | ret.r2 = REG_QRET; |
||
4322 | #endif |
||
4323 | } else { |
||
4324 | #ifndef TCC_TARGET_ARM64 |
||
4325 | #ifdef TCC_TARGET_X86_64 |
||
4326 | if ((ret.type.t & VT_BTYPE) == VT_QLONG) |
||
4327 | #else |
||
4328 | if ((ret.type.t & VT_BTYPE) == VT_LLONG) |
||
4329 | #endif |
||
4330 | ret.r2 = REG_LRET; |
||
4331 | #endif |
||
4332 | ret.r = REG_IRET; |
||
4333 | } |
||
4334 | ret.c.i = 0; |
||
4335 | } |
||
4336 | if (tok != ')') { |
||
4337 | for(;;) { |
||
4338 | expr_eq(); |
||
4339 | gfunc_param_typed(s, sa); |
||
4340 | nb_args++; |
||
4341 | if (sa) |
||
4342 | sa = sa->next; |
||
4343 | if (tok == ')') |
||
4344 | break; |
||
4345 | skip(','); |
||
4346 | } |
||
4347 | } |
||
4348 | if (sa) |
||
4349 | tcc_error("too few arguments to function"); |
||
4350 | skip(')'); |
||
4351 | if (!nocode_wanted) { |
||
4352 | gfunc_call(nb_args); |
||
4353 | } else { |
||
4354 | vtop -= (nb_args + 1); |
||
4355 | } |
||
4356 | |||
4357 | /* return value */ |
||
4358 | for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { |
||
4359 | vsetc(&ret.type, r, &ret.c); |
||
4360 | vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */ |
||
4361 | } |
||
4362 | |||
4363 | /* handle packed struct return */ |
||
4364 | if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { |
||
4365 | int addr, offset; |
||
4366 | |||
4367 | size = type_size(&s->type, &align); |
||
4368 | /* We're writing whole regs often, make sure there's enough |
||
4369 | space. Assume register size is power of 2. */ |
||
4370 | if (regsize > align) |
||
4371 | align = regsize; |
||
4372 | loc = (loc - size) & -align; |
||
4373 | addr = loc; |
||
4374 | offset = 0; |
||
4375 | for (;;) { |
||
4376 | vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); |
||
4377 | vswap(); |
||
4378 | vstore(); |
||
4379 | vtop--; |
||
4380 | if (--ret_nregs == 0) |
||
4381 | break; |
||
4382 | offset += regsize; |
||
4383 | } |
||
4384 | vset(&s->type, VT_LOCAL | VT_LVAL, addr); |
||
4385 | } |
||
4386 | } else { |
||
4387 | break; |
||
4388 | } |
||
4389 | } |
||
4390 | } |
||
4391 | |||
4392 | ST_FUNC void expr_prod(void) |
||
4393 | { |
||
4394 | int t; |
||
4395 | |||
4396 | unary(); |
||
4397 | while (tok == '*' || tok == '/' || tok == '%') { |
||
4398 | t = tok; |
||
4399 | next(); |
||
4400 | unary(); |
||
4401 | gen_op(t); |
||
4402 | } |
||
4403 | } |
||
4404 | |||
4405 | ST_FUNC void expr_sum(void) |
||
4406 | { |
||
4407 | int t; |
||
4408 | |||
4409 | expr_prod(); |
||
4410 | while (tok == '+' || tok == '-') { |
||
4411 | t = tok; |
||
4412 | next(); |
||
4413 | expr_prod(); |
||
4414 | gen_op(t); |
||
4415 | } |
||
4416 | } |
||
4417 | |||
4418 | static void expr_shift(void) |
||
4419 | { |
||
4420 | int t; |
||
4421 | |||
4422 | expr_sum(); |
||
4423 | while (tok == TOK_SHL || tok == TOK_SAR) { |
||
4424 | t = tok; |
||
4425 | next(); |
||
4426 | expr_sum(); |
||
4427 | gen_op(t); |
||
4428 | } |
||
4429 | } |
||
4430 | |||
4431 | static void expr_cmp(void) |
||
4432 | { |
||
4433 | int t; |
||
4434 | |||
4435 | expr_shift(); |
||
4436 | while ((tok >= TOK_ULE && tok <= TOK_GT) || |
||
4437 | tok == TOK_ULT || tok == TOK_UGE) { |
||
4438 | t = tok; |
||
4439 | next(); |
||
4440 | expr_shift(); |
||
4441 | gen_op(t); |
||
4442 | } |
||
4443 | } |
||
4444 | |||
4445 | static void expr_cmpeq(void) |
||
4446 | { |
||
4447 | int t; |
||
4448 | |||
4449 | expr_cmp(); |
||
4450 | while (tok == TOK_EQ || tok == TOK_NE) { |
||
4451 | t = tok; |
||
4452 | next(); |
||
4453 | expr_cmp(); |
||
4454 | gen_op(t); |
||
4455 | } |
||
4456 | } |
||
4457 | |||
4458 | static void expr_and(void) |
||
4459 | { |
||
4460 | expr_cmpeq(); |
||
4461 | while (tok == '&') { |
||
4462 | next(); |
||
4463 | expr_cmpeq(); |
||
4464 | gen_op('&'); |
||
4465 | } |
||
4466 | } |
||
4467 | |||
4468 | static void expr_xor(void) |
||
4469 | { |
||
4470 | expr_and(); |
||
4471 | while (tok == '^') { |
||
4472 | next(); |
||
4473 | expr_and(); |
||
4474 | gen_op('^'); |
||
4475 | } |
||
4476 | } |
||
4477 | |||
4478 | static void expr_or(void) |
||
4479 | { |
||
4480 | expr_xor(); |
||
4481 | while (tok == '|') { |
||
4482 | next(); |
||
4483 | expr_xor(); |
||
4484 | gen_op('|'); |
||
4485 | } |
||
4486 | } |
||
4487 | |||
4488 | /* XXX: fix this mess */ |
||
4489 | static void expr_land_const(void) |
||
4490 | { |
||
4491 | expr_or(); |
||
4492 | while (tok == TOK_LAND) { |
||
4493 | next(); |
||
4494 | expr_or(); |
||
4495 | gen_op(TOK_LAND); |
||
4496 | } |
||
4497 | } |
||
4498 | static void expr_lor_const(void) |
||
4499 | { |
||
4500 | expr_land_const(); |
||
4501 | while (tok == TOK_LOR) { |
||
4502 | next(); |
||
4503 | expr_land_const(); |
||
4504 | gen_op(TOK_LOR); |
||
4505 | } |
||
4506 | } |
||
4507 | |||
4508 | static void expr_land(void) |
||
4509 | { |
||
4510 | expr_or(); |
||
4511 | if (tok == TOK_LAND) { |
||
4512 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
4513 | CType ctb, cti; |
||
4514 | ctb.t = VT_BOOL; |
||
4515 | cti.t = VT_INT; |
||
4516 | next(); |
||
4517 | gen_cast(&ctb); |
||
4518 | if (vtop->c.i) { |
||
4519 | vpop(); |
||
4520 | expr_land(); |
||
4521 | gen_cast(&ctb); |
||
4522 | } else { |
||
4523 | int saved_nocode_wanted = nocode_wanted; |
||
4524 | nocode_wanted = 1; |
||
4525 | expr_land(); |
||
4526 | vpop(); |
||
4527 | nocode_wanted = saved_nocode_wanted; |
||
4528 | } |
||
4529 | gen_cast(&cti); |
||
4530 | } else { |
||
4531 | int t = 0; |
||
4532 | save_regs(1); |
||
4533 | for(;;) { |
||
4534 | t = gvtst(1, t); |
||
4535 | if (tok != TOK_LAND) { |
||
4536 | vseti(VT_JMPI, t); |
||
4537 | break; |
||
4538 | } |
||
4539 | next(); |
||
4540 | expr_or(); |
||
4541 | } |
||
4542 | } |
||
4543 | } |
||
4544 | } |
||
4545 | |||
4546 | static void expr_lor(void) |
||
4547 | { |
||
4548 | expr_land(); |
||
4549 | if (tok == TOK_LOR) { |
||
4550 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
4551 | CType ctb, cti; |
||
4552 | ctb.t = VT_BOOL; |
||
4553 | cti.t = VT_INT; |
||
4554 | next(); |
||
4555 | gen_cast(&ctb); |
||
4556 | if (vtop->c.i) { |
||
4557 | int saved_nocode_wanted = nocode_wanted; |
||
4558 | nocode_wanted = 1; |
||
4559 | expr_lor(); |
||
4560 | vpop(); |
||
4561 | nocode_wanted = saved_nocode_wanted; |
||
4562 | } else { |
||
4563 | vpop(); |
||
4564 | expr_lor(); |
||
4565 | gen_cast(&ctb); |
||
4566 | } |
||
4567 | gen_cast(&cti); |
||
4568 | } else { |
||
4569 | int t = 0; |
||
4570 | save_regs(1); |
||
4571 | for(;;) { |
||
4572 | t = gvtst(0, t); |
||
4573 | if (tok != TOK_LOR) { |
||
4574 | vseti(VT_JMP, t); |
||
4575 | break; |
||
4576 | } |
||
4577 | next(); |
||
4578 | expr_land(); |
||
4579 | } |
||
4580 | } |
||
4581 | } |
||
4582 | } |
||
4583 | |||
4584 | static void expr_cond(void) |
||
4585 | { |
||
4586 | int tt, u, r1, r2, rc, t1, t2, bt1, bt2, islv; |
||
4587 | SValue sv; |
||
4588 | CType type, type1, type2; |
||
4589 | |||
4590 | expr_lor(); |
||
4591 | if (tok == '?') { |
||
4592 | next(); |
||
4593 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
||
4594 | int saved_nocode_wanted = nocode_wanted; |
||
4595 | CType boolean; |
||
4596 | int c; |
||
4597 | boolean.t = VT_BOOL; |
||
4598 | vdup(); |
||
4599 | gen_cast(&boolean); |
||
4600 | c = vtop->c.i; |
||
4601 | vpop(); |
||
4602 | if (c) { |
||
4603 | if (tok != ':' || !gnu_ext) { |
||
4604 | vpop(); |
||
4605 | gexpr(); |
||
4606 | } |
||
4607 | skip(':'); |
||
4608 | nocode_wanted = 1; |
||
4609 | expr_cond(); |
||
4610 | vpop(); |
||
4611 | nocode_wanted = saved_nocode_wanted; |
||
4612 | } else { |
||
4613 | vpop(); |
||
4614 | if (tok != ':' || !gnu_ext) { |
||
4615 | nocode_wanted = 1; |
||
4616 | gexpr(); |
||
4617 | vpop(); |
||
4618 | nocode_wanted = saved_nocode_wanted; |
||
4619 | } |
||
4620 | skip(':'); |
||
4621 | expr_cond(); |
||
4622 | } |
||
4623 | } |
||
4624 | else { |
||
4625 | if (vtop != vstack) { |
||
4626 | /* needed to avoid having different registers saved in |
||
4627 | each branch */ |
||
4628 | if (is_float(vtop->type.t)) { |
||
4629 | rc = RC_FLOAT; |
||
4630 | #ifdef TCC_TARGET_X86_64 |
||
4631 | if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) { |
||
4632 | rc = RC_ST0; |
||
4633 | } |
||
4634 | #endif |
||
4635 | } |
||
4636 | else |
||
4637 | rc = RC_INT; |
||
4638 | gv(rc); |
||
4639 | save_regs(1); |
||
4640 | } |
||
4641 | if (tok == ':' && gnu_ext) { |
||
4642 | gv_dup(); |
||
4643 | tt = gvtst(1, 0); |
||
4644 | } else { |
||
4645 | tt = gvtst(1, 0); |
||
4646 | gexpr(); |
||
4647 | } |
||
4648 | type1 = vtop->type; |
||
4649 | sv = *vtop; /* save value to handle it later */ |
||
4650 | vtop--; /* no vpop so that FP stack is not flushed */ |
||
4651 | skip(':'); |
||
4652 | u = gjmp(0); |
||
4653 | gsym(tt); |
||
4654 | expr_cond(); |
||
4655 | type2 = vtop->type; |
||
4656 | |||
4657 | t1 = type1.t; |
||
4658 | bt1 = t1 & VT_BTYPE; |
||
4659 | t2 = type2.t; |
||
4660 | bt2 = t2 & VT_BTYPE; |
||
4661 | /* cast operands to correct type according to ISOC rules */ |
||
4662 | if (is_float(bt1) || is_float(bt2)) { |
||
4663 | if (bt1 == VT_LDOUBLE || bt2 == VT_LDOUBLE) { |
||
4664 | type.t = VT_LDOUBLE; |
||
4665 | } else if (bt1 == VT_DOUBLE || bt2 == VT_DOUBLE) { |
||
4666 | type.t = VT_DOUBLE; |
||
4667 | } else { |
||
4668 | type.t = VT_FLOAT; |
||
4669 | } |
||
4670 | } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { |
||
4671 | /* cast to biggest op */ |
||
4672 | type.t = VT_LLONG; |
||
4673 | /* convert to unsigned if it does not fit in a long long */ |
||
4674 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) || |
||
4675 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED)) |
||
4676 | type.t |= VT_UNSIGNED; |
||
4677 | } else if (bt1 == VT_PTR || bt2 == VT_PTR) { |
||
4678 | /* If one is a null ptr constant the result type |
||
4679 | is the other. */ |
||
4680 | if (is_null_pointer (vtop)) |
||
4681 | type = type1; |
||
4682 | else if (is_null_pointer (&sv)) |
||
4683 | type = type2; |
||
4684 | /* XXX: test pointer compatibility, C99 has more elaborate |
||
4685 | rules here. */ |
||
4686 | else |
||
4687 | type = type1; |
||
4688 | } else if (bt1 == VT_FUNC || bt2 == VT_FUNC) { |
||
4689 | /* XXX: test function pointer compatibility */ |
||
4690 | type = bt1 == VT_FUNC ? type1 : type2; |
||
4691 | } else if (bt1 == VT_STRUCT || bt2 == VT_STRUCT) { |
||
4692 | /* XXX: test structure compatibility */ |
||
4693 | type = bt1 == VT_STRUCT ? type1 : type2; |
||
4694 | } else if (bt1 == VT_VOID || bt2 == VT_VOID) { |
||
4695 | /* NOTE: as an extension, we accept void on only one side */ |
||
4696 | type.t = VT_VOID; |
||
4697 | } else { |
||
4698 | /* integer operations */ |
||
4699 | type.t = VT_INT; |
||
4700 | /* convert to unsigned if it does not fit in an integer */ |
||
4701 | if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) || |
||
4702 | (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED)) |
||
4703 | type.t |= VT_UNSIGNED; |
||
4704 | } |
||
4705 | /* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so |
||
4706 | that `(expr ? a : b).mem` does not error with "lvalue expected" */ |
||
4707 | islv = (vtop->r & VT_LVAL) && (sv.r & VT_LVAL) && VT_STRUCT == (type.t & VT_BTYPE); |
||
4708 | |||
4709 | /* now we convert second operand */ |
||
4710 | gen_cast(&type); |
||
4711 | if (islv) { |
||
4712 | mk_pointer(&vtop->type); |
||
4713 | gaddrof(); |
||
4714 | } |
||
4715 | else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) |
||
4716 | gaddrof(); |
||
4717 | rc = RC_INT; |
||
4718 | if (is_float(type.t)) { |
||
4719 | rc = RC_FLOAT; |
||
4720 | #ifdef TCC_TARGET_X86_64 |
||
4721 | if ((type.t & VT_BTYPE) == VT_LDOUBLE) { |
||
4722 | rc = RC_ST0; |
||
4723 | } |
||
4724 | #endif |
||
4725 | } else if ((type.t & VT_BTYPE) == VT_LLONG) { |
||
4726 | /* for long longs, we use fixed registers to avoid having |
||
4727 | to handle a complicated move */ |
||
4728 | rc = RC_IRET; |
||
4729 | } |
||
4730 | |||
4731 | r2 = gv(rc); |
||
4732 | /* this is horrible, but we must also convert first |
||
4733 | operand */ |
||
4734 | tt = gjmp(0); |
||
4735 | gsym(u); |
||
4736 | /* put again first value and cast it */ |
||
4737 | *vtop = sv; |
||
4738 | gen_cast(&type); |
||
4739 | if (islv) { |
||
4740 | mk_pointer(&vtop->type); |
||
4741 | gaddrof(); |
||
4742 | } |
||
4743 | else if (VT_STRUCT == (vtop->type.t & VT_BTYPE)) |
||
4744 | gaddrof(); |
||
4745 | r1 = gv(rc); |
||
4746 | move_reg(r2, r1, type.t); |
||
4747 | vtop->r = r2; |
||
4748 | gsym(tt); |
||
4749 | if (islv) |
||
4750 | indir(); |
||
4751 | } |
||
4752 | } |
||
4753 | } |
||
4754 | |||
4755 | static void expr_eq(void) |
||
4756 | { |
||
4757 | int t; |
||
4758 | |||
4759 | expr_cond(); |
||
4760 | if (tok == '=' || |
||
4761 | (tok >= TOK_A_MOD && tok <= TOK_A_DIV) || |
||
4762 | tok == TOK_A_XOR || tok == TOK_A_OR || |
||
4763 | tok == TOK_A_SHL || tok == TOK_A_SAR) { |
||
4764 | test_lvalue(); |
||
4765 | t = tok; |
||
4766 | next(); |
||
4767 | if (t == '=') { |
||
4768 | expr_eq(); |
||
4769 | } else { |
||
4770 | vdup(); |
||
4771 | expr_eq(); |
||
4772 | gen_op(t & 0x7f); |
||
4773 | } |
||
4774 | vstore(); |
||
4775 | } |
||
4776 | } |
||
4777 | |||
4778 | ST_FUNC void gexpr(void) |
||
4779 | { |
||
4780 | while (1) { |
||
4781 | expr_eq(); |
||
4782 | if (tok != ',') |
||
4783 | break; |
||
4784 | vpop(); |
||
4785 | next(); |
||
4786 | } |
||
4787 | } |
||
4788 | |||
4789 | /* parse an expression and return its type without any side effect. */ |
||
4790 | static void expr_type(CType *type) |
||
4791 | { |
||
4792 | int saved_nocode_wanted; |
||
4793 | |||
4794 | saved_nocode_wanted = nocode_wanted; |
||
4795 | nocode_wanted = 1; |
||
4796 | gexpr(); |
||
4797 | *type = vtop->type; |
||
4798 | vpop(); |
||
4799 | nocode_wanted = saved_nocode_wanted; |
||
4800 | } |
||
4801 | |||
4802 | /* parse a unary expression and return its type without any side |
||
4803 | effect. */ |
||
4804 | static void unary_type(CType *type) |
||
4805 | { |
||
4806 | int a; |
||
4807 | |||
4808 | a = nocode_wanted; |
||
4809 | nocode_wanted = 1; |
||
4810 | unary(); |
||
4811 | *type = vtop->type; |
||
4812 | vpop(); |
||
4813 | nocode_wanted = a; |
||
4814 | } |
||
4815 | |||
4816 | /* parse a constant expression and return value in vtop. */ |
||
4817 | static void expr_const1(void) |
||
4818 | { |
||
4819 | int a; |
||
4820 | a = const_wanted; |
||
4821 | const_wanted = 1; |
||
4822 | expr_cond(); |
||
4823 | const_wanted = a; |
||
4824 | } |
||
4825 | |||
4826 | /* parse an integer constant and return its value. */ |
||
4827 | ST_FUNC int expr_const(void) |
||
4828 | { |
||
4829 | int c; |
||
4830 | expr_const1(); |
||
4831 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
||
4832 | expect("constant expression"); |
||
4833 | c = vtop->c.i; |
||
4834 | vpop(); |
||
4835 | return c; |
||
4836 | } |
||
4837 | |||
4838 | /* return the label token if current token is a label, otherwise |
||
4839 | return zero */ |
||
4840 | static int is_label(void) |
||
4841 | { |
||
4842 | int last_tok; |
||
4843 | |||
4844 | /* fast test first */ |
||
4845 | if (tok < TOK_UIDENT) |
||
4846 | return 0; |
||
4847 | /* no need to save tokc because tok is an identifier */ |
||
4848 | last_tok = tok; |
||
4849 | next(); |
||
4850 | if (tok == ':') { |
||
4851 | next(); |
||
4852 | return last_tok; |
||
4853 | } else { |
||
4854 | unget_tok(last_tok); |
||
4855 | return 0; |
||
4856 | } |
||
4857 | } |
||
4858 | |||
4859 | static void label_or_decl(int l) |
||
4860 | { |
||
4861 | int last_tok; |
||
4862 | |||
4863 | /* fast test first */ |
||
4864 | if (tok >= TOK_UIDENT) |
||
4865 | { |
||
4866 | /* no need to save tokc because tok is an identifier */ |
||
4867 | last_tok = tok; |
||
4868 | next(); |
||
4869 | if (tok == ':') { |
||
4870 | unget_tok(last_tok); |
||
4871 | return; |
||
4872 | } |
||
4873 | unget_tok(last_tok); |
||
4874 | } |
||
4875 | decl(l); |
||
4876 | } |
||
4877 | |||
4878 | static void block(int *bsym, int *csym, int *case_sym, int *def_sym, |
||
4879 | int case_reg, int is_expr) |
||
4880 | { |
||
4881 | int a, b, c, d; |
||
4882 | Sym *s, *frame_bottom; |
||
4883 | |||
4884 | /* generate line number info */ |
||
4885 | if (tcc_state->do_debug && |
||
4886 | (last_line_num != file->line_num || last_ind != ind)) { |
||
4887 | put_stabn(N_SLINE, 0, file->line_num, ind - func_ind); |
||
4888 | last_ind = ind; |
||
4889 | last_line_num = file->line_num; |
||
4890 | } |
||
4891 | |||
4892 | if (is_expr) { |
||
4893 | /* default return value is (void) */ |
||
4894 | vpushi(0); |
||
4895 | vtop->type.t = VT_VOID; |
||
4896 | } |
||
4897 | |||
4898 | if (tok == TOK_IF) { |
||
4899 | /* if test */ |
||
4900 | next(); |
||
4901 | skip('('); |
||
4902 | gexpr(); |
||
4903 | skip(')'); |
||
4904 | a = gvtst(1, 0); |
||
4905 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
4906 | c = tok; |
||
4907 | if (c == TOK_ELSE) { |
||
4908 | next(); |
||
4909 | d = gjmp(0); |
||
4910 | gsym(a); |
||
4911 | block(bsym, csym, case_sym, def_sym, case_reg, 0); |
||
4912 | gsym(d); /* patch else jmp */ |
||
4913 | } else |
||
4914 | gsym(a); |
||
4915 | } else if (tok == TOK_WHILE) { |
||
4916 | next(); |
||
4917 | d = ind; |
||
4918 | vla_sp_restore(); |
||
4919 | skip('('); |
||
4920 | gexpr(); |
||
4921 | skip(')'); |
||
4922 | a = gvtst(1, 0); |
||
4923 | b = 0; |
||
4924 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
4925 | if(!nocode_wanted) |
||
4926 | gjmp_addr(d); |
||
4927 | gsym(a); |
||
4928 | gsym_addr(b, d); |
||
4929 | } else if (tok == '{') { |
||
4930 | Sym *llabel; |
||
4931 | int block_vla_sp_loc = vla_sp_loc, saved_vlas_in_scope = vlas_in_scope; |
||
4932 | |||
4933 | next(); |
||
4934 | /* record local declaration stack position */ |
||
4935 | s = local_stack; |
||
4936 | frame_bottom = sym_push2(&local_stack, SYM_FIELD, 0, 0); |
||
4937 | frame_bottom->next = scope_stack_bottom; |
||
4938 | scope_stack_bottom = frame_bottom; |
||
4939 | llabel = local_label_stack; |
||
4940 | |||
4941 | /* handle local labels declarations */ |
||
4942 | if (tok == TOK_LABEL) { |
||
4943 | next(); |
||
4944 | for(;;) { |
||
4945 | if (tok < TOK_UIDENT) |
||
4946 | expect("label identifier"); |
||
4947 | label_push(&local_label_stack, tok, LABEL_DECLARED); |
||
4948 | next(); |
||
4949 | if (tok == ',') { |
||
4950 | next(); |
||
4951 | } else { |
||
4952 | skip(';'); |
||
4953 | break; |
||
4954 | } |
||
4955 | } |
||
4956 | } |
||
4957 | while (tok != '}') { |
||
4958 | label_or_decl(VT_LOCAL); |
||
4959 | if (tok != '}') { |
||
4960 | if (is_expr) |
||
4961 | vpop(); |
||
4962 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
4963 | } |
||
4964 | } |
||
4965 | /* pop locally defined labels */ |
||
4966 | label_pop(&local_label_stack, llabel); |
||
4967 | if(is_expr) { |
||
4968 | /* XXX: this solution makes only valgrind happy... |
||
4969 | triggered by gcc.c-torture/execute/20000917-1.c */ |
||
4970 | Sym *p; |
||
4971 | switch(vtop->type.t & VT_BTYPE) { |
||
4972 | /* case VT_PTR: */ |
||
4973 | /* this breaks a compilation of the linux kernel v2.4.26 */ |
||
4974 | /* pmd_t *new = ({ __asm__ __volatile__("ud2\n") ; ((pmd_t *)1); }); */ |
||
4975 | /* Look a commit a80acab: Display error on statement expressions with complex return type */ |
||
4976 | /* A pointer is not a complex return type */ |
||
4977 | case VT_STRUCT: |
||
4978 | case VT_ENUM: |
||
4979 | case VT_FUNC: |
||
4980 | for(p=vtop->type.ref;p;p=p->prev) |
||
4981 | if(p->prev==s) |
||
4982 | tcc_error("unsupported expression type"); |
||
4983 | } |
||
4984 | } |
||
4985 | /* pop locally defined symbols */ |
||
4986 | scope_stack_bottom = scope_stack_bottom->next; |
||
4987 | sym_pop(&local_stack, s); |
||
4988 | |||
4989 | /* Pop VLA frames and restore stack pointer if required */ |
||
4990 | if (vlas_in_scope > saved_vlas_in_scope) { |
||
4991 | vla_sp_loc = saved_vlas_in_scope ? block_vla_sp_loc : vla_sp_root_loc; |
||
4992 | vla_sp_restore(); |
||
4993 | } |
||
4994 | vlas_in_scope = saved_vlas_in_scope; |
||
4995 | |||
4996 | next(); |
||
4997 | } else if (tok == TOK_RETURN) { |
||
4998 | next(); |
||
4999 | if (tok != ';') { |
||
5000 | gexpr(); |
||
5001 | gen_assign_cast(&func_vt); |
||
5002 | #ifdef TCC_TARGET_ARM64 |
||
5003 | // Perhaps it would be better to use this for all backends: |
||
5004 | greturn(); |
||
5005 | #else |
||
5006 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
||
5007 | CType type, ret_type; |
||
5008 | int ret_align, ret_nregs, regsize; |
||
5009 | ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type, |
||
5010 | &ret_align, ®size); |
||
5011 | if (0 == ret_nregs) { |
||
5012 | /* if returning structure, must copy it to implicit |
||
5013 | first pointer arg location */ |
||
5014 | type = func_vt; |
||
5015 | mk_pointer(&type); |
||
5016 | vset(&type, VT_LOCAL | VT_LVAL, func_vc); |
||
5017 | indir(); |
||
5018 | vswap(); |
||
5019 | /* copy structure value to pointer */ |
||
5020 | vstore(); |
||
5021 | } else { |
||
5022 | /* returning structure packed into registers */ |
||
5023 | int r, size, addr, align; |
||
5024 | size = type_size(&func_vt,&align); |
||
5025 | if ((vtop->r != (VT_LOCAL | VT_LVAL) || |
||
5026 | (vtop->c.i & (ret_align-1))) |
||
5027 | && (align & (ret_align-1))) { |
||
5028 | loc = (loc - size) & -ret_align; |
||
5029 | addr = loc; |
||
5030 | type = func_vt; |
||
5031 | vset(&type, VT_LOCAL | VT_LVAL, addr); |
||
5032 | vswap(); |
||
5033 | vstore(); |
||
5034 | vpop(); |
||
5035 | vset(&ret_type, VT_LOCAL | VT_LVAL, addr); |
||
5036 | } |
||
5037 | vtop->type = ret_type; |
||
5038 | if (is_float(ret_type.t)) |
||
5039 | r = rc_fret(ret_type.t); |
||
5040 | else |
||
5041 | r = RC_IRET; |
||
5042 | |||
5043 | for (;;) { |
||
5044 | gv(r); |
||
5045 | if (--ret_nregs == 0) |
||
5046 | break; |
||
5047 | /* We assume that when a structure is returned in multiple |
||
5048 | registers, their classes are consecutive values of the |
||
5049 | suite s(n) = 2^n */ |
||
5050 | r <<= 1; |
||
5051 | vtop->c.i += regsize; |
||
5052 | vtop->r = VT_LOCAL | VT_LVAL; |
||
5053 | } |
||
5054 | } |
||
5055 | } else if (is_float(func_vt.t)) { |
||
5056 | gv(rc_fret(func_vt.t)); |
||
5057 | } else { |
||
5058 | gv(RC_IRET); |
||
5059 | } |
||
5060 | #endif |
||
5061 | vtop--; /* NOT vpop() because on x86 it would flush the fp stack */ |
||
5062 | } |
||
5063 | skip(';'); |
||
5064 | rsym = gjmp(rsym); /* jmp */ |
||
5065 | } else if (tok == TOK_BREAK) { |
||
5066 | /* compute jump */ |
||
5067 | if (!bsym) |
||
5068 | tcc_error("cannot break"); |
||
5069 | *bsym = gjmp(*bsym); |
||
5070 | next(); |
||
5071 | skip(';'); |
||
5072 | } else if (tok == TOK_CONTINUE) { |
||
5073 | /* compute jump */ |
||
5074 | if (!csym) |
||
5075 | tcc_error("cannot continue"); |
||
5076 | vla_sp_restore_root(); |
||
5077 | *csym = gjmp(*csym); |
||
5078 | next(); |
||
5079 | skip(';'); |
||
5080 | } else if (tok == TOK_FOR) { |
||
5081 | int e; |
||
5082 | next(); |
||
5083 | skip('('); |
||
5084 | s = local_stack; |
||
5085 | frame_bottom = sym_push2(&local_stack, SYM_FIELD, 0, 0); |
||
5086 | frame_bottom->next = scope_stack_bottom; |
||
5087 | scope_stack_bottom = frame_bottom; |
||
5088 | if (tok != ';') { |
||
5089 | /* c99 for-loop init decl? */ |
||
5090 | if (!decl0(VT_LOCAL, 1)) { |
||
5091 | /* no, regular for-loop init expr */ |
||
5092 | gexpr(); |
||
5093 | vpop(); |
||
5094 | } |
||
5095 | } |
||
5096 | skip(';'); |
||
5097 | d = ind; |
||
5098 | c = ind; |
||
5099 | vla_sp_restore(); |
||
5100 | a = 0; |
||
5101 | b = 0; |
||
5102 | if (tok != ';') { |
||
5103 | gexpr(); |
||
5104 | a = gvtst(1, 0); |
||
5105 | } |
||
5106 | skip(';'); |
||
5107 | if (tok != ')') { |
||
5108 | e = gjmp(0); |
||
5109 | c = ind; |
||
5110 | vla_sp_restore(); |
||
5111 | gexpr(); |
||
5112 | vpop(); |
||
5113 | gjmp_addr(d); |
||
5114 | gsym(e); |
||
5115 | } |
||
5116 | skip(')'); |
||
5117 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
5118 | if(!nocode_wanted) |
||
5119 | gjmp_addr(c); |
||
5120 | gsym(a); |
||
5121 | gsym_addr(b, c); |
||
5122 | scope_stack_bottom = scope_stack_bottom->next; |
||
5123 | sym_pop(&local_stack, s); |
||
5124 | } else |
||
5125 | if (tok == TOK_DO) { |
||
5126 | next(); |
||
5127 | a = 0; |
||
5128 | b = 0; |
||
5129 | d = ind; |
||
5130 | vla_sp_restore(); |
||
5131 | block(&a, &b, case_sym, def_sym, case_reg, 0); |
||
5132 | skip(TOK_WHILE); |
||
5133 | skip('('); |
||
5134 | gsym(b); |
||
5135 | gexpr(); |
||
5136 | c = gvtst(0, 0); |
||
5137 | gsym_addr(c, d); |
||
5138 | skip(')'); |
||
5139 | gsym(a); |
||
5140 | skip(';'); |
||
5141 | } else |
||
5142 | if (tok == TOK_SWITCH) { |
||
5143 | next(); |
||
5144 | skip('('); |
||
5145 | gexpr(); |
||
5146 | /* XXX: other types than integer */ |
||
5147 | case_reg = gv(RC_INT); |
||
5148 | vpop(); |
||
5149 | skip(')'); |
||
5150 | a = 0; |
||
5151 | b = gjmp(0); /* jump to first case */ |
||
5152 | c = 0; |
||
5153 | block(&a, csym, &b, &c, case_reg, 0); |
||
5154 | /* if no default, jmp after switch */ |
||
5155 | if (c == 0) |
||
5156 | c = ind; |
||
5157 | /* default label */ |
||
5158 | gsym_addr(b, c); |
||
5159 | /* break label */ |
||
5160 | gsym(a); |
||
5161 | } else |
||
5162 | if (tok == TOK_CASE) { |
||
5163 | int v1, v2; |
||
5164 | if (!case_sym) |
||
5165 | expect("switch"); |
||
5166 | next(); |
||
5167 | v1 = expr_const(); |
||
5168 | v2 = v1; |
||
5169 | if (gnu_ext && tok == TOK_DOTS) { |
||
5170 | next(); |
||
5171 | v2 = expr_const(); |
||
5172 | if (v2 < v1) |
||
5173 | tcc_warning("empty case range"); |
||
5174 | } |
||
5175 | /* since a case is like a label, we must skip it with a jmp */ |
||
5176 | b = gjmp(0); |
||
5177 | gsym(*case_sym); |
||
5178 | vseti(case_reg, 0); |
||
5179 | vdup(); |
||
5180 | vpushi(v1); |
||
5181 | if (v1 == v2) { |
||
5182 | gen_op(TOK_EQ); |
||
5183 | *case_sym = gtst(1, 0); |
||
5184 | } else { |
||
5185 | gen_op(TOK_GE); |
||
5186 | *case_sym = gtst(1, 0); |
||
5187 | vseti(case_reg, 0); |
||
5188 | vpushi(v2); |
||
5189 | gen_op(TOK_LE); |
||
5190 | *case_sym = gtst(1, *case_sym); |
||
5191 | } |
||
5192 | case_reg = gv(RC_INT); |
||
5193 | vpop(); |
||
5194 | gsym(b); |
||
5195 | skip(':'); |
||
5196 | is_expr = 0; |
||
5197 | goto block_after_label; |
||
5198 | } else |
||
5199 | if (tok == TOK_DEFAULT) { |
||
5200 | next(); |
||
5201 | skip(':'); |
||
5202 | if (!def_sym) |
||
5203 | expect("switch"); |
||
5204 | if (*def_sym) |
||
5205 | tcc_error("too many 'default'"); |
||
5206 | *def_sym = ind; |
||
5207 | is_expr = 0; |
||
5208 | goto block_after_label; |
||
5209 | } else |
||
5210 | if (tok == TOK_GOTO) { |
||
5211 | next(); |
||
5212 | if (tok == '*' && gnu_ext) { |
||
5213 | /* computed goto */ |
||
5214 | next(); |
||
5215 | gexpr(); |
||
5216 | if ((vtop->type.t & VT_BTYPE) != VT_PTR) |
||
5217 | expect("pointer"); |
||
5218 | ggoto(); |
||
5219 | } else if (tok >= TOK_UIDENT) { |
||
5220 | s = label_find(tok); |
||
5221 | /* put forward definition if needed */ |
||
5222 | if (!s) { |
||
5223 | s = label_push(&global_label_stack, tok, LABEL_FORWARD); |
||
5224 | } else { |
||
5225 | if (s->r == LABEL_DECLARED) |
||
5226 | s->r = LABEL_FORWARD; |
||
5227 | } |
||
5228 | vla_sp_restore_root(); |
||
5229 | if (s->r & LABEL_FORWARD) |
||
5230 | s->jnext = gjmp(s->jnext); |
||
5231 | else |
||
5232 | gjmp_addr(s->jnext); |
||
5233 | next(); |
||
5234 | } else { |
||
5235 | expect("label identifier"); |
||
5236 | } |
||
5237 | skip(';'); |
||
5238 | } else if (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3) { |
||
5239 | asm_instr(); |
||
5240 | } else { |
||
5241 | b = is_label(); |
||
5242 | if (b) { |
||
5243 | /* label case */ |
||
5244 | s = label_find(b); |
||
5245 | if (s) { |
||
5246 | if (s->r == LABEL_DEFINED) |
||
5247 | tcc_error("duplicate label '%s'", get_tok_str(s->v, NULL)); |
||
5248 | gsym(s->jnext); |
||
5249 | s->r = LABEL_DEFINED; |
||
5250 | } else { |
||
5251 | s = label_push(&global_label_stack, b, LABEL_DEFINED); |
||
5252 | } |
||
5253 | s->jnext = ind; |
||
5254 | vla_sp_restore(); |
||
5255 | /* we accept this, but it is a mistake */ |
||
5256 | block_after_label: |
||
5257 | if (tok == '}') { |
||
5258 | tcc_warning("deprecated use of label at end of compound statement"); |
||
5259 | } else { |
||
5260 | if (is_expr) |
||
5261 | vpop(); |
||
5262 | block(bsym, csym, case_sym, def_sym, case_reg, is_expr); |
||
5263 | } |
||
5264 | } else { |
||
5265 | /* expression case */ |
||
5266 | if (tok != ';') { |
||
5267 | if (is_expr) { |
||
5268 | vpop(); |
||
5269 | gexpr(); |
||
5270 | } else { |
||
5271 | gexpr(); |
||
5272 | vpop(); |
||
5273 | } |
||
5274 | } |
||
5275 | skip(';'); |
||
5276 | } |
||
5277 | } |
||
5278 | } |
||
5279 | |||
5280 | /* t is the array or struct type. c is the array or struct |
||
5281 | address. cur_index/cur_field is the pointer to the current |
||
5282 | value. 'size_only' is true if only size info is needed (only used |
||
5283 | in arrays) */ |
||
5284 | static void decl_designator(CType *type, Section *sec, unsigned long c, |
||
5285 | int *cur_index, Sym **cur_field, |
||
5286 | int size_only) |
||
5287 | { |
||
5288 | Sym *s, *f; |
||
5289 | int notfirst, index, index_last, align, l, nb_elems, elem_size; |
||
5290 | CType type1; |
||
5291 | |||
5292 | notfirst = 0; |
||
5293 | elem_size = 0; |
||
5294 | nb_elems = 1; |
||
5295 | if (gnu_ext && (l = is_label()) != 0) |
||
5296 | goto struct_field; |
||
5297 | while (tok == '[' || tok == '.') { |
||
5298 | if (tok == '[') { |
||
5299 | if (!(type->t & VT_ARRAY)) |
||
5300 | expect("array type"); |
||
5301 | s = type->ref; |
||
5302 | next(); |
||
5303 | index = expr_const(); |
||
5304 | if (index < 0 || (s->c >= 0 && index >= s->c)) |
||
5305 | expect("invalid index"); |
||
5306 | if (tok == TOK_DOTS && gnu_ext) { |
||
5307 | next(); |
||
5308 | index_last = expr_const(); |
||
5309 | if (index_last < 0 || |
||
5310 | (s->c >= 0 && index_last >= s->c) || |
||
5311 | index_last < index) |
||
5312 | expect("invalid index"); |
||
5313 | } else { |
||
5314 | index_last = index; |
||
5315 | } |
||
5316 | skip(']'); |
||
5317 | if (!notfirst) |
||
5318 | *cur_index = index_last; |
||
5319 | type = pointed_type(type); |
||
5320 | elem_size = type_size(type, &align); |
||
5321 | c += index * elem_size; |
||
5322 | /* NOTE: we only support ranges for last designator */ |
||
5323 | nb_elems = index_last - index + 1; |
||
5324 | if (nb_elems != 1) { |
||
5325 | notfirst = 1; |
||
5326 | break; |
||
5327 | } |
||
5328 | } else { |
||
5329 | next(); |
||
5330 | l = tok; |
||
5331 | next(); |
||
5332 | struct_field: |
||
5333 | if ((type->t & VT_BTYPE) != VT_STRUCT) |
||
5334 | expect("struct/union type"); |
||
5335 | s = type->ref; |
||
5336 | l |= SYM_FIELD; |
||
5337 | f = s->next; |
||
5338 | while (f) { |
||
5339 | if (f->v == l) |
||
5340 | break; |
||
5341 | f = f->next; |
||
5342 | } |
||
5343 | if (!f) |
||
5344 | expect("field"); |
||
5345 | if (!notfirst) |
||
5346 | *cur_field = f; |
||
5347 | /* XXX: fix this mess by using explicit storage field */ |
||
5348 | type1 = f->type; |
||
5349 | type1.t |= (type->t & ~VT_TYPE); |
||
5350 | type = &type1; |
||
5351 | c += f->c; |
||
5352 | } |
||
5353 | notfirst = 1; |
||
5354 | } |
||
5355 | if (notfirst) { |
||
5356 | if (tok == '=') { |
||
5357 | next(); |
||
5358 | } else { |
||
5359 | if (!gnu_ext) |
||
5360 | expect("="); |
||
5361 | } |
||
5362 | } else { |
||
5363 | if (type->t & VT_ARRAY) { |
||
5364 | index = *cur_index; |
||
5365 | type = pointed_type(type); |
||
5366 | c += index * type_size(type, &align); |
||
5367 | } else { |
||
5368 | f = *cur_field; |
||
5369 | if (!f) |
||
5370 | tcc_error("too many field init"); |
||
5371 | /* XXX: fix this mess by using explicit storage field */ |
||
5372 | type1 = f->type; |
||
5373 | type1.t |= (type->t & ~VT_TYPE); |
||
5374 | type = &type1; |
||
5375 | c += f->c; |
||
5376 | } |
||
5377 | } |
||
5378 | decl_initializer(type, sec, c, 0, size_only); |
||
5379 | |||
5380 | /* XXX: make it more general */ |
||
5381 | if (!size_only && nb_elems > 1) { |
||
5382 | unsigned long c_end; |
||
5383 | uint8_t *src, *dst; |
||
5384 | int i; |
||
5385 | |||
5386 | if (!sec) |
||
5387 | tcc_error("range init not supported yet for dynamic storage"); |
||
5388 | c_end = c + nb_elems * elem_size; |
||
5389 | if (c_end > sec->data_allocated) |
||
5390 | section_realloc(sec, c_end); |
||
5391 | src = sec->data + c; |
||
5392 | dst = src; |
||
5393 | for(i = 1; i < nb_elems; i++) { |
||
5394 | dst += elem_size; |
||
5395 | memcpy(dst, src, elem_size); |
||
5396 | } |
||
5397 | } |
||
5398 | } |
||
5399 | |||
5400 | #define EXPR_VAL 0 |
||
5401 | #define EXPR_CONST 1 |
||
5402 | #define EXPR_ANY 2 |
||
5403 | |||
5404 | /* store a value or an expression directly in global data or in local array */ |
||
5405 | static void init_putv(CType *type, Section *sec, unsigned long c, |
||
5406 | int v, int expr_type) |
||
5407 | { |
||
5408 | int saved_global_expr, bt, bit_pos, bit_size; |
||
5409 | void *ptr; |
||
5410 | unsigned long long bit_mask; |
||
5411 | CType dtype; |
||
5412 | |||
5413 | switch(expr_type) { |
||
5414 | case EXPR_VAL: |
||
5415 | vpushi(v); |
||
5416 | break; |
||
5417 | case EXPR_CONST: |
||
5418 | /* compound literals must be allocated globally in this case */ |
||
5419 | saved_global_expr = global_expr; |
||
5420 | global_expr = 1; |
||
5421 | expr_const1(); |
||
5422 | global_expr = saved_global_expr; |
||
5423 | /* NOTE: symbols are accepted */ |
||
5424 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) != VT_CONST) |
||
5425 | tcc_error("initializer element is not constant"); |
||
5426 | break; |
||
5427 | case EXPR_ANY: |
||
5428 | expr_eq(); |
||
5429 | break; |
||
5430 | } |
||
5431 | |||
5432 | dtype = *type; |
||
5433 | dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */ |
||
5434 | |||
5435 | if (sec) { |
||
5436 | /* XXX: not portable */ |
||
5437 | /* XXX: generate error if incorrect relocation */ |
||
5438 | gen_assign_cast(&dtype); |
||
5439 | bt = type->t & VT_BTYPE; |
||
5440 | /* we'll write at most 16 bytes */ |
||
5441 | if (c + 16 > sec->data_allocated) { |
||
5442 | section_realloc(sec, c + 16); |
||
5443 | } |
||
5444 | ptr = sec->data + c; |
||
5445 | /* XXX: make code faster ? */ |
||
5446 | if (!(type->t & VT_BITFIELD)) { |
||
5447 | bit_pos = 0; |
||
5448 | bit_size = 32; |
||
5449 | bit_mask = -1LL; |
||
5450 | } else { |
||
5451 | bit_pos = (vtop->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
5452 | bit_size = (vtop->type.t >> (VT_STRUCT_SHIFT + 6)) & 0x3f; |
||
5453 | bit_mask = (1LL << bit_size) - 1; |
||
5454 | } |
||
5455 | if ((vtop->r & VT_SYM) && |
||
5456 | (bt == VT_BYTE || |
||
5457 | bt == VT_SHORT || |
||
5458 | bt == VT_DOUBLE || |
||
5459 | bt == VT_LDOUBLE || |
||
5460 | bt == VT_LLONG || |
||
5461 | (bt == VT_INT && bit_size != 32))) |
||
5462 | tcc_error("initializer element is not computable at load time"); |
||
5463 | switch(bt) { |
||
5464 | /* XXX: when cross-compiling we assume that each type has the |
||
5465 | same representation on host and target, which is likely to |
||
5466 | be wrong in the case of long double */ |
||
5467 | case VT_BOOL: |
||
5468 | vtop->c.i = (vtop->c.i != 0); |
||
5469 | case VT_BYTE: |
||
5470 | *(char *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
5471 | break; |
||
5472 | case VT_SHORT: |
||
5473 | *(short *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
5474 | break; |
||
5475 | case VT_DOUBLE: |
||
5476 | *(double *)ptr = vtop->c.d; |
||
5477 | break; |
||
5478 | case VT_LDOUBLE: |
||
5479 | *(long double *)ptr = vtop->c.ld; |
||
5480 | break; |
||
5481 | case VT_LLONG: |
||
5482 | *(long long *)ptr |= (vtop->c.i & bit_mask) << bit_pos; |
||
5483 | break; |
||
5484 | case VT_PTR: { |
||
5485 | addr_t val = (vtop->c.i & bit_mask) << bit_pos; |
||
5486 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
5487 | if (vtop->r & VT_SYM) |
||
5488 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
||
5489 | else |
||
5490 | *(addr_t *)ptr |= val; |
||
5491 | #else |
||
5492 | if (vtop->r & VT_SYM) |
||
5493 | greloc(sec, vtop->sym, c, R_DATA_PTR); |
||
5494 | *(addr_t *)ptr |= val; |
||
5495 | #endif |
||
5496 | break; |
||
5497 | } |
||
5498 | default: { |
||
5499 | int val = (vtop->c.i & bit_mask) << bit_pos; |
||
5500 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
||
5501 | if (vtop->r & VT_SYM) |
||
5502 | greloca(sec, vtop->sym, c, R_DATA_PTR, val); |
||
5503 | else |
||
5504 | *(int *)ptr |= val; |
||
5505 | #else |
||
5506 | if (vtop->r & VT_SYM) |
||
5507 | greloc(sec, vtop->sym, c, R_DATA_PTR); |
||
5508 | *(int *)ptr |= val; |
||
5509 | #endif |
||
5510 | break; |
||
5511 | } |
||
5512 | } |
||
5513 | vtop--; |
||
5514 | } else { |
||
5515 | vset(&dtype, VT_LOCAL|VT_LVAL, c); |
||
5516 | vswap(); |
||
5517 | vstore(); |
||
5518 | vpop(); |
||
5519 | } |
||
5520 | } |
||
5521 | |||
5522 | /* put zeros for variable based init */ |
||
5523 | static void init_putz(CType *t, Section *sec, unsigned long c, int size) |
||
5524 | { |
||
5525 | if (sec) { |
||
5526 | /* nothing to do because globals are already set to zero */ |
||
5527 | } else { |
||
5528 | vpush_global_sym(&func_old_type, TOK_memset); |
||
5529 | vseti(VT_LOCAL, c); |
||
5530 | #ifdef TCC_TARGET_ARM |
||
5531 | vpushs(size); |
||
5532 | vpushi(0); |
||
5533 | #else |
||
5534 | vpushi(0); |
||
5535 | vpushs(size); |
||
5536 | #endif |
||
5537 | gfunc_call(3); |
||
5538 | } |
||
5539 | } |
||
5540 | |||
5541 | /* 't' contains the type and storage info. 'c' is the offset of the |
||
5542 | object in section 'sec'. If 'sec' is NULL, it means stack based |
||
5543 | allocation. 'first' is true if array '{' must be read (multi |
||
5544 | dimension implicit array init handling). 'size_only' is true if |
||
5545 | size only evaluation is wanted (only for arrays). */ |
||
5546 | static void decl_initializer(CType *type, Section *sec, unsigned long c, |
||
5547 | int first, int size_only) |
||
5548 | { |
||
5549 | int index, array_length, n, no_oblock, nb, parlevel, parlevel1, i; |
||
5550 | int size1, align1, expr_type; |
||
5551 | Sym *s, *f; |
||
5552 | CType *t1; |
||
5553 | |||
5554 | if (type->t & VT_VLA) { |
||
5555 | int a; |
||
5556 | |||
5557 | /* save current stack pointer */ |
||
5558 | if (vlas_in_scope == 0) { |
||
5559 | if (vla_sp_root_loc == -1) |
||
5560 | vla_sp_root_loc = (loc -= PTR_SIZE); |
||
5561 | gen_vla_sp_save(vla_sp_root_loc); |
||
5562 | } |
||
5563 | |||
5564 | vla_runtime_type_size(type, &a); |
||
5565 | gen_vla_alloc(type, a); |
||
5566 | gen_vla_sp_save(c); |
||
5567 | vla_sp_loc = c; |
||
5568 | vlas_in_scope++; |
||
5569 | } else if (type->t & VT_ARRAY) { |
||
5570 | s = type->ref; |
||
5571 | n = s->c; |
||
5572 | array_length = 0; |
||
5573 | t1 = pointed_type(type); |
||
5574 | size1 = type_size(t1, &align1); |
||
5575 | |||
5576 | no_oblock = 1; |
||
5577 | if ((first && tok != TOK_LSTR && tok != TOK_STR) || |
||
5578 | tok == '{') { |
||
5579 | if (tok != '{') |
||
5580 | tcc_error("character array initializer must be a literal," |
||
5581 | " optionally enclosed in braces"); |
||
5582 | skip('{'); |
||
5583 | no_oblock = 0; |
||
5584 | } |
||
5585 | |||
5586 | /* only parse strings here if correct type (otherwise: handle |
||
5587 | them as ((w)char *) expressions */ |
||
5588 | if ((tok == TOK_LSTR && |
||
5589 | #ifdef TCC_TARGET_PE |
||
5590 | (t1->t & VT_BTYPE) == VT_SHORT && (t1->t & VT_UNSIGNED) |
||
5591 | #else |
||
5592 | (t1->t & VT_BTYPE) == VT_INT |
||
5593 | #endif |
||
5594 | ) || (tok == TOK_STR && (t1->t & VT_BTYPE) == VT_BYTE)) { |
||
5595 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
5596 | int cstr_len, ch; |
||
5597 | |||
5598 | /* compute maximum number of chars wanted */ |
||
5599 | if (tok == TOK_STR) |
||
5600 | cstr_len = tokc.str.size; |
||
5601 | else |
||
5602 | cstr_len = tokc.str.size / sizeof(nwchar_t); |
||
5603 | cstr_len--; |
||
5604 | nb = cstr_len; |
||
5605 | if (n >= 0 && nb > (n - array_length)) |
||
5606 | nb = n - array_length; |
||
5607 | if (!size_only) { |
||
5608 | if (cstr_len > nb) |
||
5609 | tcc_warning("initializer-string for array is too long"); |
||
5610 | /* in order to go faster for common case (char |
||
5611 | string in global variable, we handle it |
||
5612 | specifically */ |
||
5613 | if (sec && tok == TOK_STR && size1 == 1) { |
||
5614 | memcpy(sec->data + c + array_length, tokc.str.data, nb); |
||
5615 | } else { |
||
5616 | for(i=0;i |
||
5617 | if (tok == TOK_STR) |
||
5618 | ch = ((unsigned char *)tokc.str.data)[i]; |
||
5619 | else |
||
5620 | ch = ((nwchar_t *)tokc.str.data)[i]; |
||
5621 | init_putv(t1, sec, c + (array_length + i) * size1, |
||
5622 | ch, EXPR_VAL); |
||
5623 | } |
||
5624 | } |
||
5625 | } |
||
5626 | array_length += nb; |
||
5627 | next(); |
||
5628 | } |
||
5629 | /* only add trailing zero if enough storage (no |
||
5630 | warning in this case since it is standard) */ |
||
5631 | if (n < 0 || array_length < n) { |
||
5632 | if (!size_only) { |
||
5633 | init_putv(t1, sec, c + (array_length * size1), 0, EXPR_VAL); |
||
5634 | } |
||
5635 | array_length++; |
||
5636 | } |
||
5637 | } else { |
||
5638 | index = 0; |
||
5639 | while (tok != '}') { |
||
5640 | decl_designator(type, sec, c, &index, NULL, size_only); |
||
5641 | if (n >= 0 && index >= n) |
||
5642 | tcc_error("index too large"); |
||
5643 | /* must put zero in holes (note that doing it that way |
||
5644 | ensures that it even works with designators) */ |
||
5645 | if (!size_only && array_length < index) { |
||
5646 | init_putz(t1, sec, c + array_length * size1, |
||
5647 | (index - array_length) * size1); |
||
5648 | } |
||
5649 | index++; |
||
5650 | if (index > array_length) |
||
5651 | array_length = index; |
||
5652 | /* special test for multi dimensional arrays (may not |
||
5653 | be strictly correct if designators are used at the |
||
5654 | same time) */ |
||
5655 | if (index >= n && no_oblock) |
||
5656 | break; |
||
5657 | if (tok == '}') |
||
5658 | break; |
||
5659 | skip(','); |
||
5660 | } |
||
5661 | } |
||
5662 | if (!no_oblock) |
||
5663 | skip('}'); |
||
5664 | /* put zeros at the end */ |
||
5665 | if (!size_only && n >= 0 && array_length < n) { |
||
5666 | init_putz(t1, sec, c + array_length * size1, |
||
5667 | (n - array_length) * size1); |
||
5668 | } |
||
5669 | /* patch type size if needed */ |
||
5670 | if (n < 0) |
||
5671 | s->c = array_length; |
||
5672 | } else if ((type->t & VT_BTYPE) == VT_STRUCT && |
||
5673 | (sec || !first || tok == '{')) { |
||
5674 | |||
5675 | /* NOTE: the previous test is a specific case for automatic |
||
5676 | struct/union init */ |
||
5677 | /* XXX: union needs only one init */ |
||
5678 | |||
5679 | int par_count = 0; |
||
5680 | if (tok == '(') { |
||
5681 | AttributeDef ad1; |
||
5682 | CType type1; |
||
5683 | next(); |
||
5684 | if (tcc_state->old_struct_init_code) { |
||
5685 | /* an old version of struct initialization. |
||
5686 | It have a problems. But with a new version |
||
5687 | linux 2.4.26 can't load ramdisk. |
||
5688 | */ |
||
5689 | while (tok == '(') { |
||
5690 | par_count++; |
||
5691 | next(); |
||
5692 | } |
||
5693 | if (!parse_btype(&type1, &ad1)) |
||
5694 | expect("cast"); |
||
5695 | type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
||
5696 | #if 0 |
||
5697 | if (!is_assignable_types(type, &type1)) |
||
5698 | tcc_error("invalid type for cast"); |
||
5699 | #endif |
||
5700 | skip(')'); |
||
5701 | } |
||
5702 | else |
||
5703 | { |
||
5704 | if (tok != '(') { |
||
5705 | if (!parse_btype(&type1, &ad1)) |
||
5706 | expect("cast"); |
||
5707 | type_decl(&type1, &ad1, &n, TYPE_ABSTRACT); |
||
5708 | #if 0 |
||
5709 | if (!is_assignable_types(type, &type1)) |
||
5710 | tcc_error("invalid type for cast"); |
||
5711 | #endif |
||
5712 | skip(')'); |
||
5713 | } else |
||
5714 | unget_tok(tok); |
||
5715 | } |
||
5716 | } |
||
5717 | |||
5718 | no_oblock = 1; |
||
5719 | if (first || tok == '{') { |
||
5720 | skip('{'); |
||
5721 | no_oblock = 0; |
||
5722 | } |
||
5723 | s = type->ref; |
||
5724 | f = s->next; |
||
5725 | array_length = 0; |
||
5726 | index = 0; |
||
5727 | n = s->c; |
||
5728 | while (tok != '}') { |
||
5729 | decl_designator(type, sec, c, NULL, &f, size_only); |
||
5730 | index = f->c; |
||
5731 | if (!size_only && array_length < index) { |
||
5732 | init_putz(type, sec, c + array_length, |
||
5733 | index - array_length); |
||
5734 | } |
||
5735 | index = index + type_size(&f->type, &align1); |
||
5736 | if (index > array_length) |
||
5737 | array_length = index; |
||
5738 | |||
5739 | /* gr: skip fields from same union - ugly. */ |
||
5740 | while (f->next) { |
||
5741 | int align = 0; |
||
5742 | int f_size = type_size(&f->type, &align); |
||
5743 | int f_type = (f->type.t & VT_BTYPE); |
||
5744 | |||
5745 | ///printf("index: %2d %08x -- %2d %08x\n", f->c, f->type.t, f->next->c, f->next->type.t); |
||
5746 | /* test for same offset */ |
||
5747 | if (f->next->c != f->c) |
||
5748 | break; |
||
5749 | if ((f_type == VT_STRUCT) && (f_size == 0)) { |
||
5750 | /* |
||
5751 | Lets assume a structure of size 0 can't be a member of the union. |
||
5752 | This allow to compile the following code from a linux kernel v2.4.26 |
||
5753 | typedef struct { } rwlock_t; |
||
5754 | struct fs_struct { |
||
5755 | int count; |
||
5756 | rwlock_t lock; |
||
5757 | int umask; |
||
5758 | }; |
||
5759 | struct fs_struct init_fs = { { (1) }, (rwlock_t) {}, 0022, }; |
||
5760 | tcc-0.9.23 can succesfully compile this version of the kernel. |
||
5761 | gcc don't have problems with this code too. |
||
5762 | */ |
||
5763 | break; |
||
5764 | } |
||
5765 | /* if yes, test for bitfield shift */ |
||
5766 | if ((f->type.t & VT_BITFIELD) && (f->next->type.t & VT_BITFIELD)) { |
||
5767 | int bit_pos_1 = (f->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
5768 | int bit_pos_2 = (f->next->type.t >> VT_STRUCT_SHIFT) & 0x3f; |
||
5769 | //printf("bitfield %d %d\n", bit_pos_1, bit_pos_2); |
||
5770 | if (bit_pos_1 != bit_pos_2) |
||
5771 | break; |
||
5772 | } |
||
5773 | f = f->next; |
||
5774 | } |
||
5775 | |||
5776 | f = f->next; |
||
5777 | if (no_oblock && f == NULL) |
||
5778 | break; |
||
5779 | if (tok == '}') |
||
5780 | break; |
||
5781 | skip(','); |
||
5782 | } |
||
5783 | /* put zeros at the end */ |
||
5784 | if (!size_only && array_length < n) { |
||
5785 | init_putz(type, sec, c + array_length, |
||
5786 | n - array_length); |
||
5787 | } |
||
5788 | if (!no_oblock) |
||
5789 | skip('}'); |
||
5790 | while (par_count) { |
||
5791 | skip(')'); |
||
5792 | par_count--; |
||
5793 | } |
||
5794 | } else if (tok == '{') { |
||
5795 | next(); |
||
5796 | decl_initializer(type, sec, c, first, size_only); |
||
5797 | skip('}'); |
||
5798 | } else if (size_only) { |
||
5799 | /* just skip expression */ |
||
5800 | parlevel = parlevel1 = 0; |
||
5801 | while ((parlevel > 0 || parlevel1 > 0 || |
||
5802 | (tok != '}' && tok != ',')) && tok != -1) { |
||
5803 | if (tok == '(') |
||
5804 | parlevel++; |
||
5805 | else if (tok == ')') { |
||
5806 | if (parlevel == 0 && parlevel1 == 0) |
||
5807 | break; |
||
5808 | parlevel--; |
||
5809 | } |
||
5810 | else if (tok == '{') |
||
5811 | parlevel1++; |
||
5812 | else if (tok == '}') { |
||
5813 | if (parlevel == 0 && parlevel1 == 0) |
||
5814 | break; |
||
5815 | parlevel1--; |
||
5816 | } |
||
5817 | next(); |
||
5818 | } |
||
5819 | } else { |
||
5820 | /* currently, we always use constant expression for globals |
||
5821 | (may change for scripting case) */ |
||
5822 | expr_type = EXPR_CONST; |
||
5823 | if (!sec) |
||
5824 | expr_type = EXPR_ANY; |
||
5825 | init_putv(type, sec, c, 0, expr_type); |
||
5826 | } |
||
5827 | } |
||
5828 | |||
5829 | /* parse an initializer for type 't' if 'has_init' is non zero, and |
||
5830 | allocate space in local or global data space ('r' is either |
||
5831 | VT_LOCAL or VT_CONST). If 'v' is non zero, then an associated |
||
5832 | variable 'v' of scope 'scope' is declared before initializers |
||
5833 | are parsed. If 'v' is zero, then a reference to the new object |
||
5834 | is put in the value stack. If 'has_init' is 2, a special parsing |
||
5835 | is done to handle string constants. */ |
||
5836 | static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, |
||
5837 | int has_init, int v, int scope) |
||
5838 | { |
||
5839 | int size, align, addr, data_offset; |
||
5840 | int level; |
||
5841 | ParseState saved_parse_state = {0}; |
||
5842 | TokenString init_str; |
||
5843 | Section *sec; |
||
5844 | Sym *flexible_array; |
||
5845 | |||
5846 | flexible_array = NULL; |
||
5847 | if ((type->t & VT_BTYPE) == VT_STRUCT) { |
||
5848 | Sym *field = type->ref->next; |
||
5849 | if (field) { |
||
5850 | while (field->next) |
||
5851 | field = field->next; |
||
5852 | if (field->type.t & VT_ARRAY && field->type.ref->c < 0) |
||
5853 | flexible_array = field; |
||
5854 | } |
||
5855 | } |
||
5856 | |||
5857 | size = type_size(type, &align); |
||
5858 | /* If unknown size, we must evaluate it before |
||
5859 | evaluating initializers because |
||
5860 | initializers can generate global data too |
||
5861 | (e.g. string pointers or ISOC99 compound |
||
5862 | literals). It also simplifies local |
||
5863 | initializers handling */ |
||
5864 | tok_str_new(&init_str); |
||
5865 | if (size < 0 || (flexible_array && has_init)) { |
||
5866 | if (!has_init) |
||
5867 | tcc_error("unknown type size"); |
||
5868 | /* get all init string */ |
||
5869 | if (has_init == 2) { |
||
5870 | /* only get strings */ |
||
5871 | while (tok == TOK_STR || tok == TOK_LSTR) { |
||
5872 | tok_str_add_tok(&init_str); |
||
5873 | next(); |
||
5874 | } |
||
5875 | } else { |
||
5876 | level = 0; |
||
5877 | while (level > 0 || (tok != ',' && tok != ';')) { |
||
5878 | if (tok < 0) |
||
5879 | tcc_error("unexpected end of file in initializer"); |
||
5880 | tok_str_add_tok(&init_str); |
||
5881 | if (tok == '{') |
||
5882 | level++; |
||
5883 | else if (tok == '}') { |
||
5884 | level--; |
||
5885 | if (level <= 0) { |
||
5886 | next(); |
||
5887 | break; |
||
5888 | } |
||
5889 | } |
||
5890 | next(); |
||
5891 | } |
||
5892 | } |
||
5893 | tok_str_add(&init_str, -1); |
||
5894 | tok_str_add(&init_str, 0); |
||
5895 | |||
5896 | /* compute size */ |
||
5897 | save_parse_state(&saved_parse_state); |
||
5898 | |||
5899 | begin_macro(&init_str, 0); |
||
5900 | next(); |
||
5901 | decl_initializer(type, NULL, 0, 1, 1); |
||
5902 | /* prepare second initializer parsing */ |
||
5903 | macro_ptr = init_str.str; |
||
5904 | next(); |
||
5905 | |||
5906 | /* if still unknown size, error */ |
||
5907 | size = type_size(type, &align); |
||
5908 | if (size < 0) |
||
5909 | tcc_error("unknown type size"); |
||
5910 | } |
||
5911 | /* If there's a flex member and it was used in the initializer |
||
5912 | adjust size. */ |
||
5913 | if (flexible_array && |
||
5914 | flexible_array->type.ref->c > 0) |
||
5915 | size += flexible_array->type.ref->c |
||
5916 | * pointed_size(&flexible_array->type); |
||
5917 | /* take into account specified alignment if bigger */ |
||
5918 | if (ad->a.aligned) { |
||
5919 | if (ad->a.aligned > align) |
||
5920 | align = ad->a.aligned; |
||
5921 | } else if (ad->a.packed) { |
||
5922 | align = 1; |
||
5923 | } |
||
5924 | if ((r & VT_VALMASK) == VT_LOCAL) { |
||
5925 | sec = NULL; |
||
5926 | #ifdef CONFIG_TCC_BCHECK |
||
5927 | if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { |
||
5928 | loc--; |
||
5929 | } |
||
5930 | #endif |
||
5931 | loc = (loc - size) & -align; |
||
5932 | addr = loc; |
||
5933 | #ifdef CONFIG_TCC_BCHECK |
||
5934 | /* handles bounds */ |
||
5935 | /* XXX: currently, since we do only one pass, we cannot track |
||
5936 | '&' operators, so we add only arrays */ |
||
5937 | if (tcc_state->do_bounds_check && (type->t & VT_ARRAY)) { |
||
5938 | addr_t *bounds_ptr; |
||
5939 | /* add padding between regions */ |
||
5940 | loc--; |
||
5941 | /* then add local bound info */ |
||
5942 | bounds_ptr = section_ptr_add(lbounds_section, 2 * sizeof(addr_t)); |
||
5943 | bounds_ptr[0] = addr; |
||
5944 | bounds_ptr[1] = size; |
||
5945 | } |
||
5946 | #endif |
||
5947 | if (v) { |
||
5948 | /* local variable */ |
||
5949 | sym_push(v, type, r, addr); |
||
5950 | } else { |
||
5951 | /* push local reference */ |
||
5952 | vset(type, r, addr); |
||
5953 | } |
||
5954 | } else { |
||
5955 | Sym *sym; |
||
5956 | |||
5957 | sym = NULL; |
||
5958 | if (v && scope == VT_CONST) { |
||
5959 | /* see if the symbol was already defined */ |
||
5960 | sym = sym_find(v); |
||
5961 | if (sym) { |
||
5962 | if (!is_compatible_types(&sym->type, type)) |
||
5963 | tcc_error("incompatible types for redefinition of '%s'", |
||
5964 | get_tok_str(v, NULL)); |
||
5965 | if (sym->type.t & VT_EXTERN) { |
||
5966 | /* if the variable is extern, it was not allocated */ |
||
5967 | sym->type.t &= ~VT_EXTERN; |
||
5968 | /* set array size if it was omitted in extern |
||
5969 | declaration */ |
||
5970 | if ((sym->type.t & VT_ARRAY) && |
||
5971 | sym->type.ref->c < 0 && |
||
5972 | type->ref->c >= 0) |
||
5973 | sym->type.ref->c = type->ref->c; |
||
5974 | } else { |
||
5975 | /* we accept several definitions of the same |
||
5976 | global variable. this is tricky, because we |
||
5977 | must play with the SHN_COMMON type of the symbol */ |
||
5978 | /* XXX: should check if the variable was already |
||
5979 | initialized. It is incorrect to initialized it |
||
5980 | twice */ |
||
5981 | /* no init data, we won't add more to the symbol */ |
||
5982 | if (!has_init) |
||
5983 | goto no_alloc; |
||
5984 | } |
||
5985 | } |
||
5986 | } |
||
5987 | |||
5988 | /* allocate symbol in corresponding section */ |
||
5989 | sec = ad->section; |
||
5990 | if (!sec) { |
||
5991 | if (has_init) |
||
5992 | sec = data_section; |
||
5993 | else if (tcc_state->nocommon) |
||
5994 | sec = bss_section; |
||
5995 | } |
||
5996 | if (sec) { |
||
5997 | data_offset = sec->data_offset; |
||
5998 | data_offset = (data_offset + align - 1) & -align; |
||
5999 | addr = data_offset; |
||
6000 | /* very important to increment global pointer at this time |
||
6001 | because initializers themselves can create new initializers */ |
||
6002 | data_offset += size; |
||
6003 | #ifdef CONFIG_TCC_BCHECK |
||
6004 | /* add padding if bound check */ |
||
6005 | if (tcc_state->do_bounds_check) |
||
6006 | data_offset++; |
||
6007 | #endif |
||
6008 | sec->data_offset = data_offset; |
||
6009 | /* allocate section space to put the data */ |
||
6010 | if (sec->sh_type != SHT_NOBITS && |
||
6011 | data_offset > sec->data_allocated) |
||
6012 | section_realloc(sec, data_offset); |
||
6013 | /* align section if needed */ |
||
6014 | if (align > sec->sh_addralign) |
||
6015 | sec->sh_addralign = align; |
||
6016 | } else { |
||
6017 | addr = 0; /* avoid warning */ |
||
6018 | } |
||
6019 | |||
6020 | if (v) { |
||
6021 | if (scope != VT_CONST || !sym) { |
||
6022 | sym = sym_push(v, type, r | VT_SYM, 0); |
||
6023 | sym->asm_label = ad->asm_label; |
||
6024 | } |
||
6025 | /* update symbol definition */ |
||
6026 | if (sec) { |
||
6027 | put_extern_sym(sym, sec, addr, size); |
||
6028 | } else { |
||
6029 | ElfW(Sym) *esym; |
||
6030 | /* put a common area */ |
||
6031 | put_extern_sym(sym, NULL, align, size); |
||
6032 | /* XXX: find a nicer way */ |
||
6033 | esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; |
||
6034 | esym->st_shndx = SHN_COMMON; |
||
6035 | } |
||
6036 | } else { |
||
6037 | /* push global reference */ |
||
6038 | sym = get_sym_ref(type, sec, addr, size); |
||
6039 | vpushsym(type, sym); |
||
6040 | } |
||
6041 | /* patch symbol weakness */ |
||
6042 | if (type->t & VT_WEAK) |
||
6043 | weaken_symbol(sym); |
||
6044 | apply_visibility(sym, type); |
||
6045 | #ifdef CONFIG_TCC_BCHECK |
||
6046 | /* handles bounds now because the symbol must be defined |
||
6047 | before for the relocation */ |
||
6048 | if (tcc_state->do_bounds_check) { |
||
6049 | addr_t *bounds_ptr; |
||
6050 | |||
6051 | greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR); |
||
6052 | /* then add global bound info */ |
||
6053 | bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(addr_t)); |
||
6054 | bounds_ptr[0] = 0; /* relocated */ |
||
6055 | bounds_ptr[1] = size; |
||
6056 | } |
||
6057 | #endif |
||
6058 | } |
||
6059 | if (has_init || (type->t & VT_VLA)) { |
||
6060 | decl_initializer(type, sec, addr, 1, 0); |
||
6061 | /* restore parse state if needed */ |
||
6062 | if (init_str.str) { |
||
6063 | end_macro(); |
||
6064 | restore_parse_state(&saved_parse_state); |
||
6065 | } |
||
6066 | /* patch flexible array member size back to -1, */ |
||
6067 | /* for possible subsequent similar declarations */ |
||
6068 | if (flexible_array) |
||
6069 | flexible_array->type.ref->c = -1; |
||
6070 | } |
||
6071 | no_alloc: ; |
||
6072 | } |
||
6073 | |||
6074 | static void put_func_debug(Sym *sym) |
||
6075 | { |
||
6076 | char buf[512]; |
||
6077 | |||
6078 | /* stabs info */ |
||
6079 | /* XXX: we put here a dummy type */ |
||
6080 | snprintf(buf, sizeof(buf), "%s:%c1", |
||
6081 | funcname, sym->type.t & VT_STATIC ? 'f' : 'F'); |
||
6082 | put_stabs_r(buf, N_FUN, 0, file->line_num, 0, |
||
6083 | cur_text_section, sym->c); |
||
6084 | /* //gr gdb wants a line at the function */ |
||
6085 | put_stabn(N_SLINE, 0, file->line_num, 0); |
||
6086 | last_ind = 0; |
||
6087 | last_line_num = 0; |
||
6088 | } |
||
6089 | |||
6090 | /* parse an old style function declaration list */ |
||
6091 | /* XXX: check multiple parameter */ |
||
6092 | static void func_decl_list(Sym *func_sym) |
||
6093 | { |
||
6094 | AttributeDef ad; |
||
6095 | int v; |
||
6096 | Sym *s; |
||
6097 | CType btype, type; |
||
6098 | |||
6099 | /* parse each declaration */ |
||
6100 | while (tok != '{' && tok != ';' && tok != ',' && tok != TOK_EOF && |
||
6101 | tok != TOK_ASM1 && tok != TOK_ASM2 && tok != TOK_ASM3) { |
||
6102 | if (!parse_btype(&btype, &ad)) |
||
6103 | expect("declaration list"); |
||
6104 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
6105 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
6106 | tok == ';') { |
||
6107 | /* we accept no variable after */ |
||
6108 | } else { |
||
6109 | for(;;) { |
||
6110 | type = btype; |
||
6111 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
6112 | /* find parameter in function parameter list */ |
||
6113 | s = func_sym->next; |
||
6114 | while (s != NULL) { |
||
6115 | if ((s->v & ~SYM_FIELD) == v) |
||
6116 | goto found; |
||
6117 | s = s->next; |
||
6118 | } |
||
6119 | tcc_error("declaration for parameter '%s' but no such parameter", |
||
6120 | get_tok_str(v, NULL)); |
||
6121 | found: |
||
6122 | /* check that no storage specifier except 'register' was given */ |
||
6123 | if (type.t & VT_STORAGE) |
||
6124 | tcc_error("storage class specified for '%s'", get_tok_str(v, NULL)); |
||
6125 | convert_parameter_type(&type); |
||
6126 | /* we can add the type (NOTE: it could be local to the function) */ |
||
6127 | s->type = type; |
||
6128 | /* accept other parameters */ |
||
6129 | if (tok == ',') |
||
6130 | next(); |
||
6131 | else |
||
6132 | break; |
||
6133 | } |
||
6134 | } |
||
6135 | skip(';'); |
||
6136 | } |
||
6137 | } |
||
6138 | |||
6139 | /* parse a function defined by symbol 'sym' and generate its code in |
||
6140 | 'cur_text_section' */ |
||
6141 | static void gen_function(Sym *sym) |
||
6142 | { |
||
6143 | int saved_nocode_wanted = nocode_wanted; |
||
6144 | |||
6145 | nocode_wanted = 0; |
||
6146 | ind = cur_text_section->data_offset; |
||
6147 | /* NOTE: we patch the symbol size later */ |
||
6148 | put_extern_sym(sym, cur_text_section, ind, 0); |
||
6149 | funcname = get_tok_str(sym->v, NULL); |
||
6150 | func_ind = ind; |
||
6151 | /* Initialize VLA state */ |
||
6152 | vla_sp_loc = -1; |
||
6153 | vla_sp_root_loc = -1; |
||
6154 | /* put debug symbol */ |
||
6155 | if (tcc_state->do_debug) |
||
6156 | put_func_debug(sym); |
||
6157 | /* push a dummy symbol to enable local sym storage */ |
||
6158 | sym_push2(&local_stack, SYM_FIELD, 0, 0); |
||
6159 | gfunc_prolog(&sym->type); |
||
6160 | #ifdef CONFIG_TCC_BCHECK |
||
6161 | if (tcc_state->do_bounds_check && !strcmp(funcname, "main")) { |
||
6162 | int i; |
||
6163 | Sym *sym; |
||
6164 | for (i = 0, sym = local_stack; i < 2; i++, sym = sym->prev) { |
||
6165 | if (sym->v & SYM_FIELD || sym->prev->v & SYM_FIELD) |
||
6166 | break; |
||
6167 | vpush_global_sym(&func_old_type, TOK___bound_main_arg); |
||
6168 | vset(&sym->type, sym->r, sym->c); |
||
6169 | gfunc_call(1); |
||
6170 | } |
||
6171 | } |
||
6172 | #endif |
||
6173 | rsym = 0; |
||
6174 | block(NULL, NULL, NULL, NULL, 0, 0); |
||
6175 | gsym(rsym); |
||
6176 | gfunc_epilog(); |
||
6177 | cur_text_section->data_offset = ind; |
||
6178 | label_pop(&global_label_stack, NULL); |
||
6179 | /* reset local stack */ |
||
6180 | scope_stack_bottom = NULL; |
||
6181 | sym_pop(&local_stack, NULL); |
||
6182 | /* end of function */ |
||
6183 | /* patch symbol size */ |
||
6184 | ((ElfW(Sym) *)symtab_section->data)[sym->c].st_size = |
||
6185 | ind - func_ind; |
||
6186 | /* patch symbol weakness (this definition overrules any prototype) */ |
||
6187 | if (sym->type.t & VT_WEAK) |
||
6188 | weaken_symbol(sym); |
||
6189 | apply_visibility(sym, &sym->type); |
||
6190 | if (tcc_state->do_debug) { |
||
6191 | put_stabn(N_FUN, 0, 0, ind - func_ind); |
||
6192 | } |
||
6193 | /* It's better to crash than to generate wrong code */ |
||
6194 | cur_text_section = NULL; |
||
6195 | funcname = ""; /* for safety */ |
||
6196 | func_vt.t = VT_VOID; /* for safety */ |
||
6197 | func_var = 0; /* for safety */ |
||
6198 | ind = 0; /* for safety */ |
||
6199 | nocode_wanted = saved_nocode_wanted; |
||
6200 | check_vstack(); |
||
6201 | } |
||
6202 | |||
6203 | ST_FUNC void gen_inline_functions(void) |
||
6204 | { |
||
6205 | Sym *sym; |
||
6206 | int inline_generated, i, ln; |
||
6207 | struct InlineFunc *fn; |
||
6208 | |||
6209 | ln = file->line_num; |
||
6210 | /* iterate while inline function are referenced */ |
||
6211 | for(;;) { |
||
6212 | inline_generated = 0; |
||
6213 | for (i = 0; i < tcc_state->nb_inline_fns; ++i) { |
||
6214 | fn = tcc_state->inline_fns[i]; |
||
6215 | sym = fn->sym; |
||
6216 | if (sym && sym->c) { |
||
6217 | /* the function was used: generate its code and |
||
6218 | convert it to a normal function */ |
||
6219 | fn->sym = NULL; |
||
6220 | if (file) |
||
6221 | pstrcpy(file->filename, sizeof file->filename, fn->filename); |
||
6222 | sym->r = VT_SYM | VT_CONST; |
||
6223 | sym->type.t &= ~VT_INLINE; |
||
6224 | |||
6225 | begin_macro(&fn->func_str, 0); |
||
6226 | next(); |
||
6227 | cur_text_section = text_section; |
||
6228 | gen_function(sym); |
||
6229 | end_macro(); |
||
6230 | |||
6231 | inline_generated = 1; |
||
6232 | } |
||
6233 | } |
||
6234 | if (!inline_generated) |
||
6235 | break; |
||
6236 | } |
||
6237 | file->line_num = ln; |
||
6238 | /* free tokens of unused inline functions */ |
||
6239 | for (i = 0; i < tcc_state->nb_inline_fns; ++i) { |
||
6240 | fn = tcc_state->inline_fns[i]; |
||
6241 | if (fn->sym) |
||
6242 | tok_str_free(fn->func_str.str); |
||
6243 | } |
||
6244 | dynarray_reset(&tcc_state->inline_fns, &tcc_state->nb_inline_fns); |
||
6245 | } |
||
6246 | |||
6247 | /* 'l' is VT_LOCAL or VT_CONST to define default storage type */ |
||
6248 | static int decl0(int l, int is_for_loop_init) |
||
6249 | { |
||
6250 | int v, has_init, r; |
||
6251 | CType type, btype; |
||
6252 | Sym *sym; |
||
6253 | AttributeDef ad; |
||
6254 | |||
6255 | while (1) { |
||
6256 | if (!parse_btype(&btype, &ad)) { |
||
6257 | if (is_for_loop_init) |
||
6258 | return 0; |
||
6259 | /* skip redundant ';' */ |
||
6260 | /* XXX: find more elegant solution */ |
||
6261 | if (tok == ';') { |
||
6262 | next(); |
||
6263 | continue; |
||
6264 | } |
||
6265 | if (l == VT_CONST && |
||
6266 | (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
||
6267 | /* global asm block */ |
||
6268 | asm_global_instr(); |
||
6269 | continue; |
||
6270 | } |
||
6271 | /* special test for old K&R protos without explicit int |
||
6272 | type. Only accepted when defining global data */ |
||
6273 | if (l == VT_LOCAL || tok < TOK_DEFINE) |
||
6274 | break; |
||
6275 | btype.t = VT_INT; |
||
6276 | } |
||
6277 | if (((btype.t & VT_BTYPE) == VT_ENUM || |
||
6278 | (btype.t & VT_BTYPE) == VT_STRUCT) && |
||
6279 | tok == ';') { |
||
6280 | if ((btype.t & VT_BTYPE) == VT_STRUCT) { |
||
6281 | int v = btype.ref->v; |
||
6282 | if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM) |
||
6283 | tcc_warning("unnamed struct/union that defines no instances"); |
||
6284 | } |
||
6285 | next(); |
||
6286 | continue; |
||
6287 | } |
||
6288 | while (1) { /* iterate thru each declaration */ |
||
6289 | type = btype; |
||
6290 | type_decl(&type, &ad, &v, TYPE_DIRECT); |
||
6291 | #if 0 |
||
6292 | { |
||
6293 | char buf[500]; |
||
6294 | type_to_str(buf, sizeof(buf), t, get_tok_str(v, NULL)); |
||
6295 | printf("type = '%s'\n", buf); |
||
6296 | } |
||
6297 | #endif |
||
6298 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
6299 | if ((type.t & VT_STATIC) && (l == VT_LOCAL)) { |
||
6300 | tcc_error("function without file scope cannot be static"); |
||
6301 | } |
||
6302 | /* if old style function prototype, we accept a |
||
6303 | declaration list */ |
||
6304 | sym = type.ref; |
||
6305 | if (sym->c == FUNC_OLD) |
||
6306 | func_decl_list(sym); |
||
6307 | } |
||
6308 | |||
6309 | if (gnu_ext && (tok == TOK_ASM1 || tok == TOK_ASM2 || tok == TOK_ASM3)) { |
||
6310 | ad.asm_label = asm_label_instr(); |
||
6311 | /* parse one last attribute list, after asm label */ |
||
6312 | parse_attribute(&ad); |
||
6313 | if (tok == '{') |
||
6314 | expect(";"); |
||
6315 | } |
||
6316 | |||
6317 | if (ad.a.weak) |
||
6318 | type.t |= VT_WEAK; |
||
9782 | Coldy | 6319 | #if defined(TCC_TARGET_PE) || defined(TCC_TARGET_KX) |
6429 | siemargl | 6320 | if (ad.a.func_import) |
6321 | type.t |= VT_IMPORT; |
||
6322 | if (ad.a.func_export) |
||
6323 | type.t |= VT_EXPORT; |
||
6324 | #endif |
||
6325 | type.t |= ad.a.visibility << VT_VIS_SHIFT; |
||
6326 | |||
6327 | if (tok == '{') { |
||
6328 | if (l == VT_LOCAL) |
||
6329 | tcc_error("cannot use local functions"); |
||
6330 | if ((type.t & VT_BTYPE) != VT_FUNC) |
||
6331 | expect("function definition"); |
||
6332 | |||
6333 | /* reject abstract declarators in function definition */ |
||
6334 | sym = type.ref; |
||
6335 | while ((sym = sym->next) != NULL) |
||
6336 | if (!(sym->v & ~SYM_FIELD)) |
||
6337 | expect("identifier"); |
||
6338 | |||
6339 | /* XXX: cannot do better now: convert extern line to static inline */ |
||
6340 | if ((type.t & (VT_EXTERN | VT_INLINE)) == (VT_EXTERN | VT_INLINE)) |
||
6341 | type.t = (type.t & ~VT_EXTERN) | VT_STATIC; |
||
6342 | |||
6343 | sym = sym_find(v); |
||
6344 | if (sym) { |
||
6345 | Sym *ref; |
||
6346 | if ((sym->type.t & VT_BTYPE) != VT_FUNC) |
||
6347 | goto func_error1; |
||
6348 | |||
6349 | ref = sym->type.ref; |
||
6350 | if (0 == ref->a.func_proto) |
||
6351 | tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); |
||
6352 | |||
6353 | /* use func_call from prototype if not defined */ |
||
6354 | if (ref->a.func_call != FUNC_CDECL |
||
6355 | && type.ref->a.func_call == FUNC_CDECL) |
||
6356 | type.ref->a.func_call = ref->a.func_call; |
||
6357 | |||
6358 | /* use export from prototype */ |
||
6359 | if (ref->a.func_export) |
||
6360 | type.ref->a.func_export = 1; |
||
6361 | |||
6362 | /* use static from prototype */ |
||
6363 | if (sym->type.t & VT_STATIC) |
||
6364 | type.t = (type.t & ~VT_EXTERN) | VT_STATIC; |
||
6365 | |||
6366 | /* If the definition has no visibility use the |
||
6367 | one from prototype. */ |
||
6368 | if (! (type.t & VT_VIS_MASK)) |
||
6369 | type.t |= sym->type.t & VT_VIS_MASK; |
||
6370 | |||
6371 | if (!is_compatible_types(&sym->type, &type)) { |
||
6372 | func_error1: |
||
6373 | tcc_error("incompatible types for redefinition of '%s'", |
||
6374 | get_tok_str(v, NULL)); |
||
6375 | } |
||
6376 | type.ref->a.func_proto = 0; |
||
6377 | /* if symbol is already defined, then put complete type */ |
||
6378 | sym->type = type; |
||
6379 | } else { |
||
6380 | /* put function symbol */ |
||
6381 | sym = global_identifier_push(v, type.t, 0); |
||
6382 | sym->type.ref = type.ref; |
||
6383 | } |
||
6384 | |||
6385 | /* static inline functions are just recorded as a kind |
||
6386 | of macro. Their code will be emitted at the end of |
||
6387 | the compilation unit only if they are used */ |
||
6388 | if ((type.t & (VT_INLINE | VT_STATIC)) == |
||
6389 | (VT_INLINE | VT_STATIC)) { |
||
6390 | int block_level; |
||
6391 | struct InlineFunc *fn; |
||
6392 | const char *filename; |
||
6393 | |||
6394 | filename = file ? file->filename : ""; |
||
6395 | fn = tcc_malloc(sizeof *fn + strlen(filename)); |
||
6396 | strcpy(fn->filename, filename); |
||
6397 | fn->sym = sym; |
||
6398 | tok_str_new(&fn->func_str); |
||
6399 | |||
6400 | block_level = 0; |
||
6401 | for(;;) { |
||
6402 | int t; |
||
6403 | if (tok == TOK_EOF) |
||
6404 | tcc_error("unexpected end of file"); |
||
6405 | tok_str_add_tok(&fn->func_str); |
||
6406 | t = tok; |
||
6407 | next(); |
||
6408 | if (t == '{') { |
||
6409 | block_level++; |
||
6410 | } else if (t == '}') { |
||
6411 | block_level--; |
||
6412 | if (block_level == 0) |
||
6413 | break; |
||
6414 | } |
||
6415 | } |
||
6416 | tok_str_add(&fn->func_str, -1); |
||
6417 | tok_str_add(&fn->func_str, 0); |
||
6418 | dynarray_add((void ***)&tcc_state->inline_fns, &tcc_state->nb_inline_fns, fn); |
||
6419 | |||
6420 | } else { |
||
6421 | /* compute text section */ |
||
6422 | cur_text_section = ad.section; |
||
6423 | if (!cur_text_section) |
||
6424 | cur_text_section = text_section; |
||
6425 | sym->r = VT_SYM | VT_CONST; |
||
6426 | gen_function(sym); |
||
6427 | } |
||
6428 | break; |
||
6429 | } else { |
||
6430 | if (btype.t & VT_TYPEDEF) { |
||
6431 | /* save typedefed type */ |
||
6432 | /* XXX: test storage specifiers ? */ |
||
6433 | sym = sym_push(v, &type, 0, 0); |
||
6434 | sym->a = ad.a; |
||
6435 | sym->type.t |= VT_TYPEDEF; |
||
6436 | } else { |
||
6437 | r = 0; |
||
6438 | if ((type.t & VT_BTYPE) == VT_FUNC) { |
||
6439 | /* external function definition */ |
||
6440 | /* specific case for func_call attribute */ |
||
6441 | ad.a.func_proto = 1; |
||
6442 | type.ref->a = ad.a; |
||
6443 | } else if (!(type.t & VT_ARRAY)) { |
||
6444 | /* not lvalue if array */ |
||
6445 | r |= lvalue_type(type.t); |
||
6446 | } |
||
6447 | has_init = (tok == '='); |
||
6448 | if (has_init && (type.t & VT_VLA)) |
||
6449 | tcc_error("Variable length array cannot be initialized"); |
||
6450 | if ((btype.t & VT_EXTERN) || ((type.t & VT_BTYPE) == VT_FUNC) || |
||
6451 | ((type.t & VT_ARRAY) && (type.t & VT_STATIC) && |
||
6452 | !has_init && l == VT_CONST && type.ref->c < 0)) { |
||
6453 | /* external variable or function */ |
||
6454 | /* NOTE: as GCC, uninitialized global static |
||
6455 | arrays of null size are considered as |
||
6456 | extern */ |
||
6457 | sym = external_sym(v, &type, r); |
||
6458 | sym->asm_label = ad.asm_label; |
||
6459 | |||
6460 | if (ad.alias_target) { |
||
6461 | Section tsec; |
||
6462 | Elf32_Sym *esym; |
||
6463 | Sym *alias_target; |
||
6464 | |||
6465 | alias_target = sym_find(ad.alias_target); |
||
6466 | if (!alias_target || !alias_target->c) |
||
6467 | tcc_error("unsupported forward __alias__ attribute"); |
||
6468 | esym = &((Elf32_Sym *)symtab_section->data)[alias_target->c]; |
||
6469 | tsec.sh_num = esym->st_shndx; |
||
6470 | put_extern_sym2(sym, &tsec, esym->st_value, esym->st_size, 0); |
||
6471 | } |
||
6472 | } else { |
||
6473 | type.t |= (btype.t & VT_STATIC); /* Retain "static". */ |
||
6474 | if (type.t & VT_STATIC) |
||
6475 | r |= VT_CONST; |
||
6476 | else |
||
6477 | r |= l; |
||
6478 | if (has_init) |
||
6479 | next(); |
||
6480 | decl_initializer_alloc(&type, &ad, r, has_init, v, l); |
||
6481 | } |
||
6482 | } |
||
6483 | if (tok != ',') { |
||
6484 | if (is_for_loop_init) |
||
6485 | return 1; |
||
6486 | skip(';'); |
||
6487 | break; |
||
6488 | } |
||
6489 | next(); |
||
6490 | } |
||
6491 | ad.a.aligned = 0; |
||
6492 | } |
||
6493 | } |
||
6494 | return 0; |
||
6495 | } |
||
6496 | |||
6497 | ST_FUNC void decl(int l) |
||
6498 | { |
||
6499 | decl0(l, 0); |
||
6500 | }>><>>>>>>>=>>>>>>>>>>>><>><>><>><>><>><>>>>>>=><=>>>=>=>>=>>>>>>><>><>>>>>>>>=>>><>><>><>><>><>><>><>><>>>><>><>=>>>=>><>=>>=><=>><>>><>4;i++) |