mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Try a different ABI type for return values on Windows
This commit is contained in:
+64
-4
@@ -1154,6 +1154,69 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
|
|||||||
return new_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) {
|
void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
|
||||||
ast_node(pt, ProcType, 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
|
// NOTE(bill): The types are the same
|
||||||
type->Proc.abi_compat_results = gb_alloc_array(c->allocator, Type *, result_count);
|
type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results);
|
||||||
for (isize i = 0; i < result_count; i++) {
|
|
||||||
type->Proc.abi_compat_results[i] = type->Proc.results->Tuple.variables[i]->type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
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) {
|
void ir_emit_return(irProcedure *proc, irValue *v) {
|
||||||
ir_emit_defer_stmts(proc, irDeferExit_Return, NULL);
|
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));
|
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_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;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -3019,10 +3034,11 @@ irValue *ir_emit_transmute(irProcedure *proc, irValue *value, Type *t) {
|
|||||||
|
|
||||||
Type *src = base_type(src_type);
|
Type *src = base_type(src_type);
|
||||||
Type *dst = base_type(t);
|
Type *dst = base_type(t);
|
||||||
|
#if 0
|
||||||
if (are_types_identical(t, src_type)) {
|
if (are_types_identical(t, src_type)) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
irModule *m = proc->module;
|
irModule *m = proc->module;
|
||||||
|
|
||||||
i64 sz = type_size_of(m->allocator, src);
|
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)) {
|
if (ir_is_type_aggregate(src) || ir_is_type_aggregate(dst)) {
|
||||||
irValue *s = ir_address_from_load_or_generate_local(proc, value);
|
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);
|
return ir_emit_load(proc, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5214,7 +5230,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
|||||||
elem = fv->value;
|
elem = fv->value;
|
||||||
} else {
|
} else {
|
||||||
TypeAndValue tav = type_and_value_of_expr(proc->module->info, elem);
|
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];
|
index = sel.index.e[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6061,6 +6077,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
|||||||
|
|
||||||
gb_temp_arena_memory_end(tmp);
|
gb_temp_arena_memory_end(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
ir_emit_return(proc, v);
|
ir_emit_return(proc, v);
|
||||||
|
|
||||||
case_end;
|
case_end;
|
||||||
|
|||||||
+14
-8
@@ -144,17 +144,23 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
isize result_count = t->Proc.result_count;
|
isize result_count = t->Proc.result_count;
|
||||||
if (result_count == 0) {
|
if (result_count == 0) {
|
||||||
ir_fprintf(f, "void");
|
ir_fprintf(f, "void");
|
||||||
} else if (result_count == 1) {
|
|
||||||
ir_print_type(f, m, t->Proc.abi_compat_results[0]);
|
|
||||||
} else {
|
} else {
|
||||||
ir_fprintf(f, "{");
|
Type *rt = t->Proc.abi_compat_result_type;
|
||||||
for (isize i = 0; i < result_count; i++) {
|
if (!is_type_tuple(rt)) {
|
||||||
if (i > 0) {
|
ir_print_type(f, m, rt);
|
||||||
ir_fprintf(f, ", ");
|
} 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, "}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -138,7 +138,7 @@ typedef struct TypeRecord {
|
|||||||
i32 param_count; \
|
i32 param_count; \
|
||||||
i32 result_count; \
|
i32 result_count; \
|
||||||
Type **abi_compat_params; \
|
Type **abi_compat_params; \
|
||||||
Type **abi_compat_results; \
|
Type * abi_compat_result_type; \
|
||||||
bool variadic; \
|
bool variadic; \
|
||||||
bool require_results; \
|
bool require_results; \
|
||||||
ProcCallingConvention calling_convention; \
|
ProcCallingConvention calling_convention; \
|
||||||
|
|||||||
Reference in New Issue
Block a user