harec

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

commit fc135991fcc5ebe9905cbba92a8727c4fb4983fe
parent 742334caf508bb498f86dac5f9d426b78024d4e0
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue, 10 Aug 2021 11:04:55 +0200

gen: implement efficient path for slice alloc

This adds a more efficient path when initializing slices from arrays
which allows them to be generated with _at semantics on the allocated
storage area, rather than with a copy.

This also fixes an issue with freeing slices.

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

Diffstat:
Msrc/gen.c | 48++++++++++++++++++++++++------------------------
Mtests/configure | 2+-
2 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -366,42 +366,31 @@ gen_alloc_slice_at(struct gen_context *ctx, const struct expression *expr, struct gen_value out) { - // TODO: We should avoid an extra allocation for some array cases if we - // wrote a separate code-path which allocates first (using the array - // length, which is known at compile time) and then uses gen_expr_at to - // initialize directly into the new storage area. - // - // This will likely be very important if we start working with - // initializers for arrays of a large size, e.g. - // - // let x: [4096]int = alloc([0...]); - // - // The current approach will cause the [4096]int initializer to be - // stack-allocated and copied into the new allocated space. struct qbe_value qcap; if (expr->alloc.cap) { struct gen_value cap = gen_expr(ctx, expr->alloc.cap); qcap = mkqval(ctx, &cap); } - struct gen_value init = gen_expr(ctx, expr->alloc.expr); - struct qbe_value qinit = mkqval(ctx, &init); - + struct gen_value init; + struct qbe_value qinit; struct qbe_value length, initdata; const struct type *inittype = type_dealias(expr->alloc.expr->result); switch (inittype->storage) { case STORAGE_ARRAY: assert(inittype->array.length != SIZE_UNDEFINED); length = constl(inittype->array.length); - initdata = mkqval(ctx, &init); break; - case STORAGE_SLICE:; + case STORAGE_SLICE: + init = gen_expr(ctx, expr->alloc.expr); + qinit = mkqval(ctx, &init); enum qbe_instr load = load_for_type(ctx, &builtin_type_size); initdata = mkqtmp(ctx, ctx->arch.ptr, ".%d"); pushi(ctx->current, &initdata, load, &qinit, NULL); struct qbe_value offset = constl(builtin_type_size.size); struct qbe_value ptr = mkqtmp(ctx, ctx->arch.ptr, ".%d"); pushi(ctx->current, &ptr, Q_ADD, &qinit, &offset, NULL); + length = mkqtmp(ctx, ctx->arch.sz, ".%d"); pushi(ctx->current, &length, load, &ptr, NULL); break; default: abort(); // Invariant @@ -446,8 +435,18 @@ gen_alloc_slice_at(struct gen_context *ctx, pushi(ctx->current, &ptr, Q_ADD, &base, &offset, NULL); pushi(ctx->current, NULL, store, &qcap, &ptr, NULL); - struct qbe_value rtmemcpy = mkrtfunc(ctx, "rt.memcpy"); - pushi(ctx->current, NULL, Q_CALL, &rtmemcpy, &data, &initdata, &size, NULL); + if (inittype->storage == STORAGE_ARRAY) { + struct gen_value storage = (struct gen_value){ + .kind = GV_TEMP, + .type = inittype, + .name = data.name, + }; + gen_expr_at(ctx, expr->alloc.expr, storage); + } else { + struct qbe_value rtmemcpy = mkrtfunc(ctx, "rt.memcpy"); + pushi(ctx->current, NULL, Q_CALL, &rtmemcpy, + &data, &initdata, &size, NULL); + } } static struct gen_value @@ -1323,13 +1322,14 @@ static struct gen_value gen_expr_free(struct gen_context *ctx, const struct expression *expr) { const struct type *type = type_dealias(expr->alloc.expr->result); - struct gen_value val = gen_expr(ctx, expr->alloc.expr); - if (type->storage == STORAGE_SLICE - || type->storage == STORAGE_STRING) { - val = gen_load(ctx, val); - } struct qbe_value rtfunc = mkrtfunc(ctx, "rt.free"); + struct gen_value val = gen_expr(ctx, expr->alloc.expr); struct qbe_value qval = mkqval(ctx, &val); + if (type->storage == STORAGE_SLICE || type->storage == STORAGE_STRING) { + struct qbe_value lval = mklval(ctx, &val); + qval = mkqtmp(ctx, ctx->arch.ptr, ".%d"); + pushi(ctx->current, &qval, Q_LOADL, &lval, NULL); + } pushi(ctx->current, NULL, Q_CALL, &rtfunc, &qval, NULL); return gv_void; } diff --git a/tests/configure b/tests/configure @@ -77,7 +77,7 @@ tests/$t: libhart.a tests/$t.ha @printf 'HAREC\t%s\t$@\n' "tests/$t" @HARECACHE=\$(HARECACHE) ./harec -o tests/$t.ssa tests/$t.ha @\$(QBE) -o tests/$t.s tests/$t.ssa - @\$(AS) -o tests/$t.o tests/$t.s + @\$(AS) -g -o tests/$t.o tests/$t.s @\$(LD) --gc-sections -T rt/hare.sc -o tests/$t $rtstart tests/$t.o libhart.a @rm tests/$t.s tests/$t.ssa tests/$t.o