commit 96f766c0c35c08428a79b75e5945cbcc92d153da
parent ca87307666e26afeb337c89259f900a34ac09eb3
Author: Eyal Sawady <ecs@d2evs.net>
Date: Sat, 24 Jul 2021 09:37:38 +0200
gen: implement call expressions
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
2 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -436,6 +436,53 @@ gen_expr_binding(struct gen_context *ctx,
}
static void
+gen_expr_call(struct gen_context *ctx,
+ const struct expression *expr,
+ const struct gen_temp *out)
+{
+ struct gen_temp lvalue = {0};
+ gen_direct(ctx, &lvalue, expr->call.lvalue->result, "call.lvalue.%d");
+ gen_expr(ctx, expr->call.lvalue, &lvalue);
+ auto_deref(ctx, &lvalue);
+
+ const struct type *rtype = lvalue.type;
+ assert(rtype->storage == STORAGE_FUNCTION);
+ // TODO: Run deferred expressions if rtype->func.flags & FN_NORETURN
+ struct qbe_statement call = {
+ .type = Q_INSTR,
+ .instr = Q_CALL,
+ };
+ struct gen_temp returns = {0};
+ if (out) {
+ // XXX: This is definitely broken on aggregate returns
+ gen_direct(ctx, &returns, expr->result, "call.returns.%d");
+ call.out = xcalloc(1, sizeof(struct qbe_value));
+ qval_temp(ctx, call.out, &returns);
+ }
+
+ struct qbe_arguments *args, **next = &call.args;
+ struct call_argument *carg = expr->call.args;
+ args = *next = xcalloc(1, sizeof(struct qbe_arguments));
+ qval_temp(ctx, &args->value, &lvalue);
+ next = &args->next;
+ while (carg) {
+ args = *next = xcalloc(1, sizeof(struct qbe_arguments));
+ struct gen_temp arg = {0};
+ alloc_temp(ctx, &arg, carg->value->result, "call.arg.%d");
+ gen_expr(ctx, carg->value, &arg);
+ qval_temp(ctx, &args->value, &arg);
+ carg = carg->next;
+ next = &args->next;
+ }
+
+ push(&ctx->current->body, &call);
+
+ if (out) {
+ gen_copy(ctx, out, &returns);
+ }
+}
+
+static void
gen_expr_const_array(struct gen_context *ctx,
const struct type *atype,
const struct array_constant *expr,
@@ -720,7 +767,10 @@ gen_expr(struct gen_context *ctx,
break;
case EXPR_BREAK:
case EXPR_CONTINUE:
+ assert(0); // TODO
case EXPR_CALL:
+ gen_expr_call(ctx, expr, out);
+ break;
case EXPR_CAST:
assert(0); // TODO
case EXPR_CONSTANT:
diff --git a/src/genutil.c b/src/genutil.c
@@ -45,12 +45,19 @@ void
gen_direct(struct gen_context *ctx, struct gen_temp *temp,
const struct type *type, const char *fmt)
{
- assert(type->size != 0 && type->size != SIZE_UNDEFINED);
+ // Functions are a special case: the Hare type system (correctly) states
+ // that they have an undefined size and storage, but we can assign them
+ // to qbe temporaries as pointers (=l), so they are suitable for use as
+ // direct objects.
+ if (type_dealias(type)->storage != STORAGE_FUNCTION) {
+ assert(type->size != 0 && type->size != SIZE_UNDEFINED);
+ const struct qbe_type *qtype = qtype_lookup(ctx, type, false);
+ assert(qtype->stype != Q__AGGREGATE && qtype->stype != Q__VOID);
+ }
+
temp->type = type;
temp->name = gen_name(ctx, fmt);
temp->indirect = false;
- const struct qbe_type *qtype = qtype_lookup(ctx, type, false);
- assert(qtype->stype != Q__AGGREGATE && qtype->stype != Q__VOID);
}
// Emits a qbe copy instruction which makes a working copy of a gen temporary.