authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-01 03:28:13-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-01 03:28:13-05:00
log253d988e7c00f7ad0cc1b5f913562cb5c1712c91
treef4514b6232bfcfb7bee5e5274bcca7409da09906
parent834e992a7c4ca0f0e1935e01e23410bc1d95cc52

implementation of await

but it has bugs

7 files changed, 266 insertions(+), 23 deletions(-)

src/all_types.hpp+23
...@@ -1192,6 +1192,7 @@ struct TypeTableEntry {...@@ -1192,6 +1192,7 @@ struct TypeTableEntry {
1192 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]1192 TypeTableEntry *pointer_parent[2]; // [0 - mut, 1 - const]
1193 TypeTableEntry *maybe_parent;1193 TypeTableEntry *maybe_parent;
1194 TypeTableEntry *promise_parent;1194 TypeTableEntry *promise_parent;
1195 TypeTableEntry *promise_frame_parent;
1195 // If we generate a constant name value for this type, we memoize it here.1196 // If we generate a constant name value for this type, we memoize it here.
1196 // The type of this is array1197 // The type of this is array
1197 ConstExprValue *cached_const_name_val;1198 ConstExprValue *cached_const_name_val;
...@@ -1641,6 +1642,7 @@ struct CodeGen {...@@ -1641,6 +1642,7 @@ struct CodeGen {
1641 LLVMValueRef coro_free_fn_val;1642 LLVMValueRef coro_free_fn_val;
1642 LLVMValueRef coro_resume_fn_val;1643 LLVMValueRef coro_resume_fn_val;
1643 LLVMValueRef coro_save_fn_val;1644 LLVMValueRef coro_save_fn_val;
1645 LLVMValueRef coro_promise_fn_val;
1644 LLVMValueRef coro_alloc_helper_fn_val;1646 LLVMValueRef coro_alloc_helper_fn_val;
1645 bool error_during_imports;1647 bool error_during_imports;
16461648
...@@ -2025,8 +2027,10 @@ enum IrInstructionId {...@@ -2025,8 +2027,10 @@ enum IrInstructionId {
2025 IrInstructionIdCoroFree,2027 IrInstructionIdCoroFree,
2026 IrInstructionIdCoroResume,2028 IrInstructionIdCoroResume,
2027 IrInstructionIdCoroSave,2029 IrInstructionIdCoroSave,
2030 IrInstructionIdCoroPromise,
2028 IrInstructionIdCoroAllocHelper,2031 IrInstructionIdCoroAllocHelper,
2029 IrInstructionIdAtomicRmw,2032 IrInstructionIdAtomicRmw,
2033 IrInstructionIdPromiseResultType,
2030};2034};
20312035
2032struct IrInstruction {2036struct IrInstruction {
...@@ -2943,6 +2947,12 @@ struct IrInstructionCoroSave {...@@ -2943,6 +2947,12 @@ struct IrInstructionCoroSave {
2943 IrInstruction *coro_handle;2947 IrInstruction *coro_handle;
2944};2948};
29452949
2950struct IrInstructionCoroPromise {
2951 IrInstruction base;
2952
2953 IrInstruction *coro_handle;
2954};
2955
2946struct IrInstructionCoroAllocHelper {2956struct IrInstructionCoroAllocHelper {
2947 IrInstruction base;2957 IrInstruction base;
29482958
...@@ -2962,6 +2972,12 @@ struct IrInstructionAtomicRmw {...@@ -2962,6 +2972,12 @@ struct IrInstructionAtomicRmw {
2962 AtomicOrder resolved_ordering;2972 AtomicOrder resolved_ordering;
2963};2973};
29642974
2975struct IrInstructionPromiseResultType {
2976 IrInstruction base;
2977
2978 IrInstruction *promise_type;
2979};
2980
2965static const size_t slice_ptr_index = 0;2981static const size_t slice_ptr_index = 0;
2966static const size_t slice_len_index = 1;2982static const size_t slice_len_index = 1;
29672983
...@@ -2971,6 +2987,13 @@ static const size_t maybe_null_index = 1;...@@ -2971,6 +2987,13 @@ static const size_t maybe_null_index = 1;
2971static const size_t err_union_err_index = 0;2987static const size_t err_union_err_index = 0;
2972static const size_t err_union_payload_index = 1;2988static const size_t err_union_payload_index = 1;
29732989
2990#define ASYNC_ALLOC_FIELD_NAME "allocFn"
2991#define ASYNC_FREE_FIELD_NAME "freeFn"
2992#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
2993#define RESULT_FIELD_NAME "result"
2994#define RESULT_PTR_FIELD_NAME "result_ptr"
2995
2996
2974enum FloatMode {2997enum FloatMode {
2975 FloatModeOptimized,2998 FloatModeOptimized,
2976 FloatModeStrict,2999 FloatModeStrict,
src/analyze.cpp+18
...@@ -457,6 +457,23 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool...@@ -457,6 +457,23 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
457 return get_pointer_to_type_extra(g, child_type, is_const, false, get_abi_alignment(g, child_type), 0, 0);457 return get_pointer_to_type_extra(g, child_type, is_const, false, get_abi_alignment(g, child_type), 0, 0);
458}458}
459459
460TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type) {
461 if (return_type->promise_frame_parent != nullptr) {
462 return return_type->promise_frame_parent;
463 }
464
465 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
466 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
467 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};
468 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};
469 size_t field_count = type_has_bits(result_ptr_type) ? 3 : 1;
470 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
471 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, field_count);
472
473 return_type->promise_frame_parent = entry;
474 return entry;
475}
476
460TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {477TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
461 if (child_type->maybe_parent) {478 if (child_type->maybe_parent) {
462 TypeTableEntry *entry = child_type->maybe_parent;479 TypeTableEntry *entry = child_type->maybe_parent;
...@@ -5800,3 +5817,4 @@ bool fn_type_can_fail(FnTypeId *fn_type_id) {...@@ -5800,3 +5817,4 @@ bool fn_type_can_fail(FnTypeId *fn_type_id) {
5800 return return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdErrorSet ||5817 return return_type->id == TypeTableEntryIdErrorUnion || return_type->id == TypeTableEntryIdErrorSet ||
5801 fn_type_id->cc == CallingConventionAsync;5818 fn_type_id->cc == CallingConventionAsync;
5802}5819}
5820
src/analyze.hpp+1
...@@ -36,6 +36,7 @@ TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node,...@@ -36,6 +36,7 @@ TypeTableEntry *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node,
36TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],36TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *field_names[],
37 TypeTableEntry *field_types[], size_t field_count);37 TypeTableEntry *field_types[], size_t field_count);
38TypeTableEntry *get_promise_type(CodeGen *g, TypeTableEntry *result_type);38TypeTableEntry *get_promise_type(CodeGen *g, TypeTableEntry *result_type);
39TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type);
39TypeTableEntry *get_test_fn_type(CodeGen *g);40TypeTableEntry *get_test_fn_type(CodeGen *g);
40bool handle_is_ptr(TypeTableEntry *type_entry);41bool handle_is_ptr(TypeTableEntry *type_entry);
41void find_libc_include_path(CodeGen *g);42void find_libc_include_path(CodeGen *g);
src/codegen.cpp+31-1
...@@ -1081,6 +1081,23 @@ static LLVMValueRef get_coro_save_fn_val(CodeGen *g) {...@@ -1081,6 +1081,23 @@ static LLVMValueRef get_coro_save_fn_val(CodeGen *g) {
1081 return g->coro_save_fn_val;1081 return g->coro_save_fn_val;
1082}1082}
10831083
1084static LLVMValueRef get_coro_promise_fn_val(CodeGen *g) {
1085 if (g->coro_promise_fn_val)
1086 return g->coro_promise_fn_val;
1087
1088 LLVMTypeRef param_types[] = {
1089 LLVMPointerType(LLVMInt8Type(), 0),
1090 LLVMInt32Type(),
1091 LLVMInt1Type(),
1092 };
1093 LLVMTypeRef fn_type = LLVMFunctionType(LLVMPointerType(LLVMInt8Type(), 0), param_types, 3, false);
1094 Buf *name = buf_sprintf("llvm.coro.promise");
1095 g->coro_promise_fn_val = LLVMAddFunction(g->module, buf_ptr(name), fn_type);
1096 assert(LLVMGetIntrinsicID(g->coro_promise_fn_val));
1097
1098 return g->coro_promise_fn_val;
1099}
1100
1084static LLVMValueRef get_return_address_fn_val(CodeGen *g) {1101static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
1085 if (g->return_address_fn_val)1102 if (g->return_address_fn_val)
1086 return g->return_address_fn_val;1103 return g->return_address_fn_val;
...@@ -4002,6 +4019,16 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir...@@ -4002,6 +4019,16 @@ static LLVMValueRef ir_render_coro_save(CodeGen *g, IrExecutable *executable, Ir
4002 return LLVMBuildCall(g->builder, get_coro_save_fn_val(g), &coro_handle, 1, "");4019 return LLVMBuildCall(g->builder, get_coro_save_fn_val(g), &coro_handle, 1, "");
4003}4020}
40044021
4022static LLVMValueRef ir_render_coro_promise(CodeGen *g, IrExecutable *executable, IrInstructionCoroPromise *instruction) {
4023 LLVMValueRef coro_handle = ir_llvm_value(g, instruction->coro_handle);
4024 LLVMValueRef params[] = {
4025 coro_handle,
4026 LLVMConstInt(LLVMInt32Type(), get_coro_frame_align_bytes(g), false),
4027 LLVMConstNull(LLVMInt1Type()),
4028 };
4029 return LLVMBuildCall(g->builder, get_coro_promise_fn_val(g), params, 3, "");
4030}
4031
4005static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {4032static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_fn_type_ref, TypeTableEntry *fn_type) {
4006 if (g->coro_alloc_helper_fn_val != nullptr)4033 if (g->coro_alloc_helper_fn_val != nullptr)
4007 return g->coro_alloc_helper_fn_val;4034 return g->coro_alloc_helper_fn_val;
...@@ -4064,7 +4091,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f...@@ -4064,7 +4091,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
4064 LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg);4091 LLVMValueRef coro_size = LLVMGetParam(fn_val, next_arg);
4065 next_arg += 1;4092 next_arg += 1;
4066 LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->type_ref,4093 LLVMValueRef alignment_val = LLVMConstInt(g->builtin_types.entry_u29->type_ref,
4067 2 * g->pointer_size_bytes, false);4094 get_coro_frame_align_bytes(g), false);
40684095
4069 ZigList<LLVMValueRef> args = {};4096 ZigList<LLVMValueRef> args = {};
4070 args.append(sret_ptr);4097 args.append(sret_ptr);
...@@ -4218,6 +4245,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4218,6 +4245,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4218 case IrInstructionIdTagType:4245 case IrInstructionIdTagType:
4219 case IrInstructionIdExport:4246 case IrInstructionIdExport:
4220 case IrInstructionIdErrorUnion:4247 case IrInstructionIdErrorUnion:
4248 case IrInstructionIdPromiseResultType:
4221 zig_unreachable();4249 zig_unreachable();
42224250
4223 case IrInstructionIdReturn:4251 case IrInstructionIdReturn:
...@@ -4360,6 +4388,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4360,6 +4388,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4360 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);4388 return ir_render_coro_resume(g, executable, (IrInstructionCoroResume *)instruction);
4361 case IrInstructionIdCoroSave:4389 case IrInstructionIdCoroSave:
4362 return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);4390 return ir_render_coro_save(g, executable, (IrInstructionCoroSave *)instruction);
4391 case IrInstructionIdCoroPromise:
4392 return ir_render_coro_promise(g, executable, (IrInstructionCoroPromise *)instruction);
4363 case IrInstructionIdCoroAllocHelper:4393 case IrInstructionIdCoroAllocHelper:
4364 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);4394 return ir_render_coro_alloc_helper(g, executable, (IrInstructionCoroAllocHelper *)instruction);
4365 case IrInstructionIdAtomicRmw:4395 case IrInstructionIdAtomicRmw:
src/ir.cpp+167-18
...@@ -45,12 +45,6 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {...@@ -45,12 +45,6 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {
45 return { true, is_const, is_volatile };45 return { true, is_const, is_volatile };
46}46}
4747
48static const char * ASYNC_ALLOC_FIELD_NAME = "allocFn";
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";
53
54enum ConstCastResultId {48enum ConstCastResultId {
55 ConstCastResultIdOk,49 ConstCastResultIdOk,
56 ConstCastResultIdErrSet,50 ConstCastResultIdErrSet,
...@@ -697,6 +691,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) {...@@ -697,6 +691,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSave *) {
697 return IrInstructionIdCoroSave;691 return IrInstructionIdCoroSave;
698}692}
699693
694static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroPromise *) {
695 return IrInstructionIdCoroPromise;
696}
697
700static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) {698static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAllocHelper *) {
701 return IrInstructionIdCoroAllocHelper;699 return IrInstructionIdCoroAllocHelper;
702}700}
...@@ -705,6 +703,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {...@@ -705,6 +703,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAtomicRmw *) {
705 return IrInstructionIdAtomicRmw;703 return IrInstructionIdAtomicRmw;
706}704}
707705
706static constexpr IrInstructionId ir_instruction_id(IrInstructionPromiseResultType *) {
707 return IrInstructionIdPromiseResultType;
708}
709
708template<typename T>710template<typename T>
709static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {711static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
710 T *special_instruction = allocate<T>(1);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,25 +939,19 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
937static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,939static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
938 TypeTableEntry *return_type)940 TypeTableEntry *return_type)
939{941{
940 TypeTableEntry *awaiter_handle_type = get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise);942 TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type);
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);
947943
948 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);944 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
949 const_instruction->base.value.type = struct_type;945 const_instruction->base.value.type = struct_type;
950 const_instruction->base.value.special = ConstValSpecialStatic;946 const_instruction->base.value.special = ConstValSpecialStatic;
951 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(field_count);947 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count);
952 const_instruction->base.value.data.x_struct.fields[0].type = awaiter_handle_type;948 const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
953 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;949 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
954 const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;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 const_instruction->base.value.data.x_struct.fields[1].type = return_type;952 const_instruction->base.value.data.x_struct.fields[1].type = return_type;
957 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;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 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;955 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
960 }956 }
961 return &const_instruction->base;957 return &const_instruction->base;
...@@ -2605,6 +2601,17 @@ static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *...@@ -2605,6 +2601,17 @@ static IrInstruction *ir_build_coro_save(IrBuilder *irb, Scope *scope, AstNode *
2605 return &instruction->base;2601 return &instruction->base;
2606}2602}
26072603
2604static 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
2608static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node,2615static IrInstruction *ir_build_coro_alloc_helper(IrBuilder *irb, Scope *scope, AstNode *source_node,
2609 IrInstruction *alloc_fn, IrInstruction *coro_size)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,6 +2647,17 @@ static IrInstruction *ir_build_atomic_rmw(IrBuilder *irb, Scope *scope, AstNode
2640 return &instruction->base;2647 return &instruction->base;
2641}2648}
26422649
2650static 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
2643static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2661static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2644 results[ReturnKindUnconditional] = 0;2662 results[ReturnKindUnconditional] = 0;
2645 results[ReturnKindError] = 0;2663 results[ReturnKindError] = 0;
...@@ -5944,7 +5962,93 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -5944,7 +5962,93 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
5944 if (target_inst == irb->codegen->invalid_instruction)5962 if (target_inst == irb->codegen->invalid_instruction)
5945 return irb->codegen->invalid_instruction;5963 return irb->codegen->invalid_instruction;
59465964
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}
59496053
5950static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {6054static 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,6 +17503,29 @@ static TypeTableEntry *ir_analyze_instruction_coro_save(IrAnalyze *ira, IrInstru
17399 return result->value.type;17503 return result->value.type;
17400}17504}
1740117505
17506static 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
17402static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) {17529static TypeTableEntry *ir_analyze_instruction_coro_alloc_helper(IrAnalyze *ira, IrInstructionCoroAllocHelper *instruction) {
17403 IrInstruction *alloc_fn = instruction->alloc_fn->other;17530 IrInstruction *alloc_fn = instruction->alloc_fn->other;
17404 if (type_is_invalid(alloc_fn->value.type))17531 if (type_is_invalid(alloc_fn->value.type))
...@@ -17492,6 +17619,22 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr...@@ -17492,6 +17619,22 @@ static TypeTableEntry *ir_analyze_instruction_atomic_rmw(IrAnalyze *ira, IrInstr
17492 return result->value.type;17619 return result->value.type;
17493}17620}
1749417621
17622static 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
1749517638
17496static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {17639static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17497 switch (instruction->id) {17640 switch (instruction->id) {
...@@ -17719,10 +17862,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -17719,10 +17862,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
17719 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);17862 return ir_analyze_instruction_coro_resume(ira, (IrInstructionCoroResume *)instruction);
17720 case IrInstructionIdCoroSave:17863 case IrInstructionIdCoroSave:
17721 return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction);17864 return ir_analyze_instruction_coro_save(ira, (IrInstructionCoroSave *)instruction);
17865 case IrInstructionIdCoroPromise:
17866 return ir_analyze_instruction_coro_promise(ira, (IrInstructionCoroPromise *)instruction);
17722 case IrInstructionIdCoroAllocHelper:17867 case IrInstructionIdCoroAllocHelper:
17723 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);17868 return ir_analyze_instruction_coro_alloc_helper(ira, (IrInstructionCoroAllocHelper *)instruction);
17724 case IrInstructionIdAtomicRmw:17869 case IrInstructionIdAtomicRmw:
17725 return ir_analyze_instruction_atomic_rmw(ira, (IrInstructionAtomicRmw *)instruction);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 zig_unreachable();17874 zig_unreachable();
17728}17875}
...@@ -17927,6 +18074,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -17927,6 +18074,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
17927 case IrInstructionIdCoroSuspend:18074 case IrInstructionIdCoroSuspend:
17928 case IrInstructionIdCoroFree:18075 case IrInstructionIdCoroFree:
17929 case IrInstructionIdAtomicRmw:18076 case IrInstructionIdAtomicRmw:
18077 case IrInstructionIdCoroPromise:
18078 case IrInstructionIdPromiseResultType:
17930 return false;18079 return false;
1793118080
17932 case IrInstructionIdAsm:18081 case IrInstructionIdAsm:
src/ir_print.cpp+23-1
...@@ -839,7 +839,11 @@ static void ir_print_ptr_to_int(IrPrint *irp, IrInstructionPtrToInt *instruction...@@ -839,7 +839,11 @@ static void ir_print_ptr_to_int(IrPrint *irp, IrInstructionPtrToInt *instruction
839839
840static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction) {840static void ir_print_int_to_ptr(IrPrint *irp, IrInstructionIntToPtr *instruction) {
841 fprintf(irp->f, "@intToPtr(");841 fprintf(irp->f, "@intToPtr(");
842 ir_print_other_instruction(irp, instruction->dest_type);842 if (instruction->dest_type == nullptr) {
843 fprintf(irp->f, "(null)");
844 } else {
845 ir_print_other_instruction(irp, instruction->dest_type);
846 }
843 fprintf(irp->f, ",");847 fprintf(irp->f, ",");
844 ir_print_other_instruction(irp, instruction->target);848 ir_print_other_instruction(irp, instruction->target);
845 fprintf(irp->f, ")");849 fprintf(irp->f, ")");
...@@ -1105,6 +1109,18 @@ static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction)...@@ -1105,6 +1109,18 @@ static void ir_print_coro_save(IrPrint *irp, IrInstructionCoroSave *instruction)
1105 fprintf(irp->f, ")");1109 fprintf(irp->f, ")");
1106}1110}
11071111
1112static void ir_print_coro_promise(IrPrint *irp, IrInstructionCoroPromise *instruction) {
1113 fprintf(irp->f, "@coroPromise(");
1114 ir_print_other_instruction(irp, instruction->coro_handle);
1115 fprintf(irp->f, ")");
1116}
1117
1118static void ir_print_promise_result_type(IrPrint *irp, IrInstructionPromiseResultType *instruction) {
1119 fprintf(irp->f, "@PromiseResultType(");
1120 ir_print_other_instruction(irp, instruction->promise_type);
1121 fprintf(irp->f, ")");
1122}
1123
1108static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) {1124static void ir_print_coro_alloc_helper(IrPrint *irp, IrInstructionCoroAllocHelper *instruction) {
1109 fprintf(irp->f, "@coroAllocHelper(");1125 fprintf(irp->f, "@coroAllocHelper(");
1110 ir_print_other_instruction(irp, instruction->alloc_fn);1126 ir_print_other_instruction(irp, instruction->alloc_fn);
...@@ -1501,6 +1517,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1501,6 +1517,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1501 case IrInstructionIdAtomicRmw:1517 case IrInstructionIdAtomicRmw:
1502 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);1518 ir_print_atomic_rmw(irp, (IrInstructionAtomicRmw *)instruction);
1503 break;1519 break;
1520 case IrInstructionIdCoroPromise:
1521 ir_print_coro_promise(irp, (IrInstructionCoroPromise *)instruction);
1522 break;
1523 case IrInstructionIdPromiseResultType:
1524 ir_print_promise_result_type(irp, (IrInstructionPromiseResultType *)instruction);
1525 break;
1504 }1526 }
1505 fprintf(irp->f, "\n");1527 fprintf(irp->f, "\n");
1506}1528}
test/cases/coroutines.zig+3-3
...@@ -4,7 +4,7 @@ const assert = std.debug.assert;...@@ -4,7 +4,7 @@ const assert = std.debug.assert;
4var x: i32 = 1;4var x: i32 = 1;
55
6test "create a coroutine and cancel it" {6test "create a coroutine and cancel it" {
7 const p = try (async(std.debug.global_allocator) simpleAsyncFn());7 const p = try async(std.debug.global_allocator) simpleAsyncFn();
8 cancel p;8 cancel p;
9 assert(x == 2);9 assert(x == 2);
10}10}
...@@ -17,7 +17,7 @@ async fn simpleAsyncFn() void {...@@ -17,7 +17,7 @@ async fn simpleAsyncFn() void {
1717
18test "coroutine suspend, resume, cancel" {18test "coroutine suspend, resume, cancel" {
19 seq('a');19 seq('a');
20 const p = (async(std.debug.global_allocator) testAsyncSeq()) catch unreachable;20 const p = try async(std.debug.global_allocator) testAsyncSeq();
21 seq('c');21 seq('c');
22 resume p;22 resume p;
23 seq('f');23 seq('f');
...@@ -43,7 +43,7 @@ fn seq(c: u8) void {...@@ -43,7 +43,7 @@ fn seq(c: u8) void {
43}43}
4444
45test "coroutine suspend with block" {45test "coroutine suspend with block" {
46 const p = (async(std.debug.global_allocator) testSuspendBlock()) catch unreachable;46 const p = try async(std.debug.global_allocator) testSuspendBlock();
47 std.debug.assert(!result);47 std.debug.assert(!result);
48 resume a_promise;48 resume a_promise;
49 std.debug.assert(result);49 std.debug.assert(result);