~mcf/cproc

9463599fdf38b50afcc68f568cf6ad682428ce74 — Michael Forney 1 year, 7 months ago 220ec69
Keep track of type properties in type
9 files changed, 98 insertions(+), 127 deletions(-)

M cc.h
M decl.c
M doc/software.md
M eval.c
M expr.c
M init.c
M qbe.c
M stmt.c
M type.c
M cc.h => cc.h +2 -1
@@ 188,6 188,7 @@ struct member {

struct type {
	enum typekind kind;
	enum typeprop prop;
	int align;
	uint64_t size;
	struct repr *repr;


@@ 390,7 391,7 @@ _Bool consume(int);

/* type */

struct type *mktype(enum typekind);
struct type *mktype(enum typekind, enum typeprop);
struct type *mkpointertype(struct type *, enum typequal);
struct type *mkarraytype(struct type *, enum typequal, uint64_t);


M decl.c => decl.c +6 -4
@@ 185,7 185,9 @@ tagspec(struct scope *s)
			*t = typeuint;
			t->kind = kind;
		} else {
			t = mktype(kind);
			t = mktype(kind, PROPOBJECT);
			if (kind == TYPESTRUCT)
				t->prop |= PROPAGGR;
			t->repr = &i64; // XXX
			t->size = 0;
			t->align = 0;


@@ 220,7 222,7 @@ tagspec(struct scope *s)
			next();
			if (consume(TASSIGN)) {
				e = constexpr(s);
				if (e->kind != EXPRCONST || !(typeprop(e->type) & PROPINT))
				if (e->kind != EXPRCONST || !(e->type->prop & PROPINT))
					error(&tok.loc, "expected integer constant expression");
				if (e->type->basic.issigned && e->constant.i >= 1ull << 63)
					t->basic.issigned = true;


@@ 480,7 482,7 @@ declaratortypes(struct scope *s, struct list *result, char **name, bool allowabs
		case TLPAREN:  /* function declarator */
			next();
		func:
			t = mktype(TYPEFUNC);
			t = mktype(TYPEFUNC, PROPDERIVED);
			t->qual = QUALNONE;
			t->func.isprototype = false;
			t->func.isvararg = false;


@@ 676,7 678,7 @@ addmember(struct structbuilder *b, struct qualtype mt, char *name, int align, ui
				t->size = mt.type->size;
		}
	} else {  /* bit-field */
		if (!(typeprop(mt.type) & PROPINT))
		if (!(mt.type->prop & PROPINT))
			error(&tok.loc, "bit-field has invalid type");
		if (align)
			error(&tok.loc, "alignment specified for bit-field");

M doc/software.md => doc/software.md +2 -2
@@ 23,8 23,8 @@ below) to avoid errors in unused `static inline` functions in musl's
things will break if any functions with `long double` get called.

```diff
-struct type typeldouble = {.kind = TYPELDOUBLE, .size = 16, .align = 16};  // XXX: not supported by qbe
+struct type typeldouble = {.kind = TYPELDOUBLE, .size = 8, .align = 8, .repr = &f64};
-struct type typeldouble = FLTTYPE(TYPELDOUBLE, 16, NULL);  // XXX: not supported by qbe
+struct type typeldouble = FLTTYPE(TYPELDOUBLE, 8, &f64);
```

Requires several patches available here:

M eval.c => eval.c +4 -4
@@ 12,7 12,7 @@ cast(struct expr *expr)
	unsigned size;

	size = expr->type->size;
	if (typeprop(expr->type) & PROPFLOAT)
	if (expr->type->prop & PROPFLOAT)
		size |= F;
	else if (expr->type->basic.issigned)
		size |= S;


@@ 31,7 31,7 @@ static void
binary(struct expr *expr, enum tokenkind op, struct expr *l, struct expr *r)
{
	expr->kind = EXPRCONST;
	if (typeprop(l->type) & PROPFLOAT)
	if (l->type->prop & PROPFLOAT)
		op |= F;
	else if (l->type->basic.issigned)
		op |= S;


@@ 126,9 126,9 @@ eval(struct expr *expr)
		l = eval(expr->cast.e);
		if (l->kind == EXPRCONST) {
			expr->kind = EXPRCONST;
			if (typeprop(l->type) & PROPINT && typeprop(expr->type) & PROPFLOAT)
			if (l->type->prop & PROPINT && expr->type->prop & PROPFLOAT)
				expr->constant.f = l->constant.i;
			else if (typeprop(l->type) & PROPFLOAT && typeprop(expr->type) & PROPINT)
			else if (l->type->prop & PROPFLOAT && expr->type->prop & PROPINT)
				expr->constant.i = l->constant.f;
			else
				expr->constant = l->constant;

M expr.c => expr.c +9 -9
@@ 126,8 126,8 @@ mkbinaryexpr(struct location *loc, enum tokenkind op, struct expr *l, struct exp
	struct type *t = NULL;
	enum typeprop lp, rp;

	lp = typeprop(l->type);
	rp = typeprop(r->type);
	lp = l->type->prop;
	rp = r->type->prop;
	switch (op) {
	case TLOR:
	case TLAND:


@@ 167,7 167,7 @@ mkbinaryexpr(struct location *loc, enum tokenkind op, struct expr *l, struct exp
		if (l->type->kind != TYPEPOINTER || !(rp & PROPINT))
			error(loc, "invalid operands to '+' operator");
		t = l->type;
		if (t->base->incomplete || !(typeprop(t->base) & PROPOBJECT))
		if (t->base->incomplete || !(t->base->prop & PROPOBJECT))
			error(loc, "pointer operand to '+' must be to complete object type");
		r = mkbinaryexpr(loc, TMUL, exprconvert(r, &typeulong), mkconstexpr(&typeulong, t->base->size));
		break;


@@ 178,7 178,7 @@ mkbinaryexpr(struct location *loc, enum tokenkind op, struct expr *l, struct exp
		}
		if (l->type->kind != TYPEPOINTER || !(rp & PROPINT) && r->type->kind != TYPEPOINTER)
			error(loc, "invalid operands to '-' operator");
		if (l->type->base->incomplete || !(typeprop(l->type->base) & PROPOBJECT))
		if (l->type->base->incomplete || !(l->type->base->prop & PROPOBJECT))
			error(loc, "pointer operand to '-' must be to complete object type");
		if (rp & PROPINT) {
			t = l->type;


@@ 551,7 551,7 @@ postfixexpr(struct scope *s, struct expr *r)
			}
			if (arr->type->base->incomplete)
				error(&tok.loc, "array is pointer to incomplete type");
			if (!(typeprop(idx->type) & PROPINT))
			if (!(idx->type->prop & PROPINT))
				error(&tok.loc, "index is not an integer type");
			e = mkunaryexpr(TMUL, mkbinaryexpr(&tok.loc, TADD, arr, idx));
			expect(TRBRACK, "after array index");


@@ 693,7 693,7 @@ unaryexpr(struct scope *s)
	case TLNOT:
		next();
		e = castexpr(s);
		if (!(typeprop(e->type) & PROPSCALAR))
		if (!(e->type->prop & PROPSCALAR))
			error(&tok.loc, "operator '!' must have scalar operand");
		e = mkbinaryexpr(&tok.loc, TEQL, e, mkconstexpr(&typeint, 0));
		break;


@@ 823,7 823,7 @@ nullpointer(struct expr *e)
{
	if (e->kind != EXPRCONST)
		return false;
	if (!(typeprop(e->type) & PROPINT) && (e->type->kind != TYPEPOINTER || e->type->base != &typevoid))
	if (!(e->type->prop & PROPINT) && (e->type->kind != TYPEPOINTER || e->type->base != &typevoid))
		return false;
	return e->constant.i == 0;
}


@@ 847,7 847,7 @@ condexpr(struct scope *s)
	f = e->cond.f->type;
	if (t == f) {
		e->type = t;
	} else if (typeprop(t) & PROPARITH && typeprop(f) & PROPARITH) {
	} else if (t->prop & PROPARITH && f->prop & PROPARITH) {
		e->type = commonreal(&e->cond.t, &e->cond.f);
	} else if (t == &typevoid && f == &typevoid) {
		e->type = &typevoid;


@@ 890,7 890,7 @@ intconstexpr(struct scope *s, bool allowneg)
	struct expr *e;

	e = constexpr(s);
	if (e->kind != EXPRCONST || !(typeprop(e->type) & PROPINT))
	if (e->kind != EXPRCONST || !(e->type->prop & PROPINT))
		error(&tok.loc, "not an integer constant expression");
	if (!allowneg && e->type->basic.issigned && e->constant.i > INT64_MAX)
		error(&tok.loc, "integer constant expression cannot be negative");

M init.c => init.c +2 -2
@@ 244,7 244,7 @@ parseinit(struct scope *s, struct type *t)
					expr = expr->unary.base;
					base = t->base;
					/* XXX: wide string literals */
					if (!(typeprop(base) & PROPCHAR))
					if (!(base->prop & PROPCHAR))
						error(&tok.loc, "array initializer is string literal with incompatible type");
					if (t->incomplete)
						updatearray(t, expr->string.size);


@@ 257,7 257,7 @@ parseinit(struct scope *s, struct type *t)
					goto add;
				break;
			default:  /* scalar type */
				assert(typeprop(t) & PROPSCALAR);
				assert(t->prop & PROPSCALAR);
				expr = exprconvert(expr, t);
				goto add;
			}

M qbe.c => qbe.c +27 -30
@@ 247,7 247,7 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval, 
		error(&tok.loc, "volatile store is not yet supported");
	if (tq & QUALCONST)
		error(&tok.loc, "cannot store to 'const' object");
	tp = typeprop(t);
	tp = t->prop;
	assert(!lval.bits.before && !lval.bits.after || tp & PROPINT);
	switch (t->kind) {
	case TYPESTRUCT:


@@ 324,12 324,12 @@ funcload(struct func *f, struct type *t, struct lvalue lval)
		v->repr = t->repr;
		return v;
	default:
		assert(typeprop(t) & PROPREAL);
		assert(t->prop & PROPREAL);
		switch (t->size) {
		case 1: op = t->basic.issigned ? ILOADSB : ILOADUB; break;
		case 2: op = t->basic.issigned ? ILOADSH : ILOADUH; break;
		case 4: op = typeprop(t) & PROPFLOAT ? ILOADS : t->basic.issigned ? ILOADSW : ILOADUW; break;
		case 8: op = typeprop(t) & PROPFLOAT ? ILOADD : ILOADL; break;
		case 4: op = t->prop & PROPFLOAT ? ILOADS : t->basic.issigned ? ILOADSW : ILOADUW; break;
		case 8: op = t->prop & PROPFLOAT ? ILOADD : ILOADL; break;
		default:
			fatal("internal error; unimplemented load");
		}


@@ 618,7 618,7 @@ funcexpr(struct func *f, struct expr *e)
		}
		break;
	case EXPRCONST:
		if (typeprop(e->type) & PROPINT || e->type->kind == TYPEPOINTER)
		if (e->type->prop & PROPINT || e->type->kind == TYPEPOINTER)
			return mkintconst(e->type->repr, e->constant.i);
		return mkfltconst(e->type->repr, e->constant.f);
	case EXPRBITFIELD:


@@ 630,9 630,9 @@ funcexpr(struct func *f, struct expr *e)
		l = funcload(f, e->incdec.base->type, lval);
		if (e->type->kind == TYPEPOINTER)
			r = mkintconst(e->type->repr, e->type->base->size);
		else if (typeprop(e->type) & PROPINT)
		else if (e->type->prop & PROPINT)
			r = mkintconst(e->type->repr, 1);
		else if (typeprop(e->type) & PROPFLOAT)
		else if (e->type->prop & PROPFLOAT)
			r = mkfltconst(e->type->repr, 1);
		else
			fatal("not a scalar");


@@ 665,7 665,6 @@ funcexpr(struct func *f, struct expr *e)
		break;
	case EXPRCAST: {
		struct type *src, *dst;
		int srcprop, dstprop;

		l = funcexpr(f, e->cast.e);
		r = NULL;


@@ 678,19 677,17 @@ funcexpr(struct func *f, struct expr *e)
			dst = &typeulong;
		if (dst->kind == TYPEVOID)
			return NULL;
		srcprop = typeprop(src);
		dstprop = typeprop(dst);
		if (!(srcprop & PROPREAL) || !(dstprop & PROPREAL))
		if (!(src->prop & PROPREAL) || !(dst->prop & PROPREAL))
			fatal("internal error; unsupported conversion");
		if (dst->kind == TYPEBOOL) {
			l = extend(f, src, l);
			r = mkintconst(src->repr, 0);
			if (srcprop & PROPINT)
			if (src->prop & PROPINT)
				op = src->size == 8 ? ICNEL : ICNEW;
			else
				op = src->size == 8 ? ICNED : ICNES;
		} else if (dstprop & PROPINT) {
			if (srcprop & PROPINT) {
		} else if (dst->prop & PROPINT) {
			if (src->prop & PROPINT) {
				if (dst->size <= src->size) {
					op = ICOPY;
				} else {


@@ 707,7 704,7 @@ funcexpr(struct func *f, struct expr *e)
				op = src->size == 8 ? IDTOSI : ISTOSI;
			}
		} else {
			if (srcprop & PROPINT) {
			if (src->prop & PROPINT) {
				if (!src->basic.issigned)
					return utof(f, dst->repr, l);
				op = src->size == 8 ? ISLTOF : ISWTOF;


@@ 749,7 746,7 @@ funcexpr(struct func *f, struct expr *e)
			op = IMUL;
			break;
		case TDIV:
			op = !(typeprop(e->type) & PROPINT) || e->type->basic.issigned ? IDIV : IUDIV;
			op = !(e->type->prop & PROPINT) || e->type->basic.issigned ? IDIV : IUDIV;
			break;
		case TMOD:
			op = e->type->basic.issigned ? IREM : IUREM;


@@ 779,49 776,49 @@ funcexpr(struct func *f, struct expr *e)
			l = extend(f, t, l);
			r = extend(f, t, r);
			if (t->size <= 4)
				op = typeprop(t) & PROPFLOAT ? ICLTS : t->basic.issigned ? ICSLTW : ICULTW;
				op = t->prop & PROPFLOAT ? ICLTS : t->basic.issigned ? ICSLTW : ICULTW;
			else
				op = typeprop(t) & PROPFLOAT ? ICLTD : t->basic.issigned ? ICSLTL : ICULTL;
				op = t->prop & PROPFLOAT ? ICLTD : t->basic.issigned ? ICSLTL : ICULTL;
			break;
		case TGREATER:
			l = extend(f, t, l);
			r = extend(f, t, r);
			if (t->size <= 4)
				op = typeprop(t) & PROPFLOAT ? ICGTS : t->basic.issigned ? ICSGTW : ICUGTW;
				op = t->prop & PROPFLOAT ? ICGTS : t->basic.issigned ? ICSGTW : ICUGTW;
			else
				op = typeprop(t) & PROPFLOAT ? ICGTD : t->basic.issigned ? ICSGTL : ICUGTL;
				op = t->prop & PROPFLOAT ? ICGTD : t->basic.issigned ? ICSGTL : ICUGTL;
			break;
		case TLEQ:
			l = extend(f, t, l);
			r = extend(f, t, r);
			if (t->size <= 4)
				op = typeprop(t) & PROPFLOAT ? ICLES : t->basic.issigned ? ICSLEW : ICULEW;
				op = t->prop & PROPFLOAT ? ICLES : t->basic.issigned ? ICSLEW : ICULEW;
			else
				op = typeprop(t) & PROPFLOAT ? ICLED : t->basic.issigned ? ICSLEL : ICULEL;
				op = t->prop & PROPFLOAT ? ICLED : t->basic.issigned ? ICSLEL : ICULEL;
			break;
		case TGEQ:
			l = extend(f, t, l);
			r = extend(f, t, r);
			if (t->size <= 4)
				op = typeprop(t) & PROPFLOAT ? ICGES : t->basic.issigned ? ICSGEW : ICUGEW;
				op = t->prop & PROPFLOAT ? ICGES : t->basic.issigned ? ICSGEW : ICUGEW;
			else
				op = typeprop(t) & PROPFLOAT ? ICGED : t->basic.issigned ? ICSGEL : ICUGEL;
				op = t->prop & PROPFLOAT ? ICGED : t->basic.issigned ? ICSGEL : ICUGEL;
			break;
		case TEQL:
			l = extend(f, t, l);
			r = extend(f, t, r);
			if (t->size <= 4)
				op = typeprop(t) & PROPFLOAT ? ICEQS : ICEQW;
				op = t->prop & PROPFLOAT ? ICEQS : ICEQW;
			else
				op = typeprop(t) & PROPFLOAT ? ICEQD : ICEQL;
				op = t->prop & PROPFLOAT ? ICEQD : ICEQL;
			break;
		case TNEQ:
			l = extend(f, t, l);
			r = extend(f, t, r);
			if (t->size <= 4)
				op = typeprop(t) & PROPFLOAT ? ICNES : ICNEW;
				op = t->prop & PROPFLOAT ? ICNES : ICNEW;
			else
				op = typeprop(t) & PROPFLOAT ? ICNED : ICNEL;
				op = t->prop & PROPFLOAT ? ICNED : ICNEL;
			break;
		}
		if (op == INONE)


@@ 1194,7 1191,7 @@ dataitem(struct expr *expr, uint64_t size)
		dataitem(expr->binary.r, 0);
		break;
	case EXPRCONST:
		if (typeprop(expr->type) & PROPFLOAT)
		if (expr->type->prop & PROPFLOAT)
			printf("%c_%a", expr->type->size == 4 ? 's' : 'd', expr->constant.f);
		else
			printf("%" PRIu64, expr->constant.i);


@@ 1258,7 1255,7 @@ emitdata(struct decl *d, struct init *init)
			printf("z %" PRIu64 ", ", start - offset);
		if (cur->bits.before || cur->bits.after) {
			/* XXX: little-endian specific */
			assert(typeprop(cur->expr->type) & PROPINT);
			assert(cur->expr->type->prop & PROPINT);
			assert(cur->expr->kind == EXPRCONST);
			bits |= cur->expr->constant.i << cur->bits.before % 8;
			for (offset = start; offset < end; ++offset, bits >>= 8)

M stmt.c => stmt.c +1 -1
@@ 125,7 125,7 @@ stmt(struct func *f, struct scope *s)
		e = expr(s);
		expect(TRPAREN, "after expression");

		if (!(typeprop(e->type) & PROPINT))
		if (!(e->type->prop & PROPINT))
			error(&tok.loc, "controlling expression of switch statement must have integer type");
		e = exprconvert(e, typeintpromote(e->type));


M type.c => type.c +45 -74
@@ 6,40 6,60 @@
#include "util.h"
#include "cc.h"

struct type typevoid    = {.kind = TYPEVOID, .incomplete = true};
#define INTTYPE(k, n, r, s, p) { \
	.kind = k, .size = n, .align = n, .repr = r, .basic.issigned = s, \
	.prop = PROPOBJECT|PROPSCALAR|PROPARITH|PROPREAL|PROPINT|p, \
}
#define FLTTYPE(k, n, r) { \
	.kind = k, .size = n, .align = n, .repr = r, \
	.prop = PROPOBJECT|PROPSCALAR|PROPARITH|PROPREAL|PROPFLOAT, \
}

struct type typevoid    = {.kind = TYPEVOID, .prop = PROPOBJECT, .incomplete = true};

struct type typechar    = {.kind = TYPECHAR, .size = 1, .align = 1, .repr = &i8, .basic.issigned = 1};
struct type typeschar   = {.kind = TYPECHAR, .size = 1, .align = 1, .repr = &i8, .basic.issigned = 1};
struct type typeuchar   = {.kind = TYPECHAR, .size = 1, .align = 1, .repr = &i8};
struct type typebool    = INTTYPE(TYPEBOOL, 1, &i8, false, 0);

struct type typeshort   = {.kind = TYPESHORT, .size = 2, .align = 2, .repr = &i16, .basic.issigned = 1};
struct type typeushort  = {.kind = TYPESHORT, .size = 2, .align = 2, .repr = &i16};
struct type typechar    = INTTYPE(TYPECHAR, 1, &i8, true, PROPCHAR);
struct type typeschar   = INTTYPE(TYPECHAR, 1, &i8, true, PROPCHAR);
struct type typeuchar   = INTTYPE(TYPECHAR, 1, &i8, false, PROPCHAR);

struct type typeint     = {.kind = TYPEINT, .size = 4, .align = 4, .repr = &i32, .basic.issigned = 1};
struct type typeuint    = {.kind = TYPEINT, .size = 4, .align = 4, .repr = &i32};
struct type typeshort   = INTTYPE(TYPESHORT, 2, &i16, true, 0);
struct type typeushort  = INTTYPE(TYPESHORT, 2, &i16, false, 0);

struct type typelong    = {.kind = TYPELONG, .size = 8, .align = 8, .repr = &i64, .basic.issigned = 1};
struct type typeulong   = {.kind = TYPELONG, .size = 8, .align = 8, .repr = &i64};
struct type typeint     = INTTYPE(TYPEINT, 4, &i32, true, 0);
struct type typeuint    = INTTYPE(TYPEINT, 4, &i32, false, 0);

struct type typellong   = {.kind = TYPELLONG, .size = 8, .align = 8, .repr = &i64, .basic.issigned = 1};
struct type typeullong  = {.kind = TYPELLONG, .size = 8, .align = 8, .repr = &i64};
struct type typelong    = INTTYPE(TYPELONG, 8, &i64, true, 0);
struct type typeulong   = INTTYPE(TYPELONG, 8, &i64, false, 0);

struct type typebool    = {.kind = TYPEBOOL, .size = 1, .align = 1, .repr = &i8};
struct type typefloat   = {.kind = TYPEFLOAT, .size = 4, .align = 4, .repr = &f32};
struct type typedouble  = {.kind = TYPEDOUBLE, .size = 8, .align = 8, .repr = &f64};
struct type typeldouble = {.kind = TYPELDOUBLE, .size = 16, .align = 16};  // XXX: not supported by qbe
struct type typellong   = INTTYPE(TYPELLONG, 8, &i64, true, 0);
struct type typeullong  = INTTYPE(TYPELLONG, 8, &i64, false, 0);

static struct type typevaliststruct = {.kind = TYPESTRUCT, .size = 24, .align = 8};
struct type typevalist = {.kind = TYPEARRAY, .size = 24, .align = 8, .array = {1}, .base = &typevaliststruct};
struct type typevalistptr = {.kind = TYPEPOINTER, .size = 8, .align = 8, .repr = &i64, .base = &typevaliststruct};
struct type typefloat   = FLTTYPE(TYPEFLOAT, 4, &f32);
struct type typedouble  = FLTTYPE(TYPEDOUBLE, 8, &f64);
struct type typeldouble = FLTTYPE(TYPELDOUBLE, 16, NULL);  // XXX: not supported by qbe

static struct type typevaliststruct = {
	.kind = TYPESTRUCT, .size = 24, .align = 8,
	.prop = PROPOBJECT|PROPAGGR,
};
struct type typevalist = {
	.kind = TYPEARRAY, .size = 24, .align = 8, .array = {1}, .base = &typevaliststruct,
	.prop = PROPOBJECT|PROPDERIVED|PROPAGGR,
};
struct type typevalistptr = {
	.kind = TYPEPOINTER, .size = 8, .align = 8, .repr = &i64, .base = &typevaliststruct,
	.prop = PROPOBJECT|PROPDERIVED|PROPSCALAR,
};

struct type *
mktype(enum typekind kind)
mktype(enum typekind kind, enum typeprop prop)
{
	struct type *t;

	t = xmalloc(sizeof(*t));
	t->kind = kind;
	t->prop = prop;
	t->incomplete = 0;

	return t;


@@ 50,7 70,7 @@ mkpointertype(struct type *base, enum typequal qual)
{
	struct type *t;

	t = mktype(TYPEPOINTER);
	t = mktype(TYPEPOINTER, PROPOBJECT|PROPDERIVED|PROPSCALAR);
	t->base = base;
	t->qual = qual;
	t->size = 8;


@@ 65,7 85,7 @@ mkarraytype(struct type *base, enum typequal qual, uint64_t len)
{
	struct type *t;

	t = mktype(TYPEARRAY);
	t = mktype(TYPEARRAY, PROPOBJECT|PROPDERIVED|PROPAGGR);
	t->base = base;
	t->qual = qual;
	t->array.length = len;


@@ 78,59 98,10 @@ mkarraytype(struct type *base, enum typequal qual, uint64_t len)
	return t;
}

enum typeprop
typeprop(struct type *t)
{
	enum typeprop p;

	switch (t->kind) {
	case TYPEVOID:
		p = PROPOBJECT;
		break;
	case TYPECHAR:
		p = PROPOBJECT|PROPARITH|PROPSCALAR|PROPREAL|PROPINT|PROPCHAR;
		break;
	case TYPEBOOL:
	case TYPESHORT:
	case TYPEINT:
	case TYPEENUM:
	case TYPELONG:
	case TYPELLONG:
		p = PROPOBJECT|PROPARITH|PROPSCALAR|PROPREAL|PROPINT;
		break;
	case TYPEFLOAT:
	case TYPEDOUBLE:
	case TYPELDOUBLE:
		p = PROPOBJECT|PROPARITH|PROPSCALAR|PROPFLOAT;
		if (!t->basic.iscomplex)
			p |= PROPREAL;
		break;
	case TYPEPOINTER:
		p = PROPOBJECT|PROPSCALAR|PROPDERIVED;
		break;
	case TYPEARRAY:
		p = PROPOBJECT|PROPAGGR|PROPDERIVED;
		break;
	case TYPEFUNC:
		p = PROPDERIVED;
		break;
	case TYPESTRUCT:
		p = PROPOBJECT|PROPAGGR;
		break;
	case TYPEUNION:
		p = PROPOBJECT;
		break;
	default:
		fatal("unknown type");
	}

	return p;
}

static int
typerank(struct type *t)
{
	assert(typeprop(t) & PROPINT);
	assert(t->prop & PROPINT);
	switch (t->kind) {
	case TYPEBOOL:  return 1;
	case TYPECHAR:  return 2;


@@ 217,7 188,7 @@ typecomposite(struct type *t1, struct type *t2)
struct type *
typeintpromote(struct type *t)
{
	if (typeprop(t) & PROPINT && typerank(t) <= typerank(&typeint))
	if (t->prop & PROPINT && typerank(t) <= typerank(&typeint))
		return t->size < typeint.size || t->basic.issigned ? &typeint : &typeuint;
	return t;
}


@@ 235,7 206,7 @@ typecommonreal(struct type *t1, struct type *t2)
{
	struct type *tmp;

	assert(typeprop(t1) & PROPREAL && typeprop(t2) & PROPREAL);
	assert(t1->prop & PROPREAL && t2->prop & PROPREAL);
	if (t1 == t2)
		return t1;
	if (t1 == &typeldouble || t2 == &typeldouble)