authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-29 19:32:49-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-07-29 19:32:49-04:00
logdbdc4d62d08c94a967b36afdfa57b126775a4eee
treeb6ffd56af7b37257c7dd165001ca88cb80990fc4
parentee64a22045ccbc39773779d4e386e25f563c8a90
signaturelock-open Commit is signed but in an unrecognized format.

improve support for anyframe and anyframe->T

* 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,6 +1726,7 @@ struct CodeGen {
1726 LLVMValueRef err_name_table;1726 LLVMValueRef err_name_table;
1727 LLVMValueRef safety_crash_err_fn;1727 LLVMValueRef safety_crash_err_fn;
1728 LLVMValueRef return_err_fn;1728 LLVMValueRef return_err_fn;
1729 LLVMTypeRef async_fn_llvm_type;
17291730
1730 // reminder: hash tables must be initialized before use1731 // reminder: hash tables must be initialized before use
1731 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;1732 HashMap<Buf *, ZigType *, buf_hash, buf_eql_buf> import_table;
...@@ -1793,7 +1794,6 @@ struct CodeGen {...@@ -1793,7 +1794,6 @@ struct CodeGen {
1793 ZigType *entry_global_error_set;1794 ZigType *entry_global_error_set;
1794 ZigType *entry_arg_tuple;1795 ZigType *entry_arg_tuple;
1795 ZigType *entry_enum_literal;1796 ZigType *entry_enum_literal;
1796 ZigType *entry_frame_header;
1797 ZigType *entry_any_frame;1797 ZigType *entry_any_frame;
1798 } builtin_types;1798 } builtin_types;
1799 ZigType *align_amt_type;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,19 +7348,13 @@ static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) {
7348 if (is_async) {7348 if (is_async) {
7349 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(1);7349 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(1);
73507350
7351 ZigType *frame_type = g->builtin_types.entry_frame_header;7351 ZigType *frame_type = get_any_frame_type(g, fn_type_id->return_type);
7352 Error err;7352 gen_param_types.append(get_llvm_type(g, frame_type));
7353 if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) {7353 param_di_types.append(get_llvm_di_type(g, frame_type));
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));
73597354
7360 fn_type->data.fn.gen_param_info[0].src_index = 0;7355 fn_type->data.fn.gen_param_info[0].src_index = 0;
7361 fn_type->data.fn.gen_param_info[0].gen_index = 0;7356 fn_type->data.fn.gen_param_info[0].gen_index = 0;
7362 fn_type->data.fn.gen_param_info[0].type = ptr_type;7357 fn_type->data.fn.gen_param_info[0].type = frame_type;
7363
7364 } else {7358 } else {
7365 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);7359 fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id->param_count);
7366 for (size_t i = 0; i < fn_type_id->param_count; i += 1) {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,14 +4902,28 @@ static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable,
4902 return nullptr;4902 return nullptr;
4903}4903}
49044904
4905static 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
4905static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable,4918static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable,
4906 IrInstructionCoroResume *instruction)4919 IrInstructionCoroResume *instruction)
4907{4920{
4908 LLVMValueRef frame = ir_llvm_value(g, instruction->frame);4921 LLVMValueRef frame = ir_llvm_value(g, instruction->frame);
4909 ZigType *frame_type = instruction->frame->value.type;4922 ZigType *frame_type = instruction->frame->value.type;
4910 assert(frame_type->id == ZigTypeIdCoroFrame);4923 assert(frame_type->id == ZigTypeIdAnyFrame);
4911 ZigFn *fn = frame_type->data.frame.fn;4924 LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame, coro_fn_ptr_index, "");
4912 LLVMValueRef fn_val = fn_llvm_value(g, fn);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 ZigLLVMBuildCall(g->builder, fn_val, &frame, 1, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");4927 ZigLLVMBuildCall(g->builder, fn_val, &frame, 1, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
4914 return nullptr;4928 return nullptr;
4915}4929}
...@@ -6746,11 +6760,6 @@ static void define_builtin_types(CodeGen *g) {...@@ -6746,11 +6760,6 @@ static void define_builtin_types(CodeGen *g) {
67466760
6747 g->primitive_type_table.put(&entry->name, entry);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}
67556764
6756static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) {6765static 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,7 +7764,7 @@ static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node)
7764static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {7764static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
7765 assert(node->type == NodeTypeResume);7765 assert(node->type == NodeTypeResume);
77667766
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 if (target_inst == irb->codegen->invalid_instruction)7768 if (target_inst == irb->codegen->invalid_instruction)
7769 return irb->codegen->invalid_instruction;7769 return irb->codegen->invalid_instruction;
77707770
...@@ -10882,6 +10882,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou...@@ -10882,6 +10882,33 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou
10882 return result;10882 return result;
10883}10883}
1088410884
10885static 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
10898static 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
10885static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,10912static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
10886 ZigType *wanted_type, ResultLoc *result_loc)10913 ZigType *wanted_type, ResultLoc *result_loc)
10887{10914{
...@@ -11978,6 +12005,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -11978,6 +12005,29 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
11978 }12005 }
11979 }12006 }
1198012007
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 }
1198112031
11982 // cast from null literal to maybe type12032 // cast from null literal to maybe type
11983 if (wanted_type->id == ZigTypeIdOptional &&12033 if (wanted_type->id == ZigTypeIdOptional &&
...@@ -24323,17 +24373,27 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru...@@ -24323,17 +24373,27 @@ static IrInstruction *ir_analyze_instruction_suspend_br(IrAnalyze *ira, IrInstru
24323}24373}
2432424374
24325static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) {24375static IrInstruction *ir_analyze_instruction_coro_resume(IrAnalyze *ira, IrInstructionCoroResume *instruction) {
24326 IrInstruction *frame = instruction->frame->child;24376 IrInstruction *frame_ptr = instruction->frame->child;
24327 if (type_is_invalid(frame->value.type))24377 if (type_is_invalid(frame_ptr->value.type))
24328 return ira->codegen->invalid_instruction;24378 return ira->codegen->invalid_instruction;
2432924379
24330 if (frame->value.type->id != ZigTypeIdCoroFrame) {24380 IrInstruction *frame;
24331 ir_add_error(ira, instruction->frame,24381 if (frame_ptr->value.type->id == ZigTypeIdPointer &&
24332 buf_sprintf("expected frame, found '%s'", buf_ptr(&frame->value.type->name)));24382 frame_ptr->value.type->data.pointer.ptr_len == PtrLenSingle &&
24333 return ira->codegen->invalid_instruction;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 }
2433524390
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}
2433824398
24339static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) {24399static 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,15 +5,20 @@ const expect = std.testing.expect;
5var global_x: i32 = 1;5var global_x: i32 = 1;
66
7test "simple coroutine suspend and resume" {7test "simple coroutine suspend and resume" {
8 const p = async simpleAsyncFn();8 const frame = async simpleAsyncFn();
9 expect(global_x == 2);9 expect(global_x == 2);
10 resume p;10 resume frame;
11 expect(global_x == 3);11 expect(global_x == 3);
12 const af: anyframe->void = &frame;
13 resume frame;
14 expect(global_x == 4);
12}15}
13fn simpleAsyncFn() void {16fn simpleAsyncFn() void {
14 global_x += 1;17 global_x += 1;
15 suspend;18 suspend;
16 global_x += 1;19 global_x += 1;
20 suspend;
21 global_x += 1;
17}22}
1823
19var global_y: i32 = 1;24var global_y: i32 = 1;