commit e787d8fc64f1d2617263a9fee92b0fc9b000192e
parent b5728c918f1b1d3b74d8f021d012fbd482b5317e
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 9 Aug 2021 13:12:35 +0200
gen: implement array expansion
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
M | src/gen.c | | | 34 | ++++++++++++++++++++++++++++++---- |
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -893,19 +893,45 @@ gen_const_array_at(struct gen_context *ctx,
const struct expression *expr, struct gen_value out)
{
struct array_constant *aexpr = expr->constant.array;
- assert(!aexpr->expand); // TODO
struct qbe_value base = mkqval(ctx, &out);
- size_t index = 0;
+ size_t n = 0;
const struct type *atype = type_dealias(expr->result);
struct gen_value item = mktemp(ctx, atype->array.members, "item.%d");
for (const struct array_constant *ac = aexpr; ac; ac = ac->next) {
- struct qbe_value offs = constl(index * atype->array.members->size);
+ struct qbe_value offs = constl(n * atype->array.members->size);
struct qbe_value ptr = mklval(ctx, &item);
pushi(ctx->current, &ptr, Q_ADD, &base, &offs, NULL);
gen_expr_at(ctx, ac->value, item);
- ++index;
+ ++n;
}
+
+ if (!aexpr->expand) {
+ return;
+ }
+
+ struct gen_value next = mktemp(ctx, atype->array.members, ".%d");
+ struct qbe_value ptr = mklval(ctx, &next);
+
+ size_t remain = atype->array.length - n;
+ if (remain * atype->array.members->size <= 128) {
+ struct gen_value last = gen_load(ctx, item);
+ for (; n < atype->array.length; ++n) {
+ struct qbe_value offs = constl(n * atype->array.members->size);
+ pushi(ctx->current, &ptr, Q_ADD, &base, &offs, NULL);
+ gen_store(ctx, next, last);
+ }
+ return;
+ }
+
+ struct qbe_value offs = constl(n * atype->array.members->size);
+ pushi(ctx->current, &ptr, Q_ADD, &base, &offs, NULL);
+
+ struct qbe_value rtfunc = mkrtfunc(ctx, "rt.memcpy");
+ struct qbe_value dtemp = mklval(ctx, &next);
+ struct qbe_value stemp = mklval(ctx, &item);
+ struct qbe_value sz = constl(remain * atype->array.members->size);
+ pushi(ctx->current, NULL, Q_CALL, &rtfunc, &dtemp, &stemp, &sz, NULL);
}
static void