From 63b54ce7c695fb1e204fe77db029cdebf7206b28 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 13 May 2021 12:48:12 +0100 Subject: [PATCH] Add minor ignoring hint on type assertions to get better code generation with no optimizations enabled --- src/check_expr.cpp | 20 ++++++++++++++++ src/llvm_backend.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++-- src/parser.hpp | 8 ++++++- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5784744d9..51dad8f79 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3949,6 +3949,16 @@ bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, add_type_and_value(&c->checker->info, o.expr, o.mode, tuple, o.value); } + if (o.mode == Addressing_OptionalOk && expr->kind == Ast_TypeAssertion) { + // NOTE(bill): Used only for optimizations in the backend + if (is_blank_ident(lhs[0].expr)) { + expr->TypeAssertion.ignores[0] = true; + } + if (is_blank_ident(lhs[1].expr)) { + expr->TypeAssertion.ignores[1] = true; + } + } + array_add(operands, val0); array_add(operands, val1); optional_ok = true; @@ -4063,6 +4073,16 @@ bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, add_type_and_value(&c->checker->info, o.expr, o.mode, tuple, o.value); } + if (o.mode == Addressing_OptionalOk && expr->kind == Ast_TypeAssertion) { + // NOTE(bill): Used only for optimizations in the backend + if (is_blank_ident(lhs[0]->token)) { + expr->TypeAssertion.ignores[0] = true; + } + if (is_blank_ident(lhs[1]->token)) { + expr->TypeAssertion.ignores[1] = true; + } + } + array_add(operands, val0); array_add(operands, val1); optional_ok = true; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8a9e5d7e2..dc36100a4 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -11119,7 +11119,54 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A return value; } -lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos, bool do_conversion_check=true) { +lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { + GB_ASSERT(is_type_tuple(type)); + lbModule *m = p->module; + + Type *src_type = value.type; + bool is_ptr = is_type_pointer(src_type); + + + // IMPORTANT NOTE(bill): This assumes that the value is completely ignored + // so when it does an assignment, it complete ignores the value. + // Just make it two booleans and ignore the first one + // + // _, ok := x.(T); + // + Type *ok_type = type->Tuple.variables[1]->type; + Type *gen_tuple_types[2] = {}; + gen_tuple_types[0] = ok_type; + gen_tuple_types[1] = ok_type; + + Type *gen_tuple = alloc_type_tuple_from_field_types(gen_tuple_types, gb_count_of(gen_tuple_types), false, true); + + lbAddr v = lb_add_local_generated(p, gen_tuple, false); + + if (is_ptr) { + value = lb_emit_load(p, value); + } + Type *src = base_type(type_deref(src_type)); + GB_ASSERT_MSG(is_type_union(src), "%s", type_to_string(src_type)); + Type *dst = type->Tuple.variables[0]->type; + + lbValue cond = {}; + + if (is_type_union_maybe_pointer(src)) { + lbValue data = lb_emit_transmute(p, value, dst); + cond = lb_emit_comp_against_nil(p, Token_NotEq, data); + } else { + lbValue tag = lb_emit_union_tag_value(p, value); + lbValue dst_tag = lb_const_union_tag(m, src, dst); + cond = lb_emit_comp(p, Token_CmpEq, tag, dst_tag); + } + + lbValue gep1 = lb_emit_struct_ep(p, v.addr, 1); + lb_emit_store(p, gep1, cond); + + return lb_addr_load(p, v); +} + +lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) { lbModule *m = p->module; Type *src_type = value.type; @@ -11183,7 +11230,7 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p lb_start_block(p, end_block); if (!is_tuple) { - if (do_conversion_check) { + { // NOTE(bill): Panic on invalid conversion Type *dst_type = tuple->Tuple.variables[0]->type; @@ -11487,6 +11534,10 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { lbValue e = lb_build_expr(p, ta->expr); Type *t = type_deref(e.type); if (is_type_union(t)) { + if (ta->ignores[0]) { + // NOTE(bill): This is not needed for optimization levels other than 0 + return lb_emit_union_cast_only_ok_check(p, e, type, pos); + } return lb_emit_union_cast(p, e, type, pos); } else if (is_type_any(t)) { return lb_emit_any_cast(p, e, type, pos); diff --git a/src/parser.hpp b/src/parser.hpp index 982588c0f..b6bf42f63 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -345,7 +345,13 @@ AST_KIND(_ExprBegin, "", bool) \ AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \ AST_KIND(TernaryIfExpr, "ternary if expression", struct { Ast *x, *cond, *y; }) \ AST_KIND(TernaryWhenExpr, "ternary when expression", struct { Ast *x, *cond, *y; }) \ - AST_KIND(TypeAssertion, "type assertion", struct { Ast *expr; Token dot; Ast *type; Type *type_hint; }) \ + AST_KIND(TypeAssertion, "type assertion", struct { \ + Ast *expr; \ + Token dot; \ + Ast *type; \ + Type *type_hint; \ + bool ignores[2]; \ + }) \ AST_KIND(TypeCast, "type cast", struct { Token token; Ast *type, *expr; }) \ AST_KIND(AutoCast, "auto_cast", struct { Token token; Ast *expr; }) \ AST_KIND(InlineAsmExpr, "inline asm expression", struct { \