diff --git a/src/check_expr.c b/src/check_expr.c index 0854fd17d..0ee819913 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1154,6 +1154,69 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) { return new_type; } +Type *reduce_tuple_to_single_type(Type *original_type) { + if (original_type != NULL) { + Type *t = core_type(original_type); + if (t->kind == Type_Tuple && t->Tuple.variable_count == 1) { + return t->Tuple.variables[0]->type; + } + } + return original_type; +} + +Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) { + Type *new_type = original_type; + if (new_type == NULL) { + return NULL; + } + GB_ASSERT(is_type_tuple(original_type)); + + + + if (str_eq(build_context.ODIN_OS, str_lit("windows"))) { + Type *bt = core_type(reduce_tuple_to_single_type(original_type)); + // NOTE(bill): This is just reversed engineered from LLVM IR output + switch (bt->kind) { + // Okay to pass by value + // Especially the only Odin types + case Type_Pointer: break; + case Type_Proc: break; // NOTE(bill): Just a pointer + case Type_Basic: break; + + + default: { + i64 align = type_align_of(a, original_type); + i64 size = type_size_of(a, original_type); + switch (8*size) { +#if 1 + case 8: new_type = t_u8; break; + case 16: new_type = t_u16; break; + case 32: new_type = t_u32; break; + case 64: new_type = t_u64; break; +#endif + } + } break; + } + } else if (str_eq(build_context.ODIN_OS, str_lit("linux"))) { + + } else { + // IMPORTANT TODO(bill): figure out the ABI settings for Linux, OSX etc. for + // their architectures + } + + if (new_type != original_type) { + Type *tuple = make_type_tuple(a); + tuple->Tuple.variable_count = 1; + tuple->Tuple.variables = gb_alloc_array(a, Entity *, 1); + tuple->Tuple.variables[0] = make_entity_param(a, original_type->Tuple.variables[0]->scope, empty_token, new_type, false, false); + new_type = tuple; + } + + + // return reduce_tuple_to_single_type(new_type); + return new_type; +} + void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { ast_node(pt, ProcType, proc_type_node); @@ -1184,10 +1247,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { } // NOTE(bill): The types are the same - type->Proc.abi_compat_results = gb_alloc_array(c->allocator, Type *, result_count); - for (isize i = 0; i < result_count; i++) { - type->Proc.abi_compat_results[i] = type->Proc.results->Tuple.variables[i]->type; - } + type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results); } diff --git a/src/ir.c b/src/ir.c index 1ef13f8b5..3c99a6346 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1489,7 +1489,14 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_ } } - return ir_emit(p, ir_instr_call(p, value, args, arg_count, results)); + Type *abi_rt = pt->Proc.abi_compat_result_type; + Type *rt = reduce_tuple_to_single_type(results); + + irValue *result = ir_emit(p, ir_instr_call(p, value, args, arg_count, abi_rt)); + if (abi_rt != results) { + result = ir_emit_transmute(p, result, rt); + } + return result; } irValue *ir_emit_global_call(irProcedure *proc, char *name_, irValue **args, isize arg_count) { @@ -1547,6 +1554,12 @@ void ir_emit_unreachable(irProcedure *proc) { void ir_emit_return(irProcedure *proc, irValue *v) { ir_emit_defer_stmts(proc, irDeferExit_Return, NULL); + + Type *abi_rt = proc->type->Proc.abi_compat_result_type; + if (abi_rt != proc->type->Proc.results) { + v = ir_emit_transmute(proc, v, abi_rt); + } + ir_emit(proc, ir_instr_return(proc, v)); } @@ -2970,7 +2983,9 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst)); - GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); + GB_PANIC("Invalid type conversion: `%s` to `%s` for procedure `%.*s`", + type_to_string(src_type), type_to_string(t), + LIT(proc->name)); return NULL; } @@ -3019,10 +3034,11 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) { Type *src = base_type(src_type); Type *dst = base_type(t); +#if 0 if (are_types_identical(t, src_type)) { return value; } - +#endif irModule *m = proc->module; i64 sz = type_size_of(m->allocator, src); @@ -3032,7 +3048,7 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) { if (ir_is_type_aggregate(src) || ir_is_type_aggregate(dst)) { irValue *s = ir_address_from_load_or_generate_local(proc, value); - irValue *d = ir_emit_bitcast(proc, s, make_type_pointer(m->allocator, dst)); + irValue *d = ir_emit_bitcast(proc, s, make_type_pointer(m->allocator, t)); return ir_emit_load(proc, d); } @@ -5214,7 +5230,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { elem = fv->value; } else { TypeAndValue tav = type_and_value_of_expr(proc->module->info, elem); - Selection sel = lookup_field(proc->module->allocator, bt, st->fields_in_src_order[field_index]->token.string, false); + Selection sel = lookup_field_from_index(proc->module->allocator, bt, st->fields_in_src_order[field_index]->Variable.field_index); index = sel.index.e[0]; } @@ -6061,6 +6077,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { gb_temp_arena_memory_end(tmp); } + ir_emit_return(proc, v); case_end; diff --git a/src/ir_print.c b/src/ir_print.c index 145cb55a0..20eb8449d 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -144,17 +144,23 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { isize result_count = t->Proc.result_count; if (result_count == 0) { ir_fprintf(f, "void"); - } else if (result_count == 1) { - ir_print_type(f, m, t->Proc.abi_compat_results[0]); } else { - ir_fprintf(f, "{"); - for (isize i = 0; i < result_count; i++) { - if (i > 0) { - ir_fprintf(f, ", "); + Type *rt = t->Proc.abi_compat_result_type; + if (!is_type_tuple(rt)) { + ir_print_type(f, m, rt); + } else if (rt->Tuple.variable_count == 1) { + ir_print_type(f, m, rt->Tuple.variables[0]->type); + } else { + isize count = rt->Tuple.variable_count; + ir_fprintf(f, "{"); + for (isize i = 0; i < count; i++) { + if (i > 0) { + ir_fprintf(f, ", "); + } + ir_print_type(f, m, rt->Tuple.variables[i]->type); } - ir_print_type(f, m, t->Proc.abi_compat_results[i]); + ir_fprintf(f, "}"); } - ir_fprintf(f, "}"); } } diff --git a/src/types.c b/src/types.c index b70e79fbf..34b56583a 100644 --- a/src/types.c +++ b/src/types.c @@ -138,7 +138,7 @@ typedef struct TypeRecord { i32 param_count; \ i32 result_count; \ Type **abi_compat_params; \ - Type **abi_compat_results; \ + Type * abi_compat_result_type; \ bool variadic; \ bool require_results; \ ProcCallingConvention calling_convention; \