#include #include #include #include #include #include "type.h" void type_dump_func(struct type *t, FILE *fp) { struct tfield *arg; type_dump(t->func.type, fp); fputs(" (*)(", fp); if (!t->func.args) { fputs("void)", fp); return; } for (arg = t->func.args; arg->type != T_VOID; arg++) { if (arg != t->func.args) fputs(", ", fp); type_dump(arg->type, fp); } fputc(')', fp); } void type_dump(struct type *t, FILE *fp) { if (!t) { fputs("", fp); return; } switch (t->ttype){ case T_VOID: fputs("void", fp); break; case T_TYPEDEF: fputs(t->tdef.name, fp); break; case T_SCALAR: fputs(t->scalar.name, fp); break; case T_POINTER: type_dump(t->ptr.type, fp); fputs(" *", fp); break; case T_ARRAY: type_dump(t->array.type, fp); fprintf(fp, "[%zu]", t->array.len); break; case T_STRUCT: fputs("struct ", fp); fputs(t->sou.name, fp); break; case T_UNION: fputs("union ", fp); fputs(t->sou.name, fp); break; case T_FUNC: type_dump_func(t, fp); break; case T_MAP: fputs("map [", fp); type_dump(t->map.ktype, fp); fputs("] ", fp); type_dump(t->map.vtype, fp); break; } } void type_dump_cdecl_sou(struct type *t, FILE *fp) { struct tfield *f; type_dump(t, fp); fputs(" {\n", fp); for (f = t->sou.fields; f->type; f++) { fputc('\t', fp); type_dump(f->type, fp); fprintf(fp, " %s;\n", f->name); } fputs("}", fp); } void type_dump_cdecl(struct type *t, FILE *fp) { switch (t->ttype) { case T_TYPEDEF: fputs("typedef ", fp); type_dump(t->tdef.type, fp); fprintf(fp, " %s", t->tdef.name); break; case T_STRUCT: case T_UNION: type_dump_cdecl_sou(t, fp); break; case T_VOID: case T_SCALAR: case T_POINTER: case T_ARRAY: case T_MAP: case T_FUNC: type_dump(t, fp); break; } } /* void types_dump_cdecl(FILE *fp) */ /* { */ /* size_t i; */ /* for (i = 0; i < types.len; i++) { */ /* struct type *t = types.type[i]; */ /* type_dump_cdecl(t, stdout); */ /* printf(" \n", t->size); */ /* } */ /* } */ /* struct type *type_map_of(struct type *ktype, struct type *vtype) */ /* { */ /* struct type *t; */ /* size_t i; */ /* for (i = 0; i < types.len; i++) { */ /* t = types.type[i]; */ /* if ((t->ttype == T_MAP) */ /* && (t->map.ktype == ktype) */ /* && (t->map.vtype == vtype)) */ /* return t; */ /* } */ /* t = calloc(1, sizeof(*t)); */ /* t->ttype = T_MAP; */ /* t->map.vtype = vtype; */ /* t->map.ktype = ktype; */ /* type_add(t); */ /* return t; */ /* } */ /* struct type *type_ptr_of(struct type *type) */ /* { */ /* struct type *t; */ /* size_t i; */ /* for (i = 0; i < types.len; i++) { */ /* t = types.type[i]; */ /* if ((t->ttype == T_POINTER) */ /* && (t->pointer.type == type)) */ /* return t; */ /* } */ /* t = calloc(1, sizeof(*t)); */ /* t->ttype = T_POINTER; */ /* t->pointer.type = type; */ /* type_add(t); */ /* return t; */ /* } */ struct type *type_normalize(struct type *t) { while (t->ttype == T_TYPEDEF) t = t->tdef.type; return t; } int type_equal(struct type *a, struct type *b) { /* TODO */ return a == b; } int type_compatible(struct type *a, struct type *b) { a = type_normalize(a); b = type_normalize(b); if (a->ttype != b->ttype) return 0; switch (a->ttype){ case T_VOID: case T_SCALAR: case T_POINTER: return 1; case T_ARRAY: if (a->array.len != b->array.len) return 0; return type_compatible(a->array.type, b->array.type); case T_STRUCT: case T_UNION: return !strcmp(a->sou.name, b->sou.name); case T_FUNC: return type_compatible(a->func.type, b->func.type); case T_MAP: return type_compatible(a->map.vtype, b->map.vtype); case T_TYPEDEF: assert(0); } assert(0); return 0; } /* void type_size_set_sou(struct type *t) */ /* { */ /* struct tfield *f; */ /* size_t size = 0; */ /* if (!t->sou.fields) */ /* return; */ /* for (f = t->sou.fields; f->name; f++) { */ /* /\* size of all members is now known yet, abort *\/ */ /* if (!f->type->size) */ /* return; */ /* if (!t->sou.packed) */ /* size += size % f->type->size; */ /* size += f->type->size; */ /* f->offset = size; */ /* } */ /* if (!t->sou.packed && size) { */ /* /\* align complete struct to requirements of first */ /* * member, if struct keep going downwards *\/ */ /* f = t->sou.fields; */ /* while (f->type->ttype == T_STRUCT) */ /* f = f->type->sou.fields; */ /* size += size % f->type->size; */ /* } */ /* t->size = size; */ /* } */ /* void type_size_set(struct type *t) */ /* { */ /* switch (t->ttype) { */ /* case T_TYPEDEF: */ /* t->size = t->tdef.type->size; */ /* break; */ /* case T_STRUCT: */ /* case T_UNION: */ /* type_size_set_sou(t); */ /* break; */ /* case T_FUNC: */ /* t->size = t->func.type->size; */ /* assert(t->func.generate_ir); */ /* break; */ /* case T_SCALAR: */ /* break; */ /* case T_POINTER: */ /* t->size = sizeof(void *); */ /* break; */ /* case T_ARRAY: */ /* t->size = t->array.len * t->array.type->size; */ /* break; */ /* case T_MAP: */ /* /\* map fds are s64:s *\/ */ /* t->size = 8; */ /* break; */ /* } */ /* } */ static ssize_t type_alignof_union(struct type *t) { ssize_t amax = -EINVAL; struct tfield *f; for (f = t->sou.fields; f->type != T_VOID; f++) { ssize_t a; a = type_alignof(f->type); if (a < 0) return a; if (a > amax) amax = a; } return amax; } ssize_t type_alignof(struct type *t) { switch (t->ttype){ case T_VOID: case T_SCALAR: case T_POINTER: case T_FUNC: case T_MAP: return type_sizeof(t); case T_TYPEDEF: return type_alignof(t->tdef.type); case T_ARRAY: return type_alignof(t->array.type); case T_STRUCT: if (!t->sou.fields) return type_alignof(&t_void); return type_alignof(t->sou.fields->type); case T_UNION: if (!t->sou.fields) return type_alignof(&t_void); return type_alignof_union(t); } return -EINVAL; } static ssize_t type_sizeof_struct(struct type *t) { struct tfield *f; size_t size = 0; ssize_t fsize; if (!t->sou.fields) return 0; for (f = t->sou.fields; f->name; f++) { /* size of all members is now known yet, abort */ fsize = type_sizeof(f->type); if (fsize < 0) return fsize; size += fsize; if (!t->sou.packed) size += size % type_alignof(f->type); } if (!t->sou.packed && size) size += size % type_alignof(t); return size; } static ssize_t type_sizeof_union(struct type *t) { struct tfield *f; ssize_t size = 0; if (!t->sou.fields) return 0; for (f = t->sou.fields; f->name; f++) { ssize_t z, a; z = type_sizeof(f->type); a = t->sou.packed ? type_alignof(f->type) : 0; if ((z < 0) || (a < 0)) return -EINVAL; z += z % a; if (z > size) size = z; } return size; } ssize_t type_sizeof(struct type *t) { switch (t->ttype){ case T_VOID: return sizeof(void); case T_SCALAR: return t->scalar.size; case T_TYPEDEF: return type_sizeof(t->tdef.type); case T_POINTER: case T_FUNC: return sizeof(void *); case T_ARRAY: return t->array.len * type_sizeof(t->array.type); case T_STRUCT: return type_sizeof_struct(t); case T_UNION: return type_sizeof_union(t); case T_MAP: return sizeof(int); } return -EINVAL; } /* int type_walk_fields(struct tfield *f, twalk_fn pre, twalk_fn post, void *ctx) */ /* { */ /* if (!f) */ /* return 0; */ /* while (f->type != T_VOID) { */ /* if (pre && (err = pre(f->type, ctx))) */ /* return err; */ /* err = type_walk(f->type, pre, post, ctx); */ /* if (err) */ /* return err; */ /* if (post && (err = post(f->type, ctx))) */ /* return err; */ /* } */ /* } */ /* int type_walk(struct type *t, twalk_fn pre, twalk_fn post, void *ctx) */ /* { */ /* int err; */ /* if (pre && (err = pre(t, ctx))) */ /* return err; */ /* switch (t->ttype){ */ /* case T_VOID: */ /* case T_SCALAR: */ /* break; */ /* case T_TYPEDEF: */ /* err = type_walk(t->tdef.type, pre, post, ctx); */ /* break; */ /* case T_POINTER: */ /* err = type_walk(t->ptr.type, pre, post, ctx); */ /* break; */ /* case T_ARRAY: */ /* err = type_walk(t->array.type, pre, post, ctx); */ /* break; */ /* case T_STRUCT: */ /* case T_UNION: */ /* err = type_walk_fields(t->sou.fields, pre, post, ctx); */ /* break; */ /* case T_FUNC: */ /* err = type_walk_fields(t->func.args, pre, post, ctx); */ /* break; */ /* case T_MAP: */ /* err = type_walk(t->map.ktype, pre, post, ctx); */ /* if (err) */ /* break; */ /* err = type_walk(t->map.vtype, pre, post, ctx); */ /* break; */ /* } */ /* if (err) */ /* return err; */ /* if (post && (err = post(t, ctx))) */ /* return err; */ /* } */ int all_types_cmp(const void *_a, const void *_b) { const struct type *a = *((struct type **)_a); const struct type *b = *((struct type **)_b); return a - b; } struct type_list { struct type **types; size_t len; } all_types; int type_add(struct type *t) { if (bsearch(t, all_types.types, all_types.len, sizeof(*all_types.types), all_types_cmp)) return 0; /* type_size_set(t); */ all_types.types = realloc(all_types.types, ++all_types.len * sizeof(*all_types.types)); all_types.types[all_types.len - 1] = t; qsort(all_types.types, all_types.len, sizeof(*all_types.types), all_types_cmp); return 0; } int type_add_list(struct type **ts) { int err; for (; *ts; ts++) { err = type_add(*ts); if (err) return err; } return 0; } #define is_signed(_t) (((_t)(-1)) < 0) #define builtin_scalar(_t) { \ .ttype = T_SCALAR, \ .scalar = { \ .name = #_t, \ .size = sizeof(_t), \ .is_signed = is_signed(_t), \ }, \ } struct type t_void = { .ttype = T_VOID }; #pragma GCC diagnostic ignored "-Wtype-limits" /* is_signed will generate a warning for unsigned types since the * expression can never be true. this is exactly what we're interested * in here though. it gets us out of having to specify scalar * signedness per architecture. */ struct type t_char = builtin_scalar(char); struct type t_schar = builtin_scalar(signed char); struct type t_uchar = builtin_scalar(unsigned char); struct type t_short = builtin_scalar(short); struct type t_sshort = builtin_scalar(signed short); struct type t_ushort = builtin_scalar(unsigned short); struct type t_int = builtin_scalar(int); struct type t_sint = builtin_scalar(signed int); struct type t_uint = builtin_scalar(unsigned int); struct type t_long = builtin_scalar(long); struct type t_slong = builtin_scalar(signed long); struct type t_ulong = builtin_scalar(unsigned long); struct type t_llong = builtin_scalar(long long); struct type t_sllong = builtin_scalar(signed long long); struct type t_ullong = builtin_scalar(unsigned long long); #pragma GCC diagnostic pop struct type *builtin_types[] = { &t_void, &t_char, &t_schar, &t_uchar, &t_short, &t_sshort, &t_ushort, &t_int, &t_sint, &t_uint, &t_long, &t_slong, &t_ulong, &t_llong, &t_sllong, &t_ullong, NULL }; __attribute__((constructor)) static void type_init(void) { type_add_list(builtin_types); }