authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-24 02:59:51-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-24 02:59:51-04:00
loge220812f2f0fe2becd570308971f98e0290835db
treed80b9a51b13322603dfe31eedbf7b357c627eed4
parent19ee4957502c704312646f75544e968b618aa807
signature Commit is signed but in an unrecognized format.

implement local variables in async functions


3 files changed, 97 insertions(+), 20 deletions(-)

src/analyze.cpp+22-1
......@@ -1911,11 +1911,32 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
19111911 } else {
19121912 param_name = buf_sprintf("arg%" ZIG_PRI_usize "", arg_i);
19131913 }
1914 ZigType *param_type = param_info[arg_i].type;
1914 ZigType *param_type = param_info->type;
19151915 field_names.append(buf_ptr(param_name));
19161916 field_types.append(param_type);
19171917 }
19181918
1919 for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
1920 IrInstructionAllocaGen *instruction = fn->alloca_gen_list.at(alloca_i);
1921 ZigType *ptr_type = instruction->base.value.type;
1922 assert(ptr_type->id == ZigTypeIdPointer);
1923 ZigType *child_type = ptr_type->data.pointer.child_type;
1924 if (!type_has_bits(child_type))
1925 continue;
1926 if (instruction->base.ref_count == 0)
1927 continue;
1928 if (instruction->base.value.special != ConstValSpecialRuntime) {
1929 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
1930 ConstValSpecialRuntime)
1931 {
1932 continue;
1933 }
1934 }
1935 field_names.append(instruction->name_hint);
1936 field_types.append(child_type);
1937 }
1938
1939
19191940 assert(field_names.length == field_types.length);
19201941 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
19211942 field_names.items, field_types.items, field_names.length);
src/codegen.cpp+45-19
......@@ -6174,6 +6174,7 @@ static void do_code_gen(CodeGen *g) {
61746174 clear_debug_source_node(g);
61756175
61766176 bool is_async = fn_is_async(fn_table_entry);
6177 size_t async_var_index = coro_arg_start + (type_has_bits(fn_type_id->return_type) ? 1 : 0);
61776178
61786179 if (want_sret || is_async) {
61796180 g->cur_ret_ptr = LLVMGetParam(fn, 0);
......@@ -6206,25 +6207,27 @@ static void do_code_gen(CodeGen *g) {
62066207 g->cur_err_ret_trace_val_stack = nullptr;
62076208 }
62086209
6209 // allocate temporary stack data
6210 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6211 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6212 ZigType *ptr_type = instruction->base.value.type;
6213 assert(ptr_type->id == ZigTypeIdPointer);
6214 ZigType *child_type = ptr_type->data.pointer.child_type;
6215 if (!type_has_bits(child_type))
6216 continue;
6217 if (instruction->base.ref_count == 0)
6218 continue;
6219 if (instruction->base.value.special != ConstValSpecialRuntime) {
6220 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
6221 ConstValSpecialRuntime)
6222 {
6210 if (!is_async) {
6211 // allocate temporary stack data
6212 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6213 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6214 ZigType *ptr_type = instruction->base.value.type;
6215 assert(ptr_type->id == ZigTypeIdPointer);
6216 ZigType *child_type = ptr_type->data.pointer.child_type;
6217 if (!type_has_bits(child_type))
62236218 continue;
6219 if (instruction->base.ref_count == 0)
6220 continue;
6221 if (instruction->base.value.special != ConstValSpecialRuntime) {
6222 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
6223 ConstValSpecialRuntime)
6224 {
6225 continue;
6226 }
62246227 }
6228 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6229 get_ptr_align(g, ptr_type));
62256230 }
6226 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6227 get_ptr_align(g, ptr_type));
62286231 }
62296232
62306233 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
......@@ -6263,9 +6266,9 @@ static void do_code_gen(CodeGen *g) {
62636266 fn_walk_var.data.vars.var = var;
62646267 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
62656268 } else if (is_async) {
6266 size_t ret_1_or_0 = type_has_bits(fn_type_id->return_type) ? 1 : 0;
6267 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr,
6268 coro_arg_start + ret_1_or_0 + var_i, "");
6269 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, async_var_index,
6270 buf_ptr(&var->name));
6271 async_var_index += 1;
62696272 if (var->decl_node) {
62706273 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
62716274 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
......@@ -6299,6 +6302,29 @@ static void do_code_gen(CodeGen *g) {
62996302 }
63006303 }
63016304
6305 if (is_async) {
6306 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6307 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6308 ZigType *ptr_type = instruction->base.value.type;
6309 assert(ptr_type->id == ZigTypeIdPointer);
6310 ZigType *child_type = ptr_type->data.pointer.child_type;
6311 if (!type_has_bits(child_type))
6312 continue;
6313 if (instruction->base.ref_count == 0)
6314 continue;
6315 if (instruction->base.value.special != ConstValSpecialRuntime) {
6316 if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
6317 ConstValSpecialRuntime)
6318 {
6319 continue;
6320 }
6321 }
6322 instruction->base.llvm_value = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, async_var_index,
6323 instruction->name_hint);
6324 async_var_index += 1;
6325 }
6326 }
6327
63026328 // finishing error return trace setup. we have to do this after all the allocas.
63036329 if (have_err_ret_trace_stack) {
63046330 ZigType *usize = g->builtin_types.entry_usize;
test/stage1/behavior/coroutines.zig+30
......@@ -47,6 +47,36 @@ test "suspend at end of function" {
4747 };
4848 S.doTheTest();
4949}
50
51test "local variable in async function" {
52 const S = struct {
53 var x: i32 = 0;
54
55 fn doTheTest() void {
56 expect(x == 0);
57 const p = async add(1, 2);
58 expect(x == 0);
59 resume p;
60 expect(x == 0);
61 resume p;
62 expect(x == 0);
63 resume p;
64 expect(x == 3);
65 }
66
67 fn add(a: i32, b: i32) void {
68 var accum: i32 = 0;
69 suspend;
70 accum += a;
71 suspend;
72 accum += b;
73 suspend;
74 x = accum;
75 }
76 };
77 S.doTheTest();
78}
79
5080//test "coroutine suspend, resume" {
5181// seq('a');
5282// const p = try async<allocator> testAsyncSeq();