harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit ebe5d7e418e12e025a2c062141949634e2778d1e
parent bfe91ff955dd20cb803bf5a5ff54de2470ea8b90
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu,  5 Aug 2021 10:34:16 +0200

gen: implement globals

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Minclude/qbe.h | 3+++
Msrc/gen.c | 256++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/qbe.c | 30++++++++++++++++++++++++++++++
3 files changed, 288 insertions(+), 1 deletion(-)

diff --git a/include/qbe.h b/include/qbe.h @@ -263,5 +263,8 @@ void push(struct qbe_statements *stmts, struct qbe_statement *stmt); struct qbe_value *qval_dup(const struct qbe_value *val); struct qbe_value constl(uint64_t l); +struct qbe_value constw(uint32_t w); +struct qbe_value consts(float s); +struct qbe_value constd(double d); #endif diff --git a/src/gen.c b/src/gen.c @@ -995,6 +995,259 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl) ctx->current = NULL; } +static struct qbe_data_item * +gen_data_item(struct gen_context *ctx, struct expression *expr, + struct qbe_data_item *item) +{ + assert(expr->type == EXPR_CONSTANT); + + struct qbe_def *def; + const struct expression_constant *constant = &expr->constant; + const struct type *type = type_dealias(expr->result); + if (constant->object) { + item->type = QD_SYMOFFS; + item->sym = ident_to_sym(&constant->object->ident); + item->offset = constant->ival; + return item; + } + + switch (type->storage) { + case STORAGE_I8: + case STORAGE_U8: + case STORAGE_CHAR: + item->type = QD_VALUE; + item->value = constw((uint8_t)constant->uval); + item->value.type = &qbe_byte; + break; + case STORAGE_I16: + case STORAGE_U16: + item->type = QD_VALUE; + item->value = constw((uint16_t)constant->uval); + item->value.type = &qbe_half; + break; + case STORAGE_BOOL: + item->type = QD_VALUE; + item->value = constw(constant->bval ? 1 : 0); + break; + case STORAGE_I32: + case STORAGE_U32: + case STORAGE_INT: + case STORAGE_UINT: + case STORAGE_RUNE: + item->type = QD_VALUE; + item->value = constw((uint32_t)constant->uval); + break; + case STORAGE_U64: + case STORAGE_I64: + case STORAGE_SIZE: + item->type = QD_VALUE; + item->value = constl((uint64_t)constant->uval); + break; + case STORAGE_F32: + item->type = QD_VALUE; + item->value = consts((float)constant->fval); + break; + case STORAGE_F64: + item->type = QD_VALUE; + item->value = constd((double)constant->fval); + break; + case STORAGE_UINTPTR: + case STORAGE_POINTER: + assert(expr->type == EXPR_CONSTANT); // TODO? + item->type = QD_VALUE; + switch (ctx->arch.ptr->stype) { + case Q_LONG: + item->value = constl((uint64_t)constant->uval); + break; + default: assert(0); + } + break; + case STORAGE_ARRAY: + assert(type->array.length != SIZE_UNDEFINED); + size_t n = type->array.length; + for (struct array_constant *c = constant->array; + c && n; c = c->next ? c->next : c, --n) { + item = gen_data_item(ctx, c->value, item); + if (n > 1 || c->next) { + item->next = xcalloc(1, + sizeof(struct qbe_data_item)); + item = item->next; + } + } + break; + case STORAGE_STRING: + def = xcalloc(1, sizeof(struct qbe_def)); + def->name = gen_name(ctx, "strdata.%d"); + def->kind = Q_DATA; + def->data.items.type = QD_STRING; + def->data.items.str = xcalloc(1, expr->constant.string.len); + def->data.items.sz = expr->constant.string.len; + memcpy(def->data.items.str, expr->constant.string.value, + expr->constant.string.len); + + item->type = QD_VALUE; + if (expr->constant.string.len != 0) { + qbe_append_def(ctx->out, def); + item->value.kind = QV_GLOBAL; + item->value.type = &qbe_long; + item->value.name = strdup(def->name); + } else { + free(def); + item->value = constl(0); + } + + item->next = xcalloc(1, sizeof(struct qbe_data_item)); + item = item->next; + item->type = QD_VALUE; + item->value = constl(expr->constant.string.len); + item->next = xcalloc(1, sizeof(struct qbe_data_item)); + item = item->next; + item->type = QD_VALUE; + item->value = constl(expr->constant.string.len); + break; + case STORAGE_SLICE: + def = xcalloc(1, sizeof(struct qbe_def)); + def->name = gen_name(ctx, "sldata.%d"); + def->kind = Q_DATA; + + size_t len = 0; + struct qbe_data_item *subitem = &def->data.items; + for (struct array_constant *c = constant->array; + c; c = c->next) { + gen_data_item(ctx, c->value, subitem); + if (c->next) { + subitem->next = xcalloc(1, + sizeof(struct qbe_data_item)); + subitem = subitem->next; + } + ++len; + } + + item->type = QD_VALUE; + if (len != 0) { + qbe_append_def(ctx->out, def); + item->value.kind = QV_GLOBAL; + item->value.type = &qbe_long; + item->value.name = strdup(def->name); + } else { + free(def); + item->value = constl(0); + } + + item->next = xcalloc(1, sizeof(struct qbe_data_item)); + item = item->next; + item->type = QD_VALUE; + item->value = constl(len); + item->next = xcalloc(1, sizeof(struct qbe_data_item)); + item = item->next; + item->type = QD_VALUE; + item->value = constl(len); + break; + case STORAGE_STRUCT: + for (struct struct_constant *f = constant->_struct; + f; f = f->next) { + item = gen_data_item(ctx, f->value, item); + if (f->next) { + const struct struct_field *f1 = f->field; + const struct struct_field *f2 = f->next->field; + if (f2->offset != f1->offset + f1->type->size) { + item->next = xcalloc(1, + sizeof(struct qbe_data_item)); + item = item->next; + item->type = QD_ZEROED; + item->zeroed = f2->offset - + (f1->offset + f1->type->size); + } + + item->next = xcalloc(1, + sizeof(struct qbe_data_item)); + item = item->next; + } + } + break; + case STORAGE_ENUM: + switch (type->_enum.storage) { + case STORAGE_I8: + case STORAGE_U8: + item->type = QD_VALUE; + item->value = constw((uint8_t)constant->uval); + item->value.type = &qbe_byte; + break; + case STORAGE_I16: + case STORAGE_U16: + item->type = QD_VALUE; + item->value = constw((uint16_t)constant->uval); + item->value.type = &qbe_half; + break; + case STORAGE_I32: + case STORAGE_U32: + case STORAGE_INT: + case STORAGE_UINT: + item->type = QD_VALUE; + item->value = constw((uint32_t)constant->uval); + break; + case STORAGE_U64: + case STORAGE_I64: + case STORAGE_SIZE: + item->type = QD_VALUE; + item->value = constl((uint64_t)constant->uval); + break; + default: + assert(0); + } + break; + case STORAGE_TUPLE: + for (const struct tuple_constant *tuple = constant->tuple; + tuple; tuple = tuple->next) { + item = gen_data_item(ctx, tuple->value, item); + if (tuple->next) { + const struct type_tuple *f1 = tuple->field; + const struct type_tuple *f2 = tuple->next->field; + if (f2->offset != f1->offset + f1->type->size) { + item->next = xcalloc(1, + sizeof(struct qbe_data_item)); + item = item->next; + item->type = QD_ZEROED; + item->zeroed = f2->offset - + (f1->offset + f1->type->size); + } + + + item->next = xcalloc(1, + sizeof(struct qbe_data_item)); + item = item->next; + } + } + break; + case STORAGE_TAGGED: + case STORAGE_UNION: + assert(0); // TODO + case STORAGE_ALIAS: + case STORAGE_FCONST: + case STORAGE_FUNCTION: + case STORAGE_ICONST: + case STORAGE_NULL: + case STORAGE_VOID: + assert(0); // Invariant + } + + assert(item->type != QD_VALUE || item->value.type); + return item; +} + +static void +gen_global_decl(struct gen_context *ctx, const struct declaration *decl) +{ + assert(decl->type == DECL_GLOBAL); + const struct global_decl *global = &decl->global; + struct qbe_def *qdef = xcalloc(1, sizeof(struct qbe_def)); + qdef->kind = Q_DATA; + qdef->exported = decl->exported; + qdef->name = ident_to_sym(&decl->ident); + gen_data_item(ctx, global->value, &qdef->data.items); + qbe_append_def(ctx->out, qdef); +} + static void gen_decl(struct gen_context *ctx, const struct declaration *decl) { @@ -1003,7 +1256,8 @@ gen_decl(struct gen_context *ctx, const struct declaration *decl) gen_function_decl(ctx, decl); break; case DECL_GLOBAL: - assert(0); // TODO + gen_global_decl(ctx, decl); + break; case DECL_CONST: case DECL_TYPE: break; // Nothing to do diff --git a/src/qbe.c b/src/qbe.c @@ -274,3 +274,33 @@ constl(uint64_t l) .lval = l, }; } + +struct qbe_value +constw(uint32_t w) +{ + return (struct qbe_value){ + .kind = QV_CONST, + .type = &qbe_word, + .wval = w, + }; +} + +struct qbe_value +consts(float s) +{ + return (struct qbe_value){ + .kind = QV_CONST, + .type = &qbe_single, + .sval = s, + }; +} + +struct qbe_value +constd(double d) +{ + return (struct qbe_value){ + .kind = QV_CONST, + .type = &qbe_double, + .dval = d, + }; +}