diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 456b2cdc7..ce6b0eb82 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -81,7 +81,6 @@ gb_internal void cg_global_source_code_location_const(cgModule *m, String const } } - gb_internal cgValue cg_emit_source_code_location_as_global(cgProcedure *p, String const &proc_name, TokenPos pos) { cgModule *m = p->module; char name[32] = {}; @@ -1047,3 +1046,10 @@ gb_internal cgValue cg_const_union_tag(cgProcedure *p, Type *u, Type *v) { return cg_const_value(p, union_tag_type(u), exact_value_i64(union_variant_index(u, v))); } + + +gb_internal cgValue cg_find_or_add_entity_string(cgProcedure *p, String const &s) { + // TODO(bill): make this better + return cg_const_string(p, t_string, s); +} + diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp index 02f8da5e1..af1c234e0 100644 --- a/src/tilde_expr.cpp +++ b/src/tilde_expr.cpp @@ -945,6 +945,13 @@ gb_internal void cg_emit_store_union_variant(cgProcedure *p, cgValue parent, cgV } } +gb_internal cgValue cg_emit_union_tag_value(cgProcedure *p, cgValue u) { + cgValue ptr = cg_address_from_load_or_generate_local(p, u); + cgValue tag_ptr = cg_emit_union_tag_ptr(p, ptr); + return cg_emit_load(p, tag_ptr); +} + + gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t) { t = reduce_tuple_to_single_type(t); @@ -3154,6 +3161,7 @@ cgAddr cg_build_addr_compound_lit(cgProcedure *p, Ast *expr) { } case Type_SimdVector: { + GB_PANIC("TODO(bill): #simd compound literals"); // auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); // populate(p, cl->elems, &temp_data, type); @@ -3241,151 +3249,150 @@ gb_internal cgValue cg_build_unary_and(cgProcedure *p, Ast *expr) { cgAddr addr = cg_build_addr_compound_lit(p, expr); return addr.addr; } else if (ue_expr->kind == Ast_TypeAssertion) { - GB_PANIC("TODO(bill): &v.(T)"); - // if (is_type_tuple(tv.type)) { - // Type *tuple = tv.type; - // Type *ptr_type = tuple->Tuple.variables[0]->type; - // Type *ok_type = tuple->Tuple.variables[1]->type; + if (is_type_tuple(tv.type)) { + Type *tuple = tv.type; + Type *ptr_type = tuple->Tuple.variables[0]->type; + Type *ok_type = tuple->Tuple.variables[1]->type; - // ast_node(ta, TypeAssertion, ue_expr); - // TokenPos pos = ast_token(expr).pos; - // Type *type = type_of_expr(ue_expr); - // GB_ASSERT(!is_type_tuple(type)); + ast_node(ta, TypeAssertion, ue_expr); + TokenPos pos = ast_token(expr).pos; + Type *type = type_of_expr(ue_expr); + GB_ASSERT(!is_type_tuple(type)); - // lbValue e = lb_build_expr(p, ta->expr); - // Type *t = type_deref(e.type); - // if (is_type_union(t)) { - // lbValue v = e; - // if (!is_type_pointer(v.type)) { - // v = lb_address_from_load_or_generate_local(p, v); - // } - // Type *src_type = type_deref(v.type); - // Type *dst_type = type; + cgValue e = cg_build_expr(p, ta->expr); + Type *t = type_deref(e.type); + if (is_type_union(t)) { + cgValue v = e; + if (!is_type_pointer(v.type)) { + v = cg_address_from_load_or_generate_local(p, v); + } + Type *src_type = type_deref(v.type); + Type *dst_type = type; - // lbValue src_tag = {}; - // lbValue dst_tag = {}; - // if (is_type_union_maybe_pointer(src_type)) { - // src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); - // dst_tag = lb_const_bool(p->module, t_bool, true); - // } else { - // src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); - // dst_tag = lb_const_union_tag(p->module, src_type, dst_type); - // } + cgValue src_tag = {}; + cgValue dst_tag = {}; + if (is_type_union_maybe_pointer(src_type)) { + src_tag = cg_emit_comp_against_nil(p, Token_NotEq, v); + dst_tag = cg_const_bool(p, t_bool, true); + } else { + src_tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, v)); + dst_tag = cg_const_union_tag(p, src_type, dst_type); + } - // lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); + cgValue ok = cg_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - // lbValue data_ptr = lb_emit_conv(p, v, ptr_type); - // lbAddr res = lb_add_local_generated(p, tuple, true); - // lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - // lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - // lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type))); - // lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type)); - // return lb_addr_load(p, res); - // } else if (is_type_any(t)) { - // lbValue v = e; - // if (is_type_pointer(v.type)) { - // v = lb_emit_load(p, v); - // } + cgValue data_ptr = cg_emit_conv(p, v, ptr_type); + cgAddr res = cg_add_local(p, tuple, nullptr, true); + cgValue gep0 = cg_emit_struct_ep(p, res.addr, 0); + cgValue gep1 = cg_emit_struct_ep(p, res.addr, 1); + cg_emit_store(p, gep0, cg_emit_select(p, ok, data_ptr, cg_const_nil(p, ptr_type))); + cg_emit_store(p, gep1, cg_emit_conv(p, ok, ok_type)); + return cg_addr_load(p, res); + } else if (is_type_any(t)) { + cgValue v = e; + if (is_type_pointer(v.type)) { + v = cg_emit_load(p, v); + } - // lbValue data_ptr = lb_emit_conv(p, lb_emit_struct_ev(p, v, 0), ptr_type); - // lbValue any_id = lb_emit_struct_ev(p, v, 1); - // lbValue id = lb_typeid(p->module, type); + cgValue data_ptr = cg_emit_conv(p, cg_emit_struct_ev(p, v, 0), ptr_type); + cgValue any_id = cg_emit_struct_ev(p, v, 1); + cgValue id = cg_typeid(p, type); - // lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); + cgValue ok = cg_emit_comp(p, Token_CmpEq, any_id, id); - // lbAddr res = lb_add_local_generated(p, tuple, false); - // lbValue gep0 = lb_emit_struct_ep(p, res.addr, 0); - // lbValue gep1 = lb_emit_struct_ep(p, res.addr, 1); - // lb_emit_store(p, gep0, lb_emit_select(p, ok, data_ptr, lb_const_nil(p->module, ptr_type))); - // lb_emit_store(p, gep1, lb_emit_conv(p, ok, ok_type)); - // return lb_addr_load(p, res); - // } else { - // GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); - // } + cgAddr res = cg_add_local(p, tuple, nullptr, false); + cgValue gep0 = cg_emit_struct_ep(p, res.addr, 0); + cgValue gep1 = cg_emit_struct_ep(p, res.addr, 1); + cg_emit_store(p, gep0, cg_emit_select(p, ok, data_ptr, cg_const_nil(p, ptr_type))); + cg_emit_store(p, gep1, cg_emit_conv(p, ok, ok_type)); + return cg_addr_load(p, res); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); + } - // } else { - // GB_ASSERT(is_type_pointer(tv.type)); + } else { + GB_ASSERT(is_type_pointer(tv.type)); - // ast_node(ta, TypeAssertion, ue_expr); - // TokenPos pos = ast_token(expr).pos; - // Type *type = type_of_expr(ue_expr); - // GB_ASSERT(!is_type_tuple(type)); + ast_node(ta, TypeAssertion, ue_expr); + TokenPos pos = ast_token(expr).pos; + Type *type = type_of_expr(ue_expr); + GB_ASSERT(!is_type_tuple(type)); - // lbValue e = lb_build_expr(p, ta->expr); - // Type *t = type_deref(e.type); - // if (is_type_union(t)) { - // lbValue v = e; - // if (!is_type_pointer(v.type)) { - // v = lb_address_from_load_or_generate_local(p, v); - // } - // Type *src_type = type_deref(v.type); - // Type *dst_type = type; + cgValue e = cg_build_expr(p, ta->expr); + Type *t = type_deref(e.type); + if (is_type_union(t)) { + cgValue v = e; + if (!is_type_pointer(v.type)) { + v = cg_address_from_load_or_generate_local(p, v); + } + Type *src_type = type_deref(v.type); + Type *dst_type = type; - // if ((p->state_flags & StateFlag_no_type_assert) == 0) { - // lbValue src_tag = {}; - // lbValue dst_tag = {}; - // if (is_type_union_maybe_pointer(src_type)) { - // src_tag = lb_emit_comp_against_nil(p, Token_NotEq, v); - // dst_tag = lb_const_bool(p->module, t_bool, true); - // } else { - // src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v)); - // dst_tag = lb_const_union_tag(p->module, src_type, dst_type); - // } + if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { + cgValue src_tag = {}; + cgValue dst_tag = {}; + if (is_type_union_maybe_pointer(src_type)) { + src_tag = cg_emit_comp_against_nil(p, Token_NotEq, v); + dst_tag = cg_const_bool(p, t_bool, true); + } else { + src_tag = cg_emit_load(p, cg_emit_union_tag_ptr(p, v)); + dst_tag = cg_const_union_tag(p, src_type, dst_type); + } - // isize arg_count = 6; - // if (build_context.no_rtti) { - // arg_count = 4; - // } + isize arg_count = 6; + if (build_context.no_rtti) { + arg_count = 4; + } - // lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - // auto args = array_make(permanent_allocator(), arg_count); - // args[0] = ok; + cgValue ok = cg_emit_comp(p, Token_CmpEq, src_tag, dst_tag); + auto args = slice_make(permanent_allocator(), arg_count); + args[0] = ok; - // args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - // args[2] = lb_const_int(p->module, t_i32, pos.line); - // args[3] = lb_const_int(p->module, t_i32, pos.column); + args[1] = cg_find_or_add_entity_string(p, get_file_path_string(pos.file_id)); + args[2] = cg_const_int(p, t_i32, pos.line); + args[3] = cg_const_int(p, t_i32, pos.column); - // if (!build_context.no_rtti) { - // args[4] = lb_typeid(p->module, src_type); - // args[5] = lb_typeid(p->module, dst_type); - // } - // lb_emit_runtime_call(p, "type_assertion_check", args); - // } + if (!build_context.no_rtti) { + args[4] = cg_typeid(p, src_type); + args[5] = cg_typeid(p, dst_type); + } + cg_emit_runtime_call(p, "type_assertion_check", args); + } - // lbValue data_ptr = v; - // return lb_emit_conv(p, data_ptr, tv.type); - // } else if (is_type_any(t)) { - // lbValue v = e; - // if (is_type_pointer(v.type)) { - // v = lb_emit_load(p, v); - // } - // lbValue data_ptr = lb_emit_struct_ev(p, v, 0); - // if ((p->state_flags & StateFlag_no_type_assert) == 0) { - // GB_ASSERT(!build_context.no_rtti); + cgValue data_ptr = v; + return cg_emit_conv(p, data_ptr, tv.type); + } else if (is_type_any(t)) { + cgValue v = e; + if (is_type_pointer(v.type)) { + v = cg_emit_load(p, v); + } + cgValue data_ptr = cg_emit_struct_ev(p, v, 0); + if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { + GB_ASSERT(!build_context.no_rtti); - // lbValue any_id = lb_emit_struct_ev(p, v, 1); + cgValue any_id = cg_emit_struct_ev(p, v, 1); - // lbValue id = lb_typeid(p->module, type); - // lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - // auto args = array_make(permanent_allocator(), 6); - // args[0] = ok; + cgValue id = cg_typeid(p, type); + cgValue ok = cg_emit_comp(p, Token_CmpEq, any_id, id); + auto args = slice_make(permanent_allocator(), 6); + args[0] = ok; - // args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id)); - // args[2] = lb_const_int(p->module, t_i32, pos.line); - // args[3] = lb_const_int(p->module, t_i32, pos.column); + args[1] = cg_find_or_add_entity_string(p, get_file_path_string(pos.file_id)); + args[2] = cg_const_int(p, t_i32, pos.line); + args[3] = cg_const_int(p, t_i32, pos.column); - // args[4] = any_id; - // args[5] = id; - // lb_emit_runtime_call(p, "type_assertion_check", args); - // } + args[4] = any_id; + args[5] = id; + cg_emit_runtime_call(p, "type_assertion_check", args); + } - // return lb_emit_conv(p, data_ptr, tv.type); - // } else { - // GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); - // } - // } + return cg_emit_conv(p, data_ptr, tv.type); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(type)); + } + } } return cg_build_addr_ptr(p, ue->expr); @@ -3558,6 +3565,52 @@ gb_internal cgValue cg_emit_cast_any(cgProcedure *p, cgValue value, Type *type, return cg_value_multi2(cg_emit_load(p, gep0), cg_emit_load(p, gep1), tuple); } +gb_internal cgValue cg_emit_cast_union_ok_only(cgProcedure *p, cgValue value, Type *type, TokenPos pos) { + GB_ASSERT(is_type_tuple(type)); + + 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); + + cgAddr v = cg_add_local(p, gen_tuple, nullptr, false); + + if (is_ptr) { + value = cg_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; + + cgValue cond = {}; + + if (is_type_union_maybe_pointer(src)) { + cgValue data = cg_emit_transmute(p, value, dst); + cond = cg_emit_comp_against_nil(p, Token_NotEq, data); + } else { + cgValue tag = cg_emit_union_tag_value(p, value); + cgValue dst_tag = cg_const_union_tag(p, src, dst); + cond = cg_emit_comp(p, Token_CmpEq, tag, dst_tag); + } + + cgValue gep1 = cg_emit_struct_ep(p, v.addr, 1); + cg_emit_store(p, gep1, cond); + + return cg_addr_load(p, v); +} + gb_internal cgValue cg_build_type_assertion(cgProcedure *p, Ast *expr, Type *type) { ast_node(ta, TypeAssertion, expr); @@ -3567,6 +3620,9 @@ gb_internal cgValue cg_build_type_assertion(cgProcedure *p, Ast *expr, Type *typ Type *t = type_deref(e.type); if (is_type_union(t)) { + if (ta->ignores[0]) { + return cg_emit_cast_union_ok_only(p, e, type, pos); + } return cg_emit_cast_union(p, e, type, pos); } else if (is_type_any(t)) { return cg_emit_cast_any(p, e, type, pos); diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp index e8acccefb..65796d643 100644 --- a/src/tilde_stmt.cpp +++ b/src/tilde_stmt.cpp @@ -771,6 +771,16 @@ gb_internal cgValue cg_emit_struct_ev(cgProcedure *p, cgValue s, i64 index) { return cg_flatten_value(p, cg_emit_load(p, ptr)); } +gb_internal cgValue cg_emit_tuple_ev(cgProcedure *p, cgValue value, i64 index) { + GB_ASSERT(value.kind == cgValue_Multi); + GB_ASSERT(value.multi != nullptr); + GB_ASSERT(value.type->kind == Type_Tuple); + GB_ASSERT(0 <= index && index < value.type->Tuple.variables.count); + return value.multi->values[index]; +} + + + gb_internal cgValue cg_emit_deep_field_gep(cgProcedure *p, cgValue e, Selection const &sel) { GB_ASSERT(sel.index.count > 0); @@ -1950,6 +1960,58 @@ gb_internal void cg_build_range_stmt_struct_soa(cgProcedure *p, AstRangeStmt *rs } +gb_internal void cg_build_range_tuple(cgProcedure *p, AstRangeStmt *rs, Scope *scope) { + Ast *expr = unparen_expr(rs->expr); + + Type *expr_type = type_of_expr(expr); + Type *et = base_type(type_deref(expr_type)); + GB_ASSERT(et->kind == Type_Tuple); + + i32 value_count = cast(i32)et->Tuple.variables.count; + + cgValue *values = gb_alloc_array(permanent_allocator(), cgValue, value_count); + + cg_scope_open(p, scope); + + TB_Node *loop = cg_control_region(p, "for.tuple.loop"); + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, loop); + + TB_Node *body = cg_control_region(p, "for.tuple.body"); + TB_Node *done = cg_control_region(p, "for.tuple.done"); + + cgValue tuple_value = cg_build_expr(p, expr); + Type *tuple = tuple_value.type; + GB_ASSERT(tuple->kind == Type_Tuple); + i32 tuple_count = cast(i32)tuple->Tuple.variables.count; + i32 cond_index = tuple_count-1; + + cgValue cond = cg_emit_struct_ev(p, tuple_value, cond_index); + cg_emit_if(p, cond, body, done); + tb_inst_set_control(p->func, body); + + for (i32 i = 0; i < value_count; i++) { + values[i] = cg_emit_tuple_ev(p, tuple_value, i); + } + + GB_ASSERT(rs->vals.count <= value_count); + for (isize i = 0; i < rs->vals.count; i++) { + Ast *val = rs->vals[i]; + if (val != nullptr) { + cg_range_stmt_store_val(p, val, values[i]); + } + } + + cg_push_target_list(p, rs->label, done, loop, nullptr); + + cg_build_stmt(p, rs->body); + + cg_scope_close(p, cgDeferExit_Default, nullptr); + cg_pop_target_list(p); + cg_emit_goto(p, loop); + tb_inst_set_control(p->func, done); +} + gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { ast_node(rs, RangeStmt, node); @@ -1970,6 +2032,17 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { } } + TypeAndValue tav = type_and_value_of_expr(expr); + if (tav.mode != Addressing_Type) { + Type *expr_type = type_of_expr(expr); + Type *et = base_type(type_deref(expr_type)); + if (et->kind == Type_Tuple) { + cg_build_range_tuple(p, rs, rs->scope); + return; + } + } + + cg_scope_open(p, rs->scope); @@ -1989,7 +2062,6 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { TB_Node *loop = nullptr; TB_Node *done = nullptr; bool is_map = false; - TypeAndValue tav = type_and_value_of_expr(expr); if (tav.mode == Addressing_Type) { cg_build_range_stmt_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done); @@ -2067,8 +2139,11 @@ gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node) { break; } case Type_Tuple: - GB_PANIC("TODO(bill): cg_build_range_tuple"); - // cg_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); + GB_PANIC("Should be handled already"); + break; + + case Type_BitSet: + GB_PANIC("TODO(bill): for in bit_set"); break; default: GB_PANIC("Cannot range over %s", type_to_string(expr_type));