harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit 1a0c7945dee0e9ee9e99a7b273268c64a7861a92
parent 8531f739e8471beb24c532292a67de518c030524
Author: Pierre Curto <pierre.curto@gmail.com>
Date:   Thu, 17 Nov 2022 15:15:46 +0100

Assign slice from expandable array

Fixes: https://todo.sr.ht/~sircmpwn/hare/536

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

Diffstat:
Msrc/check.c | 6++++++
Msrc/gen.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/08-slices.ha | 19+++++++++++++++++++
3 files changed, 83 insertions(+), 0 deletions(-)

diff --git a/src/check.c b/src/check.c @@ -115,6 +115,12 @@ lower_implicit_cast(const struct type *to, struct expression *expr) if (to == expr->result || expr->terminates) { return expr; } + + if (type_dealias(to)->storage == STORAGE_SLICE && + expr->result->storage == STORAGE_ARRAY && + expr->result->array.expandable) { + return expr; + } if (type_dealias(to)->storage == STORAGE_TAGGED) { const struct type *interim = diff --git a/src/gen.c b/src/gen.c @@ -818,8 +818,66 @@ gen_expr_assert(struct gen_context *ctx, const struct expression *expr) } static struct gen_value +gen_expr_assign_slice_expandable(struct gen_context *ctx, const struct expression *expr) +{ + struct gen_value obj = gen_expr(ctx, expr->assign.object); + struct qbe_value qobj = mkqval(ctx, &obj); + + // get the length of the copy + struct qbe_value step = constl(ctx->arch.ptr->size); + struct qbe_value ptr = mkqtmp(ctx, ctx->arch.ptr, ".%d"); + struct qbe_value olen = mkqtmp(ctx, ctx->arch.sz, ".%d"); + pushi(ctx->current, &ptr, Q_ADD, &qobj, &step, NULL); + pushi(ctx->current, &olen, Q_LOADL, &ptr, NULL); + + // check if there is anything to do + struct qbe_statement lzero, lnonzero; + struct qbe_value bzero = mklabel(ctx, &lzero, ".%d"); + struct qbe_value bnonzero = mklabel(ctx, &lnonzero, ".%d"); + + struct qbe_value cmpres = mkqtmp(ctx, &qbe_word, ".%d"); + struct qbe_value zero = constl(0); + pushi(ctx->current, &cmpres, Q_CNEL, &olen, &zero, NULL); + pushi(ctx->current, NULL, Q_JNZ, &cmpres, &bnonzero, &bzero, NULL); + push(&ctx->current->body, &lnonzero); + + // get the destination + struct qbe_value odata = mkqtmp(ctx, ctx->arch.ptr, ".%d"); + pushi(ctx->current, &odata, Q_LOADL, &qobj, NULL); + + // get the source + struct gen_value val = gen_expr(ctx, expr->assign.value); + struct qbe_value qval = mkqval(ctx, &val); + struct qbe_value vdata = mkqtmp(ctx, ctx->arch.ptr, ".%d"); + pushi(ctx->current, &vdata, Q_LOADL, &qval, NULL); + + // copy the first item + const struct type *sltype = expr->assign.object->result->array.members; + enum qbe_instr store = store_for_type(ctx, sltype); + pushi(ctx->current, NULL, store, &vdata, &odata, NULL); + + // perform the copy minus the first element + struct qbe_value isize = constl(sltype->size); + struct qbe_value next = mkqtmp(ctx, ctx->arch.ptr, ".%d"); + pushi(ctx->current, &next, Q_ADD, &odata, &isize, NULL); + struct qbe_value rtmemcpy = mkrtfunc(ctx, "rt.memcpy"); + struct qbe_value one = constl(1); + pushi(ctx->current, &olen, Q_SUB, &olen, &one, NULL); + pushi(ctx->current, NULL, Q_CALL, &rtmemcpy, &next, &odata, &olen, NULL); + + push(&ctx->current->body, &lzero); + + return gv_void; +} + +static struct gen_value gen_expr_assign_slice(struct gen_context *ctx, const struct expression *expr) { + const struct type *vtype = type_dealias(expr->assign.value->result); + if (vtype->storage == STORAGE_ARRAY && vtype->array.expandable) { + return gen_expr_assign_slice_expandable(ctx, expr); + } + struct gen_value obj = gen_expr(ctx, expr->assign.object); struct gen_value val = gen_expr(ctx, expr->assign.value); struct qbe_value qobj = mkqval(ctx, &obj); diff --git a/tests/08-slices.ha b/tests/08-slices.ha @@ -168,6 +168,24 @@ fn recursive_structure() void = { assert(sum_tree(t) == 134, "recursive structure using slices"); }; +fn expandable() void = { + let s: [6]u16 = [0...]; + + s[2..2] = [1...]; + assert(s[2] == 0); + + s[1..3] = [1...]; + assert(s[0] == 0); + assert(s[1] == 1); + assert(s[2] == 1); + assert(s[3] == 0); + + s[4..] = [123...]; + assert(s[3] == 0); + assert(s[4] == 123); + assert(s[5] == 123); +}; + export fn main() void = { from_array(); storage(); @@ -176,4 +194,5 @@ export fn main() void = { assignment(); slicing(); recursive_structure(); + expandable(); };