harec

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

commit adc5dcec8156fcb56786032855f00e0a176b9085
parent 28fe97aa3582f0ed46efb519c971ba597d779a58
Author: Drew DeVault <sir@cmpwn.com>
Date:   Thu, 12 Aug 2021 08:01:11 +0200

gen: fix slicing expressions on [*]type arrays

Diffstat:
Msrc/gen.c | 53++++++++++++++++++++++++++++++++---------------------
1 file changed, 32 insertions(+), 21 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -2079,6 +2079,7 @@ gen_expr_slice_at(struct gen_context *ctx, object = gen_autoderef(ctx, object); const struct type *srctype = type_dealias(object.type); + bool check_bounds = true; struct gen_value length; struct qbe_value qlength; struct qbe_value qbase; @@ -2087,13 +2088,17 @@ gen_expr_slice_at(struct gen_context *ctx, struct qbe_value qptr = mkqtmp(ctx, ctx->arch.ptr, ".%d"); switch (srctype->storage) { case STORAGE_ARRAY: - assert(srctype->array.length != SIZE_UNDEFINED); - length = (struct gen_value){ - .kind = GV_CONST, - .type = &builtin_type_size, - .lval = srctype->array.length, - }; - qlength = mkqval(ctx, &length); + if (srctype->array.length != SIZE_UNDEFINED) { + length = (struct gen_value){ + .kind = GV_CONST, + .type = &builtin_type_size, + .lval = srctype->array.length, + }; + qlength = mkqval(ctx, &length); + } else { + assert(expr->slice.end); + check_bounds = false; + } qbase = mkqval(ctx, &object); break; case STORAGE_SLICE: @@ -2129,21 +2134,23 @@ gen_expr_slice_at(struct gen_context *ctx, struct qbe_value qstart = mkqval(ctx, &start); struct qbe_value qend = mkqval(ctx, &end); - struct qbe_value start_oob = mkqtmp(ctx, &qbe_word, ".%d"); - struct qbe_value end_oob = mkqtmp(ctx, &qbe_word, ".%d"); - struct qbe_value valid = mkqtmp(ctx, &qbe_word, ".%d"); - pushi(ctx->current, &start_oob, Q_CULTL, &qstart, &qlength, NULL); - pushi(ctx->current, &end_oob, Q_CULEL, &qend, &qlength, NULL); - pushi(ctx->current, &valid, Q_AND, &start_oob, &end_oob, NULL); + if (check_bounds) { + struct qbe_value start_oob = mkqtmp(ctx, &qbe_word, ".%d"); + struct qbe_value end_oob = mkqtmp(ctx, &qbe_word, ".%d"); + struct qbe_value valid = mkqtmp(ctx, &qbe_word, ".%d"); + pushi(ctx->current, &start_oob, Q_CULTL, &qstart, &qlength, NULL); + pushi(ctx->current, &end_oob, Q_CULEL, &qend, &qlength, NULL); + pushi(ctx->current, &valid, Q_AND, &start_oob, &end_oob, NULL); - struct qbe_statement linvalid, lvalid; - struct qbe_value binvalid = mklabel(ctx, &linvalid, ".%d"); - struct qbe_value bvalid = mklabel(ctx, &lvalid, ".%d"); + struct qbe_statement linvalid, lvalid; + struct qbe_value binvalid = mklabel(ctx, &linvalid, ".%d"); + struct qbe_value bvalid = mklabel(ctx, &lvalid, ".%d"); - pushi(ctx->current, NULL, Q_JNZ, &valid, &bvalid, &binvalid, NULL); - push(&ctx->current->body, &linvalid); - gen_fixed_abort(ctx, expr->loc, ABORT_OOB); - push(&ctx->current->body, &lvalid); + pushi(ctx->current, NULL, Q_JNZ, &valid, &bvalid, &binvalid, NULL); + push(&ctx->current->body, &linvalid); + gen_fixed_abort(ctx, expr->loc, ABORT_OOB); + push(&ctx->current->body, &lvalid); + } struct qbe_value isz = constl(srctype->array.members->size); @@ -2155,7 +2162,11 @@ gen_expr_slice_at(struct gen_context *ctx, struct qbe_value newlen = mkqtmp(ctx, ctx->arch.sz, "newlen.%d"); pushi(ctx->current, &newlen, Q_SUB, &qend, &qstart, NULL); struct qbe_value newcap = mkqtmp(ctx, ctx->arch.sz, "newcap.%d"); - pushi(ctx->current, &newcap, Q_SUB, &qlength, &qstart, NULL); + if (check_bounds) { + pushi(ctx->current, &newcap, Q_SUB, &qlength, &qstart, NULL); + } else { + pushi(ctx->current, &newcap, Q_COPY, &newlen, NULL); + } enum qbe_instr store = store_for_type(ctx, &builtin_type_size); pushi(ctx->current, NULL, store, &data, &qout, NULL);