harec

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

commit aaee24a6426cac9490712aefe03221bbf6813e8d
parent 70b85a49d251e84a6954cc653a3036927110f9b1
Author: Drew DeVault <sir@cmpwn.com>
Date:   Tue,  2 Feb 2021 18:06:55 -0500

gen: more refactoring for match

Diffstat:
Msrc/gen.c | 98+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 63 insertions(+), 35 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -1480,12 +1480,53 @@ gen_expr_list(struct gen_context *ctx, } static void +gen_recursive_match_tests(struct gen_context *ctx, const struct type *mtype, + struct qbe_value *fbranch, struct qbe_value *tag, + struct qbe_value *mval, struct match_case *_case) +{ + struct qbe_value temp = {0}, temp_tag = {0}, subval = {0}, offs = {0}; + gen_temp(ctx, &subval, &qbe_long, "subtag.ptr.%d"); + gen_temp(ctx, &temp_tag, &qbe_word, "subtag.tag.%d"); + pushi(ctx->current, &subval, Q_COPY, mval, NULL); + gen_temp(ctx, &temp, &qbe_word, "temp.%d"); + + struct qbe_value *curtag = tag; + const struct type *subtype = mtype; + const struct type *test = _case->type; + do { + struct qbe_statement slabel = {0}; + struct qbe_value sbranch = {0}; + test = tagged_select_subtype(subtype, _case->type); + if (!test) { + break; + } + + struct qbe_value match = {0}; + sbranch.kind = QV_LABEL; + sbranch.name = strdup(genl(&slabel, &ctx->id, "match.subtype.%d")); + constw(&match, test->id); + pushi(ctx->current, &temp, Q_CEQW, &match, curtag, NULL); + pushi(ctx->current, NULL, Q_JNZ, &temp, &sbranch, fbranch, NULL); + push(&ctx->current->body, &slabel); + + if (test->id != _case->type->id) { + constl(&offs, subtype->align); + pushi(ctx->current, &subval, Q_ADD, &subval, &offs, NULL); + pushi(ctx->current, &temp_tag, Q_LOADUW, &subval, NULL); + curtag = &temp_tag; + } + + subtype = test; + } while (test->id != _case->type->id); +} + +static void gen_match_tagged(struct gen_context *ctx, const struct expression *expr, const struct qbe_value *out) { const struct type *mtype = expr->match.value->result; - struct qbe_value mval = {0}, tag = {0}, match = {0}, temp = {0}; + struct qbe_value mval = {0}, tag = {0}, temp = {0}; // Kill me alloc_temp(ctx, &mval, mtype, "match.%d"); qval_deref(&mval); @@ -1515,40 +1556,22 @@ gen_match_tagged(struct gen_context *ctx, fbranch.kind = QV_LABEL; fbranch.name = strdup(genl(&flabel, &ctx->id, "next.case.%d")); - struct qbe_value temp_tag = {0}, subval = {0}, offs = {0}; - gen_temp(ctx, &subval, &qbe_long, "subtag.ptr.%d"); - gen_temp(ctx, &temp_tag, &qbe_word, "subtag.tag.%d"); - pushi(ctx->current, &subval, Q_COPY, &mval, NULL); - - struct qbe_value *curtag = &tag; - const struct type *subtype = mtype; - const struct type *test = _case->type; - do { - struct qbe_statement slabel = {0}; - struct qbe_value sbranch = {0}; - test = tagged_select_subtype(subtype, _case->type); - if (!test) { - assert(type_dealias(_case->type)->storage == TYPE_STORAGE_TAGGED); - assert(tagged_subset_compat(subtype, _case->type)); - assert(0); // TODO - } - - sbranch.kind = QV_LABEL; - sbranch.name = strdup(genl(&slabel, &ctx->id, "match.subtype.%d")); - constw(&match, test->id); - pushi(ctx->current, &temp, Q_CEQW, &match, curtag, NULL); - pushi(ctx->current, NULL, Q_JNZ, &temp, &sbranch, &fbranch, NULL); - push(&ctx->current->body, &slabel); - - if (test->id != _case->type->id) { - constl(&offs, subtype->align); - pushi(ctx->current, &subval, Q_ADD, &subval, &offs, NULL); - pushi(ctx->current, &temp_tag, Q_LOADUW, &subval, NULL); - curtag = &temp_tag; - } + bool reinterpret = false; + if (tagged_select_subtype(mtype, _case->type) == NULL) { + assert(type_dealias(_case->type)->storage == TYPE_STORAGE_TAGGED); + assert(tagged_subset_compat(mtype, _case->type)); + // Our match value can be "re-interpreted" as this case + // type because it is a subset-compatible tagged union. + // This causes later code to leave the pointer at the + // tag, rather than advancing it to the value area, + // before initializing a binding for it. + reinterpret = true; + assert(0); // TODO + } else { + gen_recursive_match_tests(ctx, mtype, + &fbranch, &tag, &mval, _case); + } - subtype = test; - } while (test->id != _case->type->id); pushi(ctx->current, NULL, Q_JMP, &tbranch, NULL); push(&ctx->current->body, &tlabel); @@ -1565,7 +1588,12 @@ gen_match_tagged(struct gen_context *ctx, ctx->bindings = binding; constl(&temp, mtype->align); val.type = &qbe_long; - pushi(ctx->current, &val, Q_ADD, &mval, &temp, NULL); + if (!reinterpret) { + pushi(ctx->current, &val, Q_ADD, + &mval, &temp, NULL); + } else { + pushi(ctx->current, &val, Q_COPY, &mval, NULL); + } } if (_case->value->terminates) {