| author | |
| committer | |
| log | 229323e13a074e94ef8a58409c81cfd9ac807dd8 |
| tree | 07e39a8d4656fcd930b381466d07e67bb8bb837b |
| parent | d3cf040c900c14feec427f3835f247b6a4c616bb |
| signature |
closes #30765 files changed, 59 insertions(+), 12 deletions(-)
src/all_types.hpp+2| ... | @@ -25,6 +25,7 @@ struct ZigFn; | ... | @@ -25,6 +25,7 @@ struct ZigFn; |
| 25 | struct Scope; | 25 | struct Scope; |
| 26 | struct ScopeBlock; | 26 | struct ScopeBlock; |
| 27 | struct ScopeFnDef; | 27 | struct ScopeFnDef; |
| 28 | struct ScopeExpr; | ||
| 28 | struct ZigType; | 29 | struct ZigType; |
| 29 | struct ZigVar; | 30 | struct ZigVar; |
| 30 | struct ErrorTableEntry; | 31 | struct ErrorTableEntry; |
| ... | @@ -2230,6 +2231,7 @@ struct ScopeLoop { | ... | @@ -2230,6 +2231,7 @@ struct ScopeLoop { |
| 2230 | ZigList<IrInstruction *> *incoming_values; | 2231 | ZigList<IrInstruction *> *incoming_values; |
| 2231 | ZigList<IrBasicBlock *> *incoming_blocks; | 2232 | ZigList<IrBasicBlock *> *incoming_blocks; |
| 2232 | ResultLocPeerParent *peer_parent; | 2233 | ResultLocPeerParent *peer_parent; |
| 2234 | ScopeExpr *spill_scope; | ||
| 2233 | }; | 2235 | }; |
| 2234 | 2236 | ||
| 2235 | // This scope blocks certain things from working such as comptime continue | 2237 | // This scope blocks certain things from working such as comptime continue |
src/analyze.cpp+20-6| ... | @@ -227,7 +227,7 @@ Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) { | ... | @@ -227,7 +227,7 @@ Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) { |
| 227 | return &scope->base; | 227 | return &scope->base; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { | 230 | ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { |
| 231 | ScopeExpr *scope = allocate<ScopeExpr>(1); | 231 | ScopeExpr *scope = allocate<ScopeExpr>(1); |
| 232 | init_scope(g, &scope->base, ScopeIdExpr, node, parent); | 232 | init_scope(g, &scope->base, ScopeIdExpr, node, parent); |
| 233 | ScopeExpr *parent_expr = find_expr_scope(parent); | 233 | ScopeExpr *parent_expr = find_expr_scope(parent); |
| ... | @@ -238,7 +238,7 @@ Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { | ... | @@ -238,7 +238,7 @@ Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) { |
| 238 | parent_expr->children_ptr[parent_expr->children_len] = scope; | 238 | parent_expr->children_ptr[parent_expr->children_len] = scope; |
| 239 | parent_expr->children_len = new_len; | 239 | parent_expr->children_len = new_len; |
| 240 | } | 240 | } |
| 241 | return &scope->base; | 241 | return scope; |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | ZigType *get_scope_import(Scope *scope) { | 244 | ZigType *get_scope_import(Scope *scope) { |
| ... | @@ -5713,7 +5713,6 @@ static void mark_suspension_point(Scope *scope) { | ... | @@ -5713,7 +5713,6 @@ static void mark_suspension_point(Scope *scope) { |
| 5713 | case ScopeIdCImport: | 5713 | case ScopeIdCImport: |
| 5714 | case ScopeIdSuspend: | 5714 | case ScopeIdSuspend: |
| 5715 | case ScopeIdTypeOf: | 5715 | case ScopeIdTypeOf: |
| 5716 | case ScopeIdBlock: | ||
| 5717 | return; | 5716 | return; |
| 5718 | case ScopeIdLoop: | 5717 | case ScopeIdLoop: |
| 5719 | case ScopeIdRuntime: | 5718 | case ScopeIdRuntime: |
| ... | @@ -5730,6 +5729,14 @@ static void mark_suspension_point(Scope *scope) { | ... | @@ -5730,6 +5729,14 @@ static void mark_suspension_point(Scope *scope) { |
| 5730 | child_expr_scope = parent_expr_scope; | 5729 | child_expr_scope = parent_expr_scope; |
| 5731 | continue; | 5730 | continue; |
| 5732 | } | 5731 | } |
| 5732 | case ScopeIdBlock: | ||
| 5733 | if (scope->parent->parent->id == ScopeIdLoop) { | ||
| 5734 | ScopeLoop *loop_scope = reinterpret_cast<ScopeLoop *>(scope->parent->parent); | ||
| 5735 | if (loop_scope->spill_scope != nullptr) { | ||
| 5736 | loop_scope->spill_scope->need_spill = MemoizedBoolTrue; | ||
| 5737 | } | ||
| 5738 | } | ||
| 5739 | return; | ||
| 5733 | } | 5740 | } |
| 5734 | } | 5741 | } |
| 5735 | } | 5742 | } |
| ... | @@ -5928,6 +5935,15 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { | ... | @@ -5928,6 +5935,15 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5928 | await->result_loc = ir_create_alloca(g, await->base.scope, await->base.source_node, fn, | 5935 | await->result_loc = ir_create_alloca(g, await->base.scope, await->base.source_node, fn, |
| 5929 | await->base.value.type, ""); | 5936 | await->base.value.type, ""); |
| 5930 | } | 5937 | } |
| 5938 | for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) { | ||
| 5939 | IrBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i); | ||
| 5940 | for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) { | ||
| 5941 | IrInstruction *instruction = block->instruction_list.at(instr_i); | ||
| 5942 | if (instruction->id == IrInstructionIdSuspendFinish) { | ||
| 5943 | mark_suspension_point(instruction->scope); | ||
| 5944 | } | ||
| 5945 | } | ||
| 5946 | } | ||
| 5931 | // Now that we've marked all the expr scopes that have to spill, we go over the instructions | 5947 | // Now that we've marked all the expr scopes that have to spill, we go over the instructions |
| 5932 | // and spill the relevant ones. | 5948 | // and spill the relevant ones. |
| 5933 | for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) { | 5949 | for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) { |
| ... | @@ -6395,9 +6411,7 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v | ... | @@ -6395,9 +6411,7 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v |
| 6395 | } | 6411 | } |
| 6396 | 6412 | ||
| 6397 | static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { | 6413 | static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { |
| 6398 | assert(type_entry->id == ZigTypeIdPointer); | 6414 | if (type_entry->id == ZigTypeIdPointer && type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { |
| 6399 | |||
| 6400 | if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { | ||
| 6401 | buf_append_buf(buf, &type_entry->name); | 6415 | buf_append_buf(buf, &type_entry->name); |
| 6402 | return; | 6416 | return; |
| 6403 | } | 6417 | } |
src/analyze.hpp+1-1| ... | @@ -114,7 +114,7 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn * | ... | @@ -114,7 +114,7 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn * |
| 114 | Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); | 114 | Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 115 | Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); | 115 | Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); |
| 116 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); | 116 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 117 | Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent); | 117 | ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 118 | 118 | ||
| 119 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); | 119 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); |
| 120 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); | 120 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); |
src/ir.cpp+9-5| ... | @@ -6474,6 +6474,8 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -6474,6 +6474,8 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 6474 | IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, | 6474 | IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, |
| 6475 | ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); | 6475 | ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); |
| 6476 | 6476 | ||
| 6477 | ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, parent_scope); | ||
| 6478 | |||
| 6477 | AstNode *index_var_source_node; | 6479 | AstNode *index_var_source_node; |
| 6478 | ZigVar *index_var; | 6480 | ZigVar *index_var; |
| 6479 | const char *index_var_name; | 6481 | const char *index_var_name; |
| ... | @@ -6504,11 +6506,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -6504,11 +6506,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 6504 | 6506 | ||
| 6505 | Buf *len_field_name = buf_create_from_str("len"); | 6507 | Buf *len_field_name = buf_create_from_str("len"); |
| 6506 | IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name, false); | 6508 | IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name, false); |
| 6507 | IrInstruction *len_val = ir_build_load_ptr(irb, parent_scope, node, len_ref); | 6509 | IrInstruction *len_val = ir_build_load_ptr(irb, &spill_scope->base, node, len_ref); |
| 6508 | ir_build_br(irb, parent_scope, node, cond_block, is_comptime); | 6510 | ir_build_br(irb, parent_scope, node, cond_block, is_comptime); |
| 6509 | 6511 | ||
| 6510 | ir_set_cursor_at_end_and_append_block(irb, cond_block); | 6512 | ir_set_cursor_at_end_and_append_block(irb, cond_block); |
| 6511 | IrInstruction *index_val = ir_build_load_ptr(irb, parent_scope, node, index_ptr); | 6513 | IrInstruction *index_val = ir_build_load_ptr(irb, &spill_scope->base, node, index_ptr); |
| 6512 | IrInstruction *cond = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); | 6514 | IrInstruction *cond = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); |
| 6513 | IrBasicBlock *after_cond_block = irb->current_basic_block; | 6515 | IrBasicBlock *after_cond_block = irb->current_basic_block; |
| 6514 | IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node)); | 6516 | IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node)); |
| ... | @@ -6518,7 +6520,8 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -6518,7 +6520,8 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 6518 | ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, is_comptime); | 6520 | ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, is_comptime); |
| 6519 | 6521 | ||
| 6520 | ir_set_cursor_at_end_and_append_block(irb, body_block); | 6522 | ir_set_cursor_at_end_and_append_block(irb, body_block); |
| 6521 | IrInstruction *elem_ptr = ir_build_elem_ptr(irb, parent_scope, node, array_val_ptr, index_val, false, | 6523 | Scope *elem_ptr_scope = node->data.for_expr.elem_is_ptr ? parent_scope : &spill_scope->base; |
| 6524 | IrInstruction *elem_ptr = ir_build_elem_ptr(irb, elem_ptr_scope, node, array_val_ptr, index_val, false, | ||
| 6522 | PtrLenSingle, nullptr); | 6525 | PtrLenSingle, nullptr); |
| 6523 | // TODO make it an error to write to element variable or i variable. | 6526 | // TODO make it an error to write to element variable or i variable. |
| 6524 | Buf *elem_var_name = elem_node->data.symbol_expr.symbol; | 6527 | Buf *elem_var_name = elem_node->data.symbol_expr.symbol; |
| ... | @@ -6526,7 +6529,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -6526,7 +6529,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 6526 | Scope *child_scope = elem_var->child_scope; | 6529 | Scope *child_scope = elem_var->child_scope; |
| 6527 | 6530 | ||
| 6528 | IrInstruction *var_ptr = node->data.for_expr.elem_is_ptr ? | 6531 | IrInstruction *var_ptr = node->data.for_expr.elem_is_ptr ? |
| 6529 | ir_build_ref(irb, parent_scope, elem_node, elem_ptr, true, false) : elem_ptr; | 6532 | ir_build_ref(irb, &spill_scope->base, elem_node, elem_ptr, true, false) : elem_ptr; |
| 6530 | ir_build_var_decl_src(irb, parent_scope, elem_node, elem_var, nullptr, var_ptr); | 6533 | ir_build_var_decl_src(irb, parent_scope, elem_node, elem_var, nullptr, var_ptr); |
| 6531 | 6534 | ||
| 6532 | ZigList<IrInstruction *> incoming_values = {0}; | 6535 | ZigList<IrInstruction *> incoming_values = {0}; |
| ... | @@ -6539,6 +6542,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo | ... | @@ -6539,6 +6542,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo |
| 6539 | loop_scope->incoming_values = &incoming_values; | 6542 | loop_scope->incoming_values = &incoming_values; |
| 6540 | loop_scope->lval = LValNone; | 6543 | loop_scope->lval = LValNone; |
| 6541 | loop_scope->peer_parent = peer_parent; | 6544 | loop_scope->peer_parent = peer_parent; |
| 6545 | loop_scope->spill_scope = spill_scope; | ||
| 6542 | 6546 | ||
| 6543 | // Note the body block of the loop is not the place that lval and result_loc are used - | 6547 | // Note the body block of the loop is not the place that lval and result_loc are used - |
| 6544 | // it's actually in break statements, handled similarly to return statements. | 6548 | // it's actually in break statements, handled similarly to return statements. |
| ... | @@ -8166,7 +8170,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc | ... | @@ -8166,7 +8170,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc |
| 8166 | { | 8170 | { |
| 8167 | child_scope = scope; | 8171 | child_scope = scope; |
| 8168 | } else { | 8172 | } else { |
| 8169 | child_scope = create_expr_scope(irb->codegen, node, scope); | 8173 | child_scope = &create_expr_scope(irb->codegen, node, scope)->base; |
| 8170 | } | 8174 | } |
| 8171 | IrInstruction *result = ir_gen_node_raw(irb, node, child_scope, lval, result_loc); | 8175 | IrInstruction *result = ir_gen_node_raw(irb, node, child_scope, lval, result_loc); |
| 8172 | if (result == irb->codegen->invalid_instruction) { | 8176 | if (result == irb->codegen->invalid_instruction) { |
test/stage1/behavior/async_fn.zig+27| ... | @@ -1151,3 +1151,30 @@ test "async fn call used in expression after a fn call" { | ... | @@ -1151,3 +1151,30 @@ test "async fn call used in expression after a fn call" { |
| 1151 | }; | 1151 | }; |
| 1152 | _ = async S.atest(); | 1152 | _ = async S.atest(); |
| 1153 | } | 1153 | } |
| 1154 | |||
| 1155 | test "suspend in for loop" { | ||
| 1156 | const S = struct { | ||
| 1157 | var global_frame: ?anyframe = null; | ||
| 1158 | |||
| 1159 | fn doTheTest() void { | ||
| 1160 | _ = async atest(); | ||
| 1161 | while (global_frame) |f| resume f; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | fn atest() void { | ||
| 1165 | expect(func([_]u8{ 1, 2, 3 }) == 6); | ||
| 1166 | } | ||
| 1167 | fn func(stuff: []const u8) u32 { | ||
| 1168 | global_frame = @frame(); | ||
| 1169 | var sum: u32 = 0; | ||
| 1170 | for (stuff) |x| { | ||
| 1171 | suspend; | ||
| 1172 | sum += x; | ||
| 1173 | } | ||
| 1174 | global_frame = null; | ||
| 1175 | return sum; | ||
| 1176 | } | ||
| 1177 | }; | ||
| 1178 | S.doTheTest(); | ||
| 1179 | } | ||
| 1180 |