authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-23 03:03:06-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-23 03:03:06-05:00
log99985ad6fc0ff4ff09c0284c40023a9c826f8108
treec2aaeaf3626e7cc4d02eb81273c49974034ee4ca
parentca1b77b2d51408589659f652b1b1dbe2a25e149f

implement Zig IR for async functions

See #727

6 files changed, 467 insertions(+), 54 deletions(-)

src/all_types.hpp+36
...@@ -56,7 +56,13 @@ struct IrExecutable {...@@ -56,7 +56,13 @@ struct IrExecutable {
56 IrAnalyze *analysis;56 IrAnalyze *analysis;
57 Scope *begin_scope;57 Scope *begin_scope;
58 ZigList<Tld *> tld_list;58 ZigList<Tld *> tld_list;
59
59 IrInstruction *coro_handle;60 IrInstruction *coro_handle;
61 IrInstruction *coro_awaiter_field_ptr;
62 IrInstruction *coro_result_ptr_field_ptr;
63 IrInstruction *implicit_allocator_ptr;
64 IrBasicBlock *coro_early_final;
65 IrBasicBlock *coro_normal_final;
60};66};
6167
62enum OutType {68enum OutType {
...@@ -1968,6 +1974,10 @@ enum IrInstructionId {...@@ -1968,6 +1974,10 @@ enum IrInstructionId {
1968 IrInstructionIdCoroSize,1974 IrInstructionIdCoroSize,
1969 IrInstructionIdCoroBegin,1975 IrInstructionIdCoroBegin,
1970 IrInstructionIdCoroAllocFail,1976 IrInstructionIdCoroAllocFail,
1977 IrInstructionIdCoroSuspend,
1978 IrInstructionIdCoroEnd,
1979 IrInstructionIdCoroFree,
1980 IrInstructionIdCoroResume,
1971};1981};
19721982
1973struct IrInstruction {1983struct IrInstruction {
...@@ -2819,6 +2829,8 @@ struct IrInstructionGetImplicitAllocator {...@@ -2819,6 +2829,8 @@ struct IrInstructionGetImplicitAllocator {
28192829
2820struct IrInstructionCoroId {2830struct IrInstructionCoroId {
2821 IrInstruction base;2831 IrInstruction base;
2832
2833 IrInstruction *promise_ptr;
2822};2834};
28232835
2824struct IrInstructionCoroAlloc {2836struct IrInstructionCoroAlloc {
...@@ -2844,6 +2856,30 @@ struct IrInstructionCoroAllocFail {...@@ -2844,6 +2856,30 @@ struct IrInstructionCoroAllocFail {
2844 IrInstruction *err_val;2856 IrInstruction *err_val;
2845};2857};
28462858
2859struct IrInstructionCoroSuspend {
2860 IrInstruction base;
2861
2862 IrInstruction *save_point;
2863 IrInstruction *is_final;
2864};
2865
2866struct IrInstructionCoroEnd {
2867 IrInstruction base;
2868};
2869
2870struct IrInstructionCoroFree {
2871 IrInstruction base;
2872
2873 IrInstruction *coro_id;
2874 IrInstruction *coro_handle;
2875};
2876
2877struct IrInstructionCoroResume {
2878 IrInstruction base;
2879
2880 IrInstruction *awaiter_handle;
2881};
2882
2847static const size_t slice_ptr_index = 0;2883static const size_t slice_ptr_index = 0;
2848static const size_t slice_len_index = 1;2884static const size_t slice_len_index = 1;
28492885
src/analyze.cpp+6-4
...@@ -475,9 +475,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -475,9 +475,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
475 if (child_type->zero_bits) {475 if (child_type->zero_bits) {
476 entry->type_ref = LLVMInt1Type();476 entry->type_ref = LLVMInt1Type();
477 entry->di_type = g->builtin_types.entry_bool->di_type;477 entry->di_type = g->builtin_types.entry_bool->di_type;
478 } else if (child_type->id == TypeTableEntryIdPointer ||478 } else if (type_is_codegen_pointer(child_type)) {
479 child_type->id == TypeTableEntryIdFn)
480 {
481 // this is an optimization but also is necessary for calling C479 // this is an optimization but also is necessary for calling C
482 // functions where all pointers are maybe pointers480 // functions where all pointers are maybe pointers
483 // function types are technically pointers481 // function types are technically pointers
...@@ -1262,7 +1260,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {...@@ -1262,7 +1260,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
1262 case TypeTableEntryIdMaybe:1260 case TypeTableEntryIdMaybe:
1263 {1261 {
1264 TypeTableEntry *child_type = type_entry->data.maybe.child_type;1262 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
1265 return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;1263 return type_is_codegen_pointer(child_type);
1266 }1264 }
1267 case TypeTableEntryIdEnum:1265 case TypeTableEntryIdEnum:
1268 return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;1266 return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
...@@ -1673,6 +1671,8 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f...@@ -1673,6 +1671,8 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
1673 field->src_index = i;1671 field->src_index = i;
1674 field->gen_index = i;1672 field->gen_index = i;
16751673
1674 assert(type_has_bits(field->type_entry));
1675
1676 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);1676 auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
1677 assert(prev_entry == nullptr);1677 assert(prev_entry == nullptr);
1678 }1678 }
...@@ -3669,9 +3669,11 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {...@@ -3669,9 +3669,11 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
3669TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) {3669TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) {
3670 if (type->id == TypeTableEntryIdPointer) return type;3670 if (type->id == TypeTableEntryIdPointer) return type;
3671 if (type->id == TypeTableEntryIdFn) return type;3671 if (type->id == TypeTableEntryIdFn) return type;
3672 if (type->id == TypeTableEntryIdPromise) return type;
3672 if (type->id == TypeTableEntryIdMaybe) {3673 if (type->id == TypeTableEntryIdMaybe) {
3673 if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type;3674 if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type;
3674 if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type;3675 if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type;
3676 if (type->data.maybe.child_type->id == TypeTableEntryIdPromise) return type->data.maybe.child_type;
3675 }3677 }
3676 return nullptr;3678 return nullptr;
3677}3679}
src/analyze.hpp+1
...@@ -51,6 +51,7 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);...@@ -51,6 +51,7 @@ VariableTableEntry *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
51Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);51Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
52void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);52void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);
53bool type_is_codegen_pointer(TypeTableEntry *type);53bool type_is_codegen_pointer(TypeTableEntry *type);
54
54TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type);55TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type);
55uint32_t get_ptr_align(TypeTableEntry *type);56uint32_t get_ptr_align(TypeTableEntry *type);
56TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);57TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
src/codegen.cpp+34-12
...@@ -542,7 +542,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {...@@ -542,7 +542,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
542542
543 if (!type_has_bits(return_type)) {543 if (!type_has_bits(return_type)) {
544 // nothing to do544 // nothing to do
545 } else if (return_type->id == TypeTableEntryIdPointer || return_type->id == TypeTableEntryIdFn) {545 } else if (type_is_codegen_pointer(return_type)) {
546 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");546 addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
547 } else if (handle_is_ptr(return_type) &&547 } else if (handle_is_ptr(return_type) &&
548 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))548 calling_convention_does_first_arg_return(fn_type->data.fn.fn_type_id.cc))
...@@ -2789,7 +2789,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLV...@@ -2789,7 +2789,7 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLV
2789 if (child_type->zero_bits) {2789 if (child_type->zero_bits) {
2790 return maybe_handle;2790 return maybe_handle;
2791 } else {2791 } else {
2792 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);2792 bool maybe_is_ptr = type_is_codegen_pointer(child_type);
2793 if (maybe_is_ptr) {2793 if (maybe_is_ptr) {
2794 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");2794 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
2795 } else {2795 } else {
...@@ -2829,7 +2829,7 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,...@@ -2829,7 +2829,7 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
2829 if (child_type->zero_bits) {2829 if (child_type->zero_bits) {
2830 return nullptr;2830 return nullptr;
2831 } else {2831 } else {
2832 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);2832 bool maybe_is_ptr = type_is_codegen_pointer(child_type);
2833 if (maybe_is_ptr) {2833 if (maybe_is_ptr) {
2834 return maybe_ptr;2834 return maybe_ptr;
2835 } else {2835 } else {
...@@ -3052,6 +3052,10 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I...@@ -3052,6 +3052,10 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I
3052 {3052 {
3053 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;3053 align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment;
3054 ptr_val = target_val;3054 ptr_val = target_val;
3055 } else if (target_type->id == TypeTableEntryIdMaybe &&
3056 target_type->data.maybe.child_type->id == TypeTableEntryIdPromise)
3057 {
3058 zig_panic("TODO audit this function");
3055 } else if (target_type->id == TypeTableEntryIdStruct && target_type->data.structure.is_slice) {3059 } else if (target_type->id == TypeTableEntryIdStruct && target_type->data.structure.is_slice) {
3056 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;3060 TypeTableEntry *slice_ptr_type = target_type->data.structure.fields[slice_ptr_index].type_entry;
3057 align_bytes = slice_ptr_type->data.pointer.alignment;3061 align_bytes = slice_ptr_type->data.pointer.alignment;
...@@ -3522,9 +3526,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I...@@ -3522,9 +3526,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
3522 }3526 }
35233527
3524 LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);3528 LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
3525 if (child_type->id == TypeTableEntryIdPointer ||3529 if (type_is_codegen_pointer(child_type)) {
3526 child_type->id == TypeTableEntryIdFn)
3527 {
3528 return payload_val;3530 return payload_val;
3529 }3531 }
35303532
...@@ -3716,6 +3718,22 @@ static LLVMValueRef ir_render_coro_alloc_fail(CodeGen *g, IrExecutable *executab...@@ -3716,6 +3718,22 @@ static LLVMValueRef ir_render_coro_alloc_fail(CodeGen *g, IrExecutable *executab
3716 zig_panic("TODO ir_render_coro_alloc_fail");3718 zig_panic("TODO ir_render_coro_alloc_fail");
3717}3719}
37183720
3721static LLVMValueRef ir_render_coro_suspend(CodeGen *g, IrExecutable *executable, IrInstructionCoroSuspend *instruction) {
3722 zig_panic("TODO ir_render_coro_suspend");
3723}
3724
3725static LLVMValueRef ir_render_coro_end(CodeGen *g, IrExecutable *executable, IrInstructionCoroEnd *instruction) {
3726 zig_panic("TODO ir_render_coro_end");
3727}
3728
3729static LLVMValueRef ir_render_coro_free(CodeGen *g, IrExecutable *executable, IrInstructionCoroFree *instruction) {
3730 zig_panic("TODO ir_render_coro_free");
3731}
3732
3733static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable, IrInstructionCoroResume *instruction) {
3734 zig_panic("TODO ir_render_coro_resume");
3735}
3736
3719static void set_debug_location(CodeGen *g, IrInstruction *instruction) {3737static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
3720 AstNode *source_node = instruction->source_node;3738 AstNode *source_node = instruction->source_node;
3721 Scope *scope = instruction->scope;3739 Scope *scope = instruction->scope;
...@@ -3911,6 +3929,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -3911,6 +3929,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3911 return ir_render_coro_begin(g, executable, (IrInstructionCoroBegin *)instruction);3929 return ir_render_coro_begin(g, executable, (IrInstructionCoroBegin *)instruction);
3912 case IrInstructionIdCoroAllocFail:3930 case IrInstructionIdCoroAllocFail:
3913 return ir_render_coro_alloc_fail(g, executable, (IrInstructionCoroAllocFail *)instruction);3931 return ir_render_coro_alloc_fail(g, executable, (IrInstructionCoroAllocFail *)instruction);
3932 case IrInstructionIdCoroSuspend:
3933 return ir_render_coro_suspend(g, executable, (IrInstructionCoroSuspend *)instruction);
3934 case IrInstructionIdCoroEnd:
3935 return ir_render_coro_end(g, executable, (IrInstructionCoroEnd *)instruction);
3936 case IrInstructionIdCoroFree:
3937 return ir_render_coro_free(g, executable, (IrInstructionCoroFree *)instruction);
3938 case IrInstructionIdCoroResume:
3939 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
3914 }3940 }
3915 zig_unreachable();3941 zig_unreachable();
3916}3942}
...@@ -4155,9 +4181,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -4155,9 +4181,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
4155 TypeTableEntry *child_type = type_entry->data.maybe.child_type;4181 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
4156 if (child_type->zero_bits) {4182 if (child_type->zero_bits) {
4157 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);4183 return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false);
4158 } else if (child_type->id == TypeTableEntryIdPointer ||4184 } else if (type_is_codegen_pointer(child_type)) {
4159 child_type->id == TypeTableEntryIdFn)
4160 {
4161 if (const_val->data.x_maybe) {4185 if (const_val->data.x_maybe) {
4162 return gen_const_val(g, const_val->data.x_maybe, "");4186 return gen_const_val(g, const_val->data.x_maybe, "");
4163 } else {4187 } else {
...@@ -6085,9 +6109,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf...@@ -6085,9 +6109,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
6085 if (child_type->zero_bits) {6109 if (child_type->zero_bits) {
6086 buf_init_from_str(out_buf, "bool");6110 buf_init_from_str(out_buf, "bool");
6087 return;6111 return;
6088 } else if (child_type->id == TypeTableEntryIdPointer ||6112 } else if (type_is_codegen_pointer(child_type)) {
6089 child_type->id == TypeTableEntryIdFn)
6090 {
6091 return get_c_type(g, gen_h, child_type, out_buf);6113 return get_c_type(g, gen_h, child_type, out_buf);
6092 } else {6114 } else {
6093 zig_unreachable();6115 zig_unreachable();
src/ir.cpp+345-37
...@@ -46,7 +46,10 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {...@@ -46,7 +46,10 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {
46}46}
4747
48static const char * ASYNC_ALLOC_FIELD_NAME = "allocFn";48static const char * ASYNC_ALLOC_FIELD_NAME = "allocFn";
49//static const char * ASYNC_FREE_FIELD_NAME = "freeFn";49static const char * ASYNC_FREE_FIELD_NAME = "freeFn";
50static const char * AWAITER_HANDLE_FIELD_NAME = "awaiter_handle";
51static const char * RESULT_FIELD_NAME = "result";
52static const char * RESULT_PTR_FIELD_NAME = "result_ptr";
5053
51enum ConstCastResultId {54enum ConstCastResultId {
52 ConstCastResultIdOk,55 ConstCastResultIdOk,
...@@ -672,6 +675,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocFail *)...@@ -672,6 +675,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocFail *)
672 return IrInstructionIdCoroAllocFail;675 return IrInstructionIdCoroAllocFail;
673}676}
674677
678static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSuspend *) {
679 return IrInstructionIdCoroSuspend;
680}
681
682static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroEnd *) {
683 return IrInstructionIdCoroEnd;
684}
685
686static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroFree *) {
687 return IrInstructionIdCoroFree;
688}
689
690static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroResume *) {
691 return IrInstructionIdCoroResume;
692}
693
675template<typename T>694template<typename T>
676static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {695static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
677 T *special_instruction = allocate<T>(1);696 T *special_instruction = allocate<T>(1);
...@@ -743,14 +762,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou...@@ -743,14 +762,6 @@ static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *sou
743 return &return_instruction->base;762 return &return_instruction->base;
744}763}
745764
746static 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
754static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node,765static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node,
755 TypeTableEntry *type_entry)766 TypeTableEntry *type_entry)
756{767{
...@@ -822,6 +833,14 @@ static IrInstruction *ir_build_const_u29(IrBuilder *irb, Scope *scope, AstNode *...@@ -822,6 +833,14 @@ static IrInstruction *ir_build_const_u29(IrBuilder *irb, Scope *scope, AstNode *
822 return &const_instruction->base;833 return &const_instruction->base;
823}834}
824835
836static 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
825static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,844static IrInstruction *ir_create_const_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
826 TypeTableEntry *type_entry)845 TypeTableEntry *type_entry)
827{846{
...@@ -909,6 +928,33 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast...@@ -909,6 +928,33 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
909 return &const_instruction->base;928 return &const_instruction->base;
910}929}
911930
931static 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
912static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,958static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
913 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)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,8 +2497,11 @@ static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *sco
2451 return &instruction->base;2497 return &instruction->base;
2452}2498}
24532499
2454static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node) {2500static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *promise_ptr) {
2455 IrInstructionCoroId *instruction = ir_build_instruction<IrInstructionCoroId>(irb, scope, source_node);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);
24562505
2457 return &instruction->base;2506 return &instruction->base;
2458}2507}
...@@ -2494,6 +2543,48 @@ static IrInstruction *ir_build_coro_alloc_fail(IrBuilder *irb, Scope *scope, Ast...@@ -2494,6 +2543,48 @@ static IrInstruction *ir_build_coro_alloc_fail(IrBuilder *irb, Scope *scope, Ast
2494 return &instruction->base;2543 return &instruction->base;
2495}2544}
24962545
2546static 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
2559static 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
2564static 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
2577static 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
2497static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2588static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2498 results[ReturnKindUnconditional] = 0;2589 results[ReturnKindUnconditional] = 0;
2499 results[ReturnKindError] = 0;2590 results[ReturnKindError] = 0;
...@@ -2566,6 +2657,29 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {...@@ -2566,6 +2657,29 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
2566 return nullptr;2657 return nullptr;
2567}2658}
25682659
2660static 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
2569static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2683static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2570 assert(node->type == NodeTypeReturnExpr);2684 assert(node->type == NodeTypeReturnExpr);
25712685
...@@ -2615,18 +2729,22 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2615,18 +2729,22 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2615 }2729 }
26162730
2617 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));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");
26182733
2619 ir_set_cursor_at_end_and_append_block(irb, err_block);2734 ir_set_cursor_at_end_and_append_block(irb, err_block);
2620 ir_gen_defers_for_block(irb, scope, outer_scope, true);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);
26222737
2623 ir_set_cursor_at_end_and_append_block(irb, ok_block);2738 ir_set_cursor_at_end_and_append_block(irb, ok_block);
2624 ir_gen_defers_for_block(irb, scope, outer_scope, false);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 } else {2744 } else {
2627 // generate unconditional defers2745 // generate unconditional defers
2628 ir_gen_defers_for_block(irb, scope, outer_scope, false);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 case ReturnKindError:2750 case ReturnKindError:
...@@ -2646,7 +2764,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2646,7 +2764,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2646 ir_set_cursor_at_end_and_append_block(irb, return_block);2764 ir_set_cursor_at_end_and_append_block(irb, return_block);
2647 ir_gen_defers_for_block(irb, scope, outer_scope, true);2765 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2648 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);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);
26502768
2651 ir_set_cursor_at_end_and_append_block(irb, continue_block);2769 ir_set_cursor_at_end_and_append_block(irb, continue_block);
2652 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);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,6 +5960,7 @@ static void invalidate_exec(IrExecutable *exec) {
5842 invalidate_exec(exec->source_exec);5960 invalidate_exec(exec->source_exec);
5843}5961}
58445962
5963
5845bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) {5964bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) {
5846 assert(node->owner);5965 assert(node->owner);
58475966
...@@ -5858,48 +5977,81 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -5858,48 +5977,81 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
58585977
5859 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);5978 FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
5860 bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;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 if (is_async) {5988 if (is_async) {
5862 IrInstruction *is_comptime_false = ir_build_const_bool(irb, scope, node, false);5989 // create the coro promise
5863 IrInstruction *coro_id = ir_build_coro_id(irb, scope, node);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 IrInstruction *need_dyn_alloc = ir_build_coro_alloc(irb, scope, node, coro_id);6015 IrInstruction *need_dyn_alloc = ir_build_coro_alloc(irb, scope, node, coro_id);
5865 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);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 IrInstruction *null_ptr = ir_build_int_to_ptr(irb, scope, node, u8_ptr_type, zero);6017 IrInstruction *null_ptr = ir_build_int_to_ptr(irb, scope, node, u8_ptr_type, zero);
58696018
5870 IrBasicBlock *dyn_alloc_block = ir_create_basic_block(irb, scope, "DynAlloc");6019 IrBasicBlock *dyn_alloc_block = ir_create_basic_block(irb, scope, "DynAlloc");
5871 IrBasicBlock *coro_begin_block = ir_create_basic_block(irb, scope, "CoroBegin");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);
58736022
5874 ir_set_cursor_at_end_and_append_block(irb, dyn_alloc_block);6023 ir_set_cursor_at_end_and_append_block(irb, dyn_alloc_block);
5875 IrInstruction *coro_size = ir_build_coro_size(irb, scope, node);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 Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);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 IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr);6029 IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr);
5880 IrInstruction *alignment = ir_build_const_u29(irb, scope, node, irb->codegen->pointer_size_bytes * 2);6030 IrInstruction *alignment = ir_build_const_u29(irb, scope, node, irb->codegen->pointer_size_bytes * 2);
5881 size_t arg_count = 3;6031 size_t arg_count = 3;
5882 IrInstruction **args = allocate<IrInstruction *>(arg_count);6032 IrInstruction **args = allocate<IrInstruction *>(arg_count);
5883 args[0] = implicit_allocator_ptr; // self6033 args[0] = irb->exec->implicit_allocator_ptr; // self
5884 args[1] = coro_size; // byte_count6034 args[1] = coro_size; // byte_count
5885 args[2] = alignment; // alignment6035 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 IrInstruction *alloc_result_ptr = ir_build_ref(irb, scope, node, alloc_result, true, false);6038 IrInstruction *alloc_result_ptr = ir_build_ref(irb, scope, node, alloc_result, true, false);
5888 IrInstruction *alloc_result_is_err = ir_build_test_err(irb, scope, node, alloc_result);6039 IrInstruction *alloc_result_is_err = ir_build_test_err(irb, scope, node, alloc_result);
5889 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError");6040 IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError");
5890 IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk");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);
58926043
5893 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);6044 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
5894 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, alloc_result_ptr);6045 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, alloc_result_ptr);
5895 ir_build_coro_alloc_fail(irb, scope, node, err_val);6046 ir_build_coro_alloc_fail(irb, scope, node, err_val);
58966047
5897 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);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 Buf *ptr_field_name = buf_create_from_str("ptr");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 IrInstruction *coro_mem_ptr = ir_build_load_ptr(irb, scope, node, coro_mem_ptr_field);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);
59036055
5904 ir_set_cursor_at_end_and_append_block(irb, coro_begin_block);6056 ir_set_cursor_at_end_and_append_block(irb, coro_begin_block);
5905 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);6057 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
...@@ -5910,6 +6062,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -5910,6 +6062,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
5910 incoming_values[1] = coro_mem_ptr;6062 incoming_values[1] = coro_mem_ptr;
5911 IrInstruction *coro_mem = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);6063 IrInstruction *coro_mem = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
5912 irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem);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 }
59146068
5915 IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE);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,7 +6072,84 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
5918 return false;6072 return false;
59196073
5920 if (!instr_is_unreachable(result)) {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 }
59236154
5924 return true;6155 return true;
...@@ -9514,8 +9745,11 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,...@@ -9514,8 +9745,11 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
9514 ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable"));9745 ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable"));
9515 return ir_unreach_error(ira);9746 return ir_unreach_error(ira);
9516 }9747 }
9517 ir_build_return_from(&ira->new_irb, &return_instruction->base, casted_value);9748 IrInstruction *result = ir_build_return(&ira->new_irb, return_instruction->base.scope,
9518 return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);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}
95209754
9521static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) {9755static 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,11 +16858,8 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr
1662416858
16625 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;16859 TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize;
1662616860
16627 if (!(target->value.type->id == TypeTableEntryIdPointer ||16861 if (!(type_is_codegen_pointer(target->value.type) || (target->value.type->id == TypeTableEntryIdMaybe &&
16628 target->value.type->id == TypeTableEntryIdFn ||16862 type_is_codegen_pointer(target->value.type->data.maybe.child_type))))
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))))
16632 {16863 {
16633 ir_add_error(ira, target,16864 ir_add_error(ira, target,
16634 buf_sprintf("expected pointer, found '%s'", buf_ptr(&target->value.type->name)));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,7 +17060,12 @@ static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructi
16829}17060}
1683017061
16831static TypeTableEntry *ir_analyze_instruction_coro_id(IrAnalyze *ira, IrInstructionCoroId *instruction) {17062static 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 ir_link_new_instruction(result, &instruction->base);17069 ir_link_new_instruction(result, &instruction->base);
16834 result->value.type = ira->codegen->builtin_types.entry_usize;17070 result->value.type = ira->codegen->builtin_types.entry_usize;
16835 return result->value.type;17071 return result->value.type;
...@@ -16889,6 +17125,63 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_fail(IrAnalyze *ira, Ir...@@ -16889,6 +17125,63 @@ static TypeTableEntry *ir_analyze_instruction_coro_alloc_fail(IrAnalyze *ira, Ir
16889 return ir_finish_anal(ira, result->value.type);17125 return ir_finish_anal(ira, result->value.type);
16890}17126}
1689117127
17128static 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
17147static 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
17155static 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
17172static 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
16892static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {17185static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
16893 switch (instruction->id) {17186 switch (instruction->id) {
16894 case IrInstructionIdInvalid:17187 case IrInstructionIdInvalid:
...@@ -17105,6 +17398,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17105,6 +17398,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17105 return ir_analyze_instruction_get_implicit_allocator(ira, (IrInstructionGetImplicitAllocator *)instruction);17398 return ir_analyze_instruction_get_implicit_allocator(ira, (IrInstructionGetImplicitAllocator *)instruction);
17106 case IrInstructionIdCoroAllocFail:17399 case IrInstructionIdCoroAllocFail:
17107 return ir_analyze_instruction_coro_alloc_fail(ira, (IrInstructionCoroAllocFail *)instruction);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 zig_unreachable();17410 zig_unreachable();
17110}17411}
...@@ -17134,7 +17435,10 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl...@@ -17134,7 +17435,10 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
17134 IrAnalyze *ira = allocate<IrAnalyze>(1);17435 IrAnalyze *ira = allocate<IrAnalyze>(1);
17135 old_exec->analysis = ira;17436 old_exec->analysis = ira;
17136 ira->codegen = codegen;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;
1713817442
17139 ira->old_irb.codegen = codegen;17443 ira->old_irb.codegen = codegen;
17140 ira->old_irb.exec = old_exec;17444 ira->old_irb.exec = old_exec;
...@@ -17222,6 +17526,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -17222,6 +17526,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
17222 case IrInstructionIdCoroId:17526 case IrInstructionIdCoroId:
17223 case IrInstructionIdCoroBegin:17527 case IrInstructionIdCoroBegin:
17224 case IrInstructionIdCoroAllocFail:17528 case IrInstructionIdCoroAllocFail:
17529 case IrInstructionIdCoroEnd:
17530 case IrInstructionIdCoroResume:
17225 return true;17531 return true;
1722617532
17227 case IrInstructionIdPhi:17533 case IrInstructionIdPhi:
...@@ -17299,6 +17605,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -17299,6 +17605,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
17299 case IrInstructionIdGetImplicitAllocator:17605 case IrInstructionIdGetImplicitAllocator:
17300 case IrInstructionIdCoroAlloc:17606 case IrInstructionIdCoroAlloc:
17301 case IrInstructionIdCoroSize:17607 case IrInstructionIdCoroSize:
17608 case IrInstructionIdCoroSuspend:
17609 case IrInstructionIdCoroFree:
17302 return false;17610 return false;
1730317611
17304 case IrInstructionIdAsm:17612 case IrInstructionIdAsm:
src/ir_print.cpp+45-1
...@@ -1031,7 +1031,9 @@ static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplic...@@ -1031,7 +1031,9 @@ static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplic
1031}1031}
10321032
1033static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) {1033static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) {
1034 fprintf(irp->f, "@coroId()");1034 fprintf(irp->f, "@coroId(");
1035 ir_print_other_instruction(irp, instruction->promise_ptr);
1036 fprintf(irp->f, ")");
1035}1037}
10361038
1037static void ir_print_coro_alloc(IrPrint *irp, IrInstructionCoroAlloc *instruction) {1039static void ir_print_coro_alloc(IrPrint *irp, IrInstructionCoroAlloc *instruction) {
...@@ -1058,6 +1060,36 @@ static void ir_print_coro_alloc_fail(IrPrint *irp, IrInstructionCoroAllocFail *i...@@ -1058,6 +1060,36 @@ static void ir_print_coro_alloc_fail(IrPrint *irp, IrInstructionCoroAllocFail *i
1058 fprintf(irp->f, ")");1060 fprintf(irp->f, ")");
1059}1061}
10601062
1063static void ir_print_coro_suspend(IrPrint *irp, IrInstructionCoroSuspend *instruction) {
1064 fprintf(irp->f, "@coroSuspend(");
1065 if (instruction->save_point != nullptr) {
1066 ir_print_other_instruction(irp, instruction->save_point);
1067 } else {
1068 fprintf(irp->f, "null");
1069 }
1070 fprintf(irp->f, ",");
1071 ir_print_other_instruction(irp, instruction->is_final);
1072 fprintf(irp->f, ")");
1073}
1074
1075static void ir_print_coro_end(IrPrint *irp, IrInstructionCoroEnd *instruction) {
1076 fprintf(irp->f, "@coroEnd()");
1077}
1078
1079static void ir_print_coro_free(IrPrint *irp, IrInstructionCoroFree *instruction) {
1080 fprintf(irp->f, "@coroFree(");
1081 ir_print_other_instruction(irp, instruction->coro_id);
1082 fprintf(irp->f, ",");
1083 ir_print_other_instruction(irp, instruction->coro_handle);
1084 fprintf(irp->f, ")");
1085}
1086
1087static void ir_print_coro_resume(IrPrint *irp, IrInstructionCoroResume *instruction) {
1088 fprintf(irp->f, "@coroResume(");
1089 ir_print_other_instruction(irp, instruction->awaiter_handle);
1090 fprintf(irp->f, ")");
1091}
1092
1061static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1093static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1062 ir_print_prefix(irp, instruction);1094 ir_print_prefix(irp, instruction);
1063 switch (instruction->id) {1095 switch (instruction->id) {
...@@ -1399,6 +1431,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1399,6 +1431,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1399 case IrInstructionIdCoroAllocFail:1431 case IrInstructionIdCoroAllocFail:
1400 ir_print_coro_alloc_fail(irp, (IrInstructionCoroAllocFail *)instruction);1432 ir_print_coro_alloc_fail(irp, (IrInstructionCoroAllocFail *)instruction);
1401 break;1433 break;
1434 case IrInstructionIdCoroSuspend:
1435 ir_print_coro_suspend(irp, (IrInstructionCoroSuspend *)instruction);
1436 break;
1437 case IrInstructionIdCoroEnd:
1438 ir_print_coro_end(irp, (IrInstructionCoroEnd *)instruction);
1439 break;
1440 case IrInstructionIdCoroFree:
1441 ir_print_coro_free(irp, (IrInstructionCoroFree *)instruction);
1442 break;
1443 case IrInstructionIdCoroResume:
1444 ir_print_coro_resume(irp, (IrInstructionCoroResume *)instruction);
1445 break;
1402 }1446 }
1403 fprintf(irp->f, "\n");1447 fprintf(irp->f, "\n");
1404}1448}