~mcf/cproc

b345b989c87aa0515bfd1d9206c3c80831923b1c — Michael Forney 1 year, 7 months ago cbff9bf
Make basic types have their own kind
4 files changed, 110 insertions(+), 117 deletions(-)

M cc.h
M decl.c
M qbe.c
M type.c
M cc.h => cc.h +10 -13
@@ 133,7 133,16 @@ enum typekind {
	TYPENONE,

	TYPEVOID,
	TYPEBASIC,
	TYPEBOOL,
	TYPECHAR,
	TYPESHORT,
	TYPEINT,
	TYPEENUM,
	TYPELONG,
	TYPELLONG,
	TYPEFLOAT,
	TYPEDOUBLE,
	TYPELDOUBLE,
	TYPEPOINTER,
	TYPEARRAY,
	TYPEFUNC,


@@ 191,18 200,6 @@ struct type {
	_Bool incomplete;
	union {
		struct {
			enum {
				BASICBOOL,
				BASICCHAR,
				BASICSHORT,
				BASICINT,
				BASICENUM,
				BASICLONG,
				BASICLLONG,
				BASICFLOAT,
				BASICDOUBLE,
				BASICLDOUBLE,
			} kind;
			_Bool issigned, iscomplex;
		} basic;
		struct {

M decl.c => decl.c +7 -6
@@ 160,7 160,7 @@ tagspec(struct scope *s)
	switch (tok.kind) {
	case TSTRUCT: kind = TYPESTRUCT; break;
	case TUNION:  kind = TYPEUNION;  break;
	case TENUM:   kind = TYPEBASIC;  break;
	case TENUM:   kind = TYPEENUM;   break;
	default: fatal("internal error: unknown tag kind");
	}
	next();


@@ 168,7 168,7 @@ tagspec(struct scope *s)
		tag = tok.lit;
		next();
		t = scopegettag(s, tag, false);
		if (s->parent && !t && tok.kind != TLBRACE && (kind == TYPEBASIC || tok.kind != TSEMICOLON))
		if (s->parent && !t && tok.kind != TLBRACE && (kind == TYPEENUM || tok.kind != TSEMICOLON))
			t = scopegettag(s->parent, tag, true);
	} else if (tok.kind != TLBRACE) {
		error(&tok.loc, "expected identifier or '{' after struct/union");


@@ 180,11 180,12 @@ tagspec(struct scope *s)
		if (t->kind != kind)
			error(&tok.loc, "redeclaration of tag '%s' with different kind", tag);
	} else {
		t = mktype(kind);
		if (kind == TYPEBASIC) {
		if (kind == TYPEENUM) {
			t = xmalloc(sizeof(*t));
			*t = typeuint;
			t->basic.kind = BASICENUM;
			t->kind = kind;
		} else {
			t = mktype(kind);
			t->repr = &i64; // XXX
			t->size = 0;
			t->align = 0;


@@ 212,7 213,7 @@ tagspec(struct scope *s)
		t->size = ALIGNUP(t->size, t->align);
		t->incomplete = false;
		break;
	case TYPEBASIC:  /* enum */
	case TYPEENUM:
		for (i = 0; tok.kind == TIDENT; ++i) {
			d = mkdecl(DECLCONST, &typeint, QUALNONE, LINKNONE);
			scopeputdecl(s, tok.lit, d);

M qbe.c => qbe.c +39 -42
@@ 250,33 250,6 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval, 
	tp = typeprop(t);
	assert(!lval.bits.before && !lval.bits.after || tp & PROPINT);
	switch (t->kind) {
	case TYPEPOINTER:
		t = &typeulong;
		/* fallthrough */
	case TYPEBASIC:
		switch (t->size) {
		case 1: loadop = ILOADUB; storeop = ISTOREB; break;
		case 2: loadop = ILOADUH; storeop = ISTOREH; break;
		case 4: loadop = ILOADUW; storeop = tp & PROPFLOAT ? ISTORES : ISTOREW; break;
		case 8: loadop = ILOADL; storeop = tp & PROPFLOAT ? ISTORED : ISTOREL; break;
		default:
			fatal("internal error; unimplemented store");
		}
		if (lval.bits.before || lval.bits.after) {
			mask = 0xffffffffffffffffu >> lval.bits.after + 64 - t->size * 8 ^ (1 << lval.bits.before) - 1;
			v = funcinst(f, IOR, t->repr,
				funcinst(f, IAND, t->repr,
					funcinst(f, loadop, t->repr, lval.addr),
					mkintconst(t->repr, ~mask),
				),
				funcinst(f, IAND, t->repr,
					funcinst(f, ISHL, t->repr, v, mkintconst(&i32, lval.bits.before)),
					mkintconst(t->repr, mask),
				),
			);
		}
		funcinst(f, storeop, NULL, v, lval.addr);
		break;
	case TYPESTRUCT:
	case TYPEUNION:
	case TYPEARRAY: {


@@ 302,8 275,34 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval, 
		}
		break;
	}
	case TYPEPOINTER:
		t = &typeulong;
		/* fallthrough */
	default:
		fatal("unimplemented store");
		assert(tp & PROPSCALAR);
		switch (t->size) {
		case 1: loadop = ILOADUB; storeop = ISTOREB; break;
		case 2: loadop = ILOADUH; storeop = ISTOREH; break;
		case 4: loadop = ILOADUW; storeop = tp & PROPFLOAT ? ISTORES : ISTOREW; break;
		case 8: loadop = ILOADL; storeop = tp & PROPFLOAT ? ISTORED : ISTOREL; break;
		default:
			fatal("internal error; unimplemented store");
		}
		if (lval.bits.before || lval.bits.after) {
			mask = 0xffffffffffffffffu >> lval.bits.after + 64 - t->size * 8 ^ (1 << lval.bits.before) - 1;
			v = funcinst(f, IOR, t->repr,
				funcinst(f, IAND, t->repr,
					funcinst(f, loadop, t->repr, lval.addr),
					mkintconst(t->repr, ~mask),
				),
				funcinst(f, IAND, t->repr,
					funcinst(f, ISHL, t->repr, v, mkintconst(&i32, lval.bits.before)),
					mkintconst(t->repr, mask),
				),
			);
		}
		funcinst(f, storeop, NULL, v, lval.addr);
		break;
	}
}



@@ 314,16 313,6 @@ funcload(struct func *f, struct type *t, struct lvalue lval)
	enum instkind op;

	switch (t->kind) {
	case TYPEBASIC:
		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;
		default:
			fatal("internal error; unimplemented load");
		}
		break;
	case TYPEPOINTER:
		op = ILOADL;
		break;


@@ 335,7 324,15 @@ funcload(struct func *f, struct type *t, struct lvalue lval)
		v->repr = t->repr;
		return v;
	default:
		fatal("unimplemented load %d", t->kind);
		assert(typeprop(t) & 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;
		default:
			fatal("internal error; unimplemented load");
		}
	}
	v = funcinst(f, op, t->repr, lval.addr);
	if (lval.bits.after)


@@ 681,11 678,11 @@ funcexpr(struct func *f, struct expr *e)
			dst = &typeulong;
		if (dst->kind == TYPEVOID)
			return NULL;
		if (src->kind != TYPEBASIC || dst->kind != TYPEBASIC)
			fatal("internal error; unsupported conversion");
		srcprop = typeprop(src);
		dstprop = typeprop(dst);
		if (dst->basic.kind == BASICBOOL) {
		if (!(srcprop & PROPREAL) || !(dstprop & PROPREAL))
			fatal("internal error; unsupported conversion");
		if (dst->kind == TYPEBOOL) {
			l = extend(f, src, l);
			r = mkintconst(src->repr, 0);
			if (srcprop & PROPINT)

M type.c => type.c +54 -56
@@ 6,28 6,28 @@
#include "util.h"
#include "cc.h"

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

struct type typechar       = {.kind = TYPEBASIC, .size = 1, .align = 1, .repr = &i8, .basic = {.kind = BASICCHAR, .issigned = 1}};
struct type typeschar      = {.kind = TYPEBASIC, .size = 1, .align = 1, .repr = &i8, .basic = {.kind = BASICCHAR, .issigned = 1}};
struct type typeuchar      = {.kind = TYPEBASIC, .size = 1, .align = 1, .repr = &i8, .basic = {.kind = BASICCHAR}};
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 typeshort      = {.kind = TYPEBASIC, .size = 2, .align = 2, .repr = &i16, .basic = {.kind = BASICSHORT, .issigned = 1}};
struct type typeushort     = {.kind = TYPEBASIC, .size = 2, .align = 2, .repr = &i16, .basic = {.kind = BASICSHORT}};
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 typeint        = {.kind = TYPEBASIC, .size = 4, .align = 4, .repr = &i32, .basic = {.kind = BASICINT, .issigned = 1}};
struct type typeuint       = {.kind = TYPEBASIC, .size = 4, .align = 4, .repr = &i32, .basic = {.kind = BASICINT}};
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 typelong       = {.kind = TYPEBASIC, .size = 8, .align = 8, .repr = &i64, .basic = {.kind = BASICLONG, .issigned = 1}};
struct type typeulong      = {.kind = TYPEBASIC, .size = 8, .align = 8, .repr = &i64, .basic = {.kind = BASICLONG}};
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 typellong      = {.kind = TYPEBASIC, .size = 8, .align = 8, .repr = &i64, .basic = {.kind = BASICLLONG, .issigned = 1}};
struct type typeullong     = {.kind = TYPEBASIC, .size = 8, .align = 8, .repr = &i64, .basic = {.kind = BASICLLONG}};
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 typebool       = {.kind = TYPEBASIC, .size = 1, .align = 1, .repr = &i8, .basic = {.kind = BASICBOOL}};
struct type typefloat      = {.kind = TYPEBASIC, .size = 4, .align = 4, .repr = &f32, .basic = {.kind = BASICFLOAT}};
struct type typedouble     = {.kind = TYPEBASIC, .size = 8, .align = 8, .repr = &f64, .basic = {.kind = BASICDOUBLE}};
struct type typeldouble    = {.kind = TYPEBASIC, .size = 16, .align = 16, .basic = {.kind = BASICLDOUBLE}};  // XXX: not supported by qbe
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

static struct type typevaliststruct = {.kind = TYPESTRUCT, .size = 24, .align = 8};
struct type typevalist = {.kind = TYPEARRAY, .size = 24, .align = 8, .array = {1}, .base = &typevaliststruct};


@@ 81,47 81,47 @@ mkarraytype(struct type *base, enum typequal qual, uint64_t len)
enum typeprop
typeprop(struct type *t)
{
	enum typeprop p = PROPNONE;
	enum typeprop p;

	switch (t->kind) {
	case TYPEVOID:
		p |= PROPOBJECT;
		p = PROPOBJECT;
		break;
	case TYPEBASIC:
		p |= PROPOBJECT|PROPARITH|PROPSCALAR;
	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;
		switch (t->basic.kind) {
		case BASICFLOAT:
		case BASICDOUBLE:
		case BASICLDOUBLE:
			p |= PROPFLOAT;
			break;
		case BASICCHAR:
			p |= PROPCHAR;
			/* fallthrough */
		default:
			p |= PROPINT;
			break;
		}
		break;
	case TYPEPOINTER:
		p |= PROPOBJECT|PROPSCALAR|PROPDERIVED;
		p = PROPOBJECT|PROPSCALAR|PROPDERIVED;
		break;
	case TYPEARRAY:
		p |= PROPOBJECT|PROPAGGR|PROPDERIVED;
		p = PROPOBJECT|PROPAGGR|PROPDERIVED;
		break;
	case TYPEFUNC:
		p |= PROPDERIVED;
		p = PROPDERIVED;
		break;
	case TYPESTRUCT:
		p |= PROPOBJECT|PROPAGGR;
		p = PROPOBJECT|PROPAGGR;
		break;
	case TYPEUNION:
		p |= PROPOBJECT;
		p = PROPOBJECT;
		break;
	default:
		break;
		fatal("unknown type");
	}

	return p;


@@ 131,14 131,14 @@ static int
typerank(struct type *t)
{
	assert(typeprop(t) & PROPINT);
	switch (t->basic.kind) {
	case BASICBOOL:  return 1;
	case BASICCHAR:  return 2;
	case BASICSHORT: return 3;
	case BASICENUM:
	case BASICINT:   return 4;
	case BASICLONG:  return 5;
	case BASICLLONG: return 6;
	switch (t->kind) {
	case TYPEBOOL:  return 1;
	case TYPECHAR:  return 2;
	case TYPESHORT: return 3;
	case TYPEENUM:
	case TYPEINT:   return 4;
	case TYPELONG:  return 5;
	case TYPELLONG: return 6;
	default:
		fatal("internal error; unhandled integer type");
	}


@@ 152,16 152,14 @@ typecompatible(struct type *t1, struct type *t2)

	if (t1 == t2)
		return true;
	if (t1->kind != t2->kind)
		return false;
	switch (t1->kind) {
	case TYPEBASIC:
		if (t1->basic.issigned != t2->basic.issigned)
			return false;
	if (t1->kind != t2->kind) {
		/* enum types are compatible with 'int', but not with
		   each other (unless they are the same type) */
		return t1->basic.kind == BASICENUM && t2->basic.kind == BASICINT ||
		       t1->basic.kind == BASICINT && t2->basic.kind == BASICENUM;
		return (t1->kind == TYPEENUM && t2->kind == TYPEINT ||
		        t1->kind == TYPEINT && t2->kind == TYPEENUM) &&
		       t1->basic.issigned == t2->basic.issigned;
	}
	switch (t1->kind) {
	case TYPEVOID:
		return true;
	case TYPEPOINTER:


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

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