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
518518 .error_union,
519519 .merge_error_sets,
520520 .switch_range,
521 .for_range,
521522 .@"await",
522523 .bit_not,
523524 .negation,
......@@ -646,6 +647,8 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
646647 .asm_output => unreachable, // Handled in `asmExpr`.
647648 .asm_input => unreachable, // Handled in `asmExpr`.
648649
650 .for_range => unreachable, // Handled in `forExpr`.
651
649652 .assign => {
650653 try assign(gz, scope, node);
651654 return rvalue(gz, ri, .void_value, node);
......@@ -834,7 +837,7 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
834837 .@"while",
835838 => 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
839842 .slice_open => {
840843 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
23422345 .@"while", => _ = try whileExpr(gz, scope, .{ .rl = .discard }, inner_node, tree.fullWhile(inner_node).?, true),
23432346
23442347 .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
23472350 else => noreturn_src_node = try unusedResultExpr(gz, scope, inner_node),
23482351 // zig fmt: on
......@@ -6282,7 +6285,7 @@ fn forExpr(
62826285 scope: *Scope,
62836286 ri: ResultInfo,
62846287 node: Ast.Node.Index,
6285 for_full: Ast.full.While,
6288 for_full: Ast.full.For,
62866289 is_statement: bool,
62876290) InnerError!Zir.Inst.Ref {
62886291 const astgen = parent_gz.astgen;
......@@ -6295,23 +6298,79 @@ fn forExpr(
62956298 const is_inline = parent_gz.force_comptime or for_full.inline_token != null;
62966299 const tree = astgen.tree;
62976300 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|
6300 token_tags[payload_token] == .asterisk
6301 else
6302 false;
6304 // Check for unterminated ranges.
6305 {
6306 var unterminated: ?Ast.Node.Index = null;
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 };
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);
6365 const len = "check_for_lens";
63096366
63106367 const index_ptr = blk: {
6311 const alloc_tag: Zir.Inst.Tag = if (is_inline) .alloc_comptime_mut else .alloc;
6312 const index_ptr = try parent_gz.addUnNode(alloc_tag, .usize_type, node);
6368 // Future optimization:
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);
63136371 // initialize to zero
63146372 _ = try parent_gz.addBin(.store, index_ptr, .zero_usize);
6373 try counters.append(index_ptr);
63156374 break :blk index_ptr;
63166375 };
63176376
......@@ -6343,13 +6402,15 @@ fn forExpr(
63436402 // cond_block unstacked now, can add new instructions to loop_scope
63446403 try loop_scope.instructions.append(astgen.gpa, cond_block);
63456404
6346 // Increment the index variable.
6347 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
6348 const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{
6349 .lhs = index_2,
6350 .rhs = .one_usize,
6351 });
6352 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);
6405 // Increment the index variable and ranges.
6406 for (counters) |counter_ptr| {
6407 const counter = try loop_scope.addUnNode(.load, counter_ptr, for_full.ast.cond_expr);
6408 const counter_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{
6409 .lhs = counter,
6410 .rhs = .one_usize,
6411 });
6412 _ = try loop_scope.addBin(.store, counter_ptr, counter_plus_one);
6413 }
63536414 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
63546415 _ = try loop_scope.addNode(repeat_tag, node);
63556416
......@@ -6366,64 +6427,62 @@ fn forExpr(
63666427 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
63676428 defer then_scope.unstack();
63686429
6369 try then_scope.addDbgBlockBegin();
6370 var payload_val_scope: Scope.LocalVal = undefined;
6371 var index_scope: Scope.LocalPtr = undefined;
6372 const then_sub_scope = blk: {
6373 const payload_token = for_full.payload_token.?;
6374 const ident = if (token_tags[payload_token] == .asterisk)
6375 payload_token + 1
6376 else
6377 payload_token;
6378 const is_ptr = ident != payload_token;
6379 const value_name = tree.tokenSlice(ident);
6380 var payload_sub_scope: *Scope = undefined;
6381 if (!mem.eql(u8, value_name, "_")) {
6382 const name_str_index = try astgen.identAsString(ident);
6383 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
6384 const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{
6385 .lhs = array_ptr,
6386 .rhs = index,
6387 });
6388 try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture);
6389 payload_val_scope = .{
6390 .parent = &then_scope.base,
6391 .gen_zir = &then_scope,
6392 .name = name_str_index,
6393 .inst = payload_inst,
6394 .token_src = ident,
6395 .id_cat = .capture,
6396 };
6397 try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst);
6398 payload_sub_scope = &payload_val_scope.base;
6399 } else if (is_ptr) {
6400 return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
6401 } else {
6402 payload_sub_scope = &then_scope.base;
6403 }
6404
6405 const index_token = if (token_tags[ident + 1] == .comma)
6406 ident + 2
6407 else
6408 break :blk payload_sub_scope;
6409 const token_bytes = tree.tokenSlice(index_token);
6410 if (mem.eql(u8, token_bytes, "_")) {
6411 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});
6412 }
6413 const index_name = try astgen.identAsString(index_token);
6414 try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture");
6415 index_scope = .{
6416 .parent = payload_sub_scope,
6417 .gen_zir = &then_scope,
6418 .name = index_name,
6419 .ptr = index_ptr,
6420 .token_src = index_token,
6421 .maybe_comptime = is_inline,
6422 .id_cat = .@"loop index capture",
6423 };
6424 try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr);
6425 break :blk &index_scope.base;
6426 };
6430 const then_sub_scope = &then_scope.base;
6431
6432 // try then_scope.addDbgBlockBegin();
6433 // var payload_val_scope: Scope.LocalVal = undefined;
6434 // var index_scope: Scope.LocalPtr = undefined;
6435 // const then_sub_scope = blk: {
6436 // const payload_token = for_full.payload_token.?;
6437 // const ident = if (token_tags[payload_token] == .asterisk)
6438 // payload_token + 1
6439 // else
6440 // payload_token;
6441 // const is_ptr = ident != payload_token;
6442 // const value_name = tree.tokenSlice(ident);
6443 // var payload_sub_scope: *Scope = undefined;
6444 // if (!mem.eql(u8, value_name, "_")) {
6445 // const name_str_index = try astgen.identAsString(ident);
6446 // const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
6447 // const payload_inst = try then_scope.addPlNode(tag, for_full.ast.cond_expr, Zir.Inst.Bin{
6448 // .lhs = array_ptr,
6449 // .rhs = index,
6450 // });
6451 // try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident, value_name, .capture);
6452 // payload_val_scope = .{
6453 // .parent = &then_scope.base,
6454 // .gen_zir = &then_scope,
6455 // .name = name_str_index,
6456 // .inst = payload_inst,
6457 // .token_src = ident,
6458 // .id_cat = .capture,
6459 // };
6460 // try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst);
6461 // payload_sub_scope = &payload_val_scope.base;
6462 // } else if (is_ptr) {
6463 // } else {
6464 // payload_sub_scope = &then_scope.base;
6465 // }
6466
6467 // const index_token = if (token_tags[ident + 1] == .comma)
6468 // ident + 2
6469 // else
6470 // break :blk payload_sub_scope;
6471 // const token_bytes = tree.tokenSlice(index_token);
6472 // const index_name = try astgen.identAsString(index_token);
6473 // try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token, token_bytes, .@"loop index capture");
6474 // index_scope = .{
6475 // .parent = payload_sub_scope,
6476 // .gen_zir = &then_scope,
6477 // .name = index_name,
6478 // .ptr = index_ptr,
6479 // .token_src = index_token,
6480 // .maybe_comptime = is_inline,
6481 // .id_cat = .@"loop index capture",
6482 // };
6483 // try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr);
6484 // break :blk &index_scope.base;
6485 // };
64276486
64286487 const then_result = try expr(&then_scope, then_sub_scope, .{ .rl = .none }, for_full.ast.then_expr);
64296488 _ = 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_
90219080 .mul_wrap,
90229081 .mul_sat,
90239082 .switch_range,
9083 .for_range,
90249084 .field_access,
90259085 .sub,
90269086 .sub_wrap,
......@@ -9310,6 +9370,7 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
93109370 .mul_wrap,
93119371 .mul_sat,
93129372 .switch_range,
9373 .for_range,
93139374 .sub,
93149375 .sub_wrap,
93159376 .sub_sat,
......@@ -9487,6 +9548,7 @@ fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.In
94879548 .mul_wrap,
94889549 .mul_sat,
94899550 .switch_range,
9551 .for_range,
94909552 .field_access,
94919553 .sub,
94929554 .sub_wrap,
......@@ -9731,6 +9793,7 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
97319793 .mul_wrap,
97329794 .mul_sat,
97339795 .switch_range,
9796 .for_range,
97349797 .field_access,
97359798 .sub,
97369799 .sub_wrap,