harec

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

commit 9e06fc263b175db0e749fb39a8ddd1c0bf7b22fc
parent d0dea0fa2751ee89d588624a4ad97b9e97f43b0d
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat,  7 Aug 2021 09:23:33 +0200

gen: implement type test assertions ('is')

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Msrc/gen.c | 36++++++++++++++++++++++++++++++++++--
Mtests/13-tagged.ha | 7+++++++
2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/src/gen.c b/src/gen.c @@ -443,7 +443,8 @@ gen_expr_cast_at(struct gen_context *ctx, // is more efficient with the _at usage. For all other cases, it falls // back to gen_expr_cast. const struct type *to = expr->result, *from = expr->cast.value->result; - if (type_dealias(to)->storage != STORAGE_TAGGED) { + if (type_dealias(to)->storage != STORAGE_TAGGED + || expr->cast.kind == C_TEST) { struct gen_value result = gen_expr_cast(ctx, expr); if (!expr->terminates) { gen_store(ctx, out, result); @@ -491,6 +492,7 @@ gen_expr_cast_at(struct gen_context *ctx, gen_copy_aligned(ctx, iout, ival); } else { // Case 3: from is a member of to + assert(subtype == from); // Lowered by check struct qbe_value qout = mkqval(ctx, &out); struct qbe_value id = constw(subtype->id); enum qbe_instr store = store_for_type(ctx, &builtin_type_uint); @@ -508,10 +510,40 @@ gen_expr_cast_at(struct gen_context *ctx, } static struct gen_value +gen_expr_type_test(struct gen_context *ctx, const struct expression *expr) +{ + const struct type *secondary = expr->cast.secondary, + *from = expr->cast.value->result; + assert(type_dealias(from)->storage == STORAGE_TAGGED); + const struct type *subtype = tagged_select_subtype(from, secondary); + assert(subtype && subtype == secondary); // Lowered by check + + struct gen_value val = gen_expr(ctx, expr->cast.value); + struct qbe_value qval = mkqval(ctx, &val); + struct qbe_value tag = mkqtmp(ctx, + qtype_lookup(ctx, &builtin_type_uint, false), + ".%d"); + enum qbe_instr load = load_for_type(ctx, &builtin_type_uint); + pushi(ctx->current, &tag, load, &qval, NULL); + struct qbe_value expected = constl(secondary->id); + struct gen_value result = mktemp(ctx, &builtin_type_bool, ".%d"); + struct qbe_value qr = mkqval(ctx, &result); + pushi(ctx->current, &qr, Q_CEQW, &tag, &expected, NULL); + return result; +} + +static struct gen_value gen_expr_cast(struct gen_context *ctx, const struct expression *expr) { - assert(expr->cast.kind == C_CAST); // TODO const struct type *to = expr->result, *from = expr->cast.value->result; + switch (expr->cast.kind) { + case C_TEST: + return gen_expr_type_test(ctx, expr); + case C_ASSERTION: + assert(0); // TODO + case C_CAST: + break; + } // Casting to tagged union prefers _at form if (type_dealias(to)->storage == STORAGE_TAGGED) { diff --git a/tests/13-tagged.ha b/tests/13-tagged.ha @@ -90,10 +90,17 @@ fn casts() void = { assert(x == (if (is_little) 0xFEu8 else 0xCAu8)); }; +fn assertions() void = { + let a: (u8 | u16) = 42u16; + assert(a is u16); + // TODO: as +}; + export fn main() void = { measurements(); storage(); operators(); reduction(); casts(); + assertions(); };