diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-05-28 14:11:00 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-05-28 14:11:00 +0100 |
| commit | b41f09b73000f45963c445f7b2b56e2adb96a00b (patch) | |
| tree | e5e8bae0c5fc3e0def4d9442ebbcdc4a97550e5d /src | |
| parent | 06185e176988085ed7e77793f128b9e431eedd5e (diff) | |
Experimental try for ABI for return values on windows
It's all done by reverse engineering it. I may be wrong...
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_expr.c | 24 | ||||
| -rw-r--r-- | src/entity.c | 1 | ||||
| -rw-r--r-- | src/ir.c | 44 | ||||
| -rw-r--r-- | src/ir_print.c | 30 | ||||
| -rw-r--r-- | src/types.c | 1 |
5 files changed, 91 insertions, 9 deletions
diff --git a/src/check_expr.c b/src/check_expr.c index 0ee819913..ec13d26b0 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -1217,6 +1217,29 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) { return new_type; } +bool abi_compat_return_by_value(gbAllocator a, ProcCallingConvention cc, Type *abi_return_type) { + if (abi_return_type == NULL) { + return false; + } + if (cc == ProcCC_Odin) { + return false; + } + + if (str_eq(build_context.ODIN_OS, str_lit("windows"))) { + i64 size = 8*type_size_of(a, abi_return_type); + switch (size) { + case 0: + case 8: + case 16: + case 32: + case 64: + return false; + default: + return true; + } + } + return false; +} void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { ast_node(pt, ProcType, proc_type_node); @@ -1248,6 +1271,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { // NOTE(bill): The types are the same type->Proc.abi_compat_result_type = type_to_abi_compat_result_type(c->allocator, type->Proc.results); + type->Proc.return_by_pointer = abi_compat_return_by_value(c->allocator, pt->calling_convention, type->Proc.abi_compat_result_type); } diff --git a/src/entity.c b/src/entity.c index 60d3d4cd8..ddc170597 100644 --- a/src/entity.c +++ b/src/entity.c @@ -43,6 +43,7 @@ typedef enum EntityFlag { EntityFlag_NoAlias = 1<<7, EntityFlag_TypeField = 1<<8, EntityFlag_Value = 1<<9, + EntityFlag_Sret = 1<<10, } EntityFlag; // Zero value means the overloading process is not yet done @@ -121,6 +121,7 @@ struct irProcedure { AstNode * body; u64 tags; + irValue * return_ptr; irValueArray params; Array(irDefer) defer_stmts; Array(irBlock *) blocks; @@ -219,6 +220,7 @@ struct irProcedure { IR_INSTR_KIND(Call, struct { \ Type * type; /* return type */ \ irValue * value; \ + irValue * return_ptr; \ irValue **args; \ isize arg_count; \ }) \ @@ -984,9 +986,10 @@ irValue *ir_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) return v; } -irValue *ir_instr_call(irProcedure *p, irValue *value, irValue **args, isize arg_count, Type *result_type) { +irValue *ir_instr_call(irProcedure *p, irValue *value, irValue *return_ptr, irValue **args, isize arg_count, Type *result_type) { irValue *v = ir_alloc_instr(p, irInstr_Call); v->Instr.Call.value = value; + v->Instr.Call.return_ptr = return_ptr; v->Instr.Call.args = args; v->Instr.Call.arg_count = arg_count; v->Instr.Call.type = result_type; @@ -1491,8 +1494,14 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_ Type *abi_rt = pt->Proc.abi_compat_result_type; Type *rt = reduce_tuple_to_single_type(results); + if (pt->Proc.return_by_pointer) { + irValue *return_ptr = ir_add_local_generated(p, rt); + GB_ASSERT(is_type_pointer(ir_type(return_ptr))); + ir_emit(p, ir_instr_call(p, value, return_ptr, args, arg_count, NULL)); + return ir_emit_load(p, return_ptr); + } - irValue *result = ir_emit(p, ir_instr_call(p, value, args, arg_count, abi_rt)); + irValue *result = ir_emit(p, ir_instr_call(p, value, NULL, args, arg_count, abi_rt)); if (abi_rt != results) { result = ir_emit_transmute(p, result, rt); } @@ -1555,12 +1564,17 @@ 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); - } + if (proc->type->Proc.return_by_pointer) { + ir_emit_store(proc, proc->return_ptr, v); + ir_emit(proc, ir_instr_return(proc, NULL)); + } else { + 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)); + } } void ir_emit_jump(irProcedure *proc, irBlock *target_block) { @@ -6718,6 +6732,20 @@ void ir_begin_procedure_body(irProcedure *proc) { proc->entry_block = ir_new_block(proc, proc->type_expr, "entry"); ir_start_block(proc, proc->entry_block); + if (proc->type->Proc.return_by_pointer) { + // NOTE(bill): this must be the first parameter stored + gbAllocator a = proc->module->allocator; + Type *ptr_type = make_type_pointer(a, reduce_tuple_to_single_type(proc->type->Proc.results)); + Entity *e = make_entity_param(a, NULL, make_token_ident(str_lit("agg.result")), ptr_type, false, false); + e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + + irValue *param = ir_value_param(a, proc, e, ptr_type); + param->Param.kind = irParamPass_Pointer; + + ir_module_add_value(proc->module, e, param); + proc->return_ptr = param; + } + if (proc->type->Proc.params != NULL) { ast_node(pt, ProcType, proc->type_expr); isize param_index = 0; @@ -6744,6 +6772,8 @@ void ir_begin_procedure_body(irProcedure *proc) { } } } + + } diff --git a/src/ir_print.c b/src/ir_print.c index 20eb8449d..f016bd887 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -142,7 +142,7 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) { GB_ASSERT(is_type_proc(t)); t = base_type(t); isize result_count = t->Proc.result_count; - if (result_count == 0) { + if (result_count == 0 || t->Proc.return_by_pointer) { ir_fprintf(f, "void"); } else { Type *rt = t->Proc.abi_compat_result_type; @@ -322,6 +322,13 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { isize result_count = t->Proc.result_count; ir_print_proc_results(f, m, t); ir_fprintf(f, " ("); + if (t->Proc.return_by_pointer) { + ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results)); + ir_fprintf(f, "* sret noalias "); + if (param_count > 0) { + ir_fprintf(f, ", "); + } + } for (isize i = 0; i < param_count; i++) { if (i > 0) { ir_fprintf(f, ", "); @@ -1248,7 +1255,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { } ir_fprintf(f, "call "); ir_print_calling_convention(f, m, proc_type->Proc.calling_convention); - if (result_type) { + if (result_type && !proc_type->Proc.return_by_pointer) { ir_print_proc_results(f, m, proc_type); } else { ir_fprintf(f, "void"); @@ -1258,6 +1265,16 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_fprintf(f, "("); + if (proc_type->Proc.return_by_pointer) { + GB_ASSERT(call->return_ptr != NULL); + ir_print_type(f, m, proc_type->Proc.results); + ir_fprintf(f, "* "); + ir_print_value(f, m, call->return_ptr, ir_type(call->return_ptr)); + if (call->arg_count > 0) { + ir_fprintf(f, ", "); + } + } + if (call->arg_count > 0) { Type *proc_type = base_type(ir_type(call->value)); GB_ASSERT(proc_type->kind == Type_Proc); @@ -1493,6 +1510,15 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { ir_fprintf(f, "("); + if (proc_type->return_by_pointer) { + ir_print_type(f, m, reduce_tuple_to_single_type(proc_type->results)); + ir_fprintf(f, "* sret noalias "); + ir_fprintf(f, "%%agg.result"); + if (param_count > 0) { + ir_fprintf(f, ", "); + } + } + if (param_count > 0) { TypeTuple *params = &proc_type->params->Tuple; for (isize i = 0; i < params->variable_count; i++) { diff --git a/src/types.c b/src/types.c index 34b56583a..e1cde37c2 100644 --- a/src/types.c +++ b/src/types.c @@ -137,6 +137,7 @@ typedef struct TypeRecord { Type * results; /* Type_Tuple */ \ i32 param_count; \ i32 result_count; \ + bool return_by_pointer; \ Type **abi_compat_params; \ Type * abi_compat_result_type; \ bool variadic; \ |