| ... | ... | @@ -6686,20 +6686,53 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *parent_scope, AstNode |
| 6686 | 6686 | return ir_build_cancel(irb, parent_scope, node, target_inst); |
| 6687 | 6687 | } |
| 6688 | 6688 | |
| 6689 | | static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 6689 | static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 6690 | 6690 | assert(node->type == NodeTypeResume); |
| 6691 | 6691 | |
| 6692 | | IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, parent_scope); |
| 6692 | IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope); |
| 6693 | 6693 | if (target_inst == irb->codegen->invalid_instruction) |
| 6694 | 6694 | return irb->codegen->invalid_instruction; |
| 6695 | 6695 | |
| 6696 | | return ir_build_coro_resume(irb, parent_scope, node, target_inst); |
| 6696 | IrBasicBlock *done_block = ir_create_basic_block(irb, scope, "ResumeDone"); |
| 6697 | IrBasicBlock *not_canceled_block = ir_create_basic_block(irb, scope, "NotCanceled"); |
| 6698 | |
| 6699 | IrInstruction *inverted_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010 |
| 6700 | IrInstruction *mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_mask); |
| 6701 | IrInstruction *is_canceled_mask = ir_build_const_usize(irb, scope, node, 0x1); // 0b001 |
| 6702 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false); |
| 6703 | IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize); |
| 6704 | IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); |
| 6705 | IrInstruction *promise_T_type_val = ir_build_const_type(irb, scope, node, |
| 6706 | get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void)); |
| 6707 | |
| 6708 | // TODO relies on Zig not re-ordering fields |
| 6709 | IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst); |
| 6710 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); |
| 6711 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); |
| 6712 | IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| 6713 | atomic_state_field_name); |
| 6714 | |
| 6715 | // clear the is_suspended bit |
| 6716 | IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, |
| 6717 | usize_type_val, atomic_state_ptr, nullptr, mask, nullptr, |
| 6718 | AtomicRmwOp_and, AtomicOrderSeqCst); |
| 6719 | |
| 6720 | IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false); |
| 6721 | IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false); |
| 6722 | ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime); |
| 6723 | |
| 6724 | ir_set_cursor_at_end_and_append_block(irb, not_canceled_block); |
| 6725 | ir_build_coro_resume(irb, scope, node, target_inst); |
| 6726 | ir_build_br(irb, scope, node, done_block, is_comptime); |
| 6727 | |
| 6728 | ir_set_cursor_at_end_and_append_block(irb, done_block); |
| 6729 | return ir_build_const_void(irb, scope, node); |
| 6697 | 6730 | } |
| 6698 | 6731 | |
| 6699 | | static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| 6732 | static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 6700 | 6733 | assert(node->type == NodeTypeAwaitExpr); |
| 6701 | 6734 | |
| 6702 | | IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, parent_scope); |
| 6735 | IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope); |
| 6703 | 6736 | if (target_inst == irb->codegen->invalid_instruction) |
| 6704 | 6737 | return irb->codegen->invalid_instruction; |
| 6705 | 6738 | |
| ... | ... | @@ -6713,7 +6746,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 6713 | 6746 | return irb->codegen->invalid_instruction; |
| 6714 | 6747 | } |
| 6715 | 6748 | |
| 6716 | | ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope); |
| 6749 | ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope); |
| 6717 | 6750 | if (scope_defer_expr) { |
| 6718 | 6751 | if (!scope_defer_expr->reported_err) { |
| 6719 | 6752 | add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression")); |
| ... | ... | @@ -6724,85 +6757,85 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 6724 | 6757 | |
| 6725 | 6758 | Scope *outer_scope = irb->exec->begin_scope; |
| 6726 | 6759 | |
| 6727 | | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, parent_scope, node, target_inst); |
| 6760 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst); |
| 6728 | 6761 | Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6729 | | IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name); |
| 6762 | IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); |
| 6730 | 6763 | |
| 6731 | 6764 | if (irb->codegen->have_err_ret_tracing) { |
| 6732 | | IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull); |
| 6765 | IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull); |
| 6733 | 6766 | Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); |
| 6734 | | IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); |
| 6735 | | ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr); |
| 6767 | IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); |
| 6768 | ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr); |
| 6736 | 6769 | } |
| 6737 | 6770 | |
| 6738 | 6771 | Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); |
| 6739 | | IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, |
| 6772 | IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| 6740 | 6773 | atomic_state_field_name); |
| 6741 | 6774 | |
| 6742 | | IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false); |
| 6743 | | VariableTableEntry *result_var = ir_create_var(irb, node, parent_scope, nullptr, |
| 6775 | IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false); |
| 6776 | VariableTableEntry *result_var = ir_create_var(irb, node, scope, nullptr, |
| 6744 | 6777 | false, false, true, const_bool_false); |
| 6745 | | IrInstruction *undefined_value = ir_build_const_undefined(irb, parent_scope, node); |
| 6746 | | IrInstruction *target_promise_type = ir_build_typeof(irb, parent_scope, node, target_inst); |
| 6747 | | IrInstruction *promise_result_type = ir_build_promise_result_type(irb, parent_scope, node, target_promise_type); |
| 6748 | | ir_build_await_bookkeeping(irb, parent_scope, node, promise_result_type); |
| 6749 | | ir_build_var_decl(irb, parent_scope, node, result_var, promise_result_type, nullptr, undefined_value); |
| 6750 | | IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, parent_scope, node, result_var); |
| 6751 | | ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr); |
| 6752 | | IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle); |
| 6753 | | IrInstruction *usize_type_val = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_usize); |
| 6754 | | IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, parent_scope, node, irb->exec->coro_handle); |
| 6755 | | IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, parent_scope, node, |
| 6778 | IrInstruction *undefined_value = ir_build_const_undefined(irb, scope, node); |
| 6779 | IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); |
| 6780 | IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); |
| 6781 | ir_build_await_bookkeeping(irb, scope, node, promise_result_type); |
| 6782 | ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); |
| 6783 | IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); |
| 6784 | ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); |
| 6785 | IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); |
| 6786 | IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize); |
| 6787 | IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle); |
| 6788 | IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, |
| 6756 | 6789 | usize_type_val, atomic_state_ptr, nullptr, coro_handle_addr, nullptr, |
| 6757 | 6790 | AtomicRmwOp_or, AtomicOrderSeqCst); |
| 6758 | | IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0); |
| 6759 | | IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, parent_scope, node, 0x7); // 0b111 |
| 6760 | | IrInstruction *ptr_mask = ir_build_un_op(irb, parent_scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000 |
| 6761 | | IrInstruction *await_handle_addr = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false); |
| 6762 | | IrInstruction *is_non_null = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false); |
| 6763 | | IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend"); |
| 6764 | | IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend"); |
| 6765 | | IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend"); |
| 6766 | | ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false); |
| 6791 | IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); |
| 6792 | IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111 |
| 6793 | IrInstruction *ptr_mask = ir_build_un_op(irb, scope, node, IrUnOpBinNot, inverted_ptr_mask); // 0b111...000 |
| 6794 | IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false); |
| 6795 | IrInstruction *is_non_null = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false); |
| 6796 | IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, scope, "YesSuspend"); |
| 6797 | IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, scope, "NoSuspend"); |
| 6798 | IrBasicBlock *merge_block = ir_create_basic_block(irb, scope, "MergeSuspend"); |
| 6799 | ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false); |
| 6767 | 6800 | |
| 6768 | 6801 | ir_set_cursor_at_end_and_append_block(irb, no_suspend_block); |
| 6769 | 6802 | if (irb->codegen->have_err_ret_tracing) { |
| 6770 | 6803 | Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); |
| 6771 | | IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name); |
| 6772 | | IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull); |
| 6773 | | ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); |
| 6804 | IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name); |
| 6805 | IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull); |
| 6806 | ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); |
| 6774 | 6807 | } |
| 6775 | 6808 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6776 | | IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name); |
| 6809 | IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); |
| 6777 | 6810 | // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to, |
| 6778 | 6811 | // because we're about to destroy the memory. So we store it into our result variable. |
| 6779 | | IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr); |
| 6780 | | ir_build_store_ptr(irb, parent_scope, node, my_result_var_ptr, no_suspend_result); |
| 6781 | | ir_build_cancel(irb, parent_scope, node, target_inst); |
| 6782 | | ir_build_br(irb, parent_scope, node, merge_block, const_bool_false); |
| 6812 | IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr); |
| 6813 | ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result); |
| 6814 | ir_build_cancel(irb, scope, node, target_inst); |
| 6815 | ir_build_br(irb, scope, node, merge_block, const_bool_false); |
| 6783 | 6816 | |
| 6784 | 6817 | ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block); |
| 6785 | | IrInstruction *suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false); |
| 6786 | | IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup"); |
| 6787 | | IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume"); |
| 6818 | IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, save_token, const_bool_false); |
| 6819 | IrBasicBlock *cleanup_block = ir_create_basic_block(irb, scope, "SuspendCleanup"); |
| 6820 | IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "SuspendResume"); |
| 6788 | 6821 | |
| 6789 | 6822 | IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2); |
| 6790 | | cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0); |
| 6823 | cases[0].value = ir_build_const_u8(irb, scope, node, 0); |
| 6791 | 6824 | cases[0].block = resume_block; |
| 6792 | | cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1); |
| 6825 | cases[1].value = ir_build_const_u8(irb, scope, node, 1); |
| 6793 | 6826 | cases[1].block = cleanup_block; |
| 6794 | | ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block, |
| 6827 | ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, |
| 6795 | 6828 | 2, cases, const_bool_false, nullptr); |
| 6796 | 6829 | |
| 6797 | 6830 | ir_set_cursor_at_end_and_append_block(irb, cleanup_block); |
| 6798 | | ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); |
| 6799 | | ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false)); |
| 6831 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 6832 | ir_mark_gen(ir_build_br(irb, scope, node, irb->exec->coro_final_cleanup_block, const_bool_false)); |
| 6800 | 6833 | |
| 6801 | 6834 | ir_set_cursor_at_end_and_append_block(irb, resume_block); |
| 6802 | | ir_build_br(irb, parent_scope, node, merge_block, const_bool_false); |
| 6835 | ir_build_br(irb, scope, node, merge_block, const_bool_false); |
| 6803 | 6836 | |
| 6804 | 6837 | ir_set_cursor_at_end_and_append_block(irb, merge_block); |
| 6805 | | return ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr); |
| 6838 | return ir_build_load_ptr(irb, scope, node, my_result_var_ptr); |
| 6806 | 6839 | } |
| 6807 | 6840 | |
| 6808 | 6841 | static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |