diff options
| author | grischka <grischka> | 2017-09-24 18:57:48 +0200 |
|---|---|---|
| committer | grischka <grischka> | 2017-09-24 18:57:48 +0200 |
| commit | 1443039416dd02750765efde1af35e31c8d41be3 (patch) | |
| tree | 4e1eed95126f8948b1af1425c418ff9343d33d5f /tccgen.c | |
| parent | 870271ea071971002fa556e09e1873db316fa1a9 (diff) | |
| download | tinycc-1443039416dd02750765efde1af35e31c8d41be3.tar.gz tinycc-1443039416dd02750765efde1af35e31c8d41be3.tar.bz2 | |
'long' review
add some features for more complete 'long' support
tcc.h:
- use LONG_SIZE=4/8 instead of TCC_LONG_ARE_64_BIT
tccgen.c:
- add ptrdiff_type, update size_type
- support shift and ?: operations
- support long enum types
- display 'long' from type_to_str
- nwchar_t is unsigned short on windows
- unrelated: use memcpy in init_putv for long doubles to avoid
random bytes in the image (if tcc was compiled by gcc) for
diff purposes.
tccpp.c:
- make parse_number return correct types
- improve multi-character-constants 'XX' 'abcd'
Changelog:
- update
Diffstat (limited to 'tccgen.c')
| -rw-r--r-- | tccgen.c | 173 |
1 files changed, 83 insertions, 90 deletions
@@ -61,7 +61,7 @@ ST_DATA int last_line_num, last_ind, func_ind; /* debug last line number and pc ST_DATA const char *funcname; ST_DATA int g_debug; -ST_DATA CType char_pointer_type, func_old_type, int_type, size_type; +ST_DATA CType char_pointer_type, func_old_type, int_type, size_type, ptrdiff_type; ST_DATA struct switch_t { struct case_t { @@ -240,9 +240,14 @@ ST_FUNC int tccgen_compile(TCCState *s1) char_pointer_type.t = VT_BYTE; mk_pointer(&char_pointer_type); #if PTR_SIZE == 4 - size_type.t = VT_INT; + size_type.t = VT_INT | VT_UNSIGNED; + ptrdiff_type.t = VT_INT; +#elif LONG_SIZE == 4 + size_type.t = VT_LLONG | VT_UNSIGNED; + ptrdiff_type.t = VT_LLONG; #else - size_type.t = VT_LLONG; + size_type.t = VT_LONG | VT_LLONG | VT_UNSIGNED; + ptrdiff_type.t = VT_LONG | VT_LLONG; #endif func_old_type.t = VT_FUNC; func_old_type.ref = sym_push(SYM_FIELD, &int_type, 0, 0); @@ -2127,12 +2132,7 @@ redo: } vrott(3); gen_opic(op); - /* set to integer type */ -#if PTR_SIZE == 8 - vtop->type.t = VT_LLONG; -#else - vtop->type.t = VT_INT; -#endif + vtop->type.t = ptrdiff_type.t; vswap(); gen_op(TOK_PDIV); } else { @@ -2218,14 +2218,15 @@ redo: t = bt1 == VT_LLONG ? VT_LLONG : VT_INT; if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED)) t |= VT_UNSIGNED; + t |= (VT_LONG & t1); goto std_op; } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { /* cast to biggest op */ - t = VT_LLONG; - /* check if we need to keep type as long or as long long */ - if ((t1 & VT_LONG && (t2 & (VT_BTYPE | VT_LONG)) != VT_LLONG) || - (t2 & VT_LONG && (t1 & (VT_BTYPE | VT_LONG)) != VT_LLONG)) - t |= VT_LONG; + t = VT_LLONG | VT_LONG; + if (bt1 == VT_LLONG) + t &= t1; + if (bt2 == VT_LLONG) + t &= t2; /* convert to unsigned if it does not fit in a long long */ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) @@ -2233,12 +2234,8 @@ redo: goto std_op; } else { /* integer operations */ - t = VT_INT; - - if ((t1 & VT_LONG) || (t2 & VT_LONG)) - t |= VT_LONG; - - /* convert to unsigned if it does not fit in an integer */ + t = VT_INT | (VT_LONG & (t1 | t2)); + /* convert to unsigned if it does not fit in an integer */ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) t |= VT_UNSIGNED; @@ -2741,7 +2738,6 @@ static int compare_types(CType *type1, CType *type2, int unqualified) t1 &= ~VT_DEFSIGN; t2 &= ~VT_DEFSIGN; } - /* XXX: bitfields ? */ if (t1 != t2) return 0; @@ -2790,14 +2786,7 @@ static void type_to_str(char *buf, int buf_size, t = type->t; bt = t & VT_BTYPE; buf[0] = '\0'; - if (t & VT_CONSTANT) - pstrcat(buf, buf_size, "const "); - if (t & VT_VOLATILE) - pstrcat(buf, buf_size, "volatile "); - 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 "); + if (t & VT_EXTERN) pstrcat(buf, buf_size, "extern "); if (t & VT_STATIC) @@ -2806,17 +2795,20 @@ static void type_to_str(char *buf, int buf_size, pstrcat(buf, buf_size, "typedef "); if (t & VT_INLINE) pstrcat(buf, buf_size, "inline "); + if (t & VT_VOLATILE) + pstrcat(buf, buf_size, "volatile "); + if (t & VT_CONSTANT) + pstrcat(buf, buf_size, "const "); + + if (((t & VT_DEFSIGN) && bt == VT_BYTE) + || ((t & VT_UNSIGNED) + && (bt == VT_SHORT || bt == VT_INT || bt == VT_LLONG) + && !IS_ENUM(t) + )) + pstrcat(buf, buf_size, (t & VT_UNSIGNED) ? "unsigned " : "signed "); + buf_size -= strlen(buf); buf += strlen(buf); - if (IS_ENUM(t)) { - tstr = "enum "; - goto tstruct; - } - - if (!bt && VT_LONG & t) { - tstr = "long"; - goto add_tstr; - } switch(bt) { case VT_VOID: @@ -2833,10 +2825,16 @@ static void type_to_str(char *buf, int buf_size, goto add_tstr; case VT_INT: tstr = "int"; - goto add_tstr; + goto maybe_long; case VT_LLONG: tstr = "long long"; - goto add_tstr; + maybe_long: + if (t & VT_LONG) + tstr = "long"; + if (!IS_ENUM(t)) + goto add_tstr; + tstr = "enum "; + goto tstruct; case VT_FLOAT: tstr = "float"; goto add_tstr; @@ -2902,7 +2900,7 @@ static void type_to_str(char *buf, int buf_size, casts if needed. */ static void gen_assign_cast(CType *dt) { - CType *st, *type1, *type2, tmp_type1, tmp_type2; + CType *st, *type1, *type2; char buf1[256], buf2[256]; int dbt, sbt; @@ -2958,7 +2956,7 @@ static void gen_assign_cast(CType *dt) in pointer target signedness. Do warn for different base types, though, in particular for unsigned enums and signed int targets. */ - if ((type1->t & VT_BTYPE) != (type2->t & VT_BTYPE) + if ((type1->t & (VT_BTYPE|VT_LONG)) != (type2->t & (VT_BTYPE|VT_LONG)) || IS_ENUM(type1->t) || IS_ENUM(type2->t) ) tcc_warning("assignment from incompatible pointer type"); @@ -2982,11 +2980,7 @@ static void gen_assign_cast(CType *dt) break; case VT_STRUCT: case_VT_STRUCT: - tmp_type1 = *dt; - tmp_type2 = *st; - tmp_type1.t &= ~(VT_CONSTANT | VT_VOLATILE); - tmp_type2.t &= ~(VT_CONSTANT | VT_VOLATILE); - if (!is_compatible_types(&tmp_type1, &tmp_type2)) { + if (!is_compatible_unqualified_types(dt, st)) { error: type_to_str(buf1, sizeof(buf1), st, NULL); type_to_str(buf2, sizeof(buf2), dt, NULL); @@ -3775,10 +3769,10 @@ do_decl: t.t = VT_INT; if (nl >= 0) { if (pl != (unsigned)pl) - t.t = VT_LLONG; + t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); t.t |= VT_UNSIGNED; } else if (pl != (int)pl || nl != (int)nl) - t.t = VT_LLONG; + t.t = (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); s->type.t = type->t = t.t | VT_ENUM; s->c = 0; /* set type for enum members */ @@ -3791,7 +3785,8 @@ do_decl: if (ll == (unsigned)ll) continue; } - ss->type.t = (ss->type.t & ~VT_BTYPE) | VT_LLONG; + ss->type.t = (ss->type.t & ~VT_BTYPE) + | (LONG_SIZE==8 ? VT_LLONG|VT_LONG : VT_LLONG); } } else { c = 0; @@ -3964,7 +3959,7 @@ static int parse_btype(CType *type, AttributeDef *ad) bt = u; } if (u != VT_INT) - t = (t & ~VT_BTYPE) | u; + t = (t & ~(VT_BTYPE|VT_LONG)) | u; typespec_found = 1; break; case TOK_VOID: @@ -3978,11 +3973,9 @@ static int parse_btype(CType *type, AttributeDef *ad) goto basic_type; case TOK_LONG: if ((t & VT_BTYPE) == VT_DOUBLE) { -#ifndef TCC_TARGET_PE - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE; -#endif - } else if (t & VT_LONG) { - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LLONG; + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; + } else if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LLONG; } else { u = VT_LONG; goto basic_type; @@ -4003,12 +3996,8 @@ static int parse_btype(CType *type, AttributeDef *ad) u = VT_FLOAT; goto basic_type; case TOK_DOUBLE: - if (t & VT_LONG) { -#ifdef TCC_TARGET_PE - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_DOUBLE; -#else - t = (t & ~(VT_LONG | VT_BTYPE)) | VT_LDOUBLE; -#endif + if ((t & (VT_BTYPE|VT_LONG)) == VT_LONG) { + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_LDOUBLE; } else { u = VT_DOUBLE; goto basic_type; @@ -4098,7 +4087,7 @@ static int parse_btype(CType *type, AttributeDef *ad) parse_attribute(ad); if (ad->attr_mode) { u = ad->attr_mode -1; - t = (t & ~VT_BTYPE) | u; + t = (t & ~(VT_BTYPE|VT_LONG)) | u; } break; /* GNUC typeof */ @@ -4118,7 +4107,7 @@ static int parse_btype(CType *type, AttributeDef *ad) s = sym_find(tok); if (!s || !(s->type.t & VT_TYPEDEF)) goto the_end; - t &= ~VT_BTYPE; + t &= ~(VT_BTYPE|VT_LONG); u = t & ~(VT_CONSTANT | VT_VOLATILE), t ^= u; type->t = (s->type.t & ~VT_TYPEDEF) | u; type->ref = s->type.ref; @@ -4139,13 +4128,13 @@ the_end: if ((t & (VT_DEFSIGN|VT_BTYPE)) == VT_BYTE) t |= VT_UNSIGNED; } - - /* long is never used as type */ - if (t & VT_LONG) -#if PTR_SIZE == 8 && !defined TCC_TARGET_PE - t = (t & ~VT_BTYPE) | VT_LLONG; -#else - t = (t & ~VT_BTYPE) | VT_INT; + /* VT_LONG is used just as a modifier for VT_INT / VT_LLONG */ + bt = t & (VT_BTYPE|VT_LONG); + if (bt == VT_LONG) + t |= LONG_SIZE == 8 ? VT_LLONG : VT_INT; +#ifdef TCC_TARGET_PE + if (bt == VT_LDOUBLE) + t = (t & ~(VT_BTYPE|VT_LONG)) | VT_DOUBLE; #endif type->t = t; return type_found; @@ -4544,9 +4533,13 @@ ST_FUNC void unary(void) case TOK_EXTENSION: next(); goto tok_next; + case TOK_LCHAR: +#ifdef TCC_TARGET_PE + t = VT_SHORT|VT_UNSIGNED; + goto push_tokc; +#endif case TOK_CINT: case TOK_CCHAR: - case TOK_LCHAR: t = VT_INT; push_tokc: type.t = t; @@ -4572,14 +4565,10 @@ ST_FUNC void unary(void) t = VT_LDOUBLE; goto push_tokc; case TOK_CLONG: + t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG; + goto push_tokc; case TOK_CULONG: - #ifdef TCC_LONG_ARE_64_BIT - t = VT_LLONG | VT_LONG; - #else - t = VT_INT | VT_LONG; - #endif - if (tok == TOK_CULONG) - t |= VT_UNSIGNED; + t = (LONG_SIZE == 8 ? VT_LLONG : VT_INT) | VT_LONG | VT_UNSIGNED; goto push_tokc; case TOK___FUNCTION__: if (!gnu_ext) @@ -5491,7 +5480,11 @@ static void expr_cond(void) } } else if (bt1 == VT_LLONG || bt2 == VT_LLONG) { /* cast to biggest op */ - type.t = VT_LLONG; + type.t = VT_LLONG | VT_LONG; + if (bt1 == VT_LLONG) + type.t &= t1; + if (bt2 == VT_LLONG) + type.t &= t2; /* convert to unsigned if it does not fit in a long long */ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) || (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED)) @@ -5518,7 +5511,7 @@ static void expr_cond(void) type.t = VT_VOID; } else { /* integer operations */ - type.t = VT_INT; + type.t = VT_INT | (VT_LONG & (t1 | t2)); /* convert to unsigned if it does not fit in an integer */ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) || (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED)) @@ -6490,20 +6483,20 @@ static void init_putv(CType *type, Section *sec, unsigned long c) *(double *)ptr = vtop->c.d; break; case VT_LDOUBLE: - if (sizeof(long double) == LDOUBLE_SIZE) - *(long double *)ptr = vtop->c.ld; - else if (sizeof(double) == LDOUBLE_SIZE) - *(double *)ptr = (double)vtop->c.ld; #if (defined __i386__ || defined __x86_64__) && (defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64) - else if (sizeof (long double) >= 10) - memcpy(memset(ptr, 0, LDOUBLE_SIZE), &vtop->c.ld, 10); + if (sizeof (long double) >= 10) /* zero pad ten-byte LD */ + memcpy(ptr, &vtop->c.ld, 10); #ifdef __TINYC__ else if (sizeof (long double) == sizeof (double)) - __asm__("fldl %1\nfstpt %0\n" : "=m" - (memset(ptr, 0, LDOUBLE_SIZE), ptr) : "m" (vtop->c.ld)); + __asm__("fldl %1\nfstpt %0\n" : "=m" (ptr) : "m" (vtop->c.ld)); #endif + else #endif - else + if (sizeof(long double) == LDOUBLE_SIZE) + *(long double*)ptr = vtop->c.ld; + else if (sizeof(double) == LDOUBLE_SIZE) + *(double *)ptr = (double)vtop->c.ld; + else tcc_error("can't cross compile long double constants"); break; #if PTR_SIZE != 8 |
