authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-10 01:12:22-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-10 01:38:40-05:00
log84e952c230ddb9c2bd232958010d2045384532eb
tree23e153f531fd723e19314320fb87424301d92f21
parent3b3649b86f74d08013b669a6a4eac573f8d7fa23

fix await multithreaded data race

coro return was reading from a value that coro await was writing to. that wasn't how it was designed to work, it was an implementation mistake. this commit also has some work-in-progress code for fixing error return traces across suspend points.

6 files changed, 110 insertions(+), 21 deletions(-)

src/all_types.hpp+9-1
...@@ -61,6 +61,7 @@ struct IrExecutable {...@@ -61,6 +61,7 @@ struct IrExecutable {
61 IrInstruction *coro_handle;61 IrInstruction *coro_handle;
62 IrInstruction *coro_awaiter_field_ptr; // this one is shared and in the promise62 IrInstruction *coro_awaiter_field_ptr; // this one is shared and in the promise
63 IrInstruction *coro_result_ptr_field_ptr;63 IrInstruction *coro_result_ptr_field_ptr;
64 IrInstruction *coro_result_field_ptr;
64 IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise65 IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise
65 IrBasicBlock *coro_early_final;66 IrBasicBlock *coro_early_final;
66 IrBasicBlock *coro_normal_final;67 IrBasicBlock *coro_normal_final;
...@@ -1281,7 +1282,7 @@ struct FnTableEntry {...@@ -1281,7 +1282,7 @@ struct FnTableEntry {
1281 bool is_cold;1282 bool is_cold;
12821283
1283 ZigList<FnExport> export_list;1284 ZigList<FnExport> export_list;
1284 bool calls_errorable_function;1285 bool calls_or_awaits_errorable_fn;
1285};1286};
12861287
1287uint32_t fn_table_entry_hash(FnTableEntry*);1288uint32_t fn_table_entry_hash(FnTableEntry*);
...@@ -2038,6 +2039,7 @@ enum IrInstructionId {...@@ -2038,6 +2039,7 @@ enum IrInstructionId {
2038 IrInstructionIdCoroAllocHelper,2039 IrInstructionIdCoroAllocHelper,
2039 IrInstructionIdAtomicRmw,2040 IrInstructionIdAtomicRmw,
2040 IrInstructionIdPromiseResultType,2041 IrInstructionIdPromiseResultType,
2042 IrInstructionIdAwaitBookkeeping,
2041};2043};
20422044
2043struct IrInstruction {2045struct IrInstruction {
...@@ -2985,6 +2987,12 @@ struct IrInstructionPromiseResultType {...@@ -2985,6 +2987,12 @@ struct IrInstructionPromiseResultType {
2985 IrInstruction *promise_type;2987 IrInstruction *promise_type;
2986};2988};
29872989
2990struct IrInstructionAwaitBookkeeping {
2991 IrInstruction base;
2992
2993 IrInstruction *promise_result_type;
2994};
2995
2988static const size_t slice_ptr_index = 0;2996static const size_t slice_ptr_index = 0;
2989static const size_t slice_len_index = 1;2997static const size_t slice_len_index = 1;
29902998
src/analyze.cpp+5-3
...@@ -5856,9 +5856,11 @@ uint32_t get_coro_frame_align_bytes(CodeGen *g) {...@@ -5856,9 +5856,11 @@ uint32_t get_coro_frame_align_bytes(CodeGen *g) {
5856 return g->pointer_size_bytes * 2;5856 return g->pointer_size_bytes * 2;
5857}5857}
58585858
5859bool type_can_fail(TypeTableEntry *type_entry) {
5860 return type_entry->id == TypeTableEntryIdErrorUnion || type_entry->id == TypeTableEntryIdErrorSet;
5861}
5862
5859bool fn_type_can_fail(FnTypeId *fn_type_id) {5863bool fn_type_can_fail(FnTypeId *fn_type_id) {
5860 TypeTableEntry *return_type = fn_type_id->return_type;5864 return type_can_fail(fn_type_id->return_type) || fn_type_id->cc == CallingConventionAsync;
5861 return return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdErrorSet ||
5862 fn_type_id->cc == CallingConventionAsync;
5863}5865}
58645866
src/analyze.hpp+1
...@@ -195,6 +195,7 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);...@@ -195,6 +195,7 @@ TypeTableEntry *get_auto_err_set_type(CodeGen *g, FnTableEntry *fn_entry);
195195
196uint32_t get_coro_frame_align_bytes(CodeGen *g);196uint32_t get_coro_frame_align_bytes(CodeGen *g);
197bool fn_type_can_fail(FnTypeId *fn_type_id);197bool fn_type_can_fail(FnTypeId *fn_type_id);
198bool type_can_fail(TypeTableEntry *type_entry);
198bool fn_eval_cacheable(Scope *scope);199bool fn_eval_cacheable(Scope *scope);
199200
200#endif201#endif
src/codegen.cpp+2-1
...@@ -4251,6 +4251,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4251,6 +4251,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4251 case IrInstructionIdExport:4251 case IrInstructionIdExport:
4252 case IrInstructionIdErrorUnion:4252 case IrInstructionIdErrorUnion:
4253 case IrInstructionIdPromiseResultType:4253 case IrInstructionIdPromiseResultType:
4254 case IrInstructionIdAwaitBookkeeping:
4254 zig_unreachable();4255 zig_unreachable();
42554256
4256 case IrInstructionIdReturn:4257 case IrInstructionIdReturn:
...@@ -5279,7 +5280,7 @@ static void do_code_gen(CodeGen *g) {...@@ -5279,7 +5280,7 @@ static void do_code_gen(CodeGen *g) {
5279 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);5280 uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
5280 if (err_ret_trace_arg_index != UINT32_MAX) {5281 if (err_ret_trace_arg_index != UINT32_MAX) {
5281 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);5282 g->cur_err_ret_trace_val = LLVMGetParam(fn, err_ret_trace_arg_index);
5282 } else if (g->have_err_ret_tracing && fn_table_entry->calls_errorable_function) {5283 } else if (g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn) {
5283 // TODO call graph analysis to find out what this number needs to be for every function5284 // TODO call graph analysis to find out what this number needs to be for every function
5284 static const size_t stack_trace_ptr_count = 30;5285 static const size_t stack_trace_ptr_count = 30;
52855286
src/ir.cpp+84-16
...@@ -707,6 +707,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultTyp...@@ -707,6 +707,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultTyp
707 return IrInstructionIdPromiseResultType;707 return IrInstructionIdPromiseResultType;
708}708}
709709
710static constexpr IrInstructionId ir_instruction_id(IrInstructionAwaitBookkeeping *) {
711 return IrInstructionIdAwaitBookkeeping;
712}
713
710template<typename T>714template<typename T>
711static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {715static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
712 T *special_instruction = allocate<T>(1);716 T *special_instruction = allocate<T>(1);
...@@ -2656,6 +2660,17 @@ static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope,...@@ -2656,6 +2660,17 @@ static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope,
2656 return &instruction->base;2660 return &instruction->base;
2657}2661}
26582662
2663static IrInstruction *ir_build_await_bookkeeping(IrBuilder *irb, Scope *scope, AstNode *source_node,
2664 IrInstruction *promise_result_type)
2665{
2666 IrInstructionAwaitBookkeeping *instruction = ir_build_instruction<IrInstructionAwaitBookkeeping>(irb, scope, source_node);
2667 instruction->promise_result_type = promise_result_type;
2668
2669 ir_ref_instruction(promise_result_type, irb->current_basic_block);
2670
2671 return &instruction->base;
2672}
2673
2659static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2674static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2660 results[ReturnKindUnconditional] = 0;2675 results[ReturnKindUnconditional] = 0;
2661 results[ReturnKindError] = 0;2676 results[ReturnKindError] = 0;
...@@ -2734,13 +2749,16 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2734,13 +2749,16 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2734 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);2749 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
2735 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;2750 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
2736 if (!is_async) {2751 if (!is_async) {
2752 //if (irb->codegen->have_err_ret_tracing) {
2753 // IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
2754 // ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
2755 //}
2737 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);2756 IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
2738 return_inst->is_gen = is_generated_code;2757 return_inst->is_gen = is_generated_code;
2739 return return_inst;2758 return return_inst;
2740 }2759 }
27412760
2742 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);2761 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
2743 ir_build_store_ptr(irb, scope, node, result_ptr, return_value);
2744 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,2762 IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
2745 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));2763 get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
2746 // TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig2764 // TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
...@@ -2756,6 +2774,22 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2756,6 +2774,22 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2756 // the above blocks are rendered by ir_gen after the rest of codegen2774 // the above blocks are rendered by ir_gen after the rest of codegen
2757}2775}
27582776
2777//static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node, bool is_async) {
2778// if (!irb->codegen->have_err_ret_tracing)
2779// return;
2780//
2781// if (is_async) {
2782// IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2783// IrInstruction *return_address_ptr = ir_build_return_address(irb, scope, node);
2784// IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2785// ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2786// return;
2787// }
2788//
2789// IrInstruction *stack_trace_ptr = ir_build_error_return_trace_nonnull(irb, scope, node);
2790// ir_build_save_err_ret_addr(irb, scope, node, stack_trace_ptr);
2791//}
2792
2759static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2793static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2760 assert(node->type == NodeTypeReturnExpr);2794 assert(node->type == NodeTypeReturnExpr);
27612795
...@@ -2791,9 +2825,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2791,9 +2825,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
27912825
2792 size_t defer_counts[2];2826 size_t defer_counts[2];
2793 ir_count_defers(irb, scope, outer_scope, defer_counts);2827 ir_count_defers(irb, scope, outer_scope, defer_counts);
2794 if (defer_counts[ReturnKindError] > 0) {2828 bool have_err_defers = defer_counts[ReturnKindError] > 0;
2829 if (have_err_defers || irb->codegen->have_err_ret_tracing) {
2795 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");2830 IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
2796 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");2831 IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
2832 if (!have_err_defers) {
2833 ir_gen_defers_for_block(irb, scope, outer_scope, false);
2834 }
27972835
2798 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);2836 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
27992837
...@@ -2808,11 +2846,16 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2808,11 +2846,16 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2808 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");2846 IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
28092847
2810 ir_set_cursor_at_end_and_append_block(irb, err_block);2848 ir_set_cursor_at_end_and_append_block(irb, err_block);
2811 ir_gen_defers_for_block(irb, scope, outer_scope, true);2849 if (have_err_defers) {
2850 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2851 }
2852 //ir_gen_save_err_ret_addr(irb, scope, node, is_async);
2812 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2853 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
28132854
2814 ir_set_cursor_at_end_and_append_block(irb, ok_block);2855 ir_set_cursor_at_end_and_append_block(irb, ok_block);
2815 ir_gen_defers_for_block(irb, scope, outer_scope, false);2856 if (have_err_defers) {
2857 ir_gen_defers_for_block(irb, scope, outer_scope, false);
2858 }
2816 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2859 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
28172860
2818 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);2861 ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
...@@ -2834,7 +2877,12 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2834,7 +2877,12 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28342877
2835 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");2878 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
2836 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");2879 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
2837 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb->exec, scope));2880 IrInstruction *is_comptime;
2881 if (ir_should_inline(irb->exec, scope)) {
2882 is_comptime = ir_build_const_bool(irb, scope, node, true);
2883 } else {
2884 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
2885 }
2838 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));2886 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
28392887
2840 ir_set_cursor_at_end_and_append_block(irb, return_block);2888 ir_set_cursor_at_end_and_append_block(irb, return_block);
...@@ -6002,6 +6050,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6002,6 +6050,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6002 IrInstruction *undefined_value = ir_build_const_undefined(irb, parent_scope, node);6050 IrInstruction *undefined_value = ir_build_const_undefined(irb, parent_scope, node);
6003 IrInstruction *target_promise_type = ir_build_typeof(irb, parent_scope, node, target_inst);6051 IrInstruction *target_promise_type = ir_build_typeof(irb, parent_scope, node, target_inst);
6004 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, parent_scope, node, target_promise_type);6052 IrInstruction *promise_result_type = ir_build_promise_result_type(irb, parent_scope, node, target_promise_type);
6053 ir_build_await_bookkeeping(irb, parent_scope, node, promise_result_type);
6005 ir_build_var_decl(irb, parent_scope, node, result_var, promise_result_type, nullptr, undefined_value);6054 ir_build_var_decl(irb, parent_scope, node, result_var, promise_result_type, nullptr, undefined_value);
6006 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, parent_scope, node, result_var, false, false);6055 IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, parent_scope, node, result_var, false, false);
6007 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);6056 ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr);
...@@ -6271,7 +6320,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6271,7 +6320,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6271 IrInstruction *coro_id;6320 IrInstruction *coro_id;
6272 IrInstruction *u8_ptr_type;6321 IrInstruction *u8_ptr_type;
6273 IrInstruction *const_bool_false;6322 IrInstruction *const_bool_false;
6274 IrInstruction *coro_result_field_ptr;
6275 TypeTableEntry *return_type;6323 TypeTableEntry *return_type;
6276 Buf *result_ptr_field_name;6324 Buf *result_ptr_field_name;
6277 VariableTableEntry *coro_size_var;6325 VariableTableEntry *coro_size_var;
...@@ -6325,10 +6373,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6325,10 +6373,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6325 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,6373 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6326 awaiter_handle_field_name);6374 awaiter_handle_field_name);
6327 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6375 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6328 coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);6376 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
6329 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6377 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6330 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);6378 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
6331 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, coro_result_field_ptr);6379 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
63326380
63336381
6334 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");6382 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
...@@ -6368,14 +6416,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6368,14 +6416,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6368 ir_build_unreachable(irb, scope, node);6416 ir_build_unreachable(irb, scope, node);
63696417
6370 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final);6418 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final);
6371 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
6372
6373 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
6374 if (type_has_bits(return_type)) {6419 if (type_has_bits(return_type)) {
6375 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);6420 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
6376 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, result_ptr);6421 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, result_ptr);
6377 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type,6422 IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type,
6378 coro_result_field_ptr);6423 irb->exec->coro_result_field_ptr);
6379 IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,6424 IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
6380 fn_entry->type_entry->data.fn.fn_type_id.return_type);6425 fn_entry->type_entry->data.fn.fn_type_id.return_type);
6381 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);6426 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
...@@ -6383,6 +6428,9 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6383,6 +6428,9 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6383 }6428 }
6384 ir_build_br(irb, scope, node, check_free_block, const_bool_false);6429 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
63856430
6431 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
6432 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
6433
6386 ir_set_cursor_at_end_and_append_block(irb, check_free_block);6434 ir_set_cursor_at_end_and_append_block(irb, check_free_block);
6387 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);6435 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
6388 IrInstruction **incoming_values = allocate<IrInstruction *>(2);6436 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
...@@ -11405,7 +11453,7 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,...@@ -11405,7 +11453,7 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
11405 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);11453 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
11406 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);11454 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11407 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);11455 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
11408 if (fn_entry == nullptr || !fn_entry->calls_errorable_function || !ira->codegen->have_err_ret_tracing) {11456 if (fn_entry == nullptr || !fn_entry->calls_or_awaits_errorable_fn || !ira->codegen->have_err_ret_tracing) {
11409 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11457 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11410 out_val->data.x_maybe = nullptr;11458 out_val->data.x_maybe = nullptr;
11411 return nullable_type;11459 return nullable_type;
...@@ -12085,7 +12133,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12085,7 +12133,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1208512133
12086 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;12134 TypeTableEntry *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
12087 if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) {12135 if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) {
12088 parent_fn_entry->calls_errorable_function = true;12136 parent_fn_entry->calls_or_awaits_errorable_fn = true;
12089 }12137 }
1209012138
12091 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;12139 size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
...@@ -12111,7 +12159,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal...@@ -12111,7 +12159,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
12111 assert(fn_type_id->return_type != nullptr);12159 assert(fn_type_id->return_type != nullptr);
12112 assert(parent_fn_entry != nullptr);12160 assert(parent_fn_entry != nullptr);
12113 if (fn_type_can_fail(fn_type_id)) {12161 if (fn_type_can_fail(fn_type_id)) {
12114 parent_fn_entry->calls_errorable_function = true;12162 parent_fn_entry->calls_or_awaits_errorable_fn = true;
12115 }12163 }
1211612164
1211712165
...@@ -17655,6 +17703,22 @@ static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira...@@ -17655,6 +17703,22 @@ static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira
17655 return ira->codegen->builtin_types.entry_type;17703 return ira->codegen->builtin_types.entry_type;
17656}17704}
1765717705
17706static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira, IrInstructionAwaitBookkeeping *instruction) {
17707 TypeTableEntry *promise_result_type = ir_resolve_type(ira, instruction->promise_result_type->other);
17708 if (type_is_invalid(promise_result_type))
17709 return ira->codegen->builtin_types.entry_invalid;
17710
17711 FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec);
17712 assert(fn_entry != nullptr);
17713
17714 if (type_can_fail(promise_result_type)) {
17715 fn_entry->calls_or_awaits_errorable_fn = true;
17716 }
17717
17718 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17719 out_val->type = ira->codegen->builtin_types.entry_void;
17720 return out_val->type;
17721}
1765817722
17659static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {17723static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17660 switch (instruction->id) {17724 switch (instruction->id) {
...@@ -17672,6 +17736,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17672,6 +17736,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17672 case IrInstructionIdErrWrapPayload:17736 case IrInstructionIdErrWrapPayload:
17673 case IrInstructionIdCast:17737 case IrInstructionIdCast:
17674 zig_unreachable();17738 zig_unreachable();
17739
17675 case IrInstructionIdReturn:17740 case IrInstructionIdReturn:
17676 return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);17741 return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
17677 case IrInstructionIdConst:17742 case IrInstructionIdConst:
...@@ -17890,6 +17955,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17890,6 +17955,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17890 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);17955 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);
17891 case IrInstructionIdPromiseResultType:17956 case IrInstructionIdPromiseResultType:
17892 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);17957 return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction);
17958 case IrInstructionIdAwaitBookkeeping:
17959 return ir_analyze_instruction_await_bookkeeping(ira, (IrInstructionAwaitBookkeeping *)instruction);
17893 }17960 }
17894 zig_unreachable();17961 zig_unreachable();
17895}17962}
...@@ -18014,6 +18081,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18014,6 +18081,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18014 case IrInstructionIdCoroResume:18081 case IrInstructionIdCoroResume:
18015 case IrInstructionIdCoroSave:18082 case IrInstructionIdCoroSave:
18016 case IrInstructionIdCoroAllocHelper:18083 case IrInstructionIdCoroAllocHelper:
18084 case IrInstructionIdAwaitBookkeeping:
18017 return true;18085 return true;
1801818086
18019 case IrInstructionIdPhi:18087 case IrInstructionIdPhi:
src/ir_print.cpp+9
...@@ -1155,6 +1155,12 @@ static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instructio...@@ -1155,6 +1155,12 @@ static void ir_print_atomic_rmw(IrPrint *irp, IrInstructionAtomicRmw *instructio
1155 fprintf(irp->f, ")");1155 fprintf(irp->f, ")");
1156}1156}
11571157
1158static void ir_print_await_bookkeeping(IrPrint *irp, IrInstructionAwaitBookkeeping *instruction) {
1159 fprintf(irp->f, "@awaitBookkeeping(");
1160 ir_print_other_instruction(irp, instruction->promise_result_type);
1161 fprintf(irp->f, ")");
1162}
1163
1158static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1164static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1159 ir_print_prefix(irp, instruction);1165 ir_print_prefix(irp, instruction);
1160 switch (instruction->id) {1166 switch (instruction->id) {
...@@ -1523,6 +1529,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1523,6 +1529,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1523 case IrInstructionIdPromiseResultType:1529 case IrInstructionIdPromiseResultType:
1524 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);1530 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);
1525 break;1531 break;
1532 case IrInstructionIdAwaitBookkeeping:
1533 ir_print_await_bookkeeping(irp, (IrInstructionAwaitBookkeeping *)instruction);
1534 break;
1526 }1535 }
1527 fprintf(irp->f, "\n");1536 fprintf(irp->f, "\n");
1528}1537}