authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-22 17:12:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-22 17:29:56-07:00
log2f391df2a7ea7cc6e7500da214100fb49ea8f661
tree3f8a6f32559b15d1a6388e874489dfd7a1e91efb
parent9f0b9b8da1a111d16eb8d1254212ff98a8b4be08

stage2: Sema improvements and boolean logic astgen

* add `Module.setBlockBody` and related functions * redo astgen for `and` and `or` to use fewer ZIR instructions and require less processing for comptime known values * Sema: rework `analyzeBody` function. See the new doc comments in this commit. Divides ZIR instructions up into 3 categories: - always noreturn - never noreturn - sometimes noreturn

4 files changed, 512 insertions(+), 415 deletions(-)

src/Module.zig+78-47
...@@ -477,7 +477,7 @@ pub const Scope = struct {...@@ -477,7 +477,7 @@ pub const Scope = struct {
477 switch (scope.tag) {477 switch (scope.tag) {
478 .file => return &scope.cast(File).?.tree,478 .file => return &scope.cast(File).?.tree,
479 .block => return &scope.cast(Block).?.src_decl.container.file_scope.tree,479 .block => return &scope.cast(Block).?.src_decl.container.file_scope.tree,
480 .gen_zir => return &scope.cast(GenZir).?.zir_code.decl.container.file_scope.tree,480 .gen_zir => return scope.cast(GenZir).?.tree(),
481 .local_val => return &scope.cast(LocalVal).?.gen_zir.zir_code.decl.container.file_scope.tree,481 .local_val => return &scope.cast(LocalVal).?.gen_zir.zir_code.decl.container.file_scope.tree,
482 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.zir_code.decl.container.file_scope.tree,482 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.zir_code.decl.container.file_scope.tree,
483 .container => return &scope.cast(Container).?.file_scope.tree,483 .container => return &scope.cast(Container).?.file_scope.tree,
...@@ -983,6 +983,30 @@ pub const Scope = struct {...@@ -983,6 +983,30 @@ pub const Scope = struct {
983 return gz.zir_code.decl.nodeSrcLoc(node_index);983 return gz.zir_code.decl.nodeSrcLoc(node_index);
984 }984 }
985985
986 pub fn tree(gz: *const GenZir) *const ast.Tree {
987 return &gz.zir_code.decl.container.file_scope.tree;
988 }
989
990 pub fn setBoolBrBody(gz: GenZir, inst: zir.Inst.Index) !void {
991 try gz.zir_code.extra.ensureCapacity(gz.zir_code.gpa, gz.zir_code.extra.items.len +
992 @typeInfo(zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
993 const zir_datas = gz.zir_code.instructions.items(.data);
994 zir_datas[inst].bool_br.payload_index = gz.zir_code.addExtraAssumeCapacity(
995 zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
996 );
997 gz.zir_code.extra.appendSliceAssumeCapacity(gz.instructions.items);
998 }
999
1000 pub fn setBlockBody(gz: GenZir, inst: zir.Inst.Index) !void {
1001 try gz.zir_code.extra.ensureCapacity(gz.zir_code.gpa, gz.zir_code.extra.items.len +
1002 @typeInfo(zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);
1003 const zir_datas = gz.zir_code.instructions.items(.data);
1004 zir_datas[inst].pl_node.payload_index = gz.zir_code.addExtraAssumeCapacity(
1005 zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
1006 );
1007 gz.zir_code.extra.appendSliceAssumeCapacity(gz.instructions.items);
1008 }
1009
986 pub fn addFnTypeCc(gz: *GenZir, tag: zir.Inst.Tag, args: struct {1010 pub fn addFnTypeCc(gz: *GenZir, tag: zir.Inst.Tag, args: struct {
987 param_types: []const zir.Inst.Ref,1011 param_types: []const zir.Inst.Ref,
988 ret_ty: zir.Inst.Ref,1012 ret_ty: zir.Inst.Ref,
...@@ -1044,73 +1068,62 @@ pub const Scope = struct {...@@ -1044,73 +1068,62 @@ pub const Scope = struct {
1044 return new_index + gz.zir_code.ref_start_index;1068 return new_index + gz.zir_code.ref_start_index;
1045 }1069 }
10461070
1047 pub fn addCondBr(1071 pub fn addCall(
1048 gz: *GenZir,1072 gz: *GenZir,
1049 condition: zir.Inst.Ref,1073 tag: zir.Inst.Tag,
1050 then_body: []const zir.Inst.Ref,1074 callee: zir.Inst.Ref,
1051 else_body: []const zir.Inst.Ref,1075 args: []const zir.Inst.Ref,
1052 /// Absolute node index. This function does the conversion to offset from Decl.1076 /// Absolute node index. This function does the conversion to offset from Decl.
1053 abs_node_index: ast.Node.Index,1077 abs_node_index: ast.Node.Index,
1054 ) !zir.Inst.Ref {1078 ) !zir.Inst.Index {
1079 assert(callee != 0);
1080 assert(abs_node_index != 0);
1055 const gpa = gz.zir_code.gpa;1081 const gpa = gz.zir_code.gpa;
1056 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1082 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1057 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);1083 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
1058 try gz.zir_code.extra.ensureCapacity(gpa, gz.zir_code.extra.items.len +1084 try gz.zir_code.extra.ensureCapacity(gpa, gz.zir_code.extra.items.len +
1059 @typeInfo(zir.Inst.CondBr).Struct.fields.len + then_body.len + else_body.len);1085 @typeInfo(zir.Inst.Call).Struct.fields.len + args.len);
10601086
1061 const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.CondBr{1087 const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.Call{
1062 .condition = condition,1088 .callee = callee,
1063 .then_body_len = @intCast(u32, then_body.len),1089 .args_len = @intCast(u32, args.len),
1064 .else_body_len = @intCast(u32, else_body.len),
1065 });1090 });
1066 gz.zir_code.extra.appendSliceAssumeCapacity(then_body);1091 gz.zir_code.extra.appendSliceAssumeCapacity(args);
1067 gz.zir_code.extra.appendSliceAssumeCapacity(else_body);
10681092
1069 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);1093 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1070 gz.zir_code.instructions.appendAssumeCapacity(.{1094 gz.zir_code.instructions.appendAssumeCapacity(.{
1071 .tag = .condbr,1095 .tag = tag,
1072 .data = .{ .pl_node = .{1096 .data = .{ .pl_node = .{
1073 .src_node = gz.zir_code.decl.nodeIndexToRelative(abs_node_index),1097 .src_node = gz.zir_code.decl.nodeIndexToRelative(abs_node_index),
1074 .payload_index = payload_index,1098 .payload_index = payload_index,
1075 } },1099 } },
1076 });1100 });
1077 gz.instructions.appendAssumeCapacity(new_index);1101 gz.instructions.appendAssumeCapacity(new_index);
1078
1079 return new_index + gz.zir_code.ref_start_index;1102 return new_index + gz.zir_code.ref_start_index;
1080 }1103 }
10811104
1082 pub fn addCall(1105 /// Note that this returns a `zir.Inst.Index` not a ref.
1106 /// Leaves the `payload_index` field undefined.
1107 pub fn addBoolBr(
1083 gz: *GenZir,1108 gz: *GenZir,
1084 tag: zir.Inst.Tag,1109 tag: zir.Inst.Tag,
1085 callee: zir.Inst.Ref,1110 lhs: zir.Inst.Ref,
1086 args: []const zir.Inst.Ref,
1087 /// Absolute node index. This function does the conversion to offset from Decl.
1088 abs_node_index: ast.Node.Index,
1089 ) !zir.Inst.Index {1111 ) !zir.Inst.Index {
1090 assert(callee != 0);1112 assert(lhs != 0);
1091 assert(abs_node_index != 0);
1092 const gpa = gz.zir_code.gpa;1113 const gpa = gz.zir_code.gpa;
1093 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1114 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1094 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);1115 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
1095 try gz.zir_code.extra.ensureCapacity(gpa, gz.zir_code.extra.items.len +
1096 @typeInfo(zir.Inst.Call).Struct.fields.len + args.len);
1097
1098 const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.Call{
1099 .callee = callee,
1100 .args_len = @intCast(u32, args.len),
1101 });
1102 gz.zir_code.extra.appendSliceAssumeCapacity(args);
11031116
1104 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);1117 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1105 gz.zir_code.instructions.appendAssumeCapacity(.{1118 gz.zir_code.instructions.appendAssumeCapacity(.{
1106 .tag = tag,1119 .tag = tag,
1107 .data = .{ .pl_node = .{1120 .data = .{ .bool_br = .{
1108 .src_node = gz.zir_code.decl.nodeIndexToRelative(abs_node_index),1121 .lhs = lhs,
1109 .payload_index = payload_index,1122 .payload_index = undefined,
1110 } },1123 } },
1111 });1124 });
1112 gz.instructions.appendAssumeCapacity(new_index);1125 gz.instructions.appendAssumeCapacity(new_index);
1113 return new_index + gz.zir_code.ref_start_index;1126 return new_index;
1114 }1127 }
11151128
1116 pub fn addInt(gz: *GenZir, integer: u64) !zir.Inst.Ref {1129 pub fn addInt(gz: *GenZir, integer: u64) !zir.Inst.Ref {
...@@ -1291,6 +1304,20 @@ pub const Scope = struct {...@@ -1291,6 +1304,20 @@ pub const Scope = struct {
1291 return new_index;1304 return new_index;
1292 }1305 }
12931306
1307 /// Note that this returns a `zir.Inst.Index` not a ref.
1308 /// Leaves the `payload_index` field undefined.
1309 pub fn addCondBr(gz: *GenZir, node: ast.Node.Index) !zir.Inst.Index {
1310 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1311 try gz.zir_code.instructions.append(gz.zir_code.gpa, .{
1312 .tag = .condbr,
1313 .data = .{ .pl_node = .{
1314 .src_node = gz.zir_code.decl.nodeIndexToRelative(node),
1315 .payload_index = undefined,
1316 } },
1317 });
1318 return new_index;
1319 }
1320
1294 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {1321 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
1295 const gpa = gz.zir_code.gpa;1322 const gpa = gz.zir_code.gpa;
1296 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1323 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
...@@ -1409,9 +1436,9 @@ pub const WipZirCode = struct {...@@ -1409,9 +1436,9 @@ pub const WipZirCode = struct {
1409 .bitcast_result_ptr,1436 .bitcast_result_ptr,
1410 .bit_or,1437 .bit_or,
1411 .block,1438 .block,
1412 .block_flat,
1413 .block_comptime,1439 .block_comptime,
1414 .block_comptime_flat,1440 .bool_br_and,
1441 .bool_br_or,
1415 .bool_not,1442 .bool_not,
1416 .bool_and,1443 .bool_and,
1417 .bool_or,1444 .bool_or,
...@@ -1461,9 +1488,6 @@ pub const WipZirCode = struct {...@@ -1461,9 +1488,6 @@ pub const WipZirCode = struct {
1461 .ret_type,1488 .ret_type,
1462 .shl,1489 .shl,
1463 .shr,1490 .shr,
1464 .store,
1465 .store_to_block_ptr,
1466 .store_to_inferred_ptr,
1467 .str,1491 .str,
1468 .sub,1492 .sub,
1469 .subwrap,1493 .subwrap,
...@@ -1497,7 +1521,6 @@ pub const WipZirCode = struct {...@@ -1497,7 +1521,6 @@ pub const WipZirCode = struct {
1497 .slice_sentinel,1521 .slice_sentinel,
1498 .import,1522 .import,
1499 .typeof_peer,1523 .typeof_peer,
1500 .resolve_inferred_alloc,
1501 => return false,1524 => return false,
15021525
1503 .breakpoint,1526 .breakpoint,
...@@ -1509,6 +1532,7 @@ pub const WipZirCode = struct {...@@ -1509,6 +1532,7 @@ pub const WipZirCode = struct {
1509 .ensure_err_payload_void,1532 .ensure_err_payload_void,
1510 .@"break",1533 .@"break",
1511 .break_void_tok,1534 .break_void_tok,
1535 .break_flat,
1512 .condbr,1536 .condbr,
1513 .compile_error,1537 .compile_error,
1514 .ret_node,1538 .ret_node,
...@@ -1517,6 +1541,10 @@ pub const WipZirCode = struct {...@@ -1517,6 +1541,10 @@ pub const WipZirCode = struct {
1517 .@"unreachable",1541 .@"unreachable",
1518 .loop,1542 .loop,
1519 .elided,1543 .elided,
1544 .store,
1545 .store_to_block_ptr,
1546 .store_to_inferred_ptr,
1547 .resolve_inferred_alloc,
1520 => return true,1548 => return true,
1521 }1549 }
1522 }1550 }
...@@ -2150,7 +2178,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2150,7 +2178,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
2150 };2178 };
2151 defer block_scope.instructions.deinit(mod.gpa);2179 defer block_scope.instructions.deinit(mod.gpa);
21522180
2153 try sema.root(&block_scope);2181 _ = try sema.root(&block_scope);
21542182
2155 decl.analysis = .complete;2183 decl.analysis = .complete;
2156 decl.generation = mod.generation;2184 decl.generation = mod.generation;
...@@ -2338,6 +2366,7 @@ fn astgenAndSemaFn(...@@ -2338,6 +2366,7 @@ fn astgenAndSemaFn(
2338 const tag: zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type;2366 const tag: zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type;
2339 break :fn_type try fn_type_scope.addFnType(tag, return_type_inst, param_types);2367 break :fn_type try fn_type_scope.addFnType(tag, return_type_inst, param_types);
2340 };2368 };
2369 _ = try fn_type_scope.addUnNode(.break_flat, fn_type_inst, 0);
23412370
2342 // We need the memory for the Type to go into the arena for the Decl2371 // We need the memory for the Type to go into the arena for the Decl
2343 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);2372 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
...@@ -2370,7 +2399,7 @@ fn astgenAndSemaFn(...@@ -2370,7 +2399,7 @@ fn astgenAndSemaFn(
2370 };2399 };
2371 defer block_scope.instructions.deinit(mod.gpa);2400 defer block_scope.instructions.deinit(mod.gpa);
23722401
2373 const fn_type = try fn_type_sema.rootAsType(&block_scope, fn_type_inst);2402 const fn_type = try fn_type_sema.rootAsType(&block_scope);
2374 if (body_node == 0) {2403 if (body_node == 0) {
2375 if (!is_extern) {2404 if (!is_extern) {
2376 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});2405 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});
...@@ -2650,6 +2679,7 @@ fn astgenAndSemaVarDecl(...@@ -2650,6 +2679,7 @@ fn astgenAndSemaVarDecl(
2650 init_result_loc,2679 init_result_loc,
2651 var_decl.ast.init_node,2680 var_decl.ast.init_node,
2652 );2681 );
2682 _ = try gen_scope.addUnNode(.break_flat, init_inst, var_decl.ast.init_node);
2653 var code = try gen_scope.finish();2683 var code = try gen_scope.finish();
2654 defer code.deinit(mod.gpa);2684 defer code.deinit(mod.gpa);
2655 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2685 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
...@@ -2676,10 +2706,9 @@ fn astgenAndSemaVarDecl(...@@ -2676,10 +2706,9 @@ fn astgenAndSemaVarDecl(
2676 };2706 };
2677 defer block_scope.instructions.deinit(mod.gpa);2707 defer block_scope.instructions.deinit(mod.gpa);
26782708
2679 try sema.root(&block_scope);2709 const init_inst_zir_ref = try sema.root(&block_scope);
2680
2681 // The result location guarantees the type coercion.2710 // The result location guarantees the type coercion.
2682 const analyzed_init_inst = try sema.resolveInst(init_inst);2711 const analyzed_init_inst = try sema.resolveInst(init_inst_zir_ref);
2683 // The is_comptime in the Scope.Block guarantees the result is comptime-known.2712 // The is_comptime in the Scope.Block guarantees the result is comptime-known.
2684 const val = analyzed_init_inst.value().?;2713 const val = analyzed_init_inst.value().?;
26852714
...@@ -2713,6 +2742,8 @@ fn astgenAndSemaVarDecl(...@@ -2713,6 +2742,8 @@ fn astgenAndSemaVarDecl(
2713 defer type_scope.instructions.deinit(mod.gpa);2742 defer type_scope.instructions.deinit(mod.gpa);
27142743
2715 const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node);2744 const var_type = try astgen.typeExpr(mod, &type_scope.base, var_decl.ast.type_node);
2745 _ = try type_scope.addUnNode(.break_flat, var_type, 0);
2746
2716 var code = try type_scope.finish();2747 var code = try type_scope.finish();
2717 defer code.deinit(mod.gpa);2748 defer code.deinit(mod.gpa);
2718 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2749 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
...@@ -2739,7 +2770,7 @@ fn astgenAndSemaVarDecl(...@@ -2739,7 +2770,7 @@ fn astgenAndSemaVarDecl(
2739 };2770 };
2740 defer block_scope.instructions.deinit(mod.gpa);2771 defer block_scope.instructions.deinit(mod.gpa);
27412772
2742 const ty = try sema.rootAsType(&block_scope, var_type);2773 const ty = try sema.rootAsType(&block_scope);
27432774
2744 break :vi .{2775 break :vi .{
2745 .ty = try ty.copy(&decl_arena.allocator),2776 .ty = try ty.copy(&decl_arena.allocator),
...@@ -3328,7 +3359,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {...@@ -3328,7 +3359,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {
3328 func.state = .in_progress;3359 func.state = .in_progress;
3329 log.debug("set {s} to in_progress", .{decl.name});3360 log.debug("set {s} to in_progress", .{decl.name});
33303361
3331 try sema.root(&inner_block);3362 _ = try sema.root(&inner_block);
33323363
3333 const instructions = try arena.allocator.dupe(*ir.Inst, inner_block.instructions.items);3364 const instructions = try arena.allocator.dupe(*ir.Inst, inner_block.instructions.items);
3334 func.state = .success;3365 func.state = .success;
src/Sema.zig+343-258
...@@ -53,172 +53,230 @@ const InnerError = Module.InnerError;...@@ -53,172 +53,230 @@ const InnerError = Module.InnerError;
53const Decl = Module.Decl;53const Decl = Module.Decl;
54const LazySrcLoc = Module.LazySrcLoc;54const LazySrcLoc = Module.LazySrcLoc;
5555
56pub fn root(sema: *Sema, root_block: *Scope.Block) !void {56pub fn root(sema: *Sema, root_block: *Scope.Block) !zir.Inst.Ref {
57 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];57 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];
58 return sema.analyzeBody(root_block, root_body);58 return sema.analyzeBody(root_block, root_body);
59}59}
6060
61pub fn rootAsType(sema: *Sema, root_block: *Scope.Block, result_inst: zir.Inst.Ref) !Type {61/// Assumes that `root_block` ends with `break_flat`.
62 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];62pub fn rootAsType(sema: *Sema, root_block: *Scope.Block) !Type {
63 try sema.analyzeBody(root_block, root_body);63 const zir_inst_ref = try sema.root(root_block);
64
65 // Source location is unneeded because resolveConstValue must have already64 // Source location is unneeded because resolveConstValue must have already
66 // been successfully called when coercing the value to a type, from the65 // been successfully called when coercing the value to a type, from the
67 // result location.66 // result location.
68 return sema.resolveType(root_block, .unneeded, result_inst);67 return sema.resolveType(root_block, .unneeded, zir_inst_ref);
69}68}
7069
71pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !void {70/// ZIR instructions which are always `noreturn` return this. This matches the
72 const tracy = trace(@src());71/// return type of `analyzeBody` so that we can tail call them.
73 defer tracy.end();72/// Only appropriate to return when the instruction is known to be NoReturn
73/// solely based on the ZIR tag.
74const always_noreturn: InnerError!zir.Inst.Ref = @as(zir.Inst.Index, 0);
75
76/// This function is the main loop of `Sema` and it can be used in two different ways:
77/// * The traditional way where there are N breaks out of the block and peer type
78/// resolution is done on the break operands. In this case, the `zir.Inst.Index`
79/// part of the return value will be `undefined`, and callsites should ignore it,
80/// finding the block result value via the block scope.
81/// * The "flat" way. There is only 1 break out of the block, and it is with a `break_flat`
82/// instruction. In this case, the `zir.Inst.Index` part of the return value will be
83/// the block result value. No block scope needs to be created for this strategy.
84pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !zir.Inst.Index {
85 // No tracy calls here, to avoid interfering with the tail call mechanism.
7486
75 const map = block.sema.inst_map;87 const map = block.sema.inst_map;
76 const tags = block.sema.code.instructions.items(.tag);88 const tags = block.sema.code.instructions.items(.tag);
7789
78 // TODO: As an optimization, look into making these switch prongs directly jump90 // We use a while(true) loop here to avoid a redundant way of breaking out of
79 // to the next one, rather than detouring through the loop condition.91 // the loop. The only way to break out of the loop is with a `noreturn`
80 // Also, look into leaving only the "noreturn" loop break condition, and removing92 // instruction.
81 // the iteration based one. Better yet, have an extra entry in the tags array as a93 // TODO: As an optimization, make sure the codegen for these switch prongs
82 // sentinel, so that exiting the loop is just another jump table prong.94 // directly jump to the next one, rather than detouring through the loop
83 // Related: https://github.com/ziglang/zig/issues/822095 // continue expression. Related: https://github.com/ziglang/zig/issues/8220
84 for (body) |zir_inst| {96 var i: usize = 0;
85 map[zir_inst] = switch (tags[zir_inst]) {97 while (true) : (i += 1) {
86 .alloc => try sema.zirAlloc(block, zir_inst),98 const inst = body[i];
87 .alloc_mut => try sema.zirAllocMut(block, zir_inst),99 map[inst] = switch (tags[inst]) {
88 .alloc_inferred => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_const)),
89 .alloc_inferred_mut => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_mut)),
90 .bitcast_ref => try sema.zirBitcastRef(block, zir_inst),
91 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, zir_inst),
92 .block => try sema.zirBlock(block, zir_inst, false),
93 .block_comptime => try sema.zirBlock(block, zir_inst, true),
94 .block_flat => try sema.zirBlockFlat(block, zir_inst, false),
95 .block_comptime_flat => try sema.zirBlockFlat(block, zir_inst, true),
96 .@"break" => try sema.zirBreak(block, zir_inst),
97 .break_void_tok => try sema.zirBreakVoidTok(block, zir_inst),
98 .breakpoint => try sema.zirBreakpoint(block, zir_inst),
99 .call => try sema.zirCall(block, zir_inst, .auto),
100 .call_compile_time => try sema.zirCall(block, zir_inst, .compile_time),
101 .call_none => try sema.zirCallNone(block, zir_inst),
102 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, zir_inst),
103 .compile_error => try sema.zirCompileError(block, zir_inst),
104 .compile_log => try sema.zirCompileLog(block, zir_inst),
105 .@"const" => try sema.zirConst(block, zir_inst),
106 .dbg_stmt_node => try sema.zirDbgStmtNode(block, zir_inst),
107 .decl_ref => try sema.zirDeclRef(block, zir_inst),
108 .decl_val => try sema.zirDeclVal(block, zir_inst),
109 .elided => continue,100 .elided => continue,
110 .ensure_result_used => try sema.zirEnsureResultUsed(block, zir_inst),101
111 .ensure_result_non_error => try sema.zirEnsureResultNonError(block, zir_inst),102 .add => try sema.zirArithmetic(block, inst),
112 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, zir_inst),103 .addwrap => try sema.zirArithmetic(block, inst),
113 .ref => try sema.zirRef(block, zir_inst),104 .alloc => try sema.zirAlloc(block, inst),
114 .resolve_inferred_alloc => try sema.zirResolveInferredAlloc(block, zir_inst),105 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
115 .ret_ptr => try sema.zirRetPtr(block, zir_inst),106 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
116 .ret_type => try sema.zirRetType(block, zir_inst),107 .alloc_mut => try sema.zirAllocMut(block, inst),
117 .store_to_block_ptr => try sema.zirStoreToBlockPtr(block, zir_inst),108 .array_cat => try sema.zirArrayCat(block, inst),
118 .store_to_inferred_ptr => try sema.zirStoreToInferredPtr(block, zir_inst),109 .array_mul => try sema.zirArrayMul(block, inst),
119 .ptr_type_simple => try sema.zirPtrTypeSimple(block, zir_inst),110 .array_type => try sema.zirArrayType(block, inst),
120 .ptr_type => try sema.zirPtrType(block, zir_inst),111 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
121 .store => try sema.zirStore(block, zir_inst),112 .as => try sema.zirAs(block, inst),
122 .set_eval_branch_quota => try sema.zirSetEvalBranchQuota(block, zir_inst),113 .as_node => try sema.zirAsNode(block, inst),
123 .str => try sema.zirStr(block, zir_inst),114 .@"asm" => try sema.zirAsm(block, inst, false),
124 .int => try sema.zirInt(block, zir_inst),115 .asm_volatile => try sema.zirAsm(block, inst, true),
125 .int_type => try sema.zirIntType(block, zir_inst),116 .bit_and => try sema.zirBitwise(block, inst),
126 .loop => try sema.zirLoop(block, zir_inst),117 .bit_not => try sema.zirBitNot(block, inst),
127 .param_type => try sema.zirParamType(block, zir_inst),118 .bit_or => try sema.zirBitwise(block, inst),
128 .ptrtoint => try sema.zirPtrtoint(block, zir_inst),119 .bitcast => try sema.zirBitcast(block, inst),
129 .field_ptr => try sema.zirFieldPtr(block, zir_inst),120 .bitcast_ref => try sema.zirBitcastRef(block, inst),
130 .field_val => try sema.zirFieldVal(block, zir_inst),121 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
131 .field_ptr_named => try sema.zirFieldPtrNamed(block, zir_inst),122 .block => try sema.zirBlock(block, inst, false),
132 .field_val_named => try sema.zirFieldValNamed(block, zir_inst),123 .block_comptime => try sema.zirBlock(block, inst, true),
133 .deref_node => try sema.zirDerefNode(block, zir_inst),124 .bool_not => try sema.zirBoolNot(block, inst),
134 .as => try sema.zirAs(block, zir_inst),125 .bool_and => try sema.zirBoolOp(block, inst, false),
135 .as_node => try sema.zirAsNode(block, zir_inst),126 .bool_or => try sema.zirBoolOp(block, inst, true),
136 .@"asm" => try sema.zirAsm(block, zir_inst, false),127 .bool_br_and => try sema.zirBoolBr(block, inst, false),
137 .asm_volatile => try sema.zirAsm(block, zir_inst, true),128 .bool_br_or => try sema.zirBoolBr(block, inst, true),
138 .@"unreachable" => try sema.zirUnreachable(block, zir_inst),129 .call => try sema.zirCall(block, inst, .auto),
139 .ret_coerce => try sema.zirRetTok(block, zir_inst, true),130 .call_compile_time => try sema.zirCall(block, inst, .compile_time),
140 .ret_tok => try sema.zirRetTok(block, zir_inst, false),131 .call_none => try sema.zirCallNone(block, inst),
141 .ret_node => try sema.zirRetNode(block, zir_inst),132 .cmp_eq => try sema.zirCmp(block, inst, .eq),
142 .fn_type => try sema.zirFnType(block, zir_inst, false),133 .cmp_gt => try sema.zirCmp(block, inst, .gt),
143 .fn_type_cc => try sema.zirFnTypeCc(block, zir_inst, false),134 .cmp_gte => try sema.zirCmp(block, inst, .gte),
144 .fn_type_var_args => try sema.zirFnType(block, zir_inst, true),135 .cmp_lt => try sema.zirCmp(block, inst, .lt),
145 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, zir_inst, true),136 .cmp_lte => try sema.zirCmp(block, inst, .lte),
146 .intcast => try sema.zirIntcast(block, zir_inst),137 .cmp_neq => try sema.zirCmp(block, inst, .neq),
147 .bitcast => try sema.zirBitcast(block, zir_inst),138 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
148 .floatcast => try sema.zirFloatcast(block, zir_inst),139 .@"const" => try sema.zirConst(block, inst),
149 .elem_ptr => try sema.zirElemPtr(block, zir_inst),140 .decl_ref => try sema.zirDeclRef(block, inst),
150 .elem_ptr_node => try sema.zirElemPtrNode(block, zir_inst),141 .decl_val => try sema.zirDeclVal(block, inst),
151 .elem_val => try sema.zirElemVal(block, zir_inst),142 .deref_node => try sema.zirDerefNode(block, inst),
152 .elem_val_node => try sema.zirElemValNode(block, zir_inst),143 .div => try sema.zirArithmetic(block, inst),
153 .add => try sema.zirArithmetic(block, zir_inst),144 .elem_ptr => try sema.zirElemPtr(block, inst),
154 .addwrap => try sema.zirArithmetic(block, zir_inst),145 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
155 .sub => try sema.zirArithmetic(block, zir_inst),146 .elem_val => try sema.zirElemVal(block, inst),
156 .subwrap => try sema.zirArithmetic(block, zir_inst),147 .elem_val_node => try sema.zirElemValNode(block, inst),
148 .enum_literal => try sema.zirEnumLiteral(block, inst),
149 .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),
150 .err_union_code => try sema.zirErrUnionCode(block, inst),
151 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
152 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
153 .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
154 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
155 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
156 .error_set => try sema.zirErrorSet(block, inst),
157 .error_union_type => try sema.zirErrorUnionType(block, inst),
158 .error_value => try sema.zirErrorValue(block, inst),
159 .field_ptr => try sema.zirFieldPtr(block, inst),
160 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
161 .field_val => try sema.zirFieldVal(block, inst),
162 .field_val_named => try sema.zirFieldValNamed(block, inst),
163 .floatcast => try sema.zirFloatcast(block, inst),
164 .fn_type => try sema.zirFnType(block, inst, false),
165 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
166 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
167 .fn_type_var_args => try sema.zirFnType(block, inst, true),
168 .import => try sema.zirImport(block, inst),
169 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
170 .int => try sema.zirInt(block, inst),
171 .int_type => try sema.zirIntType(block, inst),
172 .intcast => try sema.zirIntcast(block, inst),
173 .is_err => try sema.zirIsErr(block, inst),
174 .is_err_ptr => try sema.zirIsErrPtr(block, inst),
175 .is_non_null => try sema.zirIsNull(block, inst, true),
176 .is_non_null_ptr => try sema.zirIsNullPtr(block, inst, true),
177 .is_null => try sema.zirIsNull(block, inst, false),
178 .is_null_ptr => try sema.zirIsNullPtr(block, inst, false),
179 .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
180 .mod_rem => try sema.zirArithmetic(block, inst),
181 .mul => try sema.zirArithmetic(block, inst),
182 .mulwrap => try sema.zirArithmetic(block, inst),
157 .negate => @panic("TODO"),183 .negate => @panic("TODO"),
158 .negate_wrap => @panic("TODO"),184 .negate_wrap => @panic("TODO"),
159 .mul => try sema.zirArithmetic(block, zir_inst),185 .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
160 .mulwrap => try sema.zirArithmetic(block, zir_inst),186 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
161 .div => try sema.zirArithmetic(block, zir_inst),187 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
162 .mod_rem => try sema.zirArithmetic(block, zir_inst),188 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
163 .array_cat => try sema.zirArrayCat(block, zir_inst),189 .optional_type => try sema.zirOptionalType(block, inst),
164 .array_mul => try sema.zirArrayMul(block, zir_inst),190 .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, inst),
165 .bit_and => try sema.zirBitwise(block, zir_inst),191 .param_type => try sema.zirParamType(block, inst),
166 .bit_not => try sema.zirBitNot(block, zir_inst),192 .ptr_type => try sema.zirPtrType(block, inst),
167 .bit_or => try sema.zirBitwise(block, zir_inst),193 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
168 .xor => try sema.zirBitwise(block, zir_inst),194 .ptrtoint => try sema.zirPtrtoint(block, inst),
169 .shl => try sema.zirShl(block, zir_inst),195 .ref => try sema.zirRef(block, inst),
170 .shr => try sema.zirShr(block, zir_inst),196 .ret_ptr => try sema.zirRetPtr(block, inst),
171 .cmp_lt => try sema.zirCmp(block, zir_inst, .lt),197 .ret_type => try sema.zirRetType(block, inst),
172 .cmp_lte => try sema.zirCmp(block, zir_inst, .lte),198 .shl => try sema.zirShl(block, inst),
173 .cmp_eq => try sema.zirCmp(block, zir_inst, .eq),199 .shr => try sema.zirShr(block, inst),
174 .cmp_gte => try sema.zirCmp(block, zir_inst, .gte),200 .slice_end => try sema.zirSliceEnd(block, inst),
175 .cmp_gt => try sema.zirCmp(block, zir_inst, .gt),201 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
176 .cmp_neq => try sema.zirCmp(block, zir_inst, .neq),202 .slice_start => try sema.zirSliceStart(block, inst),
177 .condbr => try sema.zirCondbr(block, zir_inst),203 .str => try sema.zirStr(block, inst),
178 .is_null => try sema.zirIsNull(block, zir_inst, false),204 .sub => try sema.zirArithmetic(block, inst),
179 .is_non_null => try sema.zirIsNull(block, zir_inst, true),205 .subwrap => try sema.zirArithmetic(block, inst),
180 .is_null_ptr => try sema.zirIsNullPtr(block, zir_inst, false),206 .typeof => try sema.zirTypeof(block, inst),
181 .is_non_null_ptr => try sema.zirIsNullPtr(block, zir_inst, true),207 .typeof_peer => try sema.zirTypeofPeer(block, inst),
182 .is_err => try sema.zirIsErr(block, zir_inst),208 .xor => try sema.zirBitwise(block, inst),
183 .is_err_ptr => try sema.zirIsErrPtr(block, zir_inst),
184 .bool_not => try sema.zirBoolNot(block, zir_inst),
185 .typeof => try sema.zirTypeof(block, zir_inst),
186 .typeof_peer => try sema.zirTypeofPeer(block, zir_inst),
187 .optional_type => try sema.zirOptionalType(block, zir_inst),
188 .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, zir_inst),
189 .optional_payload_safe => try sema.zirOptionalPayload(block, zir_inst, true),
190 .optional_payload_unsafe => try sema.zirOptionalPayload(block, zir_inst, false),
191 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, true),
192 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, false),
193 .err_union_payload_safe => try sema.zirErrUnionPayload(block, zir_inst, true),
194 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, zir_inst, false),
195 .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, true),
196 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, false),
197 .err_union_code => try sema.zirErrUnionCode(block, zir_inst),
198 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, zir_inst),
199 .ensure_err_payload_void => try sema.zirEnsureErrPayloadVoid(block, zir_inst),
200 .array_type => try sema.zirArrayType(block, zir_inst),
201 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, zir_inst),
202 .enum_literal => try sema.zirEnumLiteral(block, zir_inst),
203 .enum_literal_small => try sema.zirEnumLiteralSmall(block, zir_inst),
204 .merge_error_sets => try sema.zirMergeErrorSets(block, zir_inst),
205 .error_union_type => try sema.zirErrorUnionType(block, zir_inst),
206 .error_set => try sema.zirErrorSet(block, zir_inst),
207 .error_value => try sema.zirErrorValue(block, zir_inst),
208 .slice_start => try sema.zirSliceStart(block, zir_inst),
209 .slice_end => try sema.zirSliceEnd(block, zir_inst),
210 .slice_sentinel => try sema.zirSliceSentinel(block, zir_inst),
211 .import => try sema.zirImport(block, zir_inst),
212 .bool_and => try sema.zirBoolOp(block, zir_inst, false),
213 .bool_or => try sema.zirBoolOp(block, zir_inst, true),
214 // TODO209 // TODO
215 //.switchbr => try sema.zirSwitchBr(block, zir_inst, false),210 //.switchbr => try sema.zirSwitchBr(block, inst, false),
216 //.switchbr_ref => try sema.zirSwitchBr(block, zir_inst, true),211 //.switchbr_ref => try sema.zirSwitchBr(block, inst, true),
217 //.switch_range => try sema.zirSwitchRange(block, zir_inst),212 //.switch_range => try sema.zirSwitchRange(block, inst),
213
214 // Instructions that we know to *always* be noreturn based solely on their tag.
215 // These functions match the return type of analyzeBody so that we can
216 // tail call them here.
217 .condbr => return sema.zirCondbr(block, inst),
218 .@"break" => return sema.zirBreak(block, inst),
219 .break_void_tok => return sema.zirBreakVoidTok(block, inst),
220 .break_flat => return sema.code.instructions.items(.data)[inst].un_node.operand,
221 .compile_error => return sema.zirCompileError(block, inst),
222 .ret_coerce => return sema.zirRetTok(block, inst, true),
223 .ret_node => return sema.zirRetNode(block, inst),
224 .ret_tok => return sema.zirRetTok(block, inst, false),
225 .@"unreachable" => return sema.zirUnreachable(block, inst),
226 .loop => return sema.zirLoop(block, inst),
227
228 // Instructions that we know can *never* be noreturn based solely on
229 // their tag. We avoid needlessly checking if they are noreturn and
230 // continue the loop.
231 // We also know that they cannot be referenced later, so we avoid
232 // putting them into the map.
233 .breakpoint => {
234 try sema.zirBreakpoint(block, inst);
235 continue;
236 },
237 .dbg_stmt_node => {
238 try sema.zirDbgStmtNode(block, inst);
239 continue;
240 },
241 .ensure_err_payload_void => {
242 try sema.zirEnsureErrPayloadVoid(block, inst);
243 continue;
244 },
245 .ensure_result_non_error => {
246 try sema.zirEnsureResultNonError(block, inst);
247 continue;
248 },
249 .ensure_result_used => {
250 try sema.zirEnsureResultUsed(block, inst);
251 continue;
252 },
253 .compile_log => {
254 try sema.zirCompileLog(block, inst);
255 continue;
256 },
257 .set_eval_branch_quota => {
258 try sema.zirSetEvalBranchQuota(block, inst);
259 continue;
260 },
261 .store => {
262 try sema.zirStore(block, inst);
263 continue;
264 },
265 .store_to_block_ptr => {
266 try sema.zirStoreToBlockPtr(block, inst);
267 continue;
268 },
269 .store_to_inferred_ptr => {
270 try sema.zirStoreToInferredPtr(block, inst);
271 continue;
272 },
273 .resolve_inferred_alloc => {
274 try sema.zirResolveInferredAlloc(block, inst);
275 continue;
276 },
218 };277 };
219 if (map[zir_inst].ty.isNoReturn()) {278 if (map[inst].ty.isNoReturn())
220 break;279 return always_noreturn;
221 }
222 }280 }
223}281}
224282
...@@ -392,7 +450,7 @@ fn zirRetType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError...@@ -392,7 +450,7 @@ fn zirRetType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
392 return sema.mod.constType(sema.arena, src, ret_type);450 return sema.mod.constType(sema.arena, src, ret_type);
393}451}
394452
395fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {453fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
396 const tracy = trace(@src());454 const tracy = trace(@src());
397 defer tracy.end();455 defer tracy.end();
398456
...@@ -400,12 +458,12 @@ fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I...@@ -400,12 +458,12 @@ fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I
400 const operand = try sema.resolveInst(inst_data.operand);458 const operand = try sema.resolveInst(inst_data.operand);
401 const src = inst_data.src();459 const src = inst_data.src();
402 switch (operand.ty.zigTypeTag()) {460 switch (operand.ty.zigTypeTag()) {
403 .Void, .NoReturn => return sema.mod.constVoid(sema.arena, .unneeded),461 .Void, .NoReturn => return,
404 else => return sema.mod.fail(&block.base, src, "expression value is ignored", .{}),462 else => return sema.mod.fail(&block.base, src, "expression value is ignored", .{}),
405 }463 }
406}464}
407465
408fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {466fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
409 const tracy = trace(@src());467 const tracy = trace(@src());
410 defer tracy.end();468 defer tracy.end();
411469
...@@ -414,7 +472,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde...@@ -414,7 +472,7 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde
414 const src = inst_data.src();472 const src = inst_data.src();
415 switch (operand.ty.zigTypeTag()) {473 switch (operand.ty.zigTypeTag()) {
416 .ErrorSet, .ErrorUnion => return sema.mod.fail(&block.base, src, "error is discarded", .{}),474 .ErrorSet, .ErrorUnion => return sema.mod.fail(&block.base, src, "error is discarded", .{}),
417 else => return sema.mod.constVoid(sema.arena, .unneeded),475 else => return,
418 }476 }
419}477}
420478
...@@ -508,11 +566,7 @@ fn zirAllocInferred(...@@ -508,11 +566,7 @@ fn zirAllocInferred(
508 return result;566 return result;
509}567}
510568
511fn zirResolveInferredAlloc(569fn zirResolveInferredAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
512 sema: *Sema,
513 block: *Scope.Block,
514 inst: zir.Inst.Index,
515) InnerError!*Inst {
516 const tracy = trace(@src());570 const tracy = trace(@src());
517 defer tracy.end();571 defer tracy.end();
518572
...@@ -536,15 +590,9 @@ fn zirResolveInferredAlloc(...@@ -536,15 +590,9 @@ fn zirResolveInferredAlloc(
536 // Change it to a normal alloc.590 // Change it to a normal alloc.
537 ptr.ty = final_ptr_ty;591 ptr.ty = final_ptr_ty;
538 ptr.tag = .alloc;592 ptr.tag = .alloc;
539
540 return sema.mod.constVoid(sema.arena, .unneeded);
541}593}
542594
543fn zirStoreToBlockPtr(595fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
544 sema: *Sema,
545 block: *Scope.Block,
546 inst: zir.Inst.Index,
547) InnerError!*Inst {
548 const tracy = trace(@src());596 const tracy = trace(@src());
549 defer tracy.end();597 defer tracy.end();
550598
...@@ -560,11 +608,7 @@ fn zirStoreToBlockPtr(...@@ -560,11 +608,7 @@ fn zirStoreToBlockPtr(
560 return sema.storePtr(block, src, bitcasted_ptr, value);608 return sema.storePtr(block, src, bitcasted_ptr, value);
561}609}
562610
563fn zirStoreToInferredPtr(611fn zirStoreToInferredPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
564 sema: *Sema,
565 block: *Scope.Block,
566 inst: zir.Inst.Index,
567) InnerError!*Inst {
568 const tracy = trace(@src());612 const tracy = trace(@src());
569 defer tracy.end();613 defer tracy.end();
570614
...@@ -583,21 +627,16 @@ fn zirStoreToInferredPtr(...@@ -583,21 +627,16 @@ fn zirStoreToInferredPtr(
583 return sema.storePtr(block, src, bitcasted_ptr, value);627 return sema.storePtr(block, src, bitcasted_ptr, value);
584}628}
585629
586fn zirSetEvalBranchQuota(630fn zirSetEvalBranchQuota(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
587 sema: *Sema,
588 block: *Scope.Block,
589 inst: zir.Inst.Index,
590) InnerError!*Inst {
591 const inst_data = sema.code.instructions.items(.data)[inst].un_node;631 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
592 const src = inst_data.src();632 const src = inst_data.src();
593 try sema.requireFunctionBlock(block, src);633 try sema.requireFunctionBlock(block, src);
594 const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32);634 const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32);
595 if (sema.branch_quota < quota)635 if (sema.branch_quota < quota)
596 sema.branch_quota = quota;636 sema.branch_quota = quota;
597 return sema.mod.constVoid(sema.arena, .unneeded);
598}637}
599638
600fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {639fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
601 const tracy = trace(@src());640 const tracy = trace(@src());
602 defer tracy.end();641 defer tracy.end();
603642
...@@ -677,7 +716,7 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In...@@ -677,7 +716,7 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In
677 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);716 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
678}717}
679718
680fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {719fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
681 const tracy = trace(@src());720 const tracy = trace(@src());
682 defer tracy.end();721 defer tracy.end();
683722
...@@ -688,7 +727,7 @@ fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner...@@ -688,7 +727,7 @@ fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) Inner
688 return sema.mod.fail(&block.base, src, "{s}", .{msg});727 return sema.mod.fail(&block.base, src, "{s}", .{msg});
689}728}
690729
691fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {730fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
692 var managed = sema.mod.compile_log_text.toManaged(sema.gpa);731 var managed = sema.mod.compile_log_text.toManaged(sema.gpa);
693 defer sema.mod.compile_log_text = managed.moveToUnmanaged();732 defer sema.mod.compile_log_text = managed.moveToUnmanaged();
694 const writer = managed.writer();733 const writer = managed.writer();
...@@ -711,10 +750,9 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr...@@ -711,10 +750,9 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr
711 if (!gop.found_existing) {750 if (!gop.found_existing) {
712 gop.entry.value = inst_data.src().toSrcLoc(&block.base);751 gop.entry.value = inst_data.src().toSrcLoc(&block.base);
713 }752 }
714 return sema.mod.constVoid(sema.arena, .unneeded);
715}753}
716754
717fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {755fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref {
718 const tracy = trace(@src());756 const tracy = trace(@src());
719 defer tracy.end();757 defer tracy.end();
720758
...@@ -746,41 +784,13 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE...@@ -746,41 +784,13 @@ fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerE
746 };784 };
747 defer child_block.instructions.deinit(sema.gpa);785 defer child_block.instructions.deinit(sema.gpa);
748786
749 try sema.analyzeBody(&child_block, body);787 _ = try sema.analyzeBody(&child_block, body);
750788
751 // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.789 // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.
752790
753 try parent_block.instructions.append(sema.gpa, &loop_inst.base);791 try parent_block.instructions.append(sema.gpa, &loop_inst.base);
754 loop_inst.body = .{ .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items) };792 loop_inst.body = .{ .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items) };
755 return &loop_inst.base;793 return always_noreturn;
756}
757
758fn zirBlockFlat(
759 sema: *Sema,
760 parent_block: *Scope.Block,
761 inst: zir.Inst.Index,
762 is_comptime: bool,
763) InnerError!*Inst {
764 const tracy = trace(@src());
765 defer tracy.end();
766
767 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
768 const src = inst_data.src();
769 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
770 const body = sema.code.extra[extra.end..][0..extra.data.operands_len];
771
772 var child_block = parent_block.makeSubBlock();
773 defer child_block.instructions.deinit(sema.gpa);
774 child_block.is_comptime = child_block.is_comptime or is_comptime;
775
776 try sema.analyzeBody(&child_block, body);
777
778 // Move the analyzed instructions into the parent block arena.
779 const copied_instructions = try sema.arena.dupe(*Inst, child_block.instructions.items);
780 try parent_block.instructions.appendSlice(sema.gpa, copied_instructions);
781
782 // The result of a flat block is the last instruction.
783 return sema.inst_map[body[body.len - 1]];
784}794}
785795
786fn zirBlock(796fn zirBlock(
...@@ -794,8 +804,8 @@ fn zirBlock(...@@ -794,8 +804,8 @@ fn zirBlock(
794804
795 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;805 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
796 const src = inst_data.src();806 const src = inst_data.src();
797 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);807 const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
798 const body = sema.code.extra[extra.end..][0..extra.data.operands_len];808 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
799809
800 // Reserve space for a Block instruction so that generated Break instructions can810 // Reserve space for a Block instruction so that generated Break instructions can
801 // point to it, even if it doesn't end up getting used because the code ends up being811 // point to it, even if it doesn't end up getting used because the code ends up being
...@@ -833,7 +843,7 @@ fn zirBlock(...@@ -833,7 +843,7 @@ fn zirBlock(
833 defer merges.results.deinit(sema.gpa);843 defer merges.results.deinit(sema.gpa);
834 defer merges.br_list.deinit(sema.gpa);844 defer merges.br_list.deinit(sema.gpa);
835845
836 try sema.analyzeBody(&child_block, body);846 _ = try sema.analyzeBody(&child_block, body);
837847
838 return sema.analyzeBlockBody(parent_block, &child_block, merges);848 return sema.analyzeBlockBody(parent_block, &child_block, merges);
839}849}
...@@ -919,17 +929,17 @@ fn analyzeBlockBody(...@@ -919,17 +929,17 @@ fn analyzeBlockBody(
919 return &merges.block_inst.base;929 return &merges.block_inst.base;
920}930}
921931
922fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {932fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
923 const tracy = trace(@src());933 const tracy = trace(@src());
924 defer tracy.end();934 defer tracy.end();
925935
926 const src_node = sema.code.instructions.items(.data)[inst].node;936 const src_node = sema.code.instructions.items(.data)[inst].node;
927 const src: LazySrcLoc = .{ .node_offset = src_node };937 const src: LazySrcLoc = .{ .node_offset = src_node };
928 try sema.requireRuntimeBlock(block, src);938 try sema.requireRuntimeBlock(block, src);
929 return block.addNoOp(src, Type.initTag(.void), .breakpoint);939 _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
930}940}
931941
932fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {942fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
933 const tracy = trace(@src());943 const tracy = trace(@src());
934 defer tracy.end();944 defer tracy.end();
935945
...@@ -939,7 +949,7 @@ fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*...@@ -939,7 +949,7 @@ fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*
939 return sema.analyzeBreak(block, sema.src, zir_block, operand);949 return sema.analyzeBreak(block, sema.src, zir_block, operand);
940}950}
941951
942fn zirBreakVoidTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {952fn zirBreakVoidTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
943 const tracy = trace(@src());953 const tracy = trace(@src());
944 defer tracy.end();954 defer tracy.end();
945955
...@@ -955,7 +965,7 @@ fn analyzeBreak(...@@ -955,7 +965,7 @@ fn analyzeBreak(
955 src: LazySrcLoc,965 src: LazySrcLoc,
956 zir_block: zir.Inst.Index,966 zir_block: zir.Inst.Index,
957 operand: *Inst,967 operand: *Inst,
958) InnerError!*Inst {968) InnerError!zir.Inst.Ref {
959 var block = start_block;969 var block = start_block;
960 while (true) {970 while (true) {
961 if (block.label) |*label| {971 if (block.label) |*label| {
...@@ -981,26 +991,24 @@ fn analyzeBreak(...@@ -981,26 +991,24 @@ fn analyzeBreak(
981 try block.instructions.append(sema.gpa, &br.base);991 try block.instructions.append(sema.gpa, &br.base);
982 try label.merges.results.append(sema.gpa, operand);992 try label.merges.results.append(sema.gpa, operand);
983 try label.merges.br_list.append(sema.gpa, br);993 try label.merges.br_list.append(sema.gpa, br);
984 return &br.base;994 return always_noreturn;
985 }995 }
986 }996 }
987 block = block.parent.?;997 block = block.parent.?;
988 }998 }
989}999}
9901000
991fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1001fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
992 const tracy = trace(@src());1002 const tracy = trace(@src());
993 defer tracy.end();1003 defer tracy.end();
9941004
995 if (block.is_comptime) {1005 if (block.is_comptime) return;
996 return sema.mod.constVoid(sema.arena, .unneeded);
997 }
9981006
999 const src_node = sema.code.instructions.items(.data)[inst].node;1007 const src_node = sema.code.instructions.items(.data)[inst].node;
1000 const src: LazySrcLoc = .{ .node_offset = src_node };1008 const src: LazySrcLoc = .{ .node_offset = src_node };
1001 const src_loc = src.toSrcLoc(&block.base);1009 const src_loc = src.toSrcLoc(&block.base);
1002 const abs_byte_off = try src_loc.byteOffset();1010 const abs_byte_off = try src_loc.byteOffset();
1003 return block.addDbgStmt(src, abs_byte_off);1011 _ = try block.addDbgStmt(src, abs_byte_off);
1004}1012}
10051013
1006fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1014fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
...@@ -1185,7 +1193,7 @@ fn analyzeCall(...@@ -1185,7 +1193,7 @@ fn analyzeCall(
11851193
1186 // This will have return instructions analyzed as break instructions to1194 // This will have return instructions analyzed as break instructions to
1187 // the block_inst above.1195 // the block_inst above.
1188 try sema.root(&child_block);1196 _ = try sema.root(&child_block);
11891197
1190 return sema.analyzeBlockBody(block, &child_block, merges);1198 return sema.analyzeBlockBody(block, &child_block, merges);
1191 }1199 }
...@@ -1638,7 +1646,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In...@@ -1638,7 +1646,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
1638 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);1646 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);
1639}1647}
16401648
1641fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1649fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
1642 const tracy = trace(@src());1650 const tracy = trace(@src());
1643 defer tracy.end();1651 defer tracy.end();
16441652
...@@ -1650,7 +1658,6 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde...@@ -1650,7 +1658,6 @@ fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Inde
1650 if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {1658 if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {
1651 return sema.mod.fail(&block.base, src, "expression value is ignored", .{});1659 return sema.mod.fail(&block.base, src, "expression value is ignored", .{});
1652 }1660 }
1653 return sema.mod.constVoid(sema.arena, .unneeded);
1654}1661}
16551662
1656fn zirFnType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: bool) InnerError!*Inst {1663fn zirFnType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: bool) InnerError!*Inst {
...@@ -2067,7 +2074,7 @@ fn zirSwitchBr(...@@ -2067,7 +2074,7 @@ fn zirSwitchBr(
2067 parent_block: *Scope.Block,2074 parent_block: *Scope.Block,
2068 inst: zir.Inst.Index,2075 inst: zir.Inst.Index,
2069 ref: bool,2076 ref: bool,
2070) InnerError!*Inst {2077) InnerError!zir.Inst.Ref {
2071 const tracy = trace(@src());2078 const tracy = trace(@src());
2072 defer tracy.end();2079 defer tracy.end();
20732080
...@@ -2087,18 +2094,18 @@ fn zirSwitchBr(...@@ -2087,18 +2094,18 @@ fn zirSwitchBr(
2087 const item = try sema.resolveConstValue(parent_block, case_src, casted);2094 const item = try sema.resolveConstValue(parent_block, case_src, casted);
20882095
2089 if (target_val.eql(item)) {2096 if (target_val.eql(item)) {
2090 try sema.analyzeBody(parent_block, case.body);2097 _ = try sema.analyzeBody(parent_block, case.body);
2091 return sema.mod.constNoReturn(sema.arena, inst.base.src);2098 return always_noreturn;
2092 }2099 }
2093 }2100 }
2094 try sema.analyzeBody(parent_block, inst.positionals.else_body);2101 _ = try sema.analyzeBody(parent_block, inst.positionals.else_body);
2095 return sema.mod.constNoReturn(sema.arena, inst.base.src);2102 return always_noreturn;
2096 }2103 }
20972104
2098 if (inst.positionals.cases.len == 0) {2105 if (inst.positionals.cases.len == 0) {
2099 // no cases just analyze else_branch2106 // no cases just analyze else_branch
2100 try sema.analyzeBody(parent_block, inst.positionals.else_body);2107 _ = try sema.analyzeBody(parent_block, inst.positionals.else_body);
2101 return sema.mod.constNoReturn(sema.arena, inst.base.src);2108 return always_noreturn;
2102 }2109 }
21032110
2104 try sema.requireRuntimeBlock(parent_block, inst.base.src);2111 try sema.requireRuntimeBlock(parent_block, inst.base.src);
...@@ -2122,7 +2129,7 @@ fn zirSwitchBr(...@@ -2122,7 +2129,7 @@ fn zirSwitchBr(
2122 const casted = try sema.coerce(block, target.ty, resolved, resolved_src);2129 const casted = try sema.coerce(block, target.ty, resolved, resolved_src);
2123 const item = try sema.resolveConstValue(parent_block, case_src, casted);2130 const item = try sema.resolveConstValue(parent_block, case_src, casted);
21242131
2125 try sema.analyzeBody(&case_block, case.body);2132 _ = try sema.analyzeBody(&case_block, case.body);
21262133
2127 cases[i] = .{2134 cases[i] = .{
2128 .item = item,2135 .item = item,
...@@ -2131,7 +2138,7 @@ fn zirSwitchBr(...@@ -2131,7 +2138,7 @@ fn zirSwitchBr(
2131 }2138 }
21322139
2133 case_block.instructions.items.len = 0;2140 case_block.instructions.items.len = 0;
2134 try sema.analyzeBody(&case_block, inst.positionals.else_body);2141 _ = try sema.analyzeBody(&case_block, inst.positionals.else_body);
21352142
2136 const else_body: ir.Body = .{2143 const else_body: ir.Body = .{
2137 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),2144 .instructions = try sema.arena.dupe(*Inst, case_block.instructions.items),
...@@ -2719,6 +2726,75 @@ fn zirBoolOp(...@@ -2719,6 +2726,75 @@ fn zirBoolOp(
2719 return block.addBinOp(src, bool_type, tag, lhs, rhs);2726 return block.addBinOp(src, bool_type, tag, lhs, rhs);
2720}2727}
27212728
2729fn zirBoolBr(
2730 sema: *Sema,
2731 parent_block: *Scope.Block,
2732 inst: zir.Inst.Index,
2733 is_bool_or: bool,
2734) InnerError!*Inst {
2735 const tracy = trace(@src());
2736 defer tracy.end();
2737
2738 const inst_data = sema.code.instructions.items(.data)[inst].bool_br;
2739 const src: LazySrcLoc = .unneeded;
2740 const lhs = try sema.resolveInst(inst_data.lhs);
2741 const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
2742 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
2743
2744 if (try sema.resolveDefinedValue(parent_block, src, lhs)) |lhs_val| {
2745 if (lhs_val.toBool() == is_bool_or) {
2746 return sema.mod.constBool(sema.arena, src, is_bool_or);
2747 }
2748 // comptime-known left-hand side. No need for a block here; the result
2749 // is simply the rhs expression. Here we rely on there only being 1
2750 // break instruction (`break_flat`).
2751 const zir_inst_ref = try sema.analyzeBody(parent_block, body);
2752 return sema.resolveInst(zir_inst_ref);
2753 }
2754
2755 const block_inst = try sema.arena.create(Inst.Block);
2756 block_inst.* = .{
2757 .base = .{
2758 .tag = Inst.Block.base_tag,
2759 .ty = Type.initTag(.bool),
2760 .src = src,
2761 },
2762 .body = undefined,
2763 };
2764
2765 var child_block = parent_block.makeSubBlock();
2766 defer child_block.instructions.deinit(sema.gpa);
2767
2768 var then_block = child_block.makeSubBlock();
2769 defer then_block.instructions.deinit(sema.gpa);
2770
2771 var else_block = child_block.makeSubBlock();
2772 defer else_block.instructions.deinit(sema.gpa);
2773
2774 const lhs_block = if (is_bool_or) &then_block else &else_block;
2775 const rhs_block = if (is_bool_or) &else_block else &then_block;
2776
2777 const lhs_result = try sema.mod.constInst(sema.arena, src, .{
2778 .ty = Type.initTag(.bool),
2779 .val = if (is_bool_or) Value.initTag(.bool_true) else Value.initTag(.bool_false),
2780 });
2781 _ = try lhs_block.addBr(src, block_inst, lhs_result);
2782
2783 const rhs_result_zir_ref = try sema.analyzeBody(rhs_block, body);
2784 const rhs_result = try sema.resolveInst(rhs_result_zir_ref);
2785 _ = try rhs_block.addBr(src, block_inst, rhs_result);
2786
2787 const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, then_block.instructions.items) };
2788 const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, rhs_block.instructions.items) };
2789 _ = try child_block.addCondBr(src, lhs, tzir_then_body, tzir_else_body);
2790
2791 block_inst.body = .{
2792 .instructions = try sema.arena.dupe(*Inst, child_block.instructions.items),
2793 };
2794 try parent_block.instructions.append(sema.gpa, &block_inst.base);
2795 return &block_inst.base;
2796}
2797
2722fn zirIsNull(2798fn zirIsNull(
2723 sema: *Sema,2799 sema: *Sema,
2724 block: *Scope.Block,2800 block: *Scope.Block,
...@@ -2770,7 +2846,11 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro...@@ -2770,7 +2846,11 @@ fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerErro
2770 return sema.analyzeIsErr(block, src, loaded);2846 return sema.analyzeIsErr(block, src, loaded);
2771}2847}
27722848
2773fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {2849fn zirCondbr(
2850 sema: *Sema,
2851 parent_block: *Scope.Block,
2852 inst: zir.Inst.Index,
2853) InnerError!zir.Inst.Ref {
2774 const tracy = trace(@src());2854 const tracy = trace(@src());
2775 defer tracy.end();2855 defer tracy.end();
27762856
...@@ -2787,8 +2867,8 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne...@@ -2787,8 +2867,8 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne
27872867
2788 if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| {2868 if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| {
2789 const body = if (cond_val.toBool()) then_body else else_body;2869 const body = if (cond_val.toBool()) then_body else else_body;
2790 try sema.analyzeBody(parent_block, body);2870 _ = try sema.analyzeBody(parent_block, body);
2791 return sema.mod.constNoReturn(sema.arena, src);2871 return always_noreturn;
2792 }2872 }
27932873
2794 var true_block: Scope.Block = .{2874 var true_block: Scope.Block = .{
...@@ -2800,7 +2880,7 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne...@@ -2800,7 +2880,7 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne
2800 .is_comptime = parent_block.is_comptime,2880 .is_comptime = parent_block.is_comptime,
2801 };2881 };
2802 defer true_block.instructions.deinit(sema.gpa);2882 defer true_block.instructions.deinit(sema.gpa);
2803 try sema.analyzeBody(&true_block, then_body);2883 _ = try sema.analyzeBody(&true_block, then_body);
28042884
2805 var false_block: Scope.Block = .{2885 var false_block: Scope.Block = .{
2806 .parent = parent_block,2886 .parent = parent_block,
...@@ -2811,14 +2891,15 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne...@@ -2811,14 +2891,15 @@ fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) Inne
2811 .is_comptime = parent_block.is_comptime,2891 .is_comptime = parent_block.is_comptime,
2812 };2892 };
2813 defer false_block.instructions.deinit(sema.gpa);2893 defer false_block.instructions.deinit(sema.gpa);
2814 try sema.analyzeBody(&false_block, else_body);2894 _ = try sema.analyzeBody(&false_block, else_body);
28152895
2816 const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, true_block.instructions.items) };2896 const tzir_then_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, true_block.instructions.items) };
2817 const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, false_block.instructions.items) };2897 const tzir_else_body: ir.Body = .{ .instructions = try sema.arena.dupe(*Inst, false_block.instructions.items) };
2818 return parent_block.addCondBr(src, cond, tzir_then_body, tzir_else_body);2898 _ = try parent_block.addCondBr(src, cond, tzir_then_body, tzir_else_body);
2899 return always_noreturn;
2819}2900}
28202901
2821fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {2902fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref {
2822 const tracy = trace(@src());2903 const tracy = trace(@src());
2823 defer tracy.end();2904 defer tracy.end();
28242905
...@@ -2830,7 +2911,8 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE...@@ -2830,7 +2911,8 @@ fn zirUnreachable(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
2830 if (safety_check and block.wantSafety()) {2911 if (safety_check and block.wantSafety()) {
2831 return sema.safetyPanic(block, src, .unreach);2912 return sema.safetyPanic(block, src, .unreach);
2832 } else {2913 } else {
2833 return block.addNoOp(src, Type.initTag(.noreturn), .unreach);2914 _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);
2915 return always_noreturn;
2834 }2916 }
2835}2917}
28362918
...@@ -2839,7 +2921,7 @@ fn zirRetTok(...@@ -2839,7 +2921,7 @@ fn zirRetTok(
2839 block: *Scope.Block,2921 block: *Scope.Block,
2840 inst: zir.Inst.Index,2922 inst: zir.Inst.Index,
2841 need_coercion: bool,2923 need_coercion: bool,
2842) InnerError!*Inst {2924) InnerError!zir.Inst.Ref {
2843 const tracy = trace(@src());2925 const tracy = trace(@src());
2844 defer tracy.end();2926 defer tracy.end();
28452927
...@@ -2850,7 +2932,7 @@ fn zirRetTok(...@@ -2850,7 +2932,7 @@ fn zirRetTok(
2850 return sema.analyzeRet(block, operand, src, need_coercion);2932 return sema.analyzeRet(block, operand, src, need_coercion);
2851}2933}
28522934
2853fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {2935fn zirRetNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Ref {
2854 const tracy = trace(@src());2936 const tracy = trace(@src());
2855 defer tracy.end();2937 defer tracy.end();
28562938
...@@ -2867,22 +2949,24 @@ fn analyzeRet(...@@ -2867,22 +2949,24 @@ fn analyzeRet(
2867 operand: *Inst,2949 operand: *Inst,
2868 src: LazySrcLoc,2950 src: LazySrcLoc,
2869 need_coercion: bool,2951 need_coercion: bool,
2870) InnerError!*Inst {2952) InnerError!zir.Inst.Ref {
2871 if (block.inlining) |inlining| {2953 if (block.inlining) |inlining| {
2872 // We are inlining a function call; rewrite the `ret` as a `break`.2954 // We are inlining a function call; rewrite the `ret` as a `break`.
2873 try inlining.merges.results.append(sema.gpa, operand);2955 try inlining.merges.results.append(sema.gpa, operand);
2874 const br = try block.addBr(src, inlining.merges.block_inst, operand);2956 _ = try block.addBr(src, inlining.merges.block_inst, operand);
2875 return &br.base;2957 return always_noreturn;
2876 }2958 }
28772959
2878 if (need_coercion) {2960 if (need_coercion) {
2879 if (sema.func) |func| {2961 if (sema.func) |func| {
2880 const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty;2962 const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty;
2881 const casted_operand = try sema.coerce(block, fn_ty.fnReturnType(), operand, src);2963 const casted_operand = try sema.coerce(block, fn_ty.fnReturnType(), operand, src);
2882 return block.addUnOp(src, Type.initTag(.noreturn), .ret, casted_operand);2964 _ = try block.addUnOp(src, Type.initTag(.noreturn), .ret, casted_operand);
2965 return always_noreturn;
2883 }2966 }
2884 }2967 }
2885 return block.addUnOp(src, Type.initTag(.noreturn), .ret, operand);2968 _ = try block.addUnOp(src, Type.initTag(.noreturn), .ret, operand);
2969 return always_noreturn;
2886}2970}
28872971
2888fn floatOpAllowed(tag: zir.Inst.Tag) bool {2972fn floatOpAllowed(tag: zir.Inst.Tag) bool {
...@@ -3051,10 +3135,11 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id:...@@ -3051,10 +3135,11 @@ fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id:
3051 try parent_block.instructions.append(sema.gpa, &block_inst.base);3135 try parent_block.instructions.append(sema.gpa, &block_inst.base);
3052}3136}
30533137
3054fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !*Inst {3138fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !zir.Inst.Ref {
3055 // TODO Once we have a panic function to call, call it here instead of breakpoint.3139 // TODO Once we have a panic function to call, call it here instead of breakpoint.
3056 _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);3140 _ = try block.addNoOp(src, Type.initTag(.void), .breakpoint);
3057 return block.addNoOp(src, Type.initTag(.noreturn), .unreach);3141 _ = try block.addNoOp(src, Type.initTag(.noreturn), .unreach);
3142 return always_noreturn;
3058}3143}
30593144
3060fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {3145fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
...@@ -3405,20 +3490,20 @@ fn storePtr(...@@ -3405,20 +3490,20 @@ fn storePtr(
3405 src: LazySrcLoc,3490 src: LazySrcLoc,
3406 ptr: *Inst,3491 ptr: *Inst,
3407 uncasted_value: *Inst,3492 uncasted_value: *Inst,
3408) !*Inst {3493) !void {
3409 if (ptr.ty.isConstPtr())3494 if (ptr.ty.isConstPtr())
3410 return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});3495 return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});
34113496
3412 const elem_ty = ptr.ty.elemType();3497 const elem_ty = ptr.ty.elemType();
3413 const value = try sema.coerce(block, elem_ty, uncasted_value, uncasted_value.src);3498 const value = try sema.coerce(block, elem_ty, uncasted_value, uncasted_value.src);
3414 if (elem_ty.onePossibleValue() != null)3499 if (elem_ty.onePossibleValue() != null)
3415 return sema.mod.constVoid(sema.arena, .unneeded);3500 return;
34163501
3417 // TODO handle comptime pointer writes3502 // TODO handle comptime pointer writes
3418 // TODO handle if the element type requires comptime3503 // TODO handle if the element type requires comptime
34193504
3420 try sema.requireRuntimeBlock(block, src);3505 try sema.requireRuntimeBlock(block, src);
3421 return block.addBinOp(src, Type.initTag(.void), .store, ptr, value);3506 _ = try block.addBinOp(src, Type.initTag(.void), .store, ptr, value);
3422}3507}
34233508
3424fn bitcast(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {3509fn bitcast(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
src/astgen.zig+33-93
...@@ -370,8 +370,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -370,8 +370,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
370 .array_cat => return simpleBinOp(mod, scope, rl, node, .array_cat),370 .array_cat => return simpleBinOp(mod, scope, rl, node, .array_cat),
371 .array_mult => return simpleBinOp(mod, scope, rl, node, .array_mul),371 .array_mult => return simpleBinOp(mod, scope, rl, node, .array_mul),
372372
373 .bool_and => return boolBinOp(mod, scope, rl, node, .bool_and),373 .bool_and => return boolBinOp(mod, scope, rl, node, .bool_br_and),
374 .bool_or => return boolBinOp(mod, scope, rl, node, .bool_or),374 .bool_or => return boolBinOp(mod, scope, rl, node, .bool_br_or),
375375
376 .bool_not => return boolNot(mod, scope, rl, node),376 .bool_not => return boolNot(mod, scope, rl, node),
377 .bit_not => return bitNot(mod, scope, rl, node),377 .bit_not => return bitNot(mod, scope, rl, node),
...@@ -425,8 +425,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -425,8 +425,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
425 .field_access => return fieldAccess(mod, scope, rl, node),425 .field_access => return fieldAccess(mod, scope, rl, node),
426 .float_literal => return floatLiteral(mod, scope, rl, node),426 .float_literal => return floatLiteral(mod, scope, rl, node),
427427
428 .if_simple => return ifExpr(mod, scope, rl, tree.ifSimple(node)),428 .if_simple => return ifExpr(mod, scope, rl, node, tree.ifSimple(node)),
429 .@"if" => return ifExpr(mod, scope, rl, tree.ifFull(node)),429 .@"if" => return ifExpr(mod, scope, rl, node, tree.ifFull(node)),
430430
431 .while_simple => return whileExpr(mod, scope, rl, tree.whileSimple(node)),431 .while_simple => return whileExpr(mod, scope, rl, tree.whileSimple(node)),
432 .while_cont => return whileExpr(mod, scope, rl, tree.whileCont(node)),432 .while_cont => return whileExpr(mod, scope, rl, tree.whileCont(node)),
...@@ -923,6 +923,7 @@ fn labeledBlockExpr(...@@ -923,6 +923,7 @@ fn labeledBlockExpr(
923 // so that break statements can reference it.923 // so that break statements can reference it.
924 const gz = parent_scope.getGenZir();924 const gz = parent_scope.getGenZir();
925 const block_inst = try gz.addBlock(zir_tag, block_node);925 const block_inst = try gz.addBlock(zir_tag, block_node);
926 try gz.instructions.append(mod.gpa, block_inst);
926927
927 var block_scope: Scope.GenZir = .{928 var block_scope: Scope.GenZir = .{
928 .parent = parent_scope,929 .parent = parent_scope,
...@@ -946,8 +947,6 @@ fn labeledBlockExpr(...@@ -946,8 +947,6 @@ fn labeledBlockExpr(
946 return mod.failTok(parent_scope, label_token, "unused block label", .{});947 return mod.failTok(parent_scope, label_token, "unused block label", .{});
947 }948 }
948949
949 try gz.instructions.append(mod.gpa, block_inst);
950
951 const zir_tags = gz.zir_code.instructions.items(.tag);950 const zir_tags = gz.zir_code.instructions.items(.tag);
952 const zir_datas = gz.zir_code.instructions.items(.data);951 const zir_datas = gz.zir_code.instructions.items(.data);
953952
...@@ -961,7 +960,7 @@ fn labeledBlockExpr(...@@ -961,7 +960,7 @@ fn labeledBlockExpr(
961 }960 }
962 // TODO technically not needed since we changed the tag to break_void but961 // TODO technically not needed since we changed the tag to break_void but
963 // would be better still to elide the ones that are in this list.962 // would be better still to elide the ones that are in this list.
964 try copyBodyNoEliding(block_inst, block_scope);963 try block_scope.setBlockBody(block_inst);
965964
966 return gz.zir_code.ref_start_index + block_inst;965 return gz.zir_code.ref_start_index + block_inst;
967 },966 },
...@@ -975,7 +974,7 @@ fn labeledBlockExpr(...@@ -975,7 +974,7 @@ fn labeledBlockExpr(
975 // TODO technically not needed since we changed the tag to elided but974 // TODO technically not needed since we changed the tag to elided but
976 // would be better still to elide the ones that are in this list.975 // would be better still to elide the ones that are in this list.
977 }976 }
978 try copyBodyNoEliding(block_inst, block_scope);977 try block_scope.setBlockBody(block_inst);
979 const block_ref = gz.zir_code.ref_start_index + block_inst;978 const block_ref = gz.zir_code.ref_start_index + block_inst;
980 switch (rl) {979 switch (rl) {
981 .ref => return block_ref,980 .ref => return block_ref,
...@@ -1635,8 +1634,8 @@ fn finishThenElseBlock(...@@ -1635,8 +1634,8 @@ fn finishThenElseBlock(
1635 });1634 });
1636 }1635 }
1637 assert(!strat.elide_store_to_block_ptr_instructions);1636 assert(!strat.elide_store_to_block_ptr_instructions);
1638 try copyBodyNoEliding(then_body, then_scope.*);1637 try then_scope.setBlockBody(then_body);
1639 try copyBodyNoEliding(else_body, else_scope.*);1638 try else_scope.setBlockBody(else_body);
1640 return &main_block.base;1639 return &main_block.base;
1641 },1640 },
1642 .break_operand => {1641 .break_operand => {
...@@ -1662,8 +1661,8 @@ fn finishThenElseBlock(...@@ -1662,8 +1661,8 @@ fn finishThenElseBlock(
1662 try copyBodyWithElidedStoreBlockPtr(then_body, then_scope.*);1661 try copyBodyWithElidedStoreBlockPtr(then_body, then_scope.*);
1663 try copyBodyWithElidedStoreBlockPtr(else_body, else_scope.*);1662 try copyBodyWithElidedStoreBlockPtr(else_body, else_scope.*);
1664 } else {1663 } else {
1665 try copyBodyNoEliding(then_body, then_scope.*);1664 try then_scope.setBlockBody(then_body);
1666 try copyBodyNoEliding(else_body, else_scope.*);1665 try else_scope.setBlockBody(else_body);
1667 }1666 }
1668 switch (rl) {1667 switch (rl) {
1669 .ref => return &main_block.base,1668 .ref => return &main_block.base,
...@@ -1801,95 +1800,49 @@ fn boolBinOp(...@@ -1801,95 +1800,49 @@ fn boolBinOp(
1801 mod: *Module,1800 mod: *Module,
1802 scope: *Scope,1801 scope: *Scope,
1803 rl: ResultLoc,1802 rl: ResultLoc,
1804 infix_node: ast.Node.Index,1803 node: ast.Node.Index,
1805 kind: enum { bool_and, bool_or },1804 zir_tag: zir.Inst.Tag,
1806) InnerError!zir.Inst.Ref {1805) InnerError!zir.Inst.Ref {
1807 const tree = scope.tree();
1808 const node_datas = tree.nodes.items(.data);
1809 const bool_type = @enumToInt(zir.Const.bool_type);
1810 const gz = scope.getGenZir();1806 const gz = scope.getGenZir();
1807 const node_datas = gz.tree().nodes.items(.data);
1808 const bool_type = @enumToInt(zir.Const.bool_type);
18111809
1812 const lhs = try expr(mod, scope, .{ .ty = bool_type }, node_datas[infix_node].lhs);1810 const lhs = try expr(mod, scope, .{ .ty = bool_type }, node_datas[node].lhs);
18131811 const bool_br = try gz.addBoolBr(zir_tag, lhs);
1814 const block_inst = try gz.addBlock(.block, infix_node);
1815 const block_ref = gz.zir_code.ref_start_index + block_inst;
1816 var block_scope: Scope.GenZir = .{
1817 .parent = scope,
1818 .zir_code = gz.zir_code,
1819 .force_comptime = gz.force_comptime,
1820 };
1821 defer block_scope.instructions.deinit(mod.gpa);
18221812
1823 var rhs_scope: Scope.GenZir = .{1813 var rhs_scope: Scope.GenZir = .{
1824 .parent = &block_scope.base,1814 .parent = scope,
1825 .zir_code = gz.zir_code,1815 .zir_code = gz.zir_code,
1826 .force_comptime = gz.force_comptime,1816 .force_comptime = gz.force_comptime,
1827 };1817 };
1828 defer rhs_scope.instructions.deinit(mod.gpa);1818 defer rhs_scope.instructions.deinit(mod.gpa);
1829 const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, node_datas[infix_node].rhs);1819 const rhs = try expr(mod, &rhs_scope.base, .{ .ty = bool_type }, node_datas[node].rhs);
1830 _ = try rhs_scope.addBin(.@"break", block_inst, rhs);1820 _ = try rhs_scope.addUnNode(.break_flat, rhs, node);
18311821 try rhs_scope.setBoolBrBody(bool_br);
1832 // TODO: should we have zir.Const instructions for `break true` and `break false`?
1833 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1834 const break_true_false_ref = new_index + gz.zir_code.ref_start_index;
1835 try gz.zir_code.instructions.append(gz.zir_code.gpa, .{ .tag = .@"break", .data = .{ .bin = .{
1836 .lhs = block_inst,
1837 .rhs = switch (kind) {
1838 .bool_and => @enumToInt(zir.Const.bool_false),
1839 .bool_or => @enumToInt(zir.Const.bool_true),
1840 },
1841 } } });
1842
1843 switch (kind) {
1844 // if lhs // AND
1845 // break rhs
1846 // else
1847 // break false
1848 .bool_and => _ = try block_scope.addCondBr(
1849 lhs,
1850 rhs_scope.instructions.items,
1851 &[_]zir.Inst.Ref{break_true_false_ref},
1852 infix_node,
1853 ),
1854 // if lhs // OR
1855 // break true
1856 // else
1857 // break rhs
1858 .bool_or => _ = try block_scope.addCondBr(
1859 lhs,
1860 &[_]zir.Inst.Ref{break_true_false_ref},
1861 rhs_scope.instructions.items,
1862 infix_node,
1863 ),
1864 }
18651822
1866 try gz.instructions.append(mod.gpa, block_inst);1823 const block_ref = gz.zir_code.ref_start_index + bool_br;
1867 try copyBodyNoEliding(block_inst, block_scope);1824 return rvalue(mod, scope, rl, block_ref, node);
1868
1869 return rvalue(mod, scope, rl, block_ref, infix_node);
1870}1825}
18711826
1872fn ifExpr(1827fn ifExpr(
1873 mod: *Module,1828 mod: *Module,
1874 scope: *Scope,1829 scope: *Scope,
1875 rl: ResultLoc,1830 rl: ResultLoc,
1831 node: ast.Node.Index,
1876 if_full: ast.full.If,1832 if_full: ast.full.If,
1877) InnerError!zir.Inst.Ref {1833) InnerError!zir.Inst.Ref {
1878 if (true) @panic("TODO update for zir-memory-layout");1834 if (true) @panic("TODO update for zir-memory-layout");
1835 const parent_gz = scope.getGenZir();
1879 var block_scope: Scope.GenZir = .{1836 var block_scope: Scope.GenZir = .{
1880 .parent = scope,1837 .parent = scope,
1881 .decl = scope.ownerDecl().?,1838 .zir_code = parent_gz.zir_code,
1882 .arena = scope.arena(),
1883 .force_comptime = scope.isComptime(),1839 .force_comptime = scope.isComptime(),
1884 .instructions = .{},1840 .instructions = .{},
1885 };1841 };
1886 setBlockResultLoc(&block_scope, rl);1842 setBlockResultLoc(&block_scope, rl);
1887 defer block_scope.instructions.deinit(mod.gpa);1843 defer block_scope.instructions.deinit(mod.gpa);
18881844
1889 const tree = scope.tree();1845 const tree = parent_gz.tree();
1890 const main_tokens = tree.nodes.items(.main_token);
1891
1892 const if_src = token_starts[if_full.ast.if_token];
18931846
1894 const cond = c: {1847 const cond = c: {
1895 // TODO https://github.com/ziglang/zig/issues/79291848 // TODO https://github.com/ziglang/zig/issues/7929
...@@ -1898,23 +1851,16 @@ fn ifExpr(...@@ -1898,23 +1851,16 @@ fn ifExpr(
1898 } else if (if_full.payload_token) |payload_token| {1851 } else if (if_full.payload_token) |payload_token| {
1899 return mod.failTok(scope, payload_token, "TODO implement if optional", .{});1852 return mod.failTok(scope, payload_token, "TODO implement if optional", .{});
1900 } else {1853 } else {
1901 const bool_type = try addZIRInstConst(mod, &block_scope.base, if_src, .{1854 const bool_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.bool_type) };
1902 .ty = Type.initTag(.type),1855 break :c try expr(mod, &block_scope.base, bool_rl, if_full.ast.cond_expr);
1903 .val = Value.initTag(.bool_type),
1904 });
1905 break :c try expr(mod, &block_scope.base, .{ .ty = bool_type }, if_full.ast.cond_expr);
1906 }1856 }
1907 };1857 };
19081858
1909 const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{1859 const condbr = try block_scope.addCondBr(node);
1910 .condition = cond,
1911 .then_body = undefined, // populated below
1912 .else_body = undefined, // populated below
1913 }, .{});
19141860
1915 const block = try addZIRInstBlock(mod, scope, if_src, .block, .{1861 const block = try parent_gz.addBlock(.block, node);
1916 .instructions = try block_scope.arena.dupe(zir.Inst.Ref, block_scope.instructions.items),1862 try parent_gz.instructions.append(mod.gpa, block);
1917 });1863 try block_scope.setBlockBody(block);
19181864
1919 const then_src = token_starts[tree.lastToken(if_full.ast.then_expr)];1865 const then_src = token_starts[tree.lastToken(if_full.ast.then_expr)];
1920 var then_scope: Scope.GenZir = .{1866 var then_scope: Scope.GenZir = .{
...@@ -1990,12 +1936,6 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZir)...@@ -1990,12 +1936,6 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZir)
1990 assert(dst_index == body.instructions.len);1936 assert(dst_index == body.instructions.len);
1991}1937}
19921938
1993fn copyBodyNoEliding(block_inst: zir.Inst.Index, gz: Module.Scope.GenZir) !void {
1994 const zir_datas = gz.zir_code.instructions.items(.data);
1995 zir_datas[block_inst].pl_node.payload_index = @intCast(u32, gz.zir_code.extra.items.len);
1996 try gz.zir_code.extra.appendSlice(gz.zir_code.gpa, gz.instructions.items);
1997}
1998
1999fn whileExpr(1939fn whileExpr(
2000 mod: *Module,1940 mod: *Module,
2001 scope: *Scope,1941 scope: *Scope,
src/zir.zig+58-17
...@@ -99,11 +99,7 @@ pub const Code = struct {...@@ -99,11 +99,7 @@ pub const Code = struct {
99 try stderr.print("ZIR {s} {s} {{\n", .{ kind, decl_name });99 try stderr.print("ZIR {s} {s} {{\n", .{ kind, decl_name });
100100
101 const root_body = code.extra[code.root_start..][0..code.root_len];101 const root_body = code.extra[code.root_start..][0..code.root_len];
102 for (root_body) |inst| {102 try writer.writeBody(stderr, root_body);
103 try stderr.print(" %{d} ", .{inst});
104 try writer.writeInstToStream(stderr, inst);
105 try stderr.writeByte('\n');
106 }
107103
108 try stderr.print("}} // ZIR {s} {s}\n\n", .{ kind, decl_name });104 try stderr.print("}} // ZIR {s} {s}\n\n", .{ kind, decl_name });
109 }105 }
...@@ -451,16 +447,10 @@ pub const Inst = struct {...@@ -451,16 +447,10 @@ pub const Inst = struct {
451 /// Bitwise OR. `|`447 /// Bitwise OR. `|`
452 bit_or,448 bit_or,
453 /// A labeled block of code, which can return a value.449 /// A labeled block of code, which can return a value.
454 /// Uses the `pl_node` union field. Payload is `MultiOp`.450 /// Uses the `pl_node` union field. Payload is `Block`.
455 block,451 block,
456 /// A block of code, which can return a value. There are no instructions that break out of
457 /// this block; it is implied that the final instruction is the result.
458 /// Uses the `pl_node` union field. Payload is `MultiOp`.
459 block_flat,
460 /// Same as `block` but additionally makes the inner instructions execute at comptime.452 /// Same as `block` but additionally makes the inner instructions execute at comptime.
461 block_comptime,453 block_comptime,
462 /// Same as `block_flat` but additionally makes the inner instructions execute at comptime.
463 block_comptime_flat,
464 /// Boolean AND. See also `bit_and`.454 /// Boolean AND. See also `bit_and`.
465 /// Uses the `pl_node` union field. Payload is `Bin`.455 /// Uses the `pl_node` union field. Payload is `Bin`.
466 bool_and,456 bool_and,
...@@ -470,6 +460,14 @@ pub const Inst = struct {...@@ -470,6 +460,14 @@ pub const Inst = struct {
470 /// Boolean OR. See also `bit_or`.460 /// Boolean OR. See also `bit_or`.
471 /// Uses the `pl_node` union field. Payload is `Bin`.461 /// Uses the `pl_node` union field. Payload is `Bin`.
472 bool_or,462 bool_or,
463 /// Short-circuiting boolean `and`. `lhs` is a boolean `Ref` and the other operand
464 /// is a block, which is evaluated if `lhs` is `true`.
465 /// Uses the `bool_br` union field.
466 bool_br_and,
467 /// Short-circuiting boolean `or`. `lhs` is a boolean `Ref` and the other operand
468 /// is a block, which is evaluated if `lhs` is `false`.
469 /// Uses the `bool_br` union field.
470 bool_br_or,
473 /// Return a value from a block.471 /// Return a value from a block.
474 /// Uses the `bin` union field: `lhs` is `Index` to the block (*not* `Ref`!),472 /// Uses the `bin` union field: `lhs` is `Index` to the block (*not* `Ref`!),
475 /// `rhs` is operand.473 /// `rhs` is operand.
...@@ -480,6 +478,12 @@ pub const Inst = struct {...@@ -480,6 +478,12 @@ pub const Inst = struct {
480 /// Uses the `un_tok` union field.478 /// Uses the `un_tok` union field.
481 /// Note that the block operand is a `Index`, not `Ref`.479 /// Note that the block operand is a `Index`, not `Ref`.
482 break_void_tok,480 break_void_tok,
481 /// Return a value from a block. This is a special form that is only valid
482 /// when there is exactly 1 break from a block (this one). This instruction
483 /// allows using the return value from `Sema.analyzeBody`. The block is
484 /// assumed to be the direct parent of this instruction.
485 /// Uses the `un_node` union field. The AST node is unused.
486 break_flat,
483 /// Uses the `node` union field.487 /// Uses the `node` union field.
484 breakpoint,488 breakpoint,
485 /// Function call with modifier `.auto`.489 /// Function call with modifier `.auto`.
...@@ -637,7 +641,7 @@ pub const Inst = struct {...@@ -637,7 +641,7 @@ pub const Inst = struct {
637 /// A labeled block of code that loops forever. At the end of the body it is implied641 /// A labeled block of code that loops forever. At the end of the body it is implied
638 /// to repeat; no explicit "repeat" instruction terminates loop bodies.642 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
639 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.643 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.
640 /// The payload is `MultiOp`.644 /// The payload is `Block`.
641 loop,645 loop,
642 /// Merge two error sets into one, `E1 || E2`.646 /// Merge two error sets into one, `E1 || E2`.
643 merge_error_sets,647 merge_error_sets,
...@@ -886,9 +890,9 @@ pub const Inst = struct {...@@ -886,9 +890,9 @@ pub const Inst = struct {
886 .bitcast_result_ptr,890 .bitcast_result_ptr,
887 .bit_or,891 .bit_or,
888 .block,892 .block,
889 .block_flat,
890 .block_comptime,893 .block_comptime,
891 .block_comptime_flat,894 .bool_br_and,
895 .bool_br_or,
892 .bool_not,896 .bool_not,
893 .bool_and,897 .bool_and,
894 .bool_or,898 .bool_or,
...@@ -988,6 +992,7 @@ pub const Inst = struct {...@@ -988,6 +992,7 @@ pub const Inst = struct {
988992
989 .@"break",993 .@"break",
990 .break_void_tok,994 .break_void_tok,
995 .break_flat,
991 .condbr,996 .condbr,
992 .compile_error,997 .compile_error,
993 .ret_node,998 .ret_node,
...@@ -1127,6 +1132,11 @@ pub const Inst = struct {...@@ -1127,6 +1132,11 @@ pub const Inst = struct {
1127 /// For `fn_type_cc` this points to `FnTypeCc` in `extra`.1132 /// For `fn_type_cc` this points to `FnTypeCc` in `extra`.
1128 payload_index: u32,1133 payload_index: u32,
1129 },1134 },
1135 bool_br: struct {
1136 lhs: Ref,
1137 /// Points to a `Block`.
1138 payload_index: u32,
1139 },
1130 param_type: struct {1140 param_type: struct {
1131 callee: Ref,1141 callee: Ref,
1132 param_index: u32,1142 param_index: u32,
...@@ -1191,6 +1201,12 @@ pub const Inst = struct {...@@ -1191,6 +1201,12 @@ pub const Inst = struct {
1191 operands_len: u32,1201 operands_len: u32,
1192 };1202 };
11931203
1204 /// This data is stored inside extra, with trailing operands according to `body_len`.
1205 /// Each operand is an `Index`.
1206 pub const Block = struct {
1207 body_len: u32,
1208 };
1209
1194 /// Stored inside extra, with trailing arguments according to `args_len`.1210 /// Stored inside extra, with trailing arguments according to `args_len`.
1195 /// Each argument is a `Ref`.1211 /// Each argument is a `Ref`.
1196 pub const Call = struct {1212 pub const Call = struct {
...@@ -1342,6 +1358,7 @@ const Writer = struct {...@@ -1342,6 +1358,7 @@ const Writer = struct {
1342 .err_union_payload_unsafe_ptr,1358 .err_union_payload_unsafe_ptr,
1343 .err_union_code,1359 .err_union_code,
1344 .err_union_code_ptr,1360 .err_union_code_ptr,
1361 .break_flat,
1345 => try self.writeUnNode(stream, inst),1362 => try self.writeUnNode(stream, inst),
13461363
1347 .break_void_tok,1364 .break_void_tok,
...@@ -1358,6 +1375,10 @@ const Writer = struct {...@@ -1358,6 +1375,10 @@ const Writer = struct {
1358 .ensure_err_payload_void,1375 .ensure_err_payload_void,
1359 => try self.writeUnTok(stream, inst),1376 => try self.writeUnTok(stream, inst),
13601377
1378 .bool_br_and,
1379 .bool_br_or,
1380 => try self.writeBoolBr(stream, inst),
1381
1361 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),1382 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
1362 .@"const" => try self.writeConst(stream, inst),1383 .@"const" => try self.writeConst(stream, inst),
1363 .param_type => try self.writeParamType(stream, inst),1384 .param_type => try self.writeParamType(stream, inst),
...@@ -1370,9 +1391,7 @@ const Writer = struct {...@@ -1370,9 +1391,7 @@ const Writer = struct {
1370 .@"asm",1391 .@"asm",
1371 .asm_volatile,1392 .asm_volatile,
1372 .block,1393 .block,
1373 .block_flat,
1374 .block_comptime,1394 .block_comptime,
1375 .block_comptime_flat,
1376 .call,1395 .call,
1377 .call_compile_time,1396 .call_compile_time,
1378 .compile_log,1397 .compile_log,
...@@ -1618,6 +1637,19 @@ const Writer = struct {...@@ -1618,6 +1637,19 @@ const Writer = struct {
1618 return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);1637 return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);
1619 }1638 }
16201639
1640 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1641 const inst_data = self.code.instructions.items(.data)[inst].bool_br;
1642 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
1643 const body = self.code.extra[extra.end..][0..extra.data.body_len];
1644 try self.writeInstRef(stream, inst_data.lhs);
1645 try stream.writeAll(", {\n");
1646 self.indent += 2;
1647 try self.writeBody(stream, body);
1648 self.indent -= 2;
1649 try stream.writeByteNTimes(' ', self.indent);
1650 try stream.writeAll("})");
1651 }
1652
1621 fn writeFnTypeCc(1653 fn writeFnTypeCc(
1622 self: *Writer,1654 self: *Writer,
1623 stream: anytype,1655 stream: anytype,
...@@ -1713,4 +1745,13 @@ const Writer = struct {...@@ -1713,4 +1745,13 @@ const Writer = struct {
1713 @tagName(src), delta_line.line + 1, delta_line.column + 1,1745 @tagName(src), delta_line.line + 1, delta_line.column + 1,
1714 });1746 });
1715 }1747 }
1748
1749 fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void {
1750 for (body) |inst| {
1751 try stream.writeByteNTimes(' ', self.indent);
1752 try stream.print("%{d} ", .{inst});
1753 try self.writeInstToStream(stream, inst);
1754 try stream.writeByte('\n');
1755 }
1756 }
1716};1757};