harec

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

commit 4a488a47776df4a4f811a6869b779ce18f27b0fd
parent 3fa71772e8769a24939a8f7db9379776fece4098
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Wed,  3 Feb 2021 18:40:40 -0500

gen: implement append

Diffstat:
Msrc/gen.c | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 1 deletion(-)

diff --git a/src/gen.c b/src/gen.c @@ -562,7 +562,90 @@ gen_expr_append(struct gen_context *ctx, const struct qbe_value *out) { assert(expr->type == EXPR_APPEND); - assert(0); // TODO + struct qbe_value variadic = {0}, vptr = {0}, vlen = {0}, temp = {0}; + if (expr->append.variadic) { + struct qbe_value vlenptr = {0}; + alloc_temp(ctx, &variadic, expr->append.variadic->result, + "append.variadic.%d"); + gen_expression(ctx, expr->append.variadic, &variadic); + qval_deref(&variadic); + gen_loadtemp(ctx, &vptr, &variadic, &qbe_long, false); + qval_deref(&vptr); + gen_temp(ctx, &vlenptr, &qbe_long, "append.vlenptr.%d"); + constl(&temp, builtin_type_size.size); + pushi(ctx->current, &vlenptr, Q_ADD, &vptr, &temp, NULL); + qval_deref(&vlenptr); + gen_loadtemp(ctx, &vlen, &vlenptr, &qbe_long, false); + } + + struct qbe_value val = {0}; + gen_temp(ctx, &val, &qbe_long, "append.val.%d"); + if (expr->append.expr->type == EXPR_ACCESS) { + struct qbe_value tmp = {0}; + address_object(ctx, expr->append.expr, &tmp); + qval_address(&tmp); + gen_store(ctx, &val, &tmp); + } else { + assert(expr->append.expr->type == EXPR_UNARITHM); + assert(expr->append.expr->unarithm.op == UN_DEREF); + gen_expression(ctx, expr->append.expr->unarithm.operand, &val); + } + + struct qbe_value len = {0}, newlen = {0}, lenptr = {0}; + gen_temp(ctx, &lenptr, &qbe_long, "append.lenptr.%d"); + gen_temp(ctx, &newlen, &qbe_long, "append.newlen.%d"); + gen_loadtemp(ctx, &lenptr, &val, &qbe_long, false); + constl(&temp, builtin_type_size.size); + pushi(ctx->current, &lenptr, Q_ADD, &lenptr, &temp, NULL); + qval_deref(&lenptr); + gen_loadtemp(ctx, &len, &lenptr, &qbe_long, false); + size_t args = 0; + for (struct append_values *value = expr->append.values; value; + value = value->next) { + args++; + } + constl(&temp, args); + pushi(ctx->current, &newlen, Q_ADD, &len, &temp, NULL); + if (expr->append.variadic) { + pushi(ctx->current, &newlen, Q_ADD, &newlen, &vlen, NULL); + } + gen_store(ctx, &lenptr, &newlen); + + struct qbe_value rtfunc = {0}, membsz = {0}; + constl(&membsz, expr->append.expr->result->array.members->size); + rtfunc.kind = QV_GLOBAL; + rtfunc.name = strdup("rt.ensure"); + rtfunc.type = &qbe_long; + pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, &newlen, NULL); + + struct qbe_value ptr = {0}; + const struct qbe_type *type = + qtype_for_type(ctx, expr->append.expr->result->array.members, false); + qval_deref(&val); + gen_loadtemp(ctx, &ptr, &val, &qbe_long, "append.ptr.%d"); + qval_address(&ptr); + pushi(ctx->current, &len, Q_MUL, &len, &membsz, NULL); + pushi(ctx->current, &ptr, Q_ADD, &ptr, &len, NULL); + for (struct append_values *value = expr->append.values; value; + value = value->next) { + struct qbe_value v = {0}; + alloc_temp(ctx, &v, value->expr->result, "append.value.%d"); + gen_expression(ctx, value->expr, &v); + v.indirect = false; + ptr.type = type; + gen_copy(ctx, &ptr, &v); + ptr.type = &qbe_long; + pushi(ctx->current, &ptr, Q_ADD, &ptr, &membsz, NULL); + } + if (expr->append.variadic) { + struct qbe_value rtmemcpy = {0}, v = {0}; + gen_loadtemp(ctx, &v, &vptr, &qbe_long, false); + rtmemcpy.kind = QV_GLOBAL; + rtmemcpy.name = strdup("rt.memcpy"); + rtmemcpy.type = &qbe_long; + pushi(ctx->current, &vlen, Q_MUL, &vlen, &membsz, NULL); + pushi(ctx->current, NULL, Q_CALL, &rtmemcpy, &ptr, &v, &vlen, NULL); + } } static void