harec

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

commit 604219dd6e033416f52bb9c9361e5158e60d5e42
parent 440f489eb0b70733552aad5d2c3a4dc0421cdffc
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Fri, 22 Jan 2021 12:34:23 -0500

gen: implement allocations

Diffstat:
Msrc/gen.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 87 insertions(+), 2 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -475,6 +475,90 @@ gen_expr_access(struct gen_context *ctx, } } +static void gen_alloc(struct gen_context *ctx, + const struct expression *expr, + const struct qbe_value *out) +{ + assert(expr->type == EXPR_ALLOC && expr->alloc.kind == AKIND_ALLOC); + // TODO: Slices + assert(type_dealias(expr->result)->storage == TYPE_STORAGE_POINTER); + // TODO: Explicit capacity + assert(expr->alloc.cap == NULL); + struct qbe_value ret = {0}, size = {0}; + gen_temp(ctx, &size, + qtype_for_type(ctx, &builtin_type_size, true), + "alloc.size.%d"); + constl(&size, type_dealias(expr->result)->pointer.referent->size); + // XXX: ARCH + gen_temp(ctx, &ret, &qbe_long, "alloc.ret.%d"); + struct qbe_value rtalloc = {0}; + rtalloc.kind = QV_GLOBAL; + rtalloc.name = strdup("rt.malloc"); + rtalloc.type = &qbe_long; + pushi(ctx->current, &ret, Q_CALL, &rtalloc, &size, NULL); + gen_store(ctx, out, &ret); + qval_deref(&ret); + struct qbe_value load = {0}; + gen_loadtemp(ctx, &load, out, + qtype_for_type(ctx, expr->result, false), + type_is_signed(expr->result)); + + struct qbe_statement nulll = {0}, validl = {0}, endl = {0}; + struct qbe_value bnull = {0}, bvalid = {0}, bend = {0}; + bvalid.kind = QV_LABEL; + bvalid.name = strdup(genl(&validl, &ctx->id, "alloc.valid.%d")); + bnull.kind = QV_LABEL; + bnull.name = strdup(genl(&nulll, &ctx->id, "alloc.null.%d")); + bend.kind = QV_LABEL; + bend.name = strdup(genl(&endl, &ctx->id, "alloc.end.%d")); + // XXX: null might not be 0 + pushi(ctx->current, NULL, Q_JNZ, &load, &bvalid, &bnull, NULL); + push(&ctx->current->body, &nulll); + + if (type_dealias(expr->result)->pointer.flags & PTR_NULLABLE) { + pushi(ctx->current, NULL, Q_JMP, &bend, NULL); + } else { + struct qbe_value reason = {0}, rtabort = {0}; + constl(&reason, 2); + rtabort.kind = QV_GLOBAL; + rtabort.name = strdup("rt.abort_fixed"); + rtabort.type = &qbe_long; + pushi(ctx->current, NULL, Q_CALL, &rtabort, &reason, NULL); + } + push(&ctx->current->body, &validl); + if (!type_is_aggregate(type_dealias(expr->result)->pointer.referent)) { + qval_deref(&load); + } + gen_expression(ctx, expr->alloc.expr, &load); + push(&ctx->current->body, &endl); +} + +static void +gen_expr_alloc(struct gen_context *ctx, + const struct expression *expr, + const struct qbe_value *out) +{ + assert(expr->type == EXPR_ALLOC); + struct qbe_value val = {0}, rtfunc = {0}; + switch (expr->alloc.kind) { + case AKIND_ALLOC: + gen_alloc(ctx, expr, out); + break; + case AKIND_APPEND: + assert(0); // TODO + case AKIND_FREE: + gen_temp(ctx, &val, + qtype_for_type(ctx, expr->alloc.expr->result, true), + "free.%d"); + gen_expression(ctx, expr->alloc.expr, &val); + rtfunc.kind = QV_GLOBAL; + rtfunc.name = strdup("rt.free"); + rtfunc.type = &qbe_long; + pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, NULL); + break; + } +} + static void gen_expr_assert(struct gen_context *ctx, const struct expression *expr, @@ -952,7 +1036,8 @@ gen_expr_cast(struct gen_context *ctx, default: assert(0); // Invariant } - } else if (from->storage == TYPE_STORAGE_POINTER) { + } else if (from->storage == TYPE_STORAGE_POINTER + || from->storage == TYPE_STORAGE_NULL) { assert(to->storage == TYPE_STORAGE_UINTPTR); op = Q_COPY; } else if (from->storage == TYPE_STORAGE_RUNE) { @@ -1597,7 +1682,7 @@ gen_expression(struct gen_context *ctx, gen_expr_access(ctx, expr, out); break; case EXPR_ALLOC: - assert(0); // TODO + gen_expr_alloc(ctx, expr, out); break; case EXPR_ASSERT: gen_expr_assert(ctx, expr, out);