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) {...@@ -1911,11 +1911,32 @@ static Error resolve_coro_frame(CodeGen *g, ZigType *frame_type) {
1911 } else {1911 } else {
1912 param_name = buf_sprintf("arg%" ZIG_PRI_usize "", arg_i);1912 param_name = buf_sprintf("arg%" ZIG_PRI_usize "", arg_i);
1913 }1913 }
1914 ZigType *param_type = param_info[arg_i].type;1914 ZigType *param_type = param_info->type;
1915 field_names.append(buf_ptr(param_name));1915 field_names.append(buf_ptr(param_name));
1916 field_types.append(param_type);1916 field_types.append(param_type);
1917 }1917 }
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
1919 assert(field_names.length == field_types.length);1940 assert(field_names.length == field_types.length);
1920 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),1941 frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name),
1921 field_names.items, field_types.items, field_names.length);1942 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) {...@@ -6174,6 +6174,7 @@ static void do_code_gen(CodeGen *g) {
6174 clear_debug_source_node(g);6174 clear_debug_source_node(g);
61756175
6176 bool is_async = fn_is_async(fn_table_entry);6176 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
6178 if (want_sret || is_async) {6179 if (want_sret || is_async) {
6179 g->cur_ret_ptr = LLVMGetParam(fn, 0);6180 g->cur_ret_ptr = LLVMGetParam(fn, 0);
...@@ -6206,25 +6207,27 @@ static void do_code_gen(CodeGen *g) {...@@ -6206,25 +6207,27 @@ static void do_code_gen(CodeGen *g) {
6206 g->cur_err_ret_trace_val_stack = nullptr;6207 g->cur_err_ret_trace_val_stack = nullptr;
6207 }6208 }
62086209
6209 // allocate temporary stack data6210 if (!is_async) {
6210 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {6211 // allocate temporary stack data
6211 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);6212 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
6212 ZigType *ptr_type = instruction->base.value.type;6213 IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i);
6213 assert(ptr_type->id == ZigTypeIdPointer);6214 ZigType *ptr_type = instruction->base.value.type;
6214 ZigType *child_type = ptr_type->data.pointer.child_type;6215 assert(ptr_type->id == ZigTypeIdPointer);
6215 if (!type_has_bits(child_type))6216 ZigType *child_type = ptr_type->data.pointer.child_type;
6216 continue;6217 if (!type_has_bits(child_type))
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 {
6223 continue;6218 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 }
6224 }6227 }
6228 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6229 get_ptr_align(g, ptr_type));
6225 }6230 }
6226 instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
6227 get_ptr_align(g, ptr_type));
6228 }6231 }
62296232
6230 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);6233 ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base);
...@@ -6263,9 +6266,9 @@ static void do_code_gen(CodeGen *g) {...@@ -6263,9 +6266,9 @@ static void do_code_gen(CodeGen *g) {
6263 fn_walk_var.data.vars.var = var;6266 fn_walk_var.data.vars.var = var;
6264 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);6267 iter_function_params_c_abi(g, fn_table_entry->type_entry, &fn_walk_var, var->src_arg_index);
6265 } else if (is_async) {6268 } else if (is_async) {
6266 size_t ret_1_or_0 = type_has_bits(fn_type_id->return_type) ? 1 : 0;6269 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, async_var_index,
6267 var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr,6270 buf_ptr(&var->name));
6268 coro_arg_start + ret_1_or_0 + var_i, "");6271 async_var_index += 1;
6269 if (var->decl_node) {6272 if (var->decl_node) {
6270 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),6273 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
6271 buf_ptr(&var->name), import->data.structure.root_struct->di_file,6274 buf_ptr(&var->name), import->data.structure.root_struct->di_file,
...@@ -6299,6 +6302,29 @@ static void do_code_gen(CodeGen *g) {...@@ -6299,6 +6302,29 @@ static void do_code_gen(CodeGen *g) {
6299 }6302 }
6300 }6303 }
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
6302 // finishing error return trace setup. we have to do this after all the allocas.6328 // finishing error return trace setup. we have to do this after all the allocas.
6303 if (have_err_ret_trace_stack) {6329 if (have_err_ret_trace_stack) {
6304 ZigType *usize = g->builtin_types.entry_usize;6330 ZigType *usize = g->builtin_types.entry_usize;
test/stage1/behavior/coroutines.zig+30
...@@ -47,6 +47,36 @@ test "suspend at end of function" {...@@ -47,6 +47,36 @@ test "suspend at end of function" {
47 };47 };
48 S.doTheTest();48 S.doTheTest();
49}49}
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
50//test "coroutine suspend, resume" {80//test "coroutine suspend, resume" {
51// seq('a');81// seq('a');
52// const p = try async<allocator> testAsyncSeq();82// const p = try async<allocator> testAsyncSeq();