| author | |
| committer | |
| log | dbdc4d62d08c94a967b36afdfa57b126775a4eee |
| tree | b6ffd56af7b37257c7dd165001ca88cb80990fc4 |
| parent | ee64a22045ccbc39773779d4e386e25f563c8a90 |
| signature | Commit is signed but in an unrecognized format. |
* add implicit cast from `*@Frame(func)` to `anyframe->T` or `anyframe`.
* add implicit cast from `anyframe->T` to `anyframe`.
* `resume` works on `anyframe->T` and `anyframe` types.5 files changed, 97 insertions(+), 29 deletions(-)
src/all_types.hpp+1-1| ... | ... | @@ -1726,6 +1726,7 @@ struct CodeGen { |
| 1726 | 1726 | LLVMValueRef err_name_table; |
| 1727 | 1727 | LLVMValueRef safety_crash_err_fn; |
| 1728 | 1728 | LLVMValueRef return_err_fn; |
| 1729 | LLVMTypeRef async_fn_llvm_type; | |
| 1729 | 1730 | |
| 1730 | 1731 | // reminder: hash tables must be initialized before use |
| 1731 | 1732 | HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table; |
| ... | ... | @@ -1793,7 +1794,6 @@ struct CodeGen { |
| 1793 | 1794 | ZigType *entry_global_error_set; |
| 1794 | 1795 | ZigType *entry_arg_tuple; |
| 1795 | 1796 | ZigType *entry_enum_literal; |
| 1796 | ZigType *entry_frame_header; | |
| 1797 | 1797 | ZigType *entry_any_frame; |
| 1798 | 1798 | } builtin_types; |
| 1799 | 1799 | ZigType *align_amt_type; |
src/analyze.cpp+4-10| ... | ... | @@ -7348,19 +7348,13 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) { |
| 7348 | 7348 | if (is_async) { |
| 7349 | 7349 | fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(1); |
| 7350 | 7350 | |
| 7351 | ZigType *frame_type = g->builtin_types.entry_frame_header; | |
| 7352 | Error err; | |
| 7353 | if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { | |
| 7354 | zig_unreachable(); | |
| 7355 | } | |
| 7356 | ZigType *ptr_type = get_pointer_to_type(g, frame_type, false); | |
| 7357 | gen_param_types.append(get_llvm_type(g, ptr_type)); | |
| 7358 | param_di_types.append(get_llvm_di_type(g, ptr_type)); | |
| 7351 | ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type); | |
| 7352 | gen_param_types.append(get_llvm_type(g, frame_type)); | |
| 7353 | param_di_types.append(get_llvm_di_type(g, frame_type)); | |
| 7359 | 7354 | |
| 7360 | 7355 | fn_type->data.fn.gen_param_info[0].src_index = 0; |
| 7361 | 7356 | fn_type->data.fn.gen_param_info[0].gen_index = 0; |
| 7362 | fn_type->data.fn.gen_param_info[0].type = ptr_type; | |
| 7363 | ||
| 7357 | fn_type->data.fn.gen_param_info[0].type = frame_type; | |
| 7364 | 7358 | } else { |
| 7365 | 7359 | fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count); |
| 7366 | 7360 | for (size_t i = 0; i < fn_type_id->param_count; i += 1) { |
src/codegen.cpp+17-8| ... | ... | @@ -4902,14 +4902,28 @@ static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable, |
| 4902 | 4902 | return nullptr; |
| 4903 | 4903 | } |
| 4904 | 4904 | |
| 4905 | static LLVMTypeRef async_fn_llvm_type(CodeGen *g) { | |
| 4906 | if (g->async_fn_llvm_type != nullptr) | |
| 4907 | return g->async_fn_llvm_type; | |
| 4908 | ||
| 4909 | ZigType *anyframe_type = get_any_frame_type(g, nullptr); | |
| 4910 | LLVMTypeRef param_type = get_llvm_type(g, anyframe_type); | |
| 4911 | LLVMTypeRef return_type = LLVMVoidType(); | |
| 4912 | LLVMTypeRef fn_type = LLVMFunctionType(return_type, &param_type, 1, false); | |
| 4913 | g->async_fn_llvm_type = LLVMPointerType(fn_type, 0); | |
| 4914 | ||
| 4915 | return g->async_fn_llvm_type; | |
| 4916 | } | |
| 4917 | ||
| 4905 | 4918 | static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable, |
| 4906 | 4919 | IrInstructionCoroResume *instruction) |
| 4907 | 4920 | { |
| 4908 | 4921 | LLVMValueRef frame = ir_llvm_value(g, instruction->frame); |
| 4909 | 4922 | ZigType *frame_type = instruction->frame->value.type; |
| 4910 | assert(frame_type->id == ZigTypeIdCoroFrame); | |
| 4911 | ZigFn *fn = frame_type->data.frame.fn; | |
| 4912 | LLVMValueRef fn_val = fn_llvm_value(g, fn); | |
| 4923 | assert(frame_type->id == ZigTypeIdAnyFrame); | |
| 4924 | LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame, coro_fn_ptr_index, ""); | |
| 4925 | LLVMValueRef uncasted_fn_val = LLVMBuildLoad(g->builder, fn_ptr_ptr, ""); | |
| 4926 | LLVMValueRef fn_val = LLVMBuildIntToPtr(g->builder, uncasted_fn_val, async_fn_llvm_type(g), ""); | |
| 4913 | 4927 | ZigLLVMBuildCall(g->builder, fn_val, &frame, 1, LLVMFastCallConv, ZigLLVM_FnInlineAuto, ""); |
| 4914 | 4928 | return nullptr; |
| 4915 | 4929 | } |
| ... | ... | @@ -6746,11 +6760,6 @@ static void define_builtin_types(CodeGen *g) { |
| 6746 | 6760 | |
| 6747 | 6761 | g->primitive_type_table.put(&entry->name, entry); |
| 6748 | 6762 | } |
| 6749 | { | |
| 6750 | const char *field_names[] = {"resume_index"}; | |
| 6751 | ZigType *field_types[] = {g->builtin_types.entry_usize}; | |
| 6752 | g->builtin_types.entry_frame_header = get_struct_type(g, "(frame header)", field_names, field_types, 1); | |
| 6753 | } | |
| 6754 | 6763 | } |
| 6755 | 6764 | |
| 6756 | 6765 | static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) { |
src/ir.cpp+68-8| ... | ... | @@ -7764,7 +7764,7 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) |
| 7764 | 7764 | static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 7765 | 7765 | assert(node->type == NodeTypeResume); |
| 7766 | 7766 | |
| 7767 | IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope); | |
| 7767 | IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr); | |
| 7768 | 7768 | if (target_inst == irb->codegen->invalid_instruction) |
| 7769 | 7769 | return irb->codegen->invalid_instruction; |
| 7770 | 7770 | |
| ... | ... | @@ -10882,6 +10882,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou |
| 10882 | 10882 | return result; |
| 10883 | 10883 | } |
| 10884 | 10884 | |
| 10885 | static IrInstruction *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr, | |
| 10886 | IrInstruction *value, ZigType *wanted_type) | |
| 10887 | { | |
| 10888 | if (instr_is_comptime(value)) { | |
| 10889 | zig_panic("TODO comptime frame pointer"); | |
| 10890 | } | |
| 10891 | ||
| 10892 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, | |
| 10893 | wanted_type, value, CastOpBitCast); | |
| 10894 | result->value.type = wanted_type; | |
| 10895 | return result; | |
| 10896 | } | |
| 10897 | ||
| 10898 | static IrInstruction *ir_analyze_anyframe_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr, | |
| 10899 | IrInstruction *value, ZigType *wanted_type) | |
| 10900 | { | |
| 10901 | if (instr_is_comptime(value)) { | |
| 10902 | zig_panic("TODO comptime anyframe->T to anyframe"); | |
| 10903 | } | |
| 10904 | ||
| 10905 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, | |
| 10906 | wanted_type, value, CastOpBitCast); | |
| 10907 | result->value.type = wanted_type; | |
| 10908 | return result; | |
| 10909 | } | |
| 10910 | ||
| 10911 | ||
| 10885 | 10912 | static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, |
| 10886 | 10913 | ZigType *wanted_type, ResultLoc *result_loc) |
| 10887 | 10914 | { |
| ... | ... | @@ -11978,6 +12005,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 11978 | 12005 | } |
| 11979 | 12006 | } |
| 11980 | 12007 | |
| 12008 | // *@Frame(func) to anyframe->T or anyframe | |
| 12009 | if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle && | |
| 12010 | actual_type->data.pointer.child_type->id == ZigTypeIdCoroFrame && wanted_type->id == ZigTypeIdAnyFrame) | |
| 12011 | { | |
| 12012 | bool ok = true; | |
| 12013 | if (wanted_type->data.any_frame.result_type != nullptr) { | |
| 12014 | ZigFn *fn = actual_type->data.pointer.child_type->data.frame.fn; | |
| 12015 | ZigType *fn_return_type = fn->type_entry->data.fn.fn_type_id.return_type; | |
| 12016 | if (wanted_type->data.any_frame.result_type != fn_return_type) { | |
| 12017 | ok = false; | |
| 12018 | } | |
| 12019 | } | |
| 12020 | if (ok) { | |
| 12021 | return ir_analyze_frame_ptr_to_anyframe(ira, source_instr, value, wanted_type); | |
| 12022 | } | |
| 12023 | } | |
| 12024 | ||
| 12025 | // anyframe->T to anyframe | |
| 12026 | if (actual_type->id == ZigTypeIdAnyFrame && actual_type->data.any_frame.result_type != nullptr && | |
| 12027 | wanted_type->id == ZigTypeIdAnyFrame && wanted_type->data.any_frame.result_type == nullptr) | |
| 12028 | { | |
| 12029 | return ir_analyze_anyframe_to_anyframe(ira, source_instr, value, wanted_type); | |
| 12030 | } | |
| 11981 | 12031 | |
| 11982 | 12032 | // cast from null literal to maybe type |
| 11983 | 12033 | if (wanted_type->id == ZigTypeIdOptional && |
| ... | ... | @@ -24323,17 +24373,27 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru |
| 24323 | 24373 | } |
| 24324 | 24374 | |
| 24325 | 24375 | static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) { |
| 24326 | IrInstruction *frame = instruction->frame->child; | |
| 24327 | if (type_is_invalid(frame->value.type)) | |
| 24376 | IrInstruction *frame_ptr = instruction->frame->child; | |
| 24377 | if (type_is_invalid(frame_ptr->value.type)) | |
| 24328 | 24378 | return ira->codegen->invalid_instruction; |
| 24329 | 24379 | |
| 24330 | if (frame->value.type->id != ZigTypeIdCoroFrame) { | |
| 24331 | ir_add_error(ira, instruction->frame, | |
| 24332 | buf_sprintf("expected frame, found '%s'", buf_ptr(&frame->value.type->name))); | |
| 24333 | return ira->codegen->invalid_instruction; | |
| 24380 | IrInstruction *frame; | |
| 24381 | if (frame_ptr->value.type->id == ZigTypeIdPointer && | |
| 24382 | frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle && | |
| 24383 | frame_ptr->value.type->data.pointer.is_const && | |
| 24384 | frame_ptr->value.type->data.pointer.child_type->id == ZigTypeIdAnyFrame) | |
| 24385 | { | |
| 24386 | frame = ir_get_deref(ira, &instruction->base, frame_ptr, nullptr); | |
| 24387 | } else { | |
| 24388 | frame = frame_ptr; | |
| 24334 | 24389 | } |
| 24335 | 24390 | |
| 24336 | return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, frame); | |
| 24391 | ZigType *any_frame_type = get_any_frame_type(ira->codegen, nullptr); | |
| 24392 | IrInstruction *casted_frame = ir_implicit_cast(ira, frame, any_frame_type); | |
| 24393 | if (type_is_invalid(casted_frame->value.type)) | |
| 24394 | return ira->codegen->invalid_instruction; | |
| 24395 | ||
| 24396 | return ir_build_coro_resume(&ira->new_irb, instruction->base.scope, instruction->base.source_node, casted_frame); | |
| 24337 | 24397 | } |
| 24338 | 24398 | |
| 24339 | 24399 | static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { |
test/stage1/behavior/coroutines.zig+7-2| ... | ... | @@ -5,15 +5,20 @@ const expect = std.testing.expect; |
| 5 | 5 | var global_x: i32 = 1; |
| 6 | 6 | |
| 7 | 7 | test "simple coroutine suspend and resume" { |
| 8 | const p = async simpleAsyncFn(); | |
| 8 | const frame = async simpleAsyncFn(); | |
| 9 | 9 | expect(global_x == 2); |
| 10 | resume p; | |
| 10 | resume frame; | |
| 11 | 11 | expect(global_x == 3); |
| 12 | const af: anyframe->void = &frame; | |
| 13 | resume frame; | |
| 14 | expect(global_x == 4); | |
| 12 | 15 | } |
| 13 | 16 | fn simpleAsyncFn() void { |
| 14 | 17 | global_x += 1; |
| 15 | 18 | suspend; |
| 16 | 19 | global_x += 1; |
| 20 | suspend; | |
| 21 | global_x += 1; | |
| 17 | 22 | } |
| 18 | 23 | |
| 19 | 24 | var global_y: i32 = 1; |