authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-21 23:27:47-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-21 23:27:47-04:00
log59bf9ca58c992e02423fae2ba8773eac098189b9
tree742f097934f954997e70bfd13b3911013a80f141
parent11bd50f2b2a74ce25d841a15ba67d042d41b71c2
signature Commit is signed but in an unrecognized format.

implement async function parameters


4 files changed, 90 insertions(+), 56 deletions(-)

src/all_types.hpp+1
...@@ -3638,6 +3638,7 @@ static const size_t err_union_err_index = 0;...@@ -3638,6 +3638,7 @@ static const size_t err_union_err_index = 0;
3638static const size_t err_union_payload_index = 1;3638static const size_t err_union_payload_index = 1;
36393639
3640static const size_t coro_resume_index_index = 0;3640static const size_t coro_resume_index_index = 0;
3641static const size_t coro_arg_start = 1;
36413642
3642// TODO call graph analysis to find out what this number needs to be for every function3643// TODO call graph analysis to find out what this number needs to be for every function
3643// MUST BE A POWER OF TWO.3644// MUST BE A POWER OF TWO.
src/analyze.cpp+48-23
...@@ -1891,6 +1891,21 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {...@@ -1891,6 +1891,21 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
1891 field_names.append("resume_index");1891 field_names.append("resume_index");
1892 field_types.append(g->builtin_types.entry_usize);1892 field_types.append(g->builtin_types.entry_usize);
18931893
1894 for (size_t arg_i = 0; arg_i < fn->type_entry->data.fn.fn_type_id.param_count; arg_i += 1) {
1895 FnTypeParamInfo *param_info = &fn->type_entry->data.fn.fn_type_id.param_info[arg_i];
1896 AstNode *param_decl_node = get_param_decl_node(fn, arg_i);
1897 Buf *param_name;
1898 bool is_var_args = param_decl_node && param_decl_node->data.param_decl.is_var_args;
1899 if (param_decl_node && !is_var_args) {
1900 param_name = param_decl_node->data.param_decl.name;
1901 } else {
1902 param_name = buf_sprintf("arg%" ZIG_PRI_usize "", arg_i);
1903 }
1904 ZigType *param_type = param_info[arg_i].type;
1905 field_names.append(buf_ptr(param_name));
1906 field_types.append(param_type);
1907 }
1908
1894 assert(field_names.length == field_types.length);1909 assert(field_names.length == field_types.length);
1895 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),1910 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
1896 field_names.items, field_types.items, field_names.length);1911 field_names.items, field_types.items, field_names.length);
...@@ -7058,19 +7073,22 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {...@@ -7058,19 +7073,22 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {
7058 // +1 for maybe first argument the error return trace7073 // +1 for maybe first argument the error return trace
7059 // +2 for maybe arguments async allocator and error code pointer7074 // +2 for maybe arguments async allocator and error code pointer
7060 ZigList<ZigLLVMDIType *> param_di_types = {};7075 ZigList<ZigLLVMDIType *> param_di_types = {};
7061 param_di_types.append(get_llvm_di_type(g, fn_type_id->return_type));
7062 ZigType *gen_return_type;7076 ZigType *gen_return_type;
7063 if (is_async) {7077 if (is_async) {
7064 gen_return_type = g->builtin_types.entry_usize;7078 gen_return_type = g->builtin_types.entry_usize;
7079 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7065 } else if (!type_has_bits(fn_type_id->return_type)) {7080 } else if (!type_has_bits(fn_type_id->return_type)) {
7066 gen_return_type = g->builtin_types.entry_void;7081 gen_return_type = g->builtin_types.entry_void;
7082 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7067 } else if (first_arg_return) {7083 } else if (first_arg_return) {
7084 gen_return_type = g->builtin_types.entry_void;
7085 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7068 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);7086 ZigType *gen_type = get_pointer_to_type(g, fn_type_id->return_type, false);
7069 gen_param_types.append(get_llvm_type(g, gen_type));7087 gen_param_types.append(get_llvm_type(g, gen_type));
7070 param_di_types.append(get_llvm_di_type(g, gen_type));7088 param_di_types.append(get_llvm_di_type(g, gen_type));
7071 gen_return_type = g->builtin_types.entry_void;
7072 } else {7089 } else {
7073 gen_return_type = fn_type_id->return_type;7090 gen_return_type = fn_type_id->return_type;
7091 param_di_types.append(get_llvm_di_type(g, gen_return_type));
7074 }7092 }
7075 fn_type->data.fn.gen_return_type = gen_return_type;7093 fn_type->data.fn.gen_return_type = gen_return_type;
70767094
...@@ -7080,36 +7098,43 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {...@@ -7080,36 +7098,43 @@ void resolve_llvm_types_fn(CodeGen *g, ZigType *fn_type, ZigFn *fn) {
7080 param_di_types.append(get_llvm_di_type(g, gen_type));7098 param_di_types.append(get_llvm_di_type(g, gen_type));
7081 }7099 }
7082 if (is_async) {7100 if (is_async) {
7101 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(1);
7102
7083 ZigType *frame_type = (fn == nullptr) ? g->builtin_types.entry_frame_header : get_coro_frame_type(g, fn);7103 ZigType *frame_type = (fn == nullptr) ? g->builtin_types.entry_frame_header : get_coro_frame_type(g, fn);
7084 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);7104 ZigType *ptr_type = get_pointer_to_type(g, frame_type, false);
7085 gen_param_types.append(get_llvm_type(g, ptr_type));7105 gen_param_types.append(get_llvm_type(g, ptr_type));
7086 param_di_types.append(get_llvm_di_type(g, ptr_type));7106 param_di_types.append(get_llvm_di_type(g, ptr_type));
7087 }
70887107
7089 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);7108 fn_type->data.fn.gen_param_info[0].src_index = 0;
7090 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {7109 fn_type->data.fn.gen_param_info[0].gen_index = 0;
7091 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];7110 fn_type->data.fn.gen_param_info[0].type = ptr_type;
7092 ZigType *type_entry = src_param_info->type;
7093 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
70947111
7095 gen_param_info->src_index = i;7112 } else {
7096 gen_param_info->gen_index = SIZE_MAX;7113 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
7114 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {
7115 FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
7116 ZigType *type_entry = src_param_info->type;
7117 FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
70977118
7098 if (is_c_abi || !type_has_bits(type_entry))7119 gen_param_info->src_index = i;
7099 continue;7120 gen_param_info->gen_index = SIZE_MAX;
71007121
7101 ZigType *gen_type;7122 if (is_c_abi || !type_has_bits(type_entry))
7102 if (handle_is_ptr(type_entry)) {7123 continue;
7103 gen_type = get_pointer_to_type(g, type_entry, true);
7104 gen_param_info->is_byval = true;
7105 } else {
7106 gen_type = type_entry;
7107 }
7108 gen_param_info->gen_index = gen_param_types.length;
7109 gen_param_info->type = gen_type;
7110 gen_param_types.append(get_llvm_type(g, gen_type));
71117124
7112 param_di_types.append(get_llvm_di_type(g, gen_type));7125 ZigType *gen_type;
7126 if (handle_is_ptr(type_entry)) {
7127 gen_type = get_pointer_to_type(g, type_entry, true);
7128 gen_param_info->is_byval = true;
7129 } else {
7130 gen_type = type_entry;
7131 }
7132 gen_param_info->gen_index = gen_param_types.length;
7133 gen_param_info->type = gen_type;
7134 gen_param_types.append(get_llvm_type(g, gen_type));
7135
7136 param_di_types.append(get_llvm_di_type(g, gen_type));
7137 }
7113 }7138 }
71147139
7115 if (is_c_abi) {7140 if (is_c_abi) {
src/codegen.cpp+22-15
...@@ -1965,10 +1965,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_...@@ -1965,10 +1965,12 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
1965 }1965 }
1966 case FnWalkIdInits: {1966 case FnWalkIdInits: {
1967 clear_debug_source_node(g);1967 clear_debug_source_node(g);
1968 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);1968 if (fn_walk->data.inits.fn->resume_blocks.length == 0) {
1969 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);1969 LLVMValueRef arg = LLVMGetParam(llvm_fn, fn_walk->data.inits.gen_i);
1970 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");1970 LLVMTypeRef ptr_to_int_type_ref = LLVMPointerType(LLVMIntType((unsigned)ty_size * 8), 0);
1971 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);1971 LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, var->value_ref, ptr_to_int_type_ref, "");
1972 gen_store_untyped(g, arg, bitcasted, var->align_bytes, false);
1973 }
1972 if (var->decl_node) {1974 if (var->decl_node) {
1973 gen_var_debug_decl(g, var);1975 gen_var_debug_decl(g, var);
1974 }1976 }
...@@ -2061,7 +2063,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {...@@ -2061,7 +2063,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
2061 assert(variable);2063 assert(variable);
2062 assert(variable->value_ref);2064 assert(variable->value_ref);
20632065
2064 if (!handle_is_ptr(variable->var_type)) {2066 if (!handle_is_ptr(variable->var_type) && fn_walk->data.inits.fn->resume_blocks.length == 0) {
2065 clear_debug_source_node(g);2067 clear_debug_source_node(g);
2066 ZigType *fn_type = fn_table_entry->type_entry;2068 ZigType *fn_type = fn_table_entry->type_entry;
2067 unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index;2069 unsigned gen_arg_index = fn_type->data.fn.gen_param_info[variable->src_arg_index].gen_index;
...@@ -3471,8 +3473,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3471,8 +3473,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3471 if (prefix_arg_err_ret_stack) {3473 if (prefix_arg_err_ret_stack) {
3472 zig_panic("TODO");3474 zig_panic("TODO");
3473 }3475 }
3474
3475 gen_param_values.append(result_loc);
3476 } else {3476 } else {
3477 if (first_arg_ret) {3477 if (first_arg_ret) {
3478 gen_param_values.append(result_loc);3478 gen_param_values.append(result_loc);
...@@ -3504,6 +3504,15 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3504,6 +3504,15 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3504 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);3504 LLVMCallConv llvm_cc = get_llvm_cc(g, cc);
3505 LLVMValueRef result;3505 LLVMValueRef result;
35063506
3507 if (instruction->is_async) {
3508 for (size_t arg_i = 0; arg_i < gen_param_values.length; arg_i += 1) {
3509 LLVMValueRef arg_ptr = LLVMBuildStructGEP(g->builder, result_loc, coro_arg_start + arg_i, "");
3510 LLVMBuildStore(g->builder, gen_param_values.at(arg_i), arg_ptr);
3511 }
3512 ZigLLVMBuildCall(g->builder, fn_val, &result_loc, 1, llvm_cc, fn_inline, "");
3513 return nullptr;
3514 }
3515
3507 if (instruction->new_stack == nullptr) {3516 if (instruction->new_stack == nullptr) {
3508 result = ZigLLVMBuildCall(g->builder, fn_val,3517 result = ZigLLVMBuildCall(g->builder, fn_val,
3509 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");3518 gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, "");
...@@ -3519,11 +3528,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr...@@ -3519,11 +3528,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
3519 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");3528 LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, "");
3520 }3529 }
35213530
3522
3523 if (instruction->is_async) {
3524 return nullptr;
3525 }
3526
3527 if (src_return_type->id == ZigTypeIdUnreachable) {3531 if (src_return_type->id == ZigTypeIdUnreachable) {
3528 return LLVMBuildUnreachable(g->builder);3532 return LLVMBuildUnreachable(g->builder);
3529 } else if (!ret_has_bits) {3533 } else if (!ret_has_bits) {
...@@ -6285,7 +6289,9 @@ static void do_code_gen(CodeGen *g) {...@@ -6285,7 +6289,9 @@ static void do_code_gen(CodeGen *g) {
6285 build_all_basic_blocks(g, fn_table_entry);6289 build_all_basic_blocks(g, fn_table_entry);
6286 clear_debug_source_node(g);6290 clear_debug_source_node(g);
62876291
6288 if (want_sret || fn_table_entry->resume_blocks.length != 0) {6292 bool is_async = cc == CallingConventionAsync || fn_table_entry->resume_blocks.length != 0;
6293
6294 if (want_sret || is_async) {
6289 g->cur_ret_ptr = LLVMGetParam(fn, 0);6295 g->cur_ret_ptr = LLVMGetParam(fn, 0);
6290 } else if (handle_is_ptr(fn_type_id->return_type)) {6296 } else if (handle_is_ptr(fn_type_id->return_type)) {
6291 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);6297 g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0);
...@@ -6303,7 +6309,6 @@ static void do_code_gen(CodeGen *g) {...@@ -6303,7 +6309,6 @@ static void do_code_gen(CodeGen *g) {
6303 }6309 }
63046310
6305 // error return tracing setup6311 // error return tracing setup
6306 bool is_async = cc == CallingConventionAsync;
6307 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;6312 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;
6308 LLVMValueRef err_ret_array_val = nullptr;6313 LLVMValueRef err_ret_array_val = nullptr;
6309 if (have_err_ret_trace_stack) {6314 if (have_err_ret_trace_stack) {
...@@ -6378,7 +6383,9 @@ static void do_code_gen(CodeGen *g) {...@@ -6378,7 +6383,9 @@ static void do_code_gen(CodeGen *g) {
6378 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];6383 FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
6379 assert(gen_info->gen_index != SIZE_MAX);6384 assert(gen_info->gen_index != SIZE_MAX);
63806385
6381 if (handle_is_ptr(var->var_type)) {6386 if (is_async) {
6387 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_arg_start + var_i, "");
6388 } else if (handle_is_ptr(var->var_type)) {
6382 if (gen_info->is_byval) {6389 if (gen_info->is_byval) {
6383 gen_type = var->var_type;6390 gen_type = var->var_type;
6384 } else {6391 } else {
test/stage1/behavior/coroutines.zig+19-18
...@@ -2,33 +2,34 @@ const std = @import("std");...@@ -2,33 +2,34 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5var x: i32 = 1;5var global_x: i32 = 1;
66
7test "simple coroutine suspend and resume" {7test "simple coroutine suspend and resume" {
8 const p = async simpleAsyncFn();8 const p = async simpleAsyncFn();
9 expect(x == 2);9 expect(global_x == 2);
10 resume p;10 resume p;
11 expect(x == 3);11 expect(global_x == 3);
12}12}
13fn simpleAsyncFn() void {13fn simpleAsyncFn() void {
14 x += 1;14 global_x += 1;
15 suspend;15 suspend;
16 x += 1;16 global_x += 1;
17}17}
1818
19//test "create a coroutine and cancel it" {19var global_y: i32 = 1;
20// const p = try async<allocator> simpleAsyncFn();20
21// comptime expect(@typeOf(p) == promise->void);21test "pass parameter to coroutine" {
22// cancel p;22 const p = async simpleAsyncFnWithArg(2);
23// expect(x == 2);23 expect(global_y == 3);
24//}24 resume p;
25//async fn simpleAsyncFn() void {25 expect(global_y == 5);
26// x += 1;26}
27// suspend;27fn simpleAsyncFnWithArg(delta: i32) void {
28// x += 1;28 global_y += delta;
29//}29 suspend;
30//30 global_y += delta;
31//test "coroutine suspend, resume, cancel" {31}
32//test "coroutine suspend, resume" {
32// seq('a');33// seq('a');
33// const p = try async<allocator> testAsyncSeq();34// const p = try async<allocator> testAsyncSeq();
34// seq('c');35// seq('c');