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:
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();
};