authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-07 17:37:17-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-07 17:37:17-04:00
log229323e13a074e94ef8a58409c81cfd9ac807dd8
tree07e39a8d4656fcd930b381466d07e67bb8bb837b
parentd3cf040c900c14feec427f3835f247b6a4c616bb
signaturelock-open Commit is signed but in an unrecognized format.

fix suspensions inside for loops generating invalid LLVM IR

closes #3076

5 files changed, 59 insertions(+), 12 deletions(-)

src/all_types.hpp+2
...@@ -25,6 +25,7 @@ struct ZigFn;...@@ -25,6 +25,7 @@ struct ZigFn;
25struct Scope;25struct Scope;
26struct ScopeBlock;26struct ScopeBlock;
27struct ScopeFnDef;27struct ScopeFnDef;
28struct ScopeExpr;
28struct ZigType;29struct ZigType;
29struct ZigVar;30struct ZigVar;
30struct ErrorTableEntry;31struct 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};
22342236
2235// This scope blocks certain things from working such as comptime continue2237// 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}
229229
230Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent) {230ScopeExpr *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}
243243
244ZigType *get_scope_import(Scope *scope) {244ZigType *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 instructions5947 // 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}
63966412
6397static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {6413static 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 *
114Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);114Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
115Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);115Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
116Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);116Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);
117Scope *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent);117ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent);
118118
119void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);119void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
120ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);120ConstExprValue *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);
64766476
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
65046506
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);
65096511
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);
65196521
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;
65276530
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);
65316534
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;
65426546
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
1155test "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