Mock out for in multiple-return values

This commit is contained in:
gingerBill
2024-04-30 15:50:55 +01:00
parent f69b127c9f
commit c55b3d49b5
3 changed files with 262 additions and 125 deletions

View File

@@ -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);
}

View File

@@ -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<cgCompoundLitElemTempData>(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<lbValue>(permanent_allocator(), arg_count);
// args[0] = ok;
cgValue ok = cg_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
auto args = slice_make<cgValue>(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<lbValue>(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<cgValue>(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);

View File

@@ -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));