authorgravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-11-01 03:52:56-04:00
committergravatar for matthew.h.borkowski@gmail.comMatthew Borkowski <matthew.h.borkowski@gmail.com> 2021-11-01 05:42:39-04:00
log01842a6eadbe6e01d4afc4fc06394e73c9f24d58
treefc67e573f2542247a5410b94406b1d0615e31703
parent65c27e8e6612b8d649ae1481c27c8e7f0e78ad32

astgen.zig: avoid temporary allocations by sharing the `instructions` ArrayList between a GenZir and its sub-blocks wherever their use of it is strictly nested


1 files changed, 407 insertions(+), 224 deletions(-)

src/AstGen.zig+407-224
......@@ -117,6 +117,7 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir {
117117
118118 var top_scope: Scope.Top = .{};
119119
120 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
120121 var gen_scope: GenZir = .{
121122 .force_comptime = true,
122123 .in_defer = false,
......@@ -125,8 +126,10 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir {
125126 .decl_node_index = 0,
126127 .decl_line = 0,
127128 .astgen = &astgen,
129 .instructions = &gz_instructions,
130 .instructions_top = 0,
128131 };
129 defer gen_scope.instructions.deinit(gpa);
132 defer gz_instructions.deinit(gpa);
130133
131134 const container_decl: Ast.full.ContainerDecl = .{
132135 .layout_token = null,
......@@ -1041,12 +1044,12 @@ fn suspendExpr(
10411044 }
10421045 assert(body_node != 0);
10431046
1044 const suspend_inst = try gz.addBlock(.suspend_block, node);
1047 const suspend_inst = try gz.makeBlockInst(.suspend_block, node);
10451048 try gz.instructions.append(gpa, suspend_inst);
10461049
10471050 var suspend_scope = gz.makeSubBlock(scope);
10481051 suspend_scope.suspend_node = node;
1049 defer suspend_scope.instructions.deinit(gpa);
1052 defer suspend_scope.unstack();
10501053
10511054 const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node);
10521055 if (!gz.refIsNoReturn(body_result)) {
......@@ -1101,7 +1104,6 @@ fn fnProtoExpr(
11011104 fn_proto: Ast.full.FnProto,
11021105) InnerError!Zir.Inst.Ref {
11031106 const astgen = gz.astgen;
1104 const gpa = astgen.gpa;
11051107 const tree = astgen.tree;
11061108 const token_tags = tree.tokens.items(.tag);
11071109
......@@ -1147,14 +1149,14 @@ fn fnProtoExpr(
11471149 const param_type_node = param.type_expr;
11481150 assert(param_type_node != 0);
11491151 var param_gz = gz.makeSubBlock(scope);
1150 defer param_gz.instructions.deinit(gpa);
1152 defer param_gz.unstack();
11511153 const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node);
11521154 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
11531155 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
11541156 const main_tokens = tree.nodes.items(.main_token);
11551157 const name_token = param.name_token orelse main_tokens[param_type_node];
11561158 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1157 const param_inst = try gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
1159 const param_inst = try gz.addParam(&param_gz, tag, name_token, param_name);
11581160 assert(param_inst_expected == param_inst);
11591161 }
11601162 }
......@@ -1189,16 +1191,16 @@ fn fnProtoExpr(
11891191 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
11901192 }
11911193 var ret_gz = gz.makeSubBlock(scope);
1192 defer ret_gz.instructions.deinit(gpa);
1194 defer ret_gz.unstack();
11931195 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
11941196 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
11951197
11961198 const result = try gz.addFunc(.{
11971199 .src_node = fn_proto.ast.proto_node,
11981200 .param_block = 0,
1199 .ret_ty = ret_gz.instructions.items,
1201 .ret_gz = &ret_gz,
12001202 .ret_br = ret_br,
1201 .body = &[0]Zir.Inst.Index{},
1203 .body_gz = null,
12021204 .cc = cc,
12031205 .align_inst = align_inst,
12041206 .lib_name = 0,
......@@ -1376,7 +1378,7 @@ fn arrayInitExprRlPtr(
13761378 }
13771379
13781380 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr);
1379 defer as_scope.instructions.deinit(gz.astgen.gpa);
1381 defer as_scope.unstack();
13801382
13811383 const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements);
13821384 return as_scope.finishCoercion(gz, rl, node, result, array_ty);
......@@ -1554,7 +1556,7 @@ fn structInitExprRlPtr(
15541556 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
15551557
15561558 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);
1557 defer as_scope.instructions.deinit(gz.astgen.gpa);
1559 defer as_scope.unstack();
15581560
15591561 const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr);
15601562 return as_scope.finishCoercion(gz, rl, node, result, ty_inst);
......@@ -1875,7 +1877,7 @@ fn labeledBlockExpr(
18751877
18761878 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
18771879 // so that break statements can reference it.
1878 const block_inst = try gz.addBlock(zir_tag, block_node);
1880 const block_inst = try gz.makeBlockInst(zir_tag, block_node);
18791881 try gz.instructions.append(astgen.gpa, block_inst);
18801882
18811883 var block_scope = gz.makeSubBlock(parent_scope);
......@@ -1884,7 +1886,7 @@ fn labeledBlockExpr(
18841886 .block_inst = block_inst,
18851887 };
18861888 block_scope.setBreakResultLoc(rl);
1887 defer block_scope.instructions.deinit(astgen.gpa);
1889 defer block_scope.unstack();
18881890 defer block_scope.labeled_breaks.deinit(astgen.gpa);
18891891 defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
18901892
......@@ -2489,7 +2491,6 @@ fn varDecl(
24892491) InnerError!*Scope {
24902492 try emitDbgNode(gz, node);
24912493 const astgen = gz.astgen;
2492 const gpa = astgen.gpa;
24932494 const tree = astgen.tree;
24942495 const token_tags = tree.tokens.items(.tag);
24952496 const main_tokens = tree.nodes.items(.main_token);
......@@ -2550,7 +2551,9 @@ fn varDecl(
25502551 // Detect whether the initialization expression actually uses the
25512552 // result location pointer.
25522553 var init_scope = gz.makeSubBlock(scope);
2553 defer init_scope.instructions.deinit(gpa);
2554 // we may add more instructions to gz before stacking init_scope
2555 init_scope.instructions_top = GenZir.unstacked_top;
2556 defer init_scope.unstack();
25542557
25552558 var resolve_inferred_alloc: Zir.Inst.Ref = .none;
25562559 var opt_type_inst: Zir.Inst.Ref = .none;
......@@ -2558,6 +2561,7 @@ fn varDecl(
25582561 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);
25592562 opt_type_inst = type_inst;
25602563 if (align_inst == .none) {
2564 init_scope.instructions_top = gz.instructions.items.len;
25612565 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
25622566 } else {
25632567 init_scope.rl_ptr = try gz.addAllocExtended(.{
......@@ -2567,19 +2571,24 @@ fn varDecl(
25672571 .is_const = true,
25682572 .is_comptime = false,
25692573 });
2574 init_scope.instructions_top = gz.instructions.items.len;
25702575 }
25712576 init_scope.rl_ty_inst = type_inst;
25722577 } else {
2573 const alloc = if (align_inst == .none)
2574 try init_scope.addNode(.alloc_inferred, node)
2575 else
2576 try gz.addAllocExtended(.{
2578 const alloc = if (align_inst == .none) alloc: {
2579 init_scope.instructions_top = gz.instructions.items.len;
2580 break :alloc try init_scope.addNode(.alloc_inferred, node);
2581 } else alloc: {
2582 const ref = try gz.addAllocExtended(.{
25772583 .node = node,
25782584 .type_inst = .none,
25792585 .align_inst = align_inst,
25802586 .is_const = true,
25812587 .is_comptime = false,
25822588 });
2589 init_scope.instructions_top = gz.instructions.items.len;
2590 break :alloc ref;
2591 };
25832592 resolve_inferred_alloc = alloc;
25842593 init_scope.rl_ptr = alloc;
25852594 }
......@@ -2589,20 +2598,24 @@ fn varDecl(
25892598 const zir_tags = astgen.instructions.items(.tag);
25902599 const zir_datas = astgen.instructions.items(.data);
25912600
2592 const parent_zir = &gz.instructions;
25932601 if (align_inst == .none and init_scope.rvalue_rl_count == 1) {
25942602 // Result location pointer not used. We don't need an alloc for this
25952603 // const local, and type inference becomes trivial.
2596 // Move the init_scope instructions into the parent scope, eliding
2597 // the alloc instruction and the store_to_block_ptr instruction.
2598 try parent_zir.ensureUnusedCapacity(gpa, init_scope.instructions.items.len);
2599 for (init_scope.instructions.items) |src_inst| {
2604 // Implicitly move the init_scope instructions into the parent scope,
2605 // then elide the alloc instruction and the store_to_block_ptr instruction.
2606 var src = init_scope.instructions_top;
2607 var dst = src;
2608 init_scope.instructions_top = GenZir.unstacked_top;
2609 while (src < gz.instructions.items.len) : (src += 1) {
2610 const src_inst = gz.instructions.items[src];
26002611 if (indexToRef(src_inst) == init_scope.rl_ptr) continue;
26012612 if (zir_tags[src_inst] == .store_to_block_ptr) {
26022613 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;
26032614 }
2604 parent_zir.appendAssumeCapacity(src_inst);
2615 gz.instructions.items[dst] = src_inst;
2616 dst += 1;
26052617 }
2618 gz.instructions.items.len = dst;
26062619
26072620 const sub_scope = try block_arena.create(Scope.LocalVal);
26082621 sub_scope.* = .{
......@@ -2617,11 +2630,13 @@ fn varDecl(
26172630 }
26182631 // The initialization expression took advantage of the result location
26192632 // of the const local. In this case we will create an alloc and a LocalPtr for it.
2620 // Move the init_scope instructions into the parent scope, swapping
2633 // Implicitly move the init_scope instructions into the parent scope, then swap
26212634 // store_to_block_ptr for store_to_inferred_ptr.
2622 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;
2623 try parent_zir.ensureTotalCapacity(gpa, expected_len);
2624 for (init_scope.instructions.items) |src_inst| {
2635
2636 var src = init_scope.instructions_top;
2637 init_scope.instructions_top = GenZir.unstacked_top;
2638 while (src < gz.instructions.items.len) : (src += 1) {
2639 const src_inst = gz.instructions.items[src];
26252640 if (zir_tags[src_inst] == .store_to_block_ptr) {
26262641 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {
26272642 if (var_decl.ast.type_node != 0) {
......@@ -2631,9 +2646,7 @@ fn varDecl(
26312646 }
26322647 }
26332648 }
2634 parent_zir.appendAssumeCapacity(src_inst);
26352649 }
2636 assert(parent_zir.items.len == expected_len);
26372650 if (resolve_inferred_alloc != .none) {
26382651 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
26392652 }
......@@ -3120,7 +3133,6 @@ fn fnDecl(
31203133 body_node: Ast.Node.Index,
31213134 fn_proto: Ast.full.FnProto,
31223135) InnerError!void {
3123 const gpa = astgen.gpa;
31243136 const tree = astgen.tree;
31253137 const token_tags = tree.tokens.items(.tag);
31263138
......@@ -3130,7 +3142,7 @@ fn fnDecl(
31303142
31313143 // We insert this at the beginning so that its instruction index marks the
31323144 // start of the top level declaration.
3133 const block_inst = try gz.addBlock(.block_inline, fn_proto.ast.proto_node);
3145 const block_inst = try gz.makeBlockInst(.block_inline, fn_proto.ast.proto_node);
31343146
31353147 var decl_gz: GenZir = .{
31363148 .force_comptime = true,
......@@ -3139,8 +3151,10 @@ fn fnDecl(
31393151 .decl_line = gz.calcLine(decl_node),
31403152 .parent = scope,
31413153 .astgen = astgen,
3154 .instructions = gz.instructions,
3155 .instructions_top = gz.instructions.items.len,
31423156 };
3143 defer decl_gz.instructions.deinit(gpa);
3157 defer decl_gz.unstack();
31443158
31453159 var fn_gz: GenZir = .{
31463160 .force_comptime = false,
......@@ -3149,8 +3163,10 @@ fn fnDecl(
31493163 .decl_line = decl_gz.decl_line,
31503164 .parent = &decl_gz.base,
31513165 .astgen = astgen,
3166 .instructions = gz.instructions,
3167 .instructions_top = GenZir.unstacked_top,
31523168 };
3153 defer fn_gz.instructions.deinit(gpa);
3169 defer fn_gz.unstack();
31543170
31553171 // TODO: support noinline
31563172 const is_pub = fn_proto.visib_token != null;
......@@ -3216,7 +3232,7 @@ fn fnDecl(
32163232 const param_type_node = param.type_expr;
32173233 assert(param_type_node != 0);
32183234 var param_gz = decl_gz.makeSubBlock(scope);
3219 defer param_gz.instructions.deinit(gpa);
3235 defer param_gz.unstack();
32203236 const param_type = try expr(&param_gz, params_scope, coerced_type_rl, param_type_node);
32213237 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
32223238 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
......@@ -3224,7 +3240,7 @@ fn fnDecl(
32243240 const main_tokens = tree.nodes.items(.main_token);
32253241 const name_token = param.name_token orelse main_tokens[param_type_node];
32263242 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
3227 const param_inst = try decl_gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
3243 const param_inst = try decl_gz.addParam(&param_gz, tag, name_token, param_name);
32283244 assert(param_inst_expected == param_inst);
32293245 break :param indexToRef(param_inst);
32303246 };
......@@ -3289,7 +3305,7 @@ fn fnDecl(
32893305 };
32903306
32913307 var ret_gz = decl_gz.makeSubBlock(params_scope);
3292 defer ret_gz.instructions.deinit(gpa);
3308 defer ret_gz.unstack();
32933309 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
32943310 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
32953311
......@@ -3302,10 +3318,10 @@ fn fnDecl(
33023318 }
33033319 break :func try decl_gz.addFunc(.{
33043320 .src_node = decl_node,
3305 .ret_ty = ret_gz.instructions.items,
3321 .ret_gz = &ret_gz,
33063322 .ret_br = ret_br,
33073323 .param_block = block_inst,
3308 .body = &[0]Zir.Inst.Index{},
3324 .body_gz = null,
33093325 .cc = cc,
33103326 .align_inst = .none, // passed in the per-decl data
33113327 .lib_name = lib_name,
......@@ -3319,6 +3335,9 @@ fn fnDecl(
33193335 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
33203336 }
33213337
3338 // as a scope, fn_gz encloses ret_gz, but for instruction list, fn_gz stacks on ret_gz
3339 fn_gz.instructions_top = ret_gz.instructions.items.len;
3340
33223341 const prev_fn_block = astgen.fn_block;
33233342 astgen.fn_block = &fn_gz;
33243343 defer astgen.fn_block = prev_fn_block;
......@@ -3332,14 +3351,7 @@ fn fnDecl(
33323351 _ = try expr(&fn_gz, params_scope, .none, body_node);
33333352 try checkUsed(gz, &fn_gz.base, params_scope);
33343353
3335 const need_implicit_ret = blk: {
3336 if (fn_gz.instructions.items.len == 0)
3337 break :blk true;
3338 const last = fn_gz.instructions.items[fn_gz.instructions.items.len - 1];
3339 const zir_tags = astgen.instructions.items(.tag);
3340 break :blk !zir_tags[last].isNoReturn();
3341 };
3342 if (need_implicit_ret) {
3354 if (!fn_gz.endsWithNoReturn()) {
33433355 // Since we are adding the return instruction here, we must handle the coercion.
33443356 // We do this by using the `ret_coerce` instruction.
33453357 _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
......@@ -3350,9 +3362,9 @@ fn fnDecl(
33503362 .lbrace_line = lbrace_line,
33513363 .lbrace_column = lbrace_column,
33523364 .param_block = block_inst,
3353 .ret_ty = ret_gz.instructions.items,
3365 .ret_gz = &ret_gz,
33543366 .ret_br = ret_br,
3355 .body = fn_gz.instructions.items,
3367 .body_gz = &fn_gz,
33563368 .cc = cc,
33573369 .align_inst = .none, // passed in the per-decl data
33583370 .lib_name = lib_name,
......@@ -3364,7 +3376,7 @@ fn fnDecl(
33643376 };
33653377
33663378 // We add this at the end so that its instruction index marks the end range
3367 // of the top level declaration.
3379 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
33683380 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);
33693381 try decl_gz.setBlockBody(block_inst);
33703382
......@@ -3396,14 +3408,13 @@ fn globalVarDecl(
33963408 node: Ast.Node.Index,
33973409 var_decl: Ast.full.VarDecl,
33983410) InnerError!void {
3399 const gpa = astgen.gpa;
34003411 const tree = astgen.tree;
34013412 const token_tags = tree.tokens.items(.tag);
34023413
34033414 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
34043415 // We do this at the beginning so that the instruction index marks the range start
34053416 // of the top level declaration.
3406 const block_inst = try gz.addBlock(.block_inline, node);
3417 const block_inst = try gz.makeBlockInst(.block_inline, node);
34073418
34083419 const name_token = var_decl.ast.mut_token + 1;
34093420 const name_str_index = try astgen.identAsString(name_token);
......@@ -3416,8 +3427,10 @@ fn globalVarDecl(
34163427 .force_comptime = true,
34173428 .in_defer = false,
34183429 .anon_name_strategy = .parent,
3430 .instructions = gz.instructions,
3431 .instructions_top = gz.instructions.items.len,
34193432 };
3420 defer block_scope.instructions.deinit(gpa);
3433 defer block_scope.unstack();
34213434
34223435 const is_pub = var_decl.visib_token != null;
34233436 const is_export = blk: {
......@@ -3543,14 +3556,13 @@ fn comptimeDecl(
35433556 wip_members: *WipMembers,
35443557 node: Ast.Node.Index,
35453558) InnerError!void {
3546 const gpa = astgen.gpa;
35473559 const tree = astgen.tree;
35483560 const node_datas = tree.nodes.items(.data);
35493561 const body_node = node_datas[node].lhs;
35503562
35513563 // Up top so the ZIR instruction index marks the start range of this
35523564 // top-level declaration.
3553 const block_inst = try gz.addBlock(.block_inline, node);
3565 const block_inst = try gz.makeBlockInst(.block_inline, node);
35543566 wip_members.nextDecl(false, false, false, false);
35553567
35563568 var decl_block: GenZir = .{
......@@ -3560,11 +3572,13 @@ fn comptimeDecl(
35603572 .decl_line = gz.calcLine(node),
35613573 .parent = scope,
35623574 .astgen = astgen,
3575 .instructions = gz.instructions,
3576 .instructions_top = gz.instructions.items.len,
35633577 };
3564 defer decl_block.instructions.deinit(gpa);
3578 defer decl_block.unstack();
35653579
35663580 const block_result = try expr(&decl_block, &decl_block.base, .none, body_node);
3567 if (decl_block.instructions.items.len == 0 or !decl_block.refIsNoReturn(block_result)) {
3581 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) {
35683582 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value);
35693583 }
35703584 try decl_block.setBlockBody(block_inst);
......@@ -3589,7 +3603,6 @@ fn usingnamespaceDecl(
35893603 wip_members: *WipMembers,
35903604 node: Ast.Node.Index,
35913605) InnerError!void {
3592 const gpa = astgen.gpa;
35933606 const tree = astgen.tree;
35943607 const node_datas = tree.nodes.items(.data);
35953608
......@@ -3602,7 +3615,7 @@ fn usingnamespaceDecl(
36023615 };
36033616 // Up top so the ZIR instruction index marks the start range of this
36043617 // top-level declaration.
3605 const block_inst = try gz.addBlock(.block_inline, node);
3618 const block_inst = try gz.makeBlockInst(.block_inline, node);
36063619 wip_members.nextDecl(is_pub, true, false, false);
36073620
36083621 var decl_block: GenZir = .{
......@@ -3612,8 +3625,10 @@ fn usingnamespaceDecl(
36123625 .decl_line = gz.calcLine(node),
36133626 .parent = scope,
36143627 .astgen = astgen,
3628 .instructions = gz.instructions,
3629 .instructions_top = gz.instructions.items.len,
36153630 };
3616 defer decl_block.instructions.deinit(gpa);
3631 defer decl_block.unstack();
36173632
36183633 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
36193634 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);
......@@ -3639,14 +3654,13 @@ fn testDecl(
36393654 wip_members: *WipMembers,
36403655 node: Ast.Node.Index,
36413656) InnerError!void {
3642 const gpa = astgen.gpa;
36433657 const tree = astgen.tree;
36443658 const node_datas = tree.nodes.items(.data);
36453659 const body_node = node_datas[node].rhs;
36463660
36473661 // Up top so the ZIR instruction index marks the start range of this
36483662 // top-level declaration.
3649 const block_inst = try gz.addBlock(.block_inline, node);
3663 const block_inst = try gz.makeBlockInst(.block_inline, node);
36503664
36513665 wip_members.nextDecl(false, false, false, false);
36523666
......@@ -3657,8 +3671,10 @@ fn testDecl(
36573671 .decl_line = gz.calcLine(node),
36583672 .parent = scope,
36593673 .astgen = astgen,
3674 .instructions = gz.instructions,
3675 .instructions_top = gz.instructions.items.len,
36603676 };
3661 defer decl_block.instructions.deinit(gpa);
3677 defer decl_block.unstack();
36623678
36633679 const test_name: u32 = blk: {
36643680 const main_tokens = tree.nodes.items(.main_token);
......@@ -3679,8 +3695,10 @@ fn testDecl(
36793695 .decl_line = decl_block.decl_line,
36803696 .parent = &decl_block.base,
36813697 .astgen = astgen,
3698 .instructions = decl_block.instructions,
3699 .instructions_top = decl_block.instructions.items.len,
36823700 };
3683 defer fn_block.instructions.deinit(gpa);
3701 defer fn_block.unstack();
36843702
36853703 const prev_fn_block = astgen.fn_block;
36863704 astgen.fn_block = &fn_block;
......@@ -3693,7 +3711,7 @@ fn testDecl(
36933711 const lbrace_column = @intCast(u32, astgen.source_column);
36943712
36953713 const block_result = try expr(&fn_block, &fn_block.base, .none, body_node);
3696 if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) {
3714 if (fn_block.isEmpty() or !fn_block.refIsNoReturn(block_result)) {
36973715 // Since we are adding the return instruction here, we must handle the coercion.
36983716 // We do this by using the `ret_coerce` instruction.
36993717 _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
......@@ -3704,9 +3722,9 @@ fn testDecl(
37043722 .lbrace_line = lbrace_line,
37053723 .lbrace_column = lbrace_column,
37063724 .param_block = block_inst,
3707 .ret_ty = &.{},
3725 .ret_gz = null,
37083726 .ret_br = 0,
3709 .body = fn_block.instructions.items,
3727 .body_gz = &fn_block,
37103728 .cc = .none,
37113729 .align_inst = .none,
37123730 .lib_name = 0,
......@@ -3776,8 +3794,10 @@ fn structDeclInner(
37763794 .astgen = astgen,
37773795 .force_comptime = true,
37783796 .in_defer = false,
3797 .instructions = gz.instructions,
3798 .instructions_top = gz.instructions.items.len,
37793799 };
3780 defer block_scope.instructions.deinit(gpa);
3800 defer block_scope.unstack();
37813801
37823802 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
37833803 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);
......@@ -3829,14 +3849,16 @@ fn structDeclInner(
38293849 }
38303850 }
38313851
3832 if (block_scope.instructions.items.len != 0) {
3852 if (!block_scope.isEmpty()) {
38333853 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
38343854 }
38353855
3856 const body = block_scope.instructionsSlice();
3857
38363858 try gz.setStruct(decl_inst, .{
38373859 .src_node = node,
38383860 .layout = layout,
3839 .body_len = @intCast(u32, block_scope.instructions.items.len),
3861 .body_len = @intCast(u32, body.len),
38403862 .fields_len = field_count,
38413863 .decls_len = decl_count,
38423864 .known_has_bits = known_has_bits,
......@@ -3845,11 +3867,12 @@ fn structDeclInner(
38453867 wip_members.finishBits(bits_per_field);
38463868 const decls_slice = wip_members.declsSlice();
38473869 const fields_slice = wip_members.fieldsSlice();
3848 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + block_scope.instructions.items.len + fields_slice.len);
3870 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body.len + fields_slice.len);
38493871 astgen.extra.appendSliceAssumeCapacity(decls_slice);
3850 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
3872 astgen.extra.appendSliceAssumeCapacity(body);
38513873 astgen.extra.appendSliceAssumeCapacity(fields_slice);
38523874
3875 block_scope.unstack();
38533876 try gz.addNamespaceCaptures(&namespace);
38543877 return indexToRef(decl_inst);
38553878}
......@@ -3888,8 +3911,10 @@ fn unionDeclInner(
38883911 .astgen = astgen,
38893912 .force_comptime = true,
38903913 .in_defer = false,
3914 .instructions = gz.instructions,
3915 .instructions_top = gz.instructions.items.len,
38913916 };
3892 defer block_scope.instructions.deinit(gpa);
3917 defer block_scope.unstack();
38933918
38943919 const decl_count = try astgen.scanDecls(&namespace, members);
38953920 const field_count = @intCast(u32, members.len - decl_count);
......@@ -3972,15 +3997,17 @@ fn unionDeclInner(
39723997 return astgen.failNode(node, "union declarations must have at least one tag", .{});
39733998 }
39743999
3975 if (block_scope.instructions.items.len != 0) {
4000 if (!block_scope.isEmpty()) {
39764001 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
39774002 }
39784003
4004 const body = block_scope.instructionsSlice();
4005
39794006 try gz.setUnion(decl_inst, .{
39804007 .src_node = node,
39814008 .layout = layout,
39824009 .tag_type = arg_inst,
3983 .body_len = @intCast(u32, block_scope.instructions.items.len),
4010 .body_len = @intCast(u32, body.len),
39844011 .fields_len = field_count,
39854012 .decls_len = decl_count,
39864013 .auto_enum_tag = have_auto_enum,
......@@ -3989,11 +4016,12 @@ fn unionDeclInner(
39894016 wip_members.finishBits(bits_per_field);
39904017 const decls_slice = wip_members.declsSlice();
39914018 const fields_slice = wip_members.fieldsSlice();
3992 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + block_scope.instructions.items.len + fields_slice.len);
4019 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body.len + fields_slice.len);
39934020 astgen.extra.appendSliceAssumeCapacity(decls_slice);
3994 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
4021 astgen.extra.appendSliceAssumeCapacity(body);
39954022 astgen.extra.appendSliceAssumeCapacity(fields_slice);
39964023
4024 block_scope.unstack();
39974025 try gz.addNamespaceCaptures(&namespace);
39984026 return indexToRef(decl_inst);
39994027}
......@@ -4163,8 +4191,10 @@ fn containerDecl(
41634191 .astgen = astgen,
41644192 .force_comptime = true,
41654193 .in_defer = false,
4194 .instructions = gz.instructions,
4195 .instructions_top = gz.instructions.items.len,
41664196 };
4167 defer block_scope.instructions.deinit(gpa);
4197 defer block_scope.unstack();
41684198
41694199 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);
41704200
......@@ -4215,15 +4245,17 @@ fn containerDecl(
42154245 }
42164246 }
42174247
4218 if (block_scope.instructions.items.len != 0) {
4248 if (!block_scope.isEmpty()) {
42194249 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
42204250 }
42214251
4252 const body = block_scope.instructionsSlice();
4253
42224254 try gz.setEnum(decl_inst, .{
42234255 .src_node = node,
42244256 .nonexhaustive = nonexhaustive,
42254257 .tag_type = arg_inst,
4226 .body_len = @intCast(u32, block_scope.instructions.items.len),
4258 .body_len = @intCast(u32, body.len),
42274259 .fields_len = @intCast(u32, counts.total_fields),
42284260 .decls_len = @intCast(u32, counts.decls),
42294261 });
......@@ -4231,11 +4263,12 @@ fn containerDecl(
42314263 wip_members.finishBits(bits_per_field);
42324264 const decls_slice = wip_members.declsSlice();
42334265 const fields_slice = wip_members.fieldsSlice();
4234 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + block_scope.instructions.items.len + fields_slice.len);
4266 try astgen.extra.ensureUnusedCapacity(gpa, decls_slice.len + body.len + fields_slice.len);
42354267 astgen.extra.appendSliceAssumeCapacity(decls_slice);
4236 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
4268 astgen.extra.appendSliceAssumeCapacity(body);
42374269 astgen.extra.appendSliceAssumeCapacity(fields_slice);
42384270
4271 block_scope.unstack();
42394272 try gz.addNamespaceCaptures(&namespace);
42404273 return rvalue(gz, rl, indexToRef(decl_inst), node);
42414274 },
......@@ -4453,7 +4486,7 @@ fn tryExpr(
44534486
44544487 var block_scope = parent_gz.makeSubBlock(scope);
44554488 block_scope.setBreakResultLoc(rl);
4456 defer block_scope.instructions.deinit(astgen.gpa);
4489 defer block_scope.unstack();
44574490
44584491 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
44594492 .ref => .ref,
......@@ -4473,12 +4506,13 @@ fn tryExpr(
44734506 const cond = try block_scope.addUnNode(err_ops[0], operand, node);
44744507 const condbr = try block_scope.addCondBr(.condbr, node);
44754508
4476 const block = try parent_gz.addBlock(.block, node);
4477 try parent_gz.instructions.append(astgen.gpa, block);
4509 const block = try parent_gz.makeBlockInst(.block, node);
44784510 try block_scope.setBlockBody(block);
4511 // block_scope unstacked now, can add new instructions to parent_gz
4512 try parent_gz.instructions.append(astgen.gpa, block);
44794513
44804514 var then_scope = parent_gz.makeSubBlock(scope);
4481 defer then_scope.instructions.deinit(astgen.gpa);
4515 defer then_scope.unstack();
44824516
44834517 block_scope.break_count += 1;
44844518 // This could be a pointer or value depending on `err_ops[2]`.
......@@ -4488,8 +4522,9 @@ fn tryExpr(
44884522 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),
44894523 };
44904524
4525 // else_scope will be stacked on then_scope as both are stacked on parent_gz
44914526 var else_scope = parent_gz.makeSubBlock(scope);
4492 defer else_scope.instructions.deinit(astgen.gpa);
4527 defer else_scope.unstack();
44934528
44944529 const err_code = try else_scope.addUnNode(err_ops[1], operand, node);
44954530 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
......@@ -4529,7 +4564,7 @@ fn orelseCatchExpr(
45294564
45304565 var block_scope = parent_gz.makeSubBlock(scope);
45314566 block_scope.setBreakResultLoc(rl);
4532 defer block_scope.instructions.deinit(astgen.gpa);
4567 defer block_scope.unstack();
45334568
45344569 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
45354570 .ref => .ref,
......@@ -4544,12 +4579,13 @@ fn orelseCatchExpr(
45444579 const cond = try block_scope.addUnNode(cond_op, operand, node);
45454580 const condbr = try block_scope.addCondBr(.condbr, node);
45464581
4547 const block = try parent_gz.addBlock(.block, node);
4548 try parent_gz.instructions.append(astgen.gpa, block);
4582 const block = try parent_gz.makeBlockInst(.block, node);
45494583 try block_scope.setBlockBody(block);
4584 // block_scope unstacked now, can add new instructions to parent_gz
4585 try parent_gz.instructions.append(astgen.gpa, block);
45504586
45514587 var then_scope = parent_gz.makeSubBlock(scope);
4552 defer then_scope.instructions.deinit(astgen.gpa);
4588 defer then_scope.unstack();
45534589
45544590 // This could be a pointer or value depending on `unwrap_op`.
45554591 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
......@@ -4559,7 +4595,7 @@ fn orelseCatchExpr(
45594595 };
45604596
45614597 var else_scope = parent_gz.makeSubBlock(scope);
4562 defer else_scope.instructions.deinit(astgen.gpa);
4598 defer else_scope.unstack();
45634599
45644600 var err_val_scope: Scope.LocalVal = undefined;
45654601 const else_sub_scope = blk: {
......@@ -4606,6 +4642,7 @@ fn orelseCatchExpr(
46064642 );
46074643}
46084644
4645/// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`.
46094646fn finishThenElseBlock(
46104647 parent_gz: *GenZir,
46114648 rl: ResultLoc,
......@@ -4624,33 +4661,33 @@ fn finishThenElseBlock(
46244661 // We now have enough information to decide whether the result instruction should
46254662 // be communicated via result location pointer or break instructions.
46264663 const strat = rl.strategy(block_scope);
4664 // else_scope may be stacked on then_scope, so check for no-return on then_scope manually
4665 const tags = parent_gz.astgen.instructions.items(.tag);
4666 const then_slice = then_scope.instructionsSliceUpto(else_scope);
4667 const then_no_return = then_slice.len > 0 and tags[then_slice[then_slice.len - 1]].isNoReturn();
4668 const else_no_return = else_scope.endsWithNoReturn();
4669
46274670 switch (strat.tag) {
46284671 .break_void => {
4629 if (!then_scope.endsWithNoReturn()) {
4630 _ = try then_scope.addBreak(break_tag, then_break_block, .void_value);
4631 }
4632 if (!else_scope.endsWithNoReturn()) {
4633 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
4634 }
4672 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, .void_value) else 0;
4673 const else_break = if (!else_no_return) try else_scope.makeBreak(break_tag, main_block, .void_value) else 0;
46354674 assert(!strat.elide_store_to_block_ptr_instructions);
4636 try setCondBrPayload(condbr, cond, then_scope, else_scope);
4675 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break);
46374676 return indexToRef(main_block);
46384677 },
46394678 .break_operand => {
4640 if (!then_scope.endsWithNoReturn()) {
4641 _ = try then_scope.addBreak(break_tag, then_break_block, then_result);
4642 }
4643 if (else_result != .none) {
4644 if (!else_scope.endsWithNoReturn()) {
4645 _ = try else_scope.addBreak(break_tag, main_block, else_result);
4646 }
4647 } else {
4648 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
4649 }
4679 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, then_result) else 0;
4680 const else_break = if (else_result == .none)
4681 try else_scope.makeBreak(break_tag, main_block, .void_value)
4682 else if (!else_no_return)
4683 try else_scope.makeBreak(break_tag, main_block, else_result)
4684 else
4685 0;
4686
46504687 if (strat.elide_store_to_block_ptr_instructions) {
4651 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, else_scope, block_scope.rl_ptr);
4688 try setCondBrPayloadElideBlockStorePtr(condbr, cond, then_scope, then_break, else_scope, else_break, block_scope.rl_ptr);
46524689 } else {
4653 try setCondBrPayload(condbr, cond, then_scope, else_scope);
4690 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break);
46544691 }
46554692 const block_ref = indexToRef(main_block);
46564693 switch (rl) {
......@@ -4778,7 +4815,7 @@ fn boolBinOp(
47784815 const bool_br = try gz.addBoolBr(zir_tag, lhs);
47794816
47804817 var rhs_scope = gz.makeSubBlock(scope);
4781 defer rhs_scope.instructions.deinit(gz.astgen.gpa);
4818 defer rhs_scope.unstack();
47824819 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);
47834820 if (!gz.refIsNoReturn(rhs)) {
47844821 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
......@@ -4802,7 +4839,7 @@ fn ifExpr(
48024839
48034840 var block_scope = parent_gz.makeSubBlock(scope);
48044841 block_scope.setBreakResultLoc(rl);
4805 defer block_scope.instructions.deinit(astgen.gpa);
4842 defer block_scope.unstack();
48064843
48074844 const payload_is_ref = if (if_full.payload_token) |payload_token|
48084845 token_tags[payload_token] == .asterisk
......@@ -4840,12 +4877,13 @@ fn ifExpr(
48404877
48414878 const condbr = try block_scope.addCondBr(.condbr, node);
48424879
4843 const block = try parent_gz.addBlock(.block, node);
4844 try parent_gz.instructions.append(astgen.gpa, block);
4880 const block = try parent_gz.makeBlockInst(.block, node);
48454881 try block_scope.setBlockBody(block);
4882 // block_scope unstacked now, can add new instructions to parent_gz
4883 try parent_gz.instructions.append(astgen.gpa, block);
48464884
48474885 var then_scope = parent_gz.makeSubBlock(scope);
4848 defer then_scope.instructions.deinit(astgen.gpa);
4886 defer then_scope.unstack();
48494887
48504888 var payload_val_scope: Scope.LocalVal = undefined;
48514889
......@@ -4911,7 +4949,7 @@ fn ifExpr(
49114949 // instructions or not.
49124950
49134951 var else_scope = parent_gz.makeSubBlock(scope);
4914 defer else_scope.instructions.deinit(astgen.gpa);
4952 defer else_scope.unstack();
49154953
49164954 const else_node = if_full.ast.else_expr;
49174955 const else_info: struct {
......@@ -4974,52 +5012,70 @@ fn ifExpr(
49745012 );
49755013}
49765014
5015/// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`.
49775016fn setCondBrPayload(
49785017 condbr: Zir.Inst.Index,
49795018 cond: Zir.Inst.Ref,
49805019 then_scope: *GenZir,
5020 then_break: Zir.Inst.Index,
49815021 else_scope: *GenZir,
5022 else_break: Zir.Inst.Index,
49825023) !void {
5024 defer then_scope.unstack();
5025 defer else_scope.unstack();
49835026 const astgen = then_scope.astgen;
4984
5027 const then_body = then_scope.instructionsSliceUpto(else_scope);
5028 const else_body = else_scope.instructionsSlice();
5029 const then_body_len = @intCast(u32, then_body.len + @boolToInt(then_break != 0));
5030 const else_body_len = @intCast(u32, else_body.len + @boolToInt(else_break != 0));
49855031 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
4986 then_scope.instructions.items.len + else_scope.instructions.items.len);
5032 then_body_len + else_body_len);
49875033
49885034 const zir_datas = astgen.instructions.items(.data);
49895035 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
49905036 .condition = cond,
4991 .then_body_len = @intCast(u32, then_scope.instructions.items.len),
4992 .else_body_len = @intCast(u32, else_scope.instructions.items.len),
5037 .then_body_len = then_body_len,
5038 .else_body_len = else_body_len,
49935039 });
4994 astgen.extra.appendSliceAssumeCapacity(then_scope.instructions.items);
4995 astgen.extra.appendSliceAssumeCapacity(else_scope.instructions.items);
5040 astgen.extra.appendSliceAssumeCapacity(then_body);
5041 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break);
5042 astgen.extra.appendSliceAssumeCapacity(else_body);
5043 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break);
49965044}
49975045
5046/// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`.
49985047fn setCondBrPayloadElideBlockStorePtr(
49995048 condbr: Zir.Inst.Index,
50005049 cond: Zir.Inst.Ref,
50015050 then_scope: *GenZir,
5051 then_break: Zir.Inst.Index,
50025052 else_scope: *GenZir,
5053 else_break: Zir.Inst.Index,
50035054 block_ptr: Zir.Inst.Ref,
50045055) !void {
5056 defer then_scope.unstack();
5057 defer else_scope.unstack();
50055058 const astgen = then_scope.astgen;
5006
5059 const then_body = then_scope.instructionsSliceUpto(else_scope);
5060 const else_body = else_scope.instructionsSlice();
5061 const then_body_len = @intCast(u32, then_body.len + @boolToInt(then_break != 0));
5062 const else_body_len = @intCast(u32, else_body.len + @boolToInt(else_break != 0));
50075063 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
5008 then_scope.instructions.items.len + else_scope.instructions.items.len);
5064 then_body_len + else_body_len);
50095065
50105066 const zir_tags = astgen.instructions.items(.tag);
50115067 const zir_datas = astgen.instructions.items(.data);
50125068
50135069 const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
50145070 .condition = cond,
5015 .then_body_len = @intCast(u32, then_scope.instructions.items.len),
5016 .else_body_len = @intCast(u32, else_scope.instructions.items.len),
5071 .then_body_len = then_body_len,
5072 .else_body_len = else_body_len,
50175073 });
50185074 zir_datas[condbr].pl_node.payload_index = condbr_pl;
50195075 const then_body_len_index = condbr_pl + 1;
50205076 const else_body_len_index = condbr_pl + 2;
50215077
5022 for (then_scope.instructions.items) |src_inst| {
5078 for (then_body) |src_inst| {
50235079 if (zir_tags[src_inst] == .store_to_block_ptr) {
50245080 if (zir_datas[src_inst].bin.lhs == block_ptr) {
50255081 astgen.extra.items[then_body_len_index] -= 1;
......@@ -5028,7 +5084,8 @@ fn setCondBrPayloadElideBlockStorePtr(
50285084 }
50295085 astgen.extra.appendAssumeCapacity(src_inst);
50305086 }
5031 for (else_scope.instructions.items) |src_inst| {
5087 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break);
5088 for (else_body) |src_inst| {
50325089 if (zir_tags[src_inst] == .store_to_block_ptr) {
50335090 if (zir_datas[src_inst].bin.lhs == block_ptr) {
50345091 astgen.extra.items[else_body_len_index] -= 1;
......@@ -5037,6 +5094,7 @@ fn setCondBrPayloadElideBlockStorePtr(
50375094 }
50385095 astgen.extra.appendAssumeCapacity(src_inst);
50395096 }
5097 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break);
50405098}
50415099
50425100fn whileExpr(
......@@ -5056,17 +5114,17 @@ fn whileExpr(
50565114
50575115 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;
50585116 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
5059 const loop_block = try parent_gz.addBlock(loop_tag, node);
5117 const loop_block = try parent_gz.makeBlockInst(loop_tag, node);
50605118 try parent_gz.instructions.append(astgen.gpa, loop_block);
50615119
50625120 var loop_scope = parent_gz.makeSubBlock(scope);
50635121 loop_scope.setBreakResultLoc(rl);
5064 defer loop_scope.instructions.deinit(astgen.gpa);
5122 defer loop_scope.unstack();
50655123 defer loop_scope.labeled_breaks.deinit(astgen.gpa);
50665124 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
50675125
50685126 var continue_scope = parent_gz.makeSubBlock(&loop_scope.base);
5069 defer continue_scope.instructions.deinit(astgen.gpa);
5127 defer continue_scope.unstack();
50705128
50715129 const payload_is_ref = if (while_full.payload_token) |payload_token|
50725130 token_tags[payload_token] == .asterisk
......@@ -5105,15 +5163,19 @@ fn whileExpr(
51055163 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
51065164 const condbr = try continue_scope.addCondBr(condbr_tag, node);
51075165 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
5108 const cond_block = try loop_scope.addBlock(block_tag, node);
5109 try loop_scope.instructions.append(astgen.gpa, cond_block);
5166 const cond_block = try loop_scope.makeBlockInst(block_tag, node);
51105167 try continue_scope.setBlockBody(cond_block);
5168 // continue_scope unstacked now, can add new instructions to loop_scope
5169 try loop_scope.instructions.append(astgen.gpa, cond_block);
51115170
5171 // make scope now but don't stack on parent_gz until loop_scope
5172 // gets unstacked after cont_expr is emitted and added below
51125173 var then_scope = parent_gz.makeSubBlock(&continue_scope.base);
5113 defer then_scope.instructions.deinit(astgen.gpa);
5174 then_scope.instructions_top = GenZir.unstacked_top;
5175 defer then_scope.unstack();
51145176
5177 var payload_inst: Zir.Inst.Index = 0;
51155178 var payload_val_scope: Scope.LocalVal = undefined;
5116
51175179 const then_sub_scope = s: {
51185180 if (while_full.error_token != null) {
51195181 if (while_full.payload_token) |payload_token| {
......@@ -5121,7 +5183,8 @@ fn whileExpr(
51215183 .err_union_payload_unsafe_ptr
51225184 else
51235185 .err_union_payload_unsafe;
5124 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
5186 // will add this instruction to then_scope.instructions below
5187 payload_inst = try then_scope.makeUnNode(tag, cond.inst, node);
51255188 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
51265189 const ident_bytes = tree.tokenSlice(ident_token);
51275190 if (mem.eql(u8, "_", ident_bytes))
......@@ -5133,7 +5196,7 @@ fn whileExpr(
51335196 .parent = &then_scope.base,
51345197 .gen_zir = &then_scope,
51355198 .name = ident_name,
5136 .inst = payload_inst,
5199 .inst = indexToRef(payload_inst),
51375200 .token_src = payload_token,
51385201 .id_cat = .@"capture",
51395202 };
......@@ -5147,7 +5210,8 @@ fn whileExpr(
51475210 .optional_payload_unsafe_ptr
51485211 else
51495212 .optional_payload_unsafe;
5150 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
5213 // will add this instruction to then_scope.instructions below
5214 payload_inst = try then_scope.makeUnNode(tag, cond.inst, node);
51515215 const ident_name = try astgen.identAsString(ident_token);
51525216 const ident_bytes = tree.tokenSlice(ident_token);
51535217 if (mem.eql(u8, "_", ident_bytes))
......@@ -5157,7 +5221,7 @@ fn whileExpr(
51575221 .parent = &then_scope.base,
51585222 .gen_zir = &then_scope,
51595223 .name = ident_name,
5160 .inst = payload_inst,
5224 .inst = indexToRef(payload_inst),
51615225 .token_src = ident_token,
51625226 .id_cat = .@"capture",
51635227 };
......@@ -5187,6 +5251,9 @@ fn whileExpr(
51875251 });
51885252 }
51895253
5254 // done adding instructions to loop_scope, can now stack then_scope
5255 then_scope.instructions_top = then_scope.instructions.items.len;
5256 if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst);
51905257 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
51915258 if (!then_scope.endsWithNoReturn()) {
51925259 loop_scope.break_count += 1;
......@@ -5194,7 +5261,7 @@ fn whileExpr(
51945261 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
51955262
51965263 var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
5197 defer else_scope.instructions.deinit(astgen.gpa);
5264 defer else_scope.unstack();
51985265
51995266 const else_node = while_full.ast.else_expr;
52005267 const else_info: struct {
......@@ -5207,7 +5274,7 @@ fn whileExpr(
52075274 .err_union_code_ptr
52085275 else
52095276 .err_union_code;
5210 const payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
5277 const else_payload_inst = try else_scope.addUnNode(tag, cond.inst, node);
52115278 const ident_name = try astgen.identAsString(error_token);
52125279 const ident_bytes = tree.tokenSlice(error_token);
52135280 if (mem.eql(u8, ident_bytes, "_"))
......@@ -5217,7 +5284,7 @@ fn whileExpr(
52175284 .parent = &else_scope.base,
52185285 .gen_zir = &else_scope,
52195286 .name = ident_name,
5220 .inst = payload_inst,
5287 .inst = else_payload_inst,
52215288 .token_src = error_token,
52225289 .id_cat = .@"capture",
52235290 };
......@@ -5299,17 +5366,17 @@ fn forExpr(
52995366 };
53005367
53015368 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
5302 const loop_block = try parent_gz.addBlock(loop_tag, node);
5369 const loop_block = try parent_gz.makeBlockInst(loop_tag, node);
53035370 try parent_gz.instructions.append(astgen.gpa, loop_block);
53045371
53055372 var loop_scope = parent_gz.makeSubBlock(scope);
53065373 loop_scope.setBreakResultLoc(rl);
5307 defer loop_scope.instructions.deinit(astgen.gpa);
5374 defer loop_scope.unstack();
53085375 defer loop_scope.labeled_breaks.deinit(astgen.gpa);
53095376 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
53105377
53115378 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
5312 defer cond_scope.instructions.deinit(astgen.gpa);
5379 defer cond_scope.unstack();
53135380
53145381 // check condition i < array_expr.len
53155382 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
......@@ -5321,9 +5388,10 @@ fn forExpr(
53215388 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
53225389 const condbr = try cond_scope.addCondBr(condbr_tag, node);
53235390 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
5324 const cond_block = try loop_scope.addBlock(block_tag, node);
5325 try loop_scope.instructions.append(astgen.gpa, cond_block);
5391 const cond_block = try loop_scope.makeBlockInst(block_tag, node);
53265392 try cond_scope.setBlockBody(cond_block);
5393 // cond_block unstacked now, can add new instructions to loop_scope
5394 try loop_scope.instructions.append(astgen.gpa, cond_block);
53275395
53285396 // Increment the index variable.
53295397 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
......@@ -5346,7 +5414,7 @@ fn forExpr(
53465414 }
53475415
53485416 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
5349 defer then_scope.instructions.deinit(astgen.gpa);
5417 defer then_scope.unstack();
53505418
53515419 var payload_val_scope: Scope.LocalVal = undefined;
53525420 var index_scope: Scope.LocalPtr = undefined;
......@@ -5408,7 +5476,7 @@ fn forExpr(
54085476 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
54095477
54105478 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
5411 defer else_scope.instructions.deinit(astgen.gpa);
5479 defer else_scope.unstack();
54125480
54135481 const else_node = for_full.ast.else_expr;
54145482 const else_info: struct {
......@@ -5600,15 +5668,16 @@ fn switchExpr(
56005668 defer astgen.scratch.items.len = scratch_top;
56015669
56025670 var block_scope = parent_gz.makeSubBlock(scope);
5671 // block_scope not used for collecting instructions
5672 block_scope.instructions_top = GenZir.unstacked_top;
56035673 block_scope.setBreakResultLoc(rl);
5604 defer block_scope.instructions.deinit(gpa);
56055674
56065675 // This gets added to the parent block later, after the item expressions.
5607 const switch_block = try parent_gz.addBlock(.switch_block, switch_node);
5676 const switch_block = try parent_gz.makeBlockInst(.switch_block, switch_node);
56085677
56095678 // We re-use this same scope for all cases, including the special prong, if any.
56105679 var case_scope = parent_gz.makeSubBlock(&block_scope.base);
5611 defer case_scope.instructions.deinit(gpa);
5680 case_scope.instructions_top = GenZir.unstacked_top;
56125681
56135682 // In this pass we generate all the item and prong expressions.
56145683 var multi_case_index: u32 = 0;
......@@ -5620,12 +5689,10 @@ fn switchExpr(
56205689 else => unreachable,
56215690 };
56225691
5623 // Reset the scope.
5624 case_scope.instructions.shrinkRetainingCapacity(0);
5625
56265692 const is_multi_case = case.ast.values.len > 1 or
56275693 (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range);
56285694
5695 var capture_inst: Zir.Inst.Index = 0;
56295696 var capture_val_scope: Scope.LocalVal = undefined;
56305697 const sub_scope = blk: {
56315698 const payload_token = case.payload_token orelse break :blk &case_scope.base;
......@@ -5640,19 +5707,20 @@ fn switchExpr(
56405707 }
56415708 break :blk &case_scope.base;
56425709 }
5643 const capture = if (case_node == special_node) capture: {
5710 if (case_node == special_node) {
56445711 const capture_tag: Zir.Inst.Tag = if (is_ptr)
56455712 .switch_capture_else_ref
56465713 else
56475714 .switch_capture_else;
5648 break :capture try case_scope.add(.{
5715 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
5716 try astgen.instructions.append(gpa, .{
56495717 .tag = capture_tag,
56505718 .data = .{ .switch_capture = .{
56515719 .switch_inst = switch_block,
56525720 .prong_index = undefined,
56535721 } },
56545722 });
5655 } else capture: {
5723 } else {
56565724 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
56575725 const is_ptr_bits: u2 = @boolToInt(is_ptr);
56585726 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {
......@@ -5662,20 +5730,21 @@ fn switchExpr(
56625730 0b11 => .switch_capture_multi_ref,
56635731 };
56645732 const capture_index = if (is_multi_case) multi_case_index else scalar_case_index;
5665 break :capture try case_scope.add(.{
5733 capture_inst = @intCast(Zir.Inst.Index, astgen.instructions.len);
5734 try astgen.instructions.append(gpa, .{
56665735 .tag = capture_tag,
56675736 .data = .{ .switch_capture = .{
56685737 .switch_inst = switch_block,
56695738 .prong_index = capture_index,
56705739 } },
56715740 });
5672 };
5741 }
56735742 const capture_name = try astgen.identAsString(ident);
56745743 capture_val_scope = .{
56755744 .parent = &case_scope.base,
56765745 .gen_zir = &case_scope,
56775746 .name = capture_name,
5678 .inst = capture,
5747 .inst = indexToRef(capture_inst),
56795748 .token_src = payload_token,
56805749 .id_cat = .@"capture",
56815750 };
......@@ -5728,14 +5797,23 @@ fn switchExpr(
57285797 break :blk header_index + 1;
57295798 };
57305799
5731 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
5732 try checkUsed(parent_gz, &case_scope.base, sub_scope);
5733 if (!parent_gz.refIsNoReturn(case_result)) {
5734 block_scope.break_count += 1;
5735 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
5800 {
5801 // temporarily stack case_scope on parent_gz
5802 case_scope.instructions_top = parent_gz.instructions.items.len;
5803 defer case_scope.unstack();
5804
5805 if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst);
5806 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
5807 try checkUsed(parent_gz, &case_scope.base, sub_scope);
5808 if (!parent_gz.refIsNoReturn(case_result)) {
5809 block_scope.break_count += 1;
5810 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
5811 }
5812
5813 const case_slice = case_scope.instructionsSlice();
5814 payloads.items[body_len_index] = @intCast(u32, case_slice.len);
5815 try payloads.appendSlice(gpa, case_slice);
57365816 }
5737 payloads.items[body_len_index] = @intCast(u32, case_scope.instructions.items.len);
5738 try payloads.appendSlice(gpa, case_scope.instructions.items);
57395817 }
57405818 // Now that the item expressions are generated we can add this.
57415819 try parent_gz.instructions.append(gpa, switch_block);
......@@ -5917,13 +5995,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
59175995 const condbr = try gz.addCondBr(.condbr, node);
59185996
59195997 var then_scope = gz.makeSubBlock(scope);
5920 defer then_scope.instructions.deinit(astgen.gpa);
5998 defer then_scope.unstack();
59215999
59226000 try genDefers(&then_scope, defer_outer, scope, .normal_only);
59236001 try then_scope.addRet(rl, operand, node);
59246002
59256003 var else_scope = gz.makeSubBlock(scope);
5926 defer else_scope.instructions.deinit(astgen.gpa);
6004 defer else_scope.unstack();
59276005
59286006 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
59296007 .both = try else_scope.addUnNode(.err_union_code, result, node),
......@@ -5931,7 +6009,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
59316009 try genDefers(&else_scope, defer_outer, scope, which_ones);
59326010 try else_scope.addRet(rl, operand, node);
59336011
5934 try setCondBrPayload(condbr, is_non_err, &then_scope, &else_scope);
6012 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);
59356013
59366014 return Zir.Inst.Ref.unreachable_value;
59376015 },
......@@ -6561,10 +6639,8 @@ fn asRlPtr(
65616639 operand_node: Ast.Node.Index,
65626640 dest_type: Zir.Inst.Ref,
65636641) InnerError!Zir.Inst.Ref {
6564 const astgen = parent_gz.astgen;
6565
65666642 var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr);
6567 defer as_scope.instructions.deinit(astgen.gpa);
6643 defer as_scope.unstack();
65686644
65696645 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);
65706646 return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type);
......@@ -7336,14 +7412,15 @@ fn cImport(
73367412 var block_scope = gz.makeSubBlock(scope);
73377413 block_scope.force_comptime = true;
73387414 block_scope.c_import = true;
7339 defer block_scope.instructions.deinit(gpa);
7415 defer block_scope.unstack();
73407416
7341 const block_inst = try gz.addBlock(.c_import, node);
7417 const block_inst = try gz.makeBlockInst(.c_import, node);
73427418 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);
73437419 if (!gz.refIsNoReturn(block_result)) {
73447420 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
73457421 }
73467422 try block_scope.setBlockBody(block_inst);
7423 // block_scope unstacked now, can add new instructions to gz
73477424 try gz.instructions.append(gpa, block_inst);
73487425
73497426 return indexToRef(block_inst);
......@@ -8167,6 +8244,7 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
81678244/// result locations must call this function on their result.
81688245/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
81698246/// If the `ResultLoc` is `ty`, it will coerce the result to the type.
8247/// Assumes nothing stacked on `gz`.
81708248fn rvalue(
81718249 gz: *GenZir,
81728250 rl: ResultLoc,
......@@ -8779,9 +8857,12 @@ const GenZir = struct {
87798857 parent: *Scope,
87808858 /// All `GenZir` scopes for the same ZIR share this.
87818859 astgen: *AstGen,
8782 /// Keeps track of the list of instructions in this scope only. Indexes
8783 /// to instructions in `astgen`.
8784 instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{},
8860 /// Keeps track of the list of instructions in this scope. Possibly shared.
8861 /// Indexes to instructions in `astgen`.
8862 instructions: *ArrayListUnmanaged(Zir.Inst.Index),
8863 /// A sub-block may share its instructions ArrayList with containing GenZir,
8864 /// if use is strictly nested. This saves prior size of list for unstacking.
8865 instructions_top: usize,
87858866 label: ?Label = null,
87868867 break_block: Zir.Inst.Index = 0,
87878868 continue_block: Zir.Inst.Index = 0,
......@@ -8817,6 +8898,36 @@ const GenZir = struct {
88178898 /// Keys are the raw instruction index, values are the closure_capture instruction.
88188899 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
88198900
8901 const unstacked_top = std.math.maxInt(usize);
8902 /// Call unstack before adding any new instructions to containing GenZir.
8903 fn unstack(self: *GenZir) void {
8904 if (self.instructions_top != unstacked_top) {
8905 self.instructions.items.len = self.instructions_top;
8906 self.instructions_top = unstacked_top;
8907 }
8908 }
8909
8910 fn isEmpty(self: *const GenZir) bool {
8911 return (self.instructions_top == unstacked_top) or
8912 (self.instructions.items.len == self.instructions_top);
8913 }
8914
8915 fn instructionsSlice(self: *const GenZir) []Zir.Inst.Index {
8916 return if (self.instructions_top == unstacked_top)
8917 &[0]Zir.Inst.Index{}
8918 else
8919 self.instructions.items[self.instructions_top..];
8920 }
8921
8922 fn instructionsSliceUpto(self: *const GenZir, stacked_gz: *GenZir) []Zir.Inst.Index {
8923 return if (self.instructions_top == unstacked_top)
8924 &[0]Zir.Inst.Index{}
8925 else if (self.instructions == stacked_gz.instructions and stacked_gz.instructions_top != unstacked_top)
8926 self.instructions.items[self.instructions_top..stacked_gz.instructions_top]
8927 else
8928 self.instructions.items[self.instructions_top..];
8929 }
8930
88208931 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
88218932 return .{
88228933 .force_comptime = gz.force_comptime,
......@@ -8828,6 +8939,8 @@ const GenZir = struct {
88288939 .astgen = gz.astgen,
88298940 .suspend_node = gz.suspend_node,
88308941 .nosuspend_node = gz.nosuspend_node,
8942 .instructions = gz.instructions,
8943 .instructions_top = gz.instructions.items.len,
88318944 };
88328945 }
88338946
......@@ -8841,12 +8954,13 @@ const GenZir = struct {
88418954 // result location. If it does, elide the coerce_result_ptr instruction
88428955 // as well as the store instruction, instead passing the result as an rvalue.
88438956 var as_scope = parent_gz.makeSubBlock(scope);
8844 errdefer as_scope.instructions.deinit(parent_gz.astgen.gpa);
8957 errdefer as_scope.unstack();
88458958 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
88468959
88478960 return as_scope;
88488961 }
88498962
8963 /// Assumes `as_scope` is stacked immediately on top of `parent_gz`. Unstacks `as_scope`.
88508964 fn finishCoercion(
88518965 as_scope: *GenZir,
88528966 parent_gz: *GenZir,
......@@ -8854,25 +8968,32 @@ const GenZir = struct {
88548968 src_node: Ast.Node.Index,
88558969 result: Zir.Inst.Ref,
88568970 dest_type: Zir.Inst.Ref,
8857 ) !Zir.Inst.Ref {
8971 ) InnerError!Zir.Inst.Ref {
8972 assert(as_scope.instructions == parent_gz.instructions);
88588973 const astgen = as_scope.astgen;
8859 const parent_zir = &parent_gz.instructions;
88608974 if (as_scope.rvalue_rl_count == 1) {
88618975 // Busted! This expression didn't actually need a pointer.
88628976 const zir_tags = astgen.instructions.items(.tag);
88638977 const zir_datas = astgen.instructions.items(.data);
8864 try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);
8865 for (as_scope.instructions.items) |src_inst| {
8978 var src: usize = as_scope.instructions_top;
8979 var dst: usize = src;
8980 while (src < as_scope.instructions.items.len) : (src += 1) {
8981 const src_inst = as_scope.instructions.items[src];
88668982 if (indexToRef(src_inst) == as_scope.rl_ptr) continue;
88678983 if (zir_tags[src_inst] == .store_to_block_ptr) {
88688984 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
88698985 }
8870 parent_zir.appendAssumeCapacity(src_inst);
8986 as_scope.instructions.items[dst] = src_inst;
8987 dst += 1;
88718988 }
8989 parent_gz.instructions.items.len -= src - dst;
8990 as_scope.instructions_top = GenZir.unstacked_top;
8991 // as_scope now unstacked, can add new instructions to parent_gz
88728992 const casted_result = try parent_gz.addBin(.as, dest_type, result);
88738993 return rvalue(parent_gz, rl, casted_result, src_node);
88748994 } else {
8875 try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
8995 // implicitly move all as_scope instructions to parent_gz
8996 as_scope.instructions_top = GenZir.unstacked_top;
88768997 return result;
88778998 }
88788999 }
......@@ -8883,9 +9004,10 @@ const GenZir = struct {
88839004 used: bool = false,
88849005 };
88859006
9007 /// Assumes nothing stacked on `gz`.
88869008 fn endsWithNoReturn(gz: GenZir) bool {
9009 if (gz.isEmpty()) return false;
88879010 const tags = gz.astgen.instructions.items(.tag);
8888 if (gz.instructions.items.len == 0) return false;
88899011 const last_inst = gz.instructions.items[gz.instructions.items.len - 1];
88909012 return tags[last_inst].isNoReturn();
88919013 }
......@@ -8955,41 +9077,46 @@ const GenZir = struct {
89559077 }
89569078 }
89579079
8958 fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {
9080 /// Assumes nothing stacked on `gz`. Unstacks `gz`.
9081 fn setBoolBrBody(gz: *GenZir, inst: Zir.Inst.Index) !void {
89599082 const gpa = gz.astgen.gpa;
8960 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
8961 gz.instructions.items.len);
9083 const body = gz.instructionsSlice();
9084 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);
89629085 const zir_datas = gz.astgen.instructions.items(.data);
89639086 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(
8964 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
9087 Zir.Inst.Block{ .body_len = @intCast(u32, body.len) },
89659088 );
8966 gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);
9089 gz.astgen.extra.appendSliceAssumeCapacity(body);
9090 gz.unstack();
89679091 }
89689092
8969 fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {
9093 /// Assumes nothing stacked on `gz`. Unstacks `gz`.
9094 fn setBlockBody(gz: *GenZir, inst: Zir.Inst.Index) !void {
89709095 const gpa = gz.astgen.gpa;
8971 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
8972 gz.instructions.items.len);
9096 const body = gz.instructionsSlice();
9097 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);
89739098 const zir_datas = gz.astgen.instructions.items(.data);
89749099 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(
8975 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
9100 Zir.Inst.Block{ .body_len = @intCast(u32, body.len) },
89769101 );
8977 gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);
9102 gz.astgen.extra.appendSliceAssumeCapacity(body);
9103 gz.unstack();
89789104 }
89799105
89809106 /// Same as `setBlockBody` except we don't copy instructions which are
89819107 /// `store_to_block_ptr` instructions with lhs set to .none.
8982 fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void {
9108 /// Assumes nothing stacked on `gz`. Unstacks `gz`.
9109 fn setBlockBodyEliding(gz: *GenZir, inst: Zir.Inst.Index) !void {
89839110 const gpa = gz.astgen.gpa;
8984 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
8985 gz.instructions.items.len);
9111 const body = gz.instructionsSlice();
9112 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);
89869113 const zir_datas = gz.astgen.instructions.items(.data);
89879114 const zir_tags = gz.astgen.instructions.items(.tag);
89889115 const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{
8989 .body_len = @intCast(u32, gz.instructions.items.len),
9116 .body_len = @intCast(u32, body.len),
89909117 });
89919118 zir_datas[inst].pl_node.payload_index = block_pl_index;
8992 for (gz.instructions.items) |sub_inst| {
9119 for (body) |sub_inst| {
89939120 if (zir_tags[sub_inst] == .store_to_block_ptr and
89949121 zir_datas[sub_inst].bin.lhs == .none)
89959122 {
......@@ -8999,15 +9126,17 @@ const GenZir = struct {
89999126 }
90009127 gz.astgen.extra.appendAssumeCapacity(sub_inst);
90019128 }
9129 gz.unstack();
90029130 }
90039131
9132 /// Supports `body_gz` stacked on `ret_gz` stacked on `gz`. Unstacks `body_gz` and `ret_gz`.
90049133 fn addFunc(gz: *GenZir, args: struct {
90059134 src_node: Ast.Node.Index,
90069135 lbrace_line: u32 = 0,
90079136 lbrace_column: u32 = 0,
9008 body: []const Zir.Inst.Index,
9137 body_gz: ?*GenZir,
90099138 param_block: Zir.Inst.Index,
9010 ret_ty: []const Zir.Inst.Index,
9139 ret_gz: ?*GenZir,
90119140 ret_br: Zir.Inst.Index,
90129141 cc: Zir.Inst.Ref,
90139142 align_inst: Zir.Inst.Ref,
......@@ -9021,12 +9150,13 @@ const GenZir = struct {
90219150 const astgen = gz.astgen;
90229151 const gpa = astgen.gpa;
90239152
9024 try gz.instructions.ensureUnusedCapacity(gpa, 1);
90259153 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
90269154
9155 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
9156 var ret_ty: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
90279157 var src_locs_buffer: [3]u32 = undefined;
90289158 var src_locs: []u32 = src_locs_buffer[0..0];
9029 if (args.body.len != 0) {
9159 if (args.body_gz) |body_gz| {
90309160 const tree = astgen.tree;
90319161 const node_tags = tree.nodes.items(.tag);
90329162 const node_datas = tree.nodes.items(.data);
......@@ -9044,6 +9174,13 @@ const GenZir = struct {
90449174 src_locs_buffer[1] = rbrace_line;
90459175 src_locs_buffer[2] = columns;
90469176 src_locs = &src_locs_buffer;
9177
9178 body = body_gz.instructionsSlice();
9179 if (args.ret_gz) |ret_gz|
9180 ret_ty = ret_gz.instructionsSliceUpto(body_gz);
9181 } else {
9182 if (args.ret_gz) |ret_gz|
9183 ret_ty = ret_gz.instructionsSlice();
90479184 }
90489185
90499186 if (args.cc != .none or args.lib_name != 0 or
......@@ -9053,7 +9190,7 @@ const GenZir = struct {
90539190 try astgen.extra.ensureUnusedCapacity(
90549191 gpa,
90559192 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
9056 args.ret_ty.len + args.body.len + src_locs.len +
9193 ret_ty.len + body.len + src_locs.len +
90579194 @boolToInt(args.lib_name != 0) +
90589195 @boolToInt(args.align_inst != .none) +
90599196 @boolToInt(args.cc != .none),
......@@ -9061,8 +9198,8 @@ const GenZir = struct {
90619198 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
90629199 .src_node = gz.nodeIndexToRelative(args.src_node),
90639200 .param_block = args.param_block,
9064 .ret_body_len = @intCast(u32, args.ret_ty.len),
9065 .body_len = @intCast(u32, args.body.len),
9201 .ret_body_len = @intCast(u32, ret_ty.len),
9202 .body_len = @intCast(u32, body.len),
90669203 });
90679204 if (args.lib_name != 0) {
90689205 astgen.extra.appendAssumeCapacity(args.lib_name);
......@@ -9073,9 +9210,13 @@ const GenZir = struct {
90739210 if (args.align_inst != .none) {
90749211 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
90759212 }
9076 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
9077 astgen.extra.appendSliceAssumeCapacity(args.body);
9213 astgen.extra.appendSliceAssumeCapacity(ret_ty);
9214 astgen.extra.appendSliceAssumeCapacity(body);
90789215 astgen.extra.appendSliceAssumeCapacity(src_locs);
9216 // order is important when unstacking
9217 if (args.body_gz) |body_gz| body_gz.unstack();
9218 if (args.ret_gz) |ret_gz| ret_gz.unstack();
9219 try gz.instructions.ensureUnusedCapacity(gpa, 1);
90799220
90809221 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
90819222 if (args.ret_br != 0) {
......@@ -9103,17 +9244,21 @@ const GenZir = struct {
91039244 try astgen.extra.ensureUnusedCapacity(
91049245 gpa,
91059246 @typeInfo(Zir.Inst.Func).Struct.fields.len +
9106 args.ret_ty.len + args.body.len + src_locs.len,
9247 ret_ty.len + body.len + src_locs.len,
91079248 );
91089249
91099250 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
91109251 .param_block = args.param_block,
9111 .ret_body_len = @intCast(u32, args.ret_ty.len),
9112 .body_len = @intCast(u32, args.body.len),
9252 .ret_body_len = @intCast(u32, ret_ty.len),
9253 .body_len = @intCast(u32, body.len),
91139254 });
9114 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
9115 astgen.extra.appendSliceAssumeCapacity(args.body);
9255 astgen.extra.appendSliceAssumeCapacity(ret_ty);
9256 astgen.extra.appendSliceAssumeCapacity(body);
91169257 astgen.extra.appendSliceAssumeCapacity(src_locs);
9258 // order is important when unstacking
9259 if (args.body_gz) |body_gz| body_gz.unstack();
9260 if (args.ret_gz) |ret_gz| ret_gz.unstack();
9261 try gz.instructions.ensureUnusedCapacity(gpa, 1);
91179262
91189263 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
91199264 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
......@@ -9260,6 +9405,25 @@ const GenZir = struct {
92609405 });
92619406 }
92629407
9408 fn makeUnNode(
9409 gz: *GenZir,
9410 tag: Zir.Inst.Tag,
9411 operand: Zir.Inst.Ref,
9412 /// Absolute node index. This function does the conversion to offset from Decl.
9413 src_node: Ast.Node.Index,
9414 ) !Zir.Inst.Index {
9415 assert(operand != .none);
9416 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9417 try gz.astgen.instructions.append(gz.astgen.gpa, .{
9418 .tag = tag,
9419 .data = .{ .un_node = .{
9420 .operand = operand,
9421 .src_node = gz.nodeIndexToRelative(src_node),
9422 } },
9423 });
9424 return new_index;
9425 }
9426
92639427 fn addPlNode(
92649428 gz: *GenZir,
92659429 tag: Zir.Inst.Tag,
......@@ -9300,25 +9464,27 @@ const GenZir = struct {
93009464 });
93019465 }
93029466
9467 /// Supports `param_gz` stacked on `gz`. Assumes nothing stacked on `param_gz`. Unstacks `param_gz`.
93039468 fn addParam(
93049469 gz: *GenZir,
9470 param_gz: *GenZir,
93059471 tag: Zir.Inst.Tag,
93069472 /// Absolute token index. This function does the conversion to Decl offset.
93079473 abs_tok_index: Ast.TokenIndex,
93089474 name: u32,
9309 body: []const u32,
93109475 ) !Zir.Inst.Index {
93119476 const gpa = gz.astgen.gpa;
9312 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9477 const param_body = param_gz.instructionsSlice();
93139478 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
93149479 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len +
9315 body.len);
9480 param_body.len);
93169481
93179482 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{
93189483 .name = name,
9319 .body_len = @intCast(u32, body.len),
9484 .body_len = @intCast(u32, param_body.len),
93209485 });
9321 gz.astgen.extra.appendSliceAssumeCapacity(body);
9486 gz.astgen.extra.appendSliceAssumeCapacity(param_body);
9487 param_gz.unstack();
93229488
93239489 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
93249490 gz.astgen.instructions.appendAssumeCapacity(.{
......@@ -9461,6 +9627,23 @@ const GenZir = struct {
94619627 });
94629628 }
94639629
9630 fn makeBreak(
9631 gz: *GenZir,
9632 tag: Zir.Inst.Tag,
9633 break_block: Zir.Inst.Index,
9634 operand: Zir.Inst.Ref,
9635 ) !Zir.Inst.Index {
9636 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9637 try gz.astgen.instructions.append(gz.astgen.gpa, .{
9638 .tag = tag,
9639 .data = .{ .@"break" = .{
9640 .block_inst = break_block,
9641 .operand = operand,
9642 } },
9643 });
9644 return new_index;
9645 }
9646
94649647 fn addBin(
94659648 gz: *GenZir,
94669649 tag: Zir.Inst.Tag,
......@@ -9649,7 +9832,7 @@ const GenZir = struct {
96499832 /// Note that this returns a `Zir.Inst.Index` not a ref.
96509833 /// Does *not* append the block instruction to the scope.
96519834 /// Leaves the `payload_index` field undefined.
9652 fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index {
9835 fn makeBlockInst(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index {
96539836 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
96549837 const gpa = gz.astgen.gpa;
96559838 try gz.astgen.instructions.append(gpa, .{