harec

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

commit c2ce6392f471292486baa50e0e632226f716f990
parent 210acb6ab94480735b7ec54c1abbbf4789e5aa45
Author: Drew DeVault <sir@cmpwn.com>
Date:   Wed, 28 Apr 2021 13:04:28 -0400

all: implement static append/insert

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

Diffstat:
Minclude/expr.h | 4++++
Msrc/check.c | 6++++--
Msrc/gen.c | 68+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mtests/19-append.ha | 10++++++++++
Mtests/28-insert.ha | 10++++++++++
5 files changed, 89 insertions(+), 9 deletions(-)

diff --git a/include/expr.h b/include/expr.h @@ -80,6 +80,8 @@ struct expression_append { struct expression *expr; struct expression *variadic; struct append_values *values; + struct location loc; + bool is_static; }; struct expression_assert { @@ -222,6 +224,8 @@ struct expression_insert { struct expression *expr; struct expression *variadic; struct append_values *values; + struct location loc; + bool is_static; }; struct expressions { diff --git a/src/check.c b/src/check.c @@ -331,9 +331,10 @@ check_expr_append(struct context *ctx, struct errors *errors) { assert(aexpr->type == EXPR_APPEND); - assert(!aexpr->append.is_static); // TODO expr->type = EXPR_APPEND; expr->result = &builtin_type_void; + expr->append.is_static = aexpr->append.is_static; + expr->insert.loc = aexpr->loc; expr->append.expr = xcalloc(sizeof(struct expression), 1); errors = check_expression(ctx, aexpr->append.expr, expr->append.expr, NULL, errors); @@ -1596,9 +1597,10 @@ check_expr_insert(struct context *ctx, struct errors *errors) { assert(aexpr->type == EXPR_INSERT); - assert(!aexpr->insert.is_static); // TODO expr->type = EXPR_INSERT; expr->result = &builtin_type_void; + expr->insert.is_static = aexpr->insert.is_static; + expr->insert.loc = aexpr->loc; expr->insert.expr = xcalloc(sizeof(struct expression), 1); errors = check_expression(ctx, aexpr->insert.expr, expr->insert.expr, NULL, errors); diff --git a/src/gen.c b/src/gen.c @@ -702,12 +702,39 @@ gen_expr_append(struct gen_context *ctx, const struct type *mtype = type_dealias(expr->append.expr->result)->array.members; - struct qbe_value rtfunc = {0}, membsz = {0}; + struct qbe_value membsz = {0}; constl(&membsz, mtype->size); - rtfunc.kind = QV_GLOBAL; - rtfunc.name = strdup("rt.ensure"); - rtfunc.type = &qbe_long; - pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL); + if (!expr->append.is_static) { + struct qbe_value rtfunc = {0}; + rtfunc.kind = QV_GLOBAL; + rtfunc.name = strdup("rt.ensure"); + rtfunc.type = &qbe_long; + pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL); + } else { + struct qbe_value capptr = {0}, cap = {0}; + gen_temp(ctx, &capptr, &qbe_long, "append.capptr.%d"); + constl(&temp, builtin_type_size.size); + pushi(ctx->current, &capptr, Q_ADD, &lenptr, &temp, NULL); + qval_deref(&capptr); + gen_loadtemp(ctx, &cap, &capptr, &qbe_long, false); + + struct qbe_statement validl = {0}, invalidl = {0}; + struct qbe_value bvalid = {0}, binvalid = {0}; + bvalid.kind = QV_LABEL; + bvalid.name = strdup(genl(&validl, &ctx->id, "bounds.valid.%d")); + binvalid.kind = QV_LABEL; + binvalid.name = strdup(genl(&invalidl, &ctx->id, "bounds.invalid.%d")); + + struct qbe_value valid = {0}; + gen_temp(ctx, &valid, &qbe_word, "valid.%d"); + pushi(ctx->current, &valid, Q_CULEL, &newlen, &cap, NULL); + pushi(ctx->current, NULL, Q_JNZ, &valid, &bvalid, &binvalid, NULL); + push(&ctx->current->body, &invalidl); + + gen_fixed_abort(ctx, expr->loc, ABORT_OOB); + + push(&ctx->current->body, &validl); + } struct qbe_value ptr = {0}; const struct qbe_type *type = qtype_for_type(ctx, mtype, true); @@ -1983,9 +2010,36 @@ gen_expr_insert(struct gen_context *ctx, struct qbe_value rtfunc = {0}, membsz = {0}; constl(&membsz, mtype->size); rtfunc.kind = QV_GLOBAL; - rtfunc.name = strdup("rt.ensure"); rtfunc.type = &qbe_long; - pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL); + + if (!expr->insert.is_static) { + rtfunc.name = strdup("rt.ensure"); + pushi(ctx->current, NULL, Q_CALL, &rtfunc, &val, &membsz, NULL); + } else { + struct qbe_value capptr = {0}, cap = {0}; + gen_temp(ctx, &capptr, &qbe_long, "append.capptr.%d"); + constl(&temp, builtin_type_size.size); + pushi(ctx->current, &capptr, Q_ADD, &lenptr, &temp, NULL); + qval_deref(&capptr); + gen_loadtemp(ctx, &cap, &capptr, &qbe_long, false); + + struct qbe_statement validl = {0}, invalidl = {0}; + struct qbe_value bvalid = {0}, binvalid = {0}; + bvalid.kind = QV_LABEL; + bvalid.name = strdup(genl(&validl, &ctx->id, "bounds.valid.%d")); + binvalid.kind = QV_LABEL; + binvalid.name = strdup(genl(&invalidl, &ctx->id, "bounds.invalid.%d")); + + struct qbe_value valid = {0}; + gen_temp(ctx, &valid, &qbe_word, "valid.%d"); + pushi(ctx->current, &valid, Q_CULEL, &newlen, &cap, NULL); + pushi(ctx->current, NULL, Q_JNZ, &valid, &bvalid, &binvalid, NULL); + push(&ctx->current->body, &invalidl); + + gen_fixed_abort(ctx, expr->loc, ABORT_OOB); + + push(&ctx->current->body, &validl); + } struct qbe_value ptr = {0}; const struct qbe_type *type = qtype_for_type(ctx, mtype, true); diff --git a/tests/19-append.ha b/tests/19-append.ha @@ -42,9 +42,19 @@ fn variadic() void = { free(y); }; +fn static_append() void = { + let buf: [4]int = [0...]; + let x = buf[..0]; + static append(x, 1, 2); + static append(x, [3, 4]...); + assert(x[0] == 1 && x[1] == 2 && x[2] == 3 && x[3] == 4); + assert(buf[0] == 1 && buf[1] == 2 && buf[2] == 3 && buf[3] == 4); +}; + export fn main() void = { simple(); variadic(); + static_append(); assert(rt::compile("fn test() void = append([1], 2);") != 0); assert(rt::compile("fn test() void = { let x: []int = alloc([1], 1z); append(x[..], 2); };") != 0); diff --git a/tests/28-insert.ha b/tests/28-insert.ha @@ -38,7 +38,17 @@ fn variadic() void = { assert(sleq(x, [1, 2, 7, 8, 9, 10, 11, 12, 3, 4, 5, 6])); }; +fn static_insert() void = { + let buf: [4]int = [0...]; + let x = buf[..0]; + static insert(x[0], 1, 2); + static insert(x[1], [3, 4]...); + assert(x[0] == 1 && x[1] == 3 && x[2] == 4 && x[3] == 2); + assert(buf[0] == 1 && buf[1] == 3 && buf[2] == 4 && buf[3] == 2); +}; + export fn main() void = { basics(); variadic(); + static_insert(); };