shithub: scc

ref: ad3e410e18f471cc42104b7f39f195fb5d819b7a
dir: /cc1/types.c/

View raw version
/* See LICENSE file for copyright and license details. */
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../inc/sizes.h"
#include "../inc/cc.h"
#include "arch.h"
#include "cc1.h"
#include "arch.h"

#define NR_TYPE_HASH 16

/* FIXME:
 * Compiler can generate warnings here if the ranges of TINT,
 * TUINT and TFLOAT are smaller than any of the constants in this
 * array. Ignore them if you know that the target types are correct
 */
static struct limits limits[][4] = {
	{
		{	/* 0 = unsigned 1 byte */
			.min.i = 0,
			.max.i = 255
		},
		{	/* 1 = unsigned 2 bytes */
			.min.i = 0,
			.max.i = 65535u
		},
		{	/* 2 = unsigned 4 bytes */
			.min.i = 0,
			.max.i = 4294967295u
		},
		{	/* 3 = unsigned 8 bytes */
			.min.i = 0,
			.max.i = 18446744073709551615u
		}
	},
	{
		{	/* 0 = signed 1 byte */
			.min.i = -127,
			.max.i = 127
		},
		{	/* 1 = signed 2 byte */
			.min.i = -32767,
			.max.i = 32767
		},
		{	/* 2 = signed 4 byte */
			.min.i = -2147483647L,
			.max.i = 2147483647L
		},
		{	/* 3 = signed 8 byte */
			.min.i = -9223372036854775807LL,
			.max.i = 9223372036854775807LL,
		}
	},
	{
		{
			/* 0 = float 4 bytes */
			.min.f = -1,
			.max.f = 2
		},
		{
			/* 1 = float 8 bytes */
			.min.f = -1,
			.max.f = 2,
		},
		{
			/* 2 = float 16 bytes */
			.min.f = -1,
			.max.f = 2,
		}
	}
};

struct limits *
getlimits(Type *tp)
{
	int ntable, ntype;

	switch (tp->op) {
	case ENUM:
	case INT:
		ntable = ((tp->prop & TSIGNED) != 0);
		switch (tp->size) {
		case 1: ntype = 0; break;
		case 2: ntype = 1; break;
		case 4: ntype = 2; break;
		case 8: ntype = 3; break;
		}
		break;
	case FLOAT:
		ntable = 2;
		switch (tp->size) {
		case 4:  ntype = 0; break;
		case 8:  ntype = 1; break;
		case 16: ntype = 2; break;
		}
		break;
	default:
		abort();
	}

	return &limits[ntable][ntype];
}

Type *
ctype(unsigned type, unsigned sign, unsigned size)
{
	switch (type) {
	case CHAR:
		if (size)
			goto invalid_type;
		switch (sign) {
		case 0:
			return chartype;
		case SIGNED:
			return schartype;
		case UNSIGNED:
			return uchartype;
		}
		break;
	case VOID:
		if (size || sign)
			goto invalid_type;
		return voidtype;
	case BOOL:
		if (size || sign)
			goto invalid_type;
		return booltype;
	case 0:
		/* fallthrough */
	case INT:
		switch (size) {
		case 0:
			return (sign == UNSIGNED) ? uinttype   : inttype;
		case SHORT:
			return (sign == UNSIGNED) ? ushortype  : shortype;
		case LONG:
			return (sign == UNSIGNED) ? ulongtype  : longtype;
		case LLONG:
			return (sign == UNSIGNED) ? ullongtype : llongtype;
		}
		break;
	case DOUBLE:
		if (size == LLONG)
			goto invalid_type;
		if (size == LONG)
			size = LLONG;
		else
			size = LONG;
		goto floating;
	case FLOAT:
		if (size == LLONG)
			goto invalid_type;
	floating:
		if (sign)
			goto invalid_type;
		switch (size) {
		case 0:
			return floattype;
		case LONG:
			return doubletype;
		case LLONG:
			return ldoubletype;
		}
		break;
	}

invalid_type:
	error("invalid type specification");
}

void
typesize(Type *tp)
{
	Symbol **sp;
	Type *aux;
	unsigned long size;
	int align, a;
	TINT n;

	switch (tp->op) {
	case ARY:
		/* FIXME: Control overflow */
		tp->size = tp->n.elem * tp->type->size;
		tp->align = tp->type->align;
		return;
	case PTR:
		tp->size = pvoidtype->size;
		tp->align = pvoidtype->align;
		return;
	case STRUCT:
	case UNION:
		/* FIXME: Control overflow */
		/*
		 * The alignment of the struct/union is
		 * he alignment of the largest included type.
		 * The size of an union is the size of the largest
		 * field, and the size of a struct is the sum
		 * of the size of every field plus padding bits.
		 */
		align = size = 0;
		n = tp->n.elem;
		for (sp = tp->p.fields; n--; ++sp) {
			(*sp)->u.i = size;
			aux = (*sp)->type;
			a = aux->align;
			if (a > align)
				align = a;
			if (tp->op == STRUCT) {
				if (--a != 0)
					size += (size + a) & ~a;
				size += aux->size;
			} else {
				if (tp->size > size)
					size = aux->size;
			}
		}

		tp->align = align;
		/*
		 * We have to add the padding bits to
		 * ensure next struct in an array is well
		 * alignment.
		 */
		if (tp->op == STRUCT && align-- > 1)
			size += size + align & ~align;
		tp->size = size;
		return;
	case ENUM:
		tp->size = inttype->size;
		tp->align = inttype->align;
		return;
	case FTN:
		return;
	default:
		abort();
	}
}

Type *
mktype(Type *tp, int op, TINT nelem, Type *pars[])
{
	static Type *typetab[NR_TYPE_HASH];
	Type **tbl, type;
	unsigned t;
	Type *bp;
	int c, k_r = 0;

	if (op == PTR && tp == voidtype)
		return pvoidtype;

	if (op == KRFTN) {
		k_r = 1;
		op = FTN;
	}
	switch (op) {
	case PTR:     c = L_POINTER;  break;
	case ARY:     c = L_ARRAY;    break;
	case FTN:     c = L_FUNCTION; break;
	case ENUM:    c = L_ENUM;     break;
	case STRUCT:  c = L_STRUCT;   break;
	case UNION:   c = L_UNION;    break;
	}

	type.type = tp;
	type.op = op;
	type.prop = k_r ? TK_R : 0;
	type.letter = c;
	type.p.pars = pars;
	type.n.elem = nelem;
	type.ns = 0;

	switch (op) {
	case ARY:
		if (nelem == 0)
			break;
		/* PASSTROUGH */
	case FTN:
	case PTR:
		type.prop |= TDEFINED;
		break;
	case ENUM:
		type.prop |= TPRINTED | TINTEGER | TARITH;
		type.n.rank = RANK_INT;
		break;
	case STRUCT:
	case UNION:
		type.prop |= TAGGREG;
		break;
	default:
		abort();
	}

	t = (op ^ (uintptr_t) tp >> 3) & NR_TYPE_HASH-1;
	tbl = &typetab[t];
	for (bp = *tbl; bp; bp = bp->next) {
		if (eqtype(bp, &type, 0) && op != STRUCT && op != UNION) {
			/*
			 * pars was allocated by the caller
			 * but the type already exists, so
			 * we have to deallocte it
			 */
			free(pars);
			return bp;
		}
	}

	typesize(&type);
	bp = duptype(&type);
	bp->next = *tbl;
	return *tbl = bp;
}

int
eqtype(Type *tp1, Type *tp2, int equiv)
{
	TINT n;
	Type **p1, **p2;

	if (tp1 == tp2)
		return 1;
	if (!tp1 || !tp2)
		return 0;
	if (tp1->op != tp2->op)
		return 0;
	switch (tp1->op) {
	case UNION:
	case STRUCT:
	case FTN:
		if (tp1->n.elem != tp2->n.elem)
			return 0;
		p1 = tp1->p.pars, p2 = tp2->p.pars;
		for (n = tp1->n.elem; n > 0; --n) {
			if (!eqtype(*p1++, *p2++, equiv))
				return 0;
		}
		goto check_base;
	case ARY:
		if (equiv && (tp1->n.elem == 0 || tp2->n.elem == 0))
			goto check_base;
		if (tp1->n.elem != tp2->n.elem)
			return 0;
	case PTR:
	check_base:
		return eqtype(tp1->type, tp2->type, equiv);
	case VOID:
	case ENUM:
		return 0;
	case INT:
	case FLOAT:
		return tp1->letter == tp2->letter;
	default:
		abort();
	}
}