authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-16 01:32:15-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-16 01:44:52-05:00
log7f7d1fbe5ad16fd41eeaeb20e3e71a39bdd3f991
tree1c726145e8b301beb25ab781ab9e06d27c146797
parentcb3a818699649a985d5879151936b3b88ffddfa4
signaturelock-open Commit is signed but in an unrecognized format.

Implement noasync awaits

Note that there is not yet runtime safety for this. See #3157

6 files changed, 28 insertions(+), 10 deletions(-)

src/all_types.hpp+3
...@@ -1139,6 +1139,7 @@ struct AstNodeErrorType {...@@ -1139,6 +1139,7 @@ struct AstNodeErrorType {
1139};1139};
11401140
1141struct AstNodeAwaitExpr {1141struct AstNodeAwaitExpr {
1142 Token *noasync_token;
1142 AstNode *expr;1143 AstNode *expr;
1143};1144};
11441145
...@@ -4500,6 +4501,7 @@ struct IrInstSrcAwait {...@@ -4500,6 +4501,7 @@ struct IrInstSrcAwait {
45004501
4501 IrInstSrc *frame;4502 IrInstSrc *frame;
4502 ResultLoc *result_loc;4503 ResultLoc *result_loc;
4504 bool is_noasync;
4503};4505};
45044506
4505struct IrInstGenAwait {4507struct IrInstGenAwait {
...@@ -4508,6 +4510,7 @@ struct IrInstGenAwait {...@@ -4508,6 +4510,7 @@ struct IrInstGenAwait {
4508 IrInstGen *frame;4510 IrInstGen *frame;
4509 IrInstGen *result_loc;4511 IrInstGen *result_loc;
4510 ZigFn *target_fn;4512 ZigFn *target_fn;
4513 bool is_noasync;
4511};4514};
45124515
4513struct IrInstSrcResume {4516struct IrInstSrcResume {
src/analyze.cpp+4-4
...@@ -4710,8 +4710,7 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {...@@ -4710,8 +4710,7 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
4710 }4710 }
4711 for (size_t i = 0; i < fn->await_list.length; i += 1) {4711 for (size_t i = 0; i < fn->await_list.length; i += 1) {
4712 IrInstGenAwait *await = fn->await_list.at(i);4712 IrInstGenAwait *await = fn->await_list.at(i);
4713 // TODO If this is a noasync await, it doesn't count4713 if (await->is_noasync) continue;
4714 // https://github.com/ziglang/zig/issues/3157
4715 switch (analyze_callee_async(g, fn, await->target_fn, await->base.base.source_node, must_not_be_async,4714 switch (analyze_callee_async(g, fn, await->target_fn, await->base.base.source_node, must_not_be_async,
4716 CallModifierNone))4715 CallModifierNone))
4717 {4716 {
...@@ -6315,8 +6314,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {...@@ -6315,8 +6314,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
6315 // The funtion call result of foo() must be spilled.6314 // The funtion call result of foo() must be spilled.
6316 for (size_t i = 0; i < fn->await_list.length; i += 1) {6315 for (size_t i = 0; i < fn->await_list.length; i += 1) {
6317 IrInstGenAwait *await = fn->await_list.at(i);6316 IrInstGenAwait *await = fn->await_list.at(i);
6318 // TODO If this is a noasync await, it doesn't suspend6317 if (await->is_noasync) {
6319 // https://github.com/ziglang/zig/issues/31576318 continue;
6319 }
6320 if (await->base.value->special != ConstValSpecialRuntime) {6320 if (await->base.value->special != ConstValSpecialRuntime) {
6321 // Known at comptime. No spill, no suspend.6321 // Known at comptime. No spill, no suspend.
6322 continue;6322 continue;
src/codegen.cpp+3-1
...@@ -6188,7 +6188,9 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutableGen *executable, IrI...@@ -6188,7 +6188,9 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutableGen *executable, IrI
6188 LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?6188 LLVMValueRef result_loc = (instruction->result_loc == nullptr) ?
6189 nullptr : ir_llvm_value(g, instruction->result_loc);6189 nullptr : ir_llvm_value(g, instruction->result_loc);
61906190
6191 if (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn)) {6191 if (instruction->is_noasync ||
6192 (instruction->target_fn != nullptr && !fn_is_async(instruction->target_fn)))
6193 {
6192 return gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type,6194 return gen_await_early_return(g, &instruction->base, target_frame_ptr, result_type,
6193 ptr_result_type, result_loc, true);6195 ptr_result_type, result_loc, true);
6194 }6196 }
src/ir.cpp+10-5
...@@ -4956,11 +4956,12 @@ static IrInstGen *ir_build_suspend_finish_gen(IrAnalyze *ira, IrInst *source_ins...@@ -4956,11 +4956,12 @@ static IrInstGen *ir_build_suspend_finish_gen(IrAnalyze *ira, IrInst *source_ins
4956}4956}
49574957
4958static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,4958static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
4959 IrInstSrc *frame, ResultLoc *result_loc)4959 IrInstSrc *frame, ResultLoc *result_loc, bool is_noasync)
4960{4960{
4961 IrInstSrcAwait *instruction = ir_build_instruction<IrInstSrcAwait>(irb, scope, source_node);4961 IrInstSrcAwait *instruction = ir_build_instruction<IrInstSrcAwait>(irb, scope, source_node);
4962 instruction->frame = frame;4962 instruction->frame = frame;
4963 instruction->result_loc = result_loc;4963 instruction->result_loc = result_loc;
4964 instruction->is_noasync = is_noasync;
49644965
4965 ir_ref_instruction(frame, irb->current_basic_block);4966 ir_ref_instruction(frame, irb->current_basic_block);
49664967
...@@ -4968,13 +4969,14 @@ static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *s...@@ -4968,13 +4969,14 @@ static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *s
4968}4969}
49694970
4970static IrInstGenAwait *ir_build_await_gen(IrAnalyze *ira, IrInst *source_instruction,4971static IrInstGenAwait *ir_build_await_gen(IrAnalyze *ira, IrInst *source_instruction,
4971 IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc)4972 IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc, bool is_noasync)
4972{4973{
4973 IrInstGenAwait *instruction = ir_build_inst_gen<IrInstGenAwait>(&ira->new_irb,4974 IrInstGenAwait *instruction = ir_build_inst_gen<IrInstGenAwait>(&ira->new_irb,
4974 source_instruction->scope, source_instruction->source_node);4975 source_instruction->scope, source_instruction->source_node);
4975 instruction->base.value->type = result_type;4976 instruction->base.value->type = result_type;
4976 instruction->frame = frame;4977 instruction->frame = frame;
4977 instruction->result_loc = result_loc;4978 instruction->result_loc = result_loc;
4979 instruction->is_noasync = is_noasync;
49784980
4979 ir_ref_inst_gen(frame, ira->new_irb.current_basic_block);4981 ir_ref_inst_gen(frame, ira->new_irb.current_basic_block);
4980 if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);4982 if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);
...@@ -9953,6 +9955,8 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no...@@ -9953,6 +9955,8 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
9953{9955{
9954 assert(node->type == NodeTypeAwaitExpr);9956 assert(node->type == NodeTypeAwaitExpr);
99559957
9958 bool is_noasync = node->data.await_expr.noasync_token != nullptr;
9959
9956 AstNode *expr_node = node->data.await_expr.expr;9960 AstNode *expr_node = node->data.await_expr.expr;
9957 if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) {9961 if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) {
9958 AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr;9962 AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr;
...@@ -9985,7 +9989,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no...@@ -9985,7 +9989,7 @@ static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
9985 if (target_inst == irb->codegen->invalid_inst_src)9989 if (target_inst == irb->codegen->invalid_inst_src)
9986 return irb->codegen->invalid_inst_src;9990 return irb->codegen->invalid_inst_src;
99879991
9988 IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc);9992 IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc, is_noasync);
9989 return ir_lval_wrap(irb, scope, await_inst, lval, result_loc);9993 return ir_lval_wrap(irb, scope, await_inst, lval, result_loc);
9990}9994}
99919995
...@@ -29505,7 +29509,7 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i...@@ -29505,7 +29509,7 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i
29505 ir_assert(fn_entry != nullptr, &instruction->base.base);29509 ir_assert(fn_entry != nullptr, &instruction->base.base);
2950629510
29507 // If it's not @Frame(func) then it's definitely a suspend point29511 // If it's not @Frame(func) then it's definitely a suspend point
29508 if (target_fn == nullptr) {29512 if (target_fn == nullptr && !instruction->is_noasync) {
29509 if (fn_entry->inferred_async_node == nullptr) {29513 if (fn_entry->inferred_async_node == nullptr) {
29510 fn_entry->inferred_async_node = instruction->base.base.source_node;29514 fn_entry->inferred_async_node = instruction->base.base.source_node;
29511 }29515 }
...@@ -29528,7 +29532,8 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i...@@ -29528,7 +29532,8 @@ static IrInstGen *ir_analyze_instruction_await(IrAnalyze *ira, IrInstSrcAwait *i
29528 result_loc = nullptr;29532 result_loc = nullptr;
29529 }29533 }
2953029534
29531 IrInstGenAwait *result = ir_build_await_gen(ira, &instruction->base.base, frame, result_type, result_loc);29535 IrInstGenAwait *result = ir_build_await_gen(ira, &instruction->base.base, frame, result_type, result_loc,
29536 instruction->is_noasync);
29532 result->target_fn = target_fn;29537 result->target_fn = target_fn;
29533 fn_entry->await_list.append(result);29538 fn_entry->await_list.append(result);
29534 return ir_finish_anal(ira, &result->base);29539 return ir_finish_anal(ira, &result->base);
src/parser.cpp+4
...@@ -2596,10 +2596,14 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {...@@ -2596,10 +2596,14 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) {
2596 return res;2596 return res;
2597 }2597 }
25982598
2599 Token *noasync_token = eat_token_if(pc, TokenIdKeywordNoAsync);
2599 Token *await = eat_token_if(pc, TokenIdKeywordAwait);2600 Token *await = eat_token_if(pc, TokenIdKeywordAwait);
2600 if (await != nullptr) {2601 if (await != nullptr) {
2601 AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await);2602 AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await);
2603 res->data.await_expr.noasync_token = noasync_token;
2602 return res;2604 return res;
2605 } else if (noasync_token != nullptr) {
2606 put_back_token(pc);
2603 }2607 }
26042608
2605 return nullptr;2609 return nullptr;
test/stage1/behavior/async_fn.zig+4
...@@ -1513,9 +1513,12 @@ test "take address of temporary async frame" {...@@ -1513,9 +1513,12 @@ test "take address of temporary async frame" {
15131513
1514test "noasync await" {1514test "noasync await" {
1515 const S = struct {1515 const S = struct {
1516 var finished = false;
1517
1516 fn doTheTest() void {1518 fn doTheTest() void {
1517 var frame = async foo(false);1519 var frame = async foo(false);
1518 expect(noasync await frame == 42);1520 expect(noasync await frame == 42);
1521 finished = true;
1519 }1522 }
15201523
1521 fn foo(want_suspend: bool) i32 {1524 fn foo(want_suspend: bool) i32 {
...@@ -1526,4 +1529,5 @@ test "noasync await" {...@@ -1526,4 +1529,5 @@ test "noasync await" {
1526 }1529 }
1527 };1530 };
1528 S.doTheTest();1531 S.doTheTest();
1532 expect(S.finished);
1529}1533}