| ... | ... | @@ -117,6 +117,7 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir { |
| 117 | 117 | |
| 118 | 118 | var top_scope: Scope.Top = .{}; |
| 119 | 119 | |
| 120 | var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{}; |
| 120 | 121 | var gen_scope: GenZir = .{ |
| 121 | 122 | .force_comptime = true, |
| 122 | 123 | .in_defer = false, |
| ... | ... | @@ -125,8 +126,10 @@ pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir { |
| 125 | 126 | .decl_node_index = 0, |
| 126 | 127 | .decl_line = 0, |
| 127 | 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); |
| 130 | 133 | |
| 131 | 134 | const container_decl: Ast.full.ContainerDecl = .{ |
| 132 | 135 | .layout_token = null, |
| ... | ... | @@ -1041,12 +1044,12 @@ fn suspendExpr( |
| 1041 | 1044 | } |
| 1042 | 1045 | assert(body_node != 0); |
| 1043 | 1046 | |
| 1044 | | const suspend_inst = try gz.addBlock(.suspend_block, node); |
| 1047 | const suspend_inst = try gz.makeBlockInst(.suspend_block, node); |
| 1045 | 1048 | try gz.instructions.append(gpa, suspend_inst); |
| 1046 | 1049 | |
| 1047 | 1050 | var suspend_scope = gz.makeSubBlock(scope); |
| 1048 | 1051 | suspend_scope.suspend_node = node; |
| 1049 | | defer suspend_scope.instructions.deinit(gpa); |
| 1052 | defer suspend_scope.unstack(); |
| 1050 | 1053 | |
| 1051 | 1054 | const body_result = try expr(&suspend_scope, &suspend_scope.base, .none, body_node); |
| 1052 | 1055 | if (!gz.refIsNoReturn(body_result)) { |
| ... | ... | @@ -1101,7 +1104,6 @@ fn fnProtoExpr( |
| 1101 | 1104 | fn_proto: Ast.full.FnProto, |
| 1102 | 1105 | ) InnerError!Zir.Inst.Ref { |
| 1103 | 1106 | const astgen = gz.astgen; |
| 1104 | | const gpa = astgen.gpa; |
| 1105 | 1107 | const tree = astgen.tree; |
| 1106 | 1108 | const token_tags = tree.tokens.items(.tag); |
| 1107 | 1109 | |
| ... | ... | @@ -1147,14 +1149,14 @@ fn fnProtoExpr( |
| 1147 | 1149 | const param_type_node = param.type_expr; |
| 1148 | 1150 | assert(param_type_node != 0); |
| 1149 | 1151 | var param_gz = gz.makeSubBlock(scope); |
| 1150 | | defer param_gz.instructions.deinit(gpa); |
| 1152 | defer param_gz.unstack(); |
| 1151 | 1153 | const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node); |
| 1152 | 1154 | const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); |
| 1153 | 1155 | _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); |
| 1154 | 1156 | const main_tokens = tree.nodes.items(.main_token); |
| 1155 | 1157 | const name_token = param.name_token orelse main_tokens[param_type_node]; |
| 1156 | 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 | 1160 | assert(param_inst_expected == param_inst); |
| 1159 | 1161 | } |
| 1160 | 1162 | } |
| ... | ... | @@ -1189,16 +1191,16 @@ fn fnProtoExpr( |
| 1189 | 1191 | return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); |
| 1190 | 1192 | } |
| 1191 | 1193 | var ret_gz = gz.makeSubBlock(scope); |
| 1192 | | defer ret_gz.instructions.deinit(gpa); |
| 1194 | defer ret_gz.unstack(); |
| 1193 | 1195 | const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type); |
| 1194 | 1196 | const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty); |
| 1195 | 1197 | |
| 1196 | 1198 | const result = try gz.addFunc(.{ |
| 1197 | 1199 | .src_node = fn_proto.ast.proto_node, |
| 1198 | 1200 | .param_block = 0, |
| 1199 | | .ret_ty = ret_gz.instructions.items, |
| 1201 | .ret_gz = &ret_gz, |
| 1200 | 1202 | .ret_br = ret_br, |
| 1201 | | .body = &[0]Zir.Inst.Index{}, |
| 1203 | .body_gz = null, |
| 1202 | 1204 | .cc = cc, |
| 1203 | 1205 | .align_inst = align_inst, |
| 1204 | 1206 | .lib_name = 0, |
| ... | ... | @@ -1376,7 +1378,7 @@ fn arrayInitExprRlPtr( |
| 1376 | 1378 | } |
| 1377 | 1379 | |
| 1378 | 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(); |
| 1380 | 1382 | |
| 1381 | 1383 | const result = try arrayInitExprRlPtrInner(&as_scope, scope, node, as_scope.rl_ptr, elements); |
| 1382 | 1384 | return as_scope.finishCoercion(gz, rl, node, result, array_ty); |
| ... | ... | @@ -1554,7 +1556,7 @@ fn structInitExprRlPtr( |
| 1554 | 1556 | const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1555 | 1557 | |
| 1556 | 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(); |
| 1558 | 1560 | |
| 1559 | 1561 | const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr); |
| 1560 | 1562 | return as_scope.finishCoercion(gz, rl, node, result, ty_inst); |
| ... | ... | @@ -1875,7 +1877,7 @@ fn labeledBlockExpr( |
| 1875 | 1877 | |
| 1876 | 1878 | // Reserve the Block ZIR instruction index so that we can put it into the GenZir struct |
| 1877 | 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 | 1881 | try gz.instructions.append(astgen.gpa, block_inst); |
| 1880 | 1882 | |
| 1881 | 1883 | var block_scope = gz.makeSubBlock(parent_scope); |
| ... | ... | @@ -1884,7 +1886,7 @@ fn labeledBlockExpr( |
| 1884 | 1886 | .block_inst = block_inst, |
| 1885 | 1887 | }; |
| 1886 | 1888 | block_scope.setBreakResultLoc(rl); |
| 1887 | | defer block_scope.instructions.deinit(astgen.gpa); |
| 1889 | defer block_scope.unstack(); |
| 1888 | 1890 | defer block_scope.labeled_breaks.deinit(astgen.gpa); |
| 1889 | 1891 | defer block_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); |
| 1890 | 1892 | |
| ... | ... | @@ -2489,7 +2491,6 @@ fn varDecl( |
| 2489 | 2491 | ) InnerError!*Scope { |
| 2490 | 2492 | try emitDbgNode(gz, node); |
| 2491 | 2493 | const astgen = gz.astgen; |
| 2492 | | const gpa = astgen.gpa; |
| 2493 | 2494 | const tree = astgen.tree; |
| 2494 | 2495 | const token_tags = tree.tokens.items(.tag); |
| 2495 | 2496 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -2550,7 +2551,9 @@ fn varDecl( |
| 2550 | 2551 | // Detect whether the initialization expression actually uses the |
| 2551 | 2552 | // result location pointer. |
| 2552 | 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(); |
| 2554 | 2557 | |
| 2555 | 2558 | var resolve_inferred_alloc: Zir.Inst.Ref = .none; |
| 2556 | 2559 | var opt_type_inst: Zir.Inst.Ref = .none; |
| ... | ... | @@ -2558,6 +2561,7 @@ fn varDecl( |
| 2558 | 2561 | const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node); |
| 2559 | 2562 | opt_type_inst = type_inst; |
| 2560 | 2563 | if (align_inst == .none) { |
| 2564 | init_scope.instructions_top = gz.instructions.items.len; |
| 2561 | 2565 | init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node); |
| 2562 | 2566 | } else { |
| 2563 | 2567 | init_scope.rl_ptr = try gz.addAllocExtended(.{ |
| ... | ... | @@ -2567,19 +2571,24 @@ fn varDecl( |
| 2567 | 2571 | .is_const = true, |
| 2568 | 2572 | .is_comptime = false, |
| 2569 | 2573 | }); |
| 2574 | init_scope.instructions_top = gz.instructions.items.len; |
| 2570 | 2575 | } |
| 2571 | 2576 | init_scope.rl_ty_inst = type_inst; |
| 2572 | 2577 | } else { |
| 2573 | | const alloc = if (align_inst == .none) |
| 2574 | | try init_scope.addNode(.alloc_inferred, node) |
| 2575 | | else |
| 2576 | | try gz.addAllocExtended(.{ |
| 2578 | const alloc = if (align_inst == .none) alloc: { |
| 2579 | init_scope.instructions_top = gz.instructions.items.len; |
| 2580 | break :alloc try init_scope.addNode(.alloc_inferred, node); |
| 2581 | } else alloc: { |
| 2582 | const ref = try gz.addAllocExtended(.{ |
| 2577 | 2583 | .node = node, |
| 2578 | 2584 | .type_inst = .none, |
| 2579 | 2585 | .align_inst = align_inst, |
| 2580 | 2586 | .is_const = true, |
| 2581 | 2587 | .is_comptime = false, |
| 2582 | 2588 | }); |
| 2589 | init_scope.instructions_top = gz.instructions.items.len; |
| 2590 | break :alloc ref; |
| 2591 | }; |
| 2583 | 2592 | resolve_inferred_alloc = alloc; |
| 2584 | 2593 | init_scope.rl_ptr = alloc; |
| 2585 | 2594 | } |
| ... | ... | @@ -2589,20 +2598,24 @@ fn varDecl( |
| 2589 | 2598 | const zir_tags = astgen.instructions.items(.tag); |
| 2590 | 2599 | const zir_datas = astgen.instructions.items(.data); |
| 2591 | 2600 | |
| 2592 | | const parent_zir = &gz.instructions; |
| 2593 | 2601 | if (align_inst == .none and init_scope.rvalue_rl_count == 1) { |
| 2594 | 2602 | // Result location pointer not used. We don't need an alloc for this |
| 2595 | 2603 | // const local, and type inference becomes trivial. |
| 2596 | | // Move the init_scope instructions into the parent scope, eliding |
| 2597 | | // the alloc instruction and the store_to_block_ptr instruction. |
| 2598 | | try parent_zir.ensureUnusedCapacity(gpa, init_scope.instructions.items.len); |
| 2599 | | for (init_scope.instructions.items) |src_inst| { |
| 2604 | // Implicitly move the init_scope instructions into the parent scope, |
| 2605 | // then elide the alloc instruction and the store_to_block_ptr instruction. |
| 2606 | var src = init_scope.instructions_top; |
| 2607 | var dst = src; |
| 2608 | init_scope.instructions_top = GenZir.unstacked_top; |
| 2609 | while (src < gz.instructions.items.len) : (src += 1) { |
| 2610 | const src_inst = gz.instructions.items[src]; |
| 2600 | 2611 | if (indexToRef(src_inst) == init_scope.rl_ptr) continue; |
| 2601 | 2612 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 2602 | 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; |
| 2606 | 2619 | |
| 2607 | 2620 | const sub_scope = try block_arena.create(Scope.LocalVal); |
| 2608 | 2621 | sub_scope.* = .{ |
| ... | ... | @@ -2617,11 +2630,13 @@ fn varDecl( |
| 2617 | 2630 | } |
| 2618 | 2631 | // The initialization expression took advantage of the result location |
| 2619 | 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, swapping |
| 2633 | // Implicitly move the init_scope instructions into the parent scope, then swap |
| 2621 | 2634 | // store_to_block_ptr for store_to_inferred_ptr. |
| 2622 | | const expected_len = parent_zir.items.len + init_scope.instructions.items.len; |
| 2623 | | try parent_zir.ensureTotalCapacity(gpa, expected_len); |
| 2624 | | for (init_scope.instructions.items) |src_inst| { |
| 2635 | |
| 2636 | var src = init_scope.instructions_top; |
| 2637 | init_scope.instructions_top = GenZir.unstacked_top; |
| 2638 | while (src < gz.instructions.items.len) : (src += 1) { |
| 2639 | const src_inst = gz.instructions.items[src]; |
| 2625 | 2640 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 2626 | 2641 | if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) { |
| 2627 | 2642 | if (var_decl.ast.type_node != 0) { |
| ... | ... | @@ -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 | 2650 | if (resolve_inferred_alloc != .none) { |
| 2638 | 2651 | _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node); |
| 2639 | 2652 | } |
| ... | ... | @@ -3120,7 +3133,6 @@ fn fnDecl( |
| 3120 | 3133 | body_node: Ast.Node.Index, |
| 3121 | 3134 | fn_proto: Ast.full.FnProto, |
| 3122 | 3135 | ) InnerError!void { |
| 3123 | | const gpa = astgen.gpa; |
| 3124 | 3136 | const tree = astgen.tree; |
| 3125 | 3137 | const token_tags = tree.tokens.items(.tag); |
| 3126 | 3138 | |
| ... | ... | @@ -3130,7 +3142,7 @@ fn fnDecl( |
| 3130 | 3142 | |
| 3131 | 3143 | // We insert this at the beginning so that its instruction index marks the |
| 3132 | 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); |
| 3134 | 3146 | |
| 3135 | 3147 | var decl_gz: GenZir = .{ |
| 3136 | 3148 | .force_comptime = true, |
| ... | ... | @@ -3139,8 +3151,10 @@ fn fnDecl( |
| 3139 | 3151 | .decl_line = gz.calcLine(decl_node), |
| 3140 | 3152 | .parent = scope, |
| 3141 | 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(); |
| 3144 | 3158 | |
| 3145 | 3159 | var fn_gz: GenZir = .{ |
| 3146 | 3160 | .force_comptime = false, |
| ... | ... | @@ -3149,8 +3163,10 @@ fn fnDecl( |
| 3149 | 3163 | .decl_line = decl_gz.decl_line, |
| 3150 | 3164 | .parent = &decl_gz.base, |
| 3151 | 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(); |
| 3154 | 3170 | |
| 3155 | 3171 | // TODO: support noinline |
| 3156 | 3172 | const is_pub = fn_proto.visib_token != null; |
| ... | ... | @@ -3216,7 +3232,7 @@ fn fnDecl( |
| 3216 | 3232 | const param_type_node = param.type_expr; |
| 3217 | 3233 | assert(param_type_node != 0); |
| 3218 | 3234 | var param_gz = decl_gz.makeSubBlock(scope); |
| 3219 | | defer param_gz.instructions.deinit(gpa); |
| 3235 | defer param_gz.unstack(); |
| 3220 | 3236 | const param_type = try expr(&param_gz, params_scope, coerced_type_rl, param_type_node); |
| 3221 | 3237 | const param_inst_expected = @intCast(u32, astgen.instructions.len + 1); |
| 3222 | 3238 | _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type); |
| ... | ... | @@ -3224,7 +3240,7 @@ fn fnDecl( |
| 3224 | 3240 | const main_tokens = tree.nodes.items(.main_token); |
| 3225 | 3241 | const name_token = param.name_token orelse main_tokens[param_type_node]; |
| 3226 | 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 | 3244 | assert(param_inst_expected == param_inst); |
| 3229 | 3245 | break :param indexToRef(param_inst); |
| 3230 | 3246 | }; |
| ... | ... | @@ -3289,7 +3305,7 @@ fn fnDecl( |
| 3289 | 3305 | }; |
| 3290 | 3306 | |
| 3291 | 3307 | var ret_gz = decl_gz.makeSubBlock(params_scope); |
| 3292 | | defer ret_gz.instructions.deinit(gpa); |
| 3308 | defer ret_gz.unstack(); |
| 3293 | 3309 | const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type); |
| 3294 | 3310 | const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty); |
| 3295 | 3311 | |
| ... | ... | @@ -3302,10 +3318,10 @@ fn fnDecl( |
| 3302 | 3318 | } |
| 3303 | 3319 | break :func try decl_gz.addFunc(.{ |
| 3304 | 3320 | .src_node = decl_node, |
| 3305 | | .ret_ty = ret_gz.instructions.items, |
| 3321 | .ret_gz = &ret_gz, |
| 3306 | 3322 | .ret_br = ret_br, |
| 3307 | 3323 | .param_block = block_inst, |
| 3308 | | .body = &[0]Zir.Inst.Index{}, |
| 3324 | .body_gz = null, |
| 3309 | 3325 | .cc = cc, |
| 3310 | 3326 | .align_inst = .none, // passed in the per-decl data |
| 3311 | 3327 | .lib_name = lib_name, |
| ... | ... | @@ -3319,6 +3335,9 @@ fn fnDecl( |
| 3319 | 3335 | return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{}); |
| 3320 | 3336 | } |
| 3321 | 3337 | |
| 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 | 3341 | const prev_fn_block = astgen.fn_block; |
| 3323 | 3342 | astgen.fn_block = &fn_gz; |
| 3324 | 3343 | defer astgen.fn_block = prev_fn_block; |
| ... | ... | @@ -3332,14 +3351,7 @@ fn fnDecl( |
| 3332 | 3351 | _ = try expr(&fn_gz, params_scope, .none, body_node); |
| 3333 | 3352 | try checkUsed(gz, &fn_gz.base, params_scope); |
| 3334 | 3353 | |
| 3335 | | const need_implicit_ret = blk: { |
| 3336 | | if (fn_gz.instructions.items.len == 0) |
| 3337 | | break :blk true; |
| 3338 | | const last = fn_gz.instructions.items[fn_gz.instructions.items.len - 1]; |
| 3339 | | const zir_tags = astgen.instructions.items(.tag); |
| 3340 | | break :blk !zir_tags[last].isNoReturn(); |
| 3341 | | }; |
| 3342 | | if (need_implicit_ret) { |
| 3354 | if (!fn_gz.endsWithNoReturn()) { |
| 3343 | 3355 | // Since we are adding the return instruction here, we must handle the coercion. |
| 3344 | 3356 | // We do this by using the `ret_coerce` instruction. |
| 3345 | 3357 | _ = try fn_gz.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node)); |
| ... | ... | @@ -3350,9 +3362,9 @@ fn fnDecl( |
| 3350 | 3362 | .lbrace_line = lbrace_line, |
| 3351 | 3363 | .lbrace_column = lbrace_column, |
| 3352 | 3364 | .param_block = block_inst, |
| 3353 | | .ret_ty = ret_gz.instructions.items, |
| 3365 | .ret_gz = &ret_gz, |
| 3354 | 3366 | .ret_br = ret_br, |
| 3355 | | .body = fn_gz.instructions.items, |
| 3367 | .body_gz = &fn_gz, |
| 3356 | 3368 | .cc = cc, |
| 3357 | 3369 | .align_inst = .none, // passed in the per-decl data |
| 3358 | 3370 | .lib_name = lib_name, |
| ... | ... | @@ -3364,7 +3376,7 @@ fn fnDecl( |
| 3364 | 3376 | }; |
| 3365 | 3377 | |
| 3366 | 3378 | // 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 | 3380 | _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst); |
| 3369 | 3381 | try decl_gz.setBlockBody(block_inst); |
| 3370 | 3382 | |
| ... | ... | @@ -3396,14 +3408,13 @@ fn globalVarDecl( |
| 3396 | 3408 | node: Ast.Node.Index, |
| 3397 | 3409 | var_decl: Ast.full.VarDecl, |
| 3398 | 3410 | ) InnerError!void { |
| 3399 | | const gpa = astgen.gpa; |
| 3400 | 3411 | const tree = astgen.tree; |
| 3401 | 3412 | const token_tags = tree.tokens.items(.tag); |
| 3402 | 3413 | |
| 3403 | 3414 | const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var; |
| 3404 | 3415 | // We do this at the beginning so that the instruction index marks the range start |
| 3405 | 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); |
| 3407 | 3418 | |
| 3408 | 3419 | const name_token = var_decl.ast.mut_token + 1; |
| 3409 | 3420 | const name_str_index = try astgen.identAsString(name_token); |
| ... | ... | @@ -3416,8 +3427,10 @@ fn globalVarDecl( |
| 3416 | 3427 | .force_comptime = true, |
| 3417 | 3428 | .in_defer = false, |
| 3418 | 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(); |
| 3421 | 3434 | |
| 3422 | 3435 | const is_pub = var_decl.visib_token != null; |
| 3423 | 3436 | const is_export = blk: { |
| ... | ... | @@ -3543,14 +3556,13 @@ fn comptimeDecl( |
| 3543 | 3556 | wip_members: *WipMembers, |
| 3544 | 3557 | node: Ast.Node.Index, |
| 3545 | 3558 | ) InnerError!void { |
| 3546 | | const gpa = astgen.gpa; |
| 3547 | 3559 | const tree = astgen.tree; |
| 3548 | 3560 | const node_datas = tree.nodes.items(.data); |
| 3549 | 3561 | const body_node = node_datas[node].lhs; |
| 3550 | 3562 | |
| 3551 | 3563 | // Up top so the ZIR instruction index marks the start range of this |
| 3552 | 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 | 3566 | wip_members.nextDecl(false, false, false, false); |
| 3555 | 3567 | |
| 3556 | 3568 | var decl_block: GenZir = .{ |
| ... | ... | @@ -3560,11 +3572,13 @@ fn comptimeDecl( |
| 3560 | 3572 | .decl_line = gz.calcLine(node), |
| 3561 | 3573 | .parent = scope, |
| 3562 | 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(); |
| 3565 | 3579 | |
| 3566 | 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 | 3582 | _ = try decl_block.addBreak(.break_inline, block_inst, .void_value); |
| 3569 | 3583 | } |
| 3570 | 3584 | try decl_block.setBlockBody(block_inst); |
| ... | ... | @@ -3589,7 +3603,6 @@ fn usingnamespaceDecl( |
| 3589 | 3603 | wip_members: *WipMembers, |
| 3590 | 3604 | node: Ast.Node.Index, |
| 3591 | 3605 | ) InnerError!void { |
| 3592 | | const gpa = astgen.gpa; |
| 3593 | 3606 | const tree = astgen.tree; |
| 3594 | 3607 | const node_datas = tree.nodes.items(.data); |
| 3595 | 3608 | |
| ... | ... | @@ -3602,7 +3615,7 @@ fn usingnamespaceDecl( |
| 3602 | 3615 | }; |
| 3603 | 3616 | // Up top so the ZIR instruction index marks the start range of this |
| 3604 | 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 | 3619 | wip_members.nextDecl(is_pub, true, false, false); |
| 3607 | 3620 | |
| 3608 | 3621 | var decl_block: GenZir = .{ |
| ... | ... | @@ -3612,8 +3625,10 @@ fn usingnamespaceDecl( |
| 3612 | 3625 | .decl_line = gz.calcLine(node), |
| 3613 | 3626 | .parent = scope, |
| 3614 | 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(); |
| 3617 | 3632 | |
| 3618 | 3633 | const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr); |
| 3619 | 3634 | _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst); |
| ... | ... | @@ -3639,14 +3654,13 @@ fn testDecl( |
| 3639 | 3654 | wip_members: *WipMembers, |
| 3640 | 3655 | node: Ast.Node.Index, |
| 3641 | 3656 | ) InnerError!void { |
| 3642 | | const gpa = astgen.gpa; |
| 3643 | 3657 | const tree = astgen.tree; |
| 3644 | 3658 | const node_datas = tree.nodes.items(.data); |
| 3645 | 3659 | const body_node = node_datas[node].rhs; |
| 3646 | 3660 | |
| 3647 | 3661 | // Up top so the ZIR instruction index marks the start range of this |
| 3648 | 3662 | // top-level declaration. |
| 3649 | | const block_inst = try gz.addBlock(.block_inline, node); |
| 3663 | const block_inst = try gz.makeBlockInst(.block_inline, node); |
| 3650 | 3664 | |
| 3651 | 3665 | wip_members.nextDecl(false, false, false, false); |
| 3652 | 3666 | |
| ... | ... | @@ -3657,8 +3671,10 @@ fn testDecl( |
| 3657 | 3671 | .decl_line = gz.calcLine(node), |
| 3658 | 3672 | .parent = scope, |
| 3659 | 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(); |
| 3662 | 3678 | |
| 3663 | 3679 | const test_name: u32 = blk: { |
| 3664 | 3680 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -3679,8 +3695,10 @@ fn testDecl( |
| 3679 | 3695 | .decl_line = decl_block.decl_line, |
| 3680 | 3696 | .parent = &decl_block.base, |
| 3681 | 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(); |
| 3684 | 3702 | |
| 3685 | 3703 | const prev_fn_block = astgen.fn_block; |
| 3686 | 3704 | astgen.fn_block = &fn_block; |
| ... | ... | @@ -3693,7 +3711,7 @@ fn testDecl( |
| 3693 | 3711 | const lbrace_column = @intCast(u32, astgen.source_column); |
| 3694 | 3712 | |
| 3695 | 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 | 3715 | // Since we are adding the return instruction here, we must handle the coercion. |
| 3698 | 3716 | // We do this by using the `ret_coerce` instruction. |
| 3699 | 3717 | _ = try fn_block.addUnTok(.ret_coerce, .void_value, tree.lastToken(body_node)); |
| ... | ... | @@ -3704,9 +3722,9 @@ fn testDecl( |
| 3704 | 3722 | .lbrace_line = lbrace_line, |
| 3705 | 3723 | .lbrace_column = lbrace_column, |
| 3706 | 3724 | .param_block = block_inst, |
| 3707 | | .ret_ty = &.{}, |
| 3725 | .ret_gz = null, |
| 3708 | 3726 | .ret_br = 0, |
| 3709 | | .body = fn_block.instructions.items, |
| 3727 | .body_gz = &fn_block, |
| 3710 | 3728 | .cc = .none, |
| 3711 | 3729 | .align_inst = .none, |
| 3712 | 3730 | .lib_name = 0, |
| ... | ... | @@ -3776,8 +3794,10 @@ fn structDeclInner( |
| 3776 | 3794 | .astgen = astgen, |
| 3777 | 3795 | .force_comptime = true, |
| 3778 | 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(); |
| 3781 | 3801 | |
| 3782 | 3802 | const decl_count = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 3783 | 3803 | const field_count = @intCast(u32, container_decl.ast.members.len - decl_count); |
| ... | ... | @@ -3829,14 +3849,16 @@ fn structDeclInner( |
| 3829 | 3849 | } |
| 3830 | 3850 | } |
| 3831 | 3851 | |
| 3832 | | if (block_scope.instructions.items.len != 0) { |
| 3852 | if (!block_scope.isEmpty()) { |
| 3833 | 3853 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 3834 | 3854 | } |
| 3835 | 3855 | |
| 3856 | const body = block_scope.instructionsSlice(); |
| 3857 | |
| 3836 | 3858 | try gz.setStruct(decl_inst, .{ |
| 3837 | 3859 | .src_node = node, |
| 3838 | 3860 | .layout = layout, |
| 3839 | | .body_len = @intCast(u32, block_scope.instructions.items.len), |
| 3861 | .body_len = @intCast(u32, body.len), |
| 3840 | 3862 | .fields_len = field_count, |
| 3841 | 3863 | .decls_len = decl_count, |
| 3842 | 3864 | .known_has_bits = known_has_bits, |
| ... | ... | @@ -3845,11 +3867,12 @@ fn structDeclInner( |
| 3845 | 3867 | wip_members.finishBits(bits_per_field); |
| 3846 | 3868 | const decls_slice = wip_members.declsSlice(); |
| 3847 | 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 | 3871 | astgen.extra.appendSliceAssumeCapacity(decls_slice); |
| 3850 | | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); |
| 3872 | astgen.extra.appendSliceAssumeCapacity(body); |
| 3851 | 3873 | astgen.extra.appendSliceAssumeCapacity(fields_slice); |
| 3852 | 3874 | |
| 3875 | block_scope.unstack(); |
| 3853 | 3876 | try gz.addNamespaceCaptures(&namespace); |
| 3854 | 3877 | return indexToRef(decl_inst); |
| 3855 | 3878 | } |
| ... | ... | @@ -3888,8 +3911,10 @@ fn unionDeclInner( |
| 3888 | 3911 | .astgen = astgen, |
| 3889 | 3912 | .force_comptime = true, |
| 3890 | 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(); |
| 3893 | 3918 | |
| 3894 | 3919 | const decl_count = try astgen.scanDecls(&namespace, members); |
| 3895 | 3920 | const field_count = @intCast(u32, members.len - decl_count); |
| ... | ... | @@ -3972,15 +3997,17 @@ fn unionDeclInner( |
| 3972 | 3997 | return astgen.failNode(node, "union declarations must have at least one tag", .{}); |
| 3973 | 3998 | } |
| 3974 | 3999 | |
| 3975 | | if (block_scope.instructions.items.len != 0) { |
| 4000 | if (!block_scope.isEmpty()) { |
| 3976 | 4001 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 3977 | 4002 | } |
| 3978 | 4003 | |
| 4004 | const body = block_scope.instructionsSlice(); |
| 4005 | |
| 3979 | 4006 | try gz.setUnion(decl_inst, .{ |
| 3980 | 4007 | .src_node = node, |
| 3981 | 4008 | .layout = layout, |
| 3982 | 4009 | .tag_type = arg_inst, |
| 3983 | | .body_len = @intCast(u32, block_scope.instructions.items.len), |
| 4010 | .body_len = @intCast(u32, body.len), |
| 3984 | 4011 | .fields_len = field_count, |
| 3985 | 4012 | .decls_len = decl_count, |
| 3986 | 4013 | .auto_enum_tag = have_auto_enum, |
| ... | ... | @@ -3989,11 +4016,12 @@ fn unionDeclInner( |
| 3989 | 4016 | wip_members.finishBits(bits_per_field); |
| 3990 | 4017 | const decls_slice = wip_members.declsSlice(); |
| 3991 | 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 | 4020 | astgen.extra.appendSliceAssumeCapacity(decls_slice); |
| 3994 | | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); |
| 4021 | astgen.extra.appendSliceAssumeCapacity(body); |
| 3995 | 4022 | astgen.extra.appendSliceAssumeCapacity(fields_slice); |
| 3996 | 4023 | |
| 4024 | block_scope.unstack(); |
| 3997 | 4025 | try gz.addNamespaceCaptures(&namespace); |
| 3998 | 4026 | return indexToRef(decl_inst); |
| 3999 | 4027 | } |
| ... | ... | @@ -4163,8 +4191,10 @@ fn containerDecl( |
| 4163 | 4191 | .astgen = astgen, |
| 4164 | 4192 | .force_comptime = true, |
| 4165 | 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(); |
| 4168 | 4198 | |
| 4169 | 4199 | _ = try astgen.scanDecls(&namespace, container_decl.ast.members); |
| 4170 | 4200 | |
| ... | ... | @@ -4215,15 +4245,17 @@ fn containerDecl( |
| 4215 | 4245 | } |
| 4216 | 4246 | } |
| 4217 | 4247 | |
| 4218 | | if (block_scope.instructions.items.len != 0) { |
| 4248 | if (!block_scope.isEmpty()) { |
| 4219 | 4249 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 4220 | 4250 | } |
| 4221 | 4251 | |
| 4252 | const body = block_scope.instructionsSlice(); |
| 4253 | |
| 4222 | 4254 | try gz.setEnum(decl_inst, .{ |
| 4223 | 4255 | .src_node = node, |
| 4224 | 4256 | .nonexhaustive = nonexhaustive, |
| 4225 | 4257 | .tag_type = arg_inst, |
| 4226 | | .body_len = @intCast(u32, block_scope.instructions.items.len), |
| 4258 | .body_len = @intCast(u32, body.len), |
| 4227 | 4259 | .fields_len = @intCast(u32, counts.total_fields), |
| 4228 | 4260 | .decls_len = @intCast(u32, counts.decls), |
| 4229 | 4261 | }); |
| ... | ... | @@ -4231,11 +4263,12 @@ fn containerDecl( |
| 4231 | 4263 | wip_members.finishBits(bits_per_field); |
| 4232 | 4264 | const decls_slice = wip_members.declsSlice(); |
| 4233 | 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 | 4267 | astgen.extra.appendSliceAssumeCapacity(decls_slice); |
| 4236 | | astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); |
| 4268 | astgen.extra.appendSliceAssumeCapacity(body); |
| 4237 | 4269 | astgen.extra.appendSliceAssumeCapacity(fields_slice); |
| 4238 | 4270 | |
| 4271 | block_scope.unstack(); |
| 4239 | 4272 | try gz.addNamespaceCaptures(&namespace); |
| 4240 | 4273 | return rvalue(gz, rl, indexToRef(decl_inst), node); |
| 4241 | 4274 | }, |
| ... | ... | @@ -4453,7 +4486,7 @@ fn tryExpr( |
| 4453 | 4486 | |
| 4454 | 4487 | var block_scope = parent_gz.makeSubBlock(scope); |
| 4455 | 4488 | block_scope.setBreakResultLoc(rl); |
| 4456 | | defer block_scope.instructions.deinit(astgen.gpa); |
| 4489 | defer block_scope.unstack(); |
| 4457 | 4490 | |
| 4458 | 4491 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { |
| 4459 | 4492 | .ref => .ref, |
| ... | ... | @@ -4473,12 +4506,13 @@ fn tryExpr( |
| 4473 | 4506 | const cond = try block_scope.addUnNode(err_ops[0], operand, node); |
| 4474 | 4507 | const condbr = try block_scope.addCondBr(.condbr, node); |
| 4475 | 4508 | |
| 4476 | | const block = try parent_gz.addBlock(.block, node); |
| 4477 | | try parent_gz.instructions.append(astgen.gpa, block); |
| 4509 | const block = try parent_gz.makeBlockInst(.block, node); |
| 4478 | 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); |
| 4479 | 4513 | |
| 4480 | 4514 | var then_scope = parent_gz.makeSubBlock(scope); |
| 4481 | | defer then_scope.instructions.deinit(astgen.gpa); |
| 4515 | defer then_scope.unstack(); |
| 4482 | 4516 | |
| 4483 | 4517 | block_scope.break_count += 1; |
| 4484 | 4518 | // This could be a pointer or value depending on `err_ops[2]`. |
| ... | ... | @@ -4488,8 +4522,9 @@ fn tryExpr( |
| 4488 | 4522 | else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node), |
| 4489 | 4523 | }; |
| 4490 | 4524 | |
| 4525 | // else_scope will be stacked on then_scope as both are stacked on parent_gz |
| 4491 | 4526 | var else_scope = parent_gz.makeSubBlock(scope); |
| 4492 | | defer else_scope.instructions.deinit(astgen.gpa); |
| 4527 | defer else_scope.unstack(); |
| 4493 | 4528 | |
| 4494 | 4529 | const err_code = try else_scope.addUnNode(err_ops[1], operand, node); |
| 4495 | 4530 | try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); |
| ... | ... | @@ -4529,7 +4564,7 @@ fn orelseCatchExpr( |
| 4529 | 4564 | |
| 4530 | 4565 | var block_scope = parent_gz.makeSubBlock(scope); |
| 4531 | 4566 | block_scope.setBreakResultLoc(rl); |
| 4532 | | defer block_scope.instructions.deinit(astgen.gpa); |
| 4567 | defer block_scope.unstack(); |
| 4533 | 4568 | |
| 4534 | 4569 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { |
| 4535 | 4570 | .ref => .ref, |
| ... | ... | @@ -4544,12 +4579,13 @@ fn orelseCatchExpr( |
| 4544 | 4579 | const cond = try block_scope.addUnNode(cond_op, operand, node); |
| 4545 | 4580 | const condbr = try block_scope.addCondBr(.condbr, node); |
| 4546 | 4581 | |
| 4547 | | const block = try parent_gz.addBlock(.block, node); |
| 4548 | | try parent_gz.instructions.append(astgen.gpa, block); |
| 4582 | const block = try parent_gz.makeBlockInst(.block, node); |
| 4549 | 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); |
| 4550 | 4586 | |
| 4551 | 4587 | var then_scope = parent_gz.makeSubBlock(scope); |
| 4552 | | defer then_scope.instructions.deinit(astgen.gpa); |
| 4588 | defer then_scope.unstack(); |
| 4553 | 4589 | |
| 4554 | 4590 | // This could be a pointer or value depending on `unwrap_op`. |
| 4555 | 4591 | const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node); |
| ... | ... | @@ -4559,7 +4595,7 @@ fn orelseCatchExpr( |
| 4559 | 4595 | }; |
| 4560 | 4596 | |
| 4561 | 4597 | var else_scope = parent_gz.makeSubBlock(scope); |
| 4562 | | defer else_scope.instructions.deinit(astgen.gpa); |
| 4598 | defer else_scope.unstack(); |
| 4563 | 4599 | |
| 4564 | 4600 | var err_val_scope: Scope.LocalVal = undefined; |
| 4565 | 4601 | const else_sub_scope = blk: { |
| ... | ... | @@ -4606,6 +4642,7 @@ fn orelseCatchExpr( |
| 4606 | 4642 | ); |
| 4607 | 4643 | } |
| 4608 | 4644 | |
| 4645 | /// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`. |
| 4609 | 4646 | fn finishThenElseBlock( |
| 4610 | 4647 | parent_gz: *GenZir, |
| 4611 | 4648 | rl: ResultLoc, |
| ... | ... | @@ -4624,33 +4661,33 @@ fn finishThenElseBlock( |
| 4624 | 4661 | // We now have enough information to decide whether the result instruction should |
| 4625 | 4662 | // be communicated via result location pointer or break instructions. |
| 4626 | 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 | 4670 | switch (strat.tag) { |
| 4628 | 4671 | .break_void => { |
| 4629 | | if (!then_scope.endsWithNoReturn()) { |
| 4630 | | _ = try then_scope.addBreak(break_tag, then_break_block, .void_value); |
| 4631 | | } |
| 4632 | | if (!else_scope.endsWithNoReturn()) { |
| 4633 | | _ = try else_scope.addBreak(break_tag, main_block, .void_value); |
| 4634 | | } |
| 4672 | const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, .void_value) else 0; |
| 4673 | const else_break = if (!else_no_return) try else_scope.makeBreak(break_tag, main_block, .void_value) else 0; |
| 4635 | 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 | 4676 | return indexToRef(main_block); |
| 4638 | 4677 | }, |
| 4639 | 4678 | .break_operand => { |
| 4640 | | if (!then_scope.endsWithNoReturn()) { |
| 4641 | | _ = try then_scope.addBreak(break_tag, then_break_block, then_result); |
| 4642 | | } |
| 4643 | | if (else_result != .none) { |
| 4644 | | if (!else_scope.endsWithNoReturn()) { |
| 4645 | | _ = try else_scope.addBreak(break_tag, main_block, else_result); |
| 4646 | | } |
| 4647 | | } else { |
| 4648 | | _ = try else_scope.addBreak(break_tag, main_block, .void_value); |
| 4649 | | } |
| 4679 | const then_break = if (!then_no_return) try then_scope.makeBreak(break_tag, then_break_block, then_result) else 0; |
| 4680 | const else_break = if (else_result == .none) |
| 4681 | try else_scope.makeBreak(break_tag, main_block, .void_value) |
| 4682 | else if (!else_no_return) |
| 4683 | try else_scope.makeBreak(break_tag, main_block, else_result) |
| 4684 | else |
| 4685 | 0; |
| 4686 | |
| 4650 | 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 | 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 | 4692 | const block_ref = indexToRef(main_block); |
| 4656 | 4693 | switch (rl) { |
| ... | ... | @@ -4778,7 +4815,7 @@ fn boolBinOp( |
| 4778 | 4815 | const bool_br = try gz.addBoolBr(zir_tag, lhs); |
| 4779 | 4816 | |
| 4780 | 4817 | var rhs_scope = gz.makeSubBlock(scope); |
| 4781 | | defer rhs_scope.instructions.deinit(gz.astgen.gpa); |
| 4818 | defer rhs_scope.unstack(); |
| 4782 | 4819 | const rhs = try expr(&rhs_scope, &rhs_scope.base, bool_rl, node_datas[node].rhs); |
| 4783 | 4820 | if (!gz.refIsNoReturn(rhs)) { |
| 4784 | 4821 | _ = try rhs_scope.addBreak(.break_inline, bool_br, rhs); |
| ... | ... | @@ -4802,7 +4839,7 @@ fn ifExpr( |
| 4802 | 4839 | |
| 4803 | 4840 | var block_scope = parent_gz.makeSubBlock(scope); |
| 4804 | 4841 | block_scope.setBreakResultLoc(rl); |
| 4805 | | defer block_scope.instructions.deinit(astgen.gpa); |
| 4842 | defer block_scope.unstack(); |
| 4806 | 4843 | |
| 4807 | 4844 | const payload_is_ref = if (if_full.payload_token) |payload_token| |
| 4808 | 4845 | token_tags[payload_token] == .asterisk |
| ... | ... | @@ -4840,12 +4877,13 @@ fn ifExpr( |
| 4840 | 4877 | |
| 4841 | 4878 | const condbr = try block_scope.addCondBr(.condbr, node); |
| 4842 | 4879 | |
| 4843 | | const block = try parent_gz.addBlock(.block, node); |
| 4844 | | try parent_gz.instructions.append(astgen.gpa, block); |
| 4880 | const block = try parent_gz.makeBlockInst(.block, node); |
| 4845 | 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); |
| 4846 | 4884 | |
| 4847 | 4885 | var then_scope = parent_gz.makeSubBlock(scope); |
| 4848 | | defer then_scope.instructions.deinit(astgen.gpa); |
| 4886 | defer then_scope.unstack(); |
| 4849 | 4887 | |
| 4850 | 4888 | var payload_val_scope: Scope.LocalVal = undefined; |
| 4851 | 4889 | |
| ... | ... | @@ -4911,7 +4949,7 @@ fn ifExpr( |
| 4911 | 4949 | // instructions or not. |
| 4912 | 4950 | |
| 4913 | 4951 | var else_scope = parent_gz.makeSubBlock(scope); |
| 4914 | | defer else_scope.instructions.deinit(astgen.gpa); |
| 4952 | defer else_scope.unstack(); |
| 4915 | 4953 | |
| 4916 | 4954 | const else_node = if_full.ast.else_expr; |
| 4917 | 4955 | const else_info: struct { |
| ... | ... | @@ -4974,52 +5012,70 @@ fn ifExpr( |
| 4974 | 5012 | ); |
| 4975 | 5013 | } |
| 4976 | 5014 | |
| 5015 | /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. |
| 4977 | 5016 | fn setCondBrPayload( |
| 4978 | 5017 | condbr: Zir.Inst.Index, |
| 4979 | 5018 | cond: Zir.Inst.Ref, |
| 4980 | 5019 | then_scope: *GenZir, |
| 5020 | then_break: Zir.Inst.Index, |
| 4981 | 5021 | else_scope: *GenZir, |
| 5022 | else_break: Zir.Inst.Index, |
| 4982 | 5023 | ) !void { |
| 5024 | defer then_scope.unstack(); |
| 5025 | defer else_scope.unstack(); |
| 4983 | 5026 | const astgen = then_scope.astgen; |
| 4984 | | |
| 5027 | const then_body = then_scope.instructionsSliceUpto(else_scope); |
| 5028 | const else_body = else_scope.instructionsSlice(); |
| 5029 | const then_body_len = @intCast(u32, then_body.len + @boolToInt(then_break != 0)); |
| 5030 | const else_body_len = @intCast(u32, else_body.len + @boolToInt(else_break != 0)); |
| 4985 | 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); |
| 4987 | 5033 | |
| 4988 | 5034 | const zir_datas = astgen.instructions.items(.data); |
| 4989 | 5035 | zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ |
| 4990 | 5036 | .condition = cond, |
| 4991 | | .then_body_len = @intCast(u32, then_scope.instructions.items.len), |
| 4992 | | .else_body_len = @intCast(u32, else_scope.instructions.items.len), |
| 5037 | .then_body_len = then_body_len, |
| 5038 | .else_body_len = else_body_len, |
| 4993 | 5039 | }); |
| 4994 | | astgen.extra.appendSliceAssumeCapacity(then_scope.instructions.items); |
| 4995 | | astgen.extra.appendSliceAssumeCapacity(else_scope.instructions.items); |
| 5040 | astgen.extra.appendSliceAssumeCapacity(then_body); |
| 5041 | if (then_break != 0) astgen.extra.appendAssumeCapacity(then_break); |
| 5042 | astgen.extra.appendSliceAssumeCapacity(else_body); |
| 5043 | if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break); |
| 4996 | 5044 | } |
| 4997 | 5045 | |
| 5046 | /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. |
| 4998 | 5047 | fn setCondBrPayloadElideBlockStorePtr( |
| 4999 | 5048 | condbr: Zir.Inst.Index, |
| 5000 | 5049 | cond: Zir.Inst.Ref, |
| 5001 | 5050 | then_scope: *GenZir, |
| 5051 | then_break: Zir.Inst.Index, |
| 5002 | 5052 | else_scope: *GenZir, |
| 5053 | else_break: Zir.Inst.Index, |
| 5003 | 5054 | block_ptr: Zir.Inst.Ref, |
| 5004 | 5055 | ) !void { |
| 5056 | defer then_scope.unstack(); |
| 5057 | defer else_scope.unstack(); |
| 5005 | 5058 | const astgen = then_scope.astgen; |
| 5006 | | |
| 5059 | const then_body = then_scope.instructionsSliceUpto(else_scope); |
| 5060 | const else_body = else_scope.instructionsSlice(); |
| 5061 | const then_body_len = @intCast(u32, then_body.len + @boolToInt(then_break != 0)); |
| 5062 | const else_body_len = @intCast(u32, else_body.len + @boolToInt(else_break != 0)); |
| 5007 | 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); |
| 5009 | 5065 | |
| 5010 | 5066 | const zir_tags = astgen.instructions.items(.tag); |
| 5011 | 5067 | const zir_datas = astgen.instructions.items(.data); |
| 5012 | 5068 | |
| 5013 | 5069 | const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{ |
| 5014 | 5070 | .condition = cond, |
| 5015 | | .then_body_len = @intCast(u32, then_scope.instructions.items.len), |
| 5016 | | .else_body_len = @intCast(u32, else_scope.instructions.items.len), |
| 5071 | .then_body_len = then_body_len, |
| 5072 | .else_body_len = else_body_len, |
| 5017 | 5073 | }); |
| 5018 | 5074 | zir_datas[condbr].pl_node.payload_index = condbr_pl; |
| 5019 | 5075 | const then_body_len_index = condbr_pl + 1; |
| 5020 | 5076 | const else_body_len_index = condbr_pl + 2; |
| 5021 | 5077 | |
| 5022 | | for (then_scope.instructions.items) |src_inst| { |
| 5078 | for (then_body) |src_inst| { |
| 5023 | 5079 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 5024 | 5080 | if (zir_datas[src_inst].bin.lhs == block_ptr) { |
| 5025 | 5081 | astgen.extra.items[then_body_len_index] -= 1; |
| ... | ... | @@ -5028,7 +5084,8 @@ fn setCondBrPayloadElideBlockStorePtr( |
| 5028 | 5084 | } |
| 5029 | 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 | 5089 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 5033 | 5090 | if (zir_datas[src_inst].bin.lhs == block_ptr) { |
| 5034 | 5091 | astgen.extra.items[else_body_len_index] -= 1; |
| ... | ... | @@ -5037,6 +5094,7 @@ fn setCondBrPayloadElideBlockStorePtr( |
| 5037 | 5094 | } |
| 5038 | 5095 | astgen.extra.appendAssumeCapacity(src_inst); |
| 5039 | 5096 | } |
| 5097 | if (else_break != 0) astgen.extra.appendAssumeCapacity(else_break); |
| 5040 | 5098 | } |
| 5041 | 5099 | |
| 5042 | 5100 | fn whileExpr( |
| ... | ... | @@ -5056,17 +5114,17 @@ fn whileExpr( |
| 5056 | 5114 | |
| 5057 | 5115 | const is_inline = parent_gz.force_comptime or while_full.inline_token != null; |
| 5058 | 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 | 5118 | try parent_gz.instructions.append(astgen.gpa, loop_block); |
| 5061 | 5119 | |
| 5062 | 5120 | var loop_scope = parent_gz.makeSubBlock(scope); |
| 5063 | 5121 | loop_scope.setBreakResultLoc(rl); |
| 5064 | | defer loop_scope.instructions.deinit(astgen.gpa); |
| 5122 | defer loop_scope.unstack(); |
| 5065 | 5123 | defer loop_scope.labeled_breaks.deinit(astgen.gpa); |
| 5066 | 5124 | defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); |
| 5067 | 5125 | |
| 5068 | 5126 | var continue_scope = parent_gz.makeSubBlock(&loop_scope.base); |
| 5069 | | defer continue_scope.instructions.deinit(astgen.gpa); |
| 5127 | defer continue_scope.unstack(); |
| 5070 | 5128 | |
| 5071 | 5129 | const payload_is_ref = if (while_full.payload_token) |payload_token| |
| 5072 | 5130 | token_tags[payload_token] == .asterisk |
| ... | ... | @@ -5105,15 +5163,19 @@ fn whileExpr( |
| 5105 | 5163 | const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; |
| 5106 | 5164 | const condbr = try continue_scope.addCondBr(condbr_tag, node); |
| 5107 | 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); |
| 5109 | | try loop_scope.instructions.append(astgen.gpa, cond_block); |
| 5166 | const cond_block = try loop_scope.makeBlockInst(block_tag, node); |
| 5110 | 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); |
| 5111 | 5170 | |
| 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 | 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(); |
| 5114 | 5176 | |
| 5177 | var payload_inst: Zir.Inst.Index = 0; |
| 5115 | 5178 | var payload_val_scope: Scope.LocalVal = undefined; |
| 5116 | | |
| 5117 | 5179 | const then_sub_scope = s: { |
| 5118 | 5180 | if (while_full.error_token != null) { |
| 5119 | 5181 | if (while_full.payload_token) |payload_token| { |
| ... | ... | @@ -5121,7 +5183,8 @@ fn whileExpr( |
| 5121 | 5183 | .err_union_payload_unsafe_ptr |
| 5122 | 5184 | else |
| 5123 | 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 | 5188 | const ident_token = if (payload_is_ref) payload_token + 1 else payload_token; |
| 5126 | 5189 | const ident_bytes = tree.tokenSlice(ident_token); |
| 5127 | 5190 | if (mem.eql(u8, "_", ident_bytes)) |
| ... | ... | @@ -5133,7 +5196,7 @@ fn whileExpr( |
| 5133 | 5196 | .parent = &then_scope.base, |
| 5134 | 5197 | .gen_zir = &then_scope, |
| 5135 | 5198 | .name = ident_name, |
| 5136 | | .inst = payload_inst, |
| 5199 | .inst = indexToRef(payload_inst), |
| 5137 | 5200 | .token_src = payload_token, |
| 5138 | 5201 | .id_cat = .@"capture", |
| 5139 | 5202 | }; |
| ... | ... | @@ -5147,7 +5210,8 @@ fn whileExpr( |
| 5147 | 5210 | .optional_payload_unsafe_ptr |
| 5148 | 5211 | else |
| 5149 | 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 | 5215 | const ident_name = try astgen.identAsString(ident_token); |
| 5152 | 5216 | const ident_bytes = tree.tokenSlice(ident_token); |
| 5153 | 5217 | if (mem.eql(u8, "_", ident_bytes)) |
| ... | ... | @@ -5157,7 +5221,7 @@ fn whileExpr( |
| 5157 | 5221 | .parent = &then_scope.base, |
| 5158 | 5222 | .gen_zir = &then_scope, |
| 5159 | 5223 | .name = ident_name, |
| 5160 | | .inst = payload_inst, |
| 5224 | .inst = indexToRef(payload_inst), |
| 5161 | 5225 | .token_src = ident_token, |
| 5162 | 5226 | .id_cat = .@"capture", |
| 5163 | 5227 | }; |
| ... | ... | @@ -5187,6 +5251,9 @@ fn whileExpr( |
| 5187 | 5251 | }); |
| 5188 | 5252 | } |
| 5189 | 5253 | |
| 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 | 5257 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); |
| 5191 | 5258 | if (!then_scope.endsWithNoReturn()) { |
| 5192 | 5259 | loop_scope.break_count += 1; |
| ... | ... | @@ -5194,7 +5261,7 @@ fn whileExpr( |
| 5194 | 5261 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 5195 | 5262 | |
| 5196 | 5263 | var else_scope = parent_gz.makeSubBlock(&continue_scope.base); |
| 5197 | | defer else_scope.instructions.deinit(astgen.gpa); |
| 5264 | defer else_scope.unstack(); |
| 5198 | 5265 | |
| 5199 | 5266 | const else_node = while_full.ast.else_expr; |
| 5200 | 5267 | const else_info: struct { |
| ... | ... | @@ -5207,7 +5274,7 @@ fn whileExpr( |
| 5207 | 5274 | .err_union_code_ptr |
| 5208 | 5275 | else |
| 5209 | 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 | 5278 | const ident_name = try astgen.identAsString(error_token); |
| 5212 | 5279 | const ident_bytes = tree.tokenSlice(error_token); |
| 5213 | 5280 | if (mem.eql(u8, ident_bytes, "_")) |
| ... | ... | @@ -5217,7 +5284,7 @@ fn whileExpr( |
| 5217 | 5284 | .parent = &else_scope.base, |
| 5218 | 5285 | .gen_zir = &else_scope, |
| 5219 | 5286 | .name = ident_name, |
| 5220 | | .inst = payload_inst, |
| 5287 | .inst = else_payload_inst, |
| 5221 | 5288 | .token_src = error_token, |
| 5222 | 5289 | .id_cat = .@"capture", |
| 5223 | 5290 | }; |
| ... | ... | @@ -5299,17 +5366,17 @@ fn forExpr( |
| 5299 | 5366 | }; |
| 5300 | 5367 | |
| 5301 | 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 | 5370 | try parent_gz.instructions.append(astgen.gpa, loop_block); |
| 5304 | 5371 | |
| 5305 | 5372 | var loop_scope = parent_gz.makeSubBlock(scope); |
| 5306 | 5373 | loop_scope.setBreakResultLoc(rl); |
| 5307 | | defer loop_scope.instructions.deinit(astgen.gpa); |
| 5374 | defer loop_scope.unstack(); |
| 5308 | 5375 | defer loop_scope.labeled_breaks.deinit(astgen.gpa); |
| 5309 | 5376 | defer loop_scope.labeled_store_to_block_ptr_list.deinit(astgen.gpa); |
| 5310 | 5377 | |
| 5311 | 5378 | var cond_scope = parent_gz.makeSubBlock(&loop_scope.base); |
| 5312 | | defer cond_scope.instructions.deinit(astgen.gpa); |
| 5379 | defer cond_scope.unstack(); |
| 5313 | 5380 | |
| 5314 | 5381 | // check condition i < array_expr.len |
| 5315 | 5382 | const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); |
| ... | ... | @@ -5321,9 +5388,10 @@ fn forExpr( |
| 5321 | 5388 | const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr; |
| 5322 | 5389 | const condbr = try cond_scope.addCondBr(condbr_tag, node); |
| 5323 | 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); |
| 5325 | | try loop_scope.instructions.append(astgen.gpa, cond_block); |
| 5391 | const cond_block = try loop_scope.makeBlockInst(block_tag, node); |
| 5326 | 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); |
| 5327 | 5395 | |
| 5328 | 5396 | // Increment the index variable. |
| 5329 | 5397 | const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr); |
| ... | ... | @@ -5346,7 +5414,7 @@ fn forExpr( |
| 5346 | 5414 | } |
| 5347 | 5415 | |
| 5348 | 5416 | var then_scope = parent_gz.makeSubBlock(&cond_scope.base); |
| 5349 | | defer then_scope.instructions.deinit(astgen.gpa); |
| 5417 | defer then_scope.unstack(); |
| 5350 | 5418 | |
| 5351 | 5419 | var payload_val_scope: Scope.LocalVal = undefined; |
| 5352 | 5420 | var index_scope: Scope.LocalPtr = undefined; |
| ... | ... | @@ -5408,7 +5476,7 @@ fn forExpr( |
| 5408 | 5476 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 5409 | 5477 | |
| 5410 | 5478 | var else_scope = parent_gz.makeSubBlock(&cond_scope.base); |
| 5411 | | defer else_scope.instructions.deinit(astgen.gpa); |
| 5479 | defer else_scope.unstack(); |
| 5412 | 5480 | |
| 5413 | 5481 | const else_node = for_full.ast.else_expr; |
| 5414 | 5482 | const else_info: struct { |
| ... | ... | @@ -5600,15 +5668,16 @@ fn switchExpr( |
| 5600 | 5668 | defer astgen.scratch.items.len = scratch_top; |
| 5601 | 5669 | |
| 5602 | 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 | 5673 | block_scope.setBreakResultLoc(rl); |
| 5604 | | defer block_scope.instructions.deinit(gpa); |
| 5605 | 5674 | |
| 5606 | 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); |
| 5608 | 5677 | |
| 5609 | 5678 | // We re-use this same scope for all cases, including the special prong, if any. |
| 5610 | 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; |
| 5612 | 5681 | |
| 5613 | 5682 | // In this pass we generate all the item and prong expressions. |
| 5614 | 5683 | var multi_case_index: u32 = 0; |
| ... | ... | @@ -5620,12 +5689,10 @@ fn switchExpr( |
| 5620 | 5689 | else => unreachable, |
| 5621 | 5690 | }; |
| 5622 | 5691 | |
| 5623 | | // Reset the scope. |
| 5624 | | case_scope.instructions.shrinkRetainingCapacity(0); |
| 5625 | | |
| 5626 | 5692 | const is_multi_case = case.ast.values.len > 1 or |
| 5627 | 5693 | (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range); |
| 5628 | 5694 | |
| 5695 | var capture_inst: Zir.Inst.Index = 0; |
| 5629 | 5696 | var capture_val_scope: Scope.LocalVal = undefined; |
| 5630 | 5697 | const sub_scope = blk: { |
| 5631 | 5698 | const payload_token = case.payload_token orelse break :blk &case_scope.base; |
| ... | ... | @@ -5640,19 +5707,20 @@ fn switchExpr( |
| 5640 | 5707 | } |
| 5641 | 5708 | break :blk &case_scope.base; |
| 5642 | 5709 | } |
| 5643 | | const capture = if (case_node == special_node) capture: { |
| 5710 | if (case_node == special_node) { |
| 5644 | 5711 | const capture_tag: Zir.Inst.Tag = if (is_ptr) |
| 5645 | 5712 | .switch_capture_else_ref |
| 5646 | 5713 | else |
| 5647 | 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 | 5717 | .tag = capture_tag, |
| 5650 | 5718 | .data = .{ .switch_capture = .{ |
| 5651 | 5719 | .switch_inst = switch_block, |
| 5652 | 5720 | .prong_index = undefined, |
| 5653 | 5721 | } }, |
| 5654 | 5722 | }); |
| 5655 | | } else capture: { |
| 5723 | } else { |
| 5656 | 5724 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); |
| 5657 | 5725 | const is_ptr_bits: u2 = @boolToInt(is_ptr); |
| 5658 | 5726 | const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { |
| ... | ... | @@ -5662,20 +5730,21 @@ fn switchExpr( |
| 5662 | 5730 | 0b11 => .switch_capture_multi_ref, |
| 5663 | 5731 | }; |
| 5664 | 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 | 5735 | .tag = capture_tag, |
| 5667 | 5736 | .data = .{ .switch_capture = .{ |
| 5668 | 5737 | .switch_inst = switch_block, |
| 5669 | 5738 | .prong_index = capture_index, |
| 5670 | 5739 | } }, |
| 5671 | 5740 | }); |
| 5672 | | }; |
| 5741 | } |
| 5673 | 5742 | const capture_name = try astgen.identAsString(ident); |
| 5674 | 5743 | capture_val_scope = .{ |
| 5675 | 5744 | .parent = &case_scope.base, |
| 5676 | 5745 | .gen_zir = &case_scope, |
| 5677 | 5746 | .name = capture_name, |
| 5678 | | .inst = capture, |
| 5747 | .inst = indexToRef(capture_inst), |
| 5679 | 5748 | .token_src = payload_token, |
| 5680 | 5749 | .id_cat = .@"capture", |
| 5681 | 5750 | }; |
| ... | ... | @@ -5728,14 +5797,23 @@ fn switchExpr( |
| 5728 | 5797 | break :blk header_index + 1; |
| 5729 | 5798 | }; |
| 5730 | 5799 | |
| 5731 | | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); |
| 5732 | | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| 5733 | | if (!parent_gz.refIsNoReturn(case_result)) { |
| 5734 | | block_scope.break_count += 1; |
| 5735 | | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| 5800 | { |
| 5801 | // temporarily stack case_scope on parent_gz |
| 5802 | case_scope.instructions_top = parent_gz.instructions.items.len; |
| 5803 | defer case_scope.unstack(); |
| 5804 | |
| 5805 | if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst); |
| 5806 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); |
| 5807 | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| 5808 | if (!parent_gz.refIsNoReturn(case_result)) { |
| 5809 | block_scope.break_count += 1; |
| 5810 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| 5811 | } |
| 5812 | |
| 5813 | const case_slice = case_scope.instructionsSlice(); |
| 5814 | payloads.items[body_len_index] = @intCast(u32, case_slice.len); |
| 5815 | try payloads.appendSlice(gpa, case_slice); |
| 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 | 5818 | // Now that the item expressions are generated we can add this. |
| 5741 | 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 | 5995 | const condbr = try gz.addCondBr(.condbr, node); |
| 5918 | 5996 | |
| 5919 | 5997 | var then_scope = gz.makeSubBlock(scope); |
| 5920 | | defer then_scope.instructions.deinit(astgen.gpa); |
| 5998 | defer then_scope.unstack(); |
| 5921 | 5999 | |
| 5922 | 6000 | try genDefers(&then_scope, defer_outer, scope, .normal_only); |
| 5923 | 6001 | try then_scope.addRet(rl, operand, node); |
| 5924 | 6002 | |
| 5925 | 6003 | var else_scope = gz.makeSubBlock(scope); |
| 5926 | | defer else_scope.instructions.deinit(astgen.gpa); |
| 6004 | defer else_scope.unstack(); |
| 5927 | 6005 | |
| 5928 | 6006 | const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{ |
| 5929 | 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 | 6009 | try genDefers(&else_scope, defer_outer, scope, which_ones); |
| 5932 | 6010 | try else_scope.addRet(rl, operand, node); |
| 5933 | 6011 | |
| 5934 | | try setCondBrPayload(condbr, is_non_err, &then_scope, &else_scope); |
| 6012 | try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); |
| 5935 | 6013 | |
| 5936 | 6014 | return Zir.Inst.Ref.unreachable_value; |
| 5937 | 6015 | }, |
| ... | ... | @@ -6561,10 +6639,8 @@ fn asRlPtr( |
| 6561 | 6639 | operand_node: Ast.Node.Index, |
| 6562 | 6640 | dest_type: Zir.Inst.Ref, |
| 6563 | 6641 | ) InnerError!Zir.Inst.Ref { |
| 6564 | | const astgen = parent_gz.astgen; |
| 6565 | | |
| 6566 | 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(); |
| 6568 | 6644 | |
| 6569 | 6645 | const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node); |
| 6570 | 6646 | return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type); |
| ... | ... | @@ -7336,14 +7412,15 @@ fn cImport( |
| 7336 | 7412 | var block_scope = gz.makeSubBlock(scope); |
| 7337 | 7413 | block_scope.force_comptime = true; |
| 7338 | 7414 | block_scope.c_import = true; |
| 7339 | | defer block_scope.instructions.deinit(gpa); |
| 7415 | defer block_scope.unstack(); |
| 7340 | 7416 | |
| 7341 | | const block_inst = try gz.addBlock(.c_import, node); |
| 7417 | const block_inst = try gz.makeBlockInst(.c_import, node); |
| 7342 | 7418 | const block_result = try expr(&block_scope, &block_scope.base, .none, body_node); |
| 7343 | 7419 | if (!gz.refIsNoReturn(block_result)) { |
| 7344 | 7420 | _ = try block_scope.addBreak(.break_inline, block_inst, .void_value); |
| 7345 | 7421 | } |
| 7346 | 7422 | try block_scope.setBlockBody(block_inst); |
| 7423 | // block_scope unstacked now, can add new instructions to gz |
| 7347 | 7424 | try gz.instructions.append(gpa, block_inst); |
| 7348 | 7425 | |
| 7349 | 7426 | return indexToRef(block_inst); |
| ... | ... | @@ -8167,6 +8244,7 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool { |
| 8167 | 8244 | /// result locations must call this function on their result. |
| 8168 | 8245 | /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. |
| 8169 | 8246 | /// If the `ResultLoc` is `ty`, it will coerce the result to the type. |
| 8247 | /// Assumes nothing stacked on `gz`. |
| 8170 | 8248 | fn rvalue( |
| 8171 | 8249 | gz: *GenZir, |
| 8172 | 8250 | rl: ResultLoc, |
| ... | ... | @@ -8779,9 +8857,12 @@ const GenZir = struct { |
| 8779 | 8857 | parent: *Scope, |
| 8780 | 8858 | /// All `GenZir` scopes for the same ZIR share this. |
| 8781 | 8859 | astgen: *AstGen, |
| 8782 | | /// Keeps track of the list of instructions in this scope only. Indexes |
| 8783 | | /// to instructions in `astgen`. |
| 8784 | | instructions: ArrayListUnmanaged(Zir.Inst.Index) = .{}, |
| 8860 | /// Keeps track of the list of instructions in this scope. Possibly shared. |
| 8861 | /// Indexes to instructions in `astgen`. |
| 8862 | instructions: *ArrayListUnmanaged(Zir.Inst.Index), |
| 8863 | /// A sub-block may share its instructions ArrayList with containing GenZir, |
| 8864 | /// if use is strictly nested. This saves prior size of list for unstacking. |
| 8865 | instructions_top: usize, |
| 8785 | 8866 | label: ?Label = null, |
| 8786 | 8867 | break_block: Zir.Inst.Index = 0, |
| 8787 | 8868 | continue_block: Zir.Inst.Index = 0, |
| ... | ... | @@ -8817,6 +8898,36 @@ const GenZir = struct { |
| 8817 | 8898 | /// Keys are the raw instruction index, values are the closure_capture instruction. |
| 8818 | 8899 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, |
| 8819 | 8900 | |
| 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 | 8931 | fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { |
| 8821 | 8932 | return .{ |
| 8822 | 8933 | .force_comptime = gz.force_comptime, |
| ... | ... | @@ -8828,6 +8939,8 @@ const GenZir = struct { |
| 8828 | 8939 | .astgen = gz.astgen, |
| 8829 | 8940 | .suspend_node = gz.suspend_node, |
| 8830 | 8941 | .nosuspend_node = gz.nosuspend_node, |
| 8942 | .instructions = gz.instructions, |
| 8943 | .instructions_top = gz.instructions.items.len, |
| 8831 | 8944 | }; |
| 8832 | 8945 | } |
| 8833 | 8946 | |
| ... | ... | @@ -8841,12 +8954,13 @@ const GenZir = struct { |
| 8841 | 8954 | // result location. If it does, elide the coerce_result_ptr instruction |
| 8842 | 8955 | // as well as the store instruction, instead passing the result as an rvalue. |
| 8843 | 8956 | var as_scope = parent_gz.makeSubBlock(scope); |
| 8844 | | errdefer as_scope.instructions.deinit(parent_gz.astgen.gpa); |
| 8957 | errdefer as_scope.unstack(); |
| 8845 | 8958 | as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr); |
| 8846 | 8959 | |
| 8847 | 8960 | return as_scope; |
| 8848 | 8961 | } |
| 8849 | 8962 | |
| 8963 | /// Assumes `as_scope` is stacked immediately on top of `parent_gz`. Unstacks `as_scope`. |
| 8850 | 8964 | fn finishCoercion( |
| 8851 | 8965 | as_scope: *GenZir, |
| 8852 | 8966 | parent_gz: *GenZir, |
| ... | ... | @@ -8854,25 +8968,32 @@ const GenZir = struct { |
| 8854 | 8968 | src_node: Ast.Node.Index, |
| 8855 | 8969 | result: Zir.Inst.Ref, |
| 8856 | 8970 | dest_type: Zir.Inst.Ref, |
| 8857 | | ) !Zir.Inst.Ref { |
| 8971 | ) InnerError!Zir.Inst.Ref { |
| 8972 | assert(as_scope.instructions == parent_gz.instructions); |
| 8858 | 8973 | const astgen = as_scope.astgen; |
| 8859 | | const parent_zir = &parent_gz.instructions; |
| 8860 | 8974 | if (as_scope.rvalue_rl_count == 1) { |
| 8861 | 8975 | // Busted! This expression didn't actually need a pointer. |
| 8862 | 8976 | const zir_tags = astgen.instructions.items(.tag); |
| 8863 | 8977 | const zir_datas = astgen.instructions.items(.data); |
| 8864 | | try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len); |
| 8865 | | for (as_scope.instructions.items) |src_inst| { |
| 8978 | var src: usize = as_scope.instructions_top; |
| 8979 | var dst: usize = src; |
| 8980 | while (src < as_scope.instructions.items.len) : (src += 1) { |
| 8981 | const src_inst = as_scope.instructions.items[src]; |
| 8866 | 8982 | if (indexToRef(src_inst) == as_scope.rl_ptr) continue; |
| 8867 | 8983 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 8868 | 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 | 8992 | const casted_result = try parent_gz.addBin(.as, dest_type, result); |
| 8873 | 8993 | return rvalue(parent_gz, rl, casted_result, src_node); |
| 8874 | 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 | 8997 | return result; |
| 8877 | 8998 | } |
| 8878 | 8999 | } |
| ... | ... | @@ -8883,9 +9004,10 @@ const GenZir = struct { |
| 8883 | 9004 | used: bool = false, |
| 8884 | 9005 | }; |
| 8885 | 9006 | |
| 9007 | /// Assumes nothing stacked on `gz`. |
| 8886 | 9008 | fn endsWithNoReturn(gz: GenZir) bool { |
| 9009 | if (gz.isEmpty()) return false; |
| 8887 | 9010 | const tags = gz.astgen.instructions.items(.tag); |
| 8888 | | if (gz.instructions.items.len == 0) return false; |
| 8889 | 9011 | const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; |
| 8890 | 9012 | return tags[last_inst].isNoReturn(); |
| 8891 | 9013 | } |
| ... | ... | @@ -8955,41 +9077,46 @@ const GenZir = struct { |
| 8955 | 9077 | } |
| 8956 | 9078 | } |
| 8957 | 9079 | |
| 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 | 9082 | const gpa = gz.astgen.gpa; |
| 8960 | | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + |
| 8961 | | gz.instructions.items.len); |
| 9083 | const body = gz.instructionsSlice(); |
| 9084 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len); |
| 8962 | 9085 | const zir_datas = gz.astgen.instructions.items(.data); |
| 8963 | 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 | } |
| 8968 | 9092 | |
| 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 | 9095 | const gpa = gz.astgen.gpa; |
| 8971 | | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + |
| 8972 | | gz.instructions.items.len); |
| 9096 | const body = gz.instructionsSlice(); |
| 9097 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len); |
| 8973 | 9098 | const zir_datas = gz.astgen.instructions.items(.data); |
| 8974 | 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 | } |
| 8979 | 9105 | |
| 8980 | 9106 | /// Same as `setBlockBody` except we don't copy instructions which are |
| 8981 | 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 | 9110 | const gpa = gz.astgen.gpa; |
| 8984 | | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + |
| 8985 | | gz.instructions.items.len); |
| 9111 | const body = gz.instructionsSlice(); |
| 9112 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len + body.len); |
| 8986 | 9113 | const zir_datas = gz.astgen.instructions.items(.data); |
| 8987 | 9114 | const zir_tags = gz.astgen.instructions.items(.tag); |
| 8988 | 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 | 9118 | zir_datas[inst].pl_node.payload_index = block_pl_index; |
| 8992 | | for (gz.instructions.items) |sub_inst| { |
| 9119 | for (body) |sub_inst| { |
| 8993 | 9120 | if (zir_tags[sub_inst] == .store_to_block_ptr and |
| 8994 | 9121 | zir_datas[sub_inst].bin.lhs == .none) |
| 8995 | 9122 | { |
| ... | ... | @@ -8999,15 +9126,17 @@ const GenZir = struct { |
| 8999 | 9126 | } |
| 9000 | 9127 | gz.astgen.extra.appendAssumeCapacity(sub_inst); |
| 9001 | 9128 | } |
| 9129 | gz.unstack(); |
| 9002 | 9130 | } |
| 9003 | 9131 | |
| 9132 | /// Supports `body_gz` stacked on `ret_gz` stacked on `gz`. Unstacks `body_gz` and `ret_gz`. |
| 9004 | 9133 | fn addFunc(gz: *GenZir, args: struct { |
| 9005 | 9134 | src_node: Ast.Node.Index, |
| 9006 | 9135 | lbrace_line: u32 = 0, |
| 9007 | 9136 | lbrace_column: u32 = 0, |
| 9008 | | body: []const Zir.Inst.Index, |
| 9137 | body_gz: ?*GenZir, |
| 9009 | 9138 | param_block: Zir.Inst.Index, |
| 9010 | | ret_ty: []const Zir.Inst.Index, |
| 9139 | ret_gz: ?*GenZir, |
| 9011 | 9140 | ret_br: Zir.Inst.Index, |
| 9012 | 9141 | cc: Zir.Inst.Ref, |
| 9013 | 9142 | align_inst: Zir.Inst.Ref, |
| ... | ... | @@ -9021,12 +9150,13 @@ const GenZir = struct { |
| 9021 | 9150 | const astgen = gz.astgen; |
| 9022 | 9151 | const gpa = astgen.gpa; |
| 9023 | 9152 | |
| 9024 | | try gz.instructions.ensureUnusedCapacity(gpa, 1); |
| 9025 | 9153 | try astgen.instructions.ensureUnusedCapacity(gpa, 1); |
| 9026 | 9154 | |
| 9155 | var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; |
| 9156 | var ret_ty: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; |
| 9027 | 9157 | var src_locs_buffer: [3]u32 = undefined; |
| 9028 | 9158 | var src_locs: []u32 = src_locs_buffer[0..0]; |
| 9029 | | if (args.body.len != 0) { |
| 9159 | if (args.body_gz) |body_gz| { |
| 9030 | 9160 | const tree = astgen.tree; |
| 9031 | 9161 | const node_tags = tree.nodes.items(.tag); |
| 9032 | 9162 | const node_datas = tree.nodes.items(.data); |
| ... | ... | @@ -9044,6 +9174,13 @@ const GenZir = struct { |
| 9044 | 9174 | src_locs_buffer[1] = rbrace_line; |
| 9045 | 9175 | src_locs_buffer[2] = columns; |
| 9046 | 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 | } |
| 9048 | 9185 | |
| 9049 | 9186 | if (args.cc != .none or args.lib_name != 0 or |
| ... | ... | @@ -9053,7 +9190,7 @@ const GenZir = struct { |
| 9053 | 9190 | try astgen.extra.ensureUnusedCapacity( |
| 9054 | 9191 | gpa, |
| 9055 | 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 | 9194 | @boolToInt(args.lib_name != 0) + |
| 9058 | 9195 | @boolToInt(args.align_inst != .none) + |
| 9059 | 9196 | @boolToInt(args.cc != .none), |
| ... | ... | @@ -9061,8 +9198,8 @@ const GenZir = struct { |
| 9061 | 9198 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{ |
| 9062 | 9199 | .src_node = gz.nodeIndexToRelative(args.src_node), |
| 9063 | 9200 | .param_block = args.param_block, |
| 9064 | | .ret_body_len = @intCast(u32, args.ret_ty.len), |
| 9065 | | .body_len = @intCast(u32, args.body.len), |
| 9201 | .ret_body_len = @intCast(u32, ret_ty.len), |
| 9202 | .body_len = @intCast(u32, body.len), |
| 9066 | 9203 | }); |
| 9067 | 9204 | if (args.lib_name != 0) { |
| 9068 | 9205 | astgen.extra.appendAssumeCapacity(args.lib_name); |
| ... | ... | @@ -9073,9 +9210,13 @@ const GenZir = struct { |
| 9073 | 9210 | if (args.align_inst != .none) { |
| 9074 | 9211 | astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); |
| 9075 | 9212 | } |
| 9076 | | astgen.extra.appendSliceAssumeCapacity(args.ret_ty); |
| 9077 | | astgen.extra.appendSliceAssumeCapacity(args.body); |
| 9213 | astgen.extra.appendSliceAssumeCapacity(ret_ty); |
| 9214 | astgen.extra.appendSliceAssumeCapacity(body); |
| 9078 | 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); |
| 9079 | 9220 | |
| 9080 | 9221 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); |
| 9081 | 9222 | if (args.ret_br != 0) { |
| ... | ... | @@ -9103,17 +9244,21 @@ const GenZir = struct { |
| 9103 | 9244 | try astgen.extra.ensureUnusedCapacity( |
| 9104 | 9245 | gpa, |
| 9105 | 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 | ); |
| 9108 | 9249 | |
| 9109 | 9250 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{ |
| 9110 | 9251 | .param_block = args.param_block, |
| 9111 | | .ret_body_len = @intCast(u32, args.ret_ty.len), |
| 9112 | | .body_len = @intCast(u32, args.body.len), |
| 9252 | .ret_body_len = @intCast(u32, ret_ty.len), |
| 9253 | .body_len = @intCast(u32, body.len), |
| 9113 | 9254 | }); |
| 9114 | | astgen.extra.appendSliceAssumeCapacity(args.ret_ty); |
| 9115 | | astgen.extra.appendSliceAssumeCapacity(args.body); |
| 9255 | astgen.extra.appendSliceAssumeCapacity(ret_ty); |
| 9256 | astgen.extra.appendSliceAssumeCapacity(body); |
| 9116 | 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); |
| 9117 | 9262 | |
| 9118 | 9263 | const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func; |
| 9119 | 9264 | const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); |
| ... | ... | @@ -9260,6 +9405,25 @@ const GenZir = struct { |
| 9260 | 9405 | }); |
| 9261 | 9406 | } |
| 9262 | 9407 | |
| 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 | 9427 | fn addPlNode( |
| 9264 | 9428 | gz: *GenZir, |
| 9265 | 9429 | tag: Zir.Inst.Tag, |
| ... | ... | @@ -9300,25 +9464,27 @@ const GenZir = struct { |
| 9300 | 9464 | }); |
| 9301 | 9465 | } |
| 9302 | 9466 | |
| 9467 | /// Supports `param_gz` stacked on `gz`. Assumes nothing stacked on `param_gz`. Unstacks `param_gz`. |
| 9303 | 9468 | fn addParam( |
| 9304 | 9469 | gz: *GenZir, |
| 9470 | param_gz: *GenZir, |
| 9305 | 9471 | tag: Zir.Inst.Tag, |
| 9306 | 9472 | /// Absolute token index. This function does the conversion to Decl offset. |
| 9307 | 9473 | abs_tok_index: Ast.TokenIndex, |
| 9308 | 9474 | name: u32, |
| 9309 | | body: []const u32, |
| 9310 | 9475 | ) !Zir.Inst.Index { |
| 9311 | 9476 | const gpa = gz.astgen.gpa; |
| 9312 | | try gz.instructions.ensureUnusedCapacity(gpa, 1); |
| 9477 | const param_body = param_gz.instructionsSlice(); |
| 9313 | 9478 | try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1); |
| 9314 | 9479 | try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len + |
| 9315 | | body.len); |
| 9480 | param_body.len); |
| 9316 | 9481 | |
| 9317 | 9482 | const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{ |
| 9318 | 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(); |
| 9322 | 9488 | |
| 9323 | 9489 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); |
| 9324 | 9490 | gz.astgen.instructions.appendAssumeCapacity(.{ |
| ... | ... | @@ -9461,6 +9627,23 @@ const GenZir = struct { |
| 9461 | 9627 | }); |
| 9462 | 9628 | } |
| 9463 | 9629 | |
| 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 | 9647 | fn addBin( |
| 9465 | 9648 | gz: *GenZir, |
| 9466 | 9649 | tag: Zir.Inst.Tag, |
| ... | ... | @@ -9649,7 +9832,7 @@ const GenZir = struct { |
| 9649 | 9832 | /// Note that this returns a `Zir.Inst.Index` not a ref. |
| 9650 | 9833 | /// Does *not* append the block instruction to the scope. |
| 9651 | 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 | 9836 | const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); |
| 9654 | 9837 | const gpa = gz.astgen.gpa; |
| 9655 | 9838 | try gz.astgen.instructions.append(gpa, .{ |