diff options
| author | jiang <30155751@qq.com> | 2014-04-29 16:05:16 +0800 |
|---|---|---|
| committer | jiang <30155751@qq.com> | 2014-04-29 16:05:16 +0800 |
| commit | 2a8905c93b4f67a21e3dbf297c3e93c598831528 (patch) | |
| tree | 6f7491150cfe01700c9863946906203adad0de13 /tccgen.c | |
| parent | 02e2fe3c260415f4cb1cbcaca9b2403a17f7ff2e (diff) | |
| parent | e20c1eb99e1003c1e59522c136dbb15c52d7cc7c (diff) | |
| download | tinycc-2a8905c93b4f67a21e3dbf297c3e93c598831528.tar.gz tinycc-2a8905c93b4f67a21e3dbf297c3e93c598831528.tar.bz2 | |
So that the generated code, and more short
Diffstat (limited to 'tccgen.c')
| -rw-r--r-- | tccgen.c | 514 |
1 files changed, 357 insertions, 157 deletions
@@ -66,6 +66,7 @@ ST_DATA int const_wanted; /* true if constant wanted */ ST_DATA int nocode_wanted; /* true if no code generation wanted for an expression */ ST_DATA int global_expr; /* true if compound literals must be allocated globally (used during initializers parsing */ ST_DATA CType func_vt; /* current function return type (used by return instruction) */ +ST_DATA int func_var; /* true if current function is variadic (used by return instruction) */ ST_DATA int func_vc; ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc */ ST_DATA char *funcname; @@ -89,6 +90,10 @@ static void vla_runtime_type_size(CType *type, int *a); static void vla_sp_save(void); static int is_compatible_parameter_types(CType *type1, CType *type2); static void expr_type(CType *type); +ST_FUNC void vpush64(int ty, unsigned long long v); +ST_FUNC void vpush(CType *type); +ST_FUNC int gvtst(int inv, int t); +ST_FUNC int is_btype_size(int bt); ST_INLN int is_float(int t) { @@ -102,7 +107,8 @@ ST_INLN int is_float(int t) /* XXX: endianness dependent */ ST_FUNC int ieee_finite(double d) { - int *p = (int *)&d; + int p[4]; + memcpy(p, &d, sizeof(double)); return ((unsigned)((p[1] | 0x800fffff) + 1)) >> 31; } @@ -160,7 +166,6 @@ ST_FUNC Sym *sym_push2(Sym **ps, int v, int t, long c) tcc_error("incompatible types for redefinition of '%s'", get_tok_str(v, NULL)); } - s = *ps; s = sym_malloc(); s->asm_label = NULL; s->v = v; @@ -184,6 +189,8 @@ ST_FUNC Sym *sym_find2(Sym *s, int v) while (s) { if (s->v == v) return s; + else if (s->v == -1) + return NULL; s = s->prev; } return NULL; @@ -293,6 +300,28 @@ static void weaken_symbol(Sym *sym) } } +static void apply_visibility(Sym *sym, CType *type) +{ + int vis = sym->type.t & VT_VIS_MASK; + int vis2 = type->t & VT_VIS_MASK; + if (vis == (STV_DEFAULT << VT_VIS_SHIFT)) + vis = vis2; + else if (vis2 == (STV_DEFAULT << VT_VIS_SHIFT)) + ; + else + vis = (vis < vis2) ? vis : vis2; + sym->type.t &= ~VT_VIS_MASK; + sym->type.t |= vis; + + if (sym->c > 0) { + ElfW(Sym) *esym; + + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + vis >>= VT_VIS_SHIFT; + esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) | vis; + } +} + /* ------------------------------------------------------------------------- */ ST_FUNC void swap(int *p, int *q) @@ -308,7 +337,7 @@ static void vsetc(CType *type, int r, CValue *vc) int v; if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full"); + tcc_error("memory full (vstack)"); /* cannot let cpu flags if other instruction are generated. Also avoid leaving VT_JMP anywhere except on the top of the stack because it would complicate the code generator. */ @@ -325,7 +354,7 @@ static void vsetc(CType *type, int r, CValue *vc) } /* push constant of type "type" with useless value */ -void vpush(CType *type) +ST_FUNC void vpush(CType *type) { CValue cval; vsetc(type, VT_CONST, &cval); @@ -340,18 +369,15 @@ ST_FUNC void vpushi(int v) } /* push a pointer sized constant */ -static void vpushs(long long v) +static void vpushs(addr_t v) { CValue cval; - if (PTR_SIZE == 4) - cval.i = (int)v; - else - cval.ull = v; + cval.ptr_offset = v; vsetc(&size_type, VT_CONST, &cval); } /* push arbitrary 64bit constant */ -void vpush64(int ty, unsigned long long v) +ST_FUNC void vpush64(int ty, unsigned long long v) { CValue cval; CType ctype; @@ -367,6 +393,15 @@ static inline void vpushll(long long v) vpush64(VT_LLONG, v); } +/* push a symbol value of TYPE */ +static inline void vpushsym(CType *type, Sym *sym) +{ + CValue cval; + cval.ptr_offset = 0; + vsetc(type, VT_CONST | VT_SYM, &cval); + vtop->sym = sym; +} + /* Return a static symbol pointing to a section */ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) { @@ -384,11 +419,7 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign /* push a reference to a section offset by adding a dummy symbol */ static void vpush_ref(CType *type, Section *sec, unsigned long offset, unsigned long size) { - CValue cval; - - cval.ul = 0; - vsetc(type, VT_CONST | VT_SYM, &cval); - vtop->sym = get_sym_ref(type, sec, offset, size); + vpushsym(type, get_sym_ref(type, sec, offset, size)); } /* define a new external reference to a symbol 'v' of type 'u' */ @@ -427,19 +458,20 @@ static Sym *external_sym(int v, CType *type, int r, char *asm_label) tcc_error("incompatible types for redefinition of '%s'", get_tok_str(v, NULL)); } + /* Merge some storage attributes. */ + if (type->t & VT_WEAK) + weaken_symbol(s); + + if (type->t & VT_VIS_MASK) + apply_visibility(s, type); + return s; } /* push a reference to global symbol v */ ST_FUNC void vpush_global_sym(CType *type, int v) { - Sym *sym; - CValue cval; - - sym = external_global_sym(v, type, 0); - cval.ul = 0; - vsetc(type, VT_CONST | VT_SYM, &cval); - vtop->sym = sym; + vpushsym(type, external_global_sym(v, type, 0)); } ST_FUNC void vset(CType *type, int r, int v) @@ -482,7 +514,7 @@ ST_FUNC void vswap(void) ST_FUNC void vpushv(SValue *v) { if (vtop >= vstack + (VSTACK_SIZE - 1)) - tcc_error("memory full"); + tcc_error("memory full (vstack)"); vtop++; *vtop = *v; } @@ -762,7 +794,7 @@ ST_FUNC int gv(int rc) sym = get_sym_ref(&vtop->type, data_section, offset, size << 2); vtop->r |= VT_LVAL | VT_SYM; vtop->sym = sym; - vtop->c.ul = 0; + vtop->c.ptr_offset = 0; } #ifdef CONFIG_TCC_BCHECK if (vtop->r & VT_MUSTBOUND) @@ -800,9 +832,9 @@ ST_FUNC int gv(int rc) #else if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { int addr_type = VT_INT, load_size = 4, load_type = VT_INT; + unsigned long long ll; #endif int r2, original_type; - unsigned long long ll; original_type = vtop->type.t; /* two register type load : expand to two words temporarily */ @@ -947,7 +979,7 @@ static void lexpand(void) { int u; - u = vtop->type.t & VT_UNSIGNED; + u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); gv(RC_INT); vdup(); vtop[0].r = vtop[-1].r2; @@ -963,7 +995,7 @@ ST_FUNC void lexpand_nr(void) { int u,v; - u = vtop->type.t & VT_UNSIGNED; + u = vtop->type.t & (VT_DEFSIGN | VT_UNSIGNED); vdup(); vtop->r2 = VT_CONST; vtop->type.t = VT_INT | u; @@ -1095,6 +1127,26 @@ static void gv_dup(void) } } +/* Generate value test + * + * Generate a test for any value (jump, comparison and integers) */ +ST_FUNC int gvtst(int inv, int t) +{ + int v = vtop->r & VT_VALMASK; + if (v != VT_CMP && v != VT_JMP && v != VT_JMPI) { + vpushi(0); + gen_op(TOK_NE); + } + if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { + /* constant jmp optimization */ + if ((vtop->c.i != 0) != inv) + t = gjmp(t); + vtop--; + return t; + } + return gtst(inv, t); +} + #ifndef TCC_TARGET_X86_64 /* generate CPU independent (unsigned) long long operations */ static void gen_opl(int op) @@ -1293,13 +1345,13 @@ static void gen_opl(int op) b = 0; gen_op(op1); if (op1 != TOK_NE) { - a = gtst(1, 0); + a = gvtst(1, 0); } if (op != TOK_EQ) { /* generate non equal test */ /* XXX: NOT PORTABLE yet */ if (a == 0) { - b = gtst(0, 0); + b = gvtst(0, 0); } else { #if defined(TCC_TARGET_I386) b = psym(0x850f, 0); @@ -1324,7 +1376,7 @@ static void gen_opl(int op) else if (op1 == TOK_GE) op1 = TOK_UGE; gen_op(op1); - a = gtst(1, a); + a = gvtst(1, a); gsym(b); vseti(VT_JMPI, a); break; @@ -1553,7 +1605,7 @@ static inline int is_null_pointer(SValue *p) return 0; return ((p->type.t & VT_BTYPE) == VT_INT && p->c.i == 0) || ((p->type.t & VT_BTYPE) == VT_LLONG && p->c.ll == 0) || - ((p->type.t & VT_BTYPE) == VT_PTR && p->c.ptr == 0); + ((p->type.t & VT_BTYPE) == VT_PTR && p->c.ptr_offset == 0); } static inline int is_integer_btype(int bt) @@ -1562,7 +1614,7 @@ static inline int is_integer_btype(int bt) bt == VT_INT || bt == VT_LLONG); } -/* check types for comparison or substraction of pointers */ +/* check types for comparison or subtraction of pointers */ static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) { CType *type1, *type2, tmp_type1, tmp_type2; @@ -1599,8 +1651,8 @@ static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) return; tmp_type1 = *type1; tmp_type2 = *type2; - tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); - tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); + tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); + tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); if (!is_compatible_types(&tmp_type1, &tmp_type2)) { /* gcc-like error if '-' is used */ if (op == '-') @@ -1927,13 +1979,16 @@ static void gen_cast(CType *type) vtop->c.ull = vtop->c.ll; else if (dbt == VT_BOOL) vtop->c.i = (vtop->c.ll != 0); +#ifdef TCC_TARGET_X86_64 + else if (dbt == VT_PTR) + ; +#endif else if (dbt != VT_LLONG) { int s = 0; if ((dbt & VT_BTYPE) == VT_BYTE) s = 24; else if ((dbt & VT_BTYPE) == VT_SHORT) s = 16; - if(dbt & VT_UNSIGNED) vtop->c.ui = ((unsigned int)vtop->c.ll << s) >> s; else @@ -2151,7 +2206,7 @@ static int is_compatible_func(CType *type1, CType *type2) if (!is_compatible_types(&s1->type, &s2->type)) return 0; /* check func_call */ - if (FUNC_CALL(s1->r) != FUNC_CALL(s2->r)) + if (s1->a.func_call != s2->a.func_call) return 0; /* XXX: not complete */ if (s1->c == FUNC_OLD || s2->c == FUNC_OLD) @@ -2187,6 +2242,11 @@ static int compare_types(CType *type1, CType *type2, int unqualified) t1 &= ~(VT_CONSTANT | VT_VOLATILE); t2 &= ~(VT_CONSTANT | VT_VOLATILE); } + /* Default Vs explicit signedness only matters for char */ + if ((t1 & VT_BTYPE) != VT_BYTE) { + t1 &= ~VT_DEFSIGN; + t2 &= ~VT_DEFSIGN; + } /* XXX: bitfields ? */ if (t1 != t2) return 0; @@ -2239,8 +2299,10 @@ static void type_to_str(char *buf, int buf_size, pstrcat(buf, buf_size, "const "); if (t & VT_VOLATILE) pstrcat(buf, buf_size, "volatile "); - if (t & VT_UNSIGNED) + if ((t & (VT_DEFSIGN | VT_UNSIGNED)) == (VT_DEFSIGN | VT_UNSIGNED)) pstrcat(buf, buf_size, "unsigned "); + else if (t & VT_DEFSIGN) + pstrcat(buf, buf_size, "signed "); switch(bt) { case VT_VOID: tstr = "void"; @@ -2327,8 +2389,8 @@ static void gen_assign_cast(CType *dt) st = &vtop->type; /* source type */ dbt = dt->t & VT_BTYPE; sbt = st->t & VT_BTYPE; - if (sbt == VT_VOID) - tcc_error("Cannot assign void value"); + if (sbt == VT_VOID || dbt == VT_VOID) + tcc_error("cannot cast from/to void"); if (dt->t & VT_CONSTANT) tcc_warning("assignment of read-only location"); switch(dbt) { @@ -2360,8 +2422,10 @@ static void gen_assign_cast(CType *dt) /* exact type match, except for unsigned */ tmp_type1 = *type1; tmp_type2 = *type2; - tmp_type1.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); - tmp_type2.t &= ~(VT_UNSIGNED | VT_CONSTANT | VT_VOLATILE); + tmp_type1.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | + VT_VOLATILE); + tmp_type2.t &= ~(VT_DEFSIGN | VT_UNSIGNED | VT_CONSTANT | + VT_VOLATILE); if (!is_compatible_types(&tmp_type1, &tmp_type2)) tcc_warning("assignment from incompatible pointer type"); } @@ -2627,6 +2691,24 @@ static void parse_attribute(AttributeDef *ad) next(); skip(')'); break; + case TOK_VISIBILITY1: + case TOK_VISIBILITY2: + skip('('); + if (tok != TOK_STR) + expect("visibility(\"default|hidden|internal|protected\")"); + if (!strcmp (tokc.cstr->data, "default")) + ad->a.visibility = STV_DEFAULT; + else if (!strcmp (tokc.cstr->data, "hidden")) + ad->a.visibility = STV_HIDDEN; + else if (!strcmp (tokc.cstr->data, "internal")) + ad->a.visibility = STV_INTERNAL; + else if (!strcmp (tokc.cstr->data, "protected")) + ad->a.visibility = STV_PROTECTED; + else + expect("visibility(\"default|hidden|internal|protected\")"); + next(); + skip(')'); + break; case TOK_ALIGNED1: case TOK_ALIGNED2: if (tok == '(') { @@ -2638,15 +2720,15 @@ static void parse_attribute(AttributeDef *ad) } else { n = MAX_ALIGN; } - ad->aligned = n; + ad->a.aligned = n; break; case TOK_PACKED1: case TOK_PACKED2: - ad->packed = 1; + ad->a.packed = 1; break; case TOK_WEAK1: case TOK_WEAK2: - ad->weak = 1; + ad->a.weak = 1; break; case TOK_UNUSED1: case TOK_UNUSED2: @@ -2661,12 +2743,12 @@ static void parse_attribute(AttributeDef *ad) case TOK_CDECL1: case TOK_CDECL2: case TOK_CDECL3: - ad->func_call = FUNC_CDECL; + ad->a.func_call = FUNC_CDECL; break; case TOK_STDCALL1: case TOK_STDCALL2: case TOK_STDCALL3: - ad->func_call = FUNC_STDCALL; + ad->a.func_call = FUNC_STDCALL; break; #ifdef TCC_TARGET_I386 case TOK_REGPARM1: @@ -2678,26 +2760,26 @@ static void parse_attribute(AttributeDef *ad) else if (n < 0) n = 0; if (n > 0) - ad->func_call = FUNC_FASTCALL1 + n - 1; + ad->a.func_call = FUNC_FASTCALL1 + n - 1; skip(')'); break; case TOK_FASTCALL1: case TOK_FASTCALL2: case TOK_FASTCALL3: - ad->func_call = FUNC_FASTCALLW; + ad->a.func_call = FUNC_FASTCALLW; break; #endif case TOK_MODE: skip('('); switch(tok) { case TOK_MODE_DI: - ad->mode = VT_LLONG + 1; + ad->a.mode = VT_LLONG + 1; break; case TOK_MODE_HI: - ad->mode = VT_SHORT + 1; + ad->a.mode = VT_SHORT + 1; break; case TOK_MODE_SI: - ad->mode = VT_INT + 1; + ad->a.mode = VT_INT + 1; break; default: tcc_warning("__mode__(%s) not supported\n", get_tok_str(tok, NULL)); @@ -2707,10 +2789,10 @@ static void parse_attribute(AttributeDef *ad) skip(')'); break; case TOK_DLLEXPORT: - ad->func_export = 1; + ad->a.func_export = 1; break; case TOK_DLLIMPORT: - ad->func_import = 1; + ad->a.func_import = 1; break; default: if (tcc_state->warn_unsupported) @@ -2738,9 +2820,9 @@ static void parse_attribute(AttributeDef *ad) } /* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */ -static void struct_decl(CType *type, int u) +static void struct_decl(CType *type, int u, int tdef) { - int a, v, size, align, maxalign, c, offset; + int a, v, size, align, maxalign, c, offset, flexible; int bit_size, bit_pos, bsize, bt, lbit_pos, prevbt; Sym *s, *ss, *ass, **ps; AttributeDef ad; @@ -2759,11 +2841,13 @@ static void struct_decl(CType *type, int u) if (s->type.t != a) tcc_error("invalid type"); goto do_decl; - } + } else if (tok >= TOK_IDENT && !tdef) + tcc_error("unknown struct/union/enum"); } else { v = anon_sym++; } type1.t = a; + type1.ref = NULL; /* we put an undefined size for struct/union */ s = sym_push(v | SYM_STRUCT, &type1, 0, -1); s->r = 0; /* default alignment is zero as gcc */ @@ -2784,6 +2868,10 @@ static void struct_decl(CType *type, int u) v = tok; if (v < TOK_UIDENT) expect("identifier"); + ss = sym_find(v); + if (ss && !local_stack) + tcc_error("redefinition of enumerator '%s'", + get_tok_str(v, NULL)); next(); if (tok == '=') { next(); @@ -2800,6 +2888,7 @@ static void struct_decl(CType *type, int u) if (tok == '}') break; } + s->c = type_size(&int_type, &align); skip('}'); } else { maxalign = 1; @@ -2807,9 +2896,13 @@ static void struct_decl(CType *type, int u) prevbt = VT_INT; bit_pos = 0; offset = 0; + flexible = 0; while (tok != '}') { parse_btype(&btype, &ad); while (1) { + if (flexible) + tcc_error("flexible array member '%s' not at the end of struct", + get_tok_str(v, NULL)); bit_size = -1; v = 0; type1 = btype; @@ -2817,6 +2910,13 @@ static void struct_decl(CType *type, int u) type_decl(&type1, &ad, &v, TYPE_DIRECT | TYPE_ABSTRACT); if (v == 0 && (type1.t & VT_BTYPE) != VT_STRUCT) expect("identifier"); + if (type_size(&type1, &align) < 0) { + if ((a == TOK_STRUCT) && (type1.t & VT_ARRAY) && c) + flexible = 1; + else + tcc_error("field '%s' has incomplete type", + get_tok_str(v, NULL)); + } if ((type1.t & VT_BTYPE) == VT_FUNC || (type1.t & (VT_TYPEDEF | VT_STATIC | VT_EXTERN | VT_INLINE))) tcc_error("invalid type for '%s'", @@ -2834,10 +2934,10 @@ static void struct_decl(CType *type, int u) get_tok_str(v, NULL)); } size = type_size(&type1, &align); - if (ad.aligned) { - if (align < ad.aligned) - align = ad.aligned; - } else if (ad.packed) { + if (ad.a.aligned) { + if (align < ad.a.aligned) + align = ad.a.aligned; + } else if (ad.a.packed) { align = 1; } else if (*tcc_state->pack_stack_ptr) { if (align > *tcc_state->pack_stack_ptr) @@ -2937,19 +3037,25 @@ static void struct_decl(CType *type, int u) } } +/* return 1 if basic type is a type size (short, long, long long) */ +ST_FUNC int is_btype_size(int bt) +{ + return bt == VT_SHORT || bt == VT_LONG || bt == VT_LLONG; +} + /* return 0 if no type declaration. otherwise, return the basic type and skip it. */ static int parse_btype(CType *type, AttributeDef *ad) { - int t, u, type_found, typespec_found, typedef_found; + int t, u, bt_size, complete, type_found, typespec_found; Sym *s; CType type1; memset(ad, 0, sizeof(AttributeDef)); + complete = 0; type_found = 0; typespec_found = 0; - typedef_found = 0; t = 0; while(1) { switch(tok) { @@ -2964,9 +3070,12 @@ static int parse_btype(CType *type, AttributeDef *ad) basic_type: next(); basic_type1: - if ((t & VT_BTYPE) != 0) + if (complete) tcc_error("too many basic types"); t |= u; + bt_size = is_btype_size (u & VT_BTYPE); + if (u == VT_INT || (!bt_size && !(t & VT_TYPEDEF))) + complete = 1; typespec_found = 1; break; case TOK_VOID: @@ -2976,9 +3085,8 @@ static int parse_btype(CType *type, AttributeDef *ad) u = VT_SHORT; goto basic_type; case TOK_INT: - next(); - typespec_found = 1; - break; + u = VT_INT; + goto basic_type; case TOK_LONG: next(); if ((t & VT_BTYPE) == VT_DOUBLE) { @@ -3012,14 +3120,14 @@ static int parse_btype(CType *type, AttributeDef *ad) } break; case TOK_ENUM: - struct_decl(&type1, VT_ENUM); + struct_decl(&type1, VT_ENUM, t & VT_TYPEDEF); basic_type2: u = type1.t; type->ref = type1.ref; goto basic_type1; case TOK_STRUCT: case TOK_UNION: - struct_decl(&type1, VT_STRUCT); + struct_decl(&type1, VT_STRUCT, t & VT_TYPEDEF); goto basic_type2; /* type modifiers */ @@ -3038,8 +3146,10 @@ static int parse_btype(CType *type, AttributeDef *ad) case TOK_SIGNED1: case TOK_SIGNED2: case TOK_SIGNED3: + if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == (VT_DEFSIGN|VT_UNSIGNED)) + tcc_error("signed and unsigned modifier"); typespec_found = 1; - t |= VT_SIGNED; + t |= VT_DEFSIGN; next(); break; case TOK_REGISTER: @@ -3050,7 +3160,9 @@ static int parse_btype(CType *type, AttributeDef *ad) next(); break; case TOK_UNSIGNED: - t |= VT_UNSIGNED; + if ((t & (VT_DEFSIGN|VT_UNSIGNED)) == VT_DEFSIGN) + tcc_error("signed and unsigned modifier"); + t |= VT_DEFSIGN | VT_UNSIGNED; next(); typespec_found = 1; break; @@ -3079,8 +3191,8 @@ static int parse_btype(CType *type, AttributeDef *ad) case TOK_ATTRIBUTE1: case TOK_ATTRIBUTE2: parse_attribute(ad); - if (ad->mode) { - u = ad->mode -1; + if (ad->a.mode) { + u = ad->a.mode -1; t = (t & ~VT_BTYPE) | u; } break; @@ -3094,21 +3206,20 @@ static int parse_btype(CType *type, AttributeDef *ad) type1.t &= ~(VT_STORAGE&~VT_TYPEDEF); goto basic_type2; default: - if (typespec_found || typedef_found) + if (typespec_found) goto the_end; s = sym_find(tok); if (!s || !(s->type.t & VT_TYPEDEF)) goto the_end; - typedef_found = 1; t |= (s->type.t & ~VT_TYPEDEF); type->ref = s->type.ref; if (s->r) { /* get attributes from typedef */ - if (0 == ad->aligned) - ad->aligned = FUNC_ALIGN(s->r); - if (0 == ad->func_call) - ad->func_call = FUNC_CALL(s->r); - ad->packed |= FUNC_PACKED(s->r); + if (0 == ad->a.aligned) + ad->a.aligned = s->a.aligned; + if (0 == ad->a.func_call) + ad->a.func_call = s->a.func_call; + ad->a.packed |= s->a.packed; } next(); typespec_found = 1; @@ -3117,13 +3228,10 @@ static int parse_btype(CType *type, AttributeDef *ad) type_found = 1; } the_end: - if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED)) - tcc_error("signed and unsigned modifier"); if (tcc_state->char_is_unsigned) { - if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE) + if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) t |= VT_UNSIGNED; } - t &= ~VT_SIGNED; /* long is never used as type */ if ((t & VT_BTYPE) == VT_LONG) @@ -3248,8 +3356,9 @@ static void post_type(CType *type, AttributeDef *ad) type->t |= VT_PTR; } /* we push a anonymous symbol which will contain the function prototype */ - ad->func_args = arg_size; - s = sym_push(SYM_FIELD, type, INT_ATTR(ad), l); + ad->a.func_args = arg_size; + s = sym_push(SYM_FIELD, type, 0, l); + s->a = ad->a; s->next = first; type->t = VT_FUNC; type->ref = s; @@ -3277,6 +3386,8 @@ static void post_type(CType *type, AttributeDef *ad) skip(']'); /* parse next post type */ post_type(type, ad); + if (type->t == VT_FUNC) + tcc_error("declaration of an array of functions"); t1 |= type->t & VT_VLA; if (t1 & VT_VLA) { @@ -3444,6 +3555,9 @@ static void gfunc_param_typed(Sym *func, Sym *arg) if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) { type.t = VT_DOUBLE; gen_cast(&type); + } else if (vtop->type.t & VT_BITFIELD) { + type.t = vtop->type.t & (VT_BTYPE | VT_UNSIGNED); + gen_cast(&type); } } else if (arg == NULL) { tcc_error("too many arguments to function"); @@ -3645,7 +3759,7 @@ ST_FUNC void unary(void) vtop->c.i = vtop->c.i ^ 1; else { save_regs(1); - vseti(VT_JMP, gtst(1, 0)); + vseti(VT_JMP, gvtst(1, 0)); } break; case '~': @@ -3656,12 +3770,16 @@ ST_FUNC void unary(void) break; case '+': next(); - /* in order to force cast, we add zero */ unary(); if ((vtop->type.t & VT_BTYPE) == VT_PTR) tcc_error("pointer not accepted for unary plus"); - vpushi(0); - gen_op('+'); + /* In order to force cast, we add zero, except for floating point + where we really need an noop (otherwise -0.0 will be transformed + into +0.0). */ + if (!is_float(vtop->type.t)) { + vpushi(0); + gen_op('+'); + } break; case TOK_SIZEOF: case TOK_ALIGNOF1: @@ -3756,7 +3874,6 @@ ST_FUNC void unary(void) case TOK_builtin_va_arg_types: { CType type; - int bt; next(); skip('('); parse_type(&type); @@ -3775,9 +3892,22 @@ ST_FUNC void unary(void) break; case '-': next(); - vpushi(0); unary(); - gen_op('-'); + t = vtop->type.t & VT_BTYPE; + if (is_float(t)) { + /* In IEEE negate(x) isn't subtract(0,x), but rather + subtract(-0, x). */ + vpush(&vtop->type); + if (t == VT_FLOAT) + vtop->c.f = -0.0f; + else if (t == VT_DOUBLE) + vtop->c.d = -0.0; + else + vtop->c.ld = -0.0; + } else + vpushi(0); + vswap(); + gen_op('-'); break; case TOK_LAND: if (!gnu_ext) @@ -3798,8 +3928,7 @@ ST_FUNC void unary(void) mk_pointer(&s->type); s->type.t |= VT_STATIC; } - vset(&s->type, VT_CONST | VT_SYM, 0); - vtop->sym = s; + vpushsym(&s->type, s); next(); break; @@ -3825,13 +3954,19 @@ ST_FUNC void unary(void) expect("identifier"); s = sym_find(t); if (!s) { + const char *name = get_tok_str(t, NULL); if (tok != '(') - tcc_error("'%s' undeclared", get_tok_str(t, NULL)); + tcc_error("'%s' undeclared", name); /* for simple function calls, we tolerate undeclared external reference to int() function */ - if (tcc_state->warn_implicit_function_declaration) - tcc_warning("implicit declaration of function '%s'", - get_tok_str(t, NULL)); + if (tcc_state->warn_implicit_function_declaration +#ifdef TCC_TARGET_PE + /* people must be warned about using undeclared WINAPI functions + (which usually start with uppercase letter) */ + || (name[0] >= 'A' && name[0] <= 'Z') +#endif + ) + tcc_warning("implicit declaration of function '%s'", name); s = external_global_sym(t, &func_old_type, 0); } if ((s->type.t & (VT_STATIC | VT_INLINE | VT_BTYPE)) == @@ -3851,7 +3986,7 @@ ST_FUNC void unary(void) /* if forward reference, we must point to s */ if (vtop->r & VT_SYM) { vtop->sym = s; - vtop->c.ul = 0; + vtop->c.ptr_offset = 0; } break; } @@ -3908,7 +4043,7 @@ ST_FUNC void unary(void) } else if (tok == '(') { SValue ret; Sym *sa; - int nb_args, sret; + int nb_args, ret_nregs, ret_align, variadic; /* function call */ if ((vtop->type.t & VT_BTYPE) != VT_FUNC) { @@ -3932,9 +4067,10 @@ ST_FUNC void unary(void) ret.r2 = VT_CONST; /* compute first implicit argument if a structure is returned */ if ((s->type.t & VT_BTYPE) == VT_STRUCT) { - int ret_align; - sret = gfunc_sret(&s->type, &ret.type, &ret_align); - if (sret) { + variadic = (s->c == FUNC_ELLIPSIS); + ret_nregs = gfunc_sret(&s->type, variadic, &ret.type, + &ret_align); + if (!ret_nregs) { /* get some space for the returned structure */ size = type_size(&s->type, &align); loc = (loc - size) & -align; @@ -3947,11 +4083,11 @@ ST_FUNC void unary(void) nb_args++; } } else { - sret = 0; + ret_nregs = 1; ret.type = s->type; } - if (!sret) { + if (ret_nregs) { /* return in register */ if (is_float(ret.type.t)) { ret.r = reg_fret(ret.type.t); @@ -3990,19 +4126,31 @@ ST_FUNC void unary(void) } else { vtop -= (nb_args + 1); } + /* return value */ - vsetc(&ret.type, ret.r, &ret.c); - vtop->r2 = ret.r2; + for (r = ret.r + ret_nregs + !ret_nregs; r-- > ret.r;) { + vsetc(&ret.type, r, &ret.c); + vtop->r2 = ret.r2; /* Loop only happens when r2 is VT_CONST */ + } + /* handle packed struct return */ - if (((s->type.t & VT_BTYPE) == VT_STRUCT) && !sret) { - int addr; + if (((s->type.t & VT_BTYPE) == VT_STRUCT) && ret_nregs) { + int addr, offset; + size = type_size(&s->type, &align); loc = (loc - size) & -align; addr = loc; - vset(&ret.type, VT_LOCAL | VT_LVAL, addr); - vswap(); - vstore(); - vtop--; + offset = 0; + for (;;) { + vset(&ret.type, VT_LOCAL | VT_LVAL, addr + offset); + vswap(); + vstore(); + vtop--; + if (--ret_nregs == 0) + break; + /* XXX: compatible with arm only: ret_align == register_size */ + offset += ret_align; + } vset(&s->type, VT_LOCAL | VT_LVAL, addr); } } else { @@ -4139,7 +4287,7 @@ static void expr_land(void) t = 0; save_regs(1); for(;;) { - t = gtst(1, t); + t = gvtst(1, t); if (tok != TOK_LAND) { vseti(VT_JMPI, t); break; @@ -4159,7 +4307,7 @@ static void expr_lor(void) t = 0; save_regs(1); for(;;) { - t = gtst(0, t); + t = gvtst(0, t); if (tok != TOK_LOR) { vseti(VT_JMP, t); break; @@ -4221,9 +4369,9 @@ static void expr_cond(void) } if (tok == ':' && gnu_ext) { gv_dup(); - tt = gtst(1, 0); + tt = gvtst(1, 0); } else { - tt = gtst(1, 0); + tt = gvtst(1, 0); gexpr(); } type1 = vtop->type; @@ -4469,7 +4617,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gexpr(); skip(')'); - a = gtst(1, 0); + a = gvtst(1, 0); block(bsym, csym, case_sym, def_sym, case_reg, 0); c = tok; if (c == TOK_ELSE) { @@ -4486,7 +4634,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gexpr(); skip(')'); - a = gtst(1, 0); + a = gvtst(1, 0); b = 0; block(&a, &b, case_sym, def_sym, case_reg, 0); gjmp_addr(d); @@ -4573,8 +4721,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, gen_assign_cast(&func_vt); if ((func_vt.t & VT_BTYPE) == VT_STRUCT) { CType type, ret_type; - int ret_align; - if (gfunc_sret(&func_vt, &ret_type, &ret_align)) { + int ret_align, ret_nregs; + ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type, + &ret_align); + if (0 == ret_nregs) { /* if returning structure, must copy it to implicit first pointer arg location */ type = func_vt; @@ -4586,7 +4736,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, vstore(); } else { /* returning structure packed into registers */ - int size, addr, align; + int r, size, addr, align; size = type_size(&func_vt,&align); if ((vtop->r != (VT_LOCAL | VT_LVAL) || (vtop->c.i & (ret_align-1))) && (align & (ret_align-1))) { @@ -4600,9 +4750,22 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, } vtop->type = ret_type; if (is_float(ret_type.t)) - gv(rc_fret(ret_type.t)); + r = rc_fret(ret_type.t); else - gv(RC_IRET); + r = RC_IRET; + + for (;;) { + gv(r); + if (--ret_nregs == 0) + break; + /* We assume that when a structure is returned in multiple + registers, their classes are consecutive values of the + suite s(n) = 2^n */ + r <<= 1; + /* XXX: compatible with arm only: ret_align == register_size */ + vtop->c.i += ret_align; + vtop->r = VT_LOCAL | VT_LVAL; + } } } else if (is_float(func_vt.t)) { gv(rc_fret(func_vt.t)); @@ -4650,7 +4813,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, b = 0; if (tok != ';') { gexpr(); - a = gtst(1, 0); + a = gvtst(1, 0); } skip(';'); if (tok != ')') { @@ -4679,7 +4842,7 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, skip('('); gsym(b); gexpr(); - c = gtst(0, 0); + c = gvtst(0, 0); gsym_addr(c, d); skip(')'); gsym(a); @@ -5037,6 +5200,12 @@ static void init_putv(CType *type, Section *sec, unsigned long c, case VT_LLONG: *(long long *)ptr |= (vtop->c.ll & bit_mask) << bit_pos; break; + case VT_PTR: + if (vtop->r & VT_SYM) { + greloc(sec, vtop->sym, c, R_DATA_PTR); + } + *(addr_t *)ptr |= (vtop->c.ptr_offset & bit_mask) << bit_pos; + break; default: if (vtop->r & VT_SYM) { greloc(sec, vtop->sym, c, R_DATA_PTR); @@ -5061,8 +5230,13 @@ static void init_putz(CType *t, Section *sec, unsigned long c, int size) } else { vpush_global_sym(&func_old_type, TOK_memset); vseti(VT_LOCAL, c); +#ifdef TCC_TARGET_ARM + vpushs(size); + vpushi(0); +#else vpushi(0); vpushs(size); +#endif gfunc_call(3); } } @@ -5337,12 +5511,13 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, flexible_array = NULL; if ((type->t & VT_BTYPE) == VT_STRUCT) { - Sym *field; - field = type->ref; - while (field && field->next) - field = field->next; - if (field->type.t & VT_ARRAY && field->type.ref->c < 0) - flexible_array = field; + Sym *field = type->ref->next; + if (field) { + while (field->next) + field = field->next; + if (field->type.t & VT_ARRAY && field->type.ref->c < 0) + flexible_array = field; + } } size = type_size(type, &align); @@ -5402,10 +5577,10 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (flexible_array) size += flexible_array->type.ref->c * pointed_size(&flexible_array->type); /* take into account specified alignment if bigger */ - if (ad->aligned) { - if (ad->aligned > align) - align = ad->aligned; - } else if (ad->packed) { + if (ad->a.aligned) { + if (ad->a.aligned > align) + align = ad->a.aligned; + } else if (ad->a.packed) { align = 1; } if ((r & VT_VALMASK) == VT_LOCAL) { @@ -5452,7 +5627,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (sym->type.t & VT_EXTERN) { /* if the variable is extern, it was not allocated */ sym->type.t &= ~VT_EXTERN; - /* set array size if it was ommited in extern + /* set array size if it was omitted in extern declaration */ if ((sym->type.t & VT_ARRAY) && sym->type.ref->c < 0 && @@ -5521,17 +5696,14 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, esym->st_shndx = SHN_COMMON; } } else { - CValue cval; - /* push global reference */ sym = get_sym_ref(type, sec, addr, size); - cval.ul = 0; - vsetc(type, VT_CONST | VT_SYM, &cval); - vtop->sym = sym; + vpushsym(type, sym); } /* patch symbol weakness */ if (type->t & VT_WEAK) weaken_symbol(sym); + apply_visibility(sym, type); #ifdef CONFIG_TCC_BCHECK /* handles bounds now because the symbol must be defined before for the relocation */ @@ -5646,6 +5818,21 @@ static void gen_function(Sym *sym) /* push a dummy symbol to enable local sym storage */ sym_push2(&local_stack, SYM_FIELD, 0, 0); gfunc_prolog(&sym->type); +#ifdef CONFIG_TCC_BCHECK + if (tcc_state->do_bounds_check + && !strcmp(get_tok_str(sym->v, NULL), "main")) { + int i; + + sym = local_stack; + for (i = 0, sym = local_stack; i < 2; i++, sym = sym->prev) { + if (sym->v & SYM_FIELD || sym->prev->v & SYM_FIELD) + break; + vpush_global_sym(&func_old_type, TOK___bound_main_arg); + vset(&sym->type, sym->r, sym->c); + gfunc_call(1); + } + } +#endif rsym = 0; block(NULL, NULL, NULL, NULL, 0, 0); gsym(rsym); @@ -5662,6 +5849,7 @@ static void gen_function(Sym *sym) /* patch symbol weakness (this definition overrules any prototype) */ if (sym->type.t & VT_WEAK) weaken_symbol(sym); + apply_visibility(sym, &sym->type); if (tcc_state->do_debug) { put_stabn(N_FUN, 0, 0, ind - func_ind); } @@ -5669,6 +5857,7 @@ static void gen_function(Sym *sym) cur_text_section = NULL; funcname = ""; /* for safety */ func_vt.t = VT_VOID; /* for safety */ + func_var = 0; /* for safety */ ind = 0; /* for safety */ nocode_wanted = saved_nocode_wanted; } @@ -5786,14 +5975,16 @@ static int decl0(int l, int is_for_loop_init) parse_attribute(&ad); } - if (ad.weak) + if (ad.a.weak) type.t |= VT_WEAK; #ifdef TCC_TARGET_PE - if (ad.func_import) + if (ad.a.func_import) type.t |= VT_IMPORT; - if (ad.func_export) + if (ad.a.func_export) type.t |= VT_EXPORT; #endif + type.t |= ad.a.visibility << VT_VIS_SHIFT; + if (tok == '{') { if (l == VT_LOCAL) tcc_error("cannot use local functions"); @@ -5812,28 +6003,38 @@ static int decl0(int l, int is_for_loop_init) sym = sym_find(v); if (sym) { + Sym *ref; if ((sym->type.t & VT_BTYPE) != VT_FUNC) goto func_error1; - r = sym->type.ref->r; + ref = sym->type.ref; + if (0 == ref->a.func_proto) + tcc_error("redefinition of '%s'", get_tok_str(v, NULL)); + /* use func_call from prototype if not defined */ - if (FUNC_CALL(r) != FUNC_CDECL - && FUNC_CALL(type.ref->r) == FUNC_CDECL) - FUNC_CALL(type.ref->r) = FUNC_CALL(r); + if (ref->a.func_call != FUNC_CDECL + && type.ref->a.func_call == FUNC_CDECL) + type.ref->a.func_call = ref->a.func_call; /* use export from prototype */ - if (FUNC_EXPORT(r)) - FUNC_EXPORT(type.ref->r) = 1; + if (ref->a.func_export) + type.ref->a.func_export = 1; /* use static from prototype */ if (sym->type.t & VT_STATIC) type.t = (type.t & ~VT_EXTERN) | VT_STATIC; + /* If the definition has no visibility use the + one from prototype. */ + if (! (type.t & VT_VIS_MASK)) + type.t |= sym->type.t & VT_VIS_MASK; + if (!is_compatible_types(&sym->type, &type)) { func_error1: tcc_error("incompatible types for redefinition of '%s'", get_tok_str(v, NULL)); } + type.ref->a.func_proto = 0; /* if symbol is already defined, then put complete type */ sym->type = type; } else { @@ -5892,14 +6093,16 @@ static int decl0(int l, int is_for_loop_init) if (btype.t & VT_TYPEDEF) { /* save typedefed type */ /* XXX: test storage specifiers ? */ - sym = sym_push(v, &type, INT_ATTR(&ad), 0); + sym = sym_push(v, &type, 0, 0); + sym->a = ad.a; sym->type.t |= VT_TYPEDEF; } else { r = 0; if ((type.t & VT_BTYPE) == VT_FUNC) { /* external function definition */ /* specific case for func_call attribute */ - type.ref->r = INT_ATTR(&ad); + ad.a.func_proto = 1; + type.ref->a = ad.a; } else if (!(type.t & VT_ARRAY)) { /* not lvalue if array */ r |= lvalue_type(type.t); @@ -5916,9 +6119,6 @@ static int decl0(int l, int is_for_loop_init) extern */ sym = external_sym(v, &type, r, asm_label); - if (type.t & VT_WEAK) - weaken_symbol(sym); - if (ad.alias_target) { Section tsec; Elf32_Sym *esym; @@ -5950,7 +6150,7 @@ static int decl0(int l, int is_for_loop_init) } next(); } - ad.aligned = 0; + ad.a.aligned = 0; } } return 0; |
