commit 2a6711b038d44577cd1aca66ea666260cbecc34b
parent 8376c3d205dffff25aa6294fde4c8e57f39af613
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 31 Jan 2021 11:01:14 -0500
gen: rig up new tagged rules
Diffstat:
3 files changed, 27 insertions(+), 13 deletions(-)
diff --git a/include/types.h b/include/types.h
@@ -145,6 +145,10 @@ const struct type *type_dealias(const struct type *type);
const struct struct_field *type_get_field(
const struct type *type, const char *name);
+const struct type *tagged_select_subtype(
+ const struct type *tagged, const struct type *subtype);
+bool tagged_subset_compat(const struct type *to, const struct type *from);
+
const char *type_storage_unparse(enum type_storage storage);
bool type_is_signed(const struct type *type);
bool type_is_integer(const struct type *type);
diff --git a/src/gen.c b/src/gen.c
@@ -916,17 +916,25 @@ gen_cast_to_tagged(struct gen_context *ctx,
const struct qbe_value *out,
const struct type *from)
{
+ const struct type *tagged = expr->result;
+ const struct type *subtype = tagged_select_subtype(tagged, from);
+
struct qbe_value tag = {0}, ptr = {0}, offs = {0};
- gen_temp(ctx, &ptr, &qbe_long, "ptr.%d");
+ gen_temp(ctx, &ptr, &qbe_long, "to_tagged.from.%d");
constl(&offs, expr->result->align);
- if (type_dealias(from)->storage == TYPE_STORAGE_TAGGED) {
+ if (!subtype) {
+ pushc(ctx->current, "to_tagged; no subtype");
gen_expression(ctx, expr->cast.value, &ptr);
gen_copy(ctx, out, &ptr);
return;
-
}
- constw(&tag, expr->cast.value->result->id);
+
+ pushc(ctx->current, "to_tagged; valid subtype");
+ // TODO: check should lower this to multiple casts:
+ assert(subtype->id == from->id);
+
+ constw(&tag, subtype->id);
pushi(ctx->current, &ptr, Q_COPY, out, NULL);
pushi(ctx->current, NULL, Q_STOREW, &tag, &ptr, NULL);
@@ -1048,19 +1056,21 @@ gen_expr_cast(struct gen_context *ctx,
return;
}
- const struct type *to = type_dealias(expr->result),
- *from = type_dealias(expr->cast.value->result);
- if (to->storage == from->storage && to->size == from->size) {
- gen_expression(ctx, expr->cast.value, out);
- return;
- } else if (to->storage == TYPE_STORAGE_TAGGED) {
+ const struct type *to = expr->result, *from = expr->cast.value->result;
+ if (type_dealias(to)->storage == TYPE_STORAGE_TAGGED) {
gen_cast_to_tagged(ctx, expr, out, from);
return;
- } else if (from->storage == TYPE_STORAGE_TAGGED) {
+ } else if (type_dealias(from)->storage == TYPE_STORAGE_TAGGED) {
gen_cast_from_tagged(ctx, expr, out, to);
return;
}
+ to = type_dealias(to), from = type_dealias(from);
+ if (to->storage == from->storage && to->size == from->size) {
+ gen_expression(ctx, expr->cast.value, out);
+ return;
+ }
+
bool is_signed = type_is_signed(from);
struct qbe_value in = {0}, result = {0};
diff --git a/src/types.c b/src/types.c
@@ -346,7 +346,7 @@ strip_flags(const struct type *t, struct type *secondary)
return secondary;
}
-static const struct type *
+const struct type *
tagged_select_subtype(const struct type *tagged, const struct type *subtype)
{
tagged = type_dealias(tagged);
@@ -375,7 +375,7 @@ tagged_select_subtype(const struct type *tagged, const struct type *subtype)
return NULL;
}
-static bool
+bool
tagged_subset_compat(const struct type *to, const struct type *from)
{
// Note: this implementation depends on the invariant that tagged union