summaryrefslogtreecommitdiff
path: root/util/romcc
diff options
context:
space:
mode:
Diffstat (limited to 'util/romcc')
-rw-r--r--util/romcc/romcc.c212
1 files changed, 141 insertions, 71 deletions
diff --git a/util/romcc/romcc.c b/util/romcc/romcc.c
index 1f5c91af82..af9c5552c6 100644
--- a/util/romcc/romcc.c
+++ b/util/romcc/romcc.c
@@ -957,10 +957,13 @@ static void loc(FILE *fp, struct compile_state *state, struct triple *triple)
{
int col;
if (triple) {
+ struct occurance *spot;
+ spot = triple->occurance;
+ while(spot->parent) {
+ spot = spot->parent;
+ }
fprintf(fp, "%s:%d.%d: ",
- triple->occurance->filename,
- triple->occurance->line,
- triple->occurance->col);
+ spot->filename, spot->line, spot->col);
return;
}
if (!state->file) {
@@ -4007,10 +4010,11 @@ static size_t field_offset(struct compile_state *state,
while((type->type & TYPE_MASK) == TYPE_PRODUCT) {
if (type->left->field_ident == field) {
type = type->left;
+ break;
}
size += size_of(state, type->left);
type = type->right;
- align = align_of(state, type->left);
+ align = align_of(state, type);
pad = align - (size % align);
size += pad;
}
@@ -4379,16 +4383,13 @@ static int is_lvalue(struct compile_state *state, struct triple *def)
if (!is_stable(state, def)) {
return 0;
}
- if (def->type->type & QUAL_CONST) {
- ret = 0;
- }
- else if (def->op == OP_DOT) {
+ if (def->op == OP_DOT) {
ret = is_lvalue(state, RHS(def, 0));
}
return ret;
}
-static void lvalue(struct compile_state *state, struct triple *def)
+static void clvalue(struct compile_state *state, struct triple *def)
{
if (!def) {
internal_error(state, def, "nothing where lvalue expected?");
@@ -4397,6 +4398,13 @@ static void lvalue(struct compile_state *state, struct triple *def)
error(state, def, "lvalue expected");
}
}
+static void lvalue(struct compile_state *state, struct triple *def)
+{
+ clvalue(state, def);
+ if (def->type->type & QUAL_CONST) {
+ error(state, def, "modifable lvalue expected");
+ }
+}
static int is_pointer(struct triple *def)
{
@@ -4432,7 +4440,7 @@ static struct triple *do_mk_addr_expr(struct compile_state *state,
struct triple *expr, struct type *type, ulong_t offset)
{
struct triple *result;
- lvalue(state, expr);
+ clvalue(state, expr);
result = 0;
if (expr->op == OP_ADECL) {
@@ -4469,10 +4477,6 @@ static struct triple *mk_deref_expr(
struct type *base_type;
pointer(state, expr);
base_type = expr->type->left;
- if (!TYPE_PTR(base_type->type) && !TYPE_ARITHMETIC(base_type->type)) {
- error(state, 0,
- "Only pointer and arithmetic values can be dereferenced");
- }
return triple(state, OP_DEREF, base_type, expr, 0);
}
@@ -4593,6 +4597,9 @@ static struct triple *write_expr(
if (!is_lvalue(state, dest)) {
internal_error(state, 0, "writing to a non lvalue?");
}
+ if (dest->type->type & QUAL_CONST) {
+ internal_error(state, 0, "modifable lvalue expexted");
+ }
write_compatible(state, dest->type, rval->type);
@@ -4790,6 +4797,9 @@ static int expr_depth(struct compile_state *state, struct triple *ins)
static struct triple *flatten(
struct compile_state *state, struct triple *first, struct triple *ptr);
+static struct triple *mk_add_expr(
+ struct compile_state *state, struct triple *left, struct triple *right);
+
static struct triple *flatten_generic(
struct compile_state *state, struct triple *first, struct triple *ptr)
{
@@ -5145,8 +5155,15 @@ static struct triple *flatten(
{
struct triple *base;
base = RHS(ptr, 0);
- base = flatten(state, first, base);
- if (base->op == OP_VAL_VEC) {
+ if (base->op == OP_DEREF) {
+ ulong_t offset;
+ offset = field_offset(state, base->type, ptr->u.field);
+ ptr = mk_add_expr(state, RHS(base, 0),
+ int_const(state, &ulong_type, offset));
+ free_triple(state, base);
+ }
+ else if (base->op == OP_VAL_VEC) {
+ base = flatten(state, first, base);
ptr = struct_field(state, base, ptr->u.field);
}
break;
@@ -5694,13 +5711,13 @@ static void flatten_structures(struct compile_state *state)
do {
ins->id &= ~TRIPLE_FLAG_FLATTENED;
if ((ins->type->type & TYPE_MASK) == TYPE_STRUCT) {
- internal_error(state, 0, "STRUCT_TYPE remains?");
+ internal_error(state, ins, "STRUCT_TYPE remains?");
}
if (ins->op == OP_DOT) {
- internal_error(state, 0, "OP_DOT remains?");
+ internal_error(state, ins, "OP_DOT remains?");
}
if (ins->op == OP_VAL_VEC) {
- internal_error(state, 0, "OP_VAL_VEC remains?");
+ internal_error(state, ins, "OP_VAL_VEC remains?");
}
ins = ins->next;
} while(ins != first);
@@ -7432,25 +7449,31 @@ static struct triple *eval_const_expr(
struct compile_state *state, struct triple *expr)
{
struct triple *def;
- struct triple *head, *ptr;
- head = label(state); /* dummy initial triple */
- flatten(state, head, expr);
- for(ptr = head->next; ptr != head; ptr = ptr->next) {
- simplify(state, ptr);
- }
- /* Remove the constant value the tail of the list */
- def = head->prev;
- def->prev->next = def->next;
- def->next->prev = def->prev;
- def->next = def->prev = def;
- if (!is_const(def)) {
- internal_error(state, 0, "Not a constant expression");
- }
- /* Free the intermediate expressions */
- while(head->next != head) {
- release_triple(state, head->next);
+ if (is_const(expr)) {
+ def = expr;
+ }
+ else {
+ /* If we don't start out as a constant simplify into one */
+ struct triple *head, *ptr;
+ head = label(state); /* dummy initial triple */
+ flatten(state, head, expr);
+ for(ptr = head->next; ptr != head; ptr = ptr->next) {
+ simplify(state, ptr);
+ }
+ /* Remove the constant value the tail of the list */
+ def = head->prev;
+ def->prev->next = def->next;
+ def->next->prev = def->prev;
+ def->next = def->prev = def;
+ if (!is_const(def)) {
+ error(state, 0, "Not a constant expression");
+ }
+ /* Free the intermediate expressions */
+ while(head->next != head) {
+ release_triple(state, head->next);
+ }
+ free_triple(state, head);
}
- free_triple(state, head);
return def;
}
@@ -8364,7 +8387,7 @@ static struct type *struct_declarator(
#endif
static struct type *struct_or_union_specifier(
- struct compile_state *state, unsigned int specifiers)
+ struct compile_state *state, unsigned int spec)
{
struct type *struct_type;
struct hash_entry *ident;
@@ -8424,13 +8447,13 @@ static struct type *struct_or_union_specifier(
eat(state, TOK_SEMI);
} while(peek(state) != TOK_RBRACE);
eat(state, TOK_RBRACE);
- struct_type = new_type(TYPE_STRUCT, struct_type, 0);
+ struct_type = new_type(TYPE_STRUCT | spec, struct_type, 0);
struct_type->type_ident = ident;
struct_type->elements = elements;
symbol(state, ident, &ident->sym_struct, 0, struct_type);
}
if (ident && ident->sym_struct) {
- struct_type = ident->sym_struct->type;
+ struct_type = clone_type(spec, ident->sym_struct->type);
}
else if (ident && !ident->sym_struct) {
error(state, 0, "struct %s undeclared", ident->name);
@@ -8762,34 +8785,67 @@ static struct type *decl_specifiers(struct compile_state *state)
return type;
}
-static unsigned designator(struct compile_state *state)
+struct field_info {
+ struct type *type;
+ size_t offset;
+};
+
+static struct field_info designator(struct compile_state *state, struct type *type)
{
int tok;
- unsigned index;
- index = -1U;
+ struct field_info info;
+ info.offset = ~0U;
+ info.type = 0;
do {
switch(peek(state)) {
case TOK_LBRACKET:
{
struct triple *value;
+ if ((type->type & TYPE_MASK) != TYPE_ARRAY) {
+ error(state, 0, "Array designator not in array initializer");
+ }
eat(state, TOK_LBRACKET);
value = constant_expr(state);
eat(state, TOK_RBRACKET);
- index = value->u.cval;
+
+ info.type = type->left;
+ info.offset = value->u.cval * size_of(state, info.type);
break;
}
case TOK_DOT:
+ {
+ struct hash_entry *field;
+ struct type *member;
+ if ((type->type & TYPE_MASK) != TYPE_STRUCT) {
+ error(state, 0, "Struct designator not in struct initializer");
+ }
eat(state, TOK_DOT);
eat(state, TOK_IDENT);
- error(state, 0, "Struct Designators not currently supported");
+ field = state->token[0].ident;
+ info.offset = 0;
+ member = type->left;
+ while((member->type & TYPE_MASK) == TYPE_PRODUCT) {
+ if (member->left->field_ident == field) {
+ member = member->left;
+ break;
+ }
+ info.offset += size_of(state, member->left);
+ member = member->right;
+ }
+ if (member->field_ident != field) {
+ error(state, 0, "%s is not a member",
+ field->name);
+ }
+ info.type = member;
break;
+ }
default:
error(state, 0, "Invalid designator");
}
tok = peek(state);
} while((tok == TOK_LBRACKET) || (tok == TOK_DOT));
eat(state, TOK_EQ);
- return index;
+ return info;
}
static struct triple *initializer(
@@ -8801,74 +8857,87 @@ static struct triple *initializer(
}
else {
int comma;
- unsigned index, max_index;
+ size_t max_offset;
+ struct field_info info;
void *buf;
- max_index = index = 0;
- if ((type->type & TYPE_MASK) == TYPE_ARRAY) {
- max_index = type->elements;
- if (type->elements == ELEMENT_COUNT_UNSPECIFIED) {
- type->elements = 0;
- }
+ if (((type->type & TYPE_MASK) != TYPE_ARRAY) &&
+ ((type->type & TYPE_MASK) != TYPE_STRUCT)) {
+ internal_error(state, 0, "unknown initializer type");
+ }
+ info.offset = 0;
+ info.type = type->left;
+ if (type->elements == ELEMENT_COUNT_UNSPECIFIED) {
+ max_offset = 0;
} else {
- error(state, 0, "Struct initializers not currently supported");
+ max_offset = size_of(state, type);
}
- buf = xcmalloc(size_of(state, type), "initializer");
+ buf = xcmalloc(max_offset, "initializer");
eat(state, TOK_LBRACE);
do {
struct triple *value;
struct type *value_type;
size_t value_size;
+ void *dest;
int tok;
comma = 0;
tok = peek(state);
if ((tok == TOK_LBRACKET) || (tok == TOK_DOT)) {
- index = designator(state);
+ info = designator(state, type);
}
- if ((max_index != ELEMENT_COUNT_UNSPECIFIED) &&
- (index > max_index)) {
+ if ((type->elements != ELEMENT_COUNT_UNSPECIFIED) &&
+ (info.offset >= max_offset)) {
error(state, 0, "element beyond bounds");
}
- value_type = 0;
- if ((type->type & TYPE_MASK) == TYPE_ARRAY) {
+ value_type = info.type;
+ if ((value_type->type & TYPE_MASK) == TYPE_PRODUCT) {
value_type = type->left;
}
value = eval_const_expr(state, initializer(state, value_type));
value_size = size_of(state, value_type);
if (((type->type & TYPE_MASK) == TYPE_ARRAY) &&
- (max_index == ELEMENT_COUNT_UNSPECIFIED) &&
- (type->elements <= index)) {
+ (type->elements == ELEMENT_COUNT_UNSPECIFIED) &&
+ (max_offset <= info.offset)) {
void *old_buf;
size_t old_size;
old_buf = buf;
- old_size = size_of(state, type);
- type->elements = index + 1;
- buf = xmalloc(size_of(state, type), "initializer");
+ old_size = max_offset;
+ max_offset = info.offset + value_size;
+ buf = xmalloc(max_offset, "initializer");
memcpy(buf, old_buf, old_size);
xfree(old_buf);
}
+ dest = ((char *)buf) + info.offset;
if (value->op == OP_BLOBCONST) {
- memcpy((char *)buf + index * value_size, value->u.blob, value_size);
+ memcpy(dest, value->u.blob, value_size);
}
else if ((value->op == OP_INTCONST) && (value_size == 1)) {
- *(((uint8_t *)buf) + index) = value->u.cval & 0xff;
+ *((uint8_t *)dest) = value->u.cval & 0xff;
}
else if ((value->op == OP_INTCONST) && (value_size == 2)) {
- *(((uint16_t *)buf) + index) = value->u.cval & 0xffff;
+ *((uint16_t *)dest) = value->u.cval & 0xffff;
}
else if ((value->op == OP_INTCONST) && (value_size == 4)) {
- *(((uint32_t *)buf) + index) = value->u.cval & 0xffffffff;
+ *((uint32_t *)dest) = value->u.cval & 0xffffffff;
}
else {
fprintf(stderr, "%d %d\n",
value->op, value_size);
internal_error(state, 0, "unhandled constant initializer");
}
+ free_triple(state, value);
if (peek(state) == TOK_COMMA) {
eat(state, TOK_COMMA);
comma = 1;
}
- index += 1;
+ info.offset += value_size;
+ if ((info.type->type & TYPE_MASK) == TYPE_PRODUCT) {
+ info.type = info.type->right;
+ }
} while(comma && (peek(state) != TOK_RBRACE));
+ if ((type->elements == ELEMENT_COUNT_UNSPECIFIED) &&
+ ((type->type & TYPE_MASK) == TYPE_ARRAY)) {
+ type->elements = max_offset / size_of(state, type->left);
+ }
eat(state, TOK_RBRACE);
result = triple(state, OP_BLOBCONST, type, 0, 0);
result->u.blob = buf;
@@ -9028,7 +9097,8 @@ static struct triple *do_decl(struct compile_state *state,
default:
internal_error(state, 0, "Undefined storage class");
}
- if (((type->type & STOR_MASK) == STOR_STATIC) &&
+ if (ident &&
+ ((type->type & STOR_MASK) == STOR_STATIC) &&
((type->type & QUAL_CONST) == 0)) {
error(state, 0, "non const static variables not supported");
}