commit 6b506fe9fe1333efa974b2206a307d7647c47735
parent f6faaf8fd1cb78e62eae69ae5e618cb4ea4b1654
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 3 Jul 2021 10:57:16 -0400
gen: implement function parameters
We still need to fully validate the direct/indirect distinction.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
3 files changed, 91 insertions(+), 9 deletions(-)
diff --git a/include/gen.h b/include/gen.h
@@ -64,6 +64,7 @@ enum qbe_instr load_for_type(struct gen_context *ctx, const struct type *type);
// qtype.c
const struct qbe_type *qtype_lookup(struct gen_context *ctx,
- const struct type *type, bool xtype);
+ const struct type *type, bool xtype);
+bool type_is_aggregate(const struct type *type);
#endif
diff --git a/src/gen.c b/src/gen.c
@@ -88,16 +88,21 @@ load_temp(struct gen_context *ctx,
out->kind = QV_TEMPORARY;
if (qtype->stype == Q__AGGREGATE) {
+ assert(temp->indirect);
out->name = temp->name;
out->type = ctx->arch.ptr;
} else {
out->name = gen_name(ctx, "load.%d");
out->type = qtype;
- struct qbe_value addr;
- qval_temp(ctx, &addr, temp);
- enum qbe_instr instr = load_for_type(ctx, temp->type);
- pushi(ctx->current, out, instr, &addr, NULL);
+ struct qbe_value src;
+ qval_temp(ctx, &src, temp);
+ if (temp->indirect) {
+ enum qbe_instr instr = load_for_type(ctx, temp->type);
+ pushi(ctx->current, out, instr, &src, NULL);
+ } else {
+ pushi(ctx->current, out, Q_COPY, &src, NULL);
+ }
}
}
@@ -208,8 +213,12 @@ gen_copy(struct gen_context *ctx,
load_temp(ctx, &value, src);
qval_temp(ctx, &dtemp, dest);
- enum qbe_instr instr = store_for_type(ctx, dtype);
- pushi(ctx->current, NULL, instr, &value, &dtemp, NULL);
+ if (dest->indirect) {
+ enum qbe_instr instr = store_for_type(ctx, dtype);
+ pushi(ctx->current, NULL, instr, &value, &dtemp, NULL);
+ } else {
+ pushi(ctx->current, &dtemp, Q_COPY, &value, NULL);
+ }
}
static void gen_expr(struct gen_context *ctx,
@@ -223,6 +232,7 @@ gen_address_object(struct gen_context *ctx, struct gen_temp *temp,
const struct scope_object *obj)
{
const struct gen_binding *binding = binding_lookup(ctx, obj);
+ assert(binding->temp.indirect);
*temp = binding->temp;
}
@@ -624,8 +634,35 @@ gen_function_decl(struct gen_context *ctx, const struct declaration *decl)
qdef->func.returns = &qbe_void;
}
- // TODO: Allocate parameters
- assert(!func->scope->objects);
+ struct qbe_func_param *param, **next = &qdef->func.params;
+ struct scope_object *obj = decl->func.scope->objects;
+ while (obj) {
+ param = *next = xcalloc(1, sizeof(struct qbe_func_param));
+ assert(!obj->ident.ns); // Invariant
+ param->name = strdup(obj->ident.name);
+ param->type = qtype_lookup(ctx, obj->type, false);
+
+ struct gen_binding *gb = xcalloc(1, sizeof(struct gen_binding));
+ if (type_is_aggregate(obj->type)) {
+ gb->temp.name = strdup(param->name);
+ gb->temp.type = obj->type;
+ gb->temp.indirect = true;
+ } else {
+ alloc_temp(ctx, &gb->temp, obj->type, "parameter.%d");
+ struct gen_temp temp = {
+ .name = param->name,
+ .type = obj->type,
+ .indirect = false,
+ };
+ gen_copy(ctx, &gb->temp, &temp);
+ }
+ gb->object = obj;
+ gb->next = ctx->bindings;
+ ctx->bindings = gb;
+
+ obj = obj->lnext;
+ next = ¶m->next;
+ }
pushl(&qdef->func, &ctx->id, "body.%d");
gen_expr(ctx, func->body, ctx->rval);
diff --git a/src/qtype.c b/src/qtype.c
@@ -163,3 +163,47 @@ const struct qbe_type *qtype_lookup(
}
abort(); // Invariant
}
+
+bool
+type_is_aggregate(const struct type *type)
+{
+ switch (type->storage) {
+ case STORAGE_BOOL:
+ case STORAGE_CHAR:
+ case STORAGE_ENUM:
+ case STORAGE_F32:
+ case STORAGE_F64:
+ case STORAGE_I16:
+ case STORAGE_I32:
+ case STORAGE_I64:
+ case STORAGE_I8:
+ case STORAGE_INT:
+ case STORAGE_POINTER:
+ case STORAGE_NULL:
+ case STORAGE_RUNE:
+ case STORAGE_SIZE:
+ case STORAGE_U16:
+ case STORAGE_U32:
+ case STORAGE_U64:
+ case STORAGE_U8:
+ case STORAGE_UINT:
+ case STORAGE_UINTPTR:
+ case STORAGE_VOID:
+ return false;
+ case STORAGE_ALIAS:
+ return type_is_aggregate(type->alias.type);
+ case STORAGE_ARRAY:
+ case STORAGE_SLICE:
+ case STORAGE_STRING:
+ case STORAGE_STRUCT:
+ case STORAGE_TAGGED:
+ case STORAGE_TUPLE:
+ case STORAGE_UNION:
+ case STORAGE_FUNCTION:
+ return true;
+ case STORAGE_FCONST:
+ case STORAGE_ICONST:
+ assert(0); // Lowered in check
+ }
+ assert(0); // Unreachable
+}