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 {...@@ -117,6 +117,7 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir {
117117
118 var top_scope: Scope.Top = .{};118 var top_scope: Scope.Top = .{};
119119
120 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
120 var gen_scope: GenZir = .{121 var gen_scope: GenZir = .{
121 .force_comptime = true,122 .force_comptime = true,
122 .in_defer = false,123 .in_defer = false,
...@@ -125,8 +126,10 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir {...@@ -125,8 +126,10 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir {
125 .decl_node_index = 0,126 .decl_node_index = 0,
126 .decl_line = 0,127 .decl_line = 0,
127 .astgen = &astgen,128 .astgen = &astgen,
129 .instructions = &gz_instructions,
130 .instructions_top = 0,
128 };131 };
129 defer gen_scope.instructions.deinit(gpa);132 defer gz_instructions.deinit(gpa);
130133
131 const container_decl: Ast.full.ContainerDecl = .{134 const container_decl: Ast.full.ContainerDecl = .{
132 .layout_token = null,135 .layout_token = null,
...@@ -1041,12 +1044,12 @@ fn suspendExpr(...@@ -1041,12 +1044,12 @@ fn suspendExpr(
1041 }1044 }
1042 assert(body_node != 0);1045 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);
1045 try gz.instructions.append(gpa, suspend_inst);1048 try gz.instructions.append(gpa, suspend_inst);
10461049
1047 var suspend_scope = gz.makeSubBlock(scope);1050 var suspend_scope = gz.makeSubBlock(scope);
1048 suspend_scope.suspend_node = node;1051 suspend_scope.suspend_node = node;
1049 defer suspend_scope.instructions.deinit(gpa);1052 defer suspend_scope.unstack();
10501053
1051 const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node);1054 const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node);
1052 if (!gz.refIsNoReturn(body_result)) {1055 if (!gz.refIsNoReturn(body_result)) {
...@@ -1101,7 +1104,6 @@ fn fnProtoExpr(...@@ -1101,7 +1104,6 @@ fn fnProtoExpr(
1101 fn_proto: Ast.full.FnProto,1104 fn_proto: Ast.full.FnProto,
1102) InnerError!Zir.Inst.Ref {1105) InnerError!Zir.Inst.Ref {
1103 const astgen = gz.astgen;1106 const astgen = gz.astgen;
1104 const gpa = astgen.gpa;
1105 const tree = astgen.tree;1107 const tree = astgen.tree;
1106 const token_tags = tree.tokens.items(.tag);1108 const token_tags = tree.tokens.items(.tag);
11071109
...@@ -1147,14 +1149,14 @@ fn fnProtoExpr(...@@ -1147,14 +1149,14 @@ fn fnProtoExpr(
1147 const param_type_node = param.type_expr;1149 const param_type_node = param.type_expr;
1148 assert(param_type_node != 0);1150 assert(param_type_node != 0);
1149 var param_gz = gz.makeSubBlock(scope);1151 var param_gz = gz.makeSubBlock(scope);
1150 defer param_gz.instructions.deinit(gpa);1152 defer param_gz.unstack();
1151 const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node);1153 const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node);
1152 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);1154 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
1153 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);1155 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
1154 const main_tokens = tree.nodes.items(.main_token);1156 const main_tokens = tree.nodes.items(.main_token);
1155 const name_token = param.name_token orelse main_tokens[param_type_node];1157 const name_token = param.name_token orelse main_tokens[param_type_node];
1156 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;1158 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);
1158 assert(param_inst_expected == param_inst);1160 assert(param_inst_expected == param_inst);
1159 }1161 }
1160 }1162 }
...@@ -1189,16 +1191,16 @@ fn fnProtoExpr(...@@ -1189,16 +1191,16 @@ fn fnProtoExpr(
1189 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});1191 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
1190 }1192 }
1191 var ret_gz = gz.makeSubBlock(scope);1193 var ret_gz = gz.makeSubBlock(scope);
1192 defer ret_gz.instructions.deinit(gpa);1194 defer ret_gz.unstack();
1193 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);1195 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
1194 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);1196 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
11951197
1196 const result = try gz.addFunc(.{1198 const result = try gz.addFunc(.{
1197 .src_node = fn_proto.ast.proto_node,1199 .src_node = fn_proto.ast.proto_node,
1198 .param_block = 0,1200 .param_block = 0,
1199 .ret_ty = ret_gz.instructions.items,1201 .ret_gz = &ret_gz,
1200 .ret_br = ret_br,1202 .ret_br = ret_br,
1201 .body = &[0]Zir.Inst.Index{},1203 .body_gz = null,
1202 .cc = cc,1204 .cc = cc,
1203 .align_inst = align_inst,1205 .align_inst = align_inst,
1204 .lib_name = 0,1206 .lib_name = 0,
...@@ -1376,7 +1378,7 @@ fn arrayInitExprRlPtr(...@@ -1376,7 +1378,7 @@ fn arrayInitExprRlPtr(
1376 }1378 }
13771379
1378 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr);1380 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
1381 const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements);1383 const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements);
1382 return as_scope.finishCoercion(gz, rl, node, result, array_ty);1384 return as_scope.finishCoercion(gz, rl, node, result, array_ty);
...@@ -1554,7 +1556,7 @@ fn structInitExprRlPtr(...@@ -1554,7 +1556,7 @@ fn structInitExprRlPtr(
1554 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1556 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
15551557
1556 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);1558 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
1559 const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr);1561 const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr);
1560 return as_scope.finishCoercion(gz, rl, node, result, ty_inst);1562 return as_scope.finishCoercion(gz, rl, node, result, ty_inst);
...@@ -1875,7 +1877,7 @@ fn labeledBlockExpr(...@@ -1875,7 +1877,7 @@ fn labeledBlockExpr(
18751877
1876 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct1878 // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct
1877 // so that break statements can reference it.1879 // 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);
1879 try gz.instructions.append(astgen.gpa, block_inst);1881 try gz.instructions.append(astgen.gpa, block_inst);
18801882
1881 var block_scope = gz.makeSubBlock(parent_scope);1883 var block_scope = gz.makeSubBlock(parent_scope);
...@@ -1884,7 +1886,7 @@ fn labeledBlockExpr(...@@ -1884,7 +1886,7 @@ fn labeledBlockExpr(
1884 .block_inst = block_inst,1886 .block_inst = block_inst,
1885 };1887 };
1886 block_scope.setBreakResultLoc(rl);1888 block_scope.setBreakResultLoc(rl);
1887 defer block_scope.instructions.deinit(astgen.gpa);1889 defer block_scope.unstack();
1888 defer block_scope.labeled_breaks.deinit(astgen.gpa);1890 defer block_scope.labeled_breaks.deinit(astgen.gpa);
1889 defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);1891 defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
18901892
...@@ -2489,7 +2491,6 @@ fn varDecl(...@@ -2489,7 +2491,6 @@ fn varDecl(
2489) InnerError!*Scope {2491) InnerError!*Scope {
2490 try emitDbgNode(gz, node);2492 try emitDbgNode(gz, node);
2491 const astgen = gz.astgen;2493 const astgen = gz.astgen;
2492 const gpa = astgen.gpa;
2493 const tree = astgen.tree;2494 const tree = astgen.tree;
2494 const token_tags = tree.tokens.items(.tag);2495 const token_tags = tree.tokens.items(.tag);
2495 const main_tokens = tree.nodes.items(.main_token);2496 const main_tokens = tree.nodes.items(.main_token);
...@@ -2550,7 +2551,9 @@ fn varDecl(...@@ -2550,7 +2551,9 @@ fn varDecl(
2550 // Detect whether the initialization expression actually uses the2551 // Detect whether the initialization expression actually uses the
2551 // result location pointer.2552 // result location pointer.
2552 var init_scope = gz.makeSubBlock(scope);2553 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
2555 var resolve_inferred_alloc: Zir.Inst.Ref = .none;2558 var resolve_inferred_alloc: Zir.Inst.Ref = .none;
2556 var opt_type_inst: Zir.Inst.Ref = .none;2559 var opt_type_inst: Zir.Inst.Ref = .none;
...@@ -2558,6 +2561,7 @@ fn varDecl(...@@ -2558,6 +2561,7 @@ fn varDecl(
2558 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);2561 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);
2559 opt_type_inst = type_inst;2562 opt_type_inst = type_inst;
2560 if (align_inst == .none) {2563 if (align_inst == .none) {
2564 init_scope.instructions_top = gz.instructions.items.len;
2561 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);2565 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
2562 } else {2566 } else {
2563 init_scope.rl_ptr = try gz.addAllocExtended(.{2567 init_scope.rl_ptr = try gz.addAllocExtended(.{
...@@ -2567,19 +2571,24 @@ fn varDecl(...@@ -2567,19 +2571,24 @@ fn varDecl(
2567 .is_const = true,2571 .is_const = true,
2568 .is_comptime = false,2572 .is_comptime = false,
2569 });2573 });
2574 init_scope.instructions_top = gz.instructions.items.len;
2570 }2575 }
2571 init_scope.rl_ty_inst = type_inst;2576 init_scope.rl_ty_inst = type_inst;
2572 } else {2577 } else {
2573 const alloc = if (align_inst == .none)2578 const alloc = if (align_inst == .none) alloc: {
2574 try init_scope.addNode(.alloc_inferred, node)2579 init_scope.instructions_top = gz.instructions.items.len;
2575 else2580 break :alloc try init_scope.addNode(.alloc_inferred, node);
2576 try gz.addAllocExtended(.{2581 } else alloc: {
2582 const ref = try gz.addAllocExtended(.{
2577 .node = node,2583 .node = node,
2578 .type_inst = .none,2584 .type_inst = .none,
2579 .align_inst = align_inst,2585 .align_inst = align_inst,
2580 .is_const = true,2586 .is_const = true,
2581 .is_comptime = false,2587 .is_comptime = false,
2582 });2588 });
2589 init_scope.instructions_top = gz.instructions.items.len;
2590 break :alloc ref;
2591 };
2583 resolve_inferred_alloc = alloc;2592 resolve_inferred_alloc = alloc;
2584 init_scope.rl_ptr = alloc;2593 init_scope.rl_ptr = alloc;
2585 }2594 }
...@@ -2589,20 +2598,24 @@ fn varDecl(...@@ -2589,20 +2598,24 @@ fn varDecl(
2589 const zir_tags = astgen.instructions.items(.tag);2598 const zir_tags = astgen.instructions.items(.tag);
2590 const zir_datas = astgen.instructions.items(.data);2599 const zir_datas = astgen.instructions.items(.data);
25912600
2592 const parent_zir = &gz.instructions;
2593 if (align_inst == .none and init_scope.rvalue_rl_count == 1) {2601 if (align_inst == .none and init_scope.rvalue_rl_count == 1) {
2594 // Result location pointer not used. We don't need an alloc for this2602 // Result location pointer not used. We don't need an alloc for this
2595 // const local, and type inference becomes trivial.2603 // const local, and type inference becomes trivial.
2596 // Move the init_scope instructions into the parent scope, eliding2604 // Implicitly move the init_scope instructions into the parent scope,
2597 // the alloc instruction and the store_to_block_ptr instruction.2605 // then elide the alloc instruction and the store_to_block_ptr instruction.
2598 try parent_zir.ensureUnusedCapacity(gpa, init_scope.instructions.items.len);2606 var src = init_scope.instructions_top;
2599 for (init_scope.instructions.items) |src_inst| {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];
2600 if (indexToRef(src_inst) == init_scope.rl_ptr) continue;2611 if (indexToRef(src_inst) == init_scope.rl_ptr) continue;
2601 if (zir_tags[src_inst] == .store_to_block_ptr) {2612 if (zir_tags[src_inst] == .store_to_block_ptr) {
2602 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;2613 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;
2603 }2614 }
2604 parent_zir.appendAssumeCapacity(src_inst);2615 gz.instructions.items[dst] = src_inst;
2616 dst += 1;
2605 }2617 }
2618 gz.instructions.items.len = dst;
26062619
2607 const sub_scope = try block_arena.create(Scope.LocalVal);2620 const sub_scope = try block_arena.create(Scope.LocalVal);
2608 sub_scope.* = .{2621 sub_scope.* = .{
...@@ -2617,11 +2630,13 @@ fn varDecl(...@@ -2617,11 +2630,13 @@ fn varDecl(
2617 }2630 }
2618 // The initialization expression took advantage of the result location2631 // The initialization expression took advantage of the result location
2619 // of the const local. In this case we will create an alloc and a LocalPtr for it.2632 // 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, swapping2633 // Implicitly move the init_scope instructions into the parent scope, then swap
2621 // store_to_block_ptr for store_to_inferred_ptr.2634 // store_to_block_ptr for store_to_inferred_ptr.
2622 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;2635
2623 try parent_zir.ensureTotalCapacity(gpa, expected_len);2636 var src = init_scope.instructions_top;
2624 for (init_scope.instructions.items) |src_inst| {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];
2625 if (zir_tags[src_inst] == .store_to_block_ptr) {2640 if (zir_tags[src_inst] == .store_to_block_ptr) {
2626 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {2641 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {
2627 if (var_decl.ast.type_node != 0) {2642 if (var_decl.ast.type_node != 0) {
...@@ -2631,9 +2646,7 @@ fn varDecl(...@@ -2631,9 +2646,7 @@ fn varDecl(
2631 }2646 }
2632 }2647 }
2633 }2648 }
2634 parent_zir.appendAssumeCapacity(src_inst);
2635 }2649 }
2636 assert(parent_zir.items.len == expected_len);
2637 if (resolve_inferred_alloc != .none) {2650 if (resolve_inferred_alloc != .none) {
2638 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);2651 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
2639 }2652 }
...@@ -3120,7 +3133,6 @@ fn fnDecl(...@@ -3120,7 +3133,6 @@ fn fnDecl(
3120 body_node: Ast.Node.Index,3133 body_node: Ast.Node.Index,
3121 fn_proto: Ast.full.FnProto,3134 fn_proto: Ast.full.FnProto,
3122) InnerError!void {3135) InnerError!void {
3123 const gpa = astgen.gpa;
3124 const tree = astgen.tree;3136 const tree = astgen.tree;
3125 const token_tags = tree.tokens.items(.tag);3137 const token_tags = tree.tokens.items(.tag);
31263138
...@@ -3130,7 +3142,7 @@ fn fnDecl(...@@ -3130,7 +3142,7 @@ fn fnDecl(
31303142
3131 // We insert this at the beginning so that its instruction index marks the3143 // We insert this at the beginning so that its instruction index marks the
3132 // start of the top level declaration.3144 // 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
3135 var decl_gz: GenZir = .{3147 var decl_gz: GenZir = .{
3136 .force_comptime = true,3148 .force_comptime = true,
...@@ -3139,8 +3151,10 @@ fn fnDecl(...@@ -3139,8 +3151,10 @@ fn fnDecl(
3139 .decl_line = gz.calcLine(decl_node),3151 .decl_line = gz.calcLine(decl_node),
3140 .parent = scope,3152 .parent = scope,
3141 .astgen = astgen,3153 .astgen = astgen,
3154 .instructions = gz.instructions,
3155 .instructions_top = gz.instructions.items.len,
3142 };3156 };
3143 defer decl_gz.instructions.deinit(gpa);3157 defer decl_gz.unstack();
31443158
3145 var fn_gz: GenZir = .{3159 var fn_gz: GenZir = .{
3146 .force_comptime = false,3160 .force_comptime = false,
...@@ -3149,8 +3163,10 @@ fn fnDecl(...@@ -3149,8 +3163,10 @@ fn fnDecl(
3149 .decl_line = decl_gz.decl_line,3163 .decl_line = decl_gz.decl_line,
3150 .parent = &decl_gz.base,3164 .parent = &decl_gz.base,
3151 .astgen = astgen,3165 .astgen = astgen,
3166 .instructions = gz.instructions,
3167 .instructions_top = GenZir.unstacked_top,
3152 };3168 };
3153 defer fn_gz.instructions.deinit(gpa);3169 defer fn_gz.unstack();
31543170
3155 // TODO: support noinline3171 // TODO: support noinline
3156 const is_pub = fn_proto.visib_token != null;3172 const is_pub = fn_proto.visib_token != null;
...@@ -3216,7 +3232,7 @@ fn fnDecl(...@@ -3216,7 +3232,7 @@ fn fnDecl(
3216 const param_type_node = param.type_expr;3232 const param_type_node = param.type_expr;
3217 assert(param_type_node != 0);3233 assert(param_type_node != 0);
3218 var param_gz = decl_gz.makeSubBlock(scope);3234 var param_gz = decl_gz.makeSubBlock(scope);
3219 defer param_gz.instructions.deinit(gpa);3235 defer param_gz.unstack();
3220 const param_type = try expr(&param_gz, params_scope, coerced_type_rl, param_type_node);3236 const param_type = try expr(&param_gz, params_scope, coerced_type_rl, param_type_node);
3221 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);3237 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
3222 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);3238 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
...@@ -3224,7 +3240,7 @@ fn fnDecl(...@@ -3224,7 +3240,7 @@ fn fnDecl(
3224 const main_tokens = tree.nodes.items(.main_token);3240 const main_tokens = tree.nodes.items(.main_token);
3225 const name_token = param.name_token orelse main_tokens[param_type_node];3241 const name_token = param.name_token orelse main_tokens[param_type_node];
3226 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;3242 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);
3228 assert(param_inst_expected == param_inst);3244 assert(param_inst_expected == param_inst);
3229 break :param indexToRef(param_inst);3245 break :param indexToRef(param_inst);
3230 };3246 };
...@@ -3289,7 +3305,7 @@ fn fnDecl(...@@ -3289,7 +3305,7 @@ fn fnDecl(
3289 };3305 };
32903306
3291 var ret_gz = decl_gz.makeSubBlock(params_scope);3307 var ret_gz = decl_gz.makeSubBlock(params_scope);
3292 defer ret_gz.instructions.deinit(gpa);3308 defer ret_gz.unstack();
3293 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);3309 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
3294 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);3310 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
32953311
...@@ -3302,10 +3318,10 @@ fn fnDecl(...@@ -3302,10 +3318,10 @@ fn fnDecl(
3302 }3318 }
3303 break :func try decl_gz.addFunc(.{3319 break :func try decl_gz.addFunc(.{
3304 .src_node = decl_node,3320 .src_node = decl_node,
3305 .ret_ty = ret_gz.instructions.items,3321 .ret_gz = &ret_gz,
3306 .ret_br = ret_br,3322 .ret_br = ret_br,
3307 .param_block = block_inst,3323 .param_block = block_inst,
3308 .body = &[0]Zir.Inst.Index{},3324 .body_gz = null,
3309 .cc = cc,3325 .cc = cc,
3310 .align_inst = .none, // passed in the per-decl data3326 .align_inst = .none, // passed in the per-decl data
3311 .lib_name = lib_name,3327 .lib_name = lib_name,
...@@ -3319,6 +3335,9 @@ fn fnDecl(...@@ -3319,6 +3335,9 @@ fn fnDecl(
3319 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});3335 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
3320 }3336 }
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
3322 const prev_fn_block = astgen.fn_block;3341 const prev_fn_block = astgen.fn_block;
3323 astgen.fn_block = &fn_gz;3342 astgen.fn_block = &fn_gz;
3324 defer astgen.fn_block = prev_fn_block;3343 defer astgen.fn_block = prev_fn_block;
...@@ -3332,14 +3351,7 @@ fn fnDecl(...@@ -3332,14 +3351,7 @@ fn fnDecl(
3332 _ = try expr(&fn_gz, params_scope, .none, body_node);3351 _ = try expr(&fn_gz, params_scope, .none, body_node);
3333 try checkUsed(gz, &fn_gz.base, params_scope);3352 try checkUsed(gz, &fn_gz.base, params_scope);
33343353
3335 const need_implicit_ret = blk: {3354 if (!fn_gz.endsWithNoReturn()) {
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) {
3343 // Since we are adding the return instruction here, we must handle the coercion.3355 // Since we are adding the return instruction here, we must handle the coercion.
3344 // We do this by using the `ret_coerce` instruction.3356 // We do this by using the `ret_coerce` instruction.
3345 _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));3357 _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
...@@ -3350,9 +3362,9 @@ fn fnDecl(...@@ -3350,9 +3362,9 @@ fn fnDecl(
3350 .lbrace_line = lbrace_line,3362 .lbrace_line = lbrace_line,
3351 .lbrace_column = lbrace_column,3363 .lbrace_column = lbrace_column,
3352 .param_block = block_inst,3364 .param_block = block_inst,
3353 .ret_ty = ret_gz.instructions.items,3365 .ret_gz = &ret_gz,
3354 .ret_br = ret_br,3366 .ret_br = ret_br,
3355 .body = fn_gz.instructions.items,3367 .body_gz = &fn_gz,
3356 .cc = cc,3368 .cc = cc,
3357 .align_inst = .none, // passed in the per-decl data3369 .align_inst = .none, // passed in the per-decl data
3358 .lib_name = lib_name,3370 .lib_name = lib_name,
...@@ -3364,7 +3376,7 @@ fn fnDecl(...@@ -3364,7 +3376,7 @@ fn fnDecl(
3364 };3376 };
33653377
3366 // We add this at the end so that its instruction index marks the end range3378 // 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.
3368 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);3380 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);
3369 try decl_gz.setBlockBody(block_inst);3381 try decl_gz.setBlockBody(block_inst);
33703382
...@@ -3396,14 +3408,13 @@ fn globalVarDecl(...@@ -3396,14 +3408,13 @@ fn globalVarDecl(
3396 node: Ast.Node.Index,3408 node: Ast.Node.Index,
3397 var_decl: Ast.full.VarDecl,3409 var_decl: Ast.full.VarDecl,
3398) InnerError!void {3410) InnerError!void {
3399 const gpa = astgen.gpa;
3400 const tree = astgen.tree;3411 const tree = astgen.tree;
3401 const token_tags = tree.tokens.items(.tag);3412 const token_tags = tree.tokens.items(.tag);
34023413
3403 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;3414 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
3404 // We do this at the beginning so that the instruction index marks the range start3415 // We do this at the beginning so that the instruction index marks the range start
3405 // of the top level declaration.3416 // 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
3408 const name_token = var_decl.ast.mut_token + 1;3419 const name_token = var_decl.ast.mut_token + 1;
3409 const name_str_index = try astgen.identAsString(name_token);3420 const name_str_index = try astgen.identAsString(name_token);
...@@ -3416,8 +3427,10 @@ fn globalVarDecl(...@@ -3416,8 +3427,10 @@ fn globalVarDecl(
3416 .force_comptime = true,3427 .force_comptime = true,
3417 .in_defer = false,3428 .in_defer = false,
3418 .anon_name_strategy = .parent,3429 .anon_name_strategy = .parent,
3430 .instructions = gz.instructions,
3431 .instructions_top = gz.instructions.items.len,
3419 };3432 };
3420 defer block_scope.instructions.deinit(gpa);3433 defer block_scope.unstack();
34213434
3422 const is_pub = var_decl.visib_token != null;3435 const is_pub = var_decl.visib_token != null;
3423 const is_export = blk: {3436 const is_export = blk: {
...@@ -3543,14 +3556,13 @@ fn comptimeDecl(...@@ -3543,14 +3556,13 @@ fn comptimeDecl(
3543 wip_members: *WipMembers,3556 wip_members: *WipMembers,
3544 node: Ast.Node.Index,3557 node: Ast.Node.Index,
3545) InnerError!void {3558) InnerError!void {
3546 const gpa = astgen.gpa;
3547 const tree = astgen.tree;3559 const tree = astgen.tree;
3548 const node_datas = tree.nodes.items(.data);3560 const node_datas = tree.nodes.items(.data);
3549 const body_node = node_datas[node].lhs;3561 const body_node = node_datas[node].lhs;
35503562
3551 // Up top so the ZIR instruction index marks the start range of this3563 // Up top so the ZIR instruction index marks the start range of this
3552 // top-level declaration.3564 // top-level declaration.
3553 const block_inst = try gz.addBlock(.block_inline, node);3565 const block_inst = try gz.makeBlockInst(.block_inline, node);
3554 wip_members.nextDecl(false, false, false, false);3566 wip_members.nextDecl(false, false, false, false);
35553567
3556 var decl_block: GenZir = .{3568 var decl_block: GenZir = .{
...@@ -3560,11 +3572,13 @@ fn comptimeDecl(...@@ -3560,11 +3572,13 @@ fn comptimeDecl(
3560 .decl_line = gz.calcLine(node),3572 .decl_line = gz.calcLine(node),
3561 .parent = scope,3573 .parent = scope,
3562 .astgen = astgen,3574 .astgen = astgen,
3575 .instructions = gz.instructions,
3576 .instructions_top = gz.instructions.items.len,
3563 };3577 };
3564 defer decl_block.instructions.deinit(gpa);3578 defer decl_block.unstack();
35653579
3566 const block_result = try expr(&decl_block, &decl_block.base, .none, body_node);3580 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)) {
3568 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value);3582 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value);
3569 }3583 }
3570 try decl_block.setBlockBody(block_inst);3584 try decl_block.setBlockBody(block_inst);
...@@ -3589,7 +3603,6 @@ fn usingnamespaceDecl(...@@ -3589,7 +3603,6 @@ fn usingnamespaceDecl(
3589 wip_members: *WipMembers,3603 wip_members: *WipMembers,
3590 node: Ast.Node.Index,3604 node: Ast.Node.Index,
3591) InnerError!void {3605) InnerError!void {
3592 const gpa = astgen.gpa;
3593 const tree = astgen.tree;3606 const tree = astgen.tree;
3594 const node_datas = tree.nodes.items(.data);3607 const node_datas = tree.nodes.items(.data);
35953608
...@@ -3602,7 +3615,7 @@ fn usingnamespaceDecl(...@@ -3602,7 +3615,7 @@ fn usingnamespaceDecl(
3602 };3615 };
3603 // Up top so the ZIR instruction index marks the start range of this3616 // Up top so the ZIR instruction index marks the start range of this
3604 // top-level declaration.3617 // top-level declaration.
3605 const block_inst = try gz.addBlock(.block_inline, node);3618 const block_inst = try gz.makeBlockInst(.block_inline, node);
3606 wip_members.nextDecl(is_pub, true, false, false);3619 wip_members.nextDecl(is_pub, true, false, false);
36073620
3608 var decl_block: GenZir = .{3621 var decl_block: GenZir = .{
...@@ -3612,8 +3625,10 @@ fn usingnamespaceDecl(...@@ -3612,8 +3625,10 @@ fn usingnamespaceDecl(
3612 .decl_line = gz.calcLine(node),3625 .decl_line = gz.calcLine(node),
3613 .parent = scope,3626 .parent = scope,
3614 .astgen = astgen,3627 .astgen = astgen,
3628 .instructions = gz.instructions,
3629 .instructions_top = gz.instructions.items.len,
3615 };3630 };
3616 defer decl_block.instructions.deinit(gpa);3631 defer decl_block.unstack();
36173632
3618 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);3633 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
3619 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);3634 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);
...@@ -3639,14 +3654,13 @@ fn testDecl(...@@ -3639,14 +3654,13 @@ fn testDecl(
3639 wip_members: *WipMembers,3654 wip_members: *WipMembers,
3640 node: Ast.Node.Index,3655 node: Ast.Node.Index,
3641) InnerError!void {3656) InnerError!void {
3642 const gpa = astgen.gpa;
3643 const tree = astgen.tree;3657 const tree = astgen.tree;
3644 const node_datas = tree.nodes.items(.data);3658 const node_datas = tree.nodes.items(.data);
3645 const body_node = node_datas[node].rhs;3659 const body_node = node_datas[node].rhs;
36463660
3647 // Up top so the ZIR instruction index marks the start range of this3661 // Up top so the ZIR instruction index marks the start range of this
3648 // top-level declaration.3662 // top-level declaration.
3649 const block_inst = try gz.addBlock(.block_inline, node);3663 const block_inst = try gz.makeBlockInst(.block_inline, node);
36503664
3651 wip_members.nextDecl(false, false, false, false);3665 wip_members.nextDecl(false, false, false, false);
36523666
...@@ -3657,8 +3671,10 @@ fn testDecl(...@@ -3657,8 +3671,10 @@ fn testDecl(
3657 .decl_line = gz.calcLine(node),3671 .decl_line = gz.calcLine(node),
3658 .parent = scope,3672 .parent = scope,
3659 .astgen = astgen,3673 .astgen = astgen,
3674 .instructions = gz.instructions,
3675 .instructions_top = gz.instructions.items.len,
3660 };3676 };
3661 defer decl_block.instructions.deinit(gpa);3677 defer decl_block.unstack();
36623678
3663 const test_name: u32 = blk: {3679 const test_name: u32 = blk: {
3664 const main_tokens = tree.nodes.items(.main_token);3680 const main_tokens = tree.nodes.items(.main_token);
...@@ -3679,8 +3695,10 @@ fn testDecl(...@@ -3679,8 +3695,10 @@ fn testDecl(
3679 .decl_line = decl_block.decl_line,3695 .decl_line = decl_block.decl_line,
3680 .parent = &decl_block.base,3696 .parent = &decl_block.base,
3681 .astgen = astgen,3697 .astgen = astgen,
3698 .instructions = decl_block.instructions,
3699 .instructions_top = decl_block.instructions.items.len,
3682 };3700 };
3683 defer fn_block.instructions.deinit(gpa);3701 defer fn_block.unstack();
36843702
3685 const prev_fn_block = astgen.fn_block;3703 const prev_fn_block = astgen.fn_block;
3686 astgen.fn_block = &fn_block;3704 astgen.fn_block = &fn_block;
...@@ -3693,7 +3711,7 @@ fn testDecl(...@@ -3693,7 +3711,7 @@ fn testDecl(
3693 const lbrace_column = @intCast(u32, astgen.source_column);3711 const lbrace_column = @intCast(u32, astgen.source_column);
36943712
3695 const block_result = try expr(&fn_block, &fn_block.base, .none, body_node);3713 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)) {
3697 // Since we are adding the return instruction here, we must handle the coercion.3715 // Since we are adding the return instruction here, we must handle the coercion.
3698 // We do this by using the `ret_coerce` instruction.3716 // We do this by using the `ret_coerce` instruction.
3699 _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));3717 _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node));
...@@ -3704,9 +3722,9 @@ fn testDecl(...@@ -3704,9 +3722,9 @@ fn testDecl(
3704 .lbrace_line = lbrace_line,3722 .lbrace_line = lbrace_line,
3705 .lbrace_column = lbrace_column,3723 .lbrace_column = lbrace_column,
3706 .param_block = block_inst,3724 .param_block = block_inst,
3707 .ret_ty = &.{},3725 .ret_gz = null,
3708 .ret_br = 0,3726 .ret_br = 0,
3709 .body = fn_block.instructions.items,3727 .body_gz = &fn_block,
3710 .cc = .none,3728 .cc = .none,
3711 .align_inst = .none,3729 .align_inst = .none,
3712 .lib_name = 0,3730 .lib_name = 0,
...@@ -3776,8 +3794,10 @@ fn structDeclInner(...@@ -3776,8 +3794,10 @@ fn structDeclInner(
3776 .astgen = astgen,3794 .astgen = astgen,
3777 .force_comptime = true,3795 .force_comptime = true,
3778 .in_defer = false,3796 .in_defer = false,
3797 .instructions = gz.instructions,
3798 .instructions_top = gz.instructions.items.len,
3779 };3799 };
3780 defer block_scope.instructions.deinit(gpa);3800 defer block_scope.unstack();
37813801
3782 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);3802 const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members);
3783 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);3803 const field_count = @intCast(u32, container_decl.ast.members.len - decl_count);
...@@ -3829,14 +3849,16 @@ fn structDeclInner(...@@ -3829,14 +3849,16 @@ fn structDeclInner(
3829 }3849 }
3830 }3850 }
38313851
3832 if (block_scope.instructions.items.len != 0) {3852 if (!block_scope.isEmpty()) {
3833 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);3853 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
3834 }3854 }
38353855
3856 const body = block_scope.instructionsSlice();
3857
3836 try gz.setStruct(decl_inst, .{3858 try gz.setStruct(decl_inst, .{
3837 .src_node = node,3859 .src_node = node,
3838 .layout = layout,3860 .layout = layout,
3839 .body_len = @intCast(u32, block_scope.instructions.items.len),3861 .body_len = @intCast(u32, body.len),
3840 .fields_len = field_count,3862 .fields_len = field_count,
3841 .decls_len = decl_count,3863 .decls_len = decl_count,
3842 .known_has_bits = known_has_bits,3864 .known_has_bits = known_has_bits,
...@@ -3845,11 +3867,12 @@ fn structDeclInner(...@@ -3845,11 +3867,12 @@ fn structDeclInner(
3845 wip_members.finishBits(bits_per_field);3867 wip_members.finishBits(bits_per_field);
3846 const decls_slice = wip_members.declsSlice();3868 const decls_slice = wip_members.declsSlice();
3847 const fields_slice = wip_members.fieldsSlice();3869 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);
3849 astgen.extra.appendSliceAssumeCapacity(decls_slice);3871 astgen.extra.appendSliceAssumeCapacity(decls_slice);
3850 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);3872 astgen.extra.appendSliceAssumeCapacity(body);
3851 astgen.extra.appendSliceAssumeCapacity(fields_slice);3873 astgen.extra.appendSliceAssumeCapacity(fields_slice);
38523874
3875 block_scope.unstack();
3853 try gz.addNamespaceCaptures(&namespace);3876 try gz.addNamespaceCaptures(&namespace);
3854 return indexToRef(decl_inst);3877 return indexToRef(decl_inst);
3855}3878}
...@@ -3888,8 +3911,10 @@ fn unionDeclInner(...@@ -3888,8 +3911,10 @@ fn unionDeclInner(
3888 .astgen = astgen,3911 .astgen = astgen,
3889 .force_comptime = true,3912 .force_comptime = true,
3890 .in_defer = false,3913 .in_defer = false,
3914 .instructions = gz.instructions,
3915 .instructions_top = gz.instructions.items.len,
3891 };3916 };
3892 defer block_scope.instructions.deinit(gpa);3917 defer block_scope.unstack();
38933918
3894 const decl_count = try astgen.scanDecls(&namespace, members);3919 const decl_count = try astgen.scanDecls(&namespace, members);
3895 const field_count = @intCast(u32, members.len - decl_count);3920 const field_count = @intCast(u32, members.len - decl_count);
...@@ -3972,15 +3997,17 @@ fn unionDeclInner(...@@ -3972,15 +3997,17 @@ fn unionDeclInner(
3972 return astgen.failNode(node, "union declarations must have at least one tag", .{});3997 return astgen.failNode(node, "union declarations must have at least one tag", .{});
3973 }3998 }
39743999
3975 if (block_scope.instructions.items.len != 0) {4000 if (!block_scope.isEmpty()) {
3976 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);4001 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
3977 }4002 }
39784003
4004 const body = block_scope.instructionsSlice();
4005
3979 try gz.setUnion(decl_inst, .{4006 try gz.setUnion(decl_inst, .{
3980 .src_node = node,4007 .src_node = node,
3981 .layout = layout,4008 .layout = layout,
3982 .tag_type = arg_inst,4009 .tag_type = arg_inst,
3983 .body_len = @intCast(u32, block_scope.instructions.items.len),4010 .body_len = @intCast(u32, body.len),
3984 .fields_len = field_count,4011 .fields_len = field_count,
3985 .decls_len = decl_count,4012 .decls_len = decl_count,
3986 .auto_enum_tag = have_auto_enum,4013 .auto_enum_tag = have_auto_enum,
...@@ -3989,11 +4016,12 @@ fn unionDeclInner(...@@ -3989,11 +4016,12 @@ fn unionDeclInner(
3989 wip_members.finishBits(bits_per_field);4016 wip_members.finishBits(bits_per_field);
3990 const decls_slice = wip_members.declsSlice();4017 const decls_slice = wip_members.declsSlice();
3991 const fields_slice = wip_members.fieldsSlice();4018 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);
3993 astgen.extra.appendSliceAssumeCapacity(decls_slice);4020 astgen.extra.appendSliceAssumeCapacity(decls_slice);
3994 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);4021 astgen.extra.appendSliceAssumeCapacity(body);
3995 astgen.extra.appendSliceAssumeCapacity(fields_slice);4022 astgen.extra.appendSliceAssumeCapacity(fields_slice);
39964023
4024 block_scope.unstack();
3997 try gz.addNamespaceCaptures(&namespace);4025 try gz.addNamespaceCaptures(&namespace);
3998 return indexToRef(decl_inst);4026 return indexToRef(decl_inst);
3999}4027}
...@@ -4163,8 +4191,10 @@ fn containerDecl(...@@ -4163,8 +4191,10 @@ fn containerDecl(
4163 .astgen = astgen,4191 .astgen = astgen,
4164 .force_comptime = true,4192 .force_comptime = true,
4165 .in_defer = false,4193 .in_defer = false,
4194 .instructions = gz.instructions,
4195 .instructions_top = gz.instructions.items.len,
4166 };4196 };
4167 defer block_scope.instructions.deinit(gpa);4197 defer block_scope.unstack();
41684198
4169 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);4199 _ = try astgen.scanDecls(&namespace, container_decl.ast.members);
41704200
...@@ -4215,15 +4245,17 @@ fn containerDecl(...@@ -4215,15 +4245,17 @@ fn containerDecl(
4215 }4245 }
4216 }4246 }
42174247
4218 if (block_scope.instructions.items.len != 0) {4248 if (!block_scope.isEmpty()) {
4219 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);4249 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
4220 }4250 }
42214251
4252 const body = block_scope.instructionsSlice();
4253
4222 try gz.setEnum(decl_inst, .{4254 try gz.setEnum(decl_inst, .{
4223 .src_node = node,4255 .src_node = node,
4224 .nonexhaustive = nonexhaustive,4256 .nonexhaustive = nonexhaustive,
4225 .tag_type = arg_inst,4257 .tag_type = arg_inst,
4226 .body_len = @intCast(u32, block_scope.instructions.items.len),4258 .body_len = @intCast(u32, body.len),
4227 .fields_len = @intCast(u32, counts.total_fields),4259 .fields_len = @intCast(u32, counts.total_fields),
4228 .decls_len = @intCast(u32, counts.decls),4260 .decls_len = @intCast(u32, counts.decls),
4229 });4261 });
...@@ -4231,11 +4263,12 @@ fn containerDecl(...@@ -4231,11 +4263,12 @@ fn containerDecl(
4231 wip_members.finishBits(bits_per_field);4263 wip_members.finishBits(bits_per_field);
4232 const decls_slice = wip_members.declsSlice();4264 const decls_slice = wip_members.declsSlice();
4233 const fields_slice = wip_members.fieldsSlice();4265 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);
4235 astgen.extra.appendSliceAssumeCapacity(decls_slice);4267 astgen.extra.appendSliceAssumeCapacity(decls_slice);
4236 astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);4268 astgen.extra.appendSliceAssumeCapacity(body);
4237 astgen.extra.appendSliceAssumeCapacity(fields_slice);4269 astgen.extra.appendSliceAssumeCapacity(fields_slice);
42384270
4271 block_scope.unstack();
4239 try gz.addNamespaceCaptures(&namespace);4272 try gz.addNamespaceCaptures(&namespace);
4240 return rvalue(gz, rl, indexToRef(decl_inst), node);4273 return rvalue(gz, rl, indexToRef(decl_inst), node);
4241 },4274 },
...@@ -4453,7 +4486,7 @@ fn tryExpr(...@@ -4453,7 +4486,7 @@ fn tryExpr(
44534486
4454 var block_scope = parent_gz.makeSubBlock(scope);4487 var block_scope = parent_gz.makeSubBlock(scope);
4455 block_scope.setBreakResultLoc(rl);4488 block_scope.setBreakResultLoc(rl);
4456 defer block_scope.instructions.deinit(astgen.gpa);4489 defer block_scope.unstack();
44574490
4458 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {4491 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
4459 .ref => .ref,4492 .ref => .ref,
...@@ -4473,12 +4506,13 @@ fn tryExpr(...@@ -4473,12 +4506,13 @@ fn tryExpr(
4473 const cond = try block_scope.addUnNode(err_ops[0], operand, node);4506 const cond = try block_scope.addUnNode(err_ops[0], operand, node);
4474 const condbr = try block_scope.addCondBr(.condbr, node);4507 const condbr = try block_scope.addCondBr(.condbr, node);
44754508
4476 const block = try parent_gz.addBlock(.block, node);4509 const block = try parent_gz.makeBlockInst(.block, node);
4477 try parent_gz.instructions.append(astgen.gpa, block);
4478 try block_scope.setBlockBody(block);4510 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
4480 var then_scope = parent_gz.makeSubBlock(scope);4514 var then_scope = parent_gz.makeSubBlock(scope);
4481 defer then_scope.instructions.deinit(astgen.gpa);4515 defer then_scope.unstack();
44824516
4483 block_scope.break_count += 1;4517 block_scope.break_count += 1;
4484 // This could be a pointer or value depending on `err_ops[2]`.4518 // This could be a pointer or value depending on `err_ops[2]`.
...@@ -4488,8 +4522,9 @@ fn tryExpr(...@@ -4488,8 +4522,9 @@ fn tryExpr(
4488 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),4522 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),
4489 };4523 };
44904524
4525 // else_scope will be stacked on then_scope as both are stacked on parent_gz
4491 var else_scope = parent_gz.makeSubBlock(scope);4526 var else_scope = parent_gz.makeSubBlock(scope);
4492 defer else_scope.instructions.deinit(astgen.gpa);4527 defer else_scope.unstack();
44934528
4494 const err_code = try else_scope.addUnNode(err_ops[1], operand, node);4529 const err_code = try else_scope.addUnNode(err_ops[1], operand, node);
4495 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });4530 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
...@@ -4529,7 +4564,7 @@ fn orelseCatchExpr(...@@ -4529,7 +4564,7 @@ fn orelseCatchExpr(
45294564
4530 var block_scope = parent_gz.makeSubBlock(scope);4565 var block_scope = parent_gz.makeSubBlock(scope);
4531 block_scope.setBreakResultLoc(rl);4566 block_scope.setBreakResultLoc(rl);
4532 defer block_scope.instructions.deinit(astgen.gpa);4567 defer block_scope.unstack();
45334568
4534 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {4569 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
4535 .ref => .ref,4570 .ref => .ref,
...@@ -4544,12 +4579,13 @@ fn orelseCatchExpr(...@@ -4544,12 +4579,13 @@ fn orelseCatchExpr(
4544 const cond = try block_scope.addUnNode(cond_op, operand, node);4579 const cond = try block_scope.addUnNode(cond_op, operand, node);
4545 const condbr = try block_scope.addCondBr(.condbr, node);4580 const condbr = try block_scope.addCondBr(.condbr, node);
45464581
4547 const block = try parent_gz.addBlock(.block, node);4582 const block = try parent_gz.makeBlockInst(.block, node);
4548 try parent_gz.instructions.append(astgen.gpa, block);
4549 try block_scope.setBlockBody(block);4583 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
4551 var then_scope = parent_gz.makeSubBlock(scope);4587 var then_scope = parent_gz.makeSubBlock(scope);
4552 defer then_scope.instructions.deinit(astgen.gpa);4588 defer then_scope.unstack();
45534589
4554 // This could be a pointer or value depending on `unwrap_op`.4590 // This could be a pointer or value depending on `unwrap_op`.
4555 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);4591 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
...@@ -4559,7 +4595,7 @@ fn orelseCatchExpr(...@@ -4559,7 +4595,7 @@ fn orelseCatchExpr(
4559 };4595 };
45604596
4561 var else_scope = parent_gz.makeSubBlock(scope);4597 var else_scope = parent_gz.makeSubBlock(scope);
4562 defer else_scope.instructions.deinit(astgen.gpa);4598 defer else_scope.unstack();
45634599
4564 var err_val_scope: Scope.LocalVal = undefined;4600 var err_val_scope: Scope.LocalVal = undefined;
4565 const else_sub_scope = blk: {4601 const else_sub_scope = blk: {
...@@ -4606,6 +4642,7 @@ fn orelseCatchExpr(...@@ -4606,6 +4642,7 @@ fn orelseCatchExpr(
4606 );4642 );
4607}4643}
46084644
4645/// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`.
4609fn finishThenElseBlock(4646fn finishThenElseBlock(
4610 parent_gz: *GenZir,4647 parent_gz: *GenZir,
4611 rl: ResultLoc,4648 rl: ResultLoc,
...@@ -4624,33 +4661,33 @@ fn finishThenElseBlock(...@@ -4624,33 +4661,33 @@ fn finishThenElseBlock(
4624 // We now have enough information to decide whether the result instruction should4661 // We now have enough information to decide whether the result instruction should
4625 // be communicated via result location pointer or break instructions.4662 // be communicated via result location pointer or break instructions.
4626 const strat = rl.strategy(block_scope);4663 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
4627 switch (strat.tag) {4670 switch (strat.tag) {
4628 .break_void => {4671 .break_void => {
4629 if (!then_scope.endsWithNoReturn()) {4672 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, .void_value) else 0;
4630 _ = try then_scope.addBreak(break_tag, then_break_block, .void_value);4673 const else_break = if (!else_no_return) try else_scope.makeBreak(break_tag, main_block, .void_value) else 0;
4631 }
4632 if (!else_scope.endsWithNoReturn()) {
4633 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
4634 }
4635 assert(!strat.elide_store_to_block_ptr_instructions);4674 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);
4637 return indexToRef(main_block);4676 return indexToRef(main_block);
4638 },4677 },
4639 .break_operand => {4678 .break_operand => {
4640 if (!then_scope.endsWithNoReturn()) {4679 const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, then_result) else 0;
4641 _ = try then_scope.addBreak(break_tag, then_break_block, then_result);4680 const else_break = if (else_result == .none)
4642 }4681 try else_scope.makeBreak(break_tag, main_block, .void_value)
4643 if (else_result != .none) {4682 else if (!else_no_return)
4644 if (!else_scope.endsWithNoReturn()) {4683 try else_scope.makeBreak(break_tag, main_block, else_result)
4645 _ = try else_scope.addBreak(break_tag, main_block, else_result);4684 else
4646 }4685 0;
4647 } else {4686
4648 _ = try else_scope.addBreak(break_tag, main_block, .void_value);
4649 }
4650 if (strat.elide_store_to_block_ptr_instructions) {4687 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);
4652 } else {4689 } else {
4653 try setCondBrPayload(condbr, cond, then_scope, else_scope);4690 try setCondBrPayload(condbr, cond, then_scope, then_break, else_scope, else_break);
4654 }4691 }
4655 const block_ref = indexToRef(main_block);4692 const block_ref = indexToRef(main_block);
4656 switch (rl) {4693 switch (rl) {
...@@ -4778,7 +4815,7 @@ fn boolBinOp(...@@ -4778,7 +4815,7 @@ fn boolBinOp(
4778 const bool_br = try gz.addBoolBr(zir_tag, lhs);4815 const bool_br = try gz.addBoolBr(zir_tag, lhs);
47794816
4780 var rhs_scope = gz.makeSubBlock(scope);4817 var rhs_scope = gz.makeSubBlock(scope);
4781 defer rhs_scope.instructions.deinit(gz.astgen.gpa);4818 defer rhs_scope.unstack();
4782 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);4819 const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs);
4783 if (!gz.refIsNoReturn(rhs)) {4820 if (!gz.refIsNoReturn(rhs)) {
4784 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);4821 _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs);
...@@ -4802,7 +4839,7 @@ fn ifExpr(...@@ -4802,7 +4839,7 @@ fn ifExpr(
48024839
4803 var block_scope = parent_gz.makeSubBlock(scope);4840 var block_scope = parent_gz.makeSubBlock(scope);
4804 block_scope.setBreakResultLoc(rl);4841 block_scope.setBreakResultLoc(rl);
4805 defer block_scope.instructions.deinit(astgen.gpa);4842 defer block_scope.unstack();
48064843
4807 const payload_is_ref = if (if_full.payload_token) |payload_token|4844 const payload_is_ref = if (if_full.payload_token) |payload_token|
4808 token_tags[payload_token] == .asterisk4845 token_tags[payload_token] == .asterisk
...@@ -4840,12 +4877,13 @@ fn ifExpr(...@@ -4840,12 +4877,13 @@ fn ifExpr(
48404877
4841 const condbr = try block_scope.addCondBr(.condbr, node);4878 const condbr = try block_scope.addCondBr(.condbr, node);
48424879
4843 const block = try parent_gz.addBlock(.block, node);4880 const block = try parent_gz.makeBlockInst(.block, node);
4844 try parent_gz.instructions.append(astgen.gpa, block);
4845 try block_scope.setBlockBody(block);4881 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
4847 var then_scope = parent_gz.makeSubBlock(scope);4885 var then_scope = parent_gz.makeSubBlock(scope);
4848 defer then_scope.instructions.deinit(astgen.gpa);4886 defer then_scope.unstack();
48494887
4850 var payload_val_scope: Scope.LocalVal = undefined;4888 var payload_val_scope: Scope.LocalVal = undefined;
48514889
...@@ -4911,7 +4949,7 @@ fn ifExpr(...@@ -4911,7 +4949,7 @@ fn ifExpr(
4911 // instructions or not.4949 // instructions or not.
49124950
4913 var else_scope = parent_gz.makeSubBlock(scope);4951 var else_scope = parent_gz.makeSubBlock(scope);
4914 defer else_scope.instructions.deinit(astgen.gpa);4952 defer else_scope.unstack();
49154953
4916 const else_node = if_full.ast.else_expr;4954 const else_node = if_full.ast.else_expr;
4917 const else_info: struct {4955 const else_info: struct {
...@@ -4974,52 +5012,70 @@ fn ifExpr(...@@ -4974,52 +5012,70 @@ fn ifExpr(
4974 );5012 );
4975}5013}
49765014
5015/// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`.
4977fn setCondBrPayload(5016fn setCondBrPayload(
4978 condbr: Zir.Inst.Index,5017 condbr: Zir.Inst.Index,
4979 cond: Zir.Inst.Ref,5018 cond: Zir.Inst.Ref,
4980 then_scope: *GenZir,5019 then_scope: *GenZir,
5020 then_break: Zir.Inst.Index,
4981 else_scope: *GenZir,5021 else_scope: *GenZir,
5022 else_break: Zir.Inst.Index,
4982) !void {5023) !void {
5024 defer then_scope.unstack();
5025 defer else_scope.unstack();
4983 const astgen = then_scope.astgen;5026 const astgen = then_scope.astgen;
49845027 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));
4985 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +5031 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
4988 const zir_datas = astgen.instructions.items(.data);5034 const zir_datas = astgen.instructions.items(.data);
4989 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{5035 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
4990 .condition = cond,5036 .condition = cond,
4991 .then_body_len = @intCast(u32, then_scope.instructions.items.len),5037 .then_body_len = then_body_len,
4992 .else_body_len = @intCast(u32, else_scope.instructions.items.len),5038 .else_body_len = else_body_len,
4993 });5039 });
4994 astgen.extra.appendSliceAssumeCapacity(then_scope.instructions.items);5040 astgen.extra.appendSliceAssumeCapacity(then_body);
4995 astgen.extra.appendSliceAssumeCapacity(else_scope.instructions.items);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);
4996}5044}
49975045
5046/// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`.
4998fn setCondBrPayloadElideBlockStorePtr(5047fn setCondBrPayloadElideBlockStorePtr(
4999 condbr: Zir.Inst.Index,5048 condbr: Zir.Inst.Index,
5000 cond: Zir.Inst.Ref,5049 cond: Zir.Inst.Ref,
5001 then_scope: *GenZir,5050 then_scope: *GenZir,
5051 then_break: Zir.Inst.Index,
5002 else_scope: *GenZir,5052 else_scope: *GenZir,
5053 else_break: Zir.Inst.Index,
5003 block_ptr: Zir.Inst.Ref,5054 block_ptr: Zir.Inst.Ref,
5004) !void {5055) !void {
5056 defer then_scope.unstack();
5057 defer else_scope.unstack();
5005 const astgen = then_scope.astgen;5058 const astgen = then_scope.astgen;
50065059 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));
5007 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +5063 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
5010 const zir_tags = astgen.instructions.items(.tag);5066 const zir_tags = astgen.instructions.items(.tag);
5011 const zir_datas = astgen.instructions.items(.data);5067 const zir_datas = astgen.instructions.items(.data);
50125068
5013 const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{5069 const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
5014 .condition = cond,5070 .condition = cond,
5015 .then_body_len = @intCast(u32, then_scope.instructions.items.len),5071 .then_body_len = then_body_len,
5016 .else_body_len = @intCast(u32, else_scope.instructions.items.len),5072 .else_body_len = else_body_len,
5017 });5073 });
5018 zir_datas[condbr].pl_node.payload_index = condbr_pl;5074 zir_datas[condbr].pl_node.payload_index = condbr_pl;
5019 const then_body_len_index = condbr_pl + 1;5075 const then_body_len_index = condbr_pl + 1;
5020 const else_body_len_index = condbr_pl + 2;5076 const else_body_len_index = condbr_pl + 2;
50215077
5022 for (then_scope.instructions.items) |src_inst| {5078 for (then_body) |src_inst| {
5023 if (zir_tags[src_inst] == .store_to_block_ptr) {5079 if (zir_tags[src_inst] == .store_to_block_ptr) {
5024 if (zir_datas[src_inst].bin.lhs == block_ptr) {5080 if (zir_datas[src_inst].bin.lhs == block_ptr) {
5025 astgen.extra.items[then_body_len_index] -= 1;5081 astgen.extra.items[then_body_len_index] -= 1;
...@@ -5028,7 +5084,8 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -5028,7 +5084,8 @@ fn setCondBrPayloadElideBlockStorePtr(
5028 }5084 }
5029 astgen.extra.appendAssumeCapacity(src_inst);5085 astgen.extra.appendAssumeCapacity(src_inst);
5030 }5086 }
5031 for (else_scope.instructions.items) |src_inst| {5087 if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break);
5088 for (else_body) |src_inst| {
5032 if (zir_tags[src_inst] == .store_to_block_ptr) {5089 if (zir_tags[src_inst] == .store_to_block_ptr) {
5033 if (zir_datas[src_inst].bin.lhs == block_ptr) {5090 if (zir_datas[src_inst].bin.lhs == block_ptr) {
5034 astgen.extra.items[else_body_len_index] -= 1;5091 astgen.extra.items[else_body_len_index] -= 1;
...@@ -5037,6 +5094,7 @@ fn setCondBrPayloadElideBlockStorePtr(...@@ -5037,6 +5094,7 @@ fn setCondBrPayloadElideBlockStorePtr(
5037 }5094 }
5038 astgen.extra.appendAssumeCapacity(src_inst);5095 astgen.extra.appendAssumeCapacity(src_inst);
5039 }5096 }
5097 if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break);
5040}5098}
50415099
5042fn whileExpr(5100fn whileExpr(
...@@ -5056,17 +5114,17 @@ fn whileExpr(...@@ -5056,17 +5114,17 @@ fn whileExpr(
50565114
5057 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;5115 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;
5058 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;5116 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);
5060 try parent_gz.instructions.append(astgen.gpa, loop_block);5118 try parent_gz.instructions.append(astgen.gpa, loop_block);
50615119
5062 var loop_scope = parent_gz.makeSubBlock(scope);5120 var loop_scope = parent_gz.makeSubBlock(scope);
5063 loop_scope.setBreakResultLoc(rl);5121 loop_scope.setBreakResultLoc(rl);
5064 defer loop_scope.instructions.deinit(astgen.gpa);5122 defer loop_scope.unstack();
5065 defer loop_scope.labeled_breaks.deinit(astgen.gpa);5123 defer loop_scope.labeled_breaks.deinit(astgen.gpa);
5066 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);5124 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
50675125
5068 var continue_scope = parent_gz.makeSubBlock(&loop_scope.base);5126 var continue_scope = parent_gz.makeSubBlock(&loop_scope.base);
5069 defer continue_scope.instructions.deinit(astgen.gpa);5127 defer continue_scope.unstack();
50705128
5071 const payload_is_ref = if (while_full.payload_token) |payload_token|5129 const payload_is_ref = if (while_full.payload_token) |payload_token|
5072 token_tags[payload_token] == .asterisk5130 token_tags[payload_token] == .asterisk
...@@ -5105,15 +5163,19 @@ fn whileExpr(...@@ -5105,15 +5163,19 @@ fn whileExpr(
5105 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;5163 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
5106 const condbr = try continue_scope.addCondBr(condbr_tag, node);5164 const condbr = try continue_scope.addCondBr(condbr_tag, node);
5107 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;5165 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
5108 const cond_block = try loop_scope.addBlock(block_tag, node);5166 const cond_block = try loop_scope.makeBlockInst(block_tag, node);
5109 try loop_scope.instructions.append(astgen.gpa, cond_block);
5110 try continue_scope.setBlockBody(cond_block);5167 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
5112 var then_scope = parent_gz.makeSubBlock(&continue_scope.base);5173 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;
5115 var payload_val_scope: Scope.LocalVal = undefined;5178 var payload_val_scope: Scope.LocalVal = undefined;
5116
5117 const then_sub_scope = s: {5179 const then_sub_scope = s: {
5118 if (while_full.error_token != null) {5180 if (while_full.error_token != null) {
5119 if (while_full.payload_token) |payload_token| {5181 if (while_full.payload_token) |payload_token| {
...@@ -5121,7 +5183,8 @@ fn whileExpr(...@@ -5121,7 +5183,8 @@ fn whileExpr(
5121 .err_union_payload_unsafe_ptr5183 .err_union_payload_unsafe_ptr
5122 else5184 else
5123 .err_union_payload_unsafe;5185 .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);
5125 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;5188 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
5126 const ident_bytes = tree.tokenSlice(ident_token);5189 const ident_bytes = tree.tokenSlice(ident_token);
5127 if (mem.eql(u8, "_", ident_bytes))5190 if (mem.eql(u8, "_", ident_bytes))
...@@ -5133,7 +5196,7 @@ fn whileExpr(...@@ -5133,7 +5196,7 @@ fn whileExpr(
5133 .parent = &then_scope.base,5196 .parent = &then_scope.base,
5134 .gen_zir = &then_scope,5197 .gen_zir = &then_scope,
5135 .name = ident_name,5198 .name = ident_name,
5136 .inst = payload_inst,5199 .inst = indexToRef(payload_inst),
5137 .token_src = payload_token,5200 .token_src = payload_token,
5138 .id_cat = .@"capture",5201 .id_cat = .@"capture",
5139 };5202 };
...@@ -5147,7 +5210,8 @@ fn whileExpr(...@@ -5147,7 +5210,8 @@ fn whileExpr(
5147 .optional_payload_unsafe_ptr5210 .optional_payload_unsafe_ptr
5148 else5211 else
5149 .optional_payload_unsafe;5212 .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);
5151 const ident_name = try astgen.identAsString(ident_token);5215 const ident_name = try astgen.identAsString(ident_token);
5152 const ident_bytes = tree.tokenSlice(ident_token);5216 const ident_bytes = tree.tokenSlice(ident_token);
5153 if (mem.eql(u8, "_", ident_bytes))5217 if (mem.eql(u8, "_", ident_bytes))
...@@ -5157,7 +5221,7 @@ fn whileExpr(...@@ -5157,7 +5221,7 @@ fn whileExpr(
5157 .parent = &then_scope.base,5221 .parent = &then_scope.base,
5158 .gen_zir = &then_scope,5222 .gen_zir = &then_scope,
5159 .name = ident_name,5223 .name = ident_name,
5160 .inst = payload_inst,5224 .inst = indexToRef(payload_inst),
5161 .token_src = ident_token,5225 .token_src = ident_token,
5162 .id_cat = .@"capture",5226 .id_cat = .@"capture",
5163 };5227 };
...@@ -5187,6 +5251,9 @@ fn whileExpr(...@@ -5187,6 +5251,9 @@ fn whileExpr(
5187 });5251 });
5188 }5252 }
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);
5190 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);5257 const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
5191 if (!then_scope.endsWithNoReturn()) {5258 if (!then_scope.endsWithNoReturn()) {
5192 loop_scope.break_count += 1;5259 loop_scope.break_count += 1;
...@@ -5194,7 +5261,7 @@ fn whileExpr(...@@ -5194,7 +5261,7 @@ fn whileExpr(
5194 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);5261 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
51955262
5196 var else_scope = parent_gz.makeSubBlock(&continue_scope.base);5263 var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
5197 defer else_scope.instructions.deinit(astgen.gpa);5264 defer else_scope.unstack();
51985265
5199 const else_node = while_full.ast.else_expr;5266 const else_node = while_full.ast.else_expr;
5200 const else_info: struct {5267 const else_info: struct {
...@@ -5207,7 +5274,7 @@ fn whileExpr(...@@ -5207,7 +5274,7 @@ fn whileExpr(
5207 .err_union_code_ptr5274 .err_union_code_ptr
5208 else5275 else
5209 .err_union_code;5276 .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);
5211 const ident_name = try astgen.identAsString(error_token);5278 const ident_name = try astgen.identAsString(error_token);
5212 const ident_bytes = tree.tokenSlice(error_token);5279 const ident_bytes = tree.tokenSlice(error_token);
5213 if (mem.eql(u8, ident_bytes, "_"))5280 if (mem.eql(u8, ident_bytes, "_"))
...@@ -5217,7 +5284,7 @@ fn whileExpr(...@@ -5217,7 +5284,7 @@ fn whileExpr(
5217 .parent = &else_scope.base,5284 .parent = &else_scope.base,
5218 .gen_zir = &else_scope,5285 .gen_zir = &else_scope,
5219 .name = ident_name,5286 .name = ident_name,
5220 .inst = payload_inst,5287 .inst = else_payload_inst,
5221 .token_src = error_token,5288 .token_src = error_token,
5222 .id_cat = .@"capture",5289 .id_cat = .@"capture",
5223 };5290 };
...@@ -5299,17 +5366,17 @@ fn forExpr(...@@ -5299,17 +5366,17 @@ fn forExpr(
5299 };5366 };
53005367
5301 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;5368 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);
5303 try parent_gz.instructions.append(astgen.gpa, loop_block);5370 try parent_gz.instructions.append(astgen.gpa, loop_block);
53045371
5305 var loop_scope = parent_gz.makeSubBlock(scope);5372 var loop_scope = parent_gz.makeSubBlock(scope);
5306 loop_scope.setBreakResultLoc(rl);5373 loop_scope.setBreakResultLoc(rl);
5307 defer loop_scope.instructions.deinit(astgen.gpa);5374 defer loop_scope.unstack();
5308 defer loop_scope.labeled_breaks.deinit(astgen.gpa);5375 defer loop_scope.labeled_breaks.deinit(astgen.gpa);
5309 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);5376 defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa);
53105377
5311 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);5378 var cond_scope = parent_gz.makeSubBlock(&loop_scope.base);
5312 defer cond_scope.instructions.deinit(astgen.gpa);5379 defer cond_scope.unstack();
53135380
5314 // check condition i < array_expr.len5381 // check condition i < array_expr.len
5315 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);5382 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
...@@ -5321,9 +5388,10 @@ fn forExpr(...@@ -5321,9 +5388,10 @@ fn forExpr(
5321 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;5388 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
5322 const condbr = try cond_scope.addCondBr(condbr_tag, node);5389 const condbr = try cond_scope.addCondBr(condbr_tag, node);
5323 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;5390 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
5324 const cond_block = try loop_scope.addBlock(block_tag, node);5391 const cond_block = try loop_scope.makeBlockInst(block_tag, node);
5325 try loop_scope.instructions.append(astgen.gpa, cond_block);
5326 try cond_scope.setBlockBody(cond_block);5392 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
5328 // Increment the index variable.5396 // Increment the index variable.
5329 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);5397 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
...@@ -5346,7 +5414,7 @@ fn forExpr(...@@ -5346,7 +5414,7 @@ fn forExpr(
5346 }5414 }
53475415
5348 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);5416 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
5349 defer then_scope.instructions.deinit(astgen.gpa);5417 defer then_scope.unstack();
53505418
5351 var payload_val_scope: Scope.LocalVal = undefined;5419 var payload_val_scope: Scope.LocalVal = undefined;
5352 var index_scope: Scope.LocalPtr = undefined;5420 var index_scope: Scope.LocalPtr = undefined;
...@@ -5408,7 +5476,7 @@ fn forExpr(...@@ -5408,7 +5476,7 @@ fn forExpr(
5408 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);5476 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
54095477
5410 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);5478 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
5411 defer else_scope.instructions.deinit(astgen.gpa);5479 defer else_scope.unstack();
54125480
5413 const else_node = for_full.ast.else_expr;5481 const else_node = for_full.ast.else_expr;
5414 const else_info: struct {5482 const else_info: struct {
...@@ -5600,15 +5668,16 @@ fn switchExpr(...@@ -5600,15 +5668,16 @@ fn switchExpr(
5600 defer astgen.scratch.items.len = scratch_top;5668 defer astgen.scratch.items.len = scratch_top;
56015669
5602 var block_scope = parent_gz.makeSubBlock(scope);5670 var block_scope = parent_gz.makeSubBlock(scope);
5671 // block_scope not used for collecting instructions
5672 block_scope.instructions_top = GenZir.unstacked_top;
5603 block_scope.setBreakResultLoc(rl);5673 block_scope.setBreakResultLoc(rl);
5604 defer block_scope.instructions.deinit(gpa);
56055674
5606 // This gets added to the parent block later, after the item expressions.5675 // 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
5609 // We re-use this same scope for all cases, including the special prong, if any.5678 // We re-use this same scope for all cases, including the special prong, if any.
5610 var case_scope = parent_gz.makeSubBlock(&block_scope.base);5679 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
5613 // In this pass we generate all the item and prong expressions.5682 // In this pass we generate all the item and prong expressions.
5614 var multi_case_index: u32 = 0;5683 var multi_case_index: u32 = 0;
...@@ -5620,12 +5689,10 @@ fn switchExpr(...@@ -5620,12 +5689,10 @@ fn switchExpr(
5620 else => unreachable,5689 else => unreachable,
5621 };5690 };
56225691
5623 // Reset the scope.
5624 case_scope.instructions.shrinkRetainingCapacity(0);
5625
5626 const is_multi_case = case.ast.values.len > 1 or5692 const is_multi_case = case.ast.values.len > 1 or
5627 (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range);5693 (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range);
56285694
5695 var capture_inst: Zir.Inst.Index = 0;
5629 var capture_val_scope: Scope.LocalVal = undefined;5696 var capture_val_scope: Scope.LocalVal = undefined;
5630 const sub_scope = blk: {5697 const sub_scope = blk: {
5631 const payload_token = case.payload_token orelse break :blk &case_scope.base;5698 const payload_token = case.payload_token orelse break :blk &case_scope.base;
...@@ -5640,19 +5707,20 @@ fn switchExpr(...@@ -5640,19 +5707,20 @@ fn switchExpr(
5640 }5707 }
5641 break :blk &case_scope.base;5708 break :blk &case_scope.base;
5642 }5709 }
5643 const capture = if (case_node == special_node) capture: {5710 if (case_node == special_node) {
5644 const capture_tag: Zir.Inst.Tag = if (is_ptr)5711 const capture_tag: Zir.Inst.Tag = if (is_ptr)
5645 .switch_capture_else_ref5712 .switch_capture_else_ref
5646 else5713 else
5647 .switch_capture_else;5714 .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, .{
5649 .tag = capture_tag,5717 .tag = capture_tag,
5650 .data = .{ .switch_capture = .{5718 .data = .{ .switch_capture = .{
5651 .switch_inst = switch_block,5719 .switch_inst = switch_block,
5652 .prong_index = undefined,5720 .prong_index = undefined,
5653 } },5721 } },
5654 });5722 });
5655 } else capture: {5723 } else {
5656 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);5724 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
5657 const is_ptr_bits: u2 = @boolToInt(is_ptr);5725 const is_ptr_bits: u2 = @boolToInt(is_ptr);
5658 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {5726 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {
...@@ -5662,20 +5730,21 @@ fn switchExpr(...@@ -5662,20 +5730,21 @@ fn switchExpr(
5662 0b11 => .switch_capture_multi_ref,5730 0b11 => .switch_capture_multi_ref,
5663 };5731 };
5664 const capture_index = if (is_multi_case) multi_case_index else scalar_case_index;5732 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, .{
5666 .tag = capture_tag,5735 .tag = capture_tag,
5667 .data = .{ .switch_capture = .{5736 .data = .{ .switch_capture = .{
5668 .switch_inst = switch_block,5737 .switch_inst = switch_block,
5669 .prong_index = capture_index,5738 .prong_index = capture_index,
5670 } },5739 } },
5671 });5740 });
5672 };5741 }
5673 const capture_name = try astgen.identAsString(ident);5742 const capture_name = try astgen.identAsString(ident);
5674 capture_val_scope = .{5743 capture_val_scope = .{
5675 .parent = &case_scope.base,5744 .parent = &case_scope.base,
5676 .gen_zir = &case_scope,5745 .gen_zir = &case_scope,
5677 .name = capture_name,5746 .name = capture_name,
5678 .inst = capture,5747 .inst = indexToRef(capture_inst),
5679 .token_src = payload_token,5748 .token_src = payload_token,
5680 .id_cat = .@"capture",5749 .id_cat = .@"capture",
5681 };5750 };
...@@ -5728,14 +5797,23 @@ fn switchExpr(...@@ -5728,14 +5797,23 @@ fn switchExpr(
5728 break :blk header_index + 1;5797 break :blk header_index + 1;
5729 };5798 };
57305799
5731 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);5800 {
5732 try checkUsed(parent_gz, &case_scope.base, sub_scope);5801 // temporarily stack case_scope on parent_gz
5733 if (!parent_gz.refIsNoReturn(case_result)) {5802 case_scope.instructions_top = parent_gz.instructions.items.len;
5734 block_scope.break_count += 1;5803 defer case_scope.unstack();
5735 _ = try case_scope.addBreak(.@"break", switch_block, case_result);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);
5736 }5816 }
5737 payloads.items[body_len_index] = @intCast(u32, case_scope.instructions.items.len);
5738 try payloads.appendSlice(gpa, case_scope.instructions.items);
5739 }5817 }
5740 // Now that the item expressions are generated we can add this.5818 // Now that the item expressions are generated we can add this.
5741 try parent_gz.instructions.append(gpa, switch_block);5819 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...@@ -5917,13 +5995,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
5917 const condbr = try gz.addCondBr(.condbr, node);5995 const condbr = try gz.addCondBr(.condbr, node);
59185996
5919 var then_scope = gz.makeSubBlock(scope);5997 var then_scope = gz.makeSubBlock(scope);
5920 defer then_scope.instructions.deinit(astgen.gpa);5998 defer then_scope.unstack();
59215999
5922 try genDefers(&then_scope, defer_outer, scope, .normal_only);6000 try genDefers(&then_scope, defer_outer, scope, .normal_only);
5923 try then_scope.addRet(rl, operand, node);6001 try then_scope.addRet(rl, operand, node);
59246002
5925 var else_scope = gz.makeSubBlock(scope);6003 var else_scope = gz.makeSubBlock(scope);
5926 defer else_scope.instructions.deinit(astgen.gpa);6004 defer else_scope.unstack();
59276005
5928 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{6006 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
5929 .both = try else_scope.addUnNode(.err_union_code, result, node),6007 .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...@@ -5931,7 +6009,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
5931 try genDefers(&else_scope, defer_outer, scope, which_ones);6009 try genDefers(&else_scope, defer_outer, scope, which_ones);
5932 try else_scope.addRet(rl, operand, node);6010 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
5936 return Zir.Inst.Ref.unreachable_value;6014 return Zir.Inst.Ref.unreachable_value;
5937 },6015 },
...@@ -6561,10 +6639,8 @@ fn asRlPtr(...@@ -6561,10 +6639,8 @@ fn asRlPtr(
6561 operand_node: Ast.Node.Index,6639 operand_node: Ast.Node.Index,
6562 dest_type: Zir.Inst.Ref,6640 dest_type: Zir.Inst.Ref,
6563) InnerError!Zir.Inst.Ref {6641) InnerError!Zir.Inst.Ref {
6564 const astgen = parent_gz.astgen;
6565
6566 var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr);6642 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
6569 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);6645 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);
6570 return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type);6646 return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type);
...@@ -7336,14 +7412,15 @@ fn cImport(...@@ -7336,14 +7412,15 @@ fn cImport(
7336 var block_scope = gz.makeSubBlock(scope);7412 var block_scope = gz.makeSubBlock(scope);
7337 block_scope.force_comptime = true;7413 block_scope.force_comptime = true;
7338 block_scope.c_import = true;7414 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);
7342 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);7418 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);
7343 if (!gz.refIsNoReturn(block_result)) {7419 if (!gz.refIsNoReturn(block_result)) {
7344 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);7420 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
7345 }7421 }
7346 try block_scope.setBlockBody(block_inst);7422 try block_scope.setBlockBody(block_inst);
7423 // block_scope unstacked now, can add new instructions to gz
7347 try gz.instructions.append(gpa, block_inst);7424 try gz.instructions.append(gpa, block_inst);
73487425
7349 return indexToRef(block_inst);7426 return indexToRef(block_inst);
...@@ -8167,6 +8244,7 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8167,6 +8244,7 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8167/// result locations must call this function on their result.8244/// result locations must call this function on their result.
8168/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.8245/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
8169/// If the `ResultLoc` is `ty`, it will coerce the result to the type.8246/// If the `ResultLoc` is `ty`, it will coerce the result to the type.
8247/// Assumes nothing stacked on `gz`.
8170fn rvalue(8248fn rvalue(
8171 gz: *GenZir,8249 gz: *GenZir,
8172 rl: ResultLoc,8250 rl: ResultLoc,
...@@ -8779,9 +8857,12 @@ const GenZir = struct {...@@ -8779,9 +8857,12 @@ const GenZir = struct {
8779 parent: *Scope,8857 parent: *Scope,
8780 /// All `GenZir` scopes for the same ZIR share this.8858 /// All `GenZir` scopes for the same ZIR share this.
8781 astgen: *AstGen,8859 astgen: *AstGen,
8782 /// Keeps track of the list of instructions in this scope only. Indexes8860 /// Keeps track of the list of instructions in this scope. Possibly shared.
8783 /// to instructions in `astgen`.8861 /// Indexes to instructions in `astgen`.
8784 instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{},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,
8785 label: ?Label = null,8866 label: ?Label = null,
8786 break_block: Zir.Inst.Index = 0,8867 break_block: Zir.Inst.Index = 0,
8787 continue_block: Zir.Inst.Index = 0,8868 continue_block: Zir.Inst.Index = 0,
...@@ -8817,6 +8898,36 @@ const GenZir = struct {...@@ -8817,6 +8898,36 @@ const GenZir = struct {
8817 /// Keys are the raw instruction index, values are the closure_capture instruction.8898 /// Keys are the raw instruction index, values are the closure_capture instruction.
8818 captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},8899 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
8820 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {8931 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
8821 return .{8932 return .{
8822 .force_comptime = gz.force_comptime,8933 .force_comptime = gz.force_comptime,
...@@ -8828,6 +8939,8 @@ const GenZir = struct {...@@ -8828,6 +8939,8 @@ const GenZir = struct {
8828 .astgen = gz.astgen,8939 .astgen = gz.astgen,
8829 .suspend_node = gz.suspend_node,8940 .suspend_node = gz.suspend_node,
8830 .nosuspend_node = gz.nosuspend_node,8941 .nosuspend_node = gz.nosuspend_node,
8942 .instructions = gz.instructions,
8943 .instructions_top = gz.instructions.items.len,
8831 };8944 };
8832 }8945 }
88338946
...@@ -8841,12 +8954,13 @@ const GenZir = struct {...@@ -8841,12 +8954,13 @@ const GenZir = struct {
8841 // result location. If it does, elide the coerce_result_ptr instruction8954 // result location. If it does, elide the coerce_result_ptr instruction
8842 // as well as the store instruction, instead passing the result as an rvalue.8955 // as well as the store instruction, instead passing the result as an rvalue.
8843 var as_scope = parent_gz.makeSubBlock(scope);8956 var as_scope = parent_gz.makeSubBlock(scope);
8844 errdefer as_scope.instructions.deinit(parent_gz.astgen.gpa);8957 errdefer as_scope.unstack();
8845 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);8958 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
88468959
8847 return as_scope;8960 return as_scope;
8848 }8961 }
88498962
8963 /// Assumes `as_scope` is stacked immediately on top of `parent_gz`. Unstacks `as_scope`.
8850 fn finishCoercion(8964 fn finishCoercion(
8851 as_scope: *GenZir,8965 as_scope: *GenZir,
8852 parent_gz: *GenZir,8966 parent_gz: *GenZir,
...@@ -8854,25 +8968,32 @@ const GenZir = struct {...@@ -8854,25 +8968,32 @@ const GenZir = struct {
8854 src_node: Ast.Node.Index,8968 src_node: Ast.Node.Index,
8855 result: Zir.Inst.Ref,8969 result: Zir.Inst.Ref,
8856 dest_type: Zir.Inst.Ref,8970 dest_type: Zir.Inst.Ref,
8857 ) !Zir.Inst.Ref {8971 ) InnerError!Zir.Inst.Ref {
8972 assert(as_scope.instructions == parent_gz.instructions);
8858 const astgen = as_scope.astgen;8973 const astgen = as_scope.astgen;
8859 const parent_zir = &parent_gz.instructions;
8860 if (as_scope.rvalue_rl_count == 1) {8974 if (as_scope.rvalue_rl_count == 1) {
8861 // Busted! This expression didn't actually need a pointer.8975 // Busted! This expression didn't actually need a pointer.
8862 const zir_tags = astgen.instructions.items(.tag);8976 const zir_tags = astgen.instructions.items(.tag);
8863 const zir_datas = astgen.instructions.items(.data);8977 const zir_datas = astgen.instructions.items(.data);
8864 try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);8978 var src: usize = as_scope.instructions_top;
8865 for (as_scope.instructions.items) |src_inst| {8979 var dst: usize = src;
8980 while (src < as_scope.instructions.items.len) : (src += 1) {
8981 const src_inst = as_scope.instructions.items[src];
8866 if (indexToRef(src_inst) == as_scope.rl_ptr) continue;8982 if (indexToRef(src_inst) == as_scope.rl_ptr) continue;
8867 if (zir_tags[src_inst] == .store_to_block_ptr) {8983 if (zir_tags[src_inst] == .store_to_block_ptr) {
8868 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;8984 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
8869 }8985 }
8870 parent_zir.appendAssumeCapacity(src_inst);8986 as_scope.instructions.items[dst] = src_inst;
8987 dst += 1;
8871 }8988 }
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
8872 const casted_result = try parent_gz.addBin(.as, dest_type, result);8992 const casted_result = try parent_gz.addBin(.as, dest_type, result);
8873 return rvalue(parent_gz, rl, casted_result, src_node);8993 return rvalue(parent_gz, rl, casted_result, src_node);
8874 } else {8994 } 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;
8876 return result;8997 return result;
8877 }8998 }
8878 }8999 }
...@@ -8883,9 +9004,10 @@ const GenZir = struct {...@@ -8883,9 +9004,10 @@ const GenZir = struct {
8883 used: bool = false,9004 used: bool = false,
8884 };9005 };
88859006
9007 /// Assumes nothing stacked on `gz`.
8886 fn endsWithNoReturn(gz: GenZir) bool {9008 fn endsWithNoReturn(gz: GenZir) bool {
9009 if (gz.isEmpty()) return false;
8887 const tags = gz.astgen.instructions.items(.tag);9010 const tags = gz.astgen.instructions.items(.tag);
8888 if (gz.instructions.items.len == 0) return false;
8889 const last_inst = gz.instructions.items[gz.instructions.items.len - 1];9011 const last_inst = gz.instructions.items[gz.instructions.items.len - 1];
8890 return tags[last_inst].isNoReturn();9012 return tags[last_inst].isNoReturn();
8891 }9013 }
...@@ -8955,41 +9077,46 @@ const GenZir = struct {...@@ -8955,41 +9077,46 @@ const GenZir = struct {
8955 }9077 }
8956 }9078 }
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 {
8959 const gpa = gz.astgen.gpa;9082 const gpa = gz.astgen.gpa;
8960 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +9083 const body = gz.instructionsSlice();
8961 gz.instructions.items.len);9084 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);
8962 const zir_datas = gz.astgen.instructions.items(.data);9085 const zir_datas = gz.astgen.instructions.items(.data);
8963 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(9086 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) },
8965 );9088 );
8966 gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);9089 gz.astgen.extra.appendSliceAssumeCapacity(body);
9090 gz.unstack();
8967 }9091 }
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 {
8970 const gpa = gz.astgen.gpa;9095 const gpa = gz.astgen.gpa;
8971 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +9096 const body = gz.instructionsSlice();
8972 gz.instructions.items.len);9097 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);
8973 const zir_datas = gz.astgen.instructions.items(.data);9098 const zir_datas = gz.astgen.instructions.items(.data);
8974 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(9099 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) },
8976 );9101 );
8977 gz.astgen.extra.appendSliceAssumeCapacity(gz.instructions.items);9102 gz.astgen.extra.appendSliceAssumeCapacity(body);
9103 gz.unstack();
8978 }9104 }
89799105
8980 /// Same as `setBlockBody` except we don't copy instructions which are9106 /// Same as `setBlockBody` except we don't copy instructions which are
8981 /// `store_to_block_ptr` instructions with lhs set to .none.9107 /// `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 {
8983 const gpa = gz.astgen.gpa;9110 const gpa = gz.astgen.gpa;
8984 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +9111 const body = gz.instructionsSlice();
8985 gz.instructions.items.len);9112 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len);
8986 const zir_datas = gz.astgen.instructions.items(.data);9113 const zir_datas = gz.astgen.instructions.items(.data);
8987 const zir_tags = gz.astgen.instructions.items(.tag);9114 const zir_tags = gz.astgen.instructions.items(.tag);
8988 const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{9115 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),
8990 });9117 });
8991 zir_datas[inst].pl_node.payload_index = block_pl_index;9118 zir_datas[inst].pl_node.payload_index = block_pl_index;
8992 for (gz.instructions.items) |sub_inst| {9119 for (body) |sub_inst| {
8993 if (zir_tags[sub_inst] == .store_to_block_ptr and9120 if (zir_tags[sub_inst] == .store_to_block_ptr and
8994 zir_datas[sub_inst].bin.lhs == .none)9121 zir_datas[sub_inst].bin.lhs == .none)
8995 {9122 {
...@@ -8999,15 +9126,17 @@ const GenZir = struct {...@@ -8999,15 +9126,17 @@ const GenZir = struct {
8999 }9126 }
9000 gz.astgen.extra.appendAssumeCapacity(sub_inst);9127 gz.astgen.extra.appendAssumeCapacity(sub_inst);
9001 }9128 }
9129 gz.unstack();
9002 }9130 }
90039131
9132 /// Supports `body_gz` stacked on `ret_gz` stacked on `gz`. Unstacks `body_gz` and `ret_gz`.
9004 fn addFunc(gz: *GenZir, args: struct {9133 fn addFunc(gz: *GenZir, args: struct {
9005 src_node: Ast.Node.Index,9134 src_node: Ast.Node.Index,
9006 lbrace_line: u32 = 0,9135 lbrace_line: u32 = 0,
9007 lbrace_column: u32 = 0,9136 lbrace_column: u32 = 0,
9008 body: []const Zir.Inst.Index,9137 body_gz: ?*GenZir,
9009 param_block: Zir.Inst.Index,9138 param_block: Zir.Inst.Index,
9010 ret_ty: []const Zir.Inst.Index,9139 ret_gz: ?*GenZir,
9011 ret_br: Zir.Inst.Index,9140 ret_br: Zir.Inst.Index,
9012 cc: Zir.Inst.Ref,9141 cc: Zir.Inst.Ref,
9013 align_inst: Zir.Inst.Ref,9142 align_inst: Zir.Inst.Ref,
...@@ -9021,12 +9150,13 @@ const GenZir = struct {...@@ -9021,12 +9150,13 @@ const GenZir = struct {
9021 const astgen = gz.astgen;9150 const astgen = gz.astgen;
9022 const gpa = astgen.gpa;9151 const gpa = astgen.gpa;
90239152
9024 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9025 try astgen.instructions.ensureUnusedCapacity(gpa, 1);9153 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{};
9027 var src_locs_buffer: [3]u32 = undefined;9157 var src_locs_buffer: [3]u32 = undefined;
9028 var src_locs: []u32 = src_locs_buffer[0..0];9158 var src_locs: []u32 = src_locs_buffer[0..0];
9029 if (args.body.len != 0) {9159 if (args.body_gz) |body_gz| {
9030 const tree = astgen.tree;9160 const tree = astgen.tree;
9031 const node_tags = tree.nodes.items(.tag);9161 const node_tags = tree.nodes.items(.tag);
9032 const node_datas = tree.nodes.items(.data);9162 const node_datas = tree.nodes.items(.data);
...@@ -9044,6 +9174,13 @@ const GenZir = struct {...@@ -9044,6 +9174,13 @@ const GenZir = struct {
9044 src_locs_buffer[1] = rbrace_line;9174 src_locs_buffer[1] = rbrace_line;
9045 src_locs_buffer[2] = columns;9175 src_locs_buffer[2] = columns;
9046 src_locs = &src_locs_buffer;9176 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();
9047 }9184 }
90489185
9049 if (args.cc != .none or args.lib_name != 0 or9186 if (args.cc != .none or args.lib_name != 0 or
...@@ -9053,7 +9190,7 @@ const GenZir = struct {...@@ -9053,7 +9190,7 @@ const GenZir = struct {
9053 try astgen.extra.ensureUnusedCapacity(9190 try astgen.extra.ensureUnusedCapacity(
9054 gpa,9191 gpa,
9055 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +9192 @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 +
9057 @boolToInt(args.lib_name != 0) +9194 @boolToInt(args.lib_name != 0) +
9058 @boolToInt(args.align_inst != .none) +9195 @boolToInt(args.align_inst != .none) +
9059 @boolToInt(args.cc != .none),9196 @boolToInt(args.cc != .none),
...@@ -9061,8 +9198,8 @@ const GenZir = struct {...@@ -9061,8 +9198,8 @@ const GenZir = struct {
9061 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{9198 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
9062 .src_node = gz.nodeIndexToRelative(args.src_node),9199 .src_node = gz.nodeIndexToRelative(args.src_node),
9063 .param_block = args.param_block,9200 .param_block = args.param_block,
9064 .ret_body_len = @intCast(u32, args.ret_ty.len),9201 .ret_body_len = @intCast(u32, ret_ty.len),
9065 .body_len = @intCast(u32, args.body.len),9202 .body_len = @intCast(u32, body.len),
9066 });9203 });
9067 if (args.lib_name != 0) {9204 if (args.lib_name != 0) {
9068 astgen.extra.appendAssumeCapacity(args.lib_name);9205 astgen.extra.appendAssumeCapacity(args.lib_name);
...@@ -9073,9 +9210,13 @@ const GenZir = struct {...@@ -9073,9 +9210,13 @@ const GenZir = struct {
9073 if (args.align_inst != .none) {9210 if (args.align_inst != .none) {
9074 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));9211 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
9075 }9212 }
9076 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);9213 astgen.extra.appendSliceAssumeCapacity(ret_ty);
9077 astgen.extra.appendSliceAssumeCapacity(args.body);9214 astgen.extra.appendSliceAssumeCapacity(body);
9078 astgen.extra.appendSliceAssumeCapacity(src_locs);9215 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
9080 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);9221 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
9081 if (args.ret_br != 0) {9222 if (args.ret_br != 0) {
...@@ -9103,17 +9244,21 @@ const GenZir = struct {...@@ -9103,17 +9244,21 @@ const GenZir = struct {
9103 try astgen.extra.ensureUnusedCapacity(9244 try astgen.extra.ensureUnusedCapacity(
9104 gpa,9245 gpa,
9105 @typeInfo(Zir.Inst.Func).Struct.fields.len +9246 @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,
9107 );9248 );
91089249
9109 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{9250 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
9110 .param_block = args.param_block,9251 .param_block = args.param_block,
9111 .ret_body_len = @intCast(u32, args.ret_ty.len),9252 .ret_body_len = @intCast(u32, ret_ty.len),
9112 .body_len = @intCast(u32, args.body.len),9253 .body_len = @intCast(u32, body.len),
9113 });9254 });
9114 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);9255 astgen.extra.appendSliceAssumeCapacity(ret_ty);
9115 astgen.extra.appendSliceAssumeCapacity(args.body);9256 astgen.extra.appendSliceAssumeCapacity(body);
9116 astgen.extra.appendSliceAssumeCapacity(src_locs);9257 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
9118 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;9263 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
9119 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);9264 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
...@@ -9260,6 +9405,25 @@ const GenZir = struct {...@@ -9260,6 +9405,25 @@ const GenZir = struct {
9260 });9405 });
9261 }9406 }
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
9263 fn addPlNode(9427 fn addPlNode(
9264 gz: *GenZir,9428 gz: *GenZir,
9265 tag: Zir.Inst.Tag,9429 tag: Zir.Inst.Tag,
...@@ -9300,25 +9464,27 @@ const GenZir = struct {...@@ -9300,25 +9464,27 @@ const GenZir = struct {
9300 });9464 });
9301 }9465 }
93029466
9467 /// Supports `param_gz` stacked on `gz`. Assumes nothing stacked on `param_gz`. Unstacks `param_gz`.
9303 fn addParam(9468 fn addParam(
9304 gz: *GenZir,9469 gz: *GenZir,
9470 param_gz: *GenZir,
9305 tag: Zir.Inst.Tag,9471 tag: Zir.Inst.Tag,
9306 /// Absolute token index. This function does the conversion to Decl offset.9472 /// Absolute token index. This function does the conversion to Decl offset.
9307 abs_tok_index: Ast.TokenIndex,9473 abs_tok_index: Ast.TokenIndex,
9308 name: u32,9474 name: u32,
9309 body: []const u32,
9310 ) !Zir.Inst.Index {9475 ) !Zir.Inst.Index {
9311 const gpa = gz.astgen.gpa;9476 const gpa = gz.astgen.gpa;
9312 try gz.instructions.ensureUnusedCapacity(gpa, 1);9477 const param_body = param_gz.instructionsSlice();
9313 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);9478 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
9314 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len +9479 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len +
9315 body.len);9480 param_body.len);
93169481
9317 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{9482 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{
9318 .name = name,9483 .name = name,
9319 .body_len = @intCast(u32, body.len),9484 .body_len = @intCast(u32, param_body.len),
9320 });9485 });
9321 gz.astgen.extra.appendSliceAssumeCapacity(body);9486 gz.astgen.extra.appendSliceAssumeCapacity(param_body);
9487 param_gz.unstack();
93229488
9323 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9489 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9324 gz.astgen.instructions.appendAssumeCapacity(.{9490 gz.astgen.instructions.appendAssumeCapacity(.{
...@@ -9461,6 +9627,23 @@ const GenZir = struct {...@@ -9461,6 +9627,23 @@ const GenZir = struct {
9461 });9627 });
9462 }9628 }
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
9464 fn addBin(9647 fn addBin(
9465 gz: *GenZir,9648 gz: *GenZir,
9466 tag: Zir.Inst.Tag,9649 tag: Zir.Inst.Tag,
...@@ -9649,7 +9832,7 @@ const GenZir = struct {...@@ -9649,7 +9832,7 @@ const GenZir = struct {
9649 /// Note that this returns a `Zir.Inst.Index` not a ref.9832 /// Note that this returns a `Zir.Inst.Index` not a ref.
9650 /// Does *not* append the block instruction to the scope.9833 /// Does *not* append the block instruction to the scope.
9651 /// Leaves the `payload_index` field undefined.9834 /// 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 {
9653 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9836 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9654 const gpa = gz.astgen.gpa;9837 const gpa = gz.astgen.gpa;
9655 try gz.astgen.instructions.append(gpa, .{9838 try gz.astgen.instructions.append(gpa, .{