authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-02-01 20:39:09+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-18 19:17:20-07:00
log6733e43d87d4fe7b9d89948ebb95a72515c44fee
tree1f2726f2aaba809843500572d26315f8271200ff
parent1b7055b514955f1787937b2ef6097d2e0663da74

AstGen: work-in-progress multi-object for loops


1 files changed, 141 insertions(+), 78 deletions(-)

src/AstGen.zig+141-78
...@@ -518,6 +518,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins...@@ -518,6 +518,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Ins
518 .error_union,518 .error_union,
519 .merge_error_sets,519 .merge_error_sets,
520 .switch_range,520 .switch_range,
521 .for_range,
521 .@"await",522 .@"await",
522 .bit_not,523 .bit_not,
523 .negation,524 .negation,
...@@ -646,6 +647,8 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -646,6 +647,8 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
646 .asm_output => unreachable, // Handled in `asmExpr`.647 .asm_output => unreachable, // Handled in `asmExpr`.
647 .asm_input => unreachable, // Handled in `asmExpr`.648 .asm_input => unreachable, // Handled in `asmExpr`.
648649
650 .for_range => unreachable, // Handled in `forExpr`.
651
649 .assign => {652 .assign => {
650 try assign(gz, scope, node);653 try assign(gz, scope, node);
651 return rvalue(gz, ri, .void_value, node);654 return rvalue(gz, ri, .void_value, node);
...@@ -834,7 +837,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -834,7 +837,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
834 .@"while",837 .@"while",
835 => return whileExpr(gz, scope, ri.br(), node, tree.fullWhile(node).?, false),838 => return whileExpr(gz, scope, ri.br(), node, tree.fullWhile(node).?, false),
836839
837 .for_simple, .@"for" => return forExpr(gz, scope, ri.br(), node, tree.fullWhile(node).?, false),840 .for_simple, .@"for" => return forExpr(gz, scope, ri.br(), node, tree.fullFor(node).?, false),
838841
839 .slice_open => {842 .slice_open => {
840 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);843 const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
...@@ -2342,7 +2345,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod...@@ -2342,7 +2345,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
2342 .@"while", => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullWhile(inner_node).?, true),2345 .@"while", => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullWhile(inner_node).?, true),
23432346
2344 .for_simple,2347 .for_simple,
2345 .@"for", => _ = try forExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullWhile(inner_node).?, true),2348 .@"for", => _ = try forExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullFor(inner_node).?, true),
23462349
2347 else => noreturn_src_node = try unusedResultExpr(gz, scope, inner_node),2350 else => noreturn_src_node = try unusedResultExpr(gz, scope, inner_node),
2348 // zig fmt: on2351 // zig fmt: on
...@@ -6282,7 +6285,7 @@ fn forExpr(...@@ -6282,7 +6285,7 @@ fn forExpr(
6282 scope: *Scope,6285 scope: *Scope,
6283 ri: ResultInfo,6286 ri: ResultInfo,
6284 node: Ast.Node.Index,6287 node: Ast.Node.Index,
6285 for_full: Ast.full.While,6288 for_full: Ast.full.For,
6286 is_statement: bool,6289 is_statement: bool,
6287) InnerError!Zir.Inst.Ref {6290) InnerError!Zir.Inst.Ref {
6288 const astgen = parent_gz.astgen;6291 const astgen = parent_gz.astgen;
...@@ -6295,23 +6298,79 @@ fn forExpr(...@@ -6295,23 +6298,79 @@ fn forExpr(
6295 const is_inline = parent_gz.force_comptime or for_full.inline_token != null;6298 const is_inline = parent_gz.force_comptime or for_full.inline_token != null;
6296 const tree = astgen.tree;6299 const tree = astgen.tree;
6297 const token_tags = tree.tokens.items(.tag);6300 const token_tags = tree.tokens.items(.tag);
6301 const node_tags = tree.nodes.items(.tag);
6302 const node_data = tree.nodes.items(.data);
62986303
6299 const payload_is_ref = if (for_full.payload_token) |payload_token|6304 // Check for unterminated ranges.
6300 token_tags[payload_token] == .asterisk6305 {
6301 else6306 var unterminated: ?Ast.Node.Index = null;
6302 false;6307 for (for_full.ast.inputs) |input| {
6308 if (node_tags[input] != .for_range) break;
6309 if (node_data[input].rhs != 0) break;
6310 unterminated = unterminated orelse input;
6311 } else {
6312 return astgen.failNode(unterminated.?, "unterminated for range", .{});
6313 }
6314 }
6315
6316 var lens = astgen.gpa.alloc(Zir.Inst.Ref, for_full.ast.inputs.len);
6317 defer astgen.gpa.free(lens);
6318 var indexables = astgen.gpa.alloc(Zir.Inst.Ref, for_full.ast.inputs.len);
6319 defer astgen.gpa.free(indexables);
6320 var counters = std.ArrayList(Zir.Inst.Ref).init(astgen.gpa);
6321 defer counters.deinit();
63036322
6304 try emitDbgNode(parent_gz, for_full.ast.cond_expr);6323 const counter_alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc;
6324
6325 {
6326 var payload = for_full.payload_token;
6327 for (for_full.ast.inputs) |input, i| {
6328 const payload_is_ref = token_tags[payload] == .asterisk;
6329 const ident_tok = payload + @boolToInt(payload_is_ref);
6330
6331 if (mem.eql(u8, tree.tokenSlice(ident_tok), "_") and payload_is_ref) {
6332 return astgen.failTok(payload, "pointer modifier invalid on discard", .{});
6333 }
6334 payload = ident_tok + @as(u32, 2);
6335
6336 try emitDbgNode(parent_gz, input);
6337 if (node_tags[input] == .for_range) {
6338 if (payload_is_ref) {
6339 return astgen.failTok(ident_tok, "cannot capture reference to range", .{});
6340 }
6341 const counter_ptr = try parent_gz.addUnNode(counter_alloc_tag, .usize_type, node);
6342 const start_val = try expr(parent_gz, scope, node_data[input].lhs, input);
6343 _ = try parent_gz.addBin(.store, counter_ptr, start_val);
6344 indexables[i] = counter_ptr;
6345 try counters.append(counter_ptr);
6346
6347 const end_node = node_data[input].rhs;
6348 const end_val = if (end_node != 0) try expr(parent_gz, scope, node_data[input].rhs, input) else .none;
6349 const range_len = try parent_gz.addPlNode(.for_range_len, input, Zir.Inst.Bin{
6350 .lhs = start_val,
6351 .rhs = end_val,
6352 });
6353 lens[i] = range_len;
6354 } else {
6355 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };
6356 const indexable = try expr(parent_gz, scope, cond_ri, input);
6357 indexables[i] = indexable;
6358
6359 const indexable_len = try parent_gz.addUnNode(.indexable_ptr_len, indexable, input);
6360 lens[i] = indexable_len;
6361 }
6362 }
6363 }
63056364
6306 const cond_ri: ResultInfo = .{ .rl = if (payload_is_ref) .ref else .none };6365 const len = "check_for_lens";
6307 const array_ptr = try expr(parent_gz, scope, cond_ri, for_full.ast.cond_expr);
6308 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
63096366
6310 const index_ptr = blk: {6367 const index_ptr = blk: {
6311 const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc;6368 // Future optimization:
6312 const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node);6369 // for loops with only ranges don't need a separate index variable.
6370 const index_ptr = try parent_gz.addUnNode(counter_alloc_tag, .usize_type, node);
6313 // initialize to zero6371 // initialize to zero
6314 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize);6372 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize);
6373 try counters.append(index_ptr);
6315 break :blk index_ptr;6374 break :blk index_ptr;
6316 };6375 };
63176376
...@@ -6343,13 +6402,15 @@ fn forExpr(...@@ -6343,13 +6402,15 @@ fn forExpr(
6343 // cond_block unstacked now, can add new instructions to loop_scope6402 // cond_block unstacked now, can add new instructions to loop_scope
6344 try loop_scope.instructions.append(astgen.gpa, cond_block);6403 try loop_scope.instructions.append(astgen.gpa, cond_block);
63456404
6346 // Increment the index variable.6405 // Increment the index variable and ranges.
6347 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);6406 for (counters) |counter_ptr| {
6348 const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{6407 const counter = try loop_scope.addUnNode(.load, counter_ptr, for_full.ast.cond_expr);
6349 .lhs = index_2,6408 const counter_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{
6350 .rhs = .one_usize,6409 .lhs = counter,
6351 });6410 .rhs = .one_usize,
6352 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);6411 });
6412 _ = try loop_scope.addBin(.store, counter_ptr, counter_plus_one);
6413 }
6353 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;6414 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
6354 _ = try loop_scope.addNode(repeat_tag, node);6415 _ = try loop_scope.addNode(repeat_tag, node);
63556416
...@@ -6366,64 +6427,62 @@ fn forExpr(...@@ -6366,64 +6427,62 @@ fn forExpr(
6366 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);6427 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
6367 defer then_scope.unstack();6428 defer then_scope.unstack();
63686429
6369 try then_scope.addDbgBlockBegin();6430 const then_sub_scope = &then_scope.base;
6370 var payload_val_scope: Scope.LocalVal = undefined;6431
6371 var index_scope: Scope.LocalPtr = undefined;6432 // try then_scope.addDbgBlockBegin();
6372 const then_sub_scope = blk: {6433 // var payload_val_scope: Scope.LocalVal = undefined;
6373 const payload_token = for_full.payload_token.?;6434 // var index_scope: Scope.LocalPtr = undefined;
6374 const ident = if (token_tags[payload_token] == .asterisk)6435 // const then_sub_scope = blk: {
6375 payload_token + 16436 // const payload_token = for_full.payload_token.?;
6376 else6437 // const ident = if (token_tags[payload_token] == .asterisk)
6377 payload_token;6438 // payload_token + 1
6378 const is_ptr = ident != payload_token;6439 // else
6379 const value_name = tree.tokenSlice(ident);6440 // payload_token;
6380 var payload_sub_scope: *Scope = undefined;6441 // const is_ptr = ident != payload_token;
6381 if (!mem.eql(u8, value_name, "_")) {6442 // const value_name = tree.tokenSlice(ident);
6382 const name_str_index = try astgen.identAsString(ident);6443 // var payload_sub_scope: *Scope = undefined;
6383 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;6444 // if (!mem.eql(u8, value_name, "_")) {
6384 const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{6445 // const name_str_index = try astgen.identAsString(ident);
6385 .lhs = array_ptr,6446 // const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
6386 .rhs = index,6447 // const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{
6387 });6448 // .lhs = array_ptr,
6388 try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture);6449 // .rhs = index,
6389 payload_val_scope = .{6450 // });
6390 .parent = &then_scope.base,6451 // try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture);
6391 .gen_zir = &then_scope,6452 // payload_val_scope = .{
6392 .name = name_str_index,6453 // .parent = &then_scope.base,
6393 .inst = payload_inst,6454 // .gen_zir = &then_scope,
6394 .token_src = ident,6455 // .name = name_str_index,
6395 .id_cat = .capture,6456 // .inst = payload_inst,
6396 };6457 // .token_src = ident,
6397 try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst);6458 // .id_cat = .capture,
6398 payload_sub_scope = &payload_val_scope.base;6459 // };
6399 } else if (is_ptr) {6460 // try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst);
6400 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});6461 // payload_sub_scope = &payload_val_scope.base;
6401 } else {6462 // } else if (is_ptr) {
6402 payload_sub_scope = &then_scope.base;6463 // } else {
6403 }6464 // payload_sub_scope = &then_scope.base;
64046465 // }
6405 const index_token = if (token_tags[ident + 1] == .comma)6466
6406 ident + 26467 // const index_token = if (token_tags[ident + 1] == .comma)
6407 else6468 // ident + 2
6408 break :blk payload_sub_scope;6469 // else
6409 const token_bytes = tree.tokenSlice(index_token);6470 // break :blk payload_sub_scope;
6410 if (mem.eql(u8, token_bytes, "_")) {6471 // const token_bytes = tree.tokenSlice(index_token);
6411 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});6472 // const index_name = try astgen.identAsString(index_token);
6412 }6473 // try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture");
6413 const index_name = try astgen.identAsString(index_token);6474 // index_scope = .{
6414 try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture");6475 // .parent = payload_sub_scope,
6415 index_scope = .{6476 // .gen_zir = &then_scope,
6416 .parent = payload_sub_scope,6477 // .name = index_name,
6417 .gen_zir = &then_scope,6478 // .ptr = index_ptr,
6418 .name = index_name,6479 // .token_src = index_token,
6419 .ptr = index_ptr,6480 // .maybe_comptime = is_inline,
6420 .token_src = index_token,6481 // .id_cat = .@"loop index capture",
6421 .maybe_comptime = is_inline,6482 // };
6422 .id_cat = .@"loop index capture",6483 // try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr);
6423 };6484 // break :blk &index_scope.base;
6424 try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr);6485 // };
6425 break :blk &index_scope.base;
6426 };
64276486
6428 const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr);6487 const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr);
6429 _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr);6488 _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr);
...@@ -9021,6 +9080,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_...@@ -9021,6 +9080,7 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index, have_
9021 .mul_wrap,9080 .mul_wrap,
9022 .mul_sat,9081 .mul_sat,
9023 .switch_range,9082 .switch_range,
9083 .for_range,
9024 .field_access,9084 .field_access,
9025 .sub,9085 .sub,
9026 .sub_wrap,9086 .sub_wrap,
...@@ -9310,6 +9370,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev...@@ -9310,6 +9370,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
9310 .mul_wrap,9370 .mul_wrap,
9311 .mul_sat,9371 .mul_sat,
9312 .switch_range,9372 .switch_range,
9373 .for_range,
9313 .sub,9374 .sub,
9314 .sub_wrap,9375 .sub_wrap,
9315 .sub_sat,9376 .sub_sat,
...@@ -9487,6 +9548,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In...@@ -9487,6 +9548,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In
9487 .mul_wrap,9548 .mul_wrap,
9488 .mul_sat,9549 .mul_sat,
9489 .switch_range,9550 .switch_range,
9551 .for_range,
9490 .field_access,9552 .field_access,
9491 .sub,9553 .sub,
9492 .sub_wrap,9554 .sub_wrap,
...@@ -9731,6 +9793,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -9731,6 +9793,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
9731 .mul_wrap,9793 .mul_wrap,
9732 .mul_sat,9794 .mul_sat,
9733 .switch_range,9795 .switch_range,
9796 .for_range,
9734 .field_access,9797 .field_access,
9735 .sub,9798 .sub,
9736 .sub_wrap,9799 .sub_wrap,