harec

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

commit 727c5de862700a15dabb3863167bbbf6ddecadd7
parent 596f28ad26b2d6e1a9da2a57ad9bf027fb883585
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 13 Feb 2021 11:04:56 -0500

gen: fix double side effects of `as`

Diffstat:
Msrc/gen.c | 125++++++++++++++++++++++++++++++++++++++++---------------------------------------
1 file changed, 64 insertions(+), 61 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -1015,6 +1015,65 @@ gen_expr_call(struct gen_context *ctx, } static void +gen_expr_type_test(struct gen_context *ctx, + const struct expression *expr, + const struct qbe_value *out) +{ + // XXX: ARCH + const struct type *want = expr->cast.secondary, + *tagged = type_dealias(expr->cast.value->result); + struct qbe_value tag = {0}, in = {0}, id = {0}; + gen_temp(ctx, &tag, &qbe_word, "tag.%d"); + alloc_temp(ctx, &in, tagged, "cast.in.%d"); + qval_address(&in); + gen_expression(ctx, expr->cast.value, &in); + pushi(ctx->current, &tag, Q_LOADUW, &in, NULL); + char *type = gen_typename(want); + pushc(ctx->current, "%u => %s", want->id, want); + free(type); + constl(&id, want->id); + pushi(ctx->current, out, Q_CEQW, &tag, &id, NULL); +} + +static void +gen_type_assertion(struct gen_context *ctx, + const struct expression *expr, + struct qbe_value *in) +{ + // XXX: ARCH + const struct type *want = type_dealias(expr->cast.secondary); + struct qbe_value tag = {0}, id = {0}, result = {0}; + gen_temp(ctx, &tag, &qbe_word, "tag.%d"); + pushi(ctx->current, &tag, Q_LOADUW, in, NULL); + constw(&id, want->id); + char *type = gen_typename(want); + pushc(ctx->current, "%u => %s", want->id, type); + free(type); + gen_temp(ctx, &result, &qbe_word, "valid.%d"); + pushi(ctx->current, &result, Q_CEQW, &tag, &id, NULL); + + 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, "type.valid.%d")); + binvalid.kind = QV_LABEL; + binvalid.name = strdup(genl(&invalidl, &ctx->id, "type.invalid.%d")); + + pushi(ctx->current, NULL, Q_JNZ, &result, &bvalid, &binvalid, NULL); + + push(&ctx->current->body, &invalidl); + + struct qbe_value rtfunc = {0}; + rtfunc.kind = QV_GLOBAL; + rtfunc.name = strdup("rt.abort_fixed"); + rtfunc.type = &qbe_long; + constl(&result, ABORT_TYPE_ASSERTION); + pushi(ctx->current, NULL, Q_CALL, &rtfunc, &result, NULL); + + push(&ctx->current->body, &validl); +} + +static void gen_cast_to_tagged(struct gen_context *ctx, const struct expression *expr, const struct qbe_value *out, @@ -1070,6 +1129,7 @@ gen_cast_from_tagged(struct gen_context *ctx, const struct type *to) { if (type_dealias(to)->storage == TYPE_STORAGE_VOID) { + // TODO: generate type assertion if appropriate gen_expression(ctx, expr->cast.value, NULL); return; } @@ -1082,6 +1142,9 @@ gen_cast_from_tagged(struct gen_context *ctx, struct qbe_value object = {0}, offs = {0}, temp = {0}; alloc_temp(ctx, &object, tagged, "from.tagged.%d"); gen_expression(ctx, expr->cast.value, &object); + if (expr->cast.kind == C_ASSERTION) { + gen_type_assertion(ctx, expr, &object); + } struct qbe_value ptr = {0}; gen_temp(ctx, &ptr, &qbe_long, "ptr.%d"); @@ -1101,66 +1164,6 @@ gen_cast_from_tagged(struct gen_context *ctx, } static void -gen_expr_type_test(struct gen_context *ctx, - const struct expression *expr, - const struct qbe_value *out) -{ - // XXX: ARCH - const struct type *want = expr->cast.secondary, - *tagged = type_dealias(expr->cast.value->result); - struct qbe_value tag = {0}, in = {0}, id = {0}; - gen_temp(ctx, &tag, &qbe_word, "tag.%d"); - alloc_temp(ctx, &in, tagged, "cast.in.%d"); - qval_address(&in); - gen_expression(ctx, expr->cast.value, &in); - pushi(ctx->current, &tag, Q_LOADUW, &in, NULL); - char *type = gen_typename(want); - pushc(ctx->current, "%u => %s", want->id, want); - free(type); - constl(&id, want->id); - pushi(ctx->current, out, Q_CEQW, &tag, &id, NULL); -} - -static void -gen_expr_type_assertion(struct gen_context *ctx, - const struct expression *expr, - struct qbe_value *in, - const struct qbe_value *out) -{ - // XXX: ARCH - const struct type *want = type_dealias(expr->cast.secondary); - struct qbe_value tag = {0}, id = {0}, result = {0}; - gen_temp(ctx, &tag, &qbe_word, "tag.%d"); - pushi(ctx->current, &tag, Q_LOADUW, in, NULL); - constw(&id, want->id); - char *type = gen_typename(want); - pushc(ctx->current, "%u => %s", want->id, type); - free(type); - gen_temp(ctx, &result, &qbe_word, "valid.%d"); - pushi(ctx->current, &result, Q_CEQW, &tag, &id, NULL); - - 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, "type.valid.%d")); - binvalid.kind = QV_LABEL; - binvalid.name = strdup(genl(&invalidl, &ctx->id, "type.invalid.%d")); - - pushi(ctx->current, NULL, Q_JNZ, &result, &bvalid, &binvalid, NULL); - - push(&ctx->current->body, &invalidl); - - struct qbe_value rtfunc = {0}; - rtfunc.kind = QV_GLOBAL; - rtfunc.name = strdup("rt.abort_fixed"); - rtfunc.type = &qbe_long; - constl(&result, ABORT_TYPE_ASSERTION); - pushi(ctx->current, NULL, Q_CALL, &rtfunc, &result, NULL); - - push(&ctx->current->body, &validl); -} - -static void gen_expr_cast(struct gen_context *ctx, const struct expression *expr, const struct qbe_value *out) @@ -1227,7 +1230,7 @@ gen_expr_cast(struct gen_context *ctx, gen_expression(ctx, expr->cast.value, &in); if (expr->cast.kind == C_ASSERTION) { - gen_expr_type_assertion(ctx, expr, &in, out); + gen_type_assertion(ctx, expr, &in); } // Used for various casts