authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-06-28 01:00:58-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-06-28 01:00:58-04:00
log581d16154baa3b33ad7c07da07306dd1be346411
treee9c1c69e85696a8eb2d73a9c826d6b2cb1a9bb3a
parentac6bf53069d3dccc3236cee05d5da026642ee4d4
parentff2ddcf38d7a2f0fbed40f645278a09ca940a68a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5696 from alexnask/async_call_tuple

@asyncCall now takes arguments as a tuple instead of varargs

10 files changed, 244 insertions(+), 105 deletions(-)

doc/langref.html.in+2-2
...@@ -6689,7 +6689,7 @@ comptime {...@@ -6689,7 +6689,7 @@ comptime {
6689 {#header_close#}6689 {#header_close#}
66906690
6691 {#header_open|@asyncCall#}6691 {#header_open|@asyncCall#}
6692 <pre>{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: ...) anyframe->T{#endsyntax#}</pre>6692 <pre>{#syntax#}@asyncCall(frame_buffer: []align(@alignOf(@Frame(anyAsyncFunction))) u8, result_ptr, function_ptr, args: var) anyframe->T{#endsyntax#}</pre>
6693 <p>6693 <p>
6694 {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer,6694 {#syntax#}@asyncCall{#endsyntax#} performs an {#syntax#}async{#endsyntax#} call on a function pointer,
6695 which may or may not be an {#link|async function|Async Functions#}.6695 which may or may not be an {#link|async function|Async Functions#}.
...@@ -6716,7 +6716,7 @@ test "async fn pointer in a struct field" {...@@ -6716,7 +6716,7 @@ test "async fn pointer in a struct field" {
6716 };6716 };
6717 var foo = Foo{ .bar = func };6717 var foo = Foo{ .bar = func };
6718 var bytes: [64]u8 align(@alignOf(@Frame(func))) = undefined;6718 var bytes: [64]u8 align(@alignOf(@Frame(func))) = undefined;
6719 const f = @asyncCall(&bytes, {}, foo.bar, &data);6719 const f = @asyncCall(&bytes, {}, foo.bar, .{&data});
6720 assert(data == 2);6720 assert(data == 2);
6721 resume f;6721 resume f;
6722 assert(data == 4);6722 assert(data == 4);
lib/std/dwarf.zig+1-1
...@@ -359,7 +359,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endia...@@ -359,7 +359,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, endia
359 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64));359 const F = @TypeOf(async parseFormValue(allocator, in_stream, child_form_id, endian, is_64));
360 var frame = try allocator.create(F);360 var frame = try allocator.create(F);
361 defer allocator.destroy(frame);361 defer allocator.destroy(frame);
362 return await @asyncCall(frame, {}, parseFormValue, allocator, in_stream, child_form_id, endian, is_64);362 return await @asyncCall(frame, {}, parseFormValue, .{ allocator, in_stream, child_form_id, endian, is_64 });
363 },363 },
364 else => error.InvalidDebugInfo,364 else => error.InvalidDebugInfo,
365 };365 };
lib/std/special/test_runner.zig+1-1
...@@ -35,7 +35,7 @@ pub fn main() anyerror!void {...@@ -35,7 +35,7 @@ pub fn main() anyerror!void {
35 async_frame_buffer = try std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size);35 async_frame_buffer = try std.heap.page_allocator.alignedAlloc(u8, std.Target.stack_align, size);
36 }36 }
37 const casted_fn = @ptrCast(fn () callconv(.Async) anyerror!void, test_fn.func);37 const casted_fn = @ptrCast(fn () callconv(.Async) anyerror!void, test_fn.func);
38 break :blk await @asyncCall(async_frame_buffer, {}, casted_fn);38 break :blk await @asyncCall(async_frame_buffer, {}, casted_fn, .{});
39 },39 },
40 .blocking => {40 .blocking => {
41 skip_count += 1;41 skip_count += 1;
lib/std/start.zig+1-1
...@@ -214,7 +214,7 @@ inline fn initEventLoopAndCallMain() u8 {...@@ -214,7 +214,7 @@ inline fn initEventLoopAndCallMain() u8 {
214214
215 var result: u8 = undefined;215 var result: u8 = undefined;
216 var frame: @Frame(callMainAsync) = undefined;216 var frame: @Frame(callMainAsync) = undefined;
217 _ = @asyncCall(&frame, &result, callMainAsync, loop);217 _ = @asyncCall(&frame, &result, callMainAsync, .{loop});
218 loop.run();218 loop.run();
219 return result;219 return result;
220 }220 }
src/all_types.hpp+15
...@@ -2641,6 +2641,7 @@ enum IrInstSrcId {...@@ -2641,6 +2641,7 @@ enum IrInstSrcId {
2641 IrInstSrcIdCall,2641 IrInstSrcIdCall,
2642 IrInstSrcIdCallArgs,2642 IrInstSrcIdCallArgs,
2643 IrInstSrcIdCallExtra,2643 IrInstSrcIdCallExtra,
2644 IrInstSrcIdAsyncCallExtra,
2644 IrInstSrcIdConst,2645 IrInstSrcIdConst,
2645 IrInstSrcIdReturn,2646 IrInstSrcIdReturn,
2646 IrInstSrcIdContainerInitList,2647 IrInstSrcIdContainerInitList,
...@@ -3255,6 +3256,20 @@ struct IrInstSrcCallExtra {...@@ -3255,6 +3256,20 @@ struct IrInstSrcCallExtra {
3255 ResultLoc *result_loc;3256 ResultLoc *result_loc;
3256};3257};
32573258
3259// This is a pass1 instruction, used by @asyncCall, when the args node
3260// is not a literal.
3261// `args` is expected to be either a struct or a tuple.
3262struct IrInstSrcAsyncCallExtra {
3263 IrInstSrc base;
3264
3265 CallModifier modifier;
3266 IrInstSrc *fn_ref;
3267 IrInstSrc *ret_ptr;
3268 IrInstSrc *new_stack;
3269 IrInstSrc *args;
3270 ResultLoc *result_loc;
3271};
3272
3258struct IrInstGenCall {3273struct IrInstGenCall {
3259 IrInstGen base;3274 IrInstGen base;
32603275
src/ir.cpp+139-29
...@@ -310,6 +310,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {...@@ -310,6 +310,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {
310 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCall *>(inst));310 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCall *>(inst));
311 case IrInstSrcIdCallExtra:311 case IrInstSrcIdCallExtra:
312 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallExtra *>(inst));312 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallExtra *>(inst));
313 case IrInstSrcIdAsyncCallExtra:
314 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAsyncCallExtra *>(inst));
313 case IrInstSrcIdUnOp:315 case IrInstSrcIdUnOp:
314 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnOp *>(inst));316 return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnOp *>(inst));
315 case IrInstSrcIdCondBr:317 case IrInstSrcIdCondBr:
...@@ -1173,6 +1175,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallExtra *) {...@@ -1173,6 +1175,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallExtra *) {
1173 return IrInstSrcIdCallExtra;1175 return IrInstSrcIdCallExtra;
1174}1176}
11751177
1178static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsyncCallExtra *) {
1179 return IrInstSrcIdAsyncCallExtra;
1180}
1181
1176static constexpr IrInstSrcId ir_inst_id(IrInstSrcConst *) {1182static constexpr IrInstSrcId ir_inst_id(IrInstSrcConst *) {
1177 return IrInstSrcIdConst;1183 return IrInstSrcIdConst;
1178}1184}
...@@ -2442,6 +2448,25 @@ static IrInstSrc *ir_build_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *...@@ -2442,6 +2448,25 @@ static IrInstSrc *ir_build_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *
2442 return &call_instruction->base;2448 return &call_instruction->base;
2443}2449}
24442450
2451static IrInstSrc *ir_build_async_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
2452 CallModifier modifier, IrInstSrc *fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstSrc *args, ResultLoc *result_loc)
2453{
2454 IrInstSrcAsyncCallExtra *call_instruction = ir_build_instruction<IrInstSrcAsyncCallExtra>(irb, scope, source_node);
2455 call_instruction->modifier = modifier;
2456 call_instruction->fn_ref = fn_ref;
2457 call_instruction->ret_ptr = ret_ptr;
2458 call_instruction->new_stack = new_stack;
2459 call_instruction->args = args;
2460 call_instruction->result_loc = result_loc;
2461
2462 ir_ref_instruction(fn_ref, irb->current_basic_block);
2463 if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block);
2464 ir_ref_instruction(new_stack, irb->current_basic_block);
2465 ir_ref_instruction(args, irb->current_basic_block);
2466
2467 return &call_instruction->base;
2468}
2469
2445static IrInstSrc *ir_build_call_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,2470static IrInstSrc *ir_build_call_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
2446 IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc **args_ptr, size_t args_len,2471 IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc **args_ptr, size_t args_len,
2447 ResultLoc *result_loc)2472 ResultLoc *result_loc)
...@@ -6183,11 +6208,10 @@ static IrInstSrc *ir_gen_this(IrBuilderSrc *irb, Scope *orig_scope, AstNode *nod...@@ -6183,11 +6208,10 @@ static IrInstSrc *ir_gen_this(IrBuilderSrc *irb, Scope *orig_scope, AstNode *nod
6183static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *await_node, AstNode *call_node,6208static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *await_node, AstNode *call_node,
6184 LVal lval, ResultLoc *result_loc)6209 LVal lval, ResultLoc *result_loc)
6185{6210{
6186 size_t arg_offset = 3;6211 if (call_node->data.fn_call_expr.params.length != 4) {
6187 if (call_node->data.fn_call_expr.params.length < arg_offset) {
6188 add_node_error(irb->codegen, call_node,6212 add_node_error(irb->codegen, call_node,
6189 buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize,6213 buf_sprintf("expected 4 arguments, found %" ZIG_PRI_usize,
6190 arg_offset, call_node->data.fn_call_expr.params.length));6214 call_node->data.fn_call_expr.params.length));
6191 return irb->codegen->invalid_inst_src;6215 return irb->codegen->invalid_inst_src;
6192 }6216 }
61936217
...@@ -6206,20 +6230,37 @@ static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *aw...@@ -6206,20 +6230,37 @@ static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *aw
6206 if (fn_ref == irb->codegen->invalid_inst_src)6230 if (fn_ref == irb->codegen->invalid_inst_src)
6207 return fn_ref;6231 return fn_ref;
62086232
6209 size_t arg_count = call_node->data.fn_call_expr.params.length - arg_offset;
6210 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(arg_count);
6211 for (size_t i = 0; i < arg_count; i += 1) {
6212 AstNode *arg_node = call_node->data.fn_call_expr.params.at(i + arg_offset);
6213 IrInstSrc *arg = ir_gen_node(irb, arg_node, scope);
6214 if (arg == irb->codegen->invalid_inst_src)
6215 return arg;
6216 args[i] = arg;
6217 }
6218
6219 CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone;6233 CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone;
6220 bool is_async_call_builtin = true;6234 bool is_async_call_builtin = true;
6221 IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args,6235 AstNode *args_node = call_node->data.fn_call_expr.params.at(3);
6222 ret_ptr, modifier, is_async_call_builtin, bytes, result_loc);6236 if (args_node->type == NodeTypeContainerInitExpr) {
6237 if (args_node->data.container_init_expr.kind == ContainerInitKindArray ||
6238 args_node->data.container_init_expr.entries.length == 0)
6239 {
6240 size_t arg_count = args_node->data.container_init_expr.entries.length;
6241 IrInstSrc **args = heap::c_allocator.allocate<IrInstSrc*>(arg_count);
6242 for (size_t i = 0; i < arg_count; i += 1) {
6243 AstNode *arg_node = args_node->data.container_init_expr.entries.at(i);
6244 IrInstSrc *arg = ir_gen_node(irb, arg_node, scope);
6245 if (arg == irb->codegen->invalid_inst_src)
6246 return arg;
6247 args[i] = arg;
6248 }
6249
6250 IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args,
6251 ret_ptr, modifier, is_async_call_builtin, bytes, result_loc);
6252 return ir_lval_wrap(irb, scope, call, lval, result_loc);
6253 } else {
6254 exec_add_error_node(irb->codegen, irb->exec, args_node,
6255 buf_sprintf("TODO: @asyncCall with anon struct literal"));
6256 return irb->codegen->invalid_inst_src;
6257 }
6258 }
6259 IrInstSrc *args = ir_gen_node(irb, args_node, scope);
6260 if (args == irb->codegen->invalid_inst_src)
6261 return args;
6262
6263 IrInstSrc *call = ir_build_async_call_extra(irb, scope, call_node, modifier, fn_ref, ret_ptr, bytes, args, result_loc);
6223 return ir_lval_wrap(irb, scope, call, lval, result_loc);6264 return ir_lval_wrap(irb, scope, call, lval, result_loc);
6224}6265}
62256266
...@@ -20721,40 +20762,106 @@ static IrInstGen *ir_analyze_call_extra(IrAnalyze *ira, IrInst* source_instr,...@@ -20721,40 +20762,106 @@ static IrInstGen *ir_analyze_call_extra(IrAnalyze *ira, IrInst* source_instr,
20721 modifier, stack, stack_src, false, args_ptr, args_len, nullptr, result_loc);20762 modifier, stack, stack_src, false, args_ptr, args_len, nullptr, result_loc);
20722}20763}
2072320764
20724static IrInstGen *ir_analyze_instruction_call_extra(IrAnalyze *ira, IrInstSrcCallExtra *instruction) {20765static IrInstGen *ir_analyze_async_call_extra(IrAnalyze *ira, IrInst* source_instr, CallModifier modifier,
20725 IrInstGen *args = instruction->args->child;20766 IrInstSrc *pass1_fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstGen **args_ptr, size_t args_len, ResultLoc *result_loc)
20767{
20768 IrInstGen *fn_ref = pass1_fn_ref->child;
20769 if (type_is_invalid(fn_ref->value->type))
20770 return ira->codegen->invalid_inst_gen;
20771
20772 if (ir_should_inline(ira->old_irb.exec, source_instr->scope)) {
20773 ir_add_error(ira, source_instr, buf_sprintf("TODO: comptime @asyncCall"));
20774 return ira->codegen->invalid_inst_gen;
20775 }
20776
20777 IrInstGen *first_arg_ptr = nullptr;
20778 IrInst *first_arg_ptr_src = nullptr;
20779 ZigFn *fn = nullptr;
20780 if (instr_is_comptime(fn_ref)) {
20781 if (fn_ref->value->type->id == ZigTypeIdBoundFn) {
20782 assert(fn_ref->value->special == ConstValSpecialStatic);
20783 fn = fn_ref->value->data.x_bound_fn.fn;
20784 first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg;
20785 first_arg_ptr_src = fn_ref->value->data.x_bound_fn.first_arg_src;
20786 if (type_is_invalid(first_arg_ptr->value->type))
20787 return ira->codegen->invalid_inst_gen;
20788 } else {
20789 fn = ir_resolve_fn(ira, fn_ref);
20790 }
20791 }
20792
20793 IrInstGen *ret_ptr_uncasted = nullptr;
20794 if (ret_ptr != nullptr) {
20795 ret_ptr_uncasted = ret_ptr->child;
20796 if (type_is_invalid(ret_ptr_uncasted->value->type))
20797 return ira->codegen->invalid_inst_gen;
20798 }
20799
20800 ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type;
20801 IrInstGen *casted_new_stack = analyze_casted_new_stack(ira, source_instr, new_stack->child,
20802 &new_stack->base, true, fn);
20803 if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type))
20804 return ira->codegen->invalid_inst_gen;
20805
20806 return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr, first_arg_ptr_src,
20807 modifier, casted_new_stack, &new_stack->base, true, args_ptr, args_len, ret_ptr_uncasted, result_loc);
20808}
20809
20810static bool ir_extract_tuple_call_args(IrAnalyze *ira, IrInst *source_instr, IrInstGen *args, IrInstGen ***args_ptr, size_t *args_len) {
20726 ZigType *args_type = args->value->type;20811 ZigType *args_type = args->value->type;
20727 if (type_is_invalid(args_type))20812 if (type_is_invalid(args_type))
20728 return ira->codegen->invalid_inst_gen;20813 return false;
2072920814
20730 if (args_type->id != ZigTypeIdStruct) {20815 if (args_type->id != ZigTypeIdStruct) {
20731 ir_add_error(ira, &args->base,20816 ir_add_error(ira, &args->base,
20732 buf_sprintf("expected tuple or struct, found '%s'", buf_ptr(&args_type->name)));20817 buf_sprintf("expected tuple or struct, found '%s'", buf_ptr(&args_type->name)));
20733 return ira->codegen->invalid_inst_gen;20818 return false;
20734 }20819 }
2073520820
20736 IrInstGen **args_ptr = nullptr;
20737 size_t args_len = 0;
20738
20739 if (is_tuple(args_type)) {20821 if (is_tuple(args_type)) {
20740 args_len = args_type->data.structure.src_field_count;20822 *args_len = args_type->data.structure.src_field_count;
20741 args_ptr = heap::c_allocator.allocate<IrInstGen *>(args_len);20823 *args_ptr = heap::c_allocator.allocate<IrInstGen *>(*args_len);
20742 for (size_t i = 0; i < args_len; i += 1) {20824 for (size_t i = 0; i < *args_len; i += 1) {
20743 TypeStructField *arg_field = args_type->data.structure.fields[i];20825 TypeStructField *arg_field = args_type->data.structure.fields[i];
20744 args_ptr[i] = ir_analyze_struct_value_field_value(ira, &instruction->base.base, args, arg_field);20826 (*args_ptr)[i] = ir_analyze_struct_value_field_value(ira, source_instr, args, arg_field);
20745 if (type_is_invalid(args_ptr[i]->value->type))20827 if (type_is_invalid((*args_ptr)[i]->value->type))
20746 return ira->codegen->invalid_inst_gen;20828 return false;
20747 }20829 }
20748 } else {20830 } else {
20749 ir_add_error(ira, &args->base, buf_sprintf("TODO: struct args"));20831 ir_add_error(ira, &args->base, buf_sprintf("TODO: struct args"));
20832 return false;
20833 }
20834 return true;
20835}
20836
20837static IrInstGen *ir_analyze_instruction_call_extra(IrAnalyze *ira, IrInstSrcCallExtra *instruction) {
20838 IrInstGen *args = instruction->args->child;
20839 IrInstGen **args_ptr = nullptr;
20840 size_t args_len = 0;
20841 if (!ir_extract_tuple_call_args(ira, &instruction->base.base, args, &args_ptr, &args_len)) {
20750 return ira->codegen->invalid_inst_gen;20842 return ira->codegen->invalid_inst_gen;
20751 }20843 }
20844
20752 IrInstGen *result = ir_analyze_call_extra(ira, &instruction->base.base, instruction->options,20845 IrInstGen *result = ir_analyze_call_extra(ira, &instruction->base.base, instruction->options,
20753 instruction->fn_ref, args_ptr, args_len, instruction->result_loc);20846 instruction->fn_ref, args_ptr, args_len, instruction->result_loc);
20754 heap::c_allocator.deallocate(args_ptr, args_len);20847 heap::c_allocator.deallocate(args_ptr, args_len);
20755 return result;20848 return result;
20756}20849}
2075720850
20851static IrInstGen *ir_analyze_instruction_async_call_extra(IrAnalyze *ira, IrInstSrcAsyncCallExtra *instruction) {
20852 IrInstGen *args = instruction->args->child;
20853 IrInstGen **args_ptr = nullptr;
20854 size_t args_len = 0;
20855 if (!ir_extract_tuple_call_args(ira, &instruction->base.base, args, &args_ptr, &args_len)) {
20856 return ira->codegen->invalid_inst_gen;
20857 }
20858
20859 IrInstGen *result = ir_analyze_async_call_extra(ira, &instruction->base.base, instruction->modifier,
20860 instruction->fn_ref, instruction->ret_ptr, instruction->new_stack, args_ptr, args_len, instruction->result_loc);
20861 heap::c_allocator.deallocate(args_ptr, args_len);
20862 return result;
20863}
20864
20758static IrInstGen *ir_analyze_instruction_call_args(IrAnalyze *ira, IrInstSrcCallArgs *instruction) {20865static IrInstGen *ir_analyze_instruction_call_args(IrAnalyze *ira, IrInstSrcCallArgs *instruction) {
20759 IrInstGen **args_ptr = heap::c_allocator.allocate<IrInstGen *>(instruction->args_len);20866 IrInstGen **args_ptr = heap::c_allocator.allocate<IrInstGen *>(instruction->args_len);
20760 for (size_t i = 0; i < instruction->args_len; i += 1) {20867 for (size_t i = 0; i < instruction->args_len; i += 1) {
...@@ -31103,6 +31210,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc...@@ -31103,6 +31210,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc
31103 return ir_analyze_instruction_call_args(ira, (IrInstSrcCallArgs *)instruction);31210 return ir_analyze_instruction_call_args(ira, (IrInstSrcCallArgs *)instruction);
31104 case IrInstSrcIdCallExtra:31211 case IrInstSrcIdCallExtra:
31105 return ir_analyze_instruction_call_extra(ira, (IrInstSrcCallExtra *)instruction);31212 return ir_analyze_instruction_call_extra(ira, (IrInstSrcCallExtra *)instruction);
31213 case IrInstSrcIdAsyncCallExtra:
31214 return ir_analyze_instruction_async_call_extra(ira, (IrInstSrcAsyncCallExtra *)instruction);
31106 case IrInstSrcIdBr:31215 case IrInstSrcIdBr:
31107 return ir_analyze_instruction_br(ira, (IrInstSrcBr *)instruction);31216 return ir_analyze_instruction_br(ira, (IrInstSrcBr *)instruction);
31108 case IrInstSrcIdCondBr:31217 case IrInstSrcIdCondBr:
...@@ -31612,6 +31721,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {...@@ -31612,6 +31721,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
31612 case IrInstSrcIdDeclVar:31721 case IrInstSrcIdDeclVar:
31613 case IrInstSrcIdStorePtr:31722 case IrInstSrcIdStorePtr:
31614 case IrInstSrcIdCallExtra:31723 case IrInstSrcIdCallExtra:
31724 case IrInstSrcIdAsyncCallExtra:
31615 case IrInstSrcIdCall:31725 case IrInstSrcIdCall:
31616 case IrInstSrcIdCallArgs:31726 case IrInstSrcIdCallArgs:
31617 case IrInstSrcIdReturn:31727 case IrInstSrcIdReturn:
src/ir_print.cpp+55-54
...@@ -5,6 +5,7 @@...@@ -5,6 +5,7 @@
5 * See http://opensource.org/licenses/MIT5 * See http://opensource.org/licenses/MIT
6 */6 */
77
8#include "all_types.hpp"
8#include "analyze.hpp"9#include "analyze.hpp"
9#include "ir.hpp"10#include "ir.hpp"
10#include "ir_print.hpp"11#include "ir_print.hpp"
...@@ -55,6 +56,36 @@ struct IrPrintGen {...@@ -55,6 +56,36 @@ struct IrPrintGen {
55static void ir_print_other_inst_src(IrPrintSrc *irp, IrInstSrc *inst);56static void ir_print_other_inst_src(IrPrintSrc *irp, IrInstSrc *inst);
56static void ir_print_other_inst_gen(IrPrintGen *irp, IrInstGen *inst);57static void ir_print_other_inst_gen(IrPrintGen *irp, IrInstGen *inst);
5758
59static void ir_print_call_modifier(FILE *f, CallModifier modifier) {
60 switch (modifier) {
61 case CallModifierNone:
62 break;
63 case CallModifierNoSuspend:
64 fprintf(f, "nosuspend ");
65 break;
66 case CallModifierAsync:
67 fprintf(f, "async ");
68 break;
69 case CallModifierNeverTail:
70 fprintf(f, "notail ");
71 break;
72 case CallModifierNeverInline:
73 fprintf(f, "noinline ");
74 break;
75 case CallModifierAlwaysTail:
76 fprintf(f, "tail ");
77 break;
78 case CallModifierAlwaysInline:
79 fprintf(f, "inline ");
80 break;
81 case CallModifierCompileTime:
82 fprintf(f, "comptime ");
83 break;
84 case CallModifierBuiltin:
85 zig_unreachable();
86 }
87}
88
58const char* ir_inst_src_type_str(IrInstSrcId id) {89const char* ir_inst_src_type_str(IrInstSrcId id) {
59 switch (id) {90 switch (id) {
60 case IrInstSrcIdInvalid:91 case IrInstSrcIdInvalid:
...@@ -97,6 +128,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {...@@ -97,6 +128,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {
97 return "SrcVarPtr";128 return "SrcVarPtr";
98 case IrInstSrcIdCallExtra:129 case IrInstSrcIdCallExtra:
99 return "SrcCallExtra";130 return "SrcCallExtra";
131 case IrInstSrcIdAsyncCallExtra:
132 return "SrcAsyncCallExtra";
100 case IrInstSrcIdCall:133 case IrInstSrcIdCall:
101 return "SrcCall";134 return "SrcCall";
102 case IrInstSrcIdCallArgs:135 case IrInstSrcIdCallArgs:
...@@ -851,6 +884,23 @@ static void ir_print_call_extra(IrPrintSrc *irp, IrInstSrcCallExtra *instruction...@@ -851,6 +884,23 @@ static void ir_print_call_extra(IrPrintSrc *irp, IrInstSrcCallExtra *instruction
851 ir_print_result_loc(irp, instruction->result_loc);884 ir_print_result_loc(irp, instruction->result_loc);
852}885}
853886
887static void ir_print_async_call_extra(IrPrintSrc *irp, IrInstSrcAsyncCallExtra *instruction) {
888 fprintf(irp->f, "modifier=");
889 ir_print_call_modifier(irp->f, instruction->modifier);
890 fprintf(irp->f, ", fn=");
891 ir_print_other_inst_src(irp, instruction->fn_ref);
892 if (instruction->ret_ptr != nullptr) {
893 fprintf(irp->f, ", ret_ptr=");
894 ir_print_other_inst_src(irp, instruction->ret_ptr);
895 }
896 fprintf(irp->f, ", new_stack=");
897 ir_print_other_inst_src(irp, instruction->new_stack);
898 fprintf(irp->f, ", args=");
899 ir_print_other_inst_src(irp, instruction->args);
900 fprintf(irp->f, ", result=");
901 ir_print_result_loc(irp, instruction->result_loc);
902}
903
854static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction) {904static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction) {
855 fprintf(irp->f, "opts=");905 fprintf(irp->f, "opts=");
856 ir_print_other_inst_src(irp, instruction->options);906 ir_print_other_inst_src(irp, instruction->options);
...@@ -868,33 +918,7 @@ static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction)...@@ -868,33 +918,7 @@ static void ir_print_call_args(IrPrintSrc *irp, IrInstSrcCallArgs *instruction)
868}918}
869919
870static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction) {920static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction) {
871 switch (call_instruction->modifier) {921 ir_print_call_modifier(irp->f, call_instruction->modifier);
872 case CallModifierNone:
873 break;
874 case CallModifierNoSuspend:
875 fprintf(irp->f, "nosuspend ");
876 break;
877 case CallModifierAsync:
878 fprintf(irp->f, "async ");
879 break;
880 case CallModifierNeverTail:
881 fprintf(irp->f, "notail ");
882 break;
883 case CallModifierNeverInline:
884 fprintf(irp->f, "noinline ");
885 break;
886 case CallModifierAlwaysTail:
887 fprintf(irp->f, "tail ");
888 break;
889 case CallModifierAlwaysInline:
890 fprintf(irp->f, "inline ");
891 break;
892 case CallModifierCompileTime:
893 fprintf(irp->f, "comptime ");
894 break;
895 case CallModifierBuiltin:
896 zig_unreachable();
897 }
898 if (call_instruction->fn_entry) {922 if (call_instruction->fn_entry) {
899 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));923 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
900 } else {924 } else {
...@@ -913,33 +937,7 @@ static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction)...@@ -913,33 +937,7 @@ static void ir_print_call_src(IrPrintSrc *irp, IrInstSrcCall *call_instruction)
913}937}
914938
915static void ir_print_call_gen(IrPrintGen *irp, IrInstGenCall *call_instruction) {939static void ir_print_call_gen(IrPrintGen *irp, IrInstGenCall *call_instruction) {
916 switch (call_instruction->modifier) {940 ir_print_call_modifier(irp->f, call_instruction->modifier);
917 case CallModifierNone:
918 break;
919 case CallModifierNoSuspend:
920 fprintf(irp->f, "nosuspend ");
921 break;
922 case CallModifierAsync:
923 fprintf(irp->f, "async ");
924 break;
925 case CallModifierNeverTail:
926 fprintf(irp->f, "notail ");
927 break;
928 case CallModifierNeverInline:
929 fprintf(irp->f, "noinline ");
930 break;
931 case CallModifierAlwaysTail:
932 fprintf(irp->f, "tail ");
933 break;
934 case CallModifierAlwaysInline:
935 fprintf(irp->f, "inline ");
936 break;
937 case CallModifierCompileTime:
938 fprintf(irp->f, "comptime ");
939 break;
940 case CallModifierBuiltin:
941 zig_unreachable();
942 }
943 if (call_instruction->fn_entry) {941 if (call_instruction->fn_entry) {
944 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));942 fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
945 } else {943 } else {
...@@ -2619,6 +2617,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai...@@ -2619,6 +2617,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai
2619 case IrInstSrcIdCallExtra:2617 case IrInstSrcIdCallExtra:
2620 ir_print_call_extra(irp, (IrInstSrcCallExtra *)instruction);2618 ir_print_call_extra(irp, (IrInstSrcCallExtra *)instruction);
2621 break;2619 break;
2620 case IrInstSrcIdAsyncCallExtra:
2621 ir_print_async_call_extra(irp, (IrInstSrcAsyncCallExtra *)instruction);
2622 break;
2622 case IrInstSrcIdCall:2623 case IrInstSrcIdCall:
2623 ir_print_call_src(irp, (IrInstSrcCall *)instruction);2624 ir_print_call_src(irp, (IrInstSrcCall *)instruction);
2624 break;2625 break;
test/compile_errors.zig+16-3
...@@ -1144,13 +1144,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1144,13 +1144,26 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1144 "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'",1144 "tmp.zig:2:15: error: @Type not available for 'TypeInfo.Struct'",
1145 });1145 });
11461146
1147 cases.add("wrong type for argument tuple to @asyncCall",
1148 \\export fn entry1() void {
1149 \\ var frame: @Frame(foo) = undefined;
1150 \\ @asyncCall(&frame, {}, foo, {});
1151 \\}
1152 \\
1153 \\fn foo() i32 {
1154 \\ return 0;
1155 \\}
1156 , &[_][]const u8{
1157 "tmp.zig:3:33: error: expected tuple or struct, found 'void'",
1158 });
1159
1147 cases.add("wrong type for result ptr to @asyncCall",1160 cases.add("wrong type for result ptr to @asyncCall",
1148 \\export fn entry() void {1161 \\export fn entry() void {
1149 \\ _ = async amain();1162 \\ _ = async amain();
1150 \\}1163 \\}
1151 \\fn amain() i32 {1164 \\fn amain() i32 {
1152 \\ var frame: @Frame(foo) = undefined;1165 \\ var frame: @Frame(foo) = undefined;
1153 \\ return await @asyncCall(&frame, false, foo);1166 \\ return await @asyncCall(&frame, false, foo, .{});
1154 \\}1167 \\}
1155 \\fn foo() i32 {1168 \\fn foo() i32 {
1156 \\ return 1234;1169 \\ return 1234;
...@@ -1291,7 +1304,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1291,7 +1304,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1291 \\export fn entry() void {1304 \\export fn entry() void {
1292 \\ var ptr: fn () callconv(.Async) void = func;1305 \\ var ptr: fn () callconv(.Async) void = func;
1293 \\ var bytes: [64]u8 = undefined;1306 \\ var bytes: [64]u8 = undefined;
1294 \\ _ = @asyncCall(&bytes, {}, ptr);1307 \\ _ = @asyncCall(&bytes, {}, ptr, .{});
1295 \\}1308 \\}
1296 \\fn func() callconv(.Async) void {}1309 \\fn func() callconv(.Async) void {}
1297 , &[_][]const u8{1310 , &[_][]const u8{
...@@ -1467,7 +1480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1467,7 +1480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1467 \\export fn entry() void {1480 \\export fn entry() void {
1468 \\ var ptr = afunc;1481 \\ var ptr = afunc;
1469 \\ var bytes: [100]u8 align(16) = undefined;1482 \\ var bytes: [100]u8 align(16) = undefined;
1470 \\ _ = @asyncCall(&bytes, {}, ptr);1483 \\ _ = @asyncCall(&bytes, {}, ptr, .{});
1471 \\}1484 \\}
1472 \\fn afunc() void { }1485 \\fn afunc() void { }
1473 , &[_][]const u8{1486 , &[_][]const u8{
test/runtime_safety.zig+1-1
...@@ -280,7 +280,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -280,7 +280,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
280 \\pub fn main() void {280 \\pub fn main() void {
281 \\ var bytes: [1]u8 align(16) = undefined;281 \\ var bytes: [1]u8 align(16) = undefined;
282 \\ var ptr = other;282 \\ var ptr = other;
283 \\ var frame = @asyncCall(&bytes, {}, ptr);283 \\ var frame = @asyncCall(&bytes, {}, ptr, .{});
284 \\}284 \\}
285 \\fn other() callconv(.Async) void {285 \\fn other() callconv(.Async) void {
286 \\ suspend;286 \\ suspend;
test/stage1/behavior/async_fn.zig+13-13
...@@ -282,7 +282,7 @@ test "async fn pointer in a struct field" {...@@ -282,7 +282,7 @@ test "async fn pointer in a struct field" {
282 };282 };
283 var foo = Foo{ .bar = simpleAsyncFn2 };283 var foo = Foo{ .bar = simpleAsyncFn2 };
284 var bytes: [64]u8 align(16) = undefined;284 var bytes: [64]u8 align(16) = undefined;
285 const f = @asyncCall(&bytes, {}, foo.bar, &data);285 const f = @asyncCall(&bytes, {}, foo.bar, .{&data});
286 comptime expect(@TypeOf(f) == anyframe->void);286 comptime expect(@TypeOf(f) == anyframe->void);
287 expect(data == 2);287 expect(data == 2);
288 resume f;288 resume f;
...@@ -318,7 +318,7 @@ test "@asyncCall with return type" {...@@ -318,7 +318,7 @@ test "@asyncCall with return type" {
318 var foo = Foo{ .bar = Foo.middle };318 var foo = Foo{ .bar = Foo.middle };
319 var bytes: [150]u8 align(16) = undefined;319 var bytes: [150]u8 align(16) = undefined;
320 var aresult: i32 = 0;320 var aresult: i32 = 0;
321 _ = @asyncCall(&bytes, &aresult, foo.bar);321 _ = @asyncCall(&bytes, &aresult, foo.bar, .{});
322 expect(aresult == 0);322 expect(aresult == 0);
323 resume Foo.global_frame;323 resume Foo.global_frame;
324 expect(aresult == 1234);324 expect(aresult == 1234);
...@@ -332,7 +332,7 @@ test "async fn with inferred error set" {...@@ -332,7 +332,7 @@ test "async fn with inferred error set" {
332 var frame: [1]@Frame(middle) = undefined;332 var frame: [1]@Frame(middle) = undefined;
333 var fn_ptr = middle;333 var fn_ptr = middle;
334 var result: @TypeOf(fn_ptr).ReturnType.ErrorSet!void = undefined;334 var result: @TypeOf(fn_ptr).ReturnType.ErrorSet!void = undefined;
335 _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr);335 _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, fn_ptr, .{});
336 resume global_frame;336 resume global_frame;
337 std.testing.expectError(error.Fail, result);337 std.testing.expectError(error.Fail, result);
338 }338 }
...@@ -827,7 +827,7 @@ test "cast fn to async fn when it is inferred to be async" {...@@ -827,7 +827,7 @@ test "cast fn to async fn when it is inferred to be async" {
827 ptr = func;827 ptr = func;
828 var buf: [100]u8 align(16) = undefined;828 var buf: [100]u8 align(16) = undefined;
829 var result: i32 = undefined;829 var result: i32 = undefined;
830 const f = @asyncCall(&buf, &result, ptr);830 const f = @asyncCall(&buf, &result, ptr, .{});
831 _ = await f;831 _ = await f;
832 expect(result == 1234);832 expect(result == 1234);
833 ok = true;833 ok = true;
...@@ -855,7 +855,7 @@ test "cast fn to async fn when it is inferred to be async, awaited directly" {...@@ -855,7 +855,7 @@ test "cast fn to async fn when it is inferred to be async, awaited directly" {
855 ptr = func;855 ptr = func;
856 var buf: [100]u8 align(16) = undefined;856 var buf: [100]u8 align(16) = undefined;
857 var result: i32 = undefined;857 var result: i32 = undefined;
858 _ = await @asyncCall(&buf, &result, ptr);858 _ = await @asyncCall(&buf, &result, ptr, .{});
859 expect(result == 1234);859 expect(result == 1234);
860 ok = true;860 ok = true;
861 }861 }
...@@ -951,7 +951,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" {...@@ -951,7 +951,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" {
951 fn doTheTest() void {951 fn doTheTest() void {
952 var frame: [1]@Frame(middle) = undefined;952 var frame: [1]@Frame(middle) = undefined;
953 var result: @TypeOf(middle).ReturnType.ErrorSet!void = undefined;953 var result: @TypeOf(middle).ReturnType.ErrorSet!void = undefined;
954 _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle);954 _ = @asyncCall(std.mem.sliceAsBytes(frame[0..]), &result, middle, .{});
955 resume global_frame;955 resume global_frame;
956 std.testing.expectError(error.Fail, result);956 std.testing.expectError(error.Fail, result);
957 }957 }
...@@ -982,7 +982,7 @@ test "@asyncCall with actual frame instead of byte buffer" {...@@ -982,7 +982,7 @@ test "@asyncCall with actual frame instead of byte buffer" {
982 };982 };
983 var frame: @Frame(S.func) = undefined;983 var frame: @Frame(S.func) = undefined;
984 var result: i32 = undefined;984 var result: i32 = undefined;
985 const ptr = @asyncCall(&frame, &result, S.func);985 const ptr = @asyncCall(&frame, &result, S.func, .{});
986 resume ptr;986 resume ptr;
987 expect(result == 1234);987 expect(result == 1234);
988}988}
...@@ -1005,7 +1005,7 @@ test "@asyncCall using the result location inside the frame" {...@@ -1005,7 +1005,7 @@ test "@asyncCall using the result location inside the frame" {
1005 };1005 };
1006 var foo = Foo{ .bar = S.simple2 };1006 var foo = Foo{ .bar = S.simple2 };
1007 var bytes: [64]u8 align(16) = undefined;1007 var bytes: [64]u8 align(16) = undefined;
1008 const f = @asyncCall(&bytes, {}, foo.bar, &data);1008 const f = @asyncCall(&bytes, {}, foo.bar, .{&data});
1009 comptime expect(@TypeOf(f) == anyframe->i32);1009 comptime expect(@TypeOf(f) == anyframe->i32);
1010 expect(data == 2);1010 expect(data == 2);
1011 resume f;1011 resume f;
...@@ -1042,7 +1042,7 @@ test "using @TypeOf on a generic function call" {...@@ -1042,7 +1042,7 @@ test "using @TypeOf on a generic function call" {
1042 }1042 }
1043 const F = @TypeOf(async amain(x - 1));1043 const F = @TypeOf(async amain(x - 1));
1044 const frame = @intToPtr(*F, @ptrToInt(&buf));1044 const frame = @intToPtr(*F, @ptrToInt(&buf));
1045 return await @asyncCall(frame, {}, amain, x - 1);1045 return await @asyncCall(frame, {}, amain, .{x - 1});
1046 }1046 }
1047 };1047 };
1048 _ = async S.amain(@as(u32, 1));1048 _ = async S.amain(@as(u32, 1));
...@@ -1067,7 +1067,7 @@ test "recursive call of await @asyncCall with struct return type" {...@@ -1067,7 +1067,7 @@ test "recursive call of await @asyncCall with struct return type" {
1067 }1067 }
1068 const F = @TypeOf(async amain(x - 1));1068 const F = @TypeOf(async amain(x - 1));
1069 const frame = @intToPtr(*F, @ptrToInt(&buf));1069 const frame = @intToPtr(*F, @ptrToInt(&buf));
1070 return await @asyncCall(frame, {}, amain, x - 1);1070 return await @asyncCall(frame, {}, amain, .{x - 1});
1071 }1071 }
10721072
1073 const Foo = struct {1073 const Foo = struct {
...@@ -1078,7 +1078,7 @@ test "recursive call of await @asyncCall with struct return type" {...@@ -1078,7 +1078,7 @@ test "recursive call of await @asyncCall with struct return type" {
1078 };1078 };
1079 var res: S.Foo = undefined;1079 var res: S.Foo = undefined;
1080 var frame: @TypeOf(async S.amain(@as(u32, 1))) = undefined;1080 var frame: @TypeOf(async S.amain(@as(u32, 1))) = undefined;
1081 _ = @asyncCall(&frame, &res, S.amain, @as(u32, 1));1081 _ = @asyncCall(&frame, &res, S.amain, .{@as(u32, 1)});
1082 resume S.global_frame;1082 resume S.global_frame;
1083 expect(S.global_ok);1083 expect(S.global_ok);
1084 expect(res.x == 1);1084 expect(res.x == 1);
...@@ -1377,7 +1377,7 @@ test "async function call resolves target fn frame, comptime func" {...@@ -1377,7 +1377,7 @@ test "async function call resolves target fn frame, comptime func" {
1377 fn foo() anyerror!void {1377 fn foo() anyerror!void {
1378 const stack_size = 1000;1378 const stack_size = 1000;
1379 var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;1379 var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
1380 return await @asyncCall(&stack_frame, {}, bar);1380 return await @asyncCall(&stack_frame, {}, bar, .{});
1381 }1381 }
13821382
1383 fn bar() anyerror!void {1383 fn bar() anyerror!void {
...@@ -1400,7 +1400,7 @@ test "async function call resolves target fn frame, runtime func" {...@@ -1400,7 +1400,7 @@ test "async function call resolves target fn frame, runtime func" {
1400 const stack_size = 1000;1400 const stack_size = 1000;
1401 var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;1401 var stack_frame: [stack_size]u8 align(std.Target.stack_align) = undefined;
1402 var func: fn () callconv(.Async) anyerror!void = bar;1402 var func: fn () callconv(.Async) anyerror!void = bar;
1403 return await @asyncCall(&stack_frame, {}, func);1403 return await @asyncCall(&stack_frame, {}, func, .{});
1404 }1404 }
14051405
1406 fn bar() anyerror!void {1406 fn bar() anyerror!void {