| ... | ... | @@ -46,7 +46,10 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) { |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | 48 | static const char * ASYNC_ALLOC_FIELD_NAME = "allocFn"; |
| 49 | | //static const char * ASYNC_FREE_FIELD_NAME = "freeFn"; |
| 49 | static const char * ASYNC_FREE_FIELD_NAME = "freeFn"; |
| 50 | static const char * AWAITER_HANDLE_FIELD_NAME = "awaiter_handle"; |
| 51 | static const char * RESULT_FIELD_NAME = "result"; |
| 52 | static const char * RESULT_PTR_FIELD_NAME = "result_ptr"; |
| 50 | 53 | |
| 51 | 54 | enum ConstCastResultId { |
| 52 | 55 | ConstCastResultIdOk, |
| ... | ... | @@ -672,6 +675,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocFail *) |
| 672 | 675 | return IrInstructionIdCoroAllocFail; |
| 673 | 676 | } |
| 674 | 677 | |
| 678 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSuspend *) { |
| 679 | return IrInstructionIdCoroSuspend; |
| 680 | } |
| 681 | |
| 682 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroEnd *) { |
| 683 | return IrInstructionIdCoroEnd; |
| 684 | } |
| 685 | |
| 686 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroFree *) { |
| 687 | return IrInstructionIdCoroFree; |
| 688 | } |
| 689 | |
| 690 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) { |
| 691 | return IrInstructionIdCoroResume; |
| 692 | } |
| 693 | |
| 675 | 694 | template<typename T> |
| 676 | 695 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 677 | 696 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -743,14 +762,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou |
| 743 | 762 | return &return_instruction->base; |
| 744 | 763 | } |
| 745 | 764 | |
| 746 | | static IrInstruction *ir_build_return_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 747 | | IrInstruction *return_value) |
| 748 | | { |
| 749 | | IrInstruction *new_instruction = ir_build_return(irb, old_instruction->scope, old_instruction->source_node, return_value); |
| 750 | | ir_link_new_instruction(new_instruction, old_instruction); |
| 751 | | return new_instruction; |
| 752 | | } |
| 753 | | |
| 754 | 765 | static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 755 | 766 | TypeTableEntry *type_entry) |
| 756 | 767 | { |
| ... | ... | @@ -822,6 +833,14 @@ static IrInstruction *ir_build_const_u29(IrBuilder *irb, Scope *scope, AstNode * |
| 822 | 833 | return &const_instruction->base; |
| 823 | 834 | } |
| 824 | 835 | |
| 836 | static IrInstruction *ir_build_const_u8(IrBuilder *irb, Scope *scope, AstNode *source_node, uint8_t value) { |
| 837 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 838 | const_instruction->base.value.type = irb->codegen->builtin_types.entry_u8; |
| 839 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 840 | bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, value); |
| 841 | return &const_instruction->base; |
| 842 | } |
| 843 | |
| 825 | 844 | static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 826 | 845 | TypeTableEntry *type_entry) |
| 827 | 846 | { |
| ... | ... | @@ -909,6 +928,33 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast |
| 909 | 928 | return &const_instruction->base; |
| 910 | 929 | } |
| 911 | 930 | |
| 931 | static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 932 | TypeTableEntry *return_type) |
| 933 | { |
| 934 | TypeTableEntry *awaiter_handle_type = get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise); |
| 935 | TypeTableEntry *result_ptr_type = get_pointer_to_type(irb->codegen, return_type, false); |
| 936 | const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME}; |
| 937 | TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type}; |
| 938 | size_t field_count = type_has_bits(result_ptr_type) ? 3 : 1; |
| 939 | TypeTableEntry *struct_type = get_struct_type(irb->codegen, "AsyncFramePromise", field_names, field_types, |
| 940 | field_count); |
| 941 | |
| 942 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 943 | const_instruction->base.value.type = struct_type; |
| 944 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 945 | const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(2); |
| 946 | const_instruction->base.value.data.x_struct.fields[0].type = awaiter_handle_type; |
| 947 | const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic; |
| 948 | const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr; |
| 949 | if (field_count == 3) { |
| 950 | const_instruction->base.value.data.x_struct.fields[1].type = return_type; |
| 951 | const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef; |
| 952 | const_instruction->base.value.data.x_struct.fields[2].type = result_ptr_type; |
| 953 | const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef; |
| 954 | } |
| 955 | return &const_instruction->base; |
| 956 | } |
| 957 | |
| 912 | 958 | static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, |
| 913 | 959 | IrInstruction *op1, IrInstruction *op2, bool safety_check_on) |
| 914 | 960 | { |
| ... | ... | @@ -2451,8 +2497,11 @@ static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *sco |
| 2451 | 2497 | return &instruction->base; |
| 2452 | 2498 | } |
| 2453 | 2499 | |
| 2454 | | static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 2500 | static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *promise_ptr) { |
| 2455 | 2501 | IrInstructionCoroId *instruction = ir_build_instruction<IrInstructionCoroId>(irb, scope, source_node); |
| 2502 | instruction->promise_ptr = promise_ptr; |
| 2503 | |
| 2504 | ir_ref_instruction(promise_ptr, irb->current_basic_block); |
| 2456 | 2505 | |
| 2457 | 2506 | return &instruction->base; |
| 2458 | 2507 | } |
| ... | ... | @@ -2494,6 +2543,48 @@ static IrInstruction *ir_build_coro_alloc_fail(IrBuilder *irb, Scope *scope, Ast |
| 2494 | 2543 | return &instruction->base; |
| 2495 | 2544 | } |
| 2496 | 2545 | |
| 2546 | static IrInstruction *ir_build_coro_suspend(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2547 | IrInstruction *save_point, IrInstruction *is_final) |
| 2548 | { |
| 2549 | IrInstructionCoroSuspend *instruction = ir_build_instruction<IrInstructionCoroSuspend>(irb, scope, source_node); |
| 2550 | instruction->save_point = save_point; |
| 2551 | instruction->is_final = is_final; |
| 2552 | |
| 2553 | if (save_point != nullptr) ir_ref_instruction(save_point, irb->current_basic_block); |
| 2554 | ir_ref_instruction(is_final, irb->current_basic_block); |
| 2555 | |
| 2556 | return &instruction->base; |
| 2557 | } |
| 2558 | |
| 2559 | static IrInstruction *ir_build_coro_end(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 2560 | IrInstructionCoroEnd *instruction = ir_build_instruction<IrInstructionCoroEnd>(irb, scope, source_node); |
| 2561 | return &instruction->base; |
| 2562 | } |
| 2563 | |
| 2564 | static IrInstruction *ir_build_coro_free(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2565 | IrInstruction *coro_id, IrInstruction *coro_handle) |
| 2566 | { |
| 2567 | IrInstructionCoroFree *instruction = ir_build_instruction<IrInstructionCoroFree>(irb, scope, source_node); |
| 2568 | instruction->coro_id = coro_id; |
| 2569 | instruction->coro_handle = coro_handle; |
| 2570 | |
| 2571 | ir_ref_instruction(coro_id, irb->current_basic_block); |
| 2572 | ir_ref_instruction(coro_handle, irb->current_basic_block); |
| 2573 | |
| 2574 | return &instruction->base; |
| 2575 | } |
| 2576 | |
| 2577 | static IrInstruction *ir_build_coro_resume(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2578 | IrInstruction *awaiter_handle) |
| 2579 | { |
| 2580 | IrInstructionCoroResume *instruction = ir_build_instruction<IrInstructionCoroResume>(irb, scope, source_node); |
| 2581 | instruction->awaiter_handle = awaiter_handle; |
| 2582 | |
| 2583 | ir_ref_instruction(awaiter_handle, irb->current_basic_block); |
| 2584 | |
| 2585 | return &instruction->base; |
| 2586 | } |
| 2587 | |
| 2497 | 2588 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2498 | 2589 | results[ReturnKindUnconditional] = 0; |
| 2499 | 2590 | results[ReturnKindError] = 0; |
| ... | ... | @@ -2566,6 +2657,29 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { |
| 2566 | 2657 | return nullptr; |
| 2567 | 2658 | } |
| 2568 | 2659 | |
| 2660 | static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value, |
| 2661 | bool is_generated_code) |
| 2662 | { |
| 2663 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); |
| 2664 | bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; |
| 2665 | if (!is_async) { |
| 2666 | IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value); |
| 2667 | return_inst->is_gen = is_generated_code; |
| 2668 | return return_inst; |
| 2669 | } |
| 2670 | |
| 2671 | if (irb->exec->coro_result_ptr_field_ptr) { |
| 2672 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); |
| 2673 | ir_build_store_ptr(irb, scope, node, result_ptr, return_value); |
| 2674 | } |
| 2675 | IrInstruction *maybe_await_handle = ir_build_load_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr); |
| 2676 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle); |
| 2677 | IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false); |
| 2678 | return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final, |
| 2679 | is_comptime); |
| 2680 | // the above blocks are rendered by ir_gen after the rest of codegen |
| 2681 | } |
| 2682 | |
| 2569 | 2683 | static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { |
| 2570 | 2684 | assert(node->type == NodeTypeReturnExpr); |
| 2571 | 2685 | |
| ... | ... | @@ -2615,18 +2729,22 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2615 | 2729 | } |
| 2616 | 2730 | |
| 2617 | 2731 | ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime)); |
| 2732 | IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); |
| 2618 | 2733 | |
| 2619 | 2734 | ir_set_cursor_at_end_and_append_block(irb, err_block); |
| 2620 | 2735 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 2621 | | ir_build_return(irb, scope, node, return_value); |
| 2736 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 2622 | 2737 | |
| 2623 | 2738 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| 2624 | 2739 | ir_gen_defers_for_block(irb, scope, outer_scope, false); |
| 2625 | | return ir_build_return(irb, scope, node, return_value); |
| 2740 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 2741 | |
| 2742 | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); |
| 2743 | return ir_gen_async_return(irb, scope, node, return_value, false); |
| 2626 | 2744 | } else { |
| 2627 | 2745 | // generate unconditional defers |
| 2628 | 2746 | ir_gen_defers_for_block(irb, scope, outer_scope, false); |
| 2629 | | return ir_build_return(irb, scope, node, return_value); |
| 2747 | return ir_gen_async_return(irb, scope, node, return_value, false); |
| 2630 | 2748 | } |
| 2631 | 2749 | } |
| 2632 | 2750 | case ReturnKindError: |
| ... | ... | @@ -2646,7 +2764,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 2646 | 2764 | ir_set_cursor_at_end_and_append_block(irb, return_block); |
| 2647 | 2765 | ir_gen_defers_for_block(irb, scope, outer_scope, true); |
| 2648 | 2766 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); |
| 2649 | | ir_build_return(irb, scope, node, err_val); |
| 2767 | ir_gen_async_return(irb, scope, node, err_val, false); |
| 2650 | 2768 | |
| 2651 | 2769 | ir_set_cursor_at_end_and_append_block(irb, continue_block); |
| 2652 | 2770 | IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false); |
| ... | ... | @@ -5842,6 +5960,7 @@ static void invalidate_exec(IrExecutable *exec) { |
| 5842 | 5960 | invalidate_exec(exec->source_exec); |
| 5843 | 5961 | } |
| 5844 | 5962 | |
| 5963 | |
| 5845 | 5964 | bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { |
| 5846 | 5965 | assert(node->owner); |
| 5847 | 5966 | |
| ... | ... | @@ -5858,48 +5977,81 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 5858 | 5977 | |
| 5859 | 5978 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); |
| 5860 | 5979 | bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; |
| 5980 | IrInstruction *u8_ptr_type; |
| 5981 | IrInstruction *const_bool_false; |
| 5982 | IrInstruction *coro_unwrapped_mem_ptr; |
| 5983 | IrInstruction *coro_id; |
| 5984 | IrInstruction *coro_promise_ptr; |
| 5985 | IrInstruction *coro_result_field_ptr; |
| 5986 | TypeTableEntry *return_type; |
| 5987 | Buf *result_ptr_field_name; |
| 5861 | 5988 | if (is_async) { |
| 5862 | | IrInstruction *is_comptime_false = ir_build_const_bool(irb, scope, node, false); |
| 5863 | | IrInstruction *coro_id = ir_build_coro_id(irb, scope, node); |
| 5989 | // create the coro promise |
| 5990 | const_bool_false = ir_build_const_bool(irb, scope, node, false); |
| 5991 | VariableTableEntry *promise_var = ir_create_var(irb, node, scope, nullptr, false, false, true, const_bool_false); |
| 5992 | //scope = promise_var->child_scope; |
| 5993 | |
| 5994 | return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; |
| 5995 | IrInstruction *promise_init = ir_build_const_promise_init(irb, scope, node, return_type); |
| 5996 | ir_build_var_decl(irb, scope, node, promise_var, nullptr, nullptr, promise_init); |
| 5997 | |
| 5998 | coro_promise_ptr = ir_build_var_ptr(irb, scope, node, promise_var, false, false); |
| 5999 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 6000 | irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| 6001 | awaiter_handle_field_name); |
| 6002 | if (type_has_bits(return_type)) { |
| 6003 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6004 | coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); |
| 6005 | result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 6006 | irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, |
| 6007 | result_ptr_field_name); |
| 6008 | ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, coro_result_field_ptr); |
| 6009 | } |
| 6010 | |
| 6011 | u8_ptr_type = ir_build_const_type(irb, scope, node, |
| 6012 | get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); |
| 6013 | IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_promise_ptr); |
| 6014 | coro_id = ir_build_coro_id(irb, scope, node, promise_as_u8_ptr); |
| 5864 | 6015 | IrInstruction *need_dyn_alloc = ir_build_coro_alloc(irb, scope, node, coro_id); |
| 5865 | 6016 | IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); |
| 5866 | | IrInstruction *u8_ptr_type = ir_build_const_type(irb, scope, node, |
| 5867 | | get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false)); |
| 5868 | 6017 | IrInstruction *null_ptr = ir_build_int_to_ptr(irb, scope, node, u8_ptr_type, zero); |
| 5869 | 6018 | |
| 5870 | 6019 | IrBasicBlock *dyn_alloc_block = ir_create_basic_block(irb, scope, "DynAlloc"); |
| 5871 | 6020 | IrBasicBlock *coro_begin_block = ir_create_basic_block(irb, scope, "CoroBegin"); |
| 5872 | | ir_build_cond_br(irb, scope, node, need_dyn_alloc, dyn_alloc_block, coro_begin_block, is_comptime_false); |
| 6021 | ir_build_cond_br(irb, scope, node, need_dyn_alloc, dyn_alloc_block, coro_begin_block, const_bool_false); |
| 5873 | 6022 | |
| 5874 | 6023 | ir_set_cursor_at_end_and_append_block(irb, dyn_alloc_block); |
| 5875 | 6024 | IrInstruction *coro_size = ir_build_coro_size(irb, scope, node); |
| 5876 | | IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node); |
| 6025 | irb->exec->implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node); |
| 5877 | 6026 | Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME); |
| 5878 | | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name); |
| 6027 | IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, irb->exec->implicit_allocator_ptr, |
| 6028 | alloc_field_name); |
| 5879 | 6029 | IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr); |
| 5880 | 6030 | IrInstruction *alignment = ir_build_const_u29(irb, scope, node, irb->codegen->pointer_size_bytes * 2); |
| 5881 | 6031 | size_t arg_count = 3; |
| 5882 | 6032 | IrInstruction **args = allocate<IrInstruction *>(arg_count); |
| 5883 | | args[0] = implicit_allocator_ptr; // self |
| 6033 | args[0] = irb->exec->implicit_allocator_ptr; // self |
| 5884 | 6034 | args[1] = coro_size; // byte_count |
| 5885 | 6035 | args[2] = alignment; // alignment |
| 5886 | | IrInstruction *alloc_result = ir_build_call(irb, scope, node, nullptr, alloc_fn, arg_count, args, false, FnInlineAuto, false, nullptr); |
| 6036 | IrInstruction *alloc_result = ir_build_call(irb, scope, node, nullptr, alloc_fn, arg_count, args, false, |
| 6037 | FnInlineAuto, false, nullptr); |
| 5887 | 6038 | IrInstruction *alloc_result_ptr = ir_build_ref(irb, scope, node, alloc_result, true, false); |
| 5888 | 6039 | IrInstruction *alloc_result_is_err = ir_build_test_err(irb, scope, node, alloc_result); |
| 5889 | 6040 | IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError"); |
| 5890 | 6041 | IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk"); |
| 5891 | | ir_build_cond_br(irb, scope, node, alloc_result_is_err, alloc_err_block, alloc_ok_block, is_comptime_false); |
| 6042 | ir_build_cond_br(irb, scope, node, alloc_result_is_err, alloc_err_block, alloc_ok_block, const_bool_false); |
| 5892 | 6043 | |
| 5893 | 6044 | ir_set_cursor_at_end_and_append_block(irb, alloc_err_block); |
| 5894 | 6045 | IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, alloc_result_ptr); |
| 5895 | 6046 | ir_build_coro_alloc_fail(irb, scope, node, err_val); |
| 5896 | 6047 | |
| 5897 | 6048 | ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block); |
| 5898 | | IrInstruction *unwrapped_mem_ptr = ir_build_unwrap_err_payload(irb, scope, node, alloc_result_ptr, false); |
| 6049 | coro_unwrapped_mem_ptr = ir_build_unwrap_err_payload(irb, scope, node, alloc_result_ptr, false); |
| 5899 | 6050 | Buf *ptr_field_name = buf_create_from_str("ptr"); |
| 5900 | | IrInstruction *coro_mem_ptr_field = ir_build_field_ptr(irb, scope, node, unwrapped_mem_ptr, ptr_field_name); |
| 6051 | IrInstruction *coro_mem_ptr_field = ir_build_field_ptr(irb, scope, node, coro_unwrapped_mem_ptr, |
| 6052 | ptr_field_name); |
| 5901 | 6053 | IrInstruction *coro_mem_ptr = ir_build_load_ptr(irb, scope, node, coro_mem_ptr_field); |
| 5902 | | ir_build_br(irb, scope, node, coro_begin_block, is_comptime_false); |
| 6054 | ir_build_br(irb, scope, node, coro_begin_block, const_bool_false); |
| 5903 | 6055 | |
| 5904 | 6056 | ir_set_cursor_at_end_and_append_block(irb, coro_begin_block); |
| 5905 | 6057 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); |
| ... | ... | @@ -5910,6 +6062,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 5910 | 6062 | incoming_values[1] = coro_mem_ptr; |
| 5911 | 6063 | IrInstruction *coro_mem = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); |
| 5912 | 6064 | irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem); |
| 6065 | irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal"); |
| 6066 | irb->exec->coro_normal_final = ir_create_basic_block(irb, scope, "CoroNormalFinal"); |
| 5913 | 6067 | } |
| 5914 | 6068 | |
| 5915 | 6069 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE); |
| ... | ... | @@ -5918,7 +6072,84 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 5918 | 6072 | return false; |
| 5919 | 6073 | |
| 5920 | 6074 | if (!instr_is_unreachable(result)) { |
| 5921 | | ir_mark_gen(ir_build_return(irb, scope, result->source_node, result)); |
| 6075 | ir_gen_async_return(irb, scope, result->source_node, result, true); |
| 6076 | } |
| 6077 | |
| 6078 | if (is_async) { |
| 6079 | IrBasicBlock *invalid_resume_block = ir_create_basic_block(irb, scope, "InvalidResume"); |
| 6080 | IrBasicBlock *final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup"); |
| 6081 | IrBasicBlock *suspend_block = ir_create_basic_block(irb, scope, "Suspend"); |
| 6082 | IrBasicBlock *check_free_block = ir_create_basic_block(irb, scope, "CheckFree"); |
| 6083 | |
| 6084 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_early_final); |
| 6085 | IrInstruction *const_bool_true = ir_build_const_bool(irb, scope, node, true); |
| 6086 | IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, nullptr, const_bool_true); |
| 6087 | IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2); |
| 6088 | cases[0].value = ir_build_const_u8(irb, scope, node, 0); |
| 6089 | cases[0].block = invalid_resume_block; |
| 6090 | cases[1].value = ir_build_const_u8(irb, scope, node, 1); |
| 6091 | cases[1].block = final_cleanup_block; |
| 6092 | ir_build_switch_br(irb, scope, node, suspend_code, suspend_block, 2, cases, const_bool_false); |
| 6093 | |
| 6094 | ir_set_cursor_at_end_and_append_block(irb, suspend_block); |
| 6095 | ir_build_coro_end(irb, scope, node); |
| 6096 | ir_build_return(irb, scope, node, irb->exec->coro_handle); |
| 6097 | |
| 6098 | ir_set_cursor_at_end_and_append_block(irb, invalid_resume_block); |
| 6099 | ir_build_unreachable(irb, scope, node); |
| 6100 | |
| 6101 | ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_normal_final); |
| 6102 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); |
| 6103 | |
| 6104 | ir_set_cursor_at_end_and_append_block(irb, final_cleanup_block); |
| 6105 | if (type_has_bits(return_type)) { |
| 6106 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); |
| 6107 | IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, result_ptr); |
| 6108 | IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, |
| 6109 | coro_result_field_ptr); |
| 6110 | IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node, |
| 6111 | fn_entry->type_entry->data.fn.fn_type_id.return_type); |
| 6112 | IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst); |
| 6113 | ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val); |
| 6114 | } |
| 6115 | ir_build_br(irb, scope, node, check_free_block, const_bool_false); |
| 6116 | |
| 6117 | ir_set_cursor_at_end_and_append_block(irb, check_free_block); |
| 6118 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); |
| 6119 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 6120 | incoming_blocks[0] = final_cleanup_block; |
| 6121 | incoming_values[0] = const_bool_false; |
| 6122 | incoming_blocks[1] = irb->exec->coro_normal_final; |
| 6123 | incoming_values[1] = const_bool_true; |
| 6124 | IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); |
| 6125 | IrInstruction *mem_to_free = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle); |
| 6126 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, mem_to_free); |
| 6127 | IrBasicBlock *dyn_free_block = ir_create_basic_block(irb, scope, "DynFree"); |
| 6128 | IrBasicBlock *end_free_block = ir_create_basic_block(irb, scope, "EndFree"); |
| 6129 | ir_build_cond_br(irb, scope, node, is_non_null, dyn_free_block, end_free_block, const_bool_false); |
| 6130 | |
| 6131 | ir_set_cursor_at_end_and_append_block(irb, dyn_free_block); |
| 6132 | Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME); |
| 6133 | IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, irb->exec->implicit_allocator_ptr, |
| 6134 | free_field_name); |
| 6135 | IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr); |
| 6136 | size_t arg_count = 2; |
| 6137 | IrInstruction **args = allocate<IrInstruction *>(arg_count); |
| 6138 | args[0] = irb->exec->implicit_allocator_ptr; // self |
| 6139 | args[1] = ir_build_load_ptr(irb, scope, node, coro_unwrapped_mem_ptr); // old_mem |
| 6140 | ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr); |
| 6141 | ir_build_br(irb, scope, node, end_free_block, const_bool_false); |
| 6142 | |
| 6143 | ir_set_cursor_at_end_and_append_block(irb, end_free_block); |
| 6144 | IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume"); |
| 6145 | ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, suspend_block, const_bool_false); |
| 6146 | |
| 6147 | ir_set_cursor_at_end_and_append_block(irb, resume_block); |
| 6148 | IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node, |
| 6149 | irb->exec->coro_awaiter_field_ptr, false); |
| 6150 | IrInstruction *awaiter_handle = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); |
| 6151 | ir_build_coro_resume(irb, scope, node, awaiter_handle); |
| 6152 | ir_build_br(irb, scope, node, suspend_block, const_bool_false); |
| 5922 | 6153 | } |
| 5923 | 6154 | |
| 5924 | 6155 | return true; |
| ... | ... | @@ -9514,8 +9745,11 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, |
| 9514 | 9745 | ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable")); |
| 9515 | 9746 | return ir_unreach_error(ira); |
| 9516 | 9747 | } |
| 9517 | | ir_build_return_from(&ira->new_irb, &return_instruction->base, casted_value); |
| 9518 | | return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable); |
| 9748 | IrInstruction *result = ir_build_return(&ira->new_irb, return_instruction->base.scope, |
| 9749 | return_instruction->base.source_node, casted_value); |
| 9750 | result->value.type = ira->codegen->builtin_types.entry_unreachable; |
| 9751 | ir_link_new_instruction(result, &return_instruction->base); |
| 9752 | return ir_finish_anal(ira, result->value.type); |
| 9519 | 9753 | } |
| 9520 | 9754 | |
| 9521 | 9755 | static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) { |
| ... | ... | @@ -16624,11 +16858,8 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr |
| 16624 | 16858 | |
| 16625 | 16859 | TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; |
| 16626 | 16860 | |
| 16627 | | if (!(target->value.type->id == TypeTableEntryIdPointer || |
| 16628 | | target->value.type->id == TypeTableEntryIdFn || |
| 16629 | | (target->value.type->id == TypeTableEntryIdMaybe && |
| 16630 | | (target->value.type->data.maybe.child_type->id == TypeTableEntryIdPointer || |
| 16631 | | target->value.type->data.maybe.child_type->id == TypeTableEntryIdFn)))) |
| 16861 | if (!(type_is_codegen_pointer(target->value.type) || (target->value.type->id == TypeTableEntryIdMaybe && |
| 16862 | type_is_codegen_pointer(target->value.type->data.maybe.child_type)))) |
| 16632 | 16863 | { |
| 16633 | 16864 | ir_add_error(ira, target, |
| 16634 | 16865 | buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name))); |
| ... | ... | @@ -16829,7 +17060,12 @@ static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructi |
| 16829 | 17060 | } |
| 16830 | 17061 | |
| 16831 | 17062 | static TypeTableEntry *ir_analyze_instruction_coro_id(IrAnalyze *ira, IrInstructionCoroId *instruction) { |
| 16832 | | IrInstruction *result = ir_build_coro_id(&ira->new_irb, instruction->base.scope, instruction->base.source_node); |
| 17063 | IrInstruction *promise_ptr = instruction->promise_ptr->other; |
| 17064 | if (type_is_invalid(promise_ptr->value.type)) |
| 17065 | return ira->codegen->builtin_types.entry_invalid; |
| 17066 | |
| 17067 | IrInstruction *result = ir_build_coro_id(&ira->new_irb, instruction->base.scope, instruction->base.source_node, |
| 17068 | promise_ptr); |
| 16833 | 17069 | ir_link_new_instruction(result, &instruction->base); |
| 16834 | 17070 | result->value.type = ira->codegen->builtin_types.entry_usize; |
| 16835 | 17071 | return result->value.type; |
| ... | ... | @@ -16889,6 +17125,63 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_fail(IrAnalyze *ira, Ir |
| 16889 | 17125 | return ir_finish_anal(ira, result->value.type); |
| 16890 | 17126 | } |
| 16891 | 17127 | |
| 17128 | static TypeTableEntry *ir_analyze_instruction_coro_suspend(IrAnalyze *ira, IrInstructionCoroSuspend *instruction) { |
| 17129 | IrInstruction *save_point = nullptr; |
| 17130 | if (instruction->save_point != nullptr) { |
| 17131 | save_point = instruction->save_point->other; |
| 17132 | if (type_is_invalid(save_point->value.type)) |
| 17133 | return ira->codegen->builtin_types.entry_invalid; |
| 17134 | } |
| 17135 | |
| 17136 | IrInstruction *is_final = instruction->is_final->other; |
| 17137 | if (type_is_invalid(is_final->value.type)) |
| 17138 | return ira->codegen->builtin_types.entry_invalid; |
| 17139 | |
| 17140 | IrInstruction *result = ir_build_coro_suspend(&ira->new_irb, instruction->base.scope, |
| 17141 | instruction->base.source_node, save_point, is_final); |
| 17142 | ir_link_new_instruction(result, &instruction->base); |
| 17143 | result->value.type = ira->codegen->builtin_types.entry_u8; |
| 17144 | return result->value.type; |
| 17145 | } |
| 17146 | |
| 17147 | static TypeTableEntry *ir_analyze_instruction_coro_end(IrAnalyze *ira, IrInstructionCoroEnd *instruction) { |
| 17148 | IrInstruction *result = ir_build_coro_end(&ira->new_irb, instruction->base.scope, |
| 17149 | instruction->base.source_node); |
| 17150 | ir_link_new_instruction(result, &instruction->base); |
| 17151 | result->value.type = ira->codegen->builtin_types.entry_void; |
| 17152 | return result->value.type; |
| 17153 | } |
| 17154 | |
| 17155 | static TypeTableEntry *ir_analyze_instruction_coro_free(IrAnalyze *ira, IrInstructionCoroFree *instruction) { |
| 17156 | IrInstruction *coro_id = instruction->coro_id->other; |
| 17157 | if (type_is_invalid(coro_id->value.type)) |
| 17158 | return ira->codegen->builtin_types.entry_invalid; |
| 17159 | |
| 17160 | IrInstruction *coro_handle = instruction->coro_handle->other; |
| 17161 | if (type_is_invalid(coro_handle->value.type)) |
| 17162 | return ira->codegen->builtin_types.entry_invalid; |
| 17163 | |
| 17164 | IrInstruction *result = ir_build_coro_free(&ira->new_irb, instruction->base.scope, |
| 17165 | instruction->base.source_node, coro_id, coro_handle); |
| 17166 | ir_link_new_instruction(result, &instruction->base); |
| 17167 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, false); |
| 17168 | result->value.type = get_maybe_type(ira->codegen, ptr_type); |
| 17169 | return result->value.type; |
| 17170 | } |
| 17171 | |
| 17172 | static TypeTableEntry *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) { |
| 17173 | IrInstruction *awaiter_handle = instruction->awaiter_handle->other; |
| 17174 | if (type_is_invalid(awaiter_handle->value.type)) |
| 17175 | return ira->codegen->builtin_types.entry_invalid; |
| 17176 | |
| 17177 | IrInstruction *result = ir_build_coro_resume(&ira->new_irb, instruction->base.scope, |
| 17178 | instruction->base.source_node, awaiter_handle); |
| 17179 | ir_link_new_instruction(result, &instruction->base); |
| 17180 | result->value.type = ira->codegen->builtin_types.entry_void; |
| 17181 | return result->value.type; |
| 17182 | } |
| 17183 | |
| 17184 | |
| 16892 | 17185 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 16893 | 17186 | switch (instruction->id) { |
| 16894 | 17187 | case IrInstructionIdInvalid: |
| ... | ... | @@ -17105,6 +17398,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17105 | 17398 | return ir_analyze_instruction_get_implicit_allocator(ira, (IrInstructionGetImplicitAllocator *)instruction); |
| 17106 | 17399 | case IrInstructionIdCoroAllocFail: |
| 17107 | 17400 | return ir_analyze_instruction_coro_alloc_fail(ira, (IrInstructionCoroAllocFail *)instruction); |
| 17401 | case IrInstructionIdCoroSuspend: |
| 17402 | return ir_analyze_instruction_coro_suspend(ira, (IrInstructionCoroSuspend *)instruction); |
| 17403 | case IrInstructionIdCoroEnd: |
| 17404 | return ir_analyze_instruction_coro_end(ira, (IrInstructionCoroEnd *)instruction); |
| 17405 | case IrInstructionIdCoroFree: |
| 17406 | return ir_analyze_instruction_coro_free(ira, (IrInstructionCoroFree *)instruction); |
| 17407 | case IrInstructionIdCoroResume: |
| 17408 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); |
| 17108 | 17409 | } |
| 17109 | 17410 | zig_unreachable(); |
| 17110 | 17411 | } |
| ... | ... | @@ -17134,7 +17435,10 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl |
| 17134 | 17435 | IrAnalyze *ira = allocate<IrAnalyze>(1); |
| 17135 | 17436 | old_exec->analysis = ira; |
| 17136 | 17437 | ira->codegen = codegen; |
| 17137 | | ira->explicit_return_type = expected_type; |
| 17438 | |
| 17439 | FnTableEntry *fn_entry = exec_fn_entry(old_exec); |
| 17440 | bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync; |
| 17441 | ira->explicit_return_type = is_async ? get_promise_type(codegen, expected_type) : expected_type; |
| 17138 | 17442 | |
| 17139 | 17443 | ira->old_irb.codegen = codegen; |
| 17140 | 17444 | ira->old_irb.exec = old_exec; |
| ... | ... | @@ -17222,6 +17526,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 17222 | 17526 | case IrInstructionIdCoroId: |
| 17223 | 17527 | case IrInstructionIdCoroBegin: |
| 17224 | 17528 | case IrInstructionIdCoroAllocFail: |
| 17529 | case IrInstructionIdCoroEnd: |
| 17530 | case IrInstructionIdCoroResume: |
| 17225 | 17531 | return true; |
| 17226 | 17532 | |
| 17227 | 17533 | case IrInstructionIdPhi: |
| ... | ... | @@ -17299,6 +17605,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 17299 | 17605 | case IrInstructionIdGetImplicitAllocator: |
| 17300 | 17606 | case IrInstructionIdCoroAlloc: |
| 17301 | 17607 | case IrInstructionIdCoroSize: |
| 17608 | case IrInstructionIdCoroSuspend: |
| 17609 | case IrInstructionIdCoroFree: |
| 17302 | 17610 | return false; |
| 17303 | 17611 | |
| 17304 | 17612 | case IrInstructionIdAsm: |