| ... | ... | @@ -45,12 +45,6 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) { |
| 45 | 45 | return { true, is_const, is_volatile }; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | | static const char * ASYNC_ALLOC_FIELD_NAME = "allocFn"; |
| 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"; |
| 53 | | |
| 54 | 48 | enum ConstCastResultId { |
| 55 | 49 | ConstCastResultIdOk, |
| 56 | 50 | ConstCastResultIdErrSet, |
| ... | ... | @@ -697,6 +691,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) { |
| 697 | 691 | return IrInstructionIdCoroSave; |
| 698 | 692 | } |
| 699 | 693 | |
| 694 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroPromise *) { |
| 695 | return IrInstructionIdCoroPromise; |
| 696 | } |
| 697 | |
| 700 | 698 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) { |
| 701 | 699 | return IrInstructionIdCoroAllocHelper; |
| 702 | 700 | } |
| ... | ... | @@ -705,6 +703,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) { |
| 705 | 703 | return IrInstructionIdAtomicRmw; |
| 706 | 704 | } |
| 707 | 705 | |
| 706 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) { |
| 707 | return IrInstructionIdPromiseResultType; |
| 708 | } |
| 709 | |
| 708 | 710 | template<typename T> |
| 709 | 711 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 710 | 712 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -937,25 +939,19 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast |
| 937 | 939 | static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 938 | 940 | TypeTableEntry *return_type) |
| 939 | 941 | { |
| 940 | | TypeTableEntry *awaiter_handle_type = get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise); |
| 941 | | TypeTableEntry *result_ptr_type = get_pointer_to_type(irb->codegen, return_type, false); |
| 942 | | const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME}; |
| 943 | | TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type}; |
| 944 | | size_t field_count = type_has_bits(result_ptr_type) ? 3 : 1; |
| 945 | | TypeTableEntry *struct_type = get_struct_type(irb->codegen, "AsyncFramePromise", field_names, field_types, |
| 946 | | field_count); |
| 942 | TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type); |
| 947 | 943 | |
| 948 | 944 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node); |
| 949 | 945 | const_instruction->base.value.type = struct_type; |
| 950 | 946 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 951 | | const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(field_count); |
| 952 | | const_instruction->base.value.data.x_struct.fields[0].type = awaiter_handle_type; |
| 947 | const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count); |
| 948 | const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry; |
| 953 | 949 | const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic; |
| 954 | 950 | const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr; |
| 955 | | if (field_count == 3) { |
| 951 | if (struct_type->data.structure.src_field_count > 1) { |
| 956 | 952 | const_instruction->base.value.data.x_struct.fields[1].type = return_type; |
| 957 | 953 | const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef; |
| 958 | | const_instruction->base.value.data.x_struct.fields[2].type = result_ptr_type; |
| 954 | const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry; |
| 959 | 955 | const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef; |
| 960 | 956 | } |
| 961 | 957 | return &const_instruction->base; |
| ... | ... | @@ -2605,6 +2601,17 @@ static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode * |
| 2605 | 2601 | return &instruction->base; |
| 2606 | 2602 | } |
| 2607 | 2603 | |
| 2604 | static IrInstruction *ir_build_coro_promise(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2605 | IrInstruction *coro_handle) |
| 2606 | { |
| 2607 | IrInstructionCoroPromise *instruction = ir_build_instruction<IrInstructionCoroPromise>(irb, scope, source_node); |
| 2608 | instruction->coro_handle = coro_handle; |
| 2609 | |
| 2610 | ir_ref_instruction(coro_handle, irb->current_basic_block); |
| 2611 | |
| 2612 | return &instruction->base; |
| 2613 | } |
| 2614 | |
| 2608 | 2615 | static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2609 | 2616 | IrInstruction *alloc_fn, IrInstruction *coro_size) |
| 2610 | 2617 | { |
| ... | ... | @@ -2640,6 +2647,17 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode |
| 2640 | 2647 | return &instruction->base; |
| 2641 | 2648 | } |
| 2642 | 2649 | |
| 2650 | static IrInstruction *ir_build_promise_result_type(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2651 | IrInstruction *promise_type) |
| 2652 | { |
| 2653 | IrInstructionPromiseResultType *instruction = ir_build_instruction<IrInstructionPromiseResultType>(irb, scope, source_node); |
| 2654 | instruction->promise_type = promise_type; |
| 2655 | |
| 2656 | ir_ref_instruction(promise_type, irb->current_basic_block); |
| 2657 | |
| 2658 | return &instruction->base; |
| 2659 | } |
| 2660 | |
| 2643 | 2661 | static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { |
| 2644 | 2662 | results[ReturnKindUnconditional] = 0; |
| 2645 | 2663 | results[ReturnKindError] = 0; |
| ... | ... | @@ -5944,7 +5962,93 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast |
| 5944 | 5962 | if (target_inst == irb->codegen->invalid_instruction) |
| 5945 | 5963 | return irb->codegen->invalid_instruction; |
| 5946 | 5964 | |
| 5947 | | zig_panic("TODO: generate await expr"); |
| 5965 | FnTableEntry *fn_entry = exec_fn_entry(irb->exec); |
| 5966 | if (!fn_entry) { |
| 5967 | add_node_error(irb->codegen, node, buf_sprintf("await outside function definition")); |
| 5968 | return irb->codegen->invalid_instruction; |
| 5969 | } |
| 5970 | if (fn_entry->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync) { |
| 5971 | add_node_error(irb->codegen, node, buf_sprintf("await in non-async function")); |
| 5972 | return irb->codegen->invalid_instruction; |
| 5973 | } |
| 5974 | |
| 5975 | ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(parent_scope); |
| 5976 | if (scope_defer_expr) { |
| 5977 | if (!scope_defer_expr->reported_err) { |
| 5978 | add_node_error(irb->codegen, node, buf_sprintf("cannot await inside defer expression")); |
| 5979 | scope_defer_expr->reported_err = true; |
| 5980 | } |
| 5981 | return irb->codegen->invalid_instruction; |
| 5982 | } |
| 5983 | |
| 5984 | Scope *outer_scope = irb->exec->begin_scope; |
| 5985 | |
| 5986 | IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, parent_scope, node, target_inst); |
| 5987 | Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); |
| 5988 | IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name); |
| 5989 | |
| 5990 | Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME); |
| 5991 | IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, |
| 5992 | awaiter_handle_field_name); |
| 5993 | |
| 5994 | IrInstruction *const_bool_false = ir_build_const_bool(irb, parent_scope, node, false); |
| 5995 | VariableTableEntry *result_var = ir_create_var(irb, node, parent_scope, nullptr, |
| 5996 | false, false, true, const_bool_false); |
| 5997 | IrInstruction *undefined_value = ir_build_const_undefined(irb, parent_scope, node); |
| 5998 | IrInstruction *target_promise_type = ir_build_typeof(irb, parent_scope, node, target_inst); |
| 5999 | IrInstruction *promise_result_type = ir_build_promise_result_type(irb, parent_scope, node, target_promise_type); |
| 6000 | ir_build_var_decl(irb, parent_scope, node, result_var, promise_result_type, nullptr, undefined_value); |
| 6001 | IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, parent_scope, node, result_var, false, false); |
| 6002 | ir_build_store_ptr(irb, parent_scope, node, result_ptr_field_ptr, my_result_var_ptr); |
| 6003 | IrInstruction *save_token = ir_build_coro_save(irb, parent_scope, node, irb->exec->coro_handle); |
| 6004 | IrInstruction *promise_type_val = ir_build_const_type(irb, parent_scope, node, |
| 6005 | get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); |
| 6006 | IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, parent_scope, node, |
| 6007 | promise_type_val, awaiter_field_ptr, nullptr, irb->exec->coro_handle, nullptr, |
| 6008 | AtomicRmwOp_xchg, AtomicOrderSeqCst); |
| 6009 | IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle); |
| 6010 | IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend"); |
| 6011 | IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend"); |
| 6012 | IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge"); |
| 6013 | ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false); |
| 6014 | |
| 6015 | ir_set_cursor_at_end_and_append_block(irb, no_suspend_block); |
| 6016 | Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); |
| 6017 | IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name); |
| 6018 | IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr); |
| 6019 | ir_build_cancel(irb, parent_scope, node, target_inst); |
| 6020 | ir_build_br(irb, parent_scope, node, merge_block, const_bool_false); |
| 6021 | |
| 6022 | ir_set_cursor_at_end_and_append_block(irb, yes_suspend_block); |
| 6023 | ir_build_coro_resume(irb, parent_scope, node, target_inst); |
| 6024 | IrInstruction *suspend_code = ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false); |
| 6025 | IrBasicBlock *cleanup_block = ir_create_basic_block(irb, parent_scope, "SuspendCleanup"); |
| 6026 | IrBasicBlock *resume_block = ir_create_basic_block(irb, parent_scope, "SuspendResume"); |
| 6027 | |
| 6028 | IrInstructionSwitchBrCase *cases = allocate<IrInstructionSwitchBrCase>(2); |
| 6029 | cases[0].value = ir_build_const_u8(irb, parent_scope, node, 0); |
| 6030 | cases[0].block = resume_block; |
| 6031 | cases[1].value = ir_build_const_u8(irb, parent_scope, node, 1); |
| 6032 | cases[1].block = cleanup_block; |
| 6033 | ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block, |
| 6034 | 2, cases, const_bool_false); |
| 6035 | |
| 6036 | ir_set_cursor_at_end_and_append_block(irb, cleanup_block); |
| 6037 | ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); |
| 6038 | ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false); |
| 6039 | |
| 6040 | ir_set_cursor_at_end_and_append_block(irb, resume_block); |
| 6041 | IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr); |
| 6042 | ir_build_br(irb, parent_scope, node, merge_block, const_bool_false); |
| 6043 | |
| 6044 | ir_set_cursor_at_end_and_append_block(irb, merge_block); |
| 6045 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); |
| 6046 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); |
| 6047 | incoming_blocks[0] = resume_block; |
| 6048 | incoming_values[0] = yes_suspend_result; |
| 6049 | incoming_blocks[1] = no_suspend_block; |
| 6050 | incoming_values[1] = no_suspend_result; |
| 6051 | return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); |
| 5948 | 6052 | } |
| 5949 | 6053 | |
| 5950 | 6054 | static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) { |
| ... | ... | @@ -17399,6 +17503,29 @@ static TypeTableEntry *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstru |
| 17399 | 17503 | return result->value.type; |
| 17400 | 17504 | } |
| 17401 | 17505 | |
| 17506 | static TypeTableEntry *ir_analyze_instruction_coro_promise(IrAnalyze *ira, IrInstructionCoroPromise *instruction) { |
| 17507 | IrInstruction *coro_handle = instruction->coro_handle->other; |
| 17508 | if (type_is_invalid(coro_handle->value.type)) |
| 17509 | return ira->codegen->builtin_types.entry_invalid; |
| 17510 | |
| 17511 | if (coro_handle->value.type->id != TypeTableEntryIdPromise || |
| 17512 | coro_handle->value.type->data.promise.result_type == nullptr) |
| 17513 | { |
| 17514 | ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", |
| 17515 | buf_ptr(&coro_handle->value.type->name))); |
| 17516 | return ira->codegen->builtin_types.entry_invalid; |
| 17517 | } |
| 17518 | |
| 17519 | TypeTableEntry *coro_frame_type = get_promise_frame_type(ira->codegen, |
| 17520 | coro_handle->value.type->data.promise.result_type); |
| 17521 | |
| 17522 | IrInstruction *result = ir_build_coro_promise(&ira->new_irb, instruction->base.scope, |
| 17523 | instruction->base.source_node, coro_handle); |
| 17524 | ir_link_new_instruction(result, &instruction->base); |
| 17525 | result->value.type = get_pointer_to_type(ira->codegen, coro_frame_type, false); |
| 17526 | return result->value.type; |
| 17527 | } |
| 17528 | |
| 17402 | 17529 | static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) { |
| 17403 | 17530 | IrInstruction *alloc_fn = instruction->alloc_fn->other; |
| 17404 | 17531 | if (type_is_invalid(alloc_fn->value.type)) |
| ... | ... | @@ -17492,6 +17619,22 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr |
| 17492 | 17619 | return result->value.type; |
| 17493 | 17620 | } |
| 17494 | 17621 | |
| 17622 | static TypeTableEntry *ir_analyze_instruction_promise_result_type(IrAnalyze *ira, IrInstructionPromiseResultType *instruction) { |
| 17623 | TypeTableEntry *promise_type = ir_resolve_type(ira, instruction->promise_type->other); |
| 17624 | if (type_is_invalid(promise_type)) |
| 17625 | return ira->codegen->builtin_types.entry_invalid; |
| 17626 | |
| 17627 | if (promise_type->id != TypeTableEntryIdPromise || promise_type->data.promise.result_type == nullptr) { |
| 17628 | ir_add_error(ira, &instruction->base, buf_sprintf("expected promise->T, found '%s'", |
| 17629 | buf_ptr(&promise_type->name))); |
| 17630 | return ira->codegen->builtin_types.entry_invalid; |
| 17631 | } |
| 17632 | |
| 17633 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 17634 | out_val->data.x_type = promise_type->data.promise.result_type; |
| 17635 | return ira->codegen->builtin_types.entry_type; |
| 17636 | } |
| 17637 | |
| 17495 | 17638 | |
| 17496 | 17639 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 17497 | 17640 | switch (instruction->id) { |
| ... | ... | @@ -17719,10 +17862,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 17719 | 17862 | return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction); |
| 17720 | 17863 | case IrInstructionIdCoroSave: |
| 17721 | 17864 | return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction); |
| 17865 | case IrInstructionIdCoroPromise: |
| 17866 | return ir_analyze_instruction_coro_promise(ira, (IrInstructionCoroPromise *)instruction); |
| 17722 | 17867 | case IrInstructionIdCoroAllocHelper: |
| 17723 | 17868 | return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction); |
| 17724 | 17869 | case IrInstructionIdAtomicRmw: |
| 17725 | 17870 | return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction); |
| 17871 | case IrInstructionIdPromiseResultType: |
| 17872 | return ir_analyze_instruction_promise_result_type(ira, (IrInstructionPromiseResultType *)instruction); |
| 17726 | 17873 | } |
| 17727 | 17874 | zig_unreachable(); |
| 17728 | 17875 | } |
| ... | ... | @@ -17927,6 +18074,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 17927 | 18074 | case IrInstructionIdCoroSuspend: |
| 17928 | 18075 | case IrInstructionIdCoroFree: |
| 17929 | 18076 | case IrInstructionIdAtomicRmw: |
| 18077 | case IrInstructionIdCoroPromise: |
| 18078 | case IrInstructionIdPromiseResultType: |
| 17930 | 18079 | return false; |
| 17931 | 18080 | |
| 17932 | 18081 | case IrInstructionIdAsm: |