mirror of
https://github.com/frida/tinycc
synced 2024-11-27 18:19:35 +03:00
refactor enums
Eliminate VT_ENUM as a basic type. Instead use the integral types VT_InT/VT_LLONG with an additional flag to indicate that it is an enum.
This commit is contained in:
parent
9ba76ac834
commit
f87afa72e0
@ -249,7 +249,6 @@ static int arm64_type_size(int t)
|
||||
case VT_BYTE: return 0;
|
||||
case VT_SHORT: return 1;
|
||||
case VT_PTR: return 3;
|
||||
case VT_ENUM: return 2;
|
||||
case VT_FUNC: return 3;
|
||||
case VT_FLOAT: return 2;
|
||||
case VT_DOUBLE: return 3;
|
||||
|
31
tcc.h
31
tcc.h
@ -416,8 +416,7 @@ struct SymAttr {
|
||||
visibility : 2,
|
||||
dllexport : 1,
|
||||
dllimport : 1,
|
||||
unsigned_enum : 1,
|
||||
unused : 4;
|
||||
unused : 5;
|
||||
};
|
||||
|
||||
/* function attributes or temporary attributes for parsing */
|
||||
@ -852,14 +851,13 @@ struct filespec {
|
||||
#define VT_PTR 5 /* pointer */
|
||||
#define VT_FUNC 6 /* function type */
|
||||
#define VT_STRUCT 7 /* struct/union definition */
|
||||
#define VT_ENUM 8 /* enum definition */
|
||||
#define VT_FLOAT 9 /* IEEE float */
|
||||
#define VT_DOUBLE 10 /* IEEE double */
|
||||
#define VT_LDOUBLE 11 /* IEEE long double */
|
||||
#define VT_BOOL 12 /* ISOC99 boolean type */
|
||||
#define VT_LONG 13 /* long integer (NEVER USED as type, only during parsing) */
|
||||
#define VT_QLONG 14 /* 128-bit integer. Only used for x86-64 ABI */
|
||||
#define VT_QFLOAT 15 /* 128-bit float. Only used for x86-64 ABI */
|
||||
#define VT_FLOAT 8 /* IEEE float */
|
||||
#define VT_DOUBLE 9 /* IEEE double */
|
||||
#define VT_LDOUBLE 10 /* IEEE long double */
|
||||
#define VT_BOOL 11 /* ISOC99 boolean type */
|
||||
#define VT_LONG 12 /* long integer (NEVER USED as type, only during parsing) */
|
||||
#define VT_QLONG 13 /* 128-bit integer. Only used for x86-64 ABI */
|
||||
#define VT_QFLOAT 14 /* 128-bit float. Only used for x86-64 ABI */
|
||||
|
||||
#define VT_UNSIGNED 0x0010 /* unsigned type */
|
||||
#define VT_DEFSIGN 0x0020 /* explicitly signed or unsigned */
|
||||
@ -868,7 +866,6 @@ struct filespec {
|
||||
#define VT_CONSTANT 0x0100 /* const modifier */
|
||||
#define VT_VOLATILE 0x0200 /* volatile modifier */
|
||||
#define VT_VLA 0x0400 /* VLA type (also has VT_PTR and VT_ARRAY) */
|
||||
#define VT_UNION (VT_STRUCT|VT_UNSIGNED) /* VT_STRUCT type with some modifier */
|
||||
|
||||
/* storage */
|
||||
#define VT_EXTERN 0x00001000 /* extern definition */
|
||||
@ -882,9 +879,17 @@ struct filespec {
|
||||
#define BIT_POS(t) (((t) >> VT_STRUCT_SHIFT) & 0x3f)
|
||||
#define BIT_SIZE(t) (((t) >> (VT_STRUCT_SHIFT + 6)) & 0x3f)
|
||||
|
||||
#define VT_UNION (1 << VT_STRUCT_SHIFT | VT_STRUCT)
|
||||
#define VT_ENUM (2 << VT_STRUCT_SHIFT) /* integral type is an enum really */
|
||||
#define VT_ENUM_VAL (3 << VT_STRUCT_SHIFT) /* integral type is an enum constant really */
|
||||
|
||||
#define IS_ENUM(t) ((t & VT_STRUCT_MASK) == VT_ENUM)
|
||||
#define IS_ENUM_VAL(t) ((t & VT_STRUCT_MASK) == VT_ENUM_VAL)
|
||||
#define IS_UNION(t) ((t & (VT_STRUCT_MASK|VT_BTYPE)) == VT_UNION)
|
||||
|
||||
/* type mask (except storage) */
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE | VT_STRUCT_MASK)
|
||||
#define VT_TYPE (~VT_STORAGE)
|
||||
#define VT_STORAGE (VT_EXTERN | VT_STATIC | VT_TYPEDEF | VT_INLINE)
|
||||
#define VT_TYPE (~(VT_STORAGE|VT_STRUCT_MASK))
|
||||
|
||||
|
||||
/* token values */
|
||||
|
167
tccgen.c
167
tccgen.c
@ -86,7 +86,7 @@ static void expr_eq(void);
|
||||
static void vla_runtime_type_size(CType *type, int *a);
|
||||
static void vla_sp_restore(void);
|
||||
static void vla_sp_restore_root(void);
|
||||
static int is_compatible_parameter_types(CType *type1, CType *type2);
|
||||
static int is_compatible_unqualified_types(CType *type1, CType *type2);
|
||||
static inline int64_t expr_const64(void);
|
||||
ST_FUNC void vpush64(int ty, unsigned long long v);
|
||||
ST_FUNC void vpush(CType *type);
|
||||
@ -1087,10 +1087,8 @@ ST_FUNC int gv(int rc)
|
||||
bits = 64;
|
||||
} else
|
||||
type.t = VT_INT;
|
||||
if((vtop->type.t & VT_UNSIGNED) ||
|
||||
(vtop->type.t & VT_BTYPE) == VT_BOOL ||
|
||||
(((vtop->type.t & VT_BTYPE) == VT_ENUM) &&
|
||||
vtop->type.ref->a.unsigned_enum))
|
||||
if((vtop->type.t & VT_UNSIGNED)
|
||||
|| (vtop->type.t & VT_BTYPE) == VT_BOOL)
|
||||
type.t |= VT_UNSIGNED;
|
||||
gen_cast(&type);
|
||||
/* generate shifts */
|
||||
@ -2479,6 +2477,8 @@ ST_FUNC int type_size(CType *type, int *a)
|
||||
*a = PTR_SIZE;
|
||||
return PTR_SIZE;
|
||||
}
|
||||
} else if (IS_ENUM(type->t) && type->ref->c == -1) {
|
||||
return -1; /* incomplete enum */
|
||||
} else if (bt == VT_LDOUBLE) {
|
||||
*a = LDOUBLE_ALIGN;
|
||||
return LDOUBLE_SIZE;
|
||||
@ -2508,10 +2508,6 @@ ST_FUNC int type_size(CType *type, int *a)
|
||||
} else if (bt == VT_QLONG || bt == VT_QFLOAT) {
|
||||
*a = 8;
|
||||
return 16;
|
||||
} else if (bt == VT_ENUM) {
|
||||
*a = 4;
|
||||
/* Enums might be incomplete, so don't just return '4' here. */
|
||||
return type->ref->c;
|
||||
} else {
|
||||
/* char, void, function, _Bool */
|
||||
*a = 1;
|
||||
@ -2554,7 +2550,7 @@ ST_FUNC void mk_pointer(CType *type)
|
||||
{
|
||||
Sym *s;
|
||||
s = sym_push(SYM_FIELD, type, 0, -1);
|
||||
type->t = VT_PTR | (type->t & ~VT_TYPE);
|
||||
type->t = VT_PTR | (type->t & VT_STORAGE);
|
||||
type->ref = s;
|
||||
}
|
||||
|
||||
@ -2578,7 +2574,7 @@ static int is_compatible_func(CType *type1, CType *type2)
|
||||
while (s1 != NULL) {
|
||||
if (s2 == NULL)
|
||||
return 0;
|
||||
if (!is_compatible_parameter_types(&s1->type, &s2->type))
|
||||
if (!is_compatible_unqualified_types(&s1->type, &s2->type))
|
||||
return 0;
|
||||
s1 = s1->next;
|
||||
s2 = s2->next;
|
||||
@ -2609,21 +2605,7 @@ static int compare_types(CType *type1, CType *type2, int unqualified)
|
||||
t1 &= ~VT_DEFSIGN;
|
||||
t2 &= ~VT_DEFSIGN;
|
||||
}
|
||||
/* An enum is compatible with (unsigned) int. Ideally we would
|
||||
store the enums signedness in type->ref.a.<some_bit> and
|
||||
only accept unsigned enums with unsigned int and vice versa.
|
||||
But one of our callers (gen_assign_cast) always strips VT_UNSIGNED
|
||||
from pointer target types, so we can't add it here either. */
|
||||
if ((t1 & VT_BTYPE) == VT_ENUM) {
|
||||
t1 = VT_INT;
|
||||
if (type1->ref->a.unsigned_enum)
|
||||
t1 |= VT_UNSIGNED;
|
||||
}
|
||||
if ((t2 & VT_BTYPE) == VT_ENUM) {
|
||||
t2 = VT_INT;
|
||||
if (type2->ref->a.unsigned_enum)
|
||||
t2 |= VT_UNSIGNED;
|
||||
}
|
||||
|
||||
/* XXX: bitfields ? */
|
||||
if (t1 != t2)
|
||||
return 0;
|
||||
@ -2652,7 +2634,7 @@ static int is_compatible_types(CType *type1, CType *type2)
|
||||
|
||||
/* return true if type1 and type2 are the same (ignoring qualifiers).
|
||||
*/
|
||||
static int is_compatible_parameter_types(CType *type1, CType *type2)
|
||||
static int is_compatible_unqualified_types(CType *type1, CType *type2)
|
||||
{
|
||||
return compare_types(type1,type2,1);
|
||||
}
|
||||
@ -2690,6 +2672,10 @@ static void type_to_str(char *buf, int buf_size,
|
||||
pstrcat(buf, buf_size, "inline ");
|
||||
buf_size -= strlen(buf);
|
||||
buf += strlen(buf);
|
||||
if (IS_ENUM(type->t)) {
|
||||
tstr = "enum ";
|
||||
goto tstruct;
|
||||
}
|
||||
switch(bt) {
|
||||
case VT_VOID:
|
||||
tstr = "void";
|
||||
@ -2723,12 +2709,11 @@ static void type_to_str(char *buf, int buf_size,
|
||||
add_tstr:
|
||||
pstrcat(buf, buf_size, tstr);
|
||||
break;
|
||||
case VT_ENUM:
|
||||
case VT_STRUCT:
|
||||
if (bt == VT_STRUCT)
|
||||
tstr = "struct ";
|
||||
else
|
||||
tstr = "enum ";
|
||||
tstr = "struct ";
|
||||
if (IS_UNION(t))
|
||||
tstr = "union ";
|
||||
tstruct:
|
||||
pstrcat(buf, buf_size, tstr);
|
||||
v = type->ref->v & ~SYM_STRUCT;
|
||||
if (v >= SYM_FIRST_ANOM)
|
||||
@ -2827,21 +2812,16 @@ static void gen_assign_cast(CType *dt)
|
||||
(type2->t & VT_BTYPE) == VT_VOID) {
|
||||
/* void * can match anything */
|
||||
} else {
|
||||
//printf("types %08x %08x\n", type1->t, type2->t);
|
||||
/* exact type match, except for qualifiers */
|
||||
tmp_type1 = *type1;
|
||||
tmp_type2 = *type2;
|
||||
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(type1, type2)) {
|
||||
/* Like GCC don't warn by default for merely changes
|
||||
in pointer target signedness. Do warn for different
|
||||
base types, though, in particular for unsigned enums
|
||||
and signed int targets. */
|
||||
if ((tmp_type1.t & (VT_DEFSIGN | VT_UNSIGNED)) !=
|
||||
(tmp_type2.t & (VT_DEFSIGN | VT_UNSIGNED)) &&
|
||||
(tmp_type1.t & VT_BTYPE) == (tmp_type2.t & VT_BTYPE))
|
||||
;
|
||||
else
|
||||
if ((type1->t & VT_BTYPE) != (type2->t & VT_BTYPE)
|
||||
|| IS_ENUM(type1->t) || IS_ENUM(type2->t)
|
||||
)
|
||||
tcc_warning("assignment from incompatible pointer type");
|
||||
}
|
||||
}
|
||||
@ -3486,7 +3466,7 @@ static void struct_layout(CType *type, AttributeDef *ad)
|
||||
tcc_warning("will touch memory past end of the struct (internal limitation)");
|
||||
}
|
||||
|
||||
/* enum/struct/union declaration. u is either VT_ENUM or VT_STRUCT */
|
||||
/* enum/struct/union declaration. u is VT_ENUM/VT_STRUCT/VT_UNION */
|
||||
static void struct_decl(CType *type, int u)
|
||||
{
|
||||
int v, c, size, align, flexible, alignoverride;
|
||||
@ -3506,9 +3486,11 @@ static void struct_decl(CType *type, int u)
|
||||
expect("struct/union/enum name");
|
||||
s = struct_find(v);
|
||||
if (s && (s->sym_scope == local_scope || tok != '{')) {
|
||||
if ((s->type.t & (VT_BTYPE|VT_UNION)) != u)
|
||||
tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
|
||||
goto do_decl;
|
||||
if (u == s->type.t)
|
||||
goto do_decl;
|
||||
if (u == VT_ENUM && IS_ENUM(s->type.t))
|
||||
goto do_decl;
|
||||
tcc_error("redefinition of '%s'", get_tok_str(v, NULL));
|
||||
}
|
||||
} else {
|
||||
v = anon_sym++;
|
||||
@ -3520,7 +3502,7 @@ static void struct_decl(CType *type, int u)
|
||||
s = sym_push(v | SYM_STRUCT, &type1, 0, -1);
|
||||
s->r = 0; /* default alignment is zero as gcc */
|
||||
do_decl:
|
||||
type->t = u & VT_BTYPE; /* VT_UNION becomes VT_STRUCT */
|
||||
type->t = s->type.t;
|
||||
type->ref = s;
|
||||
|
||||
if (tok == '{') {
|
||||
@ -3528,13 +3510,15 @@ do_decl:
|
||||
if (s->c != -1)
|
||||
tcc_error("struct/union/enum already defined");
|
||||
/* cannot be empty */
|
||||
c = 0;
|
||||
/* non empty enums are not allowed */
|
||||
ps = &s->next;
|
||||
if (u == VT_ENUM) {
|
||||
int seen_neg = 0;
|
||||
int seen_wide = 0;
|
||||
long long ll = 0, pl = 0, nl = 0;
|
||||
CType t;
|
||||
t.ref = s;
|
||||
/* enum symbols have static storage */
|
||||
t.t = VT_INT|VT_STATIC|VT_ENUM_VAL;
|
||||
for(;;) {
|
||||
CType *t = &int_type;
|
||||
v = tok;
|
||||
if (v < TOK_UIDENT)
|
||||
expect("identifier");
|
||||
@ -3545,38 +3529,48 @@ do_decl:
|
||||
next();
|
||||
if (tok == '=') {
|
||||
next();
|
||||
#if PTR_SIZE == 8
|
||||
c = expr_const64();
|
||||
#else
|
||||
/* We really want to support long long enums
|
||||
on i386 as well, but the Sym structure only
|
||||
holds a 'long' for associated constants,
|
||||
and enlarging it would bump its size (no
|
||||
available padding). So punt for now. */
|
||||
c = expr_const();
|
||||
#endif
|
||||
ll = expr_const64();
|
||||
}
|
||||
if (c < 0)
|
||||
seen_neg = 1;
|
||||
if (c != (int)c && (unsigned long)c != (unsigned int)c)
|
||||
seen_wide = 1, t = &size_type;
|
||||
/* enum symbols have static storage */
|
||||
ss = sym_push(v, t, VT_CONST, c);
|
||||
ss->type.t |= VT_STATIC;
|
||||
ss = sym_push(v, &t, VT_CONST, 0);
|
||||
ss->enum_val = ll;
|
||||
*ps = ss, ps = &ss->next;
|
||||
if (ll < nl)
|
||||
nl = ll;
|
||||
if (ll > pl)
|
||||
pl = ll;
|
||||
if (tok != ',')
|
||||
break;
|
||||
next();
|
||||
c++;
|
||||
ll++;
|
||||
/* NOTE: we accept a trailing comma */
|
||||
if (tok == '}')
|
||||
break;
|
||||
}
|
||||
if (!seen_neg)
|
||||
s->a.unsigned_enum = 1;
|
||||
s->c = type_size(seen_wide ? &size_type : &int_type, &align);
|
||||
skip('}');
|
||||
/* set integral type of the enum */
|
||||
t.t = VT_INT;
|
||||
if (nl == 0) {
|
||||
if (pl != (unsigned)pl)
|
||||
t.t = VT_LLONG;
|
||||
t.t |= VT_UNSIGNED;
|
||||
} else if (pl != (int)pl || nl != (int)nl)
|
||||
t.t = VT_LLONG;
|
||||
s->type.t = type->t = t.t | VT_ENUM;
|
||||
s->c = 0;
|
||||
/* set type for enum members */
|
||||
for (ss = s->next; ss; ss = ss->next) {
|
||||
ll = ss->enum_val;
|
||||
if (ll == (int)ll) /* default is int if it fits */
|
||||
continue;
|
||||
if (t.t & VT_UNSIGNED) {
|
||||
ss->type.t |= VT_UNSIGNED;
|
||||
if (ll == (unsigned)ll)
|
||||
continue;
|
||||
}
|
||||
ss->type.t = (ss->type.t & ~VT_BTYPE) | VT_LLONG;
|
||||
}
|
||||
} else {
|
||||
ps = &s->next;
|
||||
c = 0;
|
||||
flexible = 0;
|
||||
while (tok != '}') {
|
||||
if (!parse_btype(&btype, &ad1)) {
|
||||
@ -3646,7 +3640,6 @@ do_decl:
|
||||
bt != VT_BYTE &&
|
||||
bt != VT_SHORT &&
|
||||
bt != VT_BOOL &&
|
||||
bt != VT_ENUM &&
|
||||
bt != VT_LLONG)
|
||||
tcc_error("bitfields must have scalar type");
|
||||
bsize = size * 8;
|
||||
@ -3657,9 +3650,9 @@ do_decl:
|
||||
/* no need for bit fields */
|
||||
;
|
||||
} else {
|
||||
type1.t |= VT_BITFIELD |
|
||||
(0 << VT_STRUCT_SHIFT) |
|
||||
(bit_size << (VT_STRUCT_SHIFT + 6));
|
||||
type1.t = (type1.t & ~VT_STRUCT_MASK)
|
||||
| VT_BITFIELD
|
||||
| (bit_size << (VT_STRUCT_SHIFT + 6));
|
||||
}
|
||||
}
|
||||
if (v != 0 || (type1.t & VT_BTYPE) == VT_STRUCT) {
|
||||
@ -4124,6 +4117,7 @@ static CType *type_decl(CType *type, AttributeDef *ad, int *v, int td)
|
||||
storage = type->t & VT_STORAGE;
|
||||
type->t &= ~VT_STORAGE;
|
||||
post = ret = type;
|
||||
|
||||
while (tok == '*') {
|
||||
qualifiers = 0;
|
||||
redo:
|
||||
@ -4813,8 +4807,11 @@ ST_FUNC void unary(void)
|
||||
Will be used by at least the x86 inline asm parser for
|
||||
regvars. */
|
||||
vtop->sym = s;
|
||||
if (vtop->r & VT_SYM) {
|
||||
|
||||
if (r & VT_SYM) {
|
||||
vtop->c.i = 0;
|
||||
} else if (r == VT_CONST && IS_ENUM_VAL(s->type.t)) {
|
||||
vtop->c.i = s->enum_val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -6352,7 +6349,7 @@ static void decl_initializer(CType *type, Section *sec, unsigned long c,
|
||||
/* Use i_c_parameter_t, to strip toplevel qualifiers.
|
||||
The source type might have VT_CONSTANT set, which is
|
||||
of course assignable to non-const elements. */
|
||||
is_compatible_parameter_types(type, &vtop->type)) {
|
||||
is_compatible_unqualified_types(type, &vtop->type)) {
|
||||
init_putv(type, sec, c);
|
||||
} else if (type->t & VT_ARRAY) {
|
||||
s = type->ref;
|
||||
@ -6858,16 +6855,18 @@ static int decl0(int l, int is_for_loop_init, Sym *func_sym)
|
||||
break;
|
||||
btype.t = VT_INT;
|
||||
}
|
||||
if (((btype.t & VT_BTYPE) == VT_ENUM ||
|
||||
(btype.t & VT_BTYPE) == VT_STRUCT) &&
|
||||
tok == ';') {
|
||||
if (tok == ';') {
|
||||
if ((btype.t & VT_BTYPE) == VT_STRUCT) {
|
||||
int v = btype.ref->v;
|
||||
if (!(v & SYM_FIELD) && (v & ~SYM_STRUCT) >= SYM_FIRST_ANOM)
|
||||
tcc_warning("unnamed struct/union that defines no instances");
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
next();
|
||||
continue;
|
||||
if (IS_ENUM(btype.t)) {
|
||||
next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (1) { /* iterate thru each declaration */
|
||||
type = btype;
|
||||
|
10
x86_64-gen.c
10
x86_64-gen.c
@ -415,9 +415,11 @@ void load(int r, SValue *sv)
|
||||
} else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
|
||||
b = 0xb70f; /* movzwl */
|
||||
} else {
|
||||
assert(((ft & VT_BTYPE) == VT_INT) || ((ft & VT_BTYPE) == VT_LLONG)
|
||||
|| ((ft & VT_BTYPE) == VT_PTR) || ((ft & VT_BTYPE) == VT_ENUM)
|
||||
|| ((ft & VT_BTYPE) == VT_FUNC));
|
||||
assert(((ft & VT_BTYPE) == VT_INT)
|
||||
|| ((ft & VT_BTYPE) == VT_LLONG)
|
||||
|| ((ft & VT_BTYPE) == VT_PTR)
|
||||
|| ((ft & VT_BTYPE) == VT_FUNC)
|
||||
);
|
||||
ll = is64_type(ft);
|
||||
b = 0x8b;
|
||||
}
|
||||
@ -1092,7 +1094,7 @@ static X86_64_Mode classify_x86_64_inner(CType *ty)
|
||||
case VT_BOOL:
|
||||
case VT_PTR:
|
||||
case VT_FUNC:
|
||||
case VT_ENUM: return x86_64_mode_integer;
|
||||
return x86_64_mode_integer;
|
||||
|
||||
case VT_FLOAT:
|
||||
case VT_DOUBLE: return x86_64_mode_sse;
|
||||
|
Loading…
Reference in New Issue
Block a user