harec

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

commit b643af3c085156975b1e21b599d9f0f67485eba2
parent fcad12cb2d08578feab5ef01502c15c612632095
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 30 Jan 2021 14:17:47 -0500

gen: implement basic slice allocation & free

Still pending is support for inferring the capacity from the initializer
and allocating slices initialized from other slices.

Diffstat:
Msrc/gen.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mtests/17-alloc.ha | 10++++++++++
2 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -475,13 +475,78 @@ gen_expr_access(struct gen_context *ctx, } } -static void gen_alloc(struct gen_context *ctx, +static void +gen_slice_alloc(struct gen_context *ctx, + const struct expression *expr, + const struct qbe_value *out) +{ + struct qbe_value len = {0}, cap = {0}, size = {0}, temp = {0}; + gen_temp(ctx, &len, + qtype_for_type(ctx, &builtin_type_size, true), + "slice.len.%d"); + gen_temp(ctx, &cap, + qtype_for_type(ctx, &builtin_type_size, true), + "slice.cap.%d"); + gen_temp(ctx, &size, + qtype_for_type(ctx, &builtin_type_size, true), + "slice.size.%d"); + + const struct expression *initializer = expr->alloc.expr; + if (initializer->result->storage == TYPE_STORAGE_ARRAY) { + assert(initializer->result->array.length != SIZE_UNDEFINED); + constl(&len, initializer->result->array.length); + } else { + assert(0); // TODO: Initialize one slice from another + } + + if (expr->alloc.cap != NULL) { + gen_expression(ctx, expr->alloc.cap, &cap); + constl(&temp, expr->result->array.members->size); + pushi(ctx->current, &size, Q_MUL, &cap, &temp, NULL); + } else { + assert(0); // TODO: Alloc without explicit capacity + } + + struct qbe_value ret = {0}; + 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); + + // TODO: Generate abort if it failed + + assert(!out->indirect); // TODO? + struct qbe_value ptr = {0}; + gen_temp(ctx, &ptr, &qbe_long, "alloc.ptr.%d"); + constl(&temp, 8); // XXX: ARCH + pushi(ctx->current, &ptr, Q_COPY, out, NULL); + pushi(ctx->current, NULL, Q_STOREL, &ret, &ptr, NULL); + pushi(ctx->current, &ptr, Q_ADD, &ptr, &temp, NULL); + pushi(ctx->current, NULL, Q_STOREL, &len, &ptr, NULL); + pushi(ctx->current, &ptr, Q_ADD, &ptr, &temp, NULL); + pushi(ctx->current, NULL, Q_STOREL, &cap, &ptr, NULL); + + if (initializer->result->storage == TYPE_STORAGE_ARRAY) { + gen_expression(ctx, initializer, &ret); + } else { + // TODO: I think this will have to be a separate branch once + // we've implemented it + } +} + +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); + if (type_dealias(expr->result)->storage == TYPE_STORAGE_SLICE) { + gen_slice_alloc(ctx, expr, out); + return; + } + // TODO: Explicit capacity assert(expr->alloc.cap == NULL); struct qbe_value ret = {0}, size = {0}; @@ -550,7 +615,14 @@ gen_expr_alloc(struct gen_context *ctx, gen_temp(ctx, &val, qtype_for_type(ctx, expr->alloc.expr->result, true), "free.%d"); - gen_expression(ctx, expr->alloc.expr, &val); + if (type_dealias(expr->alloc.expr->result)->storage == TYPE_STORAGE_SLICE) { + qval_address(&val); + gen_expression(ctx, expr->alloc.expr, &val); + val.type = &qbe_long; + pushi(ctx->current, &val, Q_LOADL, &val, NULL); + } else { + gen_expression(ctx, expr->alloc.expr, &val); + } rtfunc.kind = QV_GLOBAL; rtfunc.name = strdup("rt.free"); rtfunc.type = &qbe_long; diff --git a/tests/17-alloc.ha b/tests/17-alloc.ha @@ -51,9 +51,19 @@ fn double_alloc() void = { free(y); }; +fn slice() void = { + let x = alloc([]int, [1, 2, 3], 10z); + assert(len(x) == 3z); + for (let i = 0z; i < len(x); i += 1z) { + assert(x[i] == (i + 1z): int); + }; + free(x); +}; + export fn main() void = { assignment(); allocation(); double_pointer(); double_alloc(); + slice(); };