aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
authorgrischka <grischka>2017-09-24 18:57:48 +0200
committergrischka <grischka>2017-09-24 18:57:48 +0200
commit1443039416dd02750765efde1af35e31c8d41be3 (patch)
tree4e1eed95126f8948b1af1425c418ff9343d33d5f /tccgen.c
parent870271ea071971002fa556e09e1873db316fa1a9 (diff)
downloadtinycc-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.c173
1 files changed, 83 insertions, 90 deletions
diff --git a/tccgen.c b/tccgen.c
index 3da1143..e6a56a7 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -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