| ... | @@ -26,6 +26,7 @@ struct IrBuilder { | ... | @@ -26,6 +26,7 @@ struct IrBuilder { |
| 26 | CodeGen *codegen; | 26 | CodeGen *codegen; |
| 27 | IrExecutable *exec; | 27 | IrExecutable *exec; |
| 28 | IrBasicBlock *current_basic_block; | 28 | IrBasicBlock *current_basic_block; |
| | 29 | AstNode *main_block_node; |
| 29 | }; | 30 | }; |
| 30 | | 31 | |
| 31 | struct IrAnalyze { | 32 | struct IrAnalyze { |
| ... | @@ -1061,6 +1062,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { | ... | @@ -1061,6 +1062,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { |
| 1061 | return IrInstructionIdCoroResume; | 1062 | return IrInstructionIdCoroResume; |
| 1062 | } | 1063 | } |
| 1063 | | 1064 | |
| | 1065 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTestCancelRequested *) { |
| | 1066 | return IrInstructionIdTestCancelRequested; |
| | 1067 | } |
| | 1068 | |
| 1064 | template<typename T> | 1069 | template<typename T> |
| 1065 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 1070 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1066 | T *special_instruction = allocate<T>(1); | 1071 | T *special_instruction = allocate<T>(1); |
| ... | @@ -3320,6 +3325,16 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -3320,6 +3325,16 @@ static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode |
| 3320 | return &instruction->base; | 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 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { | 3338 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 3324 | results[ReturnKindUnconditional] = 0; | 3339 | results[ReturnKindUnconditional] = 0; |
| 3325 | results[ReturnKindError] = 0; | 3340 | results[ReturnKindError] = 0; |
| ... | @@ -3494,45 +3509,62 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -3494,45 +3509,62 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3494 | size_t defer_counts[2]; | 3509 | size_t defer_counts[2]; |
| 3495 | ir_count_defers(irb, scope, outer_scope, defer_counts); | 3510 | ir_count_defers(irb, scope, outer_scope, defer_counts); |
| 3496 | bool have_err_defers = defer_counts[ReturnKindError] > 0; | 3511 | bool have_err_defers = defer_counts[ReturnKindError] > 0; |
| 3497 | if (have_err_defers || irb->codegen->have_err_ret_tracing) { | 3512 | if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { |
| 3498 | IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr"); | 3513 | // only generate unconditional defers |
| 3499 | IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk"); | 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); | 3528 | IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true); |
| 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 | } | | |
| 3510 | | 3529 | |
| 3511 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime)); | 3530 | IrInstruction *force_comptime = ir_build_const_bool(irb, scope, node, should_inline); |
| 3512 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); | 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); | 3538 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, err_is_comptime)); |
| 3515 | if (irb->codegen->have_err_ret_tracing && !should_inline) { | 3539 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); |
| 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); | | |
| 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 | ir_set_cursor_at_end_and_append_block(irb, ok_block); | 3548 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| 3522 | ir_gen_defers_for_block(irb, scope, outer_scope, false); | 3549 | IrInstruction *is_canceled = ir_build_test_cancel_requested(irb, scope, node, true); |
| 3523 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); | 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); | 3554 | if (all_defers_block != normal_defers_block) { |
| 3526 | IrInstruction *result = ir_build_return(irb, scope, node, return_value); | 3555 | ir_set_cursor_at_end_and_append_block(irb, all_defers_block); |
| 3527 | result_loc_ret->base.source_instruction = result; | 3556 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 3528 | return result; | 3557 | ir_build_br(irb, scope, node, ret_stmt_block, force_comptime); |
| 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; | | |
| 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 | case ReturnKindError: | 3569 | case ReturnKindError: |
| 3538 | { | 3570 | { |
| ... | @@ -3765,18 +3797,59 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode | ... | @@ -3765,18 +3797,59 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3765 | incoming_values.append(else_expr_result); | 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 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); | 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 | ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime)); | 3807 | ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime)); |
| 3771 | ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); | 3808 | ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); |
| 3772 | IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, | 3809 | IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, |
| 3773 | incoming_blocks.items, incoming_values.items, scope_block->peer_parent); | 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 | } else { | 3812 | } else { |
| 3776 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); | | |
| 3777 | IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); | 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 | static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { | 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,6 +8184,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 8111 | | 8184 | |
| 8112 | irb->codegen = codegen; | 8185 | irb->codegen = codegen; |
| 8113 | irb->exec = ir_executable; | 8186 | irb->exec = ir_executable; |
| | 8187 | irb->main_block_node = node; |
| 8114 | | 8188 | |
| 8115 | IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry"); | 8189 | IrBasicBlock *entry_block = ir_create_basic_block(irb, scope, "Entry"); |
| 8116 | ir_set_cursor_at_end_and_append_block(irb, entry_block); | 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,6 +24677,16 @@ static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstr |
| 24603 | return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame); | 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 | static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { | 24690 | static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { |
| 24607 | switch (instruction->id) { | 24691 | switch (instruction->id) { |
| 24608 | case IrInstructionIdInvalid: | 24692 | case IrInstructionIdInvalid: |
| ... | @@ -24900,6 +24984,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction | ... | @@ -24900,6 +24984,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 24900 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); | 24984 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); |
| 24901 | case IrInstructionIdAwaitSrc: | 24985 | case IrInstructionIdAwaitSrc: |
| 24902 | return ir_analyze_instruction_await(ira, (IrInstructionAwaitSrc *)instruction); | 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 | zig_unreachable(); | 24990 | zig_unreachable(); |
| 24905 | } | 24991 | } |
| ... | @@ -25134,6 +25220,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -25134,6 +25220,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25134 | case IrInstructionIdHasDecl: | 25220 | case IrInstructionIdHasDecl: |
| 25135 | case IrInstructionIdAllocaSrc: | 25221 | case IrInstructionIdAllocaSrc: |
| 25136 | case IrInstructionIdAllocaGen: | 25222 | case IrInstructionIdAllocaGen: |
| | 25223 | case IrInstructionIdTestCancelRequested: |
| 25137 | return false; | 25224 | return false; |
| 25138 | | 25225 | |
| 25139 | case IrInstructionIdAsm: | 25226 | case IrInstructionIdAsm: |