| ... | ... | @@ -26,6 +26,7 @@ struct IrBuilder { |
| 26 | 26 | CodeGen *codegen; |
| 27 | 27 | IrExecutable *exec; |
| 28 | 28 | IrBasicBlock *current_basic_block; |
| 29 | AstNode *main_block_node; |
| 29 | 30 | }; |
| 30 | 31 | |
| 31 | 32 | struct IrAnalyze { |
| ... | ... | @@ -1061,6 +1062,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { |
| 1061 | 1062 | return IrInstructionIdCoroResume; |
| 1062 | 1063 | } |
| 1063 | 1064 | |
| 1065 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelRequested *) { |
| 1066 | return IrInstructionIdTestCancelRequested; |
| 1067 | } |
| 1068 | |
| 1064 | 1069 | template<typename T> |
| 1065 | 1070 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1066 | 1071 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -3320,6 +3325,16 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode |
| 3320 | 3325 | return &instruction->base; |
| 3321 | 3326 | } |
| 3322 | 3327 | |
| 3328 | static IrInstruction *ir_build_test_cancel_requested(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 3329 | bool use_return_begin_prev_value) |
| 3330 | { |
| 3331 | IrInstructionTestCancelRequested *instruction = ir_build_instruction<IrInstructionTestCancelRequested>(irb, scope, source_node); |
| 3332 | instruction->base.value.type = irb->codegen->builtin_types.entry_bool; |
| 3333 | instruction->use_return_begin_prev_value = use_return_begin_prev_value; |
| 3334 | |
| 3335 | return &instruction->base; |
| 3336 | } |
| 3337 | |
| 3323 | 3338 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 3324 | 3339 | results[ReturnKindUnconditional] = 0; |
| 3325 | 3340 | results[ReturnKindError] = 0; |
| ... | ... | @@ -3494,45 +3509,62 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3494 | 3509 | size_t defer_counts[2]; |
| 3495 | 3510 | ir_count_defers(irb, scope, outer_scope, defer_counts); |
| 3496 | 3511 | bool have_err_defers = defer_counts[ReturnKindError] > 0; |
| 3497 | | if (have_err_defers || irb->codegen->have_err_ret_tracing) { |
| 3498 | | IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr"); |
| 3499 | | IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk"); |
| 3512 | if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { |
| 3513 | // only generate unconditional defers |
| 3514 | ir_gen_defers_for_block(irb, scope, outer_scope, false); |
| 3515 | IrInstruction *result = ir_build_return(irb, scope, node, return_value); |
| 3516 | result_loc_ret->base.source_instruction = result; |
| 3517 | return result; |
| 3518 | } |
| 3519 | bool should_inline = ir_should_inline(irb->exec, scope); |
| 3520 | bool need_test_cancel = !should_inline && have_err_defers; |
| 3500 | 3521 | |
| 3501 | | IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true); |
| 3522 | IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr"); |
| 3523 | IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, scope, "Defers"); |
| 3524 | IrBasicBlock *ok_block = need_test_cancel ? |
| 3525 | ir_create_basic_block(irb, scope, "ErrRetOk") : normal_defers_block; |
| 3526 | IrBasicBlock *all_defers_block = have_err_defers ? ir_create_basic_block(irb, scope, "ErrDefers") : normal_defers_block; |
| 3502 | 3527 | |
| 3503 | | bool should_inline = ir_should_inline(irb->exec, scope); |
| 3504 | | IrInstruction *is_comptime; |
| 3505 | | if (should_inline) { |
| 3506 | | is_comptime = ir_build_const_bool(irb, scope, node, true); |
| 3507 | | } else { |
| 3508 | | is_comptime = ir_build_test_comptime(irb, scope, node, is_err); |
| 3509 | | } |
| 3528 | IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true); |
| 3510 | 3529 | |
| 3511 | | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime)); |
| 3512 | | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); |
| 3530 | IrInstruction *force_comptime = ir_build_const_bool(irb, scope, node, should_inline); |
| 3531 | IrInstruction *err_is_comptime; |
| 3532 | if (should_inline) { |
| 3533 | err_is_comptime = force_comptime; |
| 3534 | } else { |
| 3535 | err_is_comptime = ir_build_test_comptime(irb, scope, node, is_err); |
| 3536 | } |
| 3513 | 3537 | |
| 3514 | | ir_set_cursor_at_end_and_append_block(irb, err_block); |
| 3515 | | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 3516 | | ir_build_save_err_ret_addr(irb, scope, node); |
| 3517 | | } |
| 3518 | | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 3519 | | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 3538 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, err_is_comptime)); |
| 3539 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); |
| 3520 | 3540 | |
| 3541 | ir_set_cursor_at_end_and_append_block(irb, err_block); |
| 3542 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 3543 | ir_build_save_err_ret_addr(irb, scope, node); |
| 3544 | } |
| 3545 | ir_build_br(irb, scope, node, all_defers_block, err_is_comptime); |
| 3546 | |
| 3547 | if (need_test_cancel) { |
| 3521 | 3548 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| 3522 | | ir_gen_defers_for_block(irb, scope, outer_scope, false); |
| 3523 | | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 3549 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, scope, node, true); |
| 3550 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_canceled, |
| 3551 | all_defers_block, normal_defers_block, force_comptime)); |
| 3552 | } |
| 3524 | 3553 | |
| 3525 | | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); |
| 3526 | | IrInstruction *result = ir_build_return(irb, scope, node, return_value); |
| 3527 | | result_loc_ret->base.source_instruction = result; |
| 3528 | | return result; |
| 3529 | | } else { |
| 3530 | | // generate unconditional defers |
| 3531 | | ir_gen_defers_for_block(irb, scope, outer_scope, false); |
| 3532 | | IrInstruction *result = ir_build_return(irb, scope, node, return_value); |
| 3533 | | result_loc_ret->base.source_instruction = result; |
| 3534 | | return result; |
| 3554 | if (all_defers_block != normal_defers_block) { |
| 3555 | ir_set_cursor_at_end_and_append_block(irb, all_defers_block); |
| 3556 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 3557 | ir_build_br(irb, scope, node, ret_stmt_block, force_comptime); |
| 3535 | 3558 | } |
| 3559 | |
| 3560 | ir_set_cursor_at_end_and_append_block(irb, normal_defers_block); |
| 3561 | ir_gen_defers_for_block(irb, scope, outer_scope, false); |
| 3562 | ir_build_br(irb, scope, node, ret_stmt_block, force_comptime); |
| 3563 | |
| 3564 | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); |
| 3565 | IrInstruction *result = ir_build_return(irb, scope, node, return_value); |
| 3566 | result_loc_ret->base.source_instruction = result; |
| 3567 | return result; |
| 3536 | 3568 | } |
| 3537 | 3569 | case ReturnKindError: |
| 3538 | 3570 | { |
| ... | ... | @@ -3765,18 +3797,59 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3765 | 3797 | incoming_values.append(else_expr_result); |
| 3766 | 3798 | } |
| 3767 | 3799 | |
| 3768 | | if (block_node->data.block.name != nullptr) { |
| 3800 | bool is_return_from_fn = block_node == irb->main_block_node; |
| 3801 | if (!is_return_from_fn) { |
| 3769 | 3802 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3803 | } |
| 3804 | |
| 3805 | IrInstruction *result; |
| 3806 | if (block_node->data.block.name != nullptr) { |
| 3770 | 3807 | ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime)); |
| 3771 | 3808 | ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); |
| 3772 | 3809 | IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, |
| 3773 | 3810 | incoming_blocks.items, incoming_values.items, scope_block->peer_parent); |
| 3774 | | return ir_expr_wrap(irb, parent_scope, phi, result_loc); |
| 3811 | result = ir_expr_wrap(irb, parent_scope, phi, result_loc); |
| 3775 | 3812 | } else { |
| 3776 | | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3777 | 3813 | IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); |
| 3778 | | return ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc); |
| 3814 | result = ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc); |
| 3779 | 3815 | } |
| 3816 | if (!is_return_from_fn) |
| 3817 | return result; |
| 3818 | |
| 3819 | // no need for save_err_ret_addr because this cannot return error |
| 3820 | // but if it is a canceled async function we do need to run the errdefers |
| 3821 | |
| 3822 | ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result)); |
| 3823 | result = ir_mark_gen(ir_build_return_begin(irb, child_scope, block_node, result)); |
| 3824 | |
| 3825 | size_t defer_counts[2]; |
| 3826 | ir_count_defers(irb, child_scope, outer_block_scope, defer_counts); |
| 3827 | bool have_err_defers = defer_counts[ReturnKindError] > 0; |
| 3828 | if (!have_err_defers) { |
| 3829 | // only generate unconditional defers |
| 3830 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3831 | return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result)); |
| 3832 | } |
| 3833 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, child_scope, block_node, true); |
| 3834 | IrBasicBlock *all_defers_block = ir_create_basic_block(irb, child_scope, "ErrDefers"); |
| 3835 | IrBasicBlock *normal_defers_block = ir_create_basic_block(irb, child_scope, "Defers"); |
| 3836 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, child_scope, "RetStmt"); |
| 3837 | bool should_inline = ir_should_inline(irb->exec, child_scope); |
| 3838 | IrInstruction *errdefers_is_comptime = ir_build_const_bool(irb, child_scope, block_node, |
| 3839 | should_inline || !have_err_defers); |
| 3840 | ir_mark_gen(ir_build_cond_br(irb, child_scope, block_node, is_canceled, |
| 3841 | all_defers_block, normal_defers_block, errdefers_is_comptime)); |
| 3842 | |
| 3843 | ir_set_cursor_at_end_and_append_block(irb, all_defers_block); |
| 3844 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, true); |
| 3845 | ir_build_br(irb, child_scope, block_node, ret_stmt_block, errdefers_is_comptime); |
| 3846 | |
| 3847 | ir_set_cursor_at_end_and_append_block(irb, normal_defers_block); |
| 3848 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); |
| 3849 | ir_build_br(irb, child_scope, block_node, ret_stmt_block, errdefers_is_comptime); |
| 3850 | |
| 3851 | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); |
| 3852 | return ir_mark_gen(ir_build_return(irb, child_scope, result->source_node, result)); |
| 3780 | 3853 | } |
| 3781 | 3854 | |
| 3782 | 3855 | static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { |
| ... | ... | @@ -8111,6 +8184,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 8111 | 8184 | |
| 8112 | 8185 | irb->codegen = codegen; |
| 8113 | 8186 | irb->exec = ir_executable; |
| 8187 | irb->main_block_node = node; |
| 8114 | 8188 | |
| 8115 | 8189 | IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry"); |
| 8116 | 8190 | ir_set_cursor_at_end_and_append_block(irb, entry_block); |
| ... | ... | @@ -24603,6 +24677,16 @@ static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstr |
| 24603 | 24677 | return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame); |
| 24604 | 24678 | } |
| 24605 | 24679 | |
| 24680 | static IrInstruction *ir_analyze_instruction_test_cancel_requested(IrAnalyze *ira, |
| 24681 | IrInstructionTestCancelRequested *instruction) |
| 24682 | { |
| 24683 | if (ir_should_inline(ira->new_irb.exec, instruction->base.scope)) { |
| 24684 | return ir_const_bool(ira, &instruction->base, false); |
| 24685 | } |
| 24686 | return ir_build_test_cancel_requested(&ira->new_irb, instruction->base.scope, instruction->base.source_node, |
| 24687 | instruction->use_return_begin_prev_value); |
| 24688 | } |
| 24689 | |
| 24606 | 24690 | static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { |
| 24607 | 24691 | switch (instruction->id) { |
| 24608 | 24692 | case IrInstructionIdInvalid: |
| ... | ... | @@ -24900,6 +24984,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 24900 | 24984 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); |
| 24901 | 24985 | case IrInstructionIdAwaitSrc: |
| 24902 | 24986 | return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction); |
| 24987 | case IrInstructionIdTestCancelRequested: |
| 24988 | return ir_analyze_instruction_test_cancel_requested(ira, (IrInstructionTestCancelRequested *)instruction); |
| 24903 | 24989 | } |
| 24904 | 24990 | zig_unreachable(); |
| 24905 | 24991 | } |
| ... | ... | @@ -25134,6 +25220,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25134 | 25220 | case IrInstructionIdHasDecl: |
| 25135 | 25221 | case IrInstructionIdAllocaSrc: |
| 25136 | 25222 | case IrInstructionIdAllocaGen: |
| 25223 | case IrInstructionIdTestCancelRequested: |
| 25137 | 25224 | return false; |
| 25138 | 25225 | |
| 25139 | 25226 | case IrInstructionIdAsm: |