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:
M | src/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) {