authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-13 12:38:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 19:06:39-07:00
log9088d40e838b62c8f8ea0e6e68616b72e7704b27
tree7434f7064b0f1bd4fada91c3969c65eb5e437265
parent0170a242bb99e96fcb127e26e1b2fcbe5a19c4ee

stage2: rename zir to Zir

since it now uses top level fields

7 files changed, 2780 insertions(+), 2782 deletions(-)

src/AstGen.zig+230-230
...@@ -15,7 +15,7 @@ const ArrayListUnmanaged = std.ArrayListUnmanaged;...@@ -15,7 +15,7 @@ const ArrayListUnmanaged = std.ArrayListUnmanaged;
15const Value = @import("value.zig").Value;15const Value = @import("value.zig").Value;
16const Type = @import("type.zig").Type;16const Type = @import("type.zig").Type;
17const TypedValue = @import("TypedValue.zig");17const TypedValue = @import("TypedValue.zig");
18const zir = @import("zir.zig");18const Zir = @import("Zir.zig");
19const Module = @import("Module.zig");19const Module = @import("Module.zig");
20const trace = @import("tracy.zig").trace;20const trace = @import("tracy.zig").trace;
21const Scope = Module.Scope;21const Scope = Module.Scope;
...@@ -25,12 +25,12 @@ const Decl = Module.Decl;...@@ -25,12 +25,12 @@ const Decl = Module.Decl;
25const LazySrcLoc = Module.LazySrcLoc;25const LazySrcLoc = Module.LazySrcLoc;
26const BuiltinFn = @import("BuiltinFn.zig");26const BuiltinFn = @import("BuiltinFn.zig");
2727
28instructions: std.MultiArrayList(zir.Inst) = .{},28instructions: std.MultiArrayList(Zir.Inst) = .{},
29string_bytes: ArrayListUnmanaged(u8) = .{},29string_bytes: ArrayListUnmanaged(u8) = .{},
30extra: ArrayListUnmanaged(u32) = .{},30extra: ArrayListUnmanaged(u32) = .{},
31/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert31/// The end of special indexes. `Zir.Inst.Ref` subtracts against this number to convert
32/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.32/// to `Zir.Inst.Index`. The default here is correct if there are 0 parameters.
33ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,33ref_start_index: u32 = Zir.Inst.Ref.typed_value_map.len,
34mod: *Module,34mod: *Module,
35decl: *Decl,35decl: *Decl,
36arena: *Allocator,36arena: *Allocator,
...@@ -65,24 +65,24 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {...@@ -65,24 +65,24 @@ pub fn addExtraAssumeCapacity(astgen: *AstGen, extra: anytype) u32 {
65 inline for (fields) |field| {65 inline for (fields) |field| {
66 astgen.extra.appendAssumeCapacity(switch (field.field_type) {66 astgen.extra.appendAssumeCapacity(switch (field.field_type) {
67 u32 => @field(extra, field.name),67 u32 => @field(extra, field.name),
68 zir.Inst.Ref => @enumToInt(@field(extra, field.name)),68 Zir.Inst.Ref => @enumToInt(@field(extra, field.name)),
69 else => @compileError("bad field type"),69 else => @compileError("bad field type"),
70 });70 });
71 }71 }
72 return result;72 return result;
73}73}
7474
75pub fn appendRefs(astgen: *AstGen, refs: []const zir.Inst.Ref) !void {75pub fn appendRefs(astgen: *AstGen, refs: []const Zir.Inst.Ref) !void {
76 const coerced = @bitCast([]const u32, refs);76 const coerced = @bitCast([]const u32, refs);
77 return astgen.extra.appendSlice(astgen.mod.gpa, coerced);77 return astgen.extra.appendSlice(astgen.mod.gpa, coerced);
78}78}
7979
80pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const zir.Inst.Ref) void {80pub fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void {
81 const coerced = @bitCast([]const u32, refs);81 const coerced = @bitCast([]const u32, refs);
82 astgen.extra.appendSliceAssumeCapacity(coerced);82 astgen.extra.appendSliceAssumeCapacity(coerced);
83}83}
8484
85pub fn refIsNoReturn(astgen: AstGen, inst_ref: zir.Inst.Ref) bool {85pub fn refIsNoReturn(astgen: AstGen, inst_ref: Zir.Inst.Ref) bool {
86 if (inst_ref == .unreachable_value) return true;86 if (inst_ref == .unreachable_value) return true;
87 if (astgen.refToIndex(inst_ref)) |inst_index| {87 if (astgen.refToIndex(inst_ref)) |inst_index| {
88 return astgen.instructions.items(.tag)[inst_index].isNoReturn();88 return astgen.instructions.items(.tag)[inst_index].isNoReturn();
...@@ -90,11 +90,11 @@ pub fn refIsNoReturn(astgen: AstGen, inst_ref: zir.Inst.Ref) bool {...@@ -90,11 +90,11 @@ pub fn refIsNoReturn(astgen: AstGen, inst_ref: zir.Inst.Ref) bool {
90 return false;90 return false;
91}91}
9292
93pub fn indexToRef(astgen: AstGen, inst: zir.Inst.Index) zir.Inst.Ref {93pub fn indexToRef(astgen: AstGen, inst: Zir.Inst.Index) Zir.Inst.Ref {
94 return @intToEnum(zir.Inst.Ref, astgen.ref_start_index + inst);94 return @intToEnum(Zir.Inst.Ref, astgen.ref_start_index + inst);
95}95}
9696
97pub fn refToIndex(astgen: AstGen, inst: zir.Inst.Ref) ?zir.Inst.Index {97pub fn refToIndex(astgen: AstGen, inst: Zir.Inst.Ref) ?Zir.Inst.Index {
98 const ref_int = @enumToInt(inst);98 const ref_int = @enumToInt(inst);
99 if (ref_int >= astgen.ref_start_index) {99 if (ref_int >= astgen.ref_start_index) {
100 return ref_int - astgen.ref_start_index;100 return ref_int - astgen.ref_start_index;
...@@ -124,16 +124,16 @@ pub const ResultLoc = union(enum) {...@@ -124,16 +124,16 @@ pub const ResultLoc = union(enum) {
124 /// may be treated as `none` instead.124 /// may be treated as `none` instead.
125 none_or_ref,125 none_or_ref,
126 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.126 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
127 ty: zir.Inst.Ref,127 ty: Zir.Inst.Ref,
128 /// The expression must store its result into this typed pointer. The result instruction128 /// The expression must store its result into this typed pointer. The result instruction
129 /// from the expression must be ignored.129 /// from the expression must be ignored.
130 ptr: zir.Inst.Ref,130 ptr: Zir.Inst.Ref,
131 /// The expression must store its result into this allocation, which has an inferred type.131 /// The expression must store its result into this allocation, which has an inferred type.
132 /// The result instruction from the expression must be ignored.132 /// The result instruction from the expression must be ignored.
133 /// Always an instruction with tag `alloc_inferred`.133 /// Always an instruction with tag `alloc_inferred`.
134 inferred_ptr: zir.Inst.Ref,134 inferred_ptr: Zir.Inst.Ref,
135 /// There is a pointer for the expression to store its result into, however, its type135 /// There is a pointer for the expression to store its result into, however, its type
136 /// is inferred based on peer type resolution for a `zir.Inst.Block`.136 /// is inferred based on peer type resolution for a `Zir.Inst.Block`.
137 /// The result instruction from the expression must be ignored.137 /// The result instruction from the expression must be ignored.
138 block_ptr: *GenZir,138 block_ptr: *GenZir,
139139
...@@ -188,11 +188,11 @@ pub const ResultLoc = union(enum) {...@@ -188,11 +188,11 @@ pub const ResultLoc = union(enum) {
188 }188 }
189};189};
190190
191pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!zir.Inst.Ref {191pub fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
192 return expr(gz, scope, .{ .ty = .type_type }, type_node);192 return expr(gz, scope, .{ .ty = .type_type }, type_node);
193}193}
194194
195fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref {195fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
196 const tree = gz.tree();196 const tree = gz.tree();
197 const node_tags = tree.nodes.items(.tag);197 const node_tags = tree.nodes.items(.tag);
198 const main_tokens = tree.nodes.items(.main_token);198 const main_tokens = tree.nodes.items(.main_token);
...@@ -386,7 +386,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins...@@ -386,7 +386,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Ins
386/// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the386/// When `rl` is discard, ptr, inferred_ptr, or inferred_ptr, the
387/// result instruction can be used to inspect whether it is isNoReturn() but that is it,387/// result instruction can be used to inspect whether it is isNoReturn() but that is it,
388/// it must otherwise not be used.388/// it must otherwise not be used.
389pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!zir.Inst.Ref {389pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
390 const mod = gz.astgen.mod;390 const mod = gz.astgen.mod;
391 const tree = gz.tree();391 const tree = gz.tree();
392 const main_tokens = tree.nodes.items(.main_token);392 const main_tokens = tree.nodes.items(.main_token);
...@@ -551,7 +551,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -551,7 +551,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
551 .src_node = gz.astgen.decl.nodeIndexToRelative(node),551 .src_node = gz.astgen.decl.nodeIndexToRelative(node),
552 } },552 } },
553 });553 });
554 return zir.Inst.Ref.unreachable_value;554 return Zir.Inst.Ref.unreachable_value;
555 },555 },
556 .@"return" => return ret(gz, scope, node),556 .@"return" => return ret(gz, scope, node),
557 .field_access => return fieldAccess(gz, scope, rl, node),557 .field_access => return fieldAccess(gz, scope, rl, node),
...@@ -570,7 +570,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -570,7 +570,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
570 .slice_open => {570 .slice_open => {
571 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs);571 const lhs = try expr(gz, scope, .ref, node_datas[node].lhs);
572 const start = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs);572 const start = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs);
573 const result = try gz.addPlNode(.slice_start, node, zir.Inst.SliceStart{573 const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{
574 .lhs = lhs,574 .lhs = lhs,
575 .start = start,575 .start = start,
576 });576 });
...@@ -581,7 +581,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -581,7 +581,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
581 const extra = tree.extraData(node_datas[node].rhs, ast.Node.Slice);581 const extra = tree.extraData(node_datas[node].rhs, ast.Node.Slice);
582 const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start);582 const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start);
583 const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end);583 const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end);
584 const result = try gz.addPlNode(.slice_end, node, zir.Inst.SliceEnd{584 const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{
585 .lhs = lhs,585 .lhs = lhs,
586 .start = start,586 .start = start,
587 .end = end,587 .end = end,
...@@ -594,7 +594,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn...@@ -594,7 +594,7 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn
594 const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start);594 const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start);
595 const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end);595 const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end);
596 const sentinel = try expr(gz, scope, .{ .ty = .usize_type }, extra.sentinel);596 const sentinel = try expr(gz, scope, .{ .ty = .usize_type }, extra.sentinel);
597 const result = try gz.addPlNode(.slice_sentinel, node, zir.Inst.SliceSentinel{597 const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
598 .lhs = lhs,598 .lhs = lhs,
599 .start = start,599 .start = start,
600 .end = end,600 .end = end,
...@@ -803,7 +803,7 @@ pub fn structInitExpr(...@@ -803,7 +803,7 @@ pub fn structInitExpr(
803 rl: ResultLoc,803 rl: ResultLoc,
804 node: ast.Node.Index,804 node: ast.Node.Index,
805 struct_init: ast.full.StructInit,805 struct_init: ast.full.StructInit,
806) InnerError!zir.Inst.Ref {806) InnerError!Zir.Inst.Ref {
807 const tree = gz.tree();807 const tree = gz.tree();
808 const astgen = gz.astgen;808 const astgen = gz.astgen;
809 const mod = astgen.mod;809 const mod = astgen.mod;
...@@ -823,14 +823,14 @@ pub fn structInitExpr(...@@ -823,14 +823,14 @@ pub fn structInitExpr(
823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
824 .ref => unreachable, // struct literal not valid as l-value824 .ref => unreachable, // struct literal not valid as l-value
825 .ty => |ty_inst| {825 .ty => |ty_inst| {
826 const fields_list = try gpa.alloc(zir.Inst.StructInit.Item, struct_init.ast.fields.len);826 const fields_list = try gpa.alloc(Zir.Inst.StructInit.Item, struct_init.ast.fields.len);
827 defer gpa.free(fields_list);827 defer gpa.free(fields_list);
828828
829 for (struct_init.ast.fields) |field_init, i| {829 for (struct_init.ast.fields) |field_init, i| {
830 const name_token = tree.firstToken(field_init) - 2;830 const name_token = tree.firstToken(field_init) - 2;
831 const str_index = try gz.identAsString(name_token);831 const str_index = try gz.identAsString(name_token);
832832
833 const field_ty_inst = try gz.addPlNode(.field_type, field_init, zir.Inst.FieldType{833 const field_ty_inst = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{
834 .container_type = ty_inst,834 .container_type = ty_inst,
835 .name_start = str_index,835 .name_start = str_index,
836 });836 });
...@@ -839,31 +839,31 @@ pub fn structInitExpr(...@@ -839,31 +839,31 @@ pub fn structInitExpr(
839 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),839 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
840 };840 };
841 }841 }
842 const init_inst = try gz.addPlNode(.struct_init, node, zir.Inst.StructInit{842 const init_inst = try gz.addPlNode(.struct_init, node, Zir.Inst.StructInit{
843 .fields_len = @intCast(u32, fields_list.len),843 .fields_len = @intCast(u32, fields_list.len),
844 });844 });
845 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +845 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
846 fields_list.len * @typeInfo(zir.Inst.StructInit.Item).Struct.fields.len);846 fields_list.len * @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len);
847 for (fields_list) |field| {847 for (fields_list) |field| {
848 _ = gz.astgen.addExtraAssumeCapacity(field);848 _ = gz.astgen.addExtraAssumeCapacity(field);
849 }849 }
850 return rvalue(gz, scope, rl, init_inst, node);850 return rvalue(gz, scope, rl, init_inst, node);
851 },851 },
852 .ptr => |ptr_inst| {852 .ptr => |ptr_inst| {
853 const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);853 const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len);
854 defer gpa.free(field_ptr_list);854 defer gpa.free(field_ptr_list);
855855
856 for (struct_init.ast.fields) |field_init, i| {856 for (struct_init.ast.fields) |field_init, i| {
857 const name_token = tree.firstToken(field_init) - 2;857 const name_token = tree.firstToken(field_init) - 2;
858 const str_index = try gz.identAsString(name_token);858 const str_index = try gz.identAsString(name_token);
859 const field_ptr = try gz.addPlNode(.field_ptr, field_init, zir.Inst.Field{859 const field_ptr = try gz.addPlNode(.field_ptr, field_init, Zir.Inst.Field{
860 .lhs = ptr_inst,860 .lhs = ptr_inst,
861 .field_name_start = str_index,861 .field_name_start = str_index,
862 });862 });
863 field_ptr_list[i] = astgen.refToIndex(field_ptr).?;863 field_ptr_list[i] = astgen.refToIndex(field_ptr).?;
864 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);864 _ = try expr(gz, scope, .{ .ptr = field_ptr }, field_init);
865 }865 }
866 const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, zir.Inst.Block{866 const validate_inst = try gz.addPlNode(.validate_struct_init_ptr, node, Zir.Inst.Block{
867 .body_len = @intCast(u32, field_ptr_list.len),867 .body_len = @intCast(u32, field_ptr_list.len),
868 });868 });
869 try astgen.extra.appendSlice(gpa, field_ptr_list);869 try astgen.extra.appendSlice(gpa, field_ptr_list);
...@@ -883,7 +883,7 @@ pub fn comptimeExpr(...@@ -883,7 +883,7 @@ pub fn comptimeExpr(
883 scope: *Scope,883 scope: *Scope,
884 rl: ResultLoc,884 rl: ResultLoc,
885 node: ast.Node.Index,885 node: ast.Node.Index,
886) InnerError!zir.Inst.Ref {886) InnerError!Zir.Inst.Ref {
887 const prev_force_comptime = gz.force_comptime;887 const prev_force_comptime = gz.force_comptime;
888 gz.force_comptime = true;888 gz.force_comptime = true;
889 const result = try expr(gz, scope, rl, node);889 const result = try expr(gz, scope, rl, node);
...@@ -891,7 +891,7 @@ pub fn comptimeExpr(...@@ -891,7 +891,7 @@ pub fn comptimeExpr(
891 return result;891 return result;
892}892}
893893
894fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref {894fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
895 const mod = parent_gz.astgen.mod;895 const mod = parent_gz.astgen.mod;
896 const tree = parent_gz.tree();896 const tree = parent_gz.tree();
897 const node_datas = tree.nodes.items(.data);897 const node_datas = tree.nodes.items(.data);
...@@ -922,7 +922,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn...@@ -922,7 +922,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
922922
923 if (rhs == 0) {923 if (rhs == 0) {
924 _ = try parent_gz.addBreak(.@"break", block_inst, .void_value);924 _ = try parent_gz.addBreak(.@"break", block_inst, .void_value);
925 return zir.Inst.Ref.unreachable_value;925 return Zir.Inst.Ref.unreachable_value;
926 }926 }
927 block_gz.break_count += 1;927 block_gz.break_count += 1;
928 const prev_rvalue_rl_count = block_gz.rvalue_rl_count;928 const prev_rvalue_rl_count = block_gz.rvalue_rl_count;
...@@ -943,7 +943,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn...@@ -943,7 +943,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
943 try block_gz.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);943 try block_gz.labeled_store_to_block_ptr_list.append(mod.gpa, store_inst);
944 }944 }
945 }945 }
946 return zir.Inst.Ref.unreachable_value;946 return Zir.Inst.Ref.unreachable_value;
947 },947 },
948 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,948 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
949 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,949 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
...@@ -957,7 +957,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn...@@ -957,7 +957,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn
957 }957 }
958}958}
959959
960fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref {960fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
961 const mod = parent_gz.astgen.mod;961 const mod = parent_gz.astgen.mod;
962 const tree = parent_gz.tree();962 const tree = parent_gz.tree();
963 const node_datas = tree.nodes.items(.data);963 const node_datas = tree.nodes.items(.data);
...@@ -988,7 +988,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)...@@ -988,7 +988,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index)
988988
989 // TODO emit a break_inline if the loop being continued is inline989 // TODO emit a break_inline if the loop being continued is inline
990 _ = try parent_gz.addBreak(.@"break", continue_block, .void_value);990 _ = try parent_gz.addBreak(.@"break", continue_block, .void_value);
991 return zir.Inst.Ref.unreachable_value;991 return Zir.Inst.Ref.unreachable_value;
992 },992 },
993 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,993 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
994 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,994 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
...@@ -1008,7 +1008,7 @@ pub fn blockExpr(...@@ -1008,7 +1008,7 @@ pub fn blockExpr(
1008 rl: ResultLoc,1008 rl: ResultLoc,
1009 block_node: ast.Node.Index,1009 block_node: ast.Node.Index,
1010 statements: []const ast.Node.Index,1010 statements: []const ast.Node.Index,
1011) InnerError!zir.Inst.Ref {1011) InnerError!Zir.Inst.Ref {
1012 const tracy = trace(@src());1012 const tracy = trace(@src());
1013 defer tracy.end();1013 defer tracy.end();
10141014
...@@ -1075,8 +1075,8 @@ fn labeledBlockExpr(...@@ -1075,8 +1075,8 @@ fn labeledBlockExpr(
1075 rl: ResultLoc,1075 rl: ResultLoc,
1076 block_node: ast.Node.Index,1076 block_node: ast.Node.Index,
1077 statements: []const ast.Node.Index,1077 statements: []const ast.Node.Index,
1078 zir_tag: zir.Inst.Tag,1078 zir_tag: Zir.Inst.Tag,
1079) InnerError!zir.Inst.Ref {1079) InnerError!Zir.Inst.Ref {
1080 const tracy = trace(@src());1080 const tracy = trace(@src());
1081 defer tracy.end();1081 defer tracy.end();
10821082
...@@ -1520,8 +1520,8 @@ fn varDecl(...@@ -1520,8 +1520,8 @@ fn varDecl(
1520 };1520 };
1521 defer init_scope.instructions.deinit(gpa);1521 defer init_scope.instructions.deinit(gpa);
15221522
1523 var resolve_inferred_alloc: zir.Inst.Ref = .none;1523 var resolve_inferred_alloc: Zir.Inst.Ref = .none;
1524 var opt_type_inst: zir.Inst.Ref = .none;1524 var opt_type_inst: Zir.Inst.Ref = .none;
1525 if (var_decl.ast.type_node != 0) {1525 if (var_decl.ast.type_node != 0) {
1526 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);1526 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);
1527 opt_type_inst = type_inst;1527 opt_type_inst = type_inst;
...@@ -1593,10 +1593,10 @@ fn varDecl(...@@ -1593,10 +1593,10 @@ fn varDecl(
1593 return &sub_scope.base;1593 return &sub_scope.base;
1594 },1594 },
1595 .keyword_var => {1595 .keyword_var => {
1596 var resolve_inferred_alloc: zir.Inst.Ref = .none;1596 var resolve_inferred_alloc: Zir.Inst.Ref = .none;
1597 const var_data: struct {1597 const var_data: struct {
1598 result_loc: ResultLoc,1598 result_loc: ResultLoc,
1599 alloc: zir.Inst.Ref,1599 alloc: Zir.Inst.Ref,
1600 } = if (var_decl.ast.type_node != 0) a: {1600 } = if (var_decl.ast.type_node != 0) a: {
1601 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);1601 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
16021602
...@@ -1649,7 +1649,7 @@ fn assignOp(...@@ -1649,7 +1649,7 @@ fn assignOp(
1649 gz: *GenZir,1649 gz: *GenZir,
1650 scope: *Scope,1650 scope: *Scope,
1651 infix_node: ast.Node.Index,1651 infix_node: ast.Node.Index,
1652 op_inst_tag: zir.Inst.Tag,1652 op_inst_tag: Zir.Inst.Tag,
1653) InnerError!void {1653) InnerError!void {
1654 const tree = gz.tree();1654 const tree = gz.tree();
1655 const node_datas = tree.nodes.items(.data);1655 const node_datas = tree.nodes.items(.data);
...@@ -1659,14 +1659,14 @@ fn assignOp(...@@ -1659,14 +1659,14 @@ fn assignOp(
1659 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);1659 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
1660 const rhs = try expr(gz, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs);1660 const rhs = try expr(gz, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs);
16611661
1662 const result = try gz.addPlNode(op_inst_tag, infix_node, zir.Inst.Bin{1662 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
1663 .lhs = lhs,1663 .lhs = lhs,
1664 .rhs = rhs,1664 .rhs = rhs,
1665 });1665 });
1666 _ = try gz.addBin(.store, lhs_ptr, result);1666 _ = try gz.addBin(.store, lhs_ptr, result);
1667}1667}
16681668
1669fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!zir.Inst.Ref {1669fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
1670 const tree = gz.tree();1670 const tree = gz.tree();
1671 const node_datas = tree.nodes.items(.data);1671 const node_datas = tree.nodes.items(.data);
16721672
...@@ -1675,7 +1675,7 @@ fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inne...@@ -1675,7 +1675,7 @@ fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inne
1675 return rvalue(gz, scope, rl, result, node);1675 return rvalue(gz, scope, rl, result, node);
1676}1676}
16771677
1678fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!zir.Inst.Ref {1678fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
1679 const tree = gz.tree();1679 const tree = gz.tree();
1680 const node_datas = tree.nodes.items(.data);1680 const node_datas = tree.nodes.items(.data);
16811681
...@@ -1689,8 +1689,8 @@ fn negation(...@@ -1689,8 +1689,8 @@ fn negation(
1689 scope: *Scope,1689 scope: *Scope,
1690 rl: ResultLoc,1690 rl: ResultLoc,
1691 node: ast.Node.Index,1691 node: ast.Node.Index,
1692 tag: zir.Inst.Tag,1692 tag: Zir.Inst.Tag,
1693) InnerError!zir.Inst.Ref {1693) InnerError!Zir.Inst.Ref {
1694 const tree = gz.tree();1694 const tree = gz.tree();
1695 const node_datas = tree.nodes.items(.data);1695 const node_datas = tree.nodes.items(.data);
16961696
...@@ -1705,7 +1705,7 @@ fn ptrType(...@@ -1705,7 +1705,7 @@ fn ptrType(
1705 rl: ResultLoc,1705 rl: ResultLoc,
1706 node: ast.Node.Index,1706 node: ast.Node.Index,
1707 ptr_info: ast.full.PtrType,1707 ptr_info: ast.full.PtrType,
1708) InnerError!zir.Inst.Ref {1708) InnerError!Zir.Inst.Ref {
1709 const tree = gz.tree();1709 const tree = gz.tree();
17101710
1711 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);1711 const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type);
...@@ -1727,10 +1727,10 @@ fn ptrType(...@@ -1727,10 +1727,10 @@ fn ptrType(
1727 return rvalue(gz, scope, rl, result, node);1727 return rvalue(gz, scope, rl, result, node);
1728 }1728 }
17291729
1730 var sentinel_ref: zir.Inst.Ref = .none;1730 var sentinel_ref: Zir.Inst.Ref = .none;
1731 var align_ref: zir.Inst.Ref = .none;1731 var align_ref: Zir.Inst.Ref = .none;
1732 var bit_start_ref: zir.Inst.Ref = .none;1732 var bit_start_ref: Zir.Inst.Ref = .none;
1733 var bit_end_ref: zir.Inst.Ref = .none;1733 var bit_end_ref: Zir.Inst.Ref = .none;
1734 var trailing_count: u32 = 0;1734 var trailing_count: u32 = 0;
17351735
1736 if (ptr_info.ast.sentinel != 0) {1736 if (ptr_info.ast.sentinel != 0) {
...@@ -1752,9 +1752,9 @@ fn ptrType(...@@ -1752,9 +1752,9 @@ fn ptrType(
1752 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);1752 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);
1753 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);1753 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);
1754 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +1754 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +
1755 @typeInfo(zir.Inst.PtrType).Struct.fields.len + trailing_count);1755 @typeInfo(Zir.Inst.PtrType).Struct.fields.len + trailing_count);
17561756
1757 const payload_index = gz.astgen.addExtraAssumeCapacity(zir.Inst.PtrType{ .elem_type = elem_type });1757 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type });
1758 if (sentinel_ref != .none) {1758 if (sentinel_ref != .none) {
1759 gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref));1759 gz.astgen.extra.appendAssumeCapacity(@enumToInt(sentinel_ref));
1760 }1760 }
...@@ -1766,7 +1766,7 @@ fn ptrType(...@@ -1766,7 +1766,7 @@ fn ptrType(
1766 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref));1766 gz.astgen.extra.appendAssumeCapacity(@enumToInt(bit_end_ref));
1767 }1767 }
17681768
1769 const new_index = @intCast(zir.Inst.Index, gz.astgen.instructions.len);1769 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
1770 const result = gz.astgen.indexToRef(new_index);1770 const result = gz.astgen.indexToRef(new_index);
1771 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{1771 gz.astgen.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{
1772 .ptr_type = .{1772 .ptr_type = .{
...@@ -1787,7 +1787,7 @@ fn ptrType(...@@ -1787,7 +1787,7 @@ fn ptrType(
1787 return rvalue(gz, scope, rl, result, node);1787 return rvalue(gz, scope, rl, result, node);
1788}1788}
17891789
1790fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !zir.Inst.Ref {1790fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
1791 const tree = gz.tree();1791 const tree = gz.tree();
1792 const node_datas = tree.nodes.items(.data);1792 const node_datas = tree.nodes.items(.data);
17931793
...@@ -1799,7 +1799,7 @@ fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !z...@@ -1799,7 +1799,7 @@ fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !z
1799 return rvalue(gz, scope, rl, result, node);1799 return rvalue(gz, scope, rl, result, node);
1800}1800}
18011801
1802fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !zir.Inst.Ref {1802fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
1803 const tree = gz.tree();1803 const tree = gz.tree();
1804 const node_datas = tree.nodes.items(.data);1804 const node_datas = tree.nodes.items(.data);
1805 const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);1805 const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel);
...@@ -1818,10 +1818,10 @@ pub fn structDeclInner(...@@ -1818,10 +1818,10 @@ pub fn structDeclInner(
1818 scope: *Scope,1818 scope: *Scope,
1819 node: ast.Node.Index,1819 node: ast.Node.Index,
1820 container_decl: ast.full.ContainerDecl,1820 container_decl: ast.full.ContainerDecl,
1821 tag: zir.Inst.Tag,1821 tag: Zir.Inst.Tag,
1822) InnerError!zir.Inst.Ref {1822) InnerError!Zir.Inst.Ref {
1823 if (container_decl.ast.members.len == 0) {1823 if (container_decl.ast.members.len == 0) {
1824 return gz.addPlNode(tag, node, zir.Inst.StructDecl{ .fields_len = 0, .body_len = 0 });1824 return gz.addPlNode(tag, node, Zir.Inst.StructDecl{ .fields_len = 0, .body_len = 0 });
1825 }1825 }
18261826
1827 const astgen = gz.astgen;1827 const astgen = gz.astgen;
...@@ -1891,7 +1891,7 @@ pub fn structDeclInner(...@@ -1891,7 +1891,7 @@ pub fn structDeclInner(
1891 field_index += 1;1891 field_index += 1;
1892 }1892 }
1893 if (field_index == 0) {1893 if (field_index == 0) {
1894 return gz.addPlNode(tag, node, zir.Inst.StructDecl{ .fields_len = 0, .body_len = 0 });1894 return gz.addPlNode(tag, node, Zir.Inst.StructDecl{ .fields_len = 0, .body_len = 0 });
1895 }1895 }
1896 const empty_slot_count = 16 - (field_index % 16);1896 const empty_slot_count = 16 - (field_index % 16);
1897 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);1897 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
...@@ -1901,11 +1901,11 @@ pub fn structDeclInner(...@@ -1901,11 +1901,11 @@ pub fn structDeclInner(
1901 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);1901 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
19021902
1903 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +1903 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
1904 @typeInfo(zir.Inst.StructDecl).Struct.fields.len +1904 @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
1905 bit_bag.items.len + 1 + fields_data.items.len +1905 bit_bag.items.len + 1 + fields_data.items.len +
1906 block_scope.instructions.items.len);1906 block_scope.instructions.items.len);
1907 const zir_datas = astgen.instructions.items(.data);1907 const zir_datas = astgen.instructions.items(.data);
1908 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(zir.Inst.StructDecl{1908 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
1909 .body_len = @intCast(u32, block_scope.instructions.items.len),1909 .body_len = @intCast(u32, block_scope.instructions.items.len),
1910 .fields_len = @intCast(u32, field_index),1910 .fields_len = @intCast(u32, field_index),
1911 });1911 });
...@@ -1922,7 +1922,7 @@ fn containerDecl(...@@ -1922,7 +1922,7 @@ fn containerDecl(
1922 rl: ResultLoc,1922 rl: ResultLoc,
1923 node: ast.Node.Index,1923 node: ast.Node.Index,
1924 container_decl: ast.full.ContainerDecl,1924 container_decl: ast.full.ContainerDecl,
1925) InnerError!zir.Inst.Ref {1925) InnerError!Zir.Inst.Ref {
1926 const astgen = gz.astgen;1926 const astgen = gz.astgen;
1927 const mod = astgen.mod;1927 const mod = astgen.mod;
1928 const gpa = mod.gpa;1928 const gpa = mod.gpa;
...@@ -1933,7 +1933,7 @@ fn containerDecl(...@@ -1933,7 +1933,7 @@ fn containerDecl(
1933 // We must not create any types until Sema. Here the goal is only to generate1933 // We must not create any types until Sema. Here the goal is only to generate
1934 // ZIR for all the field types, alignments, and default value expressions.1934 // ZIR for all the field types, alignments, and default value expressions.
19351935
1936 const arg_inst: zir.Inst.Ref = if (container_decl.ast.arg != 0)1936 const arg_inst: Zir.Inst.Ref = if (container_decl.ast.arg != 0)
1937 try comptimeExpr(gz, scope, .{ .ty = .type_type }, container_decl.ast.arg)1937 try comptimeExpr(gz, scope, .{ .ty = .type_type }, container_decl.ast.arg)
1938 else1938 else
1939 .none;1939 .none;
...@@ -1941,10 +1941,10 @@ fn containerDecl(...@@ -1941,10 +1941,10 @@ fn containerDecl(
1941 switch (token_tags[container_decl.ast.main_token]) {1941 switch (token_tags[container_decl.ast.main_token]) {
1942 .keyword_struct => {1942 .keyword_struct => {
1943 const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) {1943 const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) {
1944 .keyword_packed => zir.Inst.Tag.struct_decl_packed,1944 .keyword_packed => Zir.Inst.Tag.struct_decl_packed,
1945 .keyword_extern => zir.Inst.Tag.struct_decl_extern,1945 .keyword_extern => Zir.Inst.Tag.struct_decl_extern,
1946 else => unreachable,1946 else => unreachable,
1947 } else zir.Inst.Tag.struct_decl;1947 } else Zir.Inst.Tag.struct_decl;
19481948
1949 assert(arg_inst == .none);1949 assert(arg_inst == .none);
19501950
...@@ -2123,12 +2123,12 @@ fn containerDecl(...@@ -2123,12 +2123,12 @@ fn containerDecl(
2123 // In this case we must generate ZIR code for the tag values, similar to2123 // In this case we must generate ZIR code for the tag values, similar to
2124 // how structs are handled above. The new anonymous Decl will be created in2124 // how structs are handled above. The new anonymous Decl will be created in
2125 // Sema, not AstGen.2125 // Sema, not AstGen.
2126 const tag: zir.Inst.Tag = if (counts.nonexhaustive_node == 0)2126 const tag: Zir.Inst.Tag = if (counts.nonexhaustive_node == 0)
2127 .enum_decl2127 .enum_decl
2128 else2128 else
2129 .enum_decl_nonexhaustive;2129 .enum_decl_nonexhaustive;
2130 if (counts.total_fields == 0) {2130 if (counts.total_fields == 0) {
2131 return gz.addPlNode(tag, node, zir.Inst.EnumDecl{2131 return gz.addPlNode(tag, node, Zir.Inst.EnumDecl{
2132 .tag_type = arg_inst,2132 .tag_type = arg_inst,
2133 .fields_len = 0,2133 .fields_len = 0,
2134 .body_len = 0,2134 .body_len = 0,
...@@ -2194,11 +2194,11 @@ fn containerDecl(...@@ -2194,11 +2194,11 @@ fn containerDecl(
2194 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);2194 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
21952195
2196 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +2196 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
2197 @typeInfo(zir.Inst.EnumDecl).Struct.fields.len +2197 @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len +
2198 bit_bag.items.len + 1 + fields_data.items.len +2198 bit_bag.items.len + 1 + fields_data.items.len +
2199 block_scope.instructions.items.len);2199 block_scope.instructions.items.len);
2200 const zir_datas = astgen.instructions.items(.data);2200 const zir_datas = astgen.instructions.items(.data);
2201 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(zir.Inst.EnumDecl{2201 zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
2202 .tag_type = arg_inst,2202 .tag_type = arg_inst,
2203 .body_len = @intCast(u32, block_scope.instructions.items.len),2203 .body_len = @intCast(u32, block_scope.instructions.items.len),
2204 .fields_len = @intCast(u32, field_index),2204 .fields_len = @intCast(u32, field_index),
...@@ -2222,7 +2222,7 @@ fn errorSetDecl(...@@ -2222,7 +2222,7 @@ fn errorSetDecl(
2222 scope: *Scope,2222 scope: *Scope,
2223 rl: ResultLoc,2223 rl: ResultLoc,
2224 node: ast.Node.Index,2224 node: ast.Node.Index,
2225) InnerError!zir.Inst.Ref {2225) InnerError!Zir.Inst.Ref {
2226 const astgen = gz.astgen;2226 const astgen = gz.astgen;
2227 const mod = astgen.mod;2227 const mod = astgen.mod;
2228 const tree = gz.tree();2228 const tree = gz.tree();
...@@ -2289,12 +2289,12 @@ fn orelseCatchExpr(...@@ -2289,12 +2289,12 @@ fn orelseCatchExpr(
2289 rl: ResultLoc,2289 rl: ResultLoc,
2290 node: ast.Node.Index,2290 node: ast.Node.Index,
2291 lhs: ast.Node.Index,2291 lhs: ast.Node.Index,
2292 cond_op: zir.Inst.Tag,2292 cond_op: Zir.Inst.Tag,
2293 unwrap_op: zir.Inst.Tag,2293 unwrap_op: Zir.Inst.Tag,
2294 unwrap_code_op: zir.Inst.Tag,2294 unwrap_code_op: Zir.Inst.Tag,
2295 rhs: ast.Node.Index,2295 rhs: ast.Node.Index,
2296 payload_token: ?ast.TokenIndex,2296 payload_token: ?ast.TokenIndex,
2297) InnerError!zir.Inst.Ref {2297) InnerError!Zir.Inst.Ref {
2298 const mod = parent_gz.astgen.mod;2298 const mod = parent_gz.astgen.mod;
2299 const tree = parent_gz.tree();2299 const tree = parent_gz.tree();
23002300
...@@ -2408,16 +2408,16 @@ fn finishThenElseBlock(...@@ -2408,16 +2408,16 @@ fn finishThenElseBlock(
2408 block_scope: *GenZir,2408 block_scope: *GenZir,
2409 then_scope: *GenZir,2409 then_scope: *GenZir,
2410 else_scope: *GenZir,2410 else_scope: *GenZir,
2411 condbr: zir.Inst.Index,2411 condbr: Zir.Inst.Index,
2412 cond: zir.Inst.Ref,2412 cond: Zir.Inst.Ref,
2413 then_src: ast.Node.Index,2413 then_src: ast.Node.Index,
2414 else_src: ast.Node.Index,2414 else_src: ast.Node.Index,
2415 then_result: zir.Inst.Ref,2415 then_result: Zir.Inst.Ref,
2416 else_result: zir.Inst.Ref,2416 else_result: Zir.Inst.Ref,
2417 main_block: zir.Inst.Index,2417 main_block: Zir.Inst.Index,
2418 then_break_block: zir.Inst.Index,2418 then_break_block: Zir.Inst.Index,
2419 break_tag: zir.Inst.Tag,2419 break_tag: Zir.Inst.Tag,
2420) InnerError!zir.Inst.Ref {2420) InnerError!Zir.Inst.Ref {
2421 // We now have enough information to decide whether the result instruction should2421 // We now have enough information to decide whether the result instruction should
2422 // be communicated via result location pointer or break instructions.2422 // be communicated via result location pointer or break instructions.
2423 const strat = rl.strategy(block_scope);2423 const strat = rl.strategy(block_scope);
...@@ -2475,7 +2475,7 @@ pub fn fieldAccess(...@@ -2475,7 +2475,7 @@ pub fn fieldAccess(
2475 scope: *Scope,2475 scope: *Scope,
2476 rl: ResultLoc,2476 rl: ResultLoc,
2477 node: ast.Node.Index,2477 node: ast.Node.Index,
2478) InnerError!zir.Inst.Ref {2478) InnerError!Zir.Inst.Ref {
2479 const astgen = gz.astgen;2479 const astgen = gz.astgen;
2480 const mod = astgen.mod;2480 const mod = astgen.mod;
2481 const tree = gz.tree();2481 const tree = gz.tree();
...@@ -2487,11 +2487,11 @@ pub fn fieldAccess(...@@ -2487,11 +2487,11 @@ pub fn fieldAccess(
2487 const field_ident = dot_token + 1;2487 const field_ident = dot_token + 1;
2488 const str_index = try gz.identAsString(field_ident);2488 const str_index = try gz.identAsString(field_ident);
2489 switch (rl) {2489 switch (rl) {
2490 .ref => return gz.addPlNode(.field_ptr, node, zir.Inst.Field{2490 .ref => return gz.addPlNode(.field_ptr, node, Zir.Inst.Field{
2491 .lhs = try expr(gz, scope, .ref, object_node),2491 .lhs = try expr(gz, scope, .ref, object_node),
2492 .field_name_start = str_index,2492 .field_name_start = str_index,
2493 }),2493 }),
2494 else => return rvalue(gz, scope, rl, try gz.addPlNode(.field_val, node, zir.Inst.Field{2494 else => return rvalue(gz, scope, rl, try gz.addPlNode(.field_val, node, Zir.Inst.Field{
2495 .lhs = try expr(gz, scope, .none_or_ref, object_node),2495 .lhs = try expr(gz, scope, .none_or_ref, object_node),
2496 .field_name_start = str_index,2496 .field_name_start = str_index,
2497 }), node),2497 }), node),
...@@ -2503,7 +2503,7 @@ fn arrayAccess(...@@ -2503,7 +2503,7 @@ fn arrayAccess(
2503 scope: *Scope,2503 scope: *Scope,
2504 rl: ResultLoc,2504 rl: ResultLoc,
2505 node: ast.Node.Index,2505 node: ast.Node.Index,
2506) InnerError!zir.Inst.Ref {2506) InnerError!Zir.Inst.Ref {
2507 const tree = gz.tree();2507 const tree = gz.tree();
2508 const main_tokens = tree.nodes.items(.main_token);2508 const main_tokens = tree.nodes.items(.main_token);
2509 const node_datas = tree.nodes.items(.data);2509 const node_datas = tree.nodes.items(.data);
...@@ -2526,12 +2526,12 @@ fn simpleBinOp(...@@ -2526,12 +2526,12 @@ fn simpleBinOp(
2526 scope: *Scope,2526 scope: *Scope,
2527 rl: ResultLoc,2527 rl: ResultLoc,
2528 node: ast.Node.Index,2528 node: ast.Node.Index,
2529 op_inst_tag: zir.Inst.Tag,2529 op_inst_tag: Zir.Inst.Tag,
2530) InnerError!zir.Inst.Ref {2530) InnerError!Zir.Inst.Ref {
2531 const tree = gz.tree();2531 const tree = gz.tree();
2532 const node_datas = tree.nodes.items(.data);2532 const node_datas = tree.nodes.items(.data);
25332533
2534 const result = try gz.addPlNode(op_inst_tag, node, zir.Inst.Bin{2534 const result = try gz.addPlNode(op_inst_tag, node, Zir.Inst.Bin{
2535 .lhs = try expr(gz, scope, .none, node_datas[node].lhs),2535 .lhs = try expr(gz, scope, .none, node_datas[node].lhs),
2536 .rhs = try expr(gz, scope, .none, node_datas[node].rhs),2536 .rhs = try expr(gz, scope, .none, node_datas[node].rhs),
2537 });2537 });
...@@ -2544,8 +2544,8 @@ fn simpleStrTok(...@@ -2544,8 +2544,8 @@ fn simpleStrTok(
2544 rl: ResultLoc,2544 rl: ResultLoc,
2545 ident_token: ast.TokenIndex,2545 ident_token: ast.TokenIndex,
2546 node: ast.Node.Index,2546 node: ast.Node.Index,
2547 op_inst_tag: zir.Inst.Tag,2547 op_inst_tag: Zir.Inst.Tag,
2548) InnerError!zir.Inst.Ref {2548) InnerError!Zir.Inst.Ref {
2549 const str_index = try gz.identAsString(ident_token);2549 const str_index = try gz.identAsString(ident_token);
2550 const result = try gz.addStrTok(op_inst_tag, str_index, ident_token);2550 const result = try gz.addStrTok(op_inst_tag, str_index, ident_token);
2551 return rvalue(gz, scope, rl, result, node);2551 return rvalue(gz, scope, rl, result, node);
...@@ -2556,8 +2556,8 @@ fn boolBinOp(...@@ -2556,8 +2556,8 @@ fn boolBinOp(
2556 scope: *Scope,2556 scope: *Scope,
2557 rl: ResultLoc,2557 rl: ResultLoc,
2558 node: ast.Node.Index,2558 node: ast.Node.Index,
2559 zir_tag: zir.Inst.Tag,2559 zir_tag: Zir.Inst.Tag,
2560) InnerError!zir.Inst.Ref {2560) InnerError!Zir.Inst.Ref {
2561 const node_datas = gz.tree().nodes.items(.data);2561 const node_datas = gz.tree().nodes.items(.data);
25622562
2563 const lhs = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs);2563 const lhs = try expr(gz, scope, .{ .ty = .bool_type }, node_datas[node].lhs);
...@@ -2583,7 +2583,7 @@ fn ifExpr(...@@ -2583,7 +2583,7 @@ fn ifExpr(
2583 rl: ResultLoc,2583 rl: ResultLoc,
2584 node: ast.Node.Index,2584 node: ast.Node.Index,
2585 if_full: ast.full.If,2585 if_full: ast.full.If,
2586) InnerError!zir.Inst.Ref {2586) InnerError!Zir.Inst.Ref {
2587 const mod = parent_gz.astgen.mod;2587 const mod = parent_gz.astgen.mod;
25882588
2589 var block_scope: GenZir = .{2589 var block_scope: GenZir = .{
...@@ -2640,7 +2640,7 @@ fn ifExpr(...@@ -2640,7 +2640,7 @@ fn ifExpr(
2640 const else_node = if_full.ast.else_expr;2640 const else_node = if_full.ast.else_expr;
2641 const else_info: struct {2641 const else_info: struct {
2642 src: ast.Node.Index,2642 src: ast.Node.Index,
2643 result: zir.Inst.Ref,2643 result: Zir.Inst.Ref,
2644 } = if (else_node != 0) blk: {2644 } = if (else_node != 0) blk: {
2645 block_scope.break_count += 1;2645 block_scope.break_count += 1;
2646 const sub_scope = &else_scope.base;2646 const sub_scope = &else_scope.base;
...@@ -2674,19 +2674,19 @@ fn ifExpr(...@@ -2674,19 +2674,19 @@ fn ifExpr(
2674}2674}
26752675
2676fn setCondBrPayload(2676fn setCondBrPayload(
2677 condbr: zir.Inst.Index,2677 condbr: Zir.Inst.Index,
2678 cond: zir.Inst.Ref,2678 cond: Zir.Inst.Ref,
2679 then_scope: *GenZir,2679 then_scope: *GenZir,
2680 else_scope: *GenZir,2680 else_scope: *GenZir,
2681) !void {2681) !void {
2682 const astgen = then_scope.astgen;2682 const astgen = then_scope.astgen;
26832683
2684 try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len +2684 try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len +
2685 @typeInfo(zir.Inst.CondBr).Struct.fields.len +2685 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
2686 then_scope.instructions.items.len + else_scope.instructions.items.len);2686 then_scope.instructions.items.len + else_scope.instructions.items.len);
26872687
2688 const zir_datas = astgen.instructions.items(.data);2688 const zir_datas = astgen.instructions.items(.data);
2689 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(zir.Inst.CondBr{2689 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
2690 .condition = cond,2690 .condition = cond,
2691 .then_body_len = @intCast(u32, then_scope.instructions.items.len),2691 .then_body_len = @intCast(u32, then_scope.instructions.items.len),
2692 .else_body_len = @intCast(u32, else_scope.instructions.items.len),2692 .else_body_len = @intCast(u32, else_scope.instructions.items.len),
...@@ -2697,19 +2697,19 @@ fn setCondBrPayload(...@@ -2697,19 +2697,19 @@ fn setCondBrPayload(
26972697
2698/// If `elide_block_store_ptr` is set, expects to find exactly 1 .store_to_block_ptr instruction.2698/// If `elide_block_store_ptr` is set, expects to find exactly 1 .store_to_block_ptr instruction.
2699fn setCondBrPayloadElideBlockStorePtr(2699fn setCondBrPayloadElideBlockStorePtr(
2700 condbr: zir.Inst.Index,2700 condbr: Zir.Inst.Index,
2701 cond: zir.Inst.Ref,2701 cond: Zir.Inst.Ref,
2702 then_scope: *GenZir,2702 then_scope: *GenZir,
2703 else_scope: *GenZir,2703 else_scope: *GenZir,
2704) !void {2704) !void {
2705 const astgen = then_scope.astgen;2705 const astgen = then_scope.astgen;
27062706
2707 try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len +2707 try astgen.extra.ensureCapacity(astgen.mod.gpa, astgen.extra.items.len +
2708 @typeInfo(zir.Inst.CondBr).Struct.fields.len +2708 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
2709 then_scope.instructions.items.len + else_scope.instructions.items.len - 2);2709 then_scope.instructions.items.len + else_scope.instructions.items.len - 2);
27102710
2711 const zir_datas = astgen.instructions.items(.data);2711 const zir_datas = astgen.instructions.items(.data);
2712 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(zir.Inst.CondBr{2712 zir_datas[condbr].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
2713 .condition = cond,2713 .condition = cond,
2714 .then_body_len = @intCast(u32, then_scope.instructions.items.len - 1),2714 .then_body_len = @intCast(u32, then_scope.instructions.items.len - 1),
2715 .else_body_len = @intCast(u32, else_scope.instructions.items.len - 1),2715 .else_body_len = @intCast(u32, else_scope.instructions.items.len - 1),
...@@ -2731,14 +2731,14 @@ fn whileExpr(...@@ -2731,14 +2731,14 @@ fn whileExpr(
2731 rl: ResultLoc,2731 rl: ResultLoc,
2732 node: ast.Node.Index,2732 node: ast.Node.Index,
2733 while_full: ast.full.While,2733 while_full: ast.full.While,
2734) InnerError!zir.Inst.Ref {2734) InnerError!Zir.Inst.Ref {
2735 const mod = parent_gz.astgen.mod;2735 const mod = parent_gz.astgen.mod;
2736 if (while_full.label_token) |label_token| {2736 if (while_full.label_token) |label_token| {
2737 try checkLabelRedefinition(mod, scope, label_token);2737 try checkLabelRedefinition(mod, scope, label_token);
2738 }2738 }
27392739
2740 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;2740 const is_inline = parent_gz.force_comptime or while_full.inline_token != null;
2741 const loop_tag: zir.Inst.Tag = if (is_inline) .block_inline else .loop;2741 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
2742 const loop_block = try parent_gz.addBlock(loop_tag, node);2742 const loop_block = try parent_gz.addBlock(loop_tag, node);
2743 try parent_gz.instructions.append(mod.gpa, loop_block);2743 try parent_gz.instructions.append(mod.gpa, loop_block);
27442744
...@@ -2771,9 +2771,9 @@ fn whileExpr(...@@ -2771,9 +2771,9 @@ fn whileExpr(
2771 }2771 }
2772 };2772 };
27732773
2774 const condbr_tag: zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;2774 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
2775 const condbr = try continue_scope.addCondBr(condbr_tag, node);2775 const condbr = try continue_scope.addCondBr(condbr_tag, node);
2776 const block_tag: zir.Inst.Tag = if (is_inline) .block_inline else .block;2776 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
2777 const cond_block = try loop_scope.addBlock(block_tag, node);2777 const cond_block = try loop_scope.addBlock(block_tag, node);
2778 try loop_scope.instructions.append(mod.gpa, cond_block);2778 try loop_scope.instructions.append(mod.gpa, cond_block);
2779 try continue_scope.setBlockBody(cond_block);2779 try continue_scope.setBlockBody(cond_block);
...@@ -2784,7 +2784,7 @@ fn whileExpr(...@@ -2784,7 +2784,7 @@ fn whileExpr(
2784 if (while_full.ast.cont_expr != 0) {2784 if (while_full.ast.cont_expr != 0) {
2785 _ = try expr(&loop_scope, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr);2785 _ = try expr(&loop_scope, &loop_scope.base, .{ .ty = .void_type }, while_full.ast.cont_expr);
2786 }2786 }
2787 const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;2787 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
2788 _ = try loop_scope.addNode(repeat_tag, node);2788 _ = try loop_scope.addNode(repeat_tag, node);
27892789
2790 try loop_scope.setBlockBody(loop_block);2790 try loop_scope.setBlockBody(loop_block);
...@@ -2821,7 +2821,7 @@ fn whileExpr(...@@ -2821,7 +2821,7 @@ fn whileExpr(
2821 const else_node = while_full.ast.else_expr;2821 const else_node = while_full.ast.else_expr;
2822 const else_info: struct {2822 const else_info: struct {
2823 src: ast.Node.Index,2823 src: ast.Node.Index,
2824 result: zir.Inst.Ref,2824 result: Zir.Inst.Ref,
2825 } = if (else_node != 0) blk: {2825 } = if (else_node != 0) blk: {
2826 loop_scope.break_count += 1;2826 loop_scope.break_count += 1;
2827 const sub_scope = &else_scope.base;2827 const sub_scope = &else_scope.base;
...@@ -2839,7 +2839,7 @@ fn whileExpr(...@@ -2839,7 +2839,7 @@ fn whileExpr(
2839 return mod.failTok(scope, some.token, "unused while loop label", .{});2839 return mod.failTok(scope, some.token, "unused while loop label", .{});
2840 }2840 }
2841 }2841 }
2842 const break_tag: zir.Inst.Tag = if (is_inline) .break_inline else .@"break";2842 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
2843 return finishThenElseBlock(2843 return finishThenElseBlock(
2844 parent_gz,2844 parent_gz,
2845 scope,2845 scope,
...@@ -2866,7 +2866,7 @@ fn forExpr(...@@ -2866,7 +2866,7 @@ fn forExpr(
2866 rl: ResultLoc,2866 rl: ResultLoc,
2867 node: ast.Node.Index,2867 node: ast.Node.Index,
2868 for_full: ast.full.While,2868 for_full: ast.full.While,
2869) InnerError!zir.Inst.Ref {2869) InnerError!Zir.Inst.Ref {
2870 const mod = parent_gz.astgen.mod;2870 const mod = parent_gz.astgen.mod;
2871 if (for_full.label_token) |label_token| {2871 if (for_full.label_token) |label_token| {
2872 try checkLabelRedefinition(mod, scope, label_token);2872 try checkLabelRedefinition(mod, scope, label_token);
...@@ -2886,7 +2886,7 @@ fn forExpr(...@@ -2886,7 +2886,7 @@ fn forExpr(
2886 break :blk index_ptr;2886 break :blk index_ptr;
2887 };2887 };
28882888
2889 const loop_tag: zir.Inst.Tag = if (is_inline) .block_inline else .loop;2889 const loop_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .loop;
2890 const loop_block = try parent_gz.addBlock(loop_tag, node);2890 const loop_block = try parent_gz.addBlock(loop_tag, node);
2891 try parent_gz.instructions.append(mod.gpa, loop_block);2891 try parent_gz.instructions.append(mod.gpa, loop_block);
28922892
...@@ -2909,26 +2909,26 @@ fn forExpr(...@@ -2909,26 +2909,26 @@ fn forExpr(
29092909
2910 // check condition i < array_expr.len2910 // check condition i < array_expr.len
2911 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);2911 const index = try cond_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
2912 const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, zir.Inst.Bin{2912 const cond = try cond_scope.addPlNode(.cmp_lt, for_full.ast.cond_expr, Zir.Inst.Bin{
2913 .lhs = index,2913 .lhs = index,
2914 .rhs = len,2914 .rhs = len,
2915 });2915 });
29162916
2917 const condbr_tag: zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;2917 const condbr_tag: Zir.Inst.Tag = if (is_inline) .condbr_inline else .condbr;
2918 const condbr = try cond_scope.addCondBr(condbr_tag, node);2918 const condbr = try cond_scope.addCondBr(condbr_tag, node);
2919 const block_tag: zir.Inst.Tag = if (is_inline) .block_inline else .block;2919 const block_tag: Zir.Inst.Tag = if (is_inline) .block_inline else .block;
2920 const cond_block = try loop_scope.addBlock(block_tag, node);2920 const cond_block = try loop_scope.addBlock(block_tag, node);
2921 try loop_scope.instructions.append(mod.gpa, cond_block);2921 try loop_scope.instructions.append(mod.gpa, cond_block);
2922 try cond_scope.setBlockBody(cond_block);2922 try cond_scope.setBlockBody(cond_block);
29232923
2924 // Increment the index variable.2924 // Increment the index variable.
2925 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);2925 const index_2 = try loop_scope.addUnNode(.load, index_ptr, for_full.ast.cond_expr);
2926 const index_plus_one = try loop_scope.addPlNode(.add, node, zir.Inst.Bin{2926 const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{
2927 .lhs = index_2,2927 .lhs = index_2,
2928 .rhs = .one_usize,2928 .rhs = .one_usize,
2929 });2929 });
2930 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);2930 _ = try loop_scope.addBin(.store, index_ptr, index_plus_one);
2931 const repeat_tag: zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;2931 const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
2932 _ = try loop_scope.addNode(repeat_tag, node);2932 _ = try loop_scope.addNode(repeat_tag, node);
29332933
2934 try loop_scope.setBlockBody(loop_block);2934 try loop_scope.setBlockBody(loop_block);
...@@ -2996,7 +2996,7 @@ fn forExpr(...@@ -2996,7 +2996,7 @@ fn forExpr(
2996 const else_node = for_full.ast.else_expr;2996 const else_node = for_full.ast.else_expr;
2997 const else_info: struct {2997 const else_info: struct {
2998 src: ast.Node.Index,2998 src: ast.Node.Index,
2999 result: zir.Inst.Ref,2999 result: Zir.Inst.Ref,
3000 } = if (else_node != 0) blk: {3000 } = if (else_node != 0) blk: {
3001 loop_scope.break_count += 1;3001 loop_scope.break_count += 1;
3002 const sub_scope = &else_scope.base;3002 const sub_scope = &else_scope.base;
...@@ -3014,7 +3014,7 @@ fn forExpr(...@@ -3014,7 +3014,7 @@ fn forExpr(
3014 return mod.failTok(scope, some.token, "unused for loop label", .{});3014 return mod.failTok(scope, some.token, "unused for loop label", .{});
3015 }3015 }
3016 }3016 }
3017 const break_tag: zir.Inst.Tag = if (is_inline) .break_inline else .@"break";3017 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
3018 return finishThenElseBlock(3018 return finishThenElseBlock(
3019 parent_gz,3019 parent_gz,
3020 scope,3020 scope,
...@@ -3145,7 +3145,7 @@ fn switchExpr(...@@ -3145,7 +3145,7 @@ fn switchExpr(
3145 scope: *Scope,3145 scope: *Scope,
3146 rl: ResultLoc,3146 rl: ResultLoc,
3147 switch_node: ast.Node.Index,3147 switch_node: ast.Node.Index,
3148) InnerError!zir.Inst.Ref {3148) InnerError!Zir.Inst.Ref {
3149 const astgen = parent_gz.astgen;3149 const astgen = parent_gz.astgen;
3150 const mod = astgen.mod;3150 const mod = astgen.mod;
3151 const gpa = mod.gpa;3151 const gpa = mod.gpa;
...@@ -3164,7 +3164,7 @@ fn switchExpr(...@@ -3164,7 +3164,7 @@ fn switchExpr(
3164 var any_payload_is_ref = false;3164 var any_payload_is_ref = false;
3165 var scalar_cases_len: u32 = 0;3165 var scalar_cases_len: u32 = 0;
3166 var multi_cases_len: u32 = 0;3166 var multi_cases_len: u32 = 0;
3167 var special_prong: zir.SpecialProng = .none;3167 var special_prong: Zir.SpecialProng = .none;
3168 var special_node: ast.Node.Index = 0;3168 var special_node: ast.Node.Index = 0;
3169 var else_src: ?LazySrcLoc = null;3169 var else_src: ?LazySrcLoc = null;
3170 var underscore_src: ?LazySrcLoc = null;3170 var underscore_src: ?LazySrcLoc = null;
...@@ -3265,7 +3265,7 @@ fn switchExpr(...@@ -3265,7 +3265,7 @@ fn switchExpr(
3265 const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none;3265 const operand_rl: ResultLoc = if (any_payload_is_ref) .ref else .none;
3266 const operand = try expr(parent_gz, scope, operand_rl, operand_node);3266 const operand = try expr(parent_gz, scope, operand_rl, operand_node);
3267 // We need the type of the operand to use as the result location for all the prong items.3267 // We need the type of the operand to use as the result location for all the prong items.
3268 const typeof_tag: zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof;3268 const typeof_tag: Zir.Inst.Tag = if (any_payload_is_ref) .typeof_elem else .typeof;
3269 const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node);3269 const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node);
3270 const item_rl: ResultLoc = .{ .ty = operand_ty_inst };3270 const item_rl: ResultLoc = .{ .ty = operand_ty_inst };
32713271
...@@ -3321,7 +3321,7 @@ fn switchExpr(...@@ -3321,7 +3321,7 @@ fn switchExpr(
3321 }3321 }
3322 break :blk &case_scope.base;3322 break :blk &case_scope.base;
3323 }3323 }
3324 const capture_tag: zir.Inst.Tag = if (is_ptr)3324 const capture_tag: Zir.Inst.Tag = if (is_ptr)
3325 .switch_capture_else_ref3325 .switch_capture_else_ref
3326 else3326 else
3327 .switch_capture_else;3327 .switch_capture_else;
...@@ -3347,7 +3347,7 @@ fn switchExpr(...@@ -3347,7 +3347,7 @@ fn switchExpr(
3347 block_scope.break_count += 1;3347 block_scope.break_count += 1;
3348 _ = try case_scope.addBreak(.@"break", switch_block, case_result);3348 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
3349 }3349 }
3350 // Documentation for this: `zir.Inst.SwitchBlock` and `zir.Inst.SwitchBlockMulti`.3350 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
3351 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +3351 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +
3352 3 + // operand, scalar_cases_len, else body len3352 3 + // operand, scalar_cases_len, else body len
3353 @boolToInt(multi_cases_len != 0) +3353 @boolToInt(multi_cases_len != 0) +
...@@ -3360,7 +3360,7 @@ fn switchExpr(...@@ -3360,7 +3360,7 @@ fn switchExpr(
3360 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));3360 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
3361 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);3361 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
3362 } else {3362 } else {
3363 // Documentation for this: `zir.Inst.SwitchBlock` and `zir.Inst.SwitchBlockMulti`.3363 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
3364 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +3364 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +
3365 2 + // operand, scalar_cases_len3365 2 + // operand, scalar_cases_len
3366 @boolToInt(multi_cases_len != 0));3366 @boolToInt(multi_cases_len != 0));
...@@ -3404,7 +3404,7 @@ fn switchExpr(...@@ -3404,7 +3404,7 @@ fn switchExpr(
3404 }3404 }
3405 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);3405 const is_multi_case_bits: u2 = @boolToInt(is_multi_case);
3406 const is_ptr_bits: u2 = @boolToInt(is_ptr);3406 const is_ptr_bits: u2 = @boolToInt(is_ptr);
3407 const capture_tag: zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {3407 const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) {
3408 0b00 => .switch_capture,3408 0b00 => .switch_capture,
3409 0b01 => .switch_capture_ref,3409 0b01 => .switch_capture_ref,
3410 0b10 => .switch_capture_multi,3410 0b10 => .switch_capture_multi,
...@@ -3495,9 +3495,9 @@ fn switchExpr(...@@ -3495,9 +3495,9 @@ fn switchExpr(
3495 const multi_bit: u4 = @boolToInt(multi_cases_len != 0);3495 const multi_bit: u4 = @boolToInt(multi_cases_len != 0);
3496 const special_prong_bits: u4 = @enumToInt(special_prong);3496 const special_prong_bits: u4 = @enumToInt(special_prong);
3497 comptime {3497 comptime {
3498 assert(@enumToInt(zir.SpecialProng.none) == 0b00);3498 assert(@enumToInt(Zir.SpecialProng.none) == 0b00);
3499 assert(@enumToInt(zir.SpecialProng.@"else") == 0b01);3499 assert(@enumToInt(Zir.SpecialProng.@"else") == 0b01);
3500 assert(@enumToInt(zir.SpecialProng.under) == 0b10);3500 assert(@enumToInt(Zir.SpecialProng.under) == 0b10);
3501 }3501 }
3502 const zir_tags = astgen.instructions.items(.tag);3502 const zir_tags = astgen.instructions.items(.tag);
3503 zir_tags[switch_block] = switch ((ref_bit << 3) | (special_prong_bits << 1) | multi_bit) {3503 zir_tags[switch_block] = switch ((ref_bit << 3) | (special_prong_bits << 1) | multi_bit) {
...@@ -3732,13 +3732,13 @@ fn switchExpr(...@@ -3732,13 +3732,13 @@ fn switchExpr(
3732 }3732 }
3733}3733}
37343734
3735fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref {3735fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref {
3736 const tree = gz.tree();3736 const tree = gz.tree();
3737 const node_datas = tree.nodes.items(.data);3737 const node_datas = tree.nodes.items(.data);
3738 const main_tokens = tree.nodes.items(.main_token);3738 const main_tokens = tree.nodes.items(.main_token);
37393739
3740 const operand_node = node_datas[node].lhs;3740 const operand_node = node_datas[node].lhs;
3741 const operand: zir.Inst.Ref = if (operand_node != 0) operand: {3741 const operand: Zir.Inst.Ref = if (operand_node != 0) operand: {
3742 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{3742 const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{
3743 .ptr = try gz.addNode(.ret_ptr, node),3743 .ptr = try gz.addNode(.ret_ptr, node),
3744 } else .{3744 } else .{
...@@ -3747,7 +3747,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref...@@ -3747,7 +3747,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!zir.Inst.Ref
3747 break :operand try expr(gz, scope, rl, operand_node);3747 break :operand try expr(gz, scope, rl, operand_node);
3748 } else .void_value;3748 } else .void_value;
3749 _ = try gz.addUnNode(.ret_node, operand, node);3749 _ = try gz.addUnNode(.ret_node, operand, node);
3750 return zir.Inst.Ref.unreachable_value;3750 return Zir.Inst.Ref.unreachable_value;
3751}3751}
37523752
3753fn identifier(3753fn identifier(
...@@ -3755,7 +3755,7 @@ fn identifier(...@@ -3755,7 +3755,7 @@ fn identifier(
3755 scope: *Scope,3755 scope: *Scope,
3756 rl: ResultLoc,3756 rl: ResultLoc,
3757 ident: ast.Node.Index,3757 ident: ast.Node.Index,
3758) InnerError!zir.Inst.Ref {3758) InnerError!Zir.Inst.Ref {
3759 const tracy = trace(@src());3759 const tracy = trace(@src());
3760 defer tracy.end();3760 defer tracy.end();
37613761
...@@ -3849,7 +3849,7 @@ fn stringLiteral(...@@ -3849,7 +3849,7 @@ fn stringLiteral(
3849 scope: *Scope,3849 scope: *Scope,
3850 rl: ResultLoc,3850 rl: ResultLoc,
3851 node: ast.Node.Index,3851 node: ast.Node.Index,
3852) InnerError!zir.Inst.Ref {3852) InnerError!Zir.Inst.Ref {
3853 const tree = gz.tree();3853 const tree = gz.tree();
3854 const main_tokens = tree.nodes.items(.main_token);3854 const main_tokens = tree.nodes.items(.main_token);
3855 const string_bytes = &gz.astgen.string_bytes;3855 const string_bytes = &gz.astgen.string_bytes;
...@@ -3873,7 +3873,7 @@ fn multilineStringLiteral(...@@ -3873,7 +3873,7 @@ fn multilineStringLiteral(
3873 scope: *Scope,3873 scope: *Scope,
3874 rl: ResultLoc,3874 rl: ResultLoc,
3875 node: ast.Node.Index,3875 node: ast.Node.Index,
3876) InnerError!zir.Inst.Ref {3876) InnerError!Zir.Inst.Ref {
3877 const tree = gz.tree();3877 const tree = gz.tree();
3878 const node_datas = tree.nodes.items(.data);3878 const node_datas = tree.nodes.items(.data);
3879 const main_tokens = tree.nodes.items(.main_token);3879 const main_tokens = tree.nodes.items(.main_token);
...@@ -3911,7 +3911,7 @@ fn multilineStringLiteral(...@@ -3911,7 +3911,7 @@ fn multilineStringLiteral(
3911 return rvalue(gz, scope, rl, result, node);3911 return rvalue(gz, scope, rl, result, node);
3912}3912}
39133913
3914fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !zir.Inst.Ref {3914fn charLiteral(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref {
3915 const mod = gz.astgen.mod;3915 const mod = gz.astgen.mod;
3916 const tree = gz.tree();3916 const tree = gz.tree();
3917 const main_tokens = tree.nodes.items(.main_token);3917 const main_tokens = tree.nodes.items(.main_token);
...@@ -3936,13 +3936,13 @@ fn integerLiteral(...@@ -3936,13 +3936,13 @@ fn integerLiteral(
3936 scope: *Scope,3936 scope: *Scope,
3937 rl: ResultLoc,3937 rl: ResultLoc,
3938 node: ast.Node.Index,3938 node: ast.Node.Index,
3939) InnerError!zir.Inst.Ref {3939) InnerError!Zir.Inst.Ref {
3940 const tree = gz.tree();3940 const tree = gz.tree();
3941 const main_tokens = tree.nodes.items(.main_token);3941 const main_tokens = tree.nodes.items(.main_token);
3942 const int_token = main_tokens[node];3942 const int_token = main_tokens[node];
3943 const prefixed_bytes = tree.tokenSlice(int_token);3943 const prefixed_bytes = tree.tokenSlice(int_token);
3944 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| {3944 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| {
3945 const result: zir.Inst.Ref = switch (small_int) {3945 const result: Zir.Inst.Ref = switch (small_int) {
3946 0 => .zero,3946 0 => .zero,
3947 1 => .one,3947 1 => .one,
3948 else => try gz.addInt(small_int),3948 else => try gz.addInt(small_int),
...@@ -3958,7 +3958,7 @@ fn floatLiteral(...@@ -3958,7 +3958,7 @@ fn floatLiteral(
3958 scope: *Scope,3958 scope: *Scope,
3959 rl: ResultLoc,3959 rl: ResultLoc,
3960 node: ast.Node.Index,3960 node: ast.Node.Index,
3961) InnerError!zir.Inst.Ref {3961) InnerError!Zir.Inst.Ref {
3962 const arena = gz.astgen.arena;3962 const arena = gz.astgen.arena;
3963 const tree = gz.tree();3963 const tree = gz.tree();
3964 const main_tokens = tree.nodes.items(.main_token);3964 const main_tokens = tree.nodes.items(.main_token);
...@@ -3983,7 +3983,7 @@ fn floatLiteral(...@@ -3983,7 +3983,7 @@ fn floatLiteral(
3983 // We need to use 128 bits. Break the float into 4 u32 values so we can3983 // We need to use 128 bits. Break the float into 4 u32 values so we can
3984 // put it into the `extra` array.3984 // put it into the `extra` array.
3985 const int_bits = @bitCast(u128, float_number);3985 const int_bits = @bitCast(u128, float_number);
3986 const result = try gz.addPlNode(.float128, node, zir.Inst.Float128{3986 const result = try gz.addPlNode(.float128, node, Zir.Inst.Float128{
3987 .piece0 = @truncate(u32, int_bits),3987 .piece0 = @truncate(u32, int_bits),
3988 .piece1 = @truncate(u32, int_bits >> 32),3988 .piece1 = @truncate(u32, int_bits >> 32),
3989 .piece2 = @truncate(u32, int_bits >> 64),3989 .piece2 = @truncate(u32, int_bits >> 64),
...@@ -3998,7 +3998,7 @@ fn asmExpr(...@@ -3998,7 +3998,7 @@ fn asmExpr(
3998 rl: ResultLoc,3998 rl: ResultLoc,
3999 node: ast.Node.Index,3999 node: ast.Node.Index,
4000 full: ast.full.Asm,4000 full: ast.full.Asm,
4001) InnerError!zir.Inst.Ref {4001) InnerError!Zir.Inst.Ref {
4002 const mod = gz.astgen.mod;4002 const mod = gz.astgen.mod;
4003 const arena = gz.astgen.arena;4003 const arena = gz.astgen.arena;
4004 const tree = gz.tree();4004 const tree = gz.tree();
...@@ -4014,7 +4014,7 @@ fn asmExpr(...@@ -4014,7 +4014,7 @@ fn asmExpr(
4014 }4014 }
40154015
4016 const constraints = try arena.alloc(u32, full.inputs.len);4016 const constraints = try arena.alloc(u32, full.inputs.len);
4017 const args = try arena.alloc(zir.Inst.Ref, full.inputs.len);4017 const args = try arena.alloc(Zir.Inst.Ref, full.inputs.len);
40184018
4019 for (full.inputs) |input, i| {4019 for (full.inputs) |input, i| {
4020 const constraint_token = main_tokens[input] + 2;4020 const constraint_token = main_tokens[input] + 2;
...@@ -4027,8 +4027,8 @@ fn asmExpr(...@@ -4027,8 +4027,8 @@ fn asmExpr(
4027 args[i] = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input].lhs);4027 args[i] = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[input].lhs);
4028 }4028 }
40294029
4030 const tag: zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm";4030 const tag: Zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm";
4031 const result = try gz.addPlNode(tag, node, zir.Inst.Asm{4031 const result = try gz.addPlNode(tag, node, Zir.Inst.Asm{
4032 .asm_source = asm_source,4032 .asm_source = asm_source,
4033 .return_type = .void_type,4033 .return_type = .void_type,
4034 .output = .none,4034 .output = .none,
...@@ -4051,7 +4051,7 @@ fn as(...@@ -4051,7 +4051,7 @@ fn as(
4051 node: ast.Node.Index,4051 node: ast.Node.Index,
4052 lhs: ast.Node.Index,4052 lhs: ast.Node.Index,
4053 rhs: ast.Node.Index,4053 rhs: ast.Node.Index,
4054) InnerError!zir.Inst.Ref {4054) InnerError!Zir.Inst.Ref {
4055 const dest_type = try typeExpr(gz, scope, lhs);4055 const dest_type = try typeExpr(gz, scope, lhs);
4056 switch (rl) {4056 switch (rl) {
4057 .none, .none_or_ref, .discard, .ref, .ty => {4057 .none, .none_or_ref, .discard, .ref, .ty => {
...@@ -4077,10 +4077,10 @@ fn asRlPtr(...@@ -4077,10 +4077,10 @@ fn asRlPtr(
4077 parent_gz: *GenZir,4077 parent_gz: *GenZir,
4078 scope: *Scope,4078 scope: *Scope,
4079 rl: ResultLoc,4079 rl: ResultLoc,
4080 result_ptr: zir.Inst.Ref,4080 result_ptr: Zir.Inst.Ref,
4081 operand_node: ast.Node.Index,4081 operand_node: ast.Node.Index,
4082 dest_type: zir.Inst.Ref,4082 dest_type: Zir.Inst.Ref,
4083) InnerError!zir.Inst.Ref {4083) InnerError!Zir.Inst.Ref {
4084 // Detect whether this expr() call goes into rvalue() to store the result into the4084 // Detect whether this expr() call goes into rvalue() to store the result into the
4085 // result location. If it does, elide the coerce_result_ptr instruction4085 // result location. If it does, elide the coerce_result_ptr instruction
4086 // as well as the store instruction, instead passing the result as an rvalue.4086 // as well as the store instruction, instead passing the result as an rvalue.
...@@ -4126,13 +4126,13 @@ fn bitCast(...@@ -4126,13 +4126,13 @@ fn bitCast(
4126 node: ast.Node.Index,4126 node: ast.Node.Index,
4127 lhs: ast.Node.Index,4127 lhs: ast.Node.Index,
4128 rhs: ast.Node.Index,4128 rhs: ast.Node.Index,
4129) InnerError!zir.Inst.Ref {4129) InnerError!Zir.Inst.Ref {
4130 const mod = gz.astgen.mod;4130 const mod = gz.astgen.mod;
4131 const dest_type = try typeExpr(gz, scope, lhs);4131 const dest_type = try typeExpr(gz, scope, lhs);
4132 switch (rl) {4132 switch (rl) {
4133 .none, .discard, .ty => {4133 .none, .discard, .ty => {
4134 const operand = try expr(gz, scope, .none, rhs);4134 const operand = try expr(gz, scope, .none, rhs);
4135 const result = try gz.addPlNode(.bitcast, node, zir.Inst.Bin{4135 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
4136 .lhs = dest_type,4136 .lhs = dest_type,
4137 .rhs = operand,4137 .rhs = operand,
4138 });4138 });
...@@ -4159,7 +4159,7 @@ fn typeOf(...@@ -4159,7 +4159,7 @@ fn typeOf(
4159 rl: ResultLoc,4159 rl: ResultLoc,
4160 node: ast.Node.Index,4160 node: ast.Node.Index,
4161 params: []const ast.Node.Index,4161 params: []const ast.Node.Index,
4162) InnerError!zir.Inst.Ref {4162) InnerError!Zir.Inst.Ref {
4163 if (params.len < 1) {4163 if (params.len < 1) {
4164 return gz.astgen.mod.failNode(scope, node, "expected at least 1 argument, found 0", .{});4164 return gz.astgen.mod.failNode(scope, node, "expected at least 1 argument, found 0", .{});
4165 }4165 }
...@@ -4168,12 +4168,12 @@ fn typeOf(...@@ -4168,12 +4168,12 @@ fn typeOf(
4168 return rvalue(gz, scope, rl, result, node);4168 return rvalue(gz, scope, rl, result, node);
4169 }4169 }
4170 const arena = gz.astgen.arena;4170 const arena = gz.astgen.arena;
4171 var items = try arena.alloc(zir.Inst.Ref, params.len);4171 var items = try arena.alloc(Zir.Inst.Ref, params.len);
4172 for (params) |param, param_i| {4172 for (params) |param, param_i| {
4173 items[param_i] = try expr(gz, scope, .none, param);4173 items[param_i] = try expr(gz, scope, .none, param);
4174 }4174 }
41754175
4176 const result = try gz.addPlNode(.typeof_peer, node, zir.Inst.MultiOp{4176 const result = try gz.addPlNode(.typeof_peer, node, Zir.Inst.MultiOp{
4177 .operands_len = @intCast(u32, params.len),4177 .operands_len = @intCast(u32, params.len),
4178 });4178 });
4179 try gz.astgen.appendRefs(items);4179 try gz.astgen.appendRefs(items);
...@@ -4187,7 +4187,7 @@ fn builtinCall(...@@ -4187,7 +4187,7 @@ fn builtinCall(
4187 rl: ResultLoc,4187 rl: ResultLoc,
4188 node: ast.Node.Index,4188 node: ast.Node.Index,
4189 params: []const ast.Node.Index,4189 params: []const ast.Node.Index,
4190) InnerError!zir.Inst.Ref {4190) InnerError!Zir.Inst.Ref {
4191 const mod = gz.astgen.mod;4191 const mod = gz.astgen.mod;
4192 const tree = gz.tree();4192 const tree = gz.tree();
4193 const main_tokens = tree.nodes.items(.main_token);4193 const main_tokens = tree.nodes.items(.main_token);
...@@ -4223,7 +4223,7 @@ fn builtinCall(...@@ -4223,7 +4223,7 @@ fn builtinCall(
4223 .float_cast => {4223 .float_cast => {
4224 const dest_type = try typeExpr(gz, scope, params[0]);4224 const dest_type = try typeExpr(gz, scope, params[0]);
4225 const rhs = try expr(gz, scope, .none, params[1]);4225 const rhs = try expr(gz, scope, .none, params[1]);
4226 const result = try gz.addPlNode(.floatcast, node, zir.Inst.Bin{4226 const result = try gz.addPlNode(.floatcast, node, Zir.Inst.Bin{
4227 .lhs = dest_type,4227 .lhs = dest_type,
4228 .rhs = rhs,4228 .rhs = rhs,
4229 });4229 });
...@@ -4232,7 +4232,7 @@ fn builtinCall(...@@ -4232,7 +4232,7 @@ fn builtinCall(
4232 .int_cast => {4232 .int_cast => {
4233 const dest_type = try typeExpr(gz, scope, params[0]);4233 const dest_type = try typeExpr(gz, scope, params[0]);
4234 const rhs = try expr(gz, scope, .none, params[1]);4234 const rhs = try expr(gz, scope, .none, params[1]);
4235 const result = try gz.addPlNode(.intcast, node, zir.Inst.Bin{4235 const result = try gz.addPlNode(.intcast, node, Zir.Inst.Bin{
4236 .lhs = dest_type,4236 .lhs = dest_type,
4237 .rhs = rhs,4237 .rhs = rhs,
4238 });4238 });
...@@ -4271,12 +4271,12 @@ fn builtinCall(...@@ -4271,12 +4271,12 @@ fn builtinCall(
4271 return rvalue(gz, scope, rl, result, node);4271 return rvalue(gz, scope, rl, result, node);
4272 },4272 },
4273 .compile_log => {4273 .compile_log => {
4274 const arg_refs = try mod.gpa.alloc(zir.Inst.Ref, params.len);4274 const arg_refs = try mod.gpa.alloc(Zir.Inst.Ref, params.len);
4275 defer mod.gpa.free(arg_refs);4275 defer mod.gpa.free(arg_refs);
42764276
4277 for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param);4277 for (params) |param, i| arg_refs[i] = try expr(gz, scope, .none, param);
42784278
4279 const result = try gz.addPlNode(.compile_log, node, zir.Inst.MultiOp{4279 const result = try gz.addPlNode(.compile_log, node, Zir.Inst.MultiOp{
4280 .operands_len = @intCast(u32, params.len),4280 .operands_len = @intCast(u32, params.len),
4281 });4281 });
4282 try gz.astgen.appendRefs(arg_refs);4282 try gz.astgen.appendRefs(arg_refs);
...@@ -4285,12 +4285,12 @@ fn builtinCall(...@@ -4285,12 +4285,12 @@ fn builtinCall(
4285 .field => {4285 .field => {
4286 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);4286 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
4287 if (rl == .ref) {4287 if (rl == .ref) {
4288 return try gz.addPlNode(.field_ptr_named, node, zir.Inst.FieldNamed{4288 return try gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
4289 .lhs = try expr(gz, scope, .ref, params[0]),4289 .lhs = try expr(gz, scope, .ref, params[0]),
4290 .field_name = field_name,4290 .field_name = field_name,
4291 });4291 });
4292 }4292 }
4293 const result = try gz.addPlNode(.field_val_named, node, zir.Inst.FieldNamed{4293 const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{
4294 .lhs = try expr(gz, scope, .none, params[0]),4294 .lhs = try expr(gz, scope, .none, params[0]),
4295 .field_name = field_name,4295 .field_name = field_name,
4296 });4296 });
...@@ -4301,7 +4301,7 @@ fn builtinCall(...@@ -4301,7 +4301,7 @@ fn builtinCall(
4301 .TypeOf => return typeOf(gz, scope, rl, node, params),4301 .TypeOf => return typeOf(gz, scope, rl, node, params),
43024302
4303 .int_to_enum => {4303 .int_to_enum => {
4304 const result = try gz.addPlNode(.int_to_enum, node, zir.Inst.Bin{4304 const result = try gz.addPlNode(.int_to_enum, node, Zir.Inst.Bin{
4305 .lhs = try typeExpr(gz, scope, params[0]),4305 .lhs = try typeExpr(gz, scope, params[0]),
4306 .rhs = try expr(gz, scope, .none, params[1]),4306 .rhs = try expr(gz, scope, .none, params[1]),
4307 });4307 });
...@@ -4321,7 +4321,7 @@ fn builtinCall(...@@ -4321,7 +4321,7 @@ fn builtinCall(
4321 // TODO: the second parameter here is supposed to be4321 // TODO: the second parameter here is supposed to be
4322 // `std.builtin.ExportOptions`, not a string.4322 // `std.builtin.ExportOptions`, not a string.
4323 const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);4323 const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
4324 _ = try gz.addPlNode(.@"export", node, zir.Inst.Bin{4324 _ = try gz.addPlNode(.@"export", node, Zir.Inst.Bin{
4325 .lhs = fn_to_export,4325 .lhs = fn_to_export,
4326 .rhs = export_name,4326 .rhs = export_name,
4327 });4327 });
...@@ -4331,7 +4331,7 @@ fn builtinCall(...@@ -4331,7 +4331,7 @@ fn builtinCall(
4331 .has_decl => {4331 .has_decl => {
4332 const container_type = try typeExpr(gz, scope, params[0]);4332 const container_type = try typeExpr(gz, scope, params[0]);
4333 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);4333 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
4334 const result = try gz.addPlNode(.has_decl, node, zir.Inst.Bin{4334 const result = try gz.addPlNode(.has_decl, node, Zir.Inst.Bin{
4335 .lhs = container_type,4335 .lhs = container_type,
4336 .rhs = name,4336 .rhs = name,
4337 });4337 });
...@@ -4451,14 +4451,14 @@ fn callExpr(...@@ -4451,14 +4451,14 @@ fn callExpr(
4451 rl: ResultLoc,4451 rl: ResultLoc,
4452 node: ast.Node.Index,4452 node: ast.Node.Index,
4453 call: ast.full.Call,4453 call: ast.full.Call,
4454) InnerError!zir.Inst.Ref {4454) InnerError!Zir.Inst.Ref {
4455 const mod = gz.astgen.mod;4455 const mod = gz.astgen.mod;
4456 if (call.async_token) |async_token| {4456 if (call.async_token) |async_token| {
4457 return mod.failTok(scope, async_token, "async and related features are not yet supported", .{});4457 return mod.failTok(scope, async_token, "async and related features are not yet supported", .{});
4458 }4458 }
4459 const lhs = try expr(gz, scope, .none, call.ast.fn_expr);4459 const lhs = try expr(gz, scope, .none, call.ast.fn_expr);
44604460
4461 const args = try mod.gpa.alloc(zir.Inst.Ref, call.ast.params.len);4461 const args = try mod.gpa.alloc(Zir.Inst.Ref, call.ast.params.len);
4462 defer mod.gpa.free(args);4462 defer mod.gpa.free(args);
44634463
4464 for (call.ast.params) |param_node, i| {4464 for (call.ast.params) |param_node, i| {
...@@ -4476,8 +4476,8 @@ fn callExpr(...@@ -4476,8 +4476,8 @@ fn callExpr(
4476 true => .async_kw,4476 true => .async_kw,
4477 false => .auto,4477 false => .auto,
4478 };4478 };
4479 const result: zir.Inst.Ref = res: {4479 const result: Zir.Inst.Ref = res: {
4480 const tag: zir.Inst.Tag = switch (modifier) {4480 const tag: Zir.Inst.Tag = switch (modifier) {
4481 .auto => switch (args.len == 0) {4481 .auto => switch (args.len == 0) {
4482 true => break :res try gz.addUnNode(.call_none, lhs, node),4482 true => break :res try gz.addUnNode(.call_none, lhs, node),
4483 false => .call,4483 false => .call,
...@@ -4495,7 +4495,7 @@ fn callExpr(...@@ -4495,7 +4495,7 @@ fn callExpr(
4495 return rvalue(gz, scope, rl, result, node); // TODO function call with result location4495 return rvalue(gz, scope, rl, result, node); // TODO function call with result location
4496}4496}
44974497
4498pub const simple_types = std.ComptimeStringMap(zir.Inst.Ref, .{4498pub const simple_types = std.ComptimeStringMap(Zir.Inst.Ref, .{
4499 .{ "u8", .u8_type },4499 .{ "u8", .u8_type },
4500 .{ "i8", .i8_type },4500 .{ "i8", .i8_type },
4501 .{ "u16", .u16_type },4501 .{ "u16", .u16_type },
...@@ -4756,9 +4756,9 @@ fn rvalue(...@@ -4756,9 +4756,9 @@ fn rvalue(
4756 gz: *GenZir,4756 gz: *GenZir,
4757 scope: *Scope,4757 scope: *Scope,
4758 rl: ResultLoc,4758 rl: ResultLoc,
4759 result: zir.Inst.Ref,4759 result: Zir.Inst.Ref,
4760 src_node: ast.Node.Index,4760 src_node: ast.Node.Index,
4761) InnerError!zir.Inst.Ref {4761) InnerError!Zir.Inst.Ref {
4762 switch (rl) {4762 switch (rl) {
4763 .none, .none_or_ref => return result,4763 .none, .none_or_ref => return result,
4764 .discard => {4764 .discard => {
...@@ -4774,70 +4774,70 @@ fn rvalue(...@@ -4774,70 +4774,70 @@ fn rvalue(
4774 },4774 },
4775 .ty => |ty_inst| {4775 .ty => |ty_inst| {
4776 // Quickly eliminate some common, unnecessary type coercion.4776 // Quickly eliminate some common, unnecessary type coercion.
4777 const as_ty = @as(u64, @enumToInt(zir.Inst.Ref.type_type)) << 32;4777 const as_ty = @as(u64, @enumToInt(Zir.Inst.Ref.type_type)) << 32;
4778 const as_comptime_int = @as(u64, @enumToInt(zir.Inst.Ref.comptime_int_type)) << 32;4778 const as_comptime_int = @as(u64, @enumToInt(Zir.Inst.Ref.comptime_int_type)) << 32;
4779 const as_bool = @as(u64, @enumToInt(zir.Inst.Ref.bool_type)) << 32;4779 const as_bool = @as(u64, @enumToInt(Zir.Inst.Ref.bool_type)) << 32;
4780 const as_usize = @as(u64, @enumToInt(zir.Inst.Ref.usize_type)) << 32;4780 const as_usize = @as(u64, @enumToInt(Zir.Inst.Ref.usize_type)) << 32;
4781 const as_void = @as(u64, @enumToInt(zir.Inst.Ref.void_type)) << 32;4781 const as_void = @as(u64, @enumToInt(Zir.Inst.Ref.void_type)) << 32;
4782 switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) {4782 switch ((@as(u64, @enumToInt(ty_inst)) << 32) | @as(u64, @enumToInt(result))) {
4783 as_ty | @enumToInt(zir.Inst.Ref.u8_type),4783 as_ty | @enumToInt(Zir.Inst.Ref.u8_type),
4784 as_ty | @enumToInt(zir.Inst.Ref.i8_type),4784 as_ty | @enumToInt(Zir.Inst.Ref.i8_type),
4785 as_ty | @enumToInt(zir.Inst.Ref.u16_type),4785 as_ty | @enumToInt(Zir.Inst.Ref.u16_type),
4786 as_ty | @enumToInt(zir.Inst.Ref.i16_type),4786 as_ty | @enumToInt(Zir.Inst.Ref.i16_type),
4787 as_ty | @enumToInt(zir.Inst.Ref.u32_type),4787 as_ty | @enumToInt(Zir.Inst.Ref.u32_type),
4788 as_ty | @enumToInt(zir.Inst.Ref.i32_type),4788 as_ty | @enumToInt(Zir.Inst.Ref.i32_type),
4789 as_ty | @enumToInt(zir.Inst.Ref.u64_type),4789 as_ty | @enumToInt(Zir.Inst.Ref.u64_type),
4790 as_ty | @enumToInt(zir.Inst.Ref.i64_type),4790 as_ty | @enumToInt(Zir.Inst.Ref.i64_type),
4791 as_ty | @enumToInt(zir.Inst.Ref.usize_type),4791 as_ty | @enumToInt(Zir.Inst.Ref.usize_type),
4792 as_ty | @enumToInt(zir.Inst.Ref.isize_type),4792 as_ty | @enumToInt(Zir.Inst.Ref.isize_type),
4793 as_ty | @enumToInt(zir.Inst.Ref.c_short_type),4793 as_ty | @enumToInt(Zir.Inst.Ref.c_short_type),
4794 as_ty | @enumToInt(zir.Inst.Ref.c_ushort_type),4794 as_ty | @enumToInt(Zir.Inst.Ref.c_ushort_type),
4795 as_ty | @enumToInt(zir.Inst.Ref.c_int_type),4795 as_ty | @enumToInt(Zir.Inst.Ref.c_int_type),
4796 as_ty | @enumToInt(zir.Inst.Ref.c_uint_type),4796 as_ty | @enumToInt(Zir.Inst.Ref.c_uint_type),
4797 as_ty | @enumToInt(zir.Inst.Ref.c_long_type),4797 as_ty | @enumToInt(Zir.Inst.Ref.c_long_type),
4798 as_ty | @enumToInt(zir.Inst.Ref.c_ulong_type),4798 as_ty | @enumToInt(Zir.Inst.Ref.c_ulong_type),
4799 as_ty | @enumToInt(zir.Inst.Ref.c_longlong_type),4799 as_ty | @enumToInt(Zir.Inst.Ref.c_longlong_type),
4800 as_ty | @enumToInt(zir.Inst.Ref.c_ulonglong_type),4800 as_ty | @enumToInt(Zir.Inst.Ref.c_ulonglong_type),
4801 as_ty | @enumToInt(zir.Inst.Ref.c_longdouble_type),4801 as_ty | @enumToInt(Zir.Inst.Ref.c_longdouble_type),
4802 as_ty | @enumToInt(zir.Inst.Ref.f16_type),4802 as_ty | @enumToInt(Zir.Inst.Ref.f16_type),
4803 as_ty | @enumToInt(zir.Inst.Ref.f32_type),4803 as_ty | @enumToInt(Zir.Inst.Ref.f32_type),
4804 as_ty | @enumToInt(zir.Inst.Ref.f64_type),4804 as_ty | @enumToInt(Zir.Inst.Ref.f64_type),
4805 as_ty | @enumToInt(zir.Inst.Ref.f128_type),4805 as_ty | @enumToInt(Zir.Inst.Ref.f128_type),
4806 as_ty | @enumToInt(zir.Inst.Ref.c_void_type),4806 as_ty | @enumToInt(Zir.Inst.Ref.c_void_type),
4807 as_ty | @enumToInt(zir.Inst.Ref.bool_type),4807 as_ty | @enumToInt(Zir.Inst.Ref.bool_type),
4808 as_ty | @enumToInt(zir.Inst.Ref.void_type),4808 as_ty | @enumToInt(Zir.Inst.Ref.void_type),
4809 as_ty | @enumToInt(zir.Inst.Ref.type_type),4809 as_ty | @enumToInt(Zir.Inst.Ref.type_type),
4810 as_ty | @enumToInt(zir.Inst.Ref.anyerror_type),4810 as_ty | @enumToInt(Zir.Inst.Ref.anyerror_type),
4811 as_ty | @enumToInt(zir.Inst.Ref.comptime_int_type),4811 as_ty | @enumToInt(Zir.Inst.Ref.comptime_int_type),
4812 as_ty | @enumToInt(zir.Inst.Ref.comptime_float_type),4812 as_ty | @enumToInt(Zir.Inst.Ref.comptime_float_type),
4813 as_ty | @enumToInt(zir.Inst.Ref.noreturn_type),4813 as_ty | @enumToInt(Zir.Inst.Ref.noreturn_type),
4814 as_ty | @enumToInt(zir.Inst.Ref.null_type),4814 as_ty | @enumToInt(Zir.Inst.Ref.null_type),
4815 as_ty | @enumToInt(zir.Inst.Ref.undefined_type),4815 as_ty | @enumToInt(Zir.Inst.Ref.undefined_type),
4816 as_ty | @enumToInt(zir.Inst.Ref.fn_noreturn_no_args_type),4816 as_ty | @enumToInt(Zir.Inst.Ref.fn_noreturn_no_args_type),
4817 as_ty | @enumToInt(zir.Inst.Ref.fn_void_no_args_type),4817 as_ty | @enumToInt(Zir.Inst.Ref.fn_void_no_args_type),
4818 as_ty | @enumToInt(zir.Inst.Ref.fn_naked_noreturn_no_args_type),4818 as_ty | @enumToInt(Zir.Inst.Ref.fn_naked_noreturn_no_args_type),
4819 as_ty | @enumToInt(zir.Inst.Ref.fn_ccc_void_no_args_type),4819 as_ty | @enumToInt(Zir.Inst.Ref.fn_ccc_void_no_args_type),
4820 as_ty | @enumToInt(zir.Inst.Ref.single_const_pointer_to_comptime_int_type),4820 as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type),
4821 as_ty | @enumToInt(zir.Inst.Ref.const_slice_u8_type),4821 as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type),
4822 as_ty | @enumToInt(zir.Inst.Ref.enum_literal_type),4822 as_ty | @enumToInt(Zir.Inst.Ref.enum_literal_type),
4823 as_comptime_int | @enumToInt(zir.Inst.Ref.zero),4823 as_comptime_int | @enumToInt(Zir.Inst.Ref.zero),
4824 as_comptime_int | @enumToInt(zir.Inst.Ref.one),4824 as_comptime_int | @enumToInt(Zir.Inst.Ref.one),
4825 as_bool | @enumToInt(zir.Inst.Ref.bool_true),4825 as_bool | @enumToInt(Zir.Inst.Ref.bool_true),
4826 as_bool | @enumToInt(zir.Inst.Ref.bool_false),4826 as_bool | @enumToInt(Zir.Inst.Ref.bool_false),
4827 as_usize | @enumToInt(zir.Inst.Ref.zero_usize),4827 as_usize | @enumToInt(Zir.Inst.Ref.zero_usize),
4828 as_usize | @enumToInt(zir.Inst.Ref.one_usize),4828 as_usize | @enumToInt(Zir.Inst.Ref.one_usize),
4829 as_void | @enumToInt(zir.Inst.Ref.void_value),4829 as_void | @enumToInt(Zir.Inst.Ref.void_value),
4830 => return result, // type of result is already correct4830 => return result, // type of result is already correct
48314831
4832 // Need an explicit type coercion instruction.4832 // Need an explicit type coercion instruction.
4833 else => return gz.addPlNode(.as_node, src_node, zir.Inst.As{4833 else => return gz.addPlNode(.as_node, src_node, Zir.Inst.As{
4834 .dest_type = ty_inst,4834 .dest_type = ty_inst,
4835 .operand = result,4835 .operand = result,
4836 }),4836 }),
4837 }4837 }
4838 },4838 },
4839 .ptr => |ptr_inst| {4839 .ptr => |ptr_inst| {
4840 _ = try gz.addPlNode(.store_node, src_node, zir.Inst.Bin{4840 _ = try gz.addPlNode(.store_node, src_node, Zir.Inst.Bin{
4841 .lhs = ptr_inst,4841 .lhs = ptr_inst,
4842 .rhs = result,4842 .rhs = result,
4843 });4843 });
src/Module.zig+1-1
...@@ -21,7 +21,7 @@ const TypedValue = @import("TypedValue.zig");...@@ -21,7 +21,7 @@ const TypedValue = @import("TypedValue.zig");
21const Package = @import("Package.zig");21const Package = @import("Package.zig");
22const link = @import("link.zig");22const link = @import("link.zig");
23const ir = @import("ir.zig");23const ir = @import("ir.zig");
24const Zir = @import("zir.zig"); // TODO rename this to Zir24const Zir = @import("Zir.zig");
25const trace = @import("tracy.zig").trace;25const trace = @import("tracy.zig").trace;
26const AstGen = @import("AstGen.zig");26const AstGen = @import("AstGen.zig");
27const Sema = @import("Sema.zig");27const Sema = @import("Sema.zig");
src/Sema.zig+1-1
...@@ -52,7 +52,7 @@ const Value = @import("value.zig").Value;...@@ -52,7 +52,7 @@ const Value = @import("value.zig").Value;
52const Type = @import("type.zig").Type;52const Type = @import("type.zig").Type;
53const TypedValue = @import("TypedValue.zig");53const TypedValue = @import("TypedValue.zig");
54const ir = @import("ir.zig");54const ir = @import("ir.zig");
55const Zir = @import("zir.zig"); // TODO rename to Zir.zig55const Zir = @import("Zir.zig");
56const Module = @import("Module.zig");56const Module = @import("Module.zig");
57const Inst = ir.Inst;57const Inst = ir.Inst;
58const Body = ir.Body;58const Body = ir.Body;
src/Zir.zig created+2548
...@@ -0,0 +1,2548 @@
1//! Zig Intermediate Representation. Astgen.zig converts AST nodes to these
2//! untyped IR instructions. Next, Sema.zig processes these into TZIR.
3//! The minimum amount of information needed to represent a list of ZIR instructions.
4//! Once this structure is completed, it can be used to generate TZIR, followed by
5//! machine code, without any memory access into the AST tree token list, node list,
6//! or source bytes. Exceptions include:
7//! * Compile errors, which may need to reach into these data structures to
8//! create a useful report.
9//! * In the future, possibly inline assembly, which needs to get parsed and
10//! handled by the codegen backend, and errors reported there. However for now,
11//! inline assembly is not an exception.
12
13const std = @import("std");
14const mem = std.mem;
15const Allocator = std.mem.Allocator;
16const assert = std.debug.assert;
17const BigIntConst = std.math.big.int.Const;
18const BigIntMutable = std.math.big.int.Mutable;
19const ast = std.zig.ast;
20
21const Zir = @This();
22const Type = @import("type.zig").Type;
23const Value = @import("value.zig").Value;
24const TypedValue = @import("TypedValue.zig");
25const ir = @import("ir.zig");
26const Module = @import("Module.zig");
27const LazySrcLoc = Module.LazySrcLoc;
28
29/// There is always implicitly a `block` instruction at index 0.
30/// This is so that `break_inline` can break from the root block.
31instructions: std.MultiArrayList(Inst).Slice,
32/// In order to store references to strings in fewer bytes, we copy all
33/// string bytes into here. String bytes can be null. It is up to whomever
34/// is referencing the data here whether they want to store both index and length,
35/// thus allowing null bytes, or store only index, and use null-termination. The
36/// `string_bytes` array is agnostic to either usage.
37string_bytes: []u8,
38/// The meaning of this data is determined by `Inst.Tag` value.
39extra: []u32,
40
41/// Returns the requested data, as well as the new index which is at the start of the
42/// trailers for the object.
43pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } {
44 const fields = std.meta.fields(T);
45 var i: usize = index;
46 var result: T = undefined;
47 inline for (fields) |field| {
48 @field(result, field.name) = switch (field.field_type) {
49 u32 => code.extra[i],
50 Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]),
51 else => unreachable,
52 };
53 i += 1;
54 }
55 return .{
56 .data = result,
57 .end = i,
58 };
59}
60
61/// Given an index into `string_bytes` returns the null-terminated string found there.
62pub fn nullTerminatedString(code: Zir, index: usize) [:0]const u8 {
63 var end: usize = index;
64 while (code.string_bytes[end] != 0) {
65 end += 1;
66 }
67 return code.string_bytes[index..end :0];
68}
69
70pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref {
71 const raw_slice = code.extra[start..][0..len];
72 return @bitCast([]Inst.Ref, raw_slice);
73}
74
75pub fn deinit(code: *Zir, gpa: *Allocator) void {
76 code.instructions.deinit(gpa);
77 gpa.free(code.string_bytes);
78 gpa.free(code.extra);
79 code.* = undefined;
80}
81
82/// For debugging purposes, like dumpFn but for unanalyzed zir blocks
83pub fn dump(
84 code: Zir,
85 gpa: *Allocator,
86 kind: []const u8,
87 scope: *Module.Scope,
88 param_count: usize,
89) !void {
90 var arena = std.heap.ArenaAllocator.init(gpa);
91 defer arena.deinit();
92
93 var writer: Writer = .{
94 .gpa = gpa,
95 .arena = &arena.allocator,
96 .scope = scope,
97 .code = code,
98 .indent = 0,
99 .param_count = param_count,
100 };
101
102 const decl_name = scope.srcDecl().?.name;
103 const stderr = std.io.getStdErr().writer();
104 try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name });
105 try writer.writeInstToStream(stderr, 0);
106 try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name });
107}
108
109/// These are untyped instructions generated from an Abstract Syntax Tree.
110/// The data here is immutable because it is possible to have multiple
111/// analyses on the same ZIR happening at the same time.
112pub const Inst = struct {
113 tag: Tag,
114 data: Data,
115
116 /// These names are used directly as the instruction names in the text format.
117 pub const Tag = enum(u8) {
118 /// Arithmetic addition, asserts no integer overflow.
119 /// Uses the `pl_node` union field. Payload is `Bin`.
120 add,
121 /// Twos complement wrapping integer addition.
122 /// Uses the `pl_node` union field. Payload is `Bin`.
123 addwrap,
124 /// Allocates stack local memory.
125 /// Uses the `un_node` union field. The operand is the type of the allocated object.
126 /// The node source location points to a var decl node.
127 /// Indicates the beginning of a new statement in debug info.
128 alloc,
129 /// Same as `alloc` except mutable.
130 alloc_mut,
131 /// Same as `alloc` except the type is inferred.
132 /// Uses the `node` union field.
133 alloc_inferred,
134 /// Same as `alloc_inferred` except mutable.
135 alloc_inferred_mut,
136 /// Array concatenation. `a ++ b`
137 /// Uses the `pl_node` union field. Payload is `Bin`.
138 array_cat,
139 /// Array multiplication `a ** b`
140 /// Uses the `pl_node` union field. Payload is `Bin`.
141 array_mul,
142 /// `[N]T` syntax. No source location provided.
143 /// Uses the `bin` union field. lhs is length, rhs is element type.
144 array_type,
145 /// `[N:S]T` syntax. No source location provided.
146 /// Uses the `array_type_sentinel` field.
147 array_type_sentinel,
148 /// Given a pointer to an indexable object, returns the len property. This is
149 /// used by for loops. This instruction also emits a for-loop specific compile
150 /// error if the indexable object is not indexable.
151 /// Uses the `un_node` field. The AST node is the for loop node.
152 indexable_ptr_len,
153 /// Type coercion. No source location attached.
154 /// Uses the `bin` field.
155 as,
156 /// Type coercion to the function's return type.
157 /// Uses the `pl_node` field. Payload is `As`. AST node could be many things.
158 as_node,
159 /// Inline assembly. Non-volatile.
160 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
161 @"asm",
162 /// Inline assembly with the volatile attribute.
163 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
164 asm_volatile,
165 /// Bitwise AND. `&`
166 bit_and,
167 /// Bitcast a value to a different type.
168 /// Uses the pl_node field with payload `Bin`.
169 bitcast,
170 /// A typed result location pointer is bitcasted to a new result location pointer.
171 /// The new result location pointer has an inferred type.
172 /// Uses the un_node field.
173 bitcast_result_ptr,
174 /// Bitwise NOT. `~`
175 /// Uses `un_node`.
176 bit_not,
177 /// Bitwise OR. `|`
178 bit_or,
179 /// A labeled block of code, which can return a value.
180 /// Uses the `pl_node` union field. Payload is `Block`.
181 block,
182 /// A list of instructions which are analyzed in the parent context, without
183 /// generating a runtime block. Must terminate with an "inline" variant of
184 /// a noreturn instruction.
185 /// Uses the `pl_node` union field. Payload is `Block`.
186 block_inline,
187 /// Boolean AND. See also `bit_and`.
188 /// Uses the `pl_node` union field. Payload is `Bin`.
189 bool_and,
190 /// Boolean NOT. See also `bit_not`.
191 /// Uses the `un_node` field.
192 bool_not,
193 /// Boolean OR. See also `bit_or`.
194 /// Uses the `pl_node` union field. Payload is `Bin`.
195 bool_or,
196 /// Short-circuiting boolean `and`. `lhs` is a boolean `Ref` and the other operand
197 /// is a block, which is evaluated if `lhs` is `true`.
198 /// Uses the `bool_br` union field.
199 bool_br_and,
200 /// Short-circuiting boolean `or`. `lhs` is a boolean `Ref` and the other operand
201 /// is a block, which is evaluated if `lhs` is `false`.
202 /// Uses the `bool_br` union field.
203 bool_br_or,
204 /// Return a value from a block.
205 /// Uses the `break` union field.
206 /// Uses the source information from previous instruction.
207 @"break",
208 /// Return a value from a block. This instruction is used as the terminator
209 /// of a `block_inline`. It allows using the return value from `Sema.analyzeBody`.
210 /// This instruction may also be used when it is known that there is only one
211 /// break instruction in a block, and the target block is the parent.
212 /// Uses the `break` union field.
213 break_inline,
214 /// Uses the `node` union field.
215 breakpoint,
216 /// Function call with modifier `.auto`.
217 /// Uses `pl_node`. AST node is the function call. Payload is `Call`.
218 call,
219 /// Same as `call` but it also does `ensure_result_used` on the return value.
220 call_chkused,
221 /// Same as `call` but with modifier `.compile_time`.
222 call_compile_time,
223 /// Function call with modifier `.auto`, empty parameter list.
224 /// Uses the `un_node` field. Operand is callee. AST node is the function call.
225 call_none,
226 /// Same as `call_none` but it also does `ensure_result_used` on the return value.
227 call_none_chkused,
228 /// `<`
229 /// Uses the `pl_node` union field. Payload is `Bin`.
230 cmp_lt,
231 /// `<=`
232 /// Uses the `pl_node` union field. Payload is `Bin`.
233 cmp_lte,
234 /// `==`
235 /// Uses the `pl_node` union field. Payload is `Bin`.
236 cmp_eq,
237 /// `>=`
238 /// Uses the `pl_node` union field. Payload is `Bin`.
239 cmp_gte,
240 /// `>`
241 /// Uses the `pl_node` union field. Payload is `Bin`.
242 cmp_gt,
243 /// `!=`
244 /// Uses the `pl_node` union field. Payload is `Bin`.
245 cmp_neq,
246 /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
247 /// as type coercion from the new element type to the old element type.
248 /// Uses the `bin` union field.
249 /// LHS is destination element type, RHS is result pointer.
250 coerce_result_ptr,
251 /// Emit an error message and fail compilation.
252 /// Uses the `un_node` field.
253 compile_error,
254 /// Log compile time variables and emit an error message.
255 /// Uses the `pl_node` union field. The AST node is the compile log builtin call.
256 /// The payload is `MultiOp`.
257 compile_log,
258 /// Conditional branch. Splits control flow based on a boolean condition value.
259 /// Uses the `pl_node` union field. AST node is an if, while, for, etc.
260 /// Payload is `CondBr`.
261 condbr,
262 /// Same as `condbr`, except the condition is coerced to a comptime value, and
263 /// only the taken branch is analyzed. The then block and else block must
264 /// terminate with an "inline" variant of a noreturn instruction.
265 condbr_inline,
266 /// A struct type definition. Contains references to ZIR instructions for
267 /// the field types, defaults, and alignments.
268 /// Uses the `pl_node` union field. Payload is `StructDecl`.
269 struct_decl,
270 /// Same as `struct_decl`, except has the `packed` layout.
271 struct_decl_packed,
272 /// Same as `struct_decl`, except has the `extern` layout.
273 struct_decl_extern,
274 /// A union type definition. Contains references to ZIR instructions for
275 /// the field types and optional type tag expression.
276 /// Uses the `pl_node` union field. Payload is `UnionDecl`.
277 union_decl,
278 /// An enum type definition. Contains references to ZIR instructions for
279 /// the field value expressions and optional type tag expression.
280 /// Uses the `pl_node` union field. Payload is `EnumDecl`.
281 enum_decl,
282 /// Same as `enum_decl`, except the enum is non-exhaustive.
283 enum_decl_nonexhaustive,
284 /// An opaque type definition. Provides an AST node only.
285 /// Uses the `node` union field.
286 opaque_decl,
287 /// Declares the beginning of a statement. Used for debug info.
288 /// Uses the `node` union field.
289 dbg_stmt_node,
290 /// Represents a pointer to a global decl.
291 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
292 decl_ref,
293 /// Equivalent to a decl_ref followed by load.
294 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
295 decl_val,
296 /// Same as `decl_ref` except instead of indexing into decls, uses
297 /// a name to identify the Decl. Uses the `str_tok` union field.
298 decl_ref_named,
299 /// Same as `decl_val` except instead of indexing into decls, uses
300 /// a name to identify the Decl. Uses the `str_tok` union field.
301 decl_val_named,
302 /// Load the value from a pointer. Assumes `x.*` syntax.
303 /// Uses `un_node` field. AST node is the `x.*` syntax.
304 load,
305 /// Arithmetic division. Asserts no integer overflow.
306 /// Uses the `pl_node` union field. Payload is `Bin`.
307 div,
308 /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at
309 /// the provided index. Uses the `bin` union field. Source location is implied
310 /// to be the same as the previous instruction.
311 elem_ptr,
312 /// Same as `elem_ptr` except also stores a source location node.
313 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
314 elem_ptr_node,
315 /// Given an array, slice, or pointer, returns the element at the provided index.
316 /// Uses the `bin` union field. Source location is implied to be the same
317 /// as the previous instruction.
318 elem_val,
319 /// Same as `elem_val` except also stores a source location node.
320 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
321 elem_val_node,
322 /// This instruction has been deleted late in the astgen phase. It must
323 /// be ignored, and the corresponding `Data` is undefined.
324 elided,
325 /// Emits a compile error if the operand is not `void`.
326 /// Uses the `un_node` field.
327 ensure_result_used,
328 /// Emits a compile error if an error is ignored.
329 /// Uses the `un_node` field.
330 ensure_result_non_error,
331 /// Create a `E!T` type.
332 /// Uses the `pl_node` field with `Bin` payload.
333 error_union_type,
334 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
335 error_value,
336 /// Implements the `@export` builtin function.
337 /// Uses the `pl_node` union field. Payload is `Bin`.
338 @"export",
339 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
340 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
341 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
342 field_ptr,
343 /// Given a struct or object that contains virtual fields, returns the named field.
344 /// The field name is stored in string_bytes. Used by a.b syntax.
345 /// This instruction also accepts a pointer.
346 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
347 field_val,
348 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
349 /// to the named field. The field name is a comptime instruction. Used by @field.
350 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
351 field_ptr_named,
352 /// Given a struct or object that contains virtual fields, returns the named field.
353 /// The field name is a comptime instruction. Used by @field.
354 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
355 field_val_named,
356 /// Convert a larger float type to any other float type, possibly causing
357 /// a loss of precision.
358 /// Uses the `pl_node` field. AST is the `@floatCast` syntax.
359 /// Payload is `Bin` with lhs as the dest type, rhs the operand.
360 floatcast,
361 /// Returns a function type, assuming unspecified calling convention.
362 /// Uses the `pl_node` union field. `payload_index` points to a `FnType`.
363 fn_type,
364 /// Same as `fn_type` but the function is variadic.
365 fn_type_var_args,
366 /// Returns a function type, with a calling convention instruction operand.
367 /// Uses the `pl_node` union field. `payload_index` points to a `FnTypeCc`.
368 fn_type_cc,
369 /// Same as `fn_type_cc` but the function is variadic.
370 fn_type_cc_var_args,
371 /// Implements the `@hasDecl` builtin.
372 /// Uses the `pl_node` union field. Payload is `Bin`.
373 has_decl,
374 /// `@import(operand)`.
375 /// Uses the `un_node` field.
376 import,
377 /// Integer literal that fits in a u64. Uses the int union value.
378 int,
379 /// A float literal that fits in a f32. Uses the float union value.
380 float,
381 /// A float literal that fits in a f128. Uses the `pl_node` union value.
382 /// Payload is `Float128`.
383 float128,
384 /// Convert an integer value to another integer type, asserting that the destination type
385 /// can hold the same mathematical value.
386 /// Uses the `pl_node` field. AST is the `@intCast` syntax.
387 /// Payload is `Bin` with lhs as the dest type, rhs the operand.
388 intcast,
389 /// Make an integer type out of signedness and bit count.
390 /// Payload is `int_type`
391 int_type,
392 /// Convert an error type to `u16`
393 error_to_int,
394 /// Convert a `u16` to `anyerror`
395 int_to_error,
396 /// Return a boolean false if an optional is null. `x != null`
397 /// Uses the `un_node` field.
398 is_non_null,
399 /// Return a boolean true if an optional is null. `x == null`
400 /// Uses the `un_node` field.
401 is_null,
402 /// Return a boolean false if an optional is null. `x.* != null`
403 /// Uses the `un_node` field.
404 is_non_null_ptr,
405 /// Return a boolean true if an optional is null. `x.* == null`
406 /// Uses the `un_node` field.
407 is_null_ptr,
408 /// Return a boolean true if value is an error
409 /// Uses the `un_node` field.
410 is_err,
411 /// Return a boolean true if dereferenced pointer is an error
412 /// Uses the `un_node` field.
413 is_err_ptr,
414 /// A labeled block of code that loops forever. At the end of the body will have either
415 /// a `repeat` instruction or a `repeat_inline` instruction.
416 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.
417 /// This ZIR instruction is needed because TZIR does not (yet?) match ZIR, and Sema
418 /// needs to emit more than 1 TZIR block for this instruction.
419 /// The payload is `Block`.
420 loop,
421 /// Sends runtime control flow back to the beginning of the current block.
422 /// Uses the `node` field.
423 repeat,
424 /// Sends comptime control flow back to the beginning of the current block.
425 /// Uses the `node` field.
426 repeat_inline,
427 /// Merge two error sets into one, `E1 || E2`.
428 /// Uses the `pl_node` field with payload `Bin`.
429 merge_error_sets,
430 /// Ambiguously remainder division or modulus. If the computation would possibly have
431 /// a different value depending on whether the operation is remainder division or modulus,
432 /// a compile error is emitted. Otherwise the computation is performed.
433 /// Uses the `pl_node` union field. Payload is `Bin`.
434 mod_rem,
435 /// Arithmetic multiplication. Asserts no integer overflow.
436 /// Uses the `pl_node` union field. Payload is `Bin`.
437 mul,
438 /// Twos complement wrapping integer multiplication.
439 /// Uses the `pl_node` union field. Payload is `Bin`.
440 mulwrap,
441 /// Given a reference to a function and a parameter index, returns the
442 /// type of the parameter. The only usage of this instruction is for the
443 /// result location of parameters of function calls. In the case of a function's
444 /// parameter type being `anytype`, it is the type coercion's job to detect this
445 /// scenario and skip the coercion, so that semantic analysis of this instruction
446 /// is not in a position where it must create an invalid type.
447 /// Uses the `param_type` union field.
448 param_type,
449 /// Convert a pointer to a `usize` integer.
450 /// Uses the `un_node` field. The AST node is the builtin fn call node.
451 ptrtoint,
452 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
453 /// stores it in a memory location, and returns a const pointer to it. If the value
454 /// is `comptime`, the memory location is global static constant data. Otherwise,
455 /// the memory location is in the stack frame, local to the scope containing the
456 /// instruction.
457 /// Uses the `un_tok` union field.
458 ref,
459 /// Obtains a pointer to the return value.
460 /// Uses the `node` union field.
461 ret_ptr,
462 /// Obtains the return type of the in-scope function.
463 /// Uses the `node` union field.
464 ret_type,
465 /// Sends control flow back to the function's callee.
466 /// Includes an operand as the return value.
467 /// Includes an AST node source location.
468 /// Uses the `un_node` union field.
469 ret_node,
470 /// Sends control flow back to the function's callee.
471 /// Includes an operand as the return value.
472 /// Includes a token source location.
473 /// Uses the `un_tok` union field.
474 ret_tok,
475 /// Same as `ret_tok` except the operand needs to get coerced to the function's
476 /// return type.
477 ret_coerce,
478 /// Changes the maximum number of backwards branches that compile-time
479 /// code execution can use before giving up and making a compile error.
480 /// Uses the `un_node` union field.
481 set_eval_branch_quota,
482 /// Integer shift-left. Zeroes are shifted in from the right hand side.
483 /// Uses the `pl_node` union field. Payload is `Bin`.
484 shl,
485 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
486 /// Uses the `pl_node` union field. Payload is `Bin`.
487 shr,
488 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
489 /// Uses the `ptr_type_simple` union field.
490 ptr_type_simple,
491 /// Create a pointer type which can have a sentinel, alignment, and/or bit range.
492 /// Uses the `ptr_type` union field.
493 ptr_type,
494 /// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
495 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
496 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
497 /// is the allocation that needs to have its type inferred.
498 /// Uses the `un_node` field. The AST node is the var decl.
499 resolve_inferred_alloc,
500 /// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
501 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`.
502 slice_start,
503 /// Slice operation `array_ptr[start..end]`. No sentinel.
504 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceEnd`.
505 slice_end,
506 /// Slice operation `array_ptr[start..end:sentinel]`.
507 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`.
508 slice_sentinel,
509 /// Write a value to a pointer. For loading, see `load`.
510 /// Source location is assumed to be same as previous instruction.
511 /// Uses the `bin` union field.
512 store,
513 /// Same as `store` except provides a source location.
514 /// Uses the `pl_node` union field. Payload is `Bin`.
515 store_node,
516 /// Same as `store` but the type of the value being stored will be used to infer
517 /// the block type. The LHS is the pointer to store to.
518 /// Uses the `bin` union field.
519 store_to_block_ptr,
520 /// Same as `store` but the type of the value being stored will be used to infer
521 /// the pointer type.
522 /// Uses the `bin` union field - Astgen.zig depends on the ability to change
523 /// the tag of an instruction from `store_to_block_ptr` to `store_to_inferred_ptr`
524 /// without changing the data.
525 store_to_inferred_ptr,
526 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
527 /// Uses the `str` union field.
528 str,
529 /// Arithmetic subtraction. Asserts no integer overflow.
530 /// Uses the `pl_node` union field. Payload is `Bin`.
531 sub,
532 /// Twos complement wrapping integer subtraction.
533 /// Uses the `pl_node` union field. Payload is `Bin`.
534 subwrap,
535 /// Arithmetic negation. Asserts no integer overflow.
536 /// Same as sub with a lhs of 0, split into a separate instruction to save memory.
537 /// Uses `un_node`.
538 negate,
539 /// Twos complement wrapping integer negation.
540 /// Same as subwrap with a lhs of 0, split into a separate instruction to save memory.
541 /// Uses `un_node`.
542 negate_wrap,
543 /// Returns the type of a value.
544 /// Uses the `un_tok` field.
545 typeof,
546 /// Given a value which is a pointer, returns the element type.
547 /// Uses the `un_node` field.
548 typeof_elem,
549 /// The builtin `@TypeOf` which returns the type after Peer Type Resolution
550 /// of one or more params.
551 /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
552 typeof_peer,
553 /// Asserts control-flow will not reach this instruction (`unreachable`).
554 /// Uses the `unreachable` union field.
555 @"unreachable",
556 /// Bitwise XOR. `^`
557 /// Uses the `pl_node` union field. Payload is `Bin`.
558 xor,
559 /// Create an optional type '?T'
560 /// Uses the `un_node` field.
561 optional_type,
562 /// Create an optional type '?T'. The operand is a pointer value. The optional type will
563 /// be the type of the pointer element, wrapped in an optional.
564 /// Uses the `un_node` field.
565 optional_type_from_ptr_elem,
566 /// ?T => T with safety.
567 /// Given an optional value, returns the payload value, with a safety check that
568 /// the value is non-null. Used for `orelse`, `if` and `while`.
569 /// Uses the `un_node` field.
570 optional_payload_safe,
571 /// ?T => T without safety.
572 /// Given an optional value, returns the payload value. No safety checks.
573 /// Uses the `un_node` field.
574 optional_payload_unsafe,
575 /// *?T => *T with safety.
576 /// Given a pointer to an optional value, returns a pointer to the payload value,
577 /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`.
578 /// Uses the `un_node` field.
579 optional_payload_safe_ptr,
580 /// *?T => *T without safety.
581 /// Given a pointer to an optional value, returns a pointer to the payload value.
582 /// No safety checks.
583 /// Uses the `un_node` field.
584 optional_payload_unsafe_ptr,
585 /// E!T => T with safety.
586 /// Given an error union value, returns the payload value, with a safety check
587 /// that the value is not an error. Used for catch, if, and while.
588 /// Uses the `un_node` field.
589 err_union_payload_safe,
590 /// E!T => T without safety.
591 /// Given an error union value, returns the payload value. No safety checks.
592 /// Uses the `un_node` field.
593 err_union_payload_unsafe,
594 /// *E!T => *T with safety.
595 /// Given a pointer to an error union value, returns a pointer to the payload value,
596 /// with a safety check that the value is not an error. Used for catch, if, and while.
597 /// Uses the `un_node` field.
598 err_union_payload_safe_ptr,
599 /// *E!T => *T without safety.
600 /// Given a pointer to a error union value, returns a pointer to the payload value.
601 /// No safety checks.
602 /// Uses the `un_node` field.
603 err_union_payload_unsafe_ptr,
604 /// E!T => E without safety.
605 /// Given an error union value, returns the error code. No safety checks.
606 /// Uses the `un_node` field.
607 err_union_code,
608 /// *E!T => E without safety.
609 /// Given a pointer to an error union value, returns the error code. No safety checks.
610 /// Uses the `un_node` field.
611 err_union_code_ptr,
612 /// Takes a *E!T and raises a compiler error if T != void
613 /// Uses the `un_tok` field.
614 ensure_err_payload_void,
615 /// An enum literal. Uses the `str_tok` union field.
616 enum_literal,
617 /// An enum literal 8 or fewer bytes. No source location.
618 /// Uses the `small_str` field.
619 enum_literal_small,
620 /// A switch expression. Uses the `pl_node` union field.
621 /// AST node is the switch, payload is `SwitchBlock`.
622 /// All prongs of target handled.
623 switch_block,
624 /// Same as switch_block, except one or more prongs have multiple items.
625 switch_block_multi,
626 /// Same as switch_block, except has an else prong.
627 switch_block_else,
628 /// Same as switch_block_else, except one or more prongs have multiple items.
629 switch_block_else_multi,
630 /// Same as switch_block, except has an underscore prong.
631 switch_block_under,
632 /// Same as switch_block, except one or more prongs have multiple items.
633 switch_block_under_multi,
634 /// Same as `switch_block` but the target is a pointer to the value being switched on.
635 switch_block_ref,
636 /// Same as `switch_block_multi` but the target is a pointer to the value being switched on.
637 switch_block_ref_multi,
638 /// Same as `switch_block_else` but the target is a pointer to the value being switched on.
639 switch_block_ref_else,
640 /// Same as `switch_block_else_multi` but the target is a pointer to the
641 /// value being switched on.
642 switch_block_ref_else_multi,
643 /// Same as `switch_block_under` but the target is a pointer to the value
644 /// being switched on.
645 switch_block_ref_under,
646 /// Same as `switch_block_under_multi` but the target is a pointer to
647 /// the value being switched on.
648 switch_block_ref_under_multi,
649 /// Produces the capture value for a switch prong.
650 /// Uses the `switch_capture` field.
651 switch_capture,
652 /// Produces the capture value for a switch prong.
653 /// Result is a pointer to the value.
654 /// Uses the `switch_capture` field.
655 switch_capture_ref,
656 /// Produces the capture value for a switch prong.
657 /// The prong is one of the multi cases.
658 /// Uses the `switch_capture` field.
659 switch_capture_multi,
660 /// Produces the capture value for a switch prong.
661 /// The prong is one of the multi cases.
662 /// Result is a pointer to the value.
663 /// Uses the `switch_capture` field.
664 switch_capture_multi_ref,
665 /// Produces the capture value for the else/'_' switch prong.
666 /// Uses the `switch_capture` field.
667 switch_capture_else,
668 /// Produces the capture value for the else/'_' switch prong.
669 /// Result is a pointer to the value.
670 /// Uses the `switch_capture` field.
671 switch_capture_else_ref,
672 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
673 /// initialization expression, and emits compile errors for duplicate fields
674 /// as well as missing fields, if applicable.
675 /// This instruction asserts that there is at least one field_ptr instruction,
676 /// because it must use one of them to find out the struct type.
677 /// Uses the `pl_node` field. Payload is `Block`.
678 validate_struct_init_ptr,
679 /// A struct literal with a specified type, with no fields.
680 /// Uses the `un_node` field.
681 struct_init_empty,
682 /// Given a struct, union, enum, or opaque and a field name, returns the field type.
683 /// Uses the `pl_node` field. Payload is `FieldType`.
684 field_type,
685 /// Finalizes a typed struct initialization, performs validation, and returns the
686 /// struct value.
687 /// Uses the `pl_node` field. Payload is `StructInit`.
688 struct_init,
689 /// Converts an integer into an enum value.
690 /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
691 int_to_enum,
692 /// Converts an enum value into an integer. Resulting type will be the tag type
693 /// of the enum. Uses `un_node`.
694 enum_to_int,
695 /// Implements the `@typeInfo` builtin. Uses `un_node`.
696 type_info,
697 /// Implements the `@sizeOf` builtin. Uses `un_node`.
698 size_of,
699 /// Implements the `@bitSizeOf` builtin. Uses `un_node`.
700 bit_size_of,
701
702 /// Returns whether the instruction is one of the control flow "noreturn" types.
703 /// Function calls do not count.
704 pub fn isNoReturn(tag: Tag) bool {
705 return switch (tag) {
706 .add,
707 .addwrap,
708 .alloc,
709 .alloc_mut,
710 .alloc_inferred,
711 .alloc_inferred_mut,
712 .array_cat,
713 .array_mul,
714 .array_type,
715 .array_type_sentinel,
716 .indexable_ptr_len,
717 .as,
718 .as_node,
719 .@"asm",
720 .asm_volatile,
721 .bit_and,
722 .bitcast,
723 .bitcast_result_ptr,
724 .bit_or,
725 .block,
726 .block_inline,
727 .loop,
728 .bool_br_and,
729 .bool_br_or,
730 .bool_not,
731 .bool_and,
732 .bool_or,
733 .breakpoint,
734 .call,
735 .call_chkused,
736 .call_compile_time,
737 .call_none,
738 .call_none_chkused,
739 .cmp_lt,
740 .cmp_lte,
741 .cmp_eq,
742 .cmp_gte,
743 .cmp_gt,
744 .cmp_neq,
745 .coerce_result_ptr,
746 .struct_decl,
747 .struct_decl_packed,
748 .struct_decl_extern,
749 .union_decl,
750 .enum_decl,
751 .enum_decl_nonexhaustive,
752 .opaque_decl,
753 .dbg_stmt_node,
754 .decl_ref,
755 .decl_val,
756 .decl_ref_named,
757 .decl_val_named,
758 .load,
759 .div,
760 .elem_ptr,
761 .elem_val,
762 .elem_ptr_node,
763 .elem_val_node,
764 .ensure_result_used,
765 .ensure_result_non_error,
766 .@"export",
767 .floatcast,
768 .field_ptr,
769 .field_val,
770 .field_ptr_named,
771 .field_val_named,
772 .fn_type,
773 .fn_type_var_args,
774 .fn_type_cc,
775 .fn_type_cc_var_args,
776 .has_decl,
777 .int,
778 .float,
779 .float128,
780 .intcast,
781 .int_type,
782 .is_non_null,
783 .is_null,
784 .is_non_null_ptr,
785 .is_null_ptr,
786 .is_err,
787 .is_err_ptr,
788 .mod_rem,
789 .mul,
790 .mulwrap,
791 .param_type,
792 .ptrtoint,
793 .ref,
794 .ret_ptr,
795 .ret_type,
796 .shl,
797 .shr,
798 .store,
799 .store_node,
800 .store_to_block_ptr,
801 .store_to_inferred_ptr,
802 .str,
803 .sub,
804 .subwrap,
805 .negate,
806 .negate_wrap,
807 .typeof,
808 .typeof_elem,
809 .xor,
810 .optional_type,
811 .optional_type_from_ptr_elem,
812 .optional_payload_safe,
813 .optional_payload_unsafe,
814 .optional_payload_safe_ptr,
815 .optional_payload_unsafe_ptr,
816 .err_union_payload_safe,
817 .err_union_payload_unsafe,
818 .err_union_payload_safe_ptr,
819 .err_union_payload_unsafe_ptr,
820 .err_union_code,
821 .err_union_code_ptr,
822 .error_to_int,
823 .int_to_error,
824 .ptr_type,
825 .ptr_type_simple,
826 .ensure_err_payload_void,
827 .enum_literal,
828 .enum_literal_small,
829 .merge_error_sets,
830 .error_union_type,
831 .bit_not,
832 .error_value,
833 .slice_start,
834 .slice_end,
835 .slice_sentinel,
836 .import,
837 .typeof_peer,
838 .resolve_inferred_alloc,
839 .set_eval_branch_quota,
840 .compile_log,
841 .elided,
842 .switch_capture,
843 .switch_capture_ref,
844 .switch_capture_multi,
845 .switch_capture_multi_ref,
846 .switch_capture_else,
847 .switch_capture_else_ref,
848 .switch_block,
849 .switch_block_multi,
850 .switch_block_else,
851 .switch_block_else_multi,
852 .switch_block_under,
853 .switch_block_under_multi,
854 .switch_block_ref,
855 .switch_block_ref_multi,
856 .switch_block_ref_else,
857 .switch_block_ref_else_multi,
858 .switch_block_ref_under,
859 .switch_block_ref_under_multi,
860 .validate_struct_init_ptr,
861 .struct_init_empty,
862 .struct_init,
863 .field_type,
864 .int_to_enum,
865 .enum_to_int,
866 .type_info,
867 .size_of,
868 .bit_size_of,
869 => false,
870
871 .@"break",
872 .break_inline,
873 .condbr,
874 .condbr_inline,
875 .compile_error,
876 .ret_node,
877 .ret_tok,
878 .ret_coerce,
879 .@"unreachable",
880 .repeat,
881 .repeat_inline,
882 => true,
883 };
884 }
885 };
886
887 /// The position of a ZIR instruction within the `Zir` instructions array.
888 pub const Index = u32;
889
890 /// A reference to a TypedValue, parameter of the current function,
891 /// or ZIR instruction.
892 ///
893 /// If the Ref has a tag in this enum, it refers to a TypedValue which may be
894 /// retrieved with Ref.toTypedValue().
895 ///
896 /// If the value of a Ref does not have a tag, it referes to either a parameter
897 /// of the current function or a ZIR instruction.
898 ///
899 /// The first values after the the last tag refer to parameters which may be
900 /// derived by subtracting typed_value_map.len.
901 ///
902 /// All further values refer to ZIR instructions which may be derived by
903 /// subtracting typed_value_map.len and the number of parameters.
904 ///
905 /// When adding a tag to this enum, consider adding a corresponding entry to
906 /// `simple_types` in astgen.
907 ///
908 /// The tag type is specified so that it is safe to bitcast between `[]u32`
909 /// and `[]Ref`.
910 pub const Ref = enum(u32) {
911 /// This Ref does not correspond to any ZIR instruction or constant
912 /// value and may instead be used as a sentinel to indicate null.
913 none,
914
915 u8_type,
916 i8_type,
917 u16_type,
918 i16_type,
919 u32_type,
920 i32_type,
921 u64_type,
922 i64_type,
923 usize_type,
924 isize_type,
925 c_short_type,
926 c_ushort_type,
927 c_int_type,
928 c_uint_type,
929 c_long_type,
930 c_ulong_type,
931 c_longlong_type,
932 c_ulonglong_type,
933 c_longdouble_type,
934 f16_type,
935 f32_type,
936 f64_type,
937 f128_type,
938 c_void_type,
939 bool_type,
940 void_type,
941 type_type,
942 anyerror_type,
943 comptime_int_type,
944 comptime_float_type,
945 noreturn_type,
946 null_type,
947 undefined_type,
948 fn_noreturn_no_args_type,
949 fn_void_no_args_type,
950 fn_naked_noreturn_no_args_type,
951 fn_ccc_void_no_args_type,
952 single_const_pointer_to_comptime_int_type,
953 const_slice_u8_type,
954 enum_literal_type,
955
956 /// `undefined` (untyped)
957 undef,
958 /// `0` (comptime_int)
959 zero,
960 /// `1` (comptime_int)
961 one,
962 /// `{}`
963 void_value,
964 /// `unreachable` (noreturn type)
965 unreachable_value,
966 /// `null` (untyped)
967 null_value,
968 /// `true`
969 bool_true,
970 /// `false`
971 bool_false,
972 /// `.{}` (untyped)
973 empty_struct,
974 /// `0` (usize)
975 zero_usize,
976 /// `1` (usize)
977 one_usize,
978
979 _,
980
981 pub const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{
982 .none = undefined,
983
984 .u8_type = .{
985 .ty = Type.initTag(.type),
986 .val = Value.initTag(.u8_type),
987 },
988 .i8_type = .{
989 .ty = Type.initTag(.type),
990 .val = Value.initTag(.i8_type),
991 },
992 .u16_type = .{
993 .ty = Type.initTag(.type),
994 .val = Value.initTag(.u16_type),
995 },
996 .i16_type = .{
997 .ty = Type.initTag(.type),
998 .val = Value.initTag(.i16_type),
999 },
1000 .u32_type = .{
1001 .ty = Type.initTag(.type),
1002 .val = Value.initTag(.u32_type),
1003 },
1004 .i32_type = .{
1005 .ty = Type.initTag(.type),
1006 .val = Value.initTag(.i32_type),
1007 },
1008 .u64_type = .{
1009 .ty = Type.initTag(.type),
1010 .val = Value.initTag(.u64_type),
1011 },
1012 .i64_type = .{
1013 .ty = Type.initTag(.type),
1014 .val = Value.initTag(.i64_type),
1015 },
1016 .usize_type = .{
1017 .ty = Type.initTag(.type),
1018 .val = Value.initTag(.usize_type),
1019 },
1020 .isize_type = .{
1021 .ty = Type.initTag(.type),
1022 .val = Value.initTag(.isize_type),
1023 },
1024 .c_short_type = .{
1025 .ty = Type.initTag(.type),
1026 .val = Value.initTag(.c_short_type),
1027 },
1028 .c_ushort_type = .{
1029 .ty = Type.initTag(.type),
1030 .val = Value.initTag(.c_ushort_type),
1031 },
1032 .c_int_type = .{
1033 .ty = Type.initTag(.type),
1034 .val = Value.initTag(.c_int_type),
1035 },
1036 .c_uint_type = .{
1037 .ty = Type.initTag(.type),
1038 .val = Value.initTag(.c_uint_type),
1039 },
1040 .c_long_type = .{
1041 .ty = Type.initTag(.type),
1042 .val = Value.initTag(.c_long_type),
1043 },
1044 .c_ulong_type = .{
1045 .ty = Type.initTag(.type),
1046 .val = Value.initTag(.c_ulong_type),
1047 },
1048 .c_longlong_type = .{
1049 .ty = Type.initTag(.type),
1050 .val = Value.initTag(.c_longlong_type),
1051 },
1052 .c_ulonglong_type = .{
1053 .ty = Type.initTag(.type),
1054 .val = Value.initTag(.c_ulonglong_type),
1055 },
1056 .c_longdouble_type = .{
1057 .ty = Type.initTag(.type),
1058 .val = Value.initTag(.c_longdouble_type),
1059 },
1060 .f16_type = .{
1061 .ty = Type.initTag(.type),
1062 .val = Value.initTag(.f16_type),
1063 },
1064 .f32_type = .{
1065 .ty = Type.initTag(.type),
1066 .val = Value.initTag(.f32_type),
1067 },
1068 .f64_type = .{
1069 .ty = Type.initTag(.type),
1070 .val = Value.initTag(.f64_type),
1071 },
1072 .f128_type = .{
1073 .ty = Type.initTag(.type),
1074 .val = Value.initTag(.f128_type),
1075 },
1076 .c_void_type = .{
1077 .ty = Type.initTag(.type),
1078 .val = Value.initTag(.c_void_type),
1079 },
1080 .bool_type = .{
1081 .ty = Type.initTag(.type),
1082 .val = Value.initTag(.bool_type),
1083 },
1084 .void_type = .{
1085 .ty = Type.initTag(.type),
1086 .val = Value.initTag(.void_type),
1087 },
1088 .type_type = .{
1089 .ty = Type.initTag(.type),
1090 .val = Value.initTag(.type_type),
1091 },
1092 .anyerror_type = .{
1093 .ty = Type.initTag(.type),
1094 .val = Value.initTag(.anyerror_type),
1095 },
1096 .comptime_int_type = .{
1097 .ty = Type.initTag(.type),
1098 .val = Value.initTag(.comptime_int_type),
1099 },
1100 .comptime_float_type = .{
1101 .ty = Type.initTag(.type),
1102 .val = Value.initTag(.comptime_float_type),
1103 },
1104 .noreturn_type = .{
1105 .ty = Type.initTag(.type),
1106 .val = Value.initTag(.noreturn_type),
1107 },
1108 .null_type = .{
1109 .ty = Type.initTag(.type),
1110 .val = Value.initTag(.null_type),
1111 },
1112 .undefined_type = .{
1113 .ty = Type.initTag(.type),
1114 .val = Value.initTag(.undefined_type),
1115 },
1116 .fn_noreturn_no_args_type = .{
1117 .ty = Type.initTag(.type),
1118 .val = Value.initTag(.fn_noreturn_no_args_type),
1119 },
1120 .fn_void_no_args_type = .{
1121 .ty = Type.initTag(.type),
1122 .val = Value.initTag(.fn_void_no_args_type),
1123 },
1124 .fn_naked_noreturn_no_args_type = .{
1125 .ty = Type.initTag(.type),
1126 .val = Value.initTag(.fn_naked_noreturn_no_args_type),
1127 },
1128 .fn_ccc_void_no_args_type = .{
1129 .ty = Type.initTag(.type),
1130 .val = Value.initTag(.fn_ccc_void_no_args_type),
1131 },
1132 .single_const_pointer_to_comptime_int_type = .{
1133 .ty = Type.initTag(.type),
1134 .val = Value.initTag(.single_const_pointer_to_comptime_int_type),
1135 },
1136 .const_slice_u8_type = .{
1137 .ty = Type.initTag(.type),
1138 .val = Value.initTag(.const_slice_u8_type),
1139 },
1140 .enum_literal_type = .{
1141 .ty = Type.initTag(.type),
1142 .val = Value.initTag(.enum_literal_type),
1143 },
1144
1145 .undef = .{
1146 .ty = Type.initTag(.@"undefined"),
1147 .val = Value.initTag(.undef),
1148 },
1149 .zero = .{
1150 .ty = Type.initTag(.comptime_int),
1151 .val = Value.initTag(.zero),
1152 },
1153 .zero_usize = .{
1154 .ty = Type.initTag(.usize),
1155 .val = Value.initTag(.zero),
1156 },
1157 .one = .{
1158 .ty = Type.initTag(.comptime_int),
1159 .val = Value.initTag(.one),
1160 },
1161 .one_usize = .{
1162 .ty = Type.initTag(.usize),
1163 .val = Value.initTag(.one),
1164 },
1165 .void_value = .{
1166 .ty = Type.initTag(.void),
1167 .val = Value.initTag(.void_value),
1168 },
1169 .unreachable_value = .{
1170 .ty = Type.initTag(.noreturn),
1171 .val = Value.initTag(.unreachable_value),
1172 },
1173 .null_value = .{
1174 .ty = Type.initTag(.@"null"),
1175 .val = Value.initTag(.null_value),
1176 },
1177 .bool_true = .{
1178 .ty = Type.initTag(.bool),
1179 .val = Value.initTag(.bool_true),
1180 },
1181 .bool_false = .{
1182 .ty = Type.initTag(.bool),
1183 .val = Value.initTag(.bool_false),
1184 },
1185 .empty_struct = .{
1186 .ty = Type.initTag(.empty_struct_literal),
1187 .val = Value.initTag(.empty_struct_value),
1188 },
1189 });
1190 };
1191
1192 /// All instructions have an 8-byte payload, which is contained within
1193 /// this union. `Tag` determines which union field is active, as well as
1194 /// how to interpret the data within.
1195 pub const Data = union {
1196 /// Used for unary operators, with an AST node source location.
1197 un_node: struct {
1198 /// Offset from Decl AST node index.
1199 src_node: i32,
1200 /// The meaning of this operand depends on the corresponding `Tag`.
1201 operand: Ref,
1202
1203 pub fn src(self: @This()) LazySrcLoc {
1204 return .{ .node_offset = self.src_node };
1205 }
1206 },
1207 /// Used for unary operators, with a token source location.
1208 un_tok: struct {
1209 /// Offset from Decl AST token index.
1210 src_tok: ast.TokenIndex,
1211 /// The meaning of this operand depends on the corresponding `Tag`.
1212 operand: Ref,
1213
1214 pub fn src(self: @This()) LazySrcLoc {
1215 return .{ .token_offset = self.src_tok };
1216 }
1217 },
1218 pl_node: struct {
1219 /// Offset from Decl AST node index.
1220 /// `Tag` determines which kind of AST node this points to.
1221 src_node: i32,
1222 /// index into extra.
1223 /// `Tag` determines what lives there.
1224 payload_index: u32,
1225
1226 pub fn src(self: @This()) LazySrcLoc {
1227 return .{ .node_offset = self.src_node };
1228 }
1229 },
1230 bin: Bin,
1231 /// For strings which may contain null bytes.
1232 str: struct {
1233 /// Offset into `string_bytes`.
1234 start: u32,
1235 /// Number of bytes in the string.
1236 len: u32,
1237
1238 pub fn get(self: @This(), code: Zir) []const u8 {
1239 return code.string_bytes[self.start..][0..self.len];
1240 }
1241 },
1242 /// Strings 8 or fewer bytes which may not contain null bytes.
1243 small_str: struct {
1244 bytes: [8]u8,
1245
1246 pub fn get(self: @This()) []const u8 {
1247 const end = for (self.bytes) |byte, i| {
1248 if (byte == 0) break i;
1249 } else self.bytes.len;
1250 return self.bytes[0..end];
1251 }
1252 },
1253 str_tok: struct {
1254 /// Offset into `string_bytes`. Null-terminated.
1255 start: u32,
1256 /// Offset from Decl AST token index.
1257 src_tok: u32,
1258
1259 pub fn get(self: @This(), code: Zir) [:0]const u8 {
1260 return code.nullTerminatedString(self.start);
1261 }
1262
1263 pub fn src(self: @This()) LazySrcLoc {
1264 return .{ .token_offset = self.src_tok };
1265 }
1266 },
1267 /// Offset from Decl AST token index.
1268 tok: ast.TokenIndex,
1269 /// Offset from Decl AST node index.
1270 node: i32,
1271 int: u64,
1272 float: struct {
1273 /// Offset from Decl AST node index.
1274 /// `Tag` determines which kind of AST node this points to.
1275 src_node: i32,
1276 number: f32,
1277
1278 pub fn src(self: @This()) LazySrcLoc {
1279 return .{ .node_offset = self.src_node };
1280 }
1281 },
1282 array_type_sentinel: struct {
1283 len: Ref,
1284 /// index into extra, points to an `ArrayTypeSentinel`
1285 payload_index: u32,
1286 },
1287 ptr_type_simple: struct {
1288 is_allowzero: bool,
1289 is_mutable: bool,
1290 is_volatile: bool,
1291 size: std.builtin.TypeInfo.Pointer.Size,
1292 elem_type: Ref,
1293 },
1294 ptr_type: struct {
1295 flags: packed struct {
1296 is_allowzero: bool,
1297 is_mutable: bool,
1298 is_volatile: bool,
1299 has_sentinel: bool,
1300 has_align: bool,
1301 has_bit_range: bool,
1302 _: u2 = undefined,
1303 },
1304 size: std.builtin.TypeInfo.Pointer.Size,
1305 /// Index into extra. See `PtrType`.
1306 payload_index: u32,
1307 },
1308 int_type: struct {
1309 /// Offset from Decl AST node index.
1310 /// `Tag` determines which kind of AST node this points to.
1311 src_node: i32,
1312 signedness: std.builtin.Signedness,
1313 bit_count: u16,
1314
1315 pub fn src(self: @This()) LazySrcLoc {
1316 return .{ .node_offset = self.src_node };
1317 }
1318 },
1319 bool_br: struct {
1320 lhs: Ref,
1321 /// Points to a `Block`.
1322 payload_index: u32,
1323 },
1324 param_type: struct {
1325 callee: Ref,
1326 param_index: u32,
1327 },
1328 @"unreachable": struct {
1329 /// Offset from Decl AST node index.
1330 /// `Tag` determines which kind of AST node this points to.
1331 src_node: i32,
1332 /// `false`: Not safety checked - the compiler will assume the
1333 /// correctness of this instruction.
1334 /// `true`: In safety-checked modes, this will generate a call
1335 /// to the panic function unless it can be proven unreachable by the compiler.
1336 safety: bool,
1337
1338 pub fn src(self: @This()) LazySrcLoc {
1339 return .{ .node_offset = self.src_node };
1340 }
1341 },
1342 @"break": struct {
1343 block_inst: Index,
1344 operand: Ref,
1345 },
1346 switch_capture: struct {
1347 switch_inst: Index,
1348 prong_index: u32,
1349 },
1350
1351 // Make sure we don't accidentally add a field to make this union
1352 // bigger than expected. Note that in Debug builds, Zig is allowed
1353 // to insert a secret field for safety checks.
1354 comptime {
1355 if (std.builtin.mode != .Debug) {
1356 assert(@sizeOf(Data) == 8);
1357 }
1358 }
1359 };
1360
1361 /// Stored in extra. Trailing is:
1362 /// * output_name: u32 // index into string_bytes (null terminated) if output is present
1363 /// * arg: Ref // for every args_len.
1364 /// * constraint: u32 // index into string_bytes (null terminated) for every args_len.
1365 /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.
1366 pub const Asm = struct {
1367 asm_source: Ref,
1368 return_type: Ref,
1369 /// May be omitted.
1370 output: Ref,
1371 args_len: u32,
1372 clobbers_len: u32,
1373 };
1374
1375 /// This data is stored inside extra, with trailing parameter type indexes
1376 /// according to `param_types_len`.
1377 /// Each param type is a `Ref`.
1378 pub const FnTypeCc = struct {
1379 return_type: Ref,
1380 cc: Ref,
1381 param_types_len: u32,
1382 };
1383
1384 /// This data is stored inside extra, with trailing parameter type indexes
1385 /// according to `param_types_len`.
1386 /// Each param type is a `Ref`.
1387 pub const FnType = struct {
1388 return_type: Ref,
1389 param_types_len: u32,
1390 };
1391
1392 /// This data is stored inside extra, with trailing operands according to `operands_len`.
1393 /// Each operand is a `Ref`.
1394 pub const MultiOp = struct {
1395 operands_len: u32,
1396 };
1397
1398 /// This data is stored inside extra, with trailing operands according to `body_len`.
1399 /// Each operand is an `Index`.
1400 pub const Block = struct {
1401 body_len: u32,
1402 };
1403
1404 /// Stored inside extra, with trailing arguments according to `args_len`.
1405 /// Each argument is a `Ref`.
1406 pub const Call = struct {
1407 callee: Ref,
1408 args_len: u32,
1409 };
1410
1411 /// This data is stored inside extra, with two sets of trailing `Ref`:
1412 /// * 0. the then body, according to `then_body_len`.
1413 /// * 1. the else body, according to `else_body_len`.
1414 pub const CondBr = struct {
1415 condition: Ref,
1416 then_body_len: u32,
1417 else_body_len: u32,
1418 };
1419
1420 /// Stored in extra. Depending on the flags in Data, there will be up to 4
1421 /// trailing Ref fields:
1422 /// 0. sentinel: Ref // if `has_sentinel` flag is set
1423 /// 1. align: Ref // if `has_align` flag is set
1424 /// 2. bit_start: Ref // if `has_bit_range` flag is set
1425 /// 3. bit_end: Ref // if `has_bit_range` flag is set
1426 pub const PtrType = struct {
1427 elem_type: Ref,
1428 };
1429
1430 pub const ArrayTypeSentinel = struct {
1431 sentinel: Ref,
1432 elem_type: Ref,
1433 };
1434
1435 pub const SliceStart = struct {
1436 lhs: Ref,
1437 start: Ref,
1438 };
1439
1440 pub const SliceEnd = struct {
1441 lhs: Ref,
1442 start: Ref,
1443 end: Ref,
1444 };
1445
1446 pub const SliceSentinel = struct {
1447 lhs: Ref,
1448 start: Ref,
1449 end: Ref,
1450 sentinel: Ref,
1451 };
1452
1453 /// The meaning of these operands depends on the corresponding `Tag`.
1454 pub const Bin = struct {
1455 lhs: Ref,
1456 rhs: Ref,
1457 };
1458
1459 /// This form is supported when there are no ranges, and exactly 1 item per block.
1460 /// Depending on zir tag and len fields, extra fields trail
1461 /// this one in the extra array.
1462 /// 0. else_body { // If the tag has "_else" or "_under" in it.
1463 /// body_len: u32,
1464 /// body member Index for every body_len
1465 /// }
1466 /// 1. cases: {
1467 /// item: Ref,
1468 /// body_len: u32,
1469 /// body member Index for every body_len
1470 /// } for every cases_len
1471 pub const SwitchBlock = struct {
1472 operand: Ref,
1473 cases_len: u32,
1474 };
1475
1476 /// This form is required when there exists a block which has more than one item,
1477 /// or a range.
1478 /// Depending on zir tag and len fields, extra fields trail
1479 /// this one in the extra array.
1480 /// 0. else_body { // If the tag has "_else" or "_under" in it.
1481 /// body_len: u32,
1482 /// body member Index for every body_len
1483 /// }
1484 /// 1. scalar_cases: { // for every scalar_cases_len
1485 /// item: Ref,
1486 /// body_len: u32,
1487 /// body member Index for every body_len
1488 /// }
1489 /// 2. multi_cases: { // for every multi_cases_len
1490 /// items_len: u32,
1491 /// ranges_len: u32,
1492 /// body_len: u32,
1493 /// item: Ref // for every items_len
1494 /// ranges: { // for every ranges_len
1495 /// item_first: Ref,
1496 /// item_last: Ref,
1497 /// }
1498 /// body member Index for every body_len
1499 /// }
1500 pub const SwitchBlockMulti = struct {
1501 operand: Ref,
1502 scalar_cases_len: u32,
1503 multi_cases_len: u32,
1504 };
1505
1506 pub const Field = struct {
1507 lhs: Ref,
1508 /// Offset into `string_bytes`.
1509 field_name_start: u32,
1510 };
1511
1512 pub const FieldNamed = struct {
1513 lhs: Ref,
1514 field_name: Ref,
1515 };
1516
1517 pub const As = struct {
1518 dest_type: Ref,
1519 operand: Ref,
1520 };
1521
1522 /// Trailing:
1523 /// 0. inst: Index // for every body_len
1524 /// 1. has_bits: u32 // for every 16 fields
1525 /// - sets of 2 bits:
1526 /// 0b0X: whether corresponding field has an align expression
1527 /// 0bX0: whether corresponding field has a default expression
1528 /// 2. fields: { // for every fields_len
1529 /// field_name: u32,
1530 /// field_type: Ref,
1531 /// align: Ref, // if corresponding bit is set
1532 /// default_value: Ref, // if corresponding bit is set
1533 /// }
1534 pub const StructDecl = struct {
1535 body_len: u32,
1536 fields_len: u32,
1537 };
1538
1539 /// Trailing:
1540 /// 0. inst: Index // for every body_len
1541 /// 1. has_bits: u32 // for every 32 fields
1542 /// - the bit is whether corresponding field has an value expression
1543 /// 2. fields: { // for every fields_len
1544 /// field_name: u32,
1545 /// value: Ref, // if corresponding bit is set
1546 /// }
1547 pub const EnumDecl = struct {
1548 /// Can be `Ref.none`.
1549 tag_type: Ref,
1550 body_len: u32,
1551 fields_len: u32,
1552 };
1553
1554 /// Trailing:
1555 /// 0. has_bits: u32 // for every 10 fields (+1)
1556 /// - first bit is special: set if and only if auto enum tag is enabled.
1557 /// - sets of 3 bits:
1558 /// 0b00X: whether corresponding field has a type expression
1559 /// 0b0X0: whether corresponding field has a align expression
1560 /// 0bX00: whether corresponding field has a tag value expression
1561 /// 1. field_name: u32 // for every field: null terminated string index
1562 /// 2. opt_exprs // Ref for every field for which corresponding bit is set
1563 /// - interleaved. type if present, align if present, tag value if present.
1564 pub const UnionDecl = struct {
1565 /// Can be `Ref.none`.
1566 tag_type: Ref,
1567 fields_len: u32,
1568 };
1569
1570 /// A f128 value, broken up into 4 u32 parts.
1571 pub const Float128 = struct {
1572 piece0: u32,
1573 piece1: u32,
1574 piece2: u32,
1575 piece3: u32,
1576
1577 pub fn get(self: Float128) f128 {
1578 const int_bits = @as(u128, self.piece0) |
1579 (@as(u128, self.piece1) << 32) |
1580 (@as(u128, self.piece2) << 64) |
1581 (@as(u128, self.piece3) << 96);
1582 return @bitCast(f128, int_bits);
1583 }
1584 };
1585
1586 /// Trailing is an item per field.
1587 pub const StructInit = struct {
1588 fields_len: u32,
1589
1590 pub const Item = struct {
1591 /// The `field_type` ZIR instruction for this field init.
1592 field_type: Index,
1593 /// The field init expression to be used as the field value.
1594 init: Ref,
1595 };
1596 };
1597
1598 pub const FieldType = struct {
1599 container_type: Ref,
1600 /// Offset into `string_bytes`, null terminated.
1601 name_start: u32,
1602 };
1603};
1604
1605pub const SpecialProng = enum { none, @"else", under };
1606
1607const Writer = struct {
1608 gpa: *Allocator,
1609 arena: *Allocator,
1610 scope: *Module.Scope,
1611 code: Zir,
1612 indent: usize,
1613 param_count: usize,
1614
1615 fn writeInstToStream(
1616 self: *Writer,
1617 stream: anytype,
1618 inst: Inst.Index,
1619 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1620 const tags = self.code.instructions.items(.tag);
1621 const tag = tags[inst];
1622 try stream.print("= {s}(", .{@tagName(tags[inst])});
1623 switch (tag) {
1624 .array_type,
1625 .as,
1626 .coerce_result_ptr,
1627 .elem_ptr,
1628 .elem_val,
1629 .intcast,
1630 .store,
1631 .store_to_block_ptr,
1632 .store_to_inferred_ptr,
1633 => try self.writeBin(stream, inst),
1634
1635 .alloc,
1636 .alloc_mut,
1637 .indexable_ptr_len,
1638 .bit_not,
1639 .bool_not,
1640 .negate,
1641 .negate_wrap,
1642 .call_none,
1643 .call_none_chkused,
1644 .compile_error,
1645 .load,
1646 .ensure_result_used,
1647 .ensure_result_non_error,
1648 .import,
1649 .ptrtoint,
1650 .ret_node,
1651 .set_eval_branch_quota,
1652 .resolve_inferred_alloc,
1653 .optional_type,
1654 .optional_type_from_ptr_elem,
1655 .optional_payload_safe,
1656 .optional_payload_unsafe,
1657 .optional_payload_safe_ptr,
1658 .optional_payload_unsafe_ptr,
1659 .err_union_payload_safe,
1660 .err_union_payload_unsafe,
1661 .err_union_payload_safe_ptr,
1662 .err_union_payload_unsafe_ptr,
1663 .err_union_code,
1664 .err_union_code_ptr,
1665 .int_to_error,
1666 .error_to_int,
1667 .is_non_null,
1668 .is_null,
1669 .is_non_null_ptr,
1670 .is_null_ptr,
1671 .is_err,
1672 .is_err_ptr,
1673 .typeof,
1674 .typeof_elem,
1675 .struct_init_empty,
1676 .enum_to_int,
1677 .type_info,
1678 .size_of,
1679 .bit_size_of,
1680 => try self.writeUnNode(stream, inst),
1681
1682 .ref,
1683 .ret_tok,
1684 .ret_coerce,
1685 .ensure_err_payload_void,
1686 => try self.writeUnTok(stream, inst),
1687
1688 .bool_br_and,
1689 .bool_br_or,
1690 => try self.writeBoolBr(stream, inst),
1691
1692 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
1693 .param_type => try self.writeParamType(stream, inst),
1694 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
1695 .ptr_type => try self.writePtrType(stream, inst),
1696 .int => try self.writeInt(stream, inst),
1697 .float => try self.writeFloat(stream, inst),
1698 .float128 => try self.writeFloat128(stream, inst),
1699 .str => try self.writeStr(stream, inst),
1700 .elided => try stream.writeAll(")"),
1701 .int_type => try self.writeIntType(stream, inst),
1702
1703 .@"break",
1704 .break_inline,
1705 => try self.writeBreak(stream, inst),
1706
1707 .@"asm",
1708 .asm_volatile,
1709 .elem_ptr_node,
1710 .elem_val_node,
1711 .field_ptr_named,
1712 .field_val_named,
1713 .floatcast,
1714 .slice_start,
1715 .slice_end,
1716 .slice_sentinel,
1717 .union_decl,
1718 .struct_init,
1719 .field_type,
1720 => try self.writePlNode(stream, inst),
1721
1722 .add,
1723 .addwrap,
1724 .array_cat,
1725 .array_mul,
1726 .mul,
1727 .mulwrap,
1728 .sub,
1729 .subwrap,
1730 .bool_and,
1731 .bool_or,
1732 .cmp_lt,
1733 .cmp_lte,
1734 .cmp_eq,
1735 .cmp_gte,
1736 .cmp_gt,
1737 .cmp_neq,
1738 .div,
1739 .has_decl,
1740 .mod_rem,
1741 .shl,
1742 .shr,
1743 .xor,
1744 .store_node,
1745 .error_union_type,
1746 .@"export",
1747 .merge_error_sets,
1748 .bit_and,
1749 .bit_or,
1750 .int_to_enum,
1751 => try self.writePlNodeBin(stream, inst),
1752
1753 .call,
1754 .call_chkused,
1755 .call_compile_time,
1756 => try self.writePlNodeCall(stream, inst),
1757
1758 .block,
1759 .block_inline,
1760 .loop,
1761 .validate_struct_init_ptr,
1762 => try self.writePlNodeBlock(stream, inst),
1763
1764 .condbr,
1765 .condbr_inline,
1766 => try self.writePlNodeCondBr(stream, inst),
1767
1768 .struct_decl,
1769 .struct_decl_packed,
1770 .struct_decl_extern,
1771 => try self.writeStructDecl(stream, inst),
1772
1773 .enum_decl,
1774 .enum_decl_nonexhaustive,
1775 => try self.writeEnumDecl(stream, inst),
1776
1777 .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none),
1778 .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
1779 .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under),
1780 .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none),
1781 .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
1782 .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under),
1783
1784 .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
1785 .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
1786 .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
1787 .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
1788 .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
1789 .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
1790
1791 .compile_log,
1792 .typeof_peer,
1793 => try self.writePlNodeMultiOp(stream, inst),
1794
1795 .decl_ref,
1796 .decl_val,
1797 => try self.writePlNodeDecl(stream, inst),
1798
1799 .field_ptr,
1800 .field_val,
1801 => try self.writePlNodeField(stream, inst),
1802
1803 .as_node => try self.writeAs(stream, inst),
1804
1805 .breakpoint,
1806 .opaque_decl,
1807 .dbg_stmt_node,
1808 .ret_ptr,
1809 .ret_type,
1810 .repeat,
1811 .repeat_inline,
1812 .alloc_inferred,
1813 .alloc_inferred_mut,
1814 => try self.writeNode(stream, inst),
1815
1816 .error_value,
1817 .enum_literal,
1818 .decl_ref_named,
1819 .decl_val_named,
1820 => try self.writeStrTok(stream, inst),
1821
1822 .fn_type => try self.writeFnType(stream, inst, false),
1823 .fn_type_cc => try self.writeFnTypeCc(stream, inst, false),
1824 .fn_type_var_args => try self.writeFnType(stream, inst, true),
1825 .fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true),
1826
1827 .@"unreachable" => try self.writeUnreachable(stream, inst),
1828
1829 .enum_literal_small => try self.writeSmallStr(stream, inst),
1830
1831 .switch_capture,
1832 .switch_capture_ref,
1833 .switch_capture_multi,
1834 .switch_capture_multi_ref,
1835 .switch_capture_else,
1836 .switch_capture_else_ref,
1837 => try self.writeSwitchCapture(stream, inst),
1838
1839 .bitcast,
1840 .bitcast_result_ptr,
1841 => try stream.writeAll("TODO)"),
1842 }
1843 }
1844
1845 fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1846 const inst_data = self.code.instructions.items(.data)[inst].bin;
1847 try self.writeInstRef(stream, inst_data.lhs);
1848 try stream.writeAll(", ");
1849 try self.writeInstRef(stream, inst_data.rhs);
1850 try stream.writeByte(')');
1851 }
1852
1853 fn writeUnNode(
1854 self: *Writer,
1855 stream: anytype,
1856 inst: Inst.Index,
1857 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1858 const inst_data = self.code.instructions.items(.data)[inst].un_node;
1859 try self.writeInstRef(stream, inst_data.operand);
1860 try stream.writeAll(") ");
1861 try self.writeSrc(stream, inst_data.src());
1862 }
1863
1864 fn writeUnTok(
1865 self: *Writer,
1866 stream: anytype,
1867 inst: Inst.Index,
1868 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1869 const inst_data = self.code.instructions.items(.data)[inst].un_tok;
1870 try self.writeInstRef(stream, inst_data.operand);
1871 try stream.writeAll(") ");
1872 try self.writeSrc(stream, inst_data.src());
1873 }
1874
1875 fn writeArrayTypeSentinel(
1876 self: *Writer,
1877 stream: anytype,
1878 inst: Inst.Index,
1879 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1880 const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel;
1881 try stream.writeAll("TODO)");
1882 }
1883
1884 fn writeParamType(
1885 self: *Writer,
1886 stream: anytype,
1887 inst: Inst.Index,
1888 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1889 const inst_data = self.code.instructions.items(.data)[inst].param_type;
1890 try self.writeInstRef(stream, inst_data.callee);
1891 try stream.print(", {d})", .{inst_data.param_index});
1892 }
1893
1894 fn writePtrTypeSimple(
1895 self: *Writer,
1896 stream: anytype,
1897 inst: Inst.Index,
1898 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1899 const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple;
1900 const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else "";
1901 const str_const = if (!inst_data.is_mutable) "const, " else "";
1902 const str_volatile = if (inst_data.is_volatile) "volatile, " else "";
1903 try self.writeInstRef(stream, inst_data.elem_type);
1904 try stream.print(", {s}{s}{s}{s})", .{
1905 str_allowzero,
1906 str_const,
1907 str_volatile,
1908 @tagName(inst_data.size),
1909 });
1910 }
1911
1912 fn writePtrType(
1913 self: *Writer,
1914 stream: anytype,
1915 inst: Inst.Index,
1916 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1917 const inst_data = self.code.instructions.items(.data)[inst].ptr_type;
1918 try stream.writeAll("TODO)");
1919 }
1920
1921 fn writeInt(
1922 self: *Writer,
1923 stream: anytype,
1924 inst: Inst.Index,
1925 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1926 const inst_data = self.code.instructions.items(.data)[inst].int;
1927 try stream.print("{d})", .{inst_data});
1928 }
1929
1930 fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1931 const inst_data = self.code.instructions.items(.data)[inst].float;
1932 const src = inst_data.src();
1933 try stream.print("{d}) ", .{inst_data.number});
1934 try self.writeSrc(stream, src);
1935 }
1936
1937 fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1938 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1939 const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data;
1940 const src = inst_data.src();
1941 const number = extra.get();
1942 // TODO improve std.format to be able to print f128 values
1943 try stream.print("{d}) ", .{@floatCast(f64, number)});
1944 try self.writeSrc(stream, src);
1945 }
1946
1947 fn writeStr(
1948 self: *Writer,
1949 stream: anytype,
1950 inst: Inst.Index,
1951 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1952 const inst_data = self.code.instructions.items(.data)[inst].str;
1953 const str = inst_data.get(self.code);
1954 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
1955 }
1956
1957 fn writePlNode(
1958 self: *Writer,
1959 stream: anytype,
1960 inst: Inst.Index,
1961 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1962 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1963 try stream.writeAll("TODO) ");
1964 try self.writeSrc(stream, inst_data.src());
1965 }
1966
1967 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1968 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1969 const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data;
1970 try self.writeInstRef(stream, extra.lhs);
1971 try stream.writeAll(", ");
1972 try self.writeInstRef(stream, extra.rhs);
1973 try stream.writeAll(") ");
1974 try self.writeSrc(stream, inst_data.src());
1975 }
1976
1977 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1978 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1979 const extra = self.code.extraData(Inst.Call, inst_data.payload_index);
1980 const args = self.code.refSlice(extra.end, extra.data.args_len);
1981
1982 try self.writeInstRef(stream, extra.data.callee);
1983 try stream.writeAll(", [");
1984 for (args) |arg, i| {
1985 if (i != 0) try stream.writeAll(", ");
1986 try self.writeInstRef(stream, arg);
1987 }
1988 try stream.writeAll("]) ");
1989 try self.writeSrc(stream, inst_data.src());
1990 }
1991
1992 fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1993 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1994 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
1995 const body = self.code.extra[extra.end..][0..extra.data.body_len];
1996 try stream.writeAll("{\n");
1997 self.indent += 2;
1998 try self.writeBody(stream, body);
1999 self.indent -= 2;
2000 try stream.writeByteNTimes(' ', self.indent);
2001 try stream.writeAll("}) ");
2002 try self.writeSrc(stream, inst_data.src());
2003 }
2004
2005 fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2006 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2007 const extra = self.code.extraData(Inst.CondBr, inst_data.payload_index);
2008 const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len];
2009 const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
2010 try self.writeInstRef(stream, extra.data.condition);
2011 try stream.writeAll(", {\n");
2012 self.indent += 2;
2013 try self.writeBody(stream, then_body);
2014 self.indent -= 2;
2015 try stream.writeByteNTimes(' ', self.indent);
2016 try stream.writeAll("}, {\n");
2017 self.indent += 2;
2018 try self.writeBody(stream, else_body);
2019 self.indent -= 2;
2020 try stream.writeByteNTimes(' ', self.indent);
2021 try stream.writeAll("}) ");
2022 try self.writeSrc(stream, inst_data.src());
2023 }
2024
2025 fn writeStructDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2026 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2027 const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index);
2028 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2029 const fields_len = extra.data.fields_len;
2030
2031 if (fields_len == 0) {
2032 assert(body.len == 0);
2033 try stream.writeAll("{}, {}) ");
2034 try self.writeSrc(stream, inst_data.src());
2035 return;
2036 }
2037
2038 try stream.writeAll("{\n");
2039 self.indent += 2;
2040 try self.writeBody(stream, body);
2041
2042 try stream.writeByteNTimes(' ', self.indent - 2);
2043 try stream.writeAll("}, {\n");
2044
2045 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
2046 const body_end = extra.end + body.len;
2047 var extra_index: usize = body_end + bit_bags_count;
2048 var bit_bag_index: usize = body_end;
2049 var cur_bit_bag: u32 = undefined;
2050 var field_i: u32 = 0;
2051 while (field_i < fields_len) : (field_i += 1) {
2052 if (field_i % 16 == 0) {
2053 cur_bit_bag = self.code.extra[bit_bag_index];
2054 bit_bag_index += 1;
2055 }
2056 const has_align = @truncate(u1, cur_bit_bag) != 0;
2057 cur_bit_bag >>= 1;
2058 const has_default = @truncate(u1, cur_bit_bag) != 0;
2059 cur_bit_bag >>= 1;
2060
2061 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2062 extra_index += 1;
2063 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2064 extra_index += 1;
2065
2066 try stream.writeByteNTimes(' ', self.indent);
2067 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
2068 try self.writeInstRef(stream, field_type);
2069
2070 if (has_align) {
2071 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2072 extra_index += 1;
2073
2074 try stream.writeAll(" align(");
2075 try self.writeInstRef(stream, align_ref);
2076 try stream.writeAll(")");
2077 }
2078 if (has_default) {
2079 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2080 extra_index += 1;
2081
2082 try stream.writeAll(" = ");
2083 try self.writeInstRef(stream, default_ref);
2084 }
2085 try stream.writeAll(",\n");
2086 }
2087
2088 self.indent -= 2;
2089 try stream.writeByteNTimes(' ', self.indent);
2090 try stream.writeAll("}) ");
2091 try self.writeSrc(stream, inst_data.src());
2092 }
2093
2094 fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2095 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2096 const extra = self.code.extraData(Inst.EnumDecl, inst_data.payload_index);
2097 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2098 const fields_len = extra.data.fields_len;
2099 const tag_ty_ref = extra.data.tag_type;
2100
2101 if (tag_ty_ref != .none) {
2102 try self.writeInstRef(stream, tag_ty_ref);
2103 try stream.writeAll(", ");
2104 }
2105
2106 if (fields_len == 0) {
2107 assert(body.len == 0);
2108 try stream.writeAll("{}, {}) ");
2109 try self.writeSrc(stream, inst_data.src());
2110 return;
2111 }
2112
2113 try stream.writeAll("{\n");
2114 self.indent += 2;
2115 try self.writeBody(stream, body);
2116
2117 try stream.writeByteNTimes(' ', self.indent - 2);
2118 try stream.writeAll("}, {\n");
2119
2120 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
2121 const body_end = extra.end + body.len;
2122 var extra_index: usize = body_end + bit_bags_count;
2123 var bit_bag_index: usize = body_end;
2124 var cur_bit_bag: u32 = undefined;
2125 var field_i: u32 = 0;
2126 while (field_i < fields_len) : (field_i += 1) {
2127 if (field_i % 32 == 0) {
2128 cur_bit_bag = self.code.extra[bit_bag_index];
2129 bit_bag_index += 1;
2130 }
2131 const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
2132 cur_bit_bag >>= 1;
2133
2134 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2135 extra_index += 1;
2136
2137 try stream.writeByteNTimes(' ', self.indent);
2138 try stream.print("{}", .{std.zig.fmtId(field_name)});
2139
2140 if (has_tag_value) {
2141 const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2142 extra_index += 1;
2143
2144 try stream.writeAll(" = ");
2145 try self.writeInstRef(stream, tag_value_ref);
2146 }
2147 try stream.writeAll(",\n");
2148 }
2149
2150 self.indent -= 2;
2151 try stream.writeByteNTimes(' ', self.indent);
2152 try stream.writeAll("}) ");
2153 try self.writeSrc(stream, inst_data.src());
2154 }
2155
2156 fn writePlNodeSwitchBr(
2157 self: *Writer,
2158 stream: anytype,
2159 inst: Inst.Index,
2160 special_prong: SpecialProng,
2161 ) !void {
2162 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2163 const extra = self.code.extraData(Inst.SwitchBlock, inst_data.payload_index);
2164 const special: struct {
2165 body: []const Inst.Index,
2166 end: usize,
2167 } = switch (special_prong) {
2168 .none => .{ .body = &.{}, .end = extra.end },
2169 .under, .@"else" => blk: {
2170 const body_len = self.code.extra[extra.end];
2171 const extra_body_start = extra.end + 1;
2172 break :blk .{
2173 .body = self.code.extra[extra_body_start..][0..body_len],
2174 .end = extra_body_start + body_len,
2175 };
2176 },
2177 };
2178
2179 try self.writeInstRef(stream, extra.data.operand);
2180
2181 if (special.body.len != 0) {
2182 const prong_name = switch (special_prong) {
2183 .@"else" => "else",
2184 .under => "_",
2185 else => unreachable,
2186 };
2187 try stream.print(", {s} => {{\n", .{prong_name});
2188 self.indent += 2;
2189 try self.writeBody(stream, special.body);
2190 self.indent -= 2;
2191 try stream.writeByteNTimes(' ', self.indent);
2192 try stream.writeAll("}");
2193 }
2194
2195 var extra_index: usize = special.end;
2196 {
2197 var scalar_i: usize = 0;
2198 while (scalar_i < extra.data.cases_len) : (scalar_i += 1) {
2199 const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2200 extra_index += 1;
2201 const body_len = self.code.extra[extra_index];
2202 extra_index += 1;
2203 const body = self.code.extra[extra_index..][0..body_len];
2204 extra_index += body_len;
2205
2206 try stream.writeAll(", ");
2207 try self.writeInstRef(stream, item_ref);
2208 try stream.writeAll(" => {\n");
2209 self.indent += 2;
2210 try self.writeBody(stream, body);
2211 self.indent -= 2;
2212 try stream.writeByteNTimes(' ', self.indent);
2213 try stream.writeAll("}");
2214 }
2215 }
2216 try stream.writeAll(") ");
2217 try self.writeSrc(stream, inst_data.src());
2218 }
2219
2220 fn writePlNodeSwitchBlockMulti(
2221 self: *Writer,
2222 stream: anytype,
2223 inst: Inst.Index,
2224 special_prong: SpecialProng,
2225 ) !void {
2226 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2227 const extra = self.code.extraData(Inst.SwitchBlockMulti, inst_data.payload_index);
2228 const special: struct {
2229 body: []const Inst.Index,
2230 end: usize,
2231 } = switch (special_prong) {
2232 .none => .{ .body = &.{}, .end = extra.end },
2233 .under, .@"else" => blk: {
2234 const body_len = self.code.extra[extra.end];
2235 const extra_body_start = extra.end + 1;
2236 break :blk .{
2237 .body = self.code.extra[extra_body_start..][0..body_len],
2238 .end = extra_body_start + body_len,
2239 };
2240 },
2241 };
2242
2243 try self.writeInstRef(stream, extra.data.operand);
2244
2245 if (special.body.len != 0) {
2246 const prong_name = switch (special_prong) {
2247 .@"else" => "else",
2248 .under => "_",
2249 else => unreachable,
2250 };
2251 try stream.print(", {s} => {{\n", .{prong_name});
2252 self.indent += 2;
2253 try self.writeBody(stream, special.body);
2254 self.indent -= 2;
2255 try stream.writeByteNTimes(' ', self.indent);
2256 try stream.writeAll("}");
2257 }
2258
2259 var extra_index: usize = special.end;
2260 {
2261 var scalar_i: usize = 0;
2262 while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) {
2263 const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2264 extra_index += 1;
2265 const body_len = self.code.extra[extra_index];
2266 extra_index += 1;
2267 const body = self.code.extra[extra_index..][0..body_len];
2268 extra_index += body_len;
2269
2270 try stream.writeAll(", ");
2271 try self.writeInstRef(stream, item_ref);
2272 try stream.writeAll(" => {\n");
2273 self.indent += 2;
2274 try self.writeBody(stream, body);
2275 self.indent -= 2;
2276 try stream.writeByteNTimes(' ', self.indent);
2277 try stream.writeAll("}");
2278 }
2279 }
2280 {
2281 var multi_i: usize = 0;
2282 while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) {
2283 const items_len = self.code.extra[extra_index];
2284 extra_index += 1;
2285 const ranges_len = self.code.extra[extra_index];
2286 extra_index += 1;
2287 const body_len = self.code.extra[extra_index];
2288 extra_index += 1;
2289 const items = self.code.refSlice(extra_index, items_len);
2290 extra_index += items_len;
2291
2292 for (items) |item_ref| {
2293 try stream.writeAll(", ");
2294 try self.writeInstRef(stream, item_ref);
2295 }
2296
2297 var range_i: usize = 0;
2298 while (range_i < ranges_len) : (range_i += 1) {
2299 const item_first = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2300 extra_index += 1;
2301 const item_last = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2302 extra_index += 1;
2303
2304 try stream.writeAll(", ");
2305 try self.writeInstRef(stream, item_first);
2306 try stream.writeAll("...");
2307 try self.writeInstRef(stream, item_last);
2308 }
2309
2310 const body = self.code.extra[extra_index..][0..body_len];
2311 extra_index += body_len;
2312 try stream.writeAll(" => {\n");
2313 self.indent += 2;
2314 try self.writeBody(stream, body);
2315 self.indent -= 2;
2316 try stream.writeByteNTimes(' ', self.indent);
2317 try stream.writeAll("}");
2318 }
2319 }
2320 try stream.writeAll(") ");
2321 try self.writeSrc(stream, inst_data.src());
2322 }
2323
2324 fn writePlNodeMultiOp(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2325 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2326 const extra = self.code.extraData(Inst.MultiOp, inst_data.payload_index);
2327 const operands = self.code.refSlice(extra.end, extra.data.operands_len);
2328
2329 for (operands) |operand, i| {
2330 if (i != 0) try stream.writeAll(", ");
2331 try self.writeInstRef(stream, operand);
2332 }
2333 try stream.writeAll(") ");
2334 try self.writeSrc(stream, inst_data.src());
2335 }
2336
2337 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2338 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2339 const owner_decl = self.scope.ownerDecl().?;
2340 const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key;
2341 try stream.print("{s}) ", .{decl.name});
2342 try self.writeSrc(stream, inst_data.src());
2343 }
2344
2345 fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2346 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2347 const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data;
2348 const name = self.code.nullTerminatedString(extra.field_name_start);
2349 try self.writeInstRef(stream, extra.lhs);
2350 try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)});
2351 try self.writeSrc(stream, inst_data.src());
2352 }
2353
2354 fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2355 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2356 const extra = self.code.extraData(Inst.As, inst_data.payload_index).data;
2357 try self.writeInstRef(stream, extra.dest_type);
2358 try stream.writeAll(", ");
2359 try self.writeInstRef(stream, extra.operand);
2360 try stream.writeAll(") ");
2361 try self.writeSrc(stream, inst_data.src());
2362 }
2363
2364 fn writeNode(
2365 self: *Writer,
2366 stream: anytype,
2367 inst: Inst.Index,
2368 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2369 const src_node = self.code.instructions.items(.data)[inst].node;
2370 const src: LazySrcLoc = .{ .node_offset = src_node };
2371 try stream.writeAll(") ");
2372 try self.writeSrc(stream, src);
2373 }
2374
2375 fn writeStrTok(
2376 self: *Writer,
2377 stream: anytype,
2378 inst: Inst.Index,
2379 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2380 const inst_data = self.code.instructions.items(.data)[inst].str_tok;
2381 const str = inst_data.get(self.code);
2382 try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)});
2383 try self.writeSrc(stream, inst_data.src());
2384 }
2385
2386 fn writeFnType(
2387 self: *Writer,
2388 stream: anytype,
2389 inst: Inst.Index,
2390 var_args: bool,
2391 ) !void {
2392 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2393 const src = inst_data.src();
2394 const extra = self.code.extraData(Inst.FnType, inst_data.payload_index);
2395 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
2396 return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, .none, src);
2397 }
2398
2399 fn writeFnTypeCc(
2400 self: *Writer,
2401 stream: anytype,
2402 inst: Inst.Index,
2403 var_args: bool,
2404 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2405 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2406 const src = inst_data.src();
2407 const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index);
2408 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
2409 const cc = extra.data.cc;
2410 return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, cc, src);
2411 }
2412
2413 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2414 const inst_data = self.code.instructions.items(.data)[inst].bool_br;
2415 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
2416 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2417 try self.writeInstRef(stream, inst_data.lhs);
2418 try stream.writeAll(", {\n");
2419 self.indent += 2;
2420 try self.writeBody(stream, body);
2421 self.indent -= 2;
2422 try stream.writeByteNTimes(' ', self.indent);
2423 try stream.writeAll("})");
2424 }
2425
2426 fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2427 const int_type = self.code.instructions.items(.data)[inst].int_type;
2428 const prefix: u8 = switch (int_type.signedness) {
2429 .signed => 'i',
2430 .unsigned => 'u',
2431 };
2432 try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count });
2433 try self.writeSrc(stream, int_type.src());
2434 }
2435
2436 fn writeBreak(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2437 const inst_data = self.code.instructions.items(.data)[inst].@"break";
2438
2439 try self.writeInstIndex(stream, inst_data.block_inst);
2440 try stream.writeAll(", ");
2441 try self.writeInstRef(stream, inst_data.operand);
2442 try stream.writeAll(")");
2443 }
2444
2445 fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2446 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
2447 const safety_str = if (inst_data.safety) "safe" else "unsafe";
2448 try stream.print("{s}) ", .{safety_str});
2449 try self.writeSrc(stream, inst_data.src());
2450 }
2451
2452 fn writeFnTypeCommon(
2453 self: *Writer,
2454 stream: anytype,
2455 param_types: []const Inst.Ref,
2456 ret_ty: Inst.Ref,
2457 var_args: bool,
2458 cc: Inst.Ref,
2459 src: LazySrcLoc,
2460 ) !void {
2461 try stream.writeAll("[");
2462 for (param_types) |param_type, i| {
2463 if (i != 0) try stream.writeAll(", ");
2464 try self.writeInstRef(stream, param_type);
2465 }
2466 try stream.writeAll("], ");
2467 try self.writeInstRef(stream, ret_ty);
2468 try self.writeOptionalInstRef(stream, ", cc=", cc);
2469 try self.writeFlag(stream, ", var_args", var_args);
2470 try stream.writeAll(") ");
2471 try self.writeSrc(stream, src);
2472 }
2473
2474 fn writeSmallStr(
2475 self: *Writer,
2476 stream: anytype,
2477 inst: Inst.Index,
2478 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2479 const str = self.code.instructions.items(.data)[inst].small_str.get();
2480 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
2481 }
2482
2483 fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2484 const inst_data = self.code.instructions.items(.data)[inst].switch_capture;
2485 try self.writeInstIndex(stream, inst_data.switch_inst);
2486 try stream.print(", {d})", .{inst_data.prong_index});
2487 }
2488
2489 fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void {
2490 var i: usize = @enumToInt(ref);
2491
2492 if (i < Inst.Ref.typed_value_map.len) {
2493 return stream.print("@{}", .{ref});
2494 }
2495 i -= Inst.Ref.typed_value_map.len;
2496
2497 if (i < self.param_count) {
2498 return stream.print("${d}", .{i});
2499 }
2500 i -= self.param_count;
2501
2502 return self.writeInstIndex(stream, @intCast(Inst.Index, i));
2503 }
2504
2505 fn writeInstIndex(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2506 return stream.print("%{d}", .{inst});
2507 }
2508
2509 fn writeOptionalInstRef(
2510 self: *Writer,
2511 stream: anytype,
2512 prefix: []const u8,
2513 inst: Inst.Ref,
2514 ) !void {
2515 if (inst == .none) return;
2516 try stream.writeAll(prefix);
2517 try self.writeInstRef(stream, inst);
2518 }
2519
2520 fn writeFlag(
2521 self: *Writer,
2522 stream: anytype,
2523 name: []const u8,
2524 flag: bool,
2525 ) !void {
2526 if (!flag) return;
2527 try stream.writeAll(name);
2528 }
2529
2530 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {
2531 const tree = self.scope.tree();
2532 const src_loc = src.toSrcLoc(self.scope);
2533 const abs_byte_off = try src_loc.byteOffset();
2534 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
2535 try stream.print("{s}:{d}:{d}", .{
2536 @tagName(src), delta_line.line + 1, delta_line.column + 1,
2537 });
2538 }
2539
2540 fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void {
2541 for (body) |inst| {
2542 try stream.writeByteNTimes(' ', self.indent);
2543 try stream.print("%{d} ", .{inst});
2544 try self.writeInstToStream(stream, inst);
2545 try stream.writeByte('\n');
2546 }
2547 }
2548};
src/main.zig-1
...@@ -12,7 +12,6 @@ const warn = std.log.warn;...@@ -12,7 +12,6 @@ const warn = std.log.warn;
12const Compilation = @import("Compilation.zig");12const Compilation = @import("Compilation.zig");
13const link = @import("link.zig");13const link = @import("link.zig");
14const Package = @import("Package.zig");14const Package = @import("Package.zig");
15const zir = @import("zir.zig");
16const build_options = @import("build_options");15const build_options = @import("build_options");
17const introspect = @import("introspect.zig");16const introspect = @import("introspect.zig");
18const LibCInstallation = @import("libc_installation.zig").LibCInstallation;17const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
src/test.zig-1
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const link = @import("link.zig");2const link = @import("link.zig");
3const Compilation = @import("Compilation.zig");3const Compilation = @import("Compilation.zig");
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
5const zir = @import("zir.zig");
6const Package = @import("Package.zig");5const Package = @import("Package.zig");
7const introspect = @import("introspect.zig");6const introspect = @import("introspect.zig");
8const build_options = @import("build_options");7const build_options = @import("build_options");
src/zir.zig deleted-2548
...@@ -1,2548 +0,0 @@
1//! Zig Intermediate Representation. Astgen.zig converts AST nodes to these
2//! untyped IR instructions. Next, Sema.zig processes these into TZIR.
3//! The minimum amount of information needed to represent a list of ZIR instructions.
4//! Once this structure is completed, it can be used to generate TZIR, followed by
5//! machine code, without any memory access into the AST tree token list, node list,
6//! or source bytes. Exceptions include:
7//! * Compile errors, which may need to reach into these data structures to
8//! create a useful report.
9//! * In the future, possibly inline assembly, which needs to get parsed and
10//! handled by the codegen backend, and errors reported there. However for now,
11//! inline assembly is not an exception.
12
13const std = @import("std");
14const mem = std.mem;
15const Allocator = std.mem.Allocator;
16const assert = std.debug.assert;
17const BigIntConst = std.math.big.int.Const;
18const BigIntMutable = std.math.big.int.Mutable;
19const ast = std.zig.ast;
20
21const Zir = @This();
22const Type = @import("type.zig").Type;
23const Value = @import("value.zig").Value;
24const TypedValue = @import("TypedValue.zig");
25const ir = @import("ir.zig");
26const Module = @import("Module.zig");
27const LazySrcLoc = Module.LazySrcLoc;
28
29/// There is always implicitly a `block` instruction at index 0.
30/// This is so that `break_inline` can break from the root block.
31instructions: std.MultiArrayList(Inst).Slice,
32/// In order to store references to strings in fewer bytes, we copy all
33/// string bytes into here. String bytes can be null. It is up to whomever
34/// is referencing the data here whether they want to store both index and length,
35/// thus allowing null bytes, or store only index, and use null-termination. The
36/// `string_bytes` array is agnostic to either usage.
37string_bytes: []u8,
38/// The meaning of this data is determined by `Inst.Tag` value.
39extra: []u32,
40
41/// Returns the requested data, as well as the new index which is at the start of the
42/// trailers for the object.
43pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } {
44 const fields = std.meta.fields(T);
45 var i: usize = index;
46 var result: T = undefined;
47 inline for (fields) |field| {
48 @field(result, field.name) = switch (field.field_type) {
49 u32 => code.extra[i],
50 Inst.Ref => @intToEnum(Inst.Ref, code.extra[i]),
51 else => unreachable,
52 };
53 i += 1;
54 }
55 return .{
56 .data = result,
57 .end = i,
58 };
59}
60
61/// Given an index into `string_bytes` returns the null-terminated string found there.
62pub fn nullTerminatedString(code: Zir, index: usize) [:0]const u8 {
63 var end: usize = index;
64 while (code.string_bytes[end] != 0) {
65 end += 1;
66 }
67 return code.string_bytes[index..end :0];
68}
69
70pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref {
71 const raw_slice = code.extra[start..][0..len];
72 return @bitCast([]Inst.Ref, raw_slice);
73}
74
75pub fn deinit(code: *Zir, gpa: *Allocator) void {
76 code.instructions.deinit(gpa);
77 gpa.free(code.string_bytes);
78 gpa.free(code.extra);
79 code.* = undefined;
80}
81
82/// For debugging purposes, like dumpFn but for unanalyzed zir blocks
83pub fn dump(
84 code: Zir,
85 gpa: *Allocator,
86 kind: []const u8,
87 scope: *Module.Scope,
88 param_count: usize,
89) !void {
90 var arena = std.heap.ArenaAllocator.init(gpa);
91 defer arena.deinit();
92
93 var writer: Writer = .{
94 .gpa = gpa,
95 .arena = &arena.allocator,
96 .scope = scope,
97 .code = code,
98 .indent = 0,
99 .param_count = param_count,
100 };
101
102 const decl_name = scope.srcDecl().?.name;
103 const stderr = std.io.getStdErr().writer();
104 try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name });
105 try writer.writeInstToStream(stderr, 0);
106 try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name });
107}
108
109/// These are untyped instructions generated from an Abstract Syntax Tree.
110/// The data here is immutable because it is possible to have multiple
111/// analyses on the same ZIR happening at the same time.
112pub const Inst = struct {
113 tag: Tag,
114 data: Data,
115
116 /// These names are used directly as the instruction names in the text format.
117 pub const Tag = enum(u8) {
118 /// Arithmetic addition, asserts no integer overflow.
119 /// Uses the `pl_node` union field. Payload is `Bin`.
120 add,
121 /// Twos complement wrapping integer addition.
122 /// Uses the `pl_node` union field. Payload is `Bin`.
123 addwrap,
124 /// Allocates stack local memory.
125 /// Uses the `un_node` union field. The operand is the type of the allocated object.
126 /// The node source location points to a var decl node.
127 /// Indicates the beginning of a new statement in debug info.
128 alloc,
129 /// Same as `alloc` except mutable.
130 alloc_mut,
131 /// Same as `alloc` except the type is inferred.
132 /// Uses the `node` union field.
133 alloc_inferred,
134 /// Same as `alloc_inferred` except mutable.
135 alloc_inferred_mut,
136 /// Array concatenation. `a ++ b`
137 /// Uses the `pl_node` union field. Payload is `Bin`.
138 array_cat,
139 /// Array multiplication `a ** b`
140 /// Uses the `pl_node` union field. Payload is `Bin`.
141 array_mul,
142 /// `[N]T` syntax. No source location provided.
143 /// Uses the `bin` union field. lhs is length, rhs is element type.
144 array_type,
145 /// `[N:S]T` syntax. No source location provided.
146 /// Uses the `array_type_sentinel` field.
147 array_type_sentinel,
148 /// Given a pointer to an indexable object, returns the len property. This is
149 /// used by for loops. This instruction also emits a for-loop specific compile
150 /// error if the indexable object is not indexable.
151 /// Uses the `un_node` field. The AST node is the for loop node.
152 indexable_ptr_len,
153 /// Type coercion. No source location attached.
154 /// Uses the `bin` field.
155 as,
156 /// Type coercion to the function's return type.
157 /// Uses the `pl_node` field. Payload is `As`. AST node could be many things.
158 as_node,
159 /// Inline assembly. Non-volatile.
160 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
161 @"asm",
162 /// Inline assembly with the volatile attribute.
163 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
164 asm_volatile,
165 /// Bitwise AND. `&`
166 bit_and,
167 /// Bitcast a value to a different type.
168 /// Uses the pl_node field with payload `Bin`.
169 bitcast,
170 /// A typed result location pointer is bitcasted to a new result location pointer.
171 /// The new result location pointer has an inferred type.
172 /// Uses the un_node field.
173 bitcast_result_ptr,
174 /// Bitwise NOT. `~`
175 /// Uses `un_node`.
176 bit_not,
177 /// Bitwise OR. `|`
178 bit_or,
179 /// A labeled block of code, which can return a value.
180 /// Uses the `pl_node` union field. Payload is `Block`.
181 block,
182 /// A list of instructions which are analyzed in the parent context, without
183 /// generating a runtime block. Must terminate with an "inline" variant of
184 /// a noreturn instruction.
185 /// Uses the `pl_node` union field. Payload is `Block`.
186 block_inline,
187 /// Boolean AND. See also `bit_and`.
188 /// Uses the `pl_node` union field. Payload is `Bin`.
189 bool_and,
190 /// Boolean NOT. See also `bit_not`.
191 /// Uses the `un_node` field.
192 bool_not,
193 /// Boolean OR. See also `bit_or`.
194 /// Uses the `pl_node` union field. Payload is `Bin`.
195 bool_or,
196 /// Short-circuiting boolean `and`. `lhs` is a boolean `Ref` and the other operand
197 /// is a block, which is evaluated if `lhs` is `true`.
198 /// Uses the `bool_br` union field.
199 bool_br_and,
200 /// Short-circuiting boolean `or`. `lhs` is a boolean `Ref` and the other operand
201 /// is a block, which is evaluated if `lhs` is `false`.
202 /// Uses the `bool_br` union field.
203 bool_br_or,
204 /// Return a value from a block.
205 /// Uses the `break` union field.
206 /// Uses the source information from previous instruction.
207 @"break",
208 /// Return a value from a block. This instruction is used as the terminator
209 /// of a `block_inline`. It allows using the return value from `Sema.analyzeBody`.
210 /// This instruction may also be used when it is known that there is only one
211 /// break instruction in a block, and the target block is the parent.
212 /// Uses the `break` union field.
213 break_inline,
214 /// Uses the `node` union field.
215 breakpoint,
216 /// Function call with modifier `.auto`.
217 /// Uses `pl_node`. AST node is the function call. Payload is `Call`.
218 call,
219 /// Same as `call` but it also does `ensure_result_used` on the return value.
220 call_chkused,
221 /// Same as `call` but with modifier `.compile_time`.
222 call_compile_time,
223 /// Function call with modifier `.auto`, empty parameter list.
224 /// Uses the `un_node` field. Operand is callee. AST node is the function call.
225 call_none,
226 /// Same as `call_none` but it also does `ensure_result_used` on the return value.
227 call_none_chkused,
228 /// `<`
229 /// Uses the `pl_node` union field. Payload is `Bin`.
230 cmp_lt,
231 /// `<=`
232 /// Uses the `pl_node` union field. Payload is `Bin`.
233 cmp_lte,
234 /// `==`
235 /// Uses the `pl_node` union field. Payload is `Bin`.
236 cmp_eq,
237 /// `>=`
238 /// Uses the `pl_node` union field. Payload is `Bin`.
239 cmp_gte,
240 /// `>`
241 /// Uses the `pl_node` union field. Payload is `Bin`.
242 cmp_gt,
243 /// `!=`
244 /// Uses the `pl_node` union field. Payload is `Bin`.
245 cmp_neq,
246 /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
247 /// as type coercion from the new element type to the old element type.
248 /// Uses the `bin` union field.
249 /// LHS is destination element type, RHS is result pointer.
250 coerce_result_ptr,
251 /// Emit an error message and fail compilation.
252 /// Uses the `un_node` field.
253 compile_error,
254 /// Log compile time variables and emit an error message.
255 /// Uses the `pl_node` union field. The AST node is the compile log builtin call.
256 /// The payload is `MultiOp`.
257 compile_log,
258 /// Conditional branch. Splits control flow based on a boolean condition value.
259 /// Uses the `pl_node` union field. AST node is an if, while, for, etc.
260 /// Payload is `CondBr`.
261 condbr,
262 /// Same as `condbr`, except the condition is coerced to a comptime value, and
263 /// only the taken branch is analyzed. The then block and else block must
264 /// terminate with an "inline" variant of a noreturn instruction.
265 condbr_inline,
266 /// A struct type definition. Contains references to ZIR instructions for
267 /// the field types, defaults, and alignments.
268 /// Uses the `pl_node` union field. Payload is `StructDecl`.
269 struct_decl,
270 /// Same as `struct_decl`, except has the `packed` layout.
271 struct_decl_packed,
272 /// Same as `struct_decl`, except has the `extern` layout.
273 struct_decl_extern,
274 /// A union type definition. Contains references to ZIR instructions for
275 /// the field types and optional type tag expression.
276 /// Uses the `pl_node` union field. Payload is `UnionDecl`.
277 union_decl,
278 /// An enum type definition. Contains references to ZIR instructions for
279 /// the field value expressions and optional type tag expression.
280 /// Uses the `pl_node` union field. Payload is `EnumDecl`.
281 enum_decl,
282 /// Same as `enum_decl`, except the enum is non-exhaustive.
283 enum_decl_nonexhaustive,
284 /// An opaque type definition. Provides an AST node only.
285 /// Uses the `node` union field.
286 opaque_decl,
287 /// Declares the beginning of a statement. Used for debug info.
288 /// Uses the `node` union field.
289 dbg_stmt_node,
290 /// Represents a pointer to a global decl.
291 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
292 decl_ref,
293 /// Equivalent to a decl_ref followed by load.
294 /// Uses the `pl_node` union field. `payload_index` is into `decls`.
295 decl_val,
296 /// Same as `decl_ref` except instead of indexing into decls, uses
297 /// a name to identify the Decl. Uses the `str_tok` union field.
298 decl_ref_named,
299 /// Same as `decl_val` except instead of indexing into decls, uses
300 /// a name to identify the Decl. Uses the `str_tok` union field.
301 decl_val_named,
302 /// Load the value from a pointer. Assumes `x.*` syntax.
303 /// Uses `un_node` field. AST node is the `x.*` syntax.
304 load,
305 /// Arithmetic division. Asserts no integer overflow.
306 /// Uses the `pl_node` union field. Payload is `Bin`.
307 div,
308 /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at
309 /// the provided index. Uses the `bin` union field. Source location is implied
310 /// to be the same as the previous instruction.
311 elem_ptr,
312 /// Same as `elem_ptr` except also stores a source location node.
313 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
314 elem_ptr_node,
315 /// Given an array, slice, or pointer, returns the element at the provided index.
316 /// Uses the `bin` union field. Source location is implied to be the same
317 /// as the previous instruction.
318 elem_val,
319 /// Same as `elem_val` except also stores a source location node.
320 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
321 elem_val_node,
322 /// This instruction has been deleted late in the astgen phase. It must
323 /// be ignored, and the corresponding `Data` is undefined.
324 elided,
325 /// Emits a compile error if the operand is not `void`.
326 /// Uses the `un_node` field.
327 ensure_result_used,
328 /// Emits a compile error if an error is ignored.
329 /// Uses the `un_node` field.
330 ensure_result_non_error,
331 /// Create a `E!T` type.
332 /// Uses the `pl_node` field with `Bin` payload.
333 error_union_type,
334 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
335 error_value,
336 /// Implements the `@export` builtin function.
337 /// Uses the `pl_node` union field. Payload is `Bin`.
338 @"export",
339 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
340 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
341 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
342 field_ptr,
343 /// Given a struct or object that contains virtual fields, returns the named field.
344 /// The field name is stored in string_bytes. Used by a.b syntax.
345 /// This instruction also accepts a pointer.
346 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
347 field_val,
348 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
349 /// to the named field. The field name is a comptime instruction. Used by @field.
350 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
351 field_ptr_named,
352 /// Given a struct or object that contains virtual fields, returns the named field.
353 /// The field name is a comptime instruction. Used by @field.
354 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
355 field_val_named,
356 /// Convert a larger float type to any other float type, possibly causing
357 /// a loss of precision.
358 /// Uses the `pl_node` field. AST is the `@floatCast` syntax.
359 /// Payload is `Bin` with lhs as the dest type, rhs the operand.
360 floatcast,
361 /// Returns a function type, assuming unspecified calling convention.
362 /// Uses the `pl_node` union field. `payload_index` points to a `FnType`.
363 fn_type,
364 /// Same as `fn_type` but the function is variadic.
365 fn_type_var_args,
366 /// Returns a function type, with a calling convention instruction operand.
367 /// Uses the `pl_node` union field. `payload_index` points to a `FnTypeCc`.
368 fn_type_cc,
369 /// Same as `fn_type_cc` but the function is variadic.
370 fn_type_cc_var_args,
371 /// Implements the `@hasDecl` builtin.
372 /// Uses the `pl_node` union field. Payload is `Bin`.
373 has_decl,
374 /// `@import(operand)`.
375 /// Uses the `un_node` field.
376 import,
377 /// Integer literal that fits in a u64. Uses the int union value.
378 int,
379 /// A float literal that fits in a f32. Uses the float union value.
380 float,
381 /// A float literal that fits in a f128. Uses the `pl_node` union value.
382 /// Payload is `Float128`.
383 float128,
384 /// Convert an integer value to another integer type, asserting that the destination type
385 /// can hold the same mathematical value.
386 /// Uses the `pl_node` field. AST is the `@intCast` syntax.
387 /// Payload is `Bin` with lhs as the dest type, rhs the operand.
388 intcast,
389 /// Make an integer type out of signedness and bit count.
390 /// Payload is `int_type`
391 int_type,
392 /// Convert an error type to `u16`
393 error_to_int,
394 /// Convert a `u16` to `anyerror`
395 int_to_error,
396 /// Return a boolean false if an optional is null. `x != null`
397 /// Uses the `un_node` field.
398 is_non_null,
399 /// Return a boolean true if an optional is null. `x == null`
400 /// Uses the `un_node` field.
401 is_null,
402 /// Return a boolean false if an optional is null. `x.* != null`
403 /// Uses the `un_node` field.
404 is_non_null_ptr,
405 /// Return a boolean true if an optional is null. `x.* == null`
406 /// Uses the `un_node` field.
407 is_null_ptr,
408 /// Return a boolean true if value is an error
409 /// Uses the `un_node` field.
410 is_err,
411 /// Return a boolean true if dereferenced pointer is an error
412 /// Uses the `un_node` field.
413 is_err_ptr,
414 /// A labeled block of code that loops forever. At the end of the body will have either
415 /// a `repeat` instruction or a `repeat_inline` instruction.
416 /// Uses the `pl_node` field. The AST node is either a for loop or while loop.
417 /// This ZIR instruction is needed because TZIR does not (yet?) match ZIR, and Sema
418 /// needs to emit more than 1 TZIR block for this instruction.
419 /// The payload is `Block`.
420 loop,
421 /// Sends runtime control flow back to the beginning of the current block.
422 /// Uses the `node` field.
423 repeat,
424 /// Sends comptime control flow back to the beginning of the current block.
425 /// Uses the `node` field.
426 repeat_inline,
427 /// Merge two error sets into one, `E1 || E2`.
428 /// Uses the `pl_node` field with payload `Bin`.
429 merge_error_sets,
430 /// Ambiguously remainder division or modulus. If the computation would possibly have
431 /// a different value depending on whether the operation is remainder division or modulus,
432 /// a compile error is emitted. Otherwise the computation is performed.
433 /// Uses the `pl_node` union field. Payload is `Bin`.
434 mod_rem,
435 /// Arithmetic multiplication. Asserts no integer overflow.
436 /// Uses the `pl_node` union field. Payload is `Bin`.
437 mul,
438 /// Twos complement wrapping integer multiplication.
439 /// Uses the `pl_node` union field. Payload is `Bin`.
440 mulwrap,
441 /// Given a reference to a function and a parameter index, returns the
442 /// type of the parameter. The only usage of this instruction is for the
443 /// result location of parameters of function calls. In the case of a function's
444 /// parameter type being `anytype`, it is the type coercion's job to detect this
445 /// scenario and skip the coercion, so that semantic analysis of this instruction
446 /// is not in a position where it must create an invalid type.
447 /// Uses the `param_type` union field.
448 param_type,
449 /// Convert a pointer to a `usize` integer.
450 /// Uses the `un_node` field. The AST node is the builtin fn call node.
451 ptrtoint,
452 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
453 /// stores it in a memory location, and returns a const pointer to it. If the value
454 /// is `comptime`, the memory location is global static constant data. Otherwise,
455 /// the memory location is in the stack frame, local to the scope containing the
456 /// instruction.
457 /// Uses the `un_tok` union field.
458 ref,
459 /// Obtains a pointer to the return value.
460 /// Uses the `node` union field.
461 ret_ptr,
462 /// Obtains the return type of the in-scope function.
463 /// Uses the `node` union field.
464 ret_type,
465 /// Sends control flow back to the function's callee.
466 /// Includes an operand as the return value.
467 /// Includes an AST node source location.
468 /// Uses the `un_node` union field.
469 ret_node,
470 /// Sends control flow back to the function's callee.
471 /// Includes an operand as the return value.
472 /// Includes a token source location.
473 /// Uses the `un_tok` union field.
474 ret_tok,
475 /// Same as `ret_tok` except the operand needs to get coerced to the function's
476 /// return type.
477 ret_coerce,
478 /// Changes the maximum number of backwards branches that compile-time
479 /// code execution can use before giving up and making a compile error.
480 /// Uses the `un_node` union field.
481 set_eval_branch_quota,
482 /// Integer shift-left. Zeroes are shifted in from the right hand side.
483 /// Uses the `pl_node` union field. Payload is `Bin`.
484 shl,
485 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
486 /// Uses the `pl_node` union field. Payload is `Bin`.
487 shr,
488 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
489 /// Uses the `ptr_type_simple` union field.
490 ptr_type_simple,
491 /// Create a pointer type which can have a sentinel, alignment, and/or bit range.
492 /// Uses the `ptr_type` union field.
493 ptr_type,
494 /// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
495 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
496 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
497 /// is the allocation that needs to have its type inferred.
498 /// Uses the `un_node` field. The AST node is the var decl.
499 resolve_inferred_alloc,
500 /// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
501 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`.
502 slice_start,
503 /// Slice operation `array_ptr[start..end]`. No sentinel.
504 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceEnd`.
505 slice_end,
506 /// Slice operation `array_ptr[start..end:sentinel]`.
507 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`.
508 slice_sentinel,
509 /// Write a value to a pointer. For loading, see `load`.
510 /// Source location is assumed to be same as previous instruction.
511 /// Uses the `bin` union field.
512 store,
513 /// Same as `store` except provides a source location.
514 /// Uses the `pl_node` union field. Payload is `Bin`.
515 store_node,
516 /// Same as `store` but the type of the value being stored will be used to infer
517 /// the block type. The LHS is the pointer to store to.
518 /// Uses the `bin` union field.
519 store_to_block_ptr,
520 /// Same as `store` but the type of the value being stored will be used to infer
521 /// the pointer type.
522 /// Uses the `bin` union field - Astgen.zig depends on the ability to change
523 /// the tag of an instruction from `store_to_block_ptr` to `store_to_inferred_ptr`
524 /// without changing the data.
525 store_to_inferred_ptr,
526 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
527 /// Uses the `str` union field.
528 str,
529 /// Arithmetic subtraction. Asserts no integer overflow.
530 /// Uses the `pl_node` union field. Payload is `Bin`.
531 sub,
532 /// Twos complement wrapping integer subtraction.
533 /// Uses the `pl_node` union field. Payload is `Bin`.
534 subwrap,
535 /// Arithmetic negation. Asserts no integer overflow.
536 /// Same as sub with a lhs of 0, split into a separate instruction to save memory.
537 /// Uses `un_node`.
538 negate,
539 /// Twos complement wrapping integer negation.
540 /// Same as subwrap with a lhs of 0, split into a separate instruction to save memory.
541 /// Uses `un_node`.
542 negate_wrap,
543 /// Returns the type of a value.
544 /// Uses the `un_tok` field.
545 typeof,
546 /// Given a value which is a pointer, returns the element type.
547 /// Uses the `un_node` field.
548 typeof_elem,
549 /// The builtin `@TypeOf` which returns the type after Peer Type Resolution
550 /// of one or more params.
551 /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
552 typeof_peer,
553 /// Asserts control-flow will not reach this instruction (`unreachable`).
554 /// Uses the `unreachable` union field.
555 @"unreachable",
556 /// Bitwise XOR. `^`
557 /// Uses the `pl_node` union field. Payload is `Bin`.
558 xor,
559 /// Create an optional type '?T'
560 /// Uses the `un_node` field.
561 optional_type,
562 /// Create an optional type '?T'. The operand is a pointer value. The optional type will
563 /// be the type of the pointer element, wrapped in an optional.
564 /// Uses the `un_node` field.
565 optional_type_from_ptr_elem,
566 /// ?T => T with safety.
567 /// Given an optional value, returns the payload value, with a safety check that
568 /// the value is non-null. Used for `orelse`, `if` and `while`.
569 /// Uses the `un_node` field.
570 optional_payload_safe,
571 /// ?T => T without safety.
572 /// Given an optional value, returns the payload value. No safety checks.
573 /// Uses the `un_node` field.
574 optional_payload_unsafe,
575 /// *?T => *T with safety.
576 /// Given a pointer to an optional value, returns a pointer to the payload value,
577 /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`.
578 /// Uses the `un_node` field.
579 optional_payload_safe_ptr,
580 /// *?T => *T without safety.
581 /// Given a pointer to an optional value, returns a pointer to the payload value.
582 /// No safety checks.
583 /// Uses the `un_node` field.
584 optional_payload_unsafe_ptr,
585 /// E!T => T with safety.
586 /// Given an error union value, returns the payload value, with a safety check
587 /// that the value is not an error. Used for catch, if, and while.
588 /// Uses the `un_node` field.
589 err_union_payload_safe,
590 /// E!T => T without safety.
591 /// Given an error union value, returns the payload value. No safety checks.
592 /// Uses the `un_node` field.
593 err_union_payload_unsafe,
594 /// *E!T => *T with safety.
595 /// Given a pointer to an error union value, returns a pointer to the payload value,
596 /// with a safety check that the value is not an error. Used for catch, if, and while.
597 /// Uses the `un_node` field.
598 err_union_payload_safe_ptr,
599 /// *E!T => *T without safety.
600 /// Given a pointer to a error union value, returns a pointer to the payload value.
601 /// No safety checks.
602 /// Uses the `un_node` field.
603 err_union_payload_unsafe_ptr,
604 /// E!T => E without safety.
605 /// Given an error union value, returns the error code. No safety checks.
606 /// Uses the `un_node` field.
607 err_union_code,
608 /// *E!T => E without safety.
609 /// Given a pointer to an error union value, returns the error code. No safety checks.
610 /// Uses the `un_node` field.
611 err_union_code_ptr,
612 /// Takes a *E!T and raises a compiler error if T != void
613 /// Uses the `un_tok` field.
614 ensure_err_payload_void,
615 /// An enum literal. Uses the `str_tok` union field.
616 enum_literal,
617 /// An enum literal 8 or fewer bytes. No source location.
618 /// Uses the `small_str` field.
619 enum_literal_small,
620 /// A switch expression. Uses the `pl_node` union field.
621 /// AST node is the switch, payload is `SwitchBlock`.
622 /// All prongs of target handled.
623 switch_block,
624 /// Same as switch_block, except one or more prongs have multiple items.
625 switch_block_multi,
626 /// Same as switch_block, except has an else prong.
627 switch_block_else,
628 /// Same as switch_block_else, except one or more prongs have multiple items.
629 switch_block_else_multi,
630 /// Same as switch_block, except has an underscore prong.
631 switch_block_under,
632 /// Same as switch_block, except one or more prongs have multiple items.
633 switch_block_under_multi,
634 /// Same as `switch_block` but the target is a pointer to the value being switched on.
635 switch_block_ref,
636 /// Same as `switch_block_multi` but the target is a pointer to the value being switched on.
637 switch_block_ref_multi,
638 /// Same as `switch_block_else` but the target is a pointer to the value being switched on.
639 switch_block_ref_else,
640 /// Same as `switch_block_else_multi` but the target is a pointer to the
641 /// value being switched on.
642 switch_block_ref_else_multi,
643 /// Same as `switch_block_under` but the target is a pointer to the value
644 /// being switched on.
645 switch_block_ref_under,
646 /// Same as `switch_block_under_multi` but the target is a pointer to
647 /// the value being switched on.
648 switch_block_ref_under_multi,
649 /// Produces the capture value for a switch prong.
650 /// Uses the `switch_capture` field.
651 switch_capture,
652 /// Produces the capture value for a switch prong.
653 /// Result is a pointer to the value.
654 /// Uses the `switch_capture` field.
655 switch_capture_ref,
656 /// Produces the capture value for a switch prong.
657 /// The prong is one of the multi cases.
658 /// Uses the `switch_capture` field.
659 switch_capture_multi,
660 /// Produces the capture value for a switch prong.
661 /// The prong is one of the multi cases.
662 /// Result is a pointer to the value.
663 /// Uses the `switch_capture` field.
664 switch_capture_multi_ref,
665 /// Produces the capture value for the else/'_' switch prong.
666 /// Uses the `switch_capture` field.
667 switch_capture_else,
668 /// Produces the capture value for the else/'_' switch prong.
669 /// Result is a pointer to the value.
670 /// Uses the `switch_capture` field.
671 switch_capture_else_ref,
672 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
673 /// initialization expression, and emits compile errors for duplicate fields
674 /// as well as missing fields, if applicable.
675 /// This instruction asserts that there is at least one field_ptr instruction,
676 /// because it must use one of them to find out the struct type.
677 /// Uses the `pl_node` field. Payload is `Block`.
678 validate_struct_init_ptr,
679 /// A struct literal with a specified type, with no fields.
680 /// Uses the `un_node` field.
681 struct_init_empty,
682 /// Given a struct, union, enum, or opaque and a field name, returns the field type.
683 /// Uses the `pl_node` field. Payload is `FieldType`.
684 field_type,
685 /// Finalizes a typed struct initialization, performs validation, and returns the
686 /// struct value.
687 /// Uses the `pl_node` field. Payload is `StructInit`.
688 struct_init,
689 /// Converts an integer into an enum value.
690 /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
691 int_to_enum,
692 /// Converts an enum value into an integer. Resulting type will be the tag type
693 /// of the enum. Uses `un_node`.
694 enum_to_int,
695 /// Implements the `@typeInfo` builtin. Uses `un_node`.
696 type_info,
697 /// Implements the `@sizeOf` builtin. Uses `un_node`.
698 size_of,
699 /// Implements the `@bitSizeOf` builtin. Uses `un_node`.
700 bit_size_of,
701
702 /// Returns whether the instruction is one of the control flow "noreturn" types.
703 /// Function calls do not count.
704 pub fn isNoReturn(tag: Tag) bool {
705 return switch (tag) {
706 .add,
707 .addwrap,
708 .alloc,
709 .alloc_mut,
710 .alloc_inferred,
711 .alloc_inferred_mut,
712 .array_cat,
713 .array_mul,
714 .array_type,
715 .array_type_sentinel,
716 .indexable_ptr_len,
717 .as,
718 .as_node,
719 .@"asm",
720 .asm_volatile,
721 .bit_and,
722 .bitcast,
723 .bitcast_result_ptr,
724 .bit_or,
725 .block,
726 .block_inline,
727 .loop,
728 .bool_br_and,
729 .bool_br_or,
730 .bool_not,
731 .bool_and,
732 .bool_or,
733 .breakpoint,
734 .call,
735 .call_chkused,
736 .call_compile_time,
737 .call_none,
738 .call_none_chkused,
739 .cmp_lt,
740 .cmp_lte,
741 .cmp_eq,
742 .cmp_gte,
743 .cmp_gt,
744 .cmp_neq,
745 .coerce_result_ptr,
746 .struct_decl,
747 .struct_decl_packed,
748 .struct_decl_extern,
749 .union_decl,
750 .enum_decl,
751 .enum_decl_nonexhaustive,
752 .opaque_decl,
753 .dbg_stmt_node,
754 .decl_ref,
755 .decl_val,
756 .decl_ref_named,
757 .decl_val_named,
758 .load,
759 .div,
760 .elem_ptr,
761 .elem_val,
762 .elem_ptr_node,
763 .elem_val_node,
764 .ensure_result_used,
765 .ensure_result_non_error,
766 .@"export",
767 .floatcast,
768 .field_ptr,
769 .field_val,
770 .field_ptr_named,
771 .field_val_named,
772 .fn_type,
773 .fn_type_var_args,
774 .fn_type_cc,
775 .fn_type_cc_var_args,
776 .has_decl,
777 .int,
778 .float,
779 .float128,
780 .intcast,
781 .int_type,
782 .is_non_null,
783 .is_null,
784 .is_non_null_ptr,
785 .is_null_ptr,
786 .is_err,
787 .is_err_ptr,
788 .mod_rem,
789 .mul,
790 .mulwrap,
791 .param_type,
792 .ptrtoint,
793 .ref,
794 .ret_ptr,
795 .ret_type,
796 .shl,
797 .shr,
798 .store,
799 .store_node,
800 .store_to_block_ptr,
801 .store_to_inferred_ptr,
802 .str,
803 .sub,
804 .subwrap,
805 .negate,
806 .negate_wrap,
807 .typeof,
808 .typeof_elem,
809 .xor,
810 .optional_type,
811 .optional_type_from_ptr_elem,
812 .optional_payload_safe,
813 .optional_payload_unsafe,
814 .optional_payload_safe_ptr,
815 .optional_payload_unsafe_ptr,
816 .err_union_payload_safe,
817 .err_union_payload_unsafe,
818 .err_union_payload_safe_ptr,
819 .err_union_payload_unsafe_ptr,
820 .err_union_code,
821 .err_union_code_ptr,
822 .error_to_int,
823 .int_to_error,
824 .ptr_type,
825 .ptr_type_simple,
826 .ensure_err_payload_void,
827 .enum_literal,
828 .enum_literal_small,
829 .merge_error_sets,
830 .error_union_type,
831 .bit_not,
832 .error_value,
833 .slice_start,
834 .slice_end,
835 .slice_sentinel,
836 .import,
837 .typeof_peer,
838 .resolve_inferred_alloc,
839 .set_eval_branch_quota,
840 .compile_log,
841 .elided,
842 .switch_capture,
843 .switch_capture_ref,
844 .switch_capture_multi,
845 .switch_capture_multi_ref,
846 .switch_capture_else,
847 .switch_capture_else_ref,
848 .switch_block,
849 .switch_block_multi,
850 .switch_block_else,
851 .switch_block_else_multi,
852 .switch_block_under,
853 .switch_block_under_multi,
854 .switch_block_ref,
855 .switch_block_ref_multi,
856 .switch_block_ref_else,
857 .switch_block_ref_else_multi,
858 .switch_block_ref_under,
859 .switch_block_ref_under_multi,
860 .validate_struct_init_ptr,
861 .struct_init_empty,
862 .struct_init,
863 .field_type,
864 .int_to_enum,
865 .enum_to_int,
866 .type_info,
867 .size_of,
868 .bit_size_of,
869 => false,
870
871 .@"break",
872 .break_inline,
873 .condbr,
874 .condbr_inline,
875 .compile_error,
876 .ret_node,
877 .ret_tok,
878 .ret_coerce,
879 .@"unreachable",
880 .repeat,
881 .repeat_inline,
882 => true,
883 };
884 }
885 };
886
887 /// The position of a ZIR instruction within the `Zir` instructions array.
888 pub const Index = u32;
889
890 /// A reference to a TypedValue, parameter of the current function,
891 /// or ZIR instruction.
892 ///
893 /// If the Ref has a tag in this enum, it refers to a TypedValue which may be
894 /// retrieved with Ref.toTypedValue().
895 ///
896 /// If the value of a Ref does not have a tag, it referes to either a parameter
897 /// of the current function or a ZIR instruction.
898 ///
899 /// The first values after the the last tag refer to parameters which may be
900 /// derived by subtracting typed_value_map.len.
901 ///
902 /// All further values refer to ZIR instructions which may be derived by
903 /// subtracting typed_value_map.len and the number of parameters.
904 ///
905 /// When adding a tag to this enum, consider adding a corresponding entry to
906 /// `simple_types` in astgen.
907 ///
908 /// The tag type is specified so that it is safe to bitcast between `[]u32`
909 /// and `[]Ref`.
910 pub const Ref = enum(u32) {
911 /// This Ref does not correspond to any ZIR instruction or constant
912 /// value and may instead be used as a sentinel to indicate null.
913 none,
914
915 u8_type,
916 i8_type,
917 u16_type,
918 i16_type,
919 u32_type,
920 i32_type,
921 u64_type,
922 i64_type,
923 usize_type,
924 isize_type,
925 c_short_type,
926 c_ushort_type,
927 c_int_type,
928 c_uint_type,
929 c_long_type,
930 c_ulong_type,
931 c_longlong_type,
932 c_ulonglong_type,
933 c_longdouble_type,
934 f16_type,
935 f32_type,
936 f64_type,
937 f128_type,
938 c_void_type,
939 bool_type,
940 void_type,
941 type_type,
942 anyerror_type,
943 comptime_int_type,
944 comptime_float_type,
945 noreturn_type,
946 null_type,
947 undefined_type,
948 fn_noreturn_no_args_type,
949 fn_void_no_args_type,
950 fn_naked_noreturn_no_args_type,
951 fn_ccc_void_no_args_type,
952 single_const_pointer_to_comptime_int_type,
953 const_slice_u8_type,
954 enum_literal_type,
955
956 /// `undefined` (untyped)
957 undef,
958 /// `0` (comptime_int)
959 zero,
960 /// `1` (comptime_int)
961 one,
962 /// `{}`
963 void_value,
964 /// `unreachable` (noreturn type)
965 unreachable_value,
966 /// `null` (untyped)
967 null_value,
968 /// `true`
969 bool_true,
970 /// `false`
971 bool_false,
972 /// `.{}` (untyped)
973 empty_struct,
974 /// `0` (usize)
975 zero_usize,
976 /// `1` (usize)
977 one_usize,
978
979 _,
980
981 pub const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{
982 .none = undefined,
983
984 .u8_type = .{
985 .ty = Type.initTag(.type),
986 .val = Value.initTag(.u8_type),
987 },
988 .i8_type = .{
989 .ty = Type.initTag(.type),
990 .val = Value.initTag(.i8_type),
991 },
992 .u16_type = .{
993 .ty = Type.initTag(.type),
994 .val = Value.initTag(.u16_type),
995 },
996 .i16_type = .{
997 .ty = Type.initTag(.type),
998 .val = Value.initTag(.i16_type),
999 },
1000 .u32_type = .{
1001 .ty = Type.initTag(.type),
1002 .val = Value.initTag(.u32_type),
1003 },
1004 .i32_type = .{
1005 .ty = Type.initTag(.type),
1006 .val = Value.initTag(.i32_type),
1007 },
1008 .u64_type = .{
1009 .ty = Type.initTag(.type),
1010 .val = Value.initTag(.u64_type),
1011 },
1012 .i64_type = .{
1013 .ty = Type.initTag(.type),
1014 .val = Value.initTag(.i64_type),
1015 },
1016 .usize_type = .{
1017 .ty = Type.initTag(.type),
1018 .val = Value.initTag(.usize_type),
1019 },
1020 .isize_type = .{
1021 .ty = Type.initTag(.type),
1022 .val = Value.initTag(.isize_type),
1023 },
1024 .c_short_type = .{
1025 .ty = Type.initTag(.type),
1026 .val = Value.initTag(.c_short_type),
1027 },
1028 .c_ushort_type = .{
1029 .ty = Type.initTag(.type),
1030 .val = Value.initTag(.c_ushort_type),
1031 },
1032 .c_int_type = .{
1033 .ty = Type.initTag(.type),
1034 .val = Value.initTag(.c_int_type),
1035 },
1036 .c_uint_type = .{
1037 .ty = Type.initTag(.type),
1038 .val = Value.initTag(.c_uint_type),
1039 },
1040 .c_long_type = .{
1041 .ty = Type.initTag(.type),
1042 .val = Value.initTag(.c_long_type),
1043 },
1044 .c_ulong_type = .{
1045 .ty = Type.initTag(.type),
1046 .val = Value.initTag(.c_ulong_type),
1047 },
1048 .c_longlong_type = .{
1049 .ty = Type.initTag(.type),
1050 .val = Value.initTag(.c_longlong_type),
1051 },
1052 .c_ulonglong_type = .{
1053 .ty = Type.initTag(.type),
1054 .val = Value.initTag(.c_ulonglong_type),
1055 },
1056 .c_longdouble_type = .{
1057 .ty = Type.initTag(.type),
1058 .val = Value.initTag(.c_longdouble_type),
1059 },
1060 .f16_type = .{
1061 .ty = Type.initTag(.type),
1062 .val = Value.initTag(.f16_type),
1063 },
1064 .f32_type = .{
1065 .ty = Type.initTag(.type),
1066 .val = Value.initTag(.f32_type),
1067 },
1068 .f64_type = .{
1069 .ty = Type.initTag(.type),
1070 .val = Value.initTag(.f64_type),
1071 },
1072 .f128_type = .{
1073 .ty = Type.initTag(.type),
1074 .val = Value.initTag(.f128_type),
1075 },
1076 .c_void_type = .{
1077 .ty = Type.initTag(.type),
1078 .val = Value.initTag(.c_void_type),
1079 },
1080 .bool_type = .{
1081 .ty = Type.initTag(.type),
1082 .val = Value.initTag(.bool_type),
1083 },
1084 .void_type = .{
1085 .ty = Type.initTag(.type),
1086 .val = Value.initTag(.void_type),
1087 },
1088 .type_type = .{
1089 .ty = Type.initTag(.type),
1090 .val = Value.initTag(.type_type),
1091 },
1092 .anyerror_type = .{
1093 .ty = Type.initTag(.type),
1094 .val = Value.initTag(.anyerror_type),
1095 },
1096 .comptime_int_type = .{
1097 .ty = Type.initTag(.type),
1098 .val = Value.initTag(.comptime_int_type),
1099 },
1100 .comptime_float_type = .{
1101 .ty = Type.initTag(.type),
1102 .val = Value.initTag(.comptime_float_type),
1103 },
1104 .noreturn_type = .{
1105 .ty = Type.initTag(.type),
1106 .val = Value.initTag(.noreturn_type),
1107 },
1108 .null_type = .{
1109 .ty = Type.initTag(.type),
1110 .val = Value.initTag(.null_type),
1111 },
1112 .undefined_type = .{
1113 .ty = Type.initTag(.type),
1114 .val = Value.initTag(.undefined_type),
1115 },
1116 .fn_noreturn_no_args_type = .{
1117 .ty = Type.initTag(.type),
1118 .val = Value.initTag(.fn_noreturn_no_args_type),
1119 },
1120 .fn_void_no_args_type = .{
1121 .ty = Type.initTag(.type),
1122 .val = Value.initTag(.fn_void_no_args_type),
1123 },
1124 .fn_naked_noreturn_no_args_type = .{
1125 .ty = Type.initTag(.type),
1126 .val = Value.initTag(.fn_naked_noreturn_no_args_type),
1127 },
1128 .fn_ccc_void_no_args_type = .{
1129 .ty = Type.initTag(.type),
1130 .val = Value.initTag(.fn_ccc_void_no_args_type),
1131 },
1132 .single_const_pointer_to_comptime_int_type = .{
1133 .ty = Type.initTag(.type),
1134 .val = Value.initTag(.single_const_pointer_to_comptime_int_type),
1135 },
1136 .const_slice_u8_type = .{
1137 .ty = Type.initTag(.type),
1138 .val = Value.initTag(.const_slice_u8_type),
1139 },
1140 .enum_literal_type = .{
1141 .ty = Type.initTag(.type),
1142 .val = Value.initTag(.enum_literal_type),
1143 },
1144
1145 .undef = .{
1146 .ty = Type.initTag(.@"undefined"),
1147 .val = Value.initTag(.undef),
1148 },
1149 .zero = .{
1150 .ty = Type.initTag(.comptime_int),
1151 .val = Value.initTag(.zero),
1152 },
1153 .zero_usize = .{
1154 .ty = Type.initTag(.usize),
1155 .val = Value.initTag(.zero),
1156 },
1157 .one = .{
1158 .ty = Type.initTag(.comptime_int),
1159 .val = Value.initTag(.one),
1160 },
1161 .one_usize = .{
1162 .ty = Type.initTag(.usize),
1163 .val = Value.initTag(.one),
1164 },
1165 .void_value = .{
1166 .ty = Type.initTag(.void),
1167 .val = Value.initTag(.void_value),
1168 },
1169 .unreachable_value = .{
1170 .ty = Type.initTag(.noreturn),
1171 .val = Value.initTag(.unreachable_value),
1172 },
1173 .null_value = .{
1174 .ty = Type.initTag(.@"null"),
1175 .val = Value.initTag(.null_value),
1176 },
1177 .bool_true = .{
1178 .ty = Type.initTag(.bool),
1179 .val = Value.initTag(.bool_true),
1180 },
1181 .bool_false = .{
1182 .ty = Type.initTag(.bool),
1183 .val = Value.initTag(.bool_false),
1184 },
1185 .empty_struct = .{
1186 .ty = Type.initTag(.empty_struct_literal),
1187 .val = Value.initTag(.empty_struct_value),
1188 },
1189 });
1190 };
1191
1192 /// All instructions have an 8-byte payload, which is contained within
1193 /// this union. `Tag` determines which union field is active, as well as
1194 /// how to interpret the data within.
1195 pub const Data = union {
1196 /// Used for unary operators, with an AST node source location.
1197 un_node: struct {
1198 /// Offset from Decl AST node index.
1199 src_node: i32,
1200 /// The meaning of this operand depends on the corresponding `Tag`.
1201 operand: Ref,
1202
1203 pub fn src(self: @This()) LazySrcLoc {
1204 return .{ .node_offset = self.src_node };
1205 }
1206 },
1207 /// Used for unary operators, with a token source location.
1208 un_tok: struct {
1209 /// Offset from Decl AST token index.
1210 src_tok: ast.TokenIndex,
1211 /// The meaning of this operand depends on the corresponding `Tag`.
1212 operand: Ref,
1213
1214 pub fn src(self: @This()) LazySrcLoc {
1215 return .{ .token_offset = self.src_tok };
1216 }
1217 },
1218 pl_node: struct {
1219 /// Offset from Decl AST node index.
1220 /// `Tag` determines which kind of AST node this points to.
1221 src_node: i32,
1222 /// index into extra.
1223 /// `Tag` determines what lives there.
1224 payload_index: u32,
1225
1226 pub fn src(self: @This()) LazySrcLoc {
1227 return .{ .node_offset = self.src_node };
1228 }
1229 },
1230 bin: Bin,
1231 /// For strings which may contain null bytes.
1232 str: struct {
1233 /// Offset into `string_bytes`.
1234 start: u32,
1235 /// Number of bytes in the string.
1236 len: u32,
1237
1238 pub fn get(self: @This(), code: Zir) []const u8 {
1239 return code.string_bytes[self.start..][0..self.len];
1240 }
1241 },
1242 /// Strings 8 or fewer bytes which may not contain null bytes.
1243 small_str: struct {
1244 bytes: [8]u8,
1245
1246 pub fn get(self: @This()) []const u8 {
1247 const end = for (self.bytes) |byte, i| {
1248 if (byte == 0) break i;
1249 } else self.bytes.len;
1250 return self.bytes[0..end];
1251 }
1252 },
1253 str_tok: struct {
1254 /// Offset into `string_bytes`. Null-terminated.
1255 start: u32,
1256 /// Offset from Decl AST token index.
1257 src_tok: u32,
1258
1259 pub fn get(self: @This(), code: Zir) [:0]const u8 {
1260 return code.nullTerminatedString(self.start);
1261 }
1262
1263 pub fn src(self: @This()) LazySrcLoc {
1264 return .{ .token_offset = self.src_tok };
1265 }
1266 },
1267 /// Offset from Decl AST token index.
1268 tok: ast.TokenIndex,
1269 /// Offset from Decl AST node index.
1270 node: i32,
1271 int: u64,
1272 float: struct {
1273 /// Offset from Decl AST node index.
1274 /// `Tag` determines which kind of AST node this points to.
1275 src_node: i32,
1276 number: f32,
1277
1278 pub fn src(self: @This()) LazySrcLoc {
1279 return .{ .node_offset = self.src_node };
1280 }
1281 },
1282 array_type_sentinel: struct {
1283 len: Ref,
1284 /// index into extra, points to an `ArrayTypeSentinel`
1285 payload_index: u32,
1286 },
1287 ptr_type_simple: struct {
1288 is_allowzero: bool,
1289 is_mutable: bool,
1290 is_volatile: bool,
1291 size: std.builtin.TypeInfo.Pointer.Size,
1292 elem_type: Ref,
1293 },
1294 ptr_type: struct {
1295 flags: packed struct {
1296 is_allowzero: bool,
1297 is_mutable: bool,
1298 is_volatile: bool,
1299 has_sentinel: bool,
1300 has_align: bool,
1301 has_bit_range: bool,
1302 _: u2 = undefined,
1303 },
1304 size: std.builtin.TypeInfo.Pointer.Size,
1305 /// Index into extra. See `PtrType`.
1306 payload_index: u32,
1307 },
1308 int_type: struct {
1309 /// Offset from Decl AST node index.
1310 /// `Tag` determines which kind of AST node this points to.
1311 src_node: i32,
1312 signedness: std.builtin.Signedness,
1313 bit_count: u16,
1314
1315 pub fn src(self: @This()) LazySrcLoc {
1316 return .{ .node_offset = self.src_node };
1317 }
1318 },
1319 bool_br: struct {
1320 lhs: Ref,
1321 /// Points to a `Block`.
1322 payload_index: u32,
1323 },
1324 param_type: struct {
1325 callee: Ref,
1326 param_index: u32,
1327 },
1328 @"unreachable": struct {
1329 /// Offset from Decl AST node index.
1330 /// `Tag` determines which kind of AST node this points to.
1331 src_node: i32,
1332 /// `false`: Not safety checked - the compiler will assume the
1333 /// correctness of this instruction.
1334 /// `true`: In safety-checked modes, this will generate a call
1335 /// to the panic function unless it can be proven unreachable by the compiler.
1336 safety: bool,
1337
1338 pub fn src(self: @This()) LazySrcLoc {
1339 return .{ .node_offset = self.src_node };
1340 }
1341 },
1342 @"break": struct {
1343 block_inst: Index,
1344 operand: Ref,
1345 },
1346 switch_capture: struct {
1347 switch_inst: Index,
1348 prong_index: u32,
1349 },
1350
1351 // Make sure we don't accidentally add a field to make this union
1352 // bigger than expected. Note that in Debug builds, Zig is allowed
1353 // to insert a secret field for safety checks.
1354 comptime {
1355 if (std.builtin.mode != .Debug) {
1356 assert(@sizeOf(Data) == 8);
1357 }
1358 }
1359 };
1360
1361 /// Stored in extra. Trailing is:
1362 /// * output_name: u32 // index into string_bytes (null terminated) if output is present
1363 /// * arg: Ref // for every args_len.
1364 /// * constraint: u32 // index into string_bytes (null terminated) for every args_len.
1365 /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.
1366 pub const Asm = struct {
1367 asm_source: Ref,
1368 return_type: Ref,
1369 /// May be omitted.
1370 output: Ref,
1371 args_len: u32,
1372 clobbers_len: u32,
1373 };
1374
1375 /// This data is stored inside extra, with trailing parameter type indexes
1376 /// according to `param_types_len`.
1377 /// Each param type is a `Ref`.
1378 pub const FnTypeCc = struct {
1379 return_type: Ref,
1380 cc: Ref,
1381 param_types_len: u32,
1382 };
1383
1384 /// This data is stored inside extra, with trailing parameter type indexes
1385 /// according to `param_types_len`.
1386 /// Each param type is a `Ref`.
1387 pub const FnType = struct {
1388 return_type: Ref,
1389 param_types_len: u32,
1390 };
1391
1392 /// This data is stored inside extra, with trailing operands according to `operands_len`.
1393 /// Each operand is a `Ref`.
1394 pub const MultiOp = struct {
1395 operands_len: u32,
1396 };
1397
1398 /// This data is stored inside extra, with trailing operands according to `body_len`.
1399 /// Each operand is an `Index`.
1400 pub const Block = struct {
1401 body_len: u32,
1402 };
1403
1404 /// Stored inside extra, with trailing arguments according to `args_len`.
1405 /// Each argument is a `Ref`.
1406 pub const Call = struct {
1407 callee: Ref,
1408 args_len: u32,
1409 };
1410
1411 /// This data is stored inside extra, with two sets of trailing `Ref`:
1412 /// * 0. the then body, according to `then_body_len`.
1413 /// * 1. the else body, according to `else_body_len`.
1414 pub const CondBr = struct {
1415 condition: Ref,
1416 then_body_len: u32,
1417 else_body_len: u32,
1418 };
1419
1420 /// Stored in extra. Depending on the flags in Data, there will be up to 4
1421 /// trailing Ref fields:
1422 /// 0. sentinel: Ref // if `has_sentinel` flag is set
1423 /// 1. align: Ref // if `has_align` flag is set
1424 /// 2. bit_start: Ref // if `has_bit_range` flag is set
1425 /// 3. bit_end: Ref // if `has_bit_range` flag is set
1426 pub const PtrType = struct {
1427 elem_type: Ref,
1428 };
1429
1430 pub const ArrayTypeSentinel = struct {
1431 sentinel: Ref,
1432 elem_type: Ref,
1433 };
1434
1435 pub const SliceStart = struct {
1436 lhs: Ref,
1437 start: Ref,
1438 };
1439
1440 pub const SliceEnd = struct {
1441 lhs: Ref,
1442 start: Ref,
1443 end: Ref,
1444 };
1445
1446 pub const SliceSentinel = struct {
1447 lhs: Ref,
1448 start: Ref,
1449 end: Ref,
1450 sentinel: Ref,
1451 };
1452
1453 /// The meaning of these operands depends on the corresponding `Tag`.
1454 pub const Bin = struct {
1455 lhs: Ref,
1456 rhs: Ref,
1457 };
1458
1459 /// This form is supported when there are no ranges, and exactly 1 item per block.
1460 /// Depending on zir tag and len fields, extra fields trail
1461 /// this one in the extra array.
1462 /// 0. else_body { // If the tag has "_else" or "_under" in it.
1463 /// body_len: u32,
1464 /// body member Index for every body_len
1465 /// }
1466 /// 1. cases: {
1467 /// item: Ref,
1468 /// body_len: u32,
1469 /// body member Index for every body_len
1470 /// } for every cases_len
1471 pub const SwitchBlock = struct {
1472 operand: Ref,
1473 cases_len: u32,
1474 };
1475
1476 /// This form is required when there exists a block which has more than one item,
1477 /// or a range.
1478 /// Depending on zir tag and len fields, extra fields trail
1479 /// this one in the extra array.
1480 /// 0. else_body { // If the tag has "_else" or "_under" in it.
1481 /// body_len: u32,
1482 /// body member Index for every body_len
1483 /// }
1484 /// 1. scalar_cases: { // for every scalar_cases_len
1485 /// item: Ref,
1486 /// body_len: u32,
1487 /// body member Index for every body_len
1488 /// }
1489 /// 2. multi_cases: { // for every multi_cases_len
1490 /// items_len: u32,
1491 /// ranges_len: u32,
1492 /// body_len: u32,
1493 /// item: Ref // for every items_len
1494 /// ranges: { // for every ranges_len
1495 /// item_first: Ref,
1496 /// item_last: Ref,
1497 /// }
1498 /// body member Index for every body_len
1499 /// }
1500 pub const SwitchBlockMulti = struct {
1501 operand: Ref,
1502 scalar_cases_len: u32,
1503 multi_cases_len: u32,
1504 };
1505
1506 pub const Field = struct {
1507 lhs: Ref,
1508 /// Offset into `string_bytes`.
1509 field_name_start: u32,
1510 };
1511
1512 pub const FieldNamed = struct {
1513 lhs: Ref,
1514 field_name: Ref,
1515 };
1516
1517 pub const As = struct {
1518 dest_type: Ref,
1519 operand: Ref,
1520 };
1521
1522 /// Trailing:
1523 /// 0. inst: Index // for every body_len
1524 /// 1. has_bits: u32 // for every 16 fields
1525 /// - sets of 2 bits:
1526 /// 0b0X: whether corresponding field has an align expression
1527 /// 0bX0: whether corresponding field has a default expression
1528 /// 2. fields: { // for every fields_len
1529 /// field_name: u32,
1530 /// field_type: Ref,
1531 /// align: Ref, // if corresponding bit is set
1532 /// default_value: Ref, // if corresponding bit is set
1533 /// }
1534 pub const StructDecl = struct {
1535 body_len: u32,
1536 fields_len: u32,
1537 };
1538
1539 /// Trailing:
1540 /// 0. inst: Index // for every body_len
1541 /// 1. has_bits: u32 // for every 32 fields
1542 /// - the bit is whether corresponding field has an value expression
1543 /// 2. fields: { // for every fields_len
1544 /// field_name: u32,
1545 /// value: Ref, // if corresponding bit is set
1546 /// }
1547 pub const EnumDecl = struct {
1548 /// Can be `Ref.none`.
1549 tag_type: Ref,
1550 body_len: u32,
1551 fields_len: u32,
1552 };
1553
1554 /// Trailing:
1555 /// 0. has_bits: u32 // for every 10 fields (+1)
1556 /// - first bit is special: set if and only if auto enum tag is enabled.
1557 /// - sets of 3 bits:
1558 /// 0b00X: whether corresponding field has a type expression
1559 /// 0b0X0: whether corresponding field has a align expression
1560 /// 0bX00: whether corresponding field has a tag value expression
1561 /// 1. field_name: u32 // for every field: null terminated string index
1562 /// 2. opt_exprs // Ref for every field for which corresponding bit is set
1563 /// - interleaved. type if present, align if present, tag value if present.
1564 pub const UnionDecl = struct {
1565 /// Can be `Ref.none`.
1566 tag_type: Ref,
1567 fields_len: u32,
1568 };
1569
1570 /// A f128 value, broken up into 4 u32 parts.
1571 pub const Float128 = struct {
1572 piece0: u32,
1573 piece1: u32,
1574 piece2: u32,
1575 piece3: u32,
1576
1577 pub fn get(self: Float128) f128 {
1578 const int_bits = @as(u128, self.piece0) |
1579 (@as(u128, self.piece1) << 32) |
1580 (@as(u128, self.piece2) << 64) |
1581 (@as(u128, self.piece3) << 96);
1582 return @bitCast(f128, int_bits);
1583 }
1584 };
1585
1586 /// Trailing is an item per field.
1587 pub const StructInit = struct {
1588 fields_len: u32,
1589
1590 pub const Item = struct {
1591 /// The `field_type` ZIR instruction for this field init.
1592 field_type: Index,
1593 /// The field init expression to be used as the field value.
1594 init: Ref,
1595 };
1596 };
1597
1598 pub const FieldType = struct {
1599 container_type: Ref,
1600 /// Offset into `string_bytes`, null terminated.
1601 name_start: u32,
1602 };
1603};
1604
1605pub const SpecialProng = enum { none, @"else", under };
1606
1607const Writer = struct {
1608 gpa: *Allocator,
1609 arena: *Allocator,
1610 scope: *Module.Scope,
1611 code: Zir,
1612 indent: usize,
1613 param_count: usize,
1614
1615 fn writeInstToStream(
1616 self: *Writer,
1617 stream: anytype,
1618 inst: Inst.Index,
1619 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1620 const tags = self.code.instructions.items(.tag);
1621 const tag = tags[inst];
1622 try stream.print("= {s}(", .{@tagName(tags[inst])});
1623 switch (tag) {
1624 .array_type,
1625 .as,
1626 .coerce_result_ptr,
1627 .elem_ptr,
1628 .elem_val,
1629 .intcast,
1630 .store,
1631 .store_to_block_ptr,
1632 .store_to_inferred_ptr,
1633 => try self.writeBin(stream, inst),
1634
1635 .alloc,
1636 .alloc_mut,
1637 .indexable_ptr_len,
1638 .bit_not,
1639 .bool_not,
1640 .negate,
1641 .negate_wrap,
1642 .call_none,
1643 .call_none_chkused,
1644 .compile_error,
1645 .load,
1646 .ensure_result_used,
1647 .ensure_result_non_error,
1648 .import,
1649 .ptrtoint,
1650 .ret_node,
1651 .set_eval_branch_quota,
1652 .resolve_inferred_alloc,
1653 .optional_type,
1654 .optional_type_from_ptr_elem,
1655 .optional_payload_safe,
1656 .optional_payload_unsafe,
1657 .optional_payload_safe_ptr,
1658 .optional_payload_unsafe_ptr,
1659 .err_union_payload_safe,
1660 .err_union_payload_unsafe,
1661 .err_union_payload_safe_ptr,
1662 .err_union_payload_unsafe_ptr,
1663 .err_union_code,
1664 .err_union_code_ptr,
1665 .int_to_error,
1666 .error_to_int,
1667 .is_non_null,
1668 .is_null,
1669 .is_non_null_ptr,
1670 .is_null_ptr,
1671 .is_err,
1672 .is_err_ptr,
1673 .typeof,
1674 .typeof_elem,
1675 .struct_init_empty,
1676 .enum_to_int,
1677 .type_info,
1678 .size_of,
1679 .bit_size_of,
1680 => try self.writeUnNode(stream, inst),
1681
1682 .ref,
1683 .ret_tok,
1684 .ret_coerce,
1685 .ensure_err_payload_void,
1686 => try self.writeUnTok(stream, inst),
1687
1688 .bool_br_and,
1689 .bool_br_or,
1690 => try self.writeBoolBr(stream, inst),
1691
1692 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
1693 .param_type => try self.writeParamType(stream, inst),
1694 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
1695 .ptr_type => try self.writePtrType(stream, inst),
1696 .int => try self.writeInt(stream, inst),
1697 .float => try self.writeFloat(stream, inst),
1698 .float128 => try self.writeFloat128(stream, inst),
1699 .str => try self.writeStr(stream, inst),
1700 .elided => try stream.writeAll(")"),
1701 .int_type => try self.writeIntType(stream, inst),
1702
1703 .@"break",
1704 .break_inline,
1705 => try self.writeBreak(stream, inst),
1706
1707 .@"asm",
1708 .asm_volatile,
1709 .elem_ptr_node,
1710 .elem_val_node,
1711 .field_ptr_named,
1712 .field_val_named,
1713 .floatcast,
1714 .slice_start,
1715 .slice_end,
1716 .slice_sentinel,
1717 .union_decl,
1718 .struct_init,
1719 .field_type,
1720 => try self.writePlNode(stream, inst),
1721
1722 .add,
1723 .addwrap,
1724 .array_cat,
1725 .array_mul,
1726 .mul,
1727 .mulwrap,
1728 .sub,
1729 .subwrap,
1730 .bool_and,
1731 .bool_or,
1732 .cmp_lt,
1733 .cmp_lte,
1734 .cmp_eq,
1735 .cmp_gte,
1736 .cmp_gt,
1737 .cmp_neq,
1738 .div,
1739 .has_decl,
1740 .mod_rem,
1741 .shl,
1742 .shr,
1743 .xor,
1744 .store_node,
1745 .error_union_type,
1746 .@"export",
1747 .merge_error_sets,
1748 .bit_and,
1749 .bit_or,
1750 .int_to_enum,
1751 => try self.writePlNodeBin(stream, inst),
1752
1753 .call,
1754 .call_chkused,
1755 .call_compile_time,
1756 => try self.writePlNodeCall(stream, inst),
1757
1758 .block,
1759 .block_inline,
1760 .loop,
1761 .validate_struct_init_ptr,
1762 => try self.writePlNodeBlock(stream, inst),
1763
1764 .condbr,
1765 .condbr_inline,
1766 => try self.writePlNodeCondBr(stream, inst),
1767
1768 .struct_decl,
1769 .struct_decl_packed,
1770 .struct_decl_extern,
1771 => try self.writeStructDecl(stream, inst),
1772
1773 .enum_decl,
1774 .enum_decl_nonexhaustive,
1775 => try self.writeEnumDecl(stream, inst),
1776
1777 .switch_block => try self.writePlNodeSwitchBr(stream, inst, .none),
1778 .switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
1779 .switch_block_under => try self.writePlNodeSwitchBr(stream, inst, .under),
1780 .switch_block_ref => try self.writePlNodeSwitchBr(stream, inst, .none),
1781 .switch_block_ref_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),
1782 .switch_block_ref_under => try self.writePlNodeSwitchBr(stream, inst, .under),
1783
1784 .switch_block_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
1785 .switch_block_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
1786 .switch_block_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
1787 .switch_block_ref_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .none),
1788 .switch_block_ref_else_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .@"else"),
1789 .switch_block_ref_under_multi => try self.writePlNodeSwitchBlockMulti(stream, inst, .under),
1790
1791 .compile_log,
1792 .typeof_peer,
1793 => try self.writePlNodeMultiOp(stream, inst),
1794
1795 .decl_ref,
1796 .decl_val,
1797 => try self.writePlNodeDecl(stream, inst),
1798
1799 .field_ptr,
1800 .field_val,
1801 => try self.writePlNodeField(stream, inst),
1802
1803 .as_node => try self.writeAs(stream, inst),
1804
1805 .breakpoint,
1806 .opaque_decl,
1807 .dbg_stmt_node,
1808 .ret_ptr,
1809 .ret_type,
1810 .repeat,
1811 .repeat_inline,
1812 .alloc_inferred,
1813 .alloc_inferred_mut,
1814 => try self.writeNode(stream, inst),
1815
1816 .error_value,
1817 .enum_literal,
1818 .decl_ref_named,
1819 .decl_val_named,
1820 => try self.writeStrTok(stream, inst),
1821
1822 .fn_type => try self.writeFnType(stream, inst, false),
1823 .fn_type_cc => try self.writeFnTypeCc(stream, inst, false),
1824 .fn_type_var_args => try self.writeFnType(stream, inst, true),
1825 .fn_type_cc_var_args => try self.writeFnTypeCc(stream, inst, true),
1826
1827 .@"unreachable" => try self.writeUnreachable(stream, inst),
1828
1829 .enum_literal_small => try self.writeSmallStr(stream, inst),
1830
1831 .switch_capture,
1832 .switch_capture_ref,
1833 .switch_capture_multi,
1834 .switch_capture_multi_ref,
1835 .switch_capture_else,
1836 .switch_capture_else_ref,
1837 => try self.writeSwitchCapture(stream, inst),
1838
1839 .bitcast,
1840 .bitcast_result_ptr,
1841 => try stream.writeAll("TODO)"),
1842 }
1843 }
1844
1845 fn writeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1846 const inst_data = self.code.instructions.items(.data)[inst].bin;
1847 try self.writeInstRef(stream, inst_data.lhs);
1848 try stream.writeAll(", ");
1849 try self.writeInstRef(stream, inst_data.rhs);
1850 try stream.writeByte(')');
1851 }
1852
1853 fn writeUnNode(
1854 self: *Writer,
1855 stream: anytype,
1856 inst: Inst.Index,
1857 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1858 const inst_data = self.code.instructions.items(.data)[inst].un_node;
1859 try self.writeInstRef(stream, inst_data.operand);
1860 try stream.writeAll(") ");
1861 try self.writeSrc(stream, inst_data.src());
1862 }
1863
1864 fn writeUnTok(
1865 self: *Writer,
1866 stream: anytype,
1867 inst: Inst.Index,
1868 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1869 const inst_data = self.code.instructions.items(.data)[inst].un_tok;
1870 try self.writeInstRef(stream, inst_data.operand);
1871 try stream.writeAll(") ");
1872 try self.writeSrc(stream, inst_data.src());
1873 }
1874
1875 fn writeArrayTypeSentinel(
1876 self: *Writer,
1877 stream: anytype,
1878 inst: Inst.Index,
1879 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1880 const inst_data = self.code.instructions.items(.data)[inst].array_type_sentinel;
1881 try stream.writeAll("TODO)");
1882 }
1883
1884 fn writeParamType(
1885 self: *Writer,
1886 stream: anytype,
1887 inst: Inst.Index,
1888 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1889 const inst_data = self.code.instructions.items(.data)[inst].param_type;
1890 try self.writeInstRef(stream, inst_data.callee);
1891 try stream.print(", {d})", .{inst_data.param_index});
1892 }
1893
1894 fn writePtrTypeSimple(
1895 self: *Writer,
1896 stream: anytype,
1897 inst: Inst.Index,
1898 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1899 const inst_data = self.code.instructions.items(.data)[inst].ptr_type_simple;
1900 const str_allowzero = if (inst_data.is_allowzero) "allowzero, " else "";
1901 const str_const = if (!inst_data.is_mutable) "const, " else "";
1902 const str_volatile = if (inst_data.is_volatile) "volatile, " else "";
1903 try self.writeInstRef(stream, inst_data.elem_type);
1904 try stream.print(", {s}{s}{s}{s})", .{
1905 str_allowzero,
1906 str_const,
1907 str_volatile,
1908 @tagName(inst_data.size),
1909 });
1910 }
1911
1912 fn writePtrType(
1913 self: *Writer,
1914 stream: anytype,
1915 inst: Inst.Index,
1916 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1917 const inst_data = self.code.instructions.items(.data)[inst].ptr_type;
1918 try stream.writeAll("TODO)");
1919 }
1920
1921 fn writeInt(
1922 self: *Writer,
1923 stream: anytype,
1924 inst: Inst.Index,
1925 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1926 const inst_data = self.code.instructions.items(.data)[inst].int;
1927 try stream.print("{d})", .{inst_data});
1928 }
1929
1930 fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1931 const inst_data = self.code.instructions.items(.data)[inst].float;
1932 const src = inst_data.src();
1933 try stream.print("{d}) ", .{inst_data.number});
1934 try self.writeSrc(stream, src);
1935 }
1936
1937 fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1938 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1939 const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data;
1940 const src = inst_data.src();
1941 const number = extra.get();
1942 // TODO improve std.format to be able to print f128 values
1943 try stream.print("{d}) ", .{@floatCast(f64, number)});
1944 try self.writeSrc(stream, src);
1945 }
1946
1947 fn writeStr(
1948 self: *Writer,
1949 stream: anytype,
1950 inst: Inst.Index,
1951 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1952 const inst_data = self.code.instructions.items(.data)[inst].str;
1953 const str = inst_data.get(self.code);
1954 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
1955 }
1956
1957 fn writePlNode(
1958 self: *Writer,
1959 stream: anytype,
1960 inst: Inst.Index,
1961 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1962 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1963 try stream.writeAll("TODO) ");
1964 try self.writeSrc(stream, inst_data.src());
1965 }
1966
1967 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1968 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1969 const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data;
1970 try self.writeInstRef(stream, extra.lhs);
1971 try stream.writeAll(", ");
1972 try self.writeInstRef(stream, extra.rhs);
1973 try stream.writeAll(") ");
1974 try self.writeSrc(stream, inst_data.src());
1975 }
1976
1977 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1978 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1979 const extra = self.code.extraData(Inst.Call, inst_data.payload_index);
1980 const args = self.code.refSlice(extra.end, extra.data.args_len);
1981
1982 try self.writeInstRef(stream, extra.data.callee);
1983 try stream.writeAll(", [");
1984 for (args) |arg, i| {
1985 if (i != 0) try stream.writeAll(", ");
1986 try self.writeInstRef(stream, arg);
1987 }
1988 try stream.writeAll("]) ");
1989 try self.writeSrc(stream, inst_data.src());
1990 }
1991
1992 fn writePlNodeBlock(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1993 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1994 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
1995 const body = self.code.extra[extra.end..][0..extra.data.body_len];
1996 try stream.writeAll("{\n");
1997 self.indent += 2;
1998 try self.writeBody(stream, body);
1999 self.indent -= 2;
2000 try stream.writeByteNTimes(' ', self.indent);
2001 try stream.writeAll("}) ");
2002 try self.writeSrc(stream, inst_data.src());
2003 }
2004
2005 fn writePlNodeCondBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2006 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2007 const extra = self.code.extraData(Inst.CondBr, inst_data.payload_index);
2008 const then_body = self.code.extra[extra.end..][0..extra.data.then_body_len];
2009 const else_body = self.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
2010 try self.writeInstRef(stream, extra.data.condition);
2011 try stream.writeAll(", {\n");
2012 self.indent += 2;
2013 try self.writeBody(stream, then_body);
2014 self.indent -= 2;
2015 try stream.writeByteNTimes(' ', self.indent);
2016 try stream.writeAll("}, {\n");
2017 self.indent += 2;
2018 try self.writeBody(stream, else_body);
2019 self.indent -= 2;
2020 try stream.writeByteNTimes(' ', self.indent);
2021 try stream.writeAll("}) ");
2022 try self.writeSrc(stream, inst_data.src());
2023 }
2024
2025 fn writeStructDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2026 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2027 const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index);
2028 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2029 const fields_len = extra.data.fields_len;
2030
2031 if (fields_len == 0) {
2032 assert(body.len == 0);
2033 try stream.writeAll("{}, {}) ");
2034 try self.writeSrc(stream, inst_data.src());
2035 return;
2036 }
2037
2038 try stream.writeAll("{\n");
2039 self.indent += 2;
2040 try self.writeBody(stream, body);
2041
2042 try stream.writeByteNTimes(' ', self.indent - 2);
2043 try stream.writeAll("}, {\n");
2044
2045 const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
2046 const body_end = extra.end + body.len;
2047 var extra_index: usize = body_end + bit_bags_count;
2048 var bit_bag_index: usize = body_end;
2049 var cur_bit_bag: u32 = undefined;
2050 var field_i: u32 = 0;
2051 while (field_i < fields_len) : (field_i += 1) {
2052 if (field_i % 16 == 0) {
2053 cur_bit_bag = self.code.extra[bit_bag_index];
2054 bit_bag_index += 1;
2055 }
2056 const has_align = @truncate(u1, cur_bit_bag) != 0;
2057 cur_bit_bag >>= 1;
2058 const has_default = @truncate(u1, cur_bit_bag) != 0;
2059 cur_bit_bag >>= 1;
2060
2061 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2062 extra_index += 1;
2063 const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2064 extra_index += 1;
2065
2066 try stream.writeByteNTimes(' ', self.indent);
2067 try stream.print("{}: ", .{std.zig.fmtId(field_name)});
2068 try self.writeInstRef(stream, field_type);
2069
2070 if (has_align) {
2071 const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2072 extra_index += 1;
2073
2074 try stream.writeAll(" align(");
2075 try self.writeInstRef(stream, align_ref);
2076 try stream.writeAll(")");
2077 }
2078 if (has_default) {
2079 const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2080 extra_index += 1;
2081
2082 try stream.writeAll(" = ");
2083 try self.writeInstRef(stream, default_ref);
2084 }
2085 try stream.writeAll(",\n");
2086 }
2087
2088 self.indent -= 2;
2089 try stream.writeByteNTimes(' ', self.indent);
2090 try stream.writeAll("}) ");
2091 try self.writeSrc(stream, inst_data.src());
2092 }
2093
2094 fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2095 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2096 const extra = self.code.extraData(Inst.EnumDecl, inst_data.payload_index);
2097 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2098 const fields_len = extra.data.fields_len;
2099 const tag_ty_ref = extra.data.tag_type;
2100
2101 if (tag_ty_ref != .none) {
2102 try self.writeInstRef(stream, tag_ty_ref);
2103 try stream.writeAll(", ");
2104 }
2105
2106 if (fields_len == 0) {
2107 assert(body.len == 0);
2108 try stream.writeAll("{}, {}) ");
2109 try self.writeSrc(stream, inst_data.src());
2110 return;
2111 }
2112
2113 try stream.writeAll("{\n");
2114 self.indent += 2;
2115 try self.writeBody(stream, body);
2116
2117 try stream.writeByteNTimes(' ', self.indent - 2);
2118 try stream.writeAll("}, {\n");
2119
2120 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
2121 const body_end = extra.end + body.len;
2122 var extra_index: usize = body_end + bit_bags_count;
2123 var bit_bag_index: usize = body_end;
2124 var cur_bit_bag: u32 = undefined;
2125 var field_i: u32 = 0;
2126 while (field_i < fields_len) : (field_i += 1) {
2127 if (field_i % 32 == 0) {
2128 cur_bit_bag = self.code.extra[bit_bag_index];
2129 bit_bag_index += 1;
2130 }
2131 const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
2132 cur_bit_bag >>= 1;
2133
2134 const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
2135 extra_index += 1;
2136
2137 try stream.writeByteNTimes(' ', self.indent);
2138 try stream.print("{}", .{std.zig.fmtId(field_name)});
2139
2140 if (has_tag_value) {
2141 const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2142 extra_index += 1;
2143
2144 try stream.writeAll(" = ");
2145 try self.writeInstRef(stream, tag_value_ref);
2146 }
2147 try stream.writeAll(",\n");
2148 }
2149
2150 self.indent -= 2;
2151 try stream.writeByteNTimes(' ', self.indent);
2152 try stream.writeAll("}) ");
2153 try self.writeSrc(stream, inst_data.src());
2154 }
2155
2156 fn writePlNodeSwitchBr(
2157 self: *Writer,
2158 stream: anytype,
2159 inst: Inst.Index,
2160 special_prong: SpecialProng,
2161 ) !void {
2162 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2163 const extra = self.code.extraData(Inst.SwitchBlock, inst_data.payload_index);
2164 const special: struct {
2165 body: []const Inst.Index,
2166 end: usize,
2167 } = switch (special_prong) {
2168 .none => .{ .body = &.{}, .end = extra.end },
2169 .under, .@"else" => blk: {
2170 const body_len = self.code.extra[extra.end];
2171 const extra_body_start = extra.end + 1;
2172 break :blk .{
2173 .body = self.code.extra[extra_body_start..][0..body_len],
2174 .end = extra_body_start + body_len,
2175 };
2176 },
2177 };
2178
2179 try self.writeInstRef(stream, extra.data.operand);
2180
2181 if (special.body.len != 0) {
2182 const prong_name = switch (special_prong) {
2183 .@"else" => "else",
2184 .under => "_",
2185 else => unreachable,
2186 };
2187 try stream.print(", {s} => {{\n", .{prong_name});
2188 self.indent += 2;
2189 try self.writeBody(stream, special.body);
2190 self.indent -= 2;
2191 try stream.writeByteNTimes(' ', self.indent);
2192 try stream.writeAll("}");
2193 }
2194
2195 var extra_index: usize = special.end;
2196 {
2197 var scalar_i: usize = 0;
2198 while (scalar_i < extra.data.cases_len) : (scalar_i += 1) {
2199 const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2200 extra_index += 1;
2201 const body_len = self.code.extra[extra_index];
2202 extra_index += 1;
2203 const body = self.code.extra[extra_index..][0..body_len];
2204 extra_index += body_len;
2205
2206 try stream.writeAll(", ");
2207 try self.writeInstRef(stream, item_ref);
2208 try stream.writeAll(" => {\n");
2209 self.indent += 2;
2210 try self.writeBody(stream, body);
2211 self.indent -= 2;
2212 try stream.writeByteNTimes(' ', self.indent);
2213 try stream.writeAll("}");
2214 }
2215 }
2216 try stream.writeAll(") ");
2217 try self.writeSrc(stream, inst_data.src());
2218 }
2219
2220 fn writePlNodeSwitchBlockMulti(
2221 self: *Writer,
2222 stream: anytype,
2223 inst: Inst.Index,
2224 special_prong: SpecialProng,
2225 ) !void {
2226 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2227 const extra = self.code.extraData(Inst.SwitchBlockMulti, inst_data.payload_index);
2228 const special: struct {
2229 body: []const Inst.Index,
2230 end: usize,
2231 } = switch (special_prong) {
2232 .none => .{ .body = &.{}, .end = extra.end },
2233 .under, .@"else" => blk: {
2234 const body_len = self.code.extra[extra.end];
2235 const extra_body_start = extra.end + 1;
2236 break :blk .{
2237 .body = self.code.extra[extra_body_start..][0..body_len],
2238 .end = extra_body_start + body_len,
2239 };
2240 },
2241 };
2242
2243 try self.writeInstRef(stream, extra.data.operand);
2244
2245 if (special.body.len != 0) {
2246 const prong_name = switch (special_prong) {
2247 .@"else" => "else",
2248 .under => "_",
2249 else => unreachable,
2250 };
2251 try stream.print(", {s} => {{\n", .{prong_name});
2252 self.indent += 2;
2253 try self.writeBody(stream, special.body);
2254 self.indent -= 2;
2255 try stream.writeByteNTimes(' ', self.indent);
2256 try stream.writeAll("}");
2257 }
2258
2259 var extra_index: usize = special.end;
2260 {
2261 var scalar_i: usize = 0;
2262 while (scalar_i < extra.data.scalar_cases_len) : (scalar_i += 1) {
2263 const item_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2264 extra_index += 1;
2265 const body_len = self.code.extra[extra_index];
2266 extra_index += 1;
2267 const body = self.code.extra[extra_index..][0..body_len];
2268 extra_index += body_len;
2269
2270 try stream.writeAll(", ");
2271 try self.writeInstRef(stream, item_ref);
2272 try stream.writeAll(" => {\n");
2273 self.indent += 2;
2274 try self.writeBody(stream, body);
2275 self.indent -= 2;
2276 try stream.writeByteNTimes(' ', self.indent);
2277 try stream.writeAll("}");
2278 }
2279 }
2280 {
2281 var multi_i: usize = 0;
2282 while (multi_i < extra.data.multi_cases_len) : (multi_i += 1) {
2283 const items_len = self.code.extra[extra_index];
2284 extra_index += 1;
2285 const ranges_len = self.code.extra[extra_index];
2286 extra_index += 1;
2287 const body_len = self.code.extra[extra_index];
2288 extra_index += 1;
2289 const items = self.code.refSlice(extra_index, items_len);
2290 extra_index += items_len;
2291
2292 for (items) |item_ref| {
2293 try stream.writeAll(", ");
2294 try self.writeInstRef(stream, item_ref);
2295 }
2296
2297 var range_i: usize = 0;
2298 while (range_i < ranges_len) : (range_i += 1) {
2299 const item_first = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2300 extra_index += 1;
2301 const item_last = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
2302 extra_index += 1;
2303
2304 try stream.writeAll(", ");
2305 try self.writeInstRef(stream, item_first);
2306 try stream.writeAll("...");
2307 try self.writeInstRef(stream, item_last);
2308 }
2309
2310 const body = self.code.extra[extra_index..][0..body_len];
2311 extra_index += body_len;
2312 try stream.writeAll(" => {\n");
2313 self.indent += 2;
2314 try self.writeBody(stream, body);
2315 self.indent -= 2;
2316 try stream.writeByteNTimes(' ', self.indent);
2317 try stream.writeAll("}");
2318 }
2319 }
2320 try stream.writeAll(") ");
2321 try self.writeSrc(stream, inst_data.src());
2322 }
2323
2324 fn writePlNodeMultiOp(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2325 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2326 const extra = self.code.extraData(Inst.MultiOp, inst_data.payload_index);
2327 const operands = self.code.refSlice(extra.end, extra.data.operands_len);
2328
2329 for (operands) |operand, i| {
2330 if (i != 0) try stream.writeAll(", ");
2331 try self.writeInstRef(stream, operand);
2332 }
2333 try stream.writeAll(") ");
2334 try self.writeSrc(stream, inst_data.src());
2335 }
2336
2337 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2338 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2339 const owner_decl = self.scope.ownerDecl().?;
2340 const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key;
2341 try stream.print("{s}) ", .{decl.name});
2342 try self.writeSrc(stream, inst_data.src());
2343 }
2344
2345 fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2346 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2347 const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data;
2348 const name = self.code.nullTerminatedString(extra.field_name_start);
2349 try self.writeInstRef(stream, extra.lhs);
2350 try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(name)});
2351 try self.writeSrc(stream, inst_data.src());
2352 }
2353
2354 fn writeAs(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2355 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2356 const extra = self.code.extraData(Inst.As, inst_data.payload_index).data;
2357 try self.writeInstRef(stream, extra.dest_type);
2358 try stream.writeAll(", ");
2359 try self.writeInstRef(stream, extra.operand);
2360 try stream.writeAll(") ");
2361 try self.writeSrc(stream, inst_data.src());
2362 }
2363
2364 fn writeNode(
2365 self: *Writer,
2366 stream: anytype,
2367 inst: Inst.Index,
2368 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2369 const src_node = self.code.instructions.items(.data)[inst].node;
2370 const src: LazySrcLoc = .{ .node_offset = src_node };
2371 try stream.writeAll(") ");
2372 try self.writeSrc(stream, src);
2373 }
2374
2375 fn writeStrTok(
2376 self: *Writer,
2377 stream: anytype,
2378 inst: Inst.Index,
2379 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2380 const inst_data = self.code.instructions.items(.data)[inst].str_tok;
2381 const str = inst_data.get(self.code);
2382 try stream.print("\"{}\") ", .{std.zig.fmtEscapes(str)});
2383 try self.writeSrc(stream, inst_data.src());
2384 }
2385
2386 fn writeFnType(
2387 self: *Writer,
2388 stream: anytype,
2389 inst: Inst.Index,
2390 var_args: bool,
2391 ) !void {
2392 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2393 const src = inst_data.src();
2394 const extra = self.code.extraData(Inst.FnType, inst_data.payload_index);
2395 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
2396 return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, .none, src);
2397 }
2398
2399 fn writeFnTypeCc(
2400 self: *Writer,
2401 stream: anytype,
2402 inst: Inst.Index,
2403 var_args: bool,
2404 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2405 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2406 const src = inst_data.src();
2407 const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index);
2408 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
2409 const cc = extra.data.cc;
2410 return self.writeFnTypeCommon(stream, param_types, extra.data.return_type, var_args, cc, src);
2411 }
2412
2413 fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2414 const inst_data = self.code.instructions.items(.data)[inst].bool_br;
2415 const extra = self.code.extraData(Inst.Block, inst_data.payload_index);
2416 const body = self.code.extra[extra.end..][0..extra.data.body_len];
2417 try self.writeInstRef(stream, inst_data.lhs);
2418 try stream.writeAll(", {\n");
2419 self.indent += 2;
2420 try self.writeBody(stream, body);
2421 self.indent -= 2;
2422 try stream.writeByteNTimes(' ', self.indent);
2423 try stream.writeAll("})");
2424 }
2425
2426 fn writeIntType(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2427 const int_type = self.code.instructions.items(.data)[inst].int_type;
2428 const prefix: u8 = switch (int_type.signedness) {
2429 .signed => 'i',
2430 .unsigned => 'u',
2431 };
2432 try stream.print("{c}{d}) ", .{ prefix, int_type.bit_count });
2433 try self.writeSrc(stream, int_type.src());
2434 }
2435
2436 fn writeBreak(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2437 const inst_data = self.code.instructions.items(.data)[inst].@"break";
2438
2439 try self.writeInstIndex(stream, inst_data.block_inst);
2440 try stream.writeAll(", ");
2441 try self.writeInstRef(stream, inst_data.operand);
2442 try stream.writeAll(")");
2443 }
2444
2445 fn writeUnreachable(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2446 const inst_data = self.code.instructions.items(.data)[inst].@"unreachable";
2447 const safety_str = if (inst_data.safety) "safe" else "unsafe";
2448 try stream.print("{s}) ", .{safety_str});
2449 try self.writeSrc(stream, inst_data.src());
2450 }
2451
2452 fn writeFnTypeCommon(
2453 self: *Writer,
2454 stream: anytype,
2455 param_types: []const Inst.Ref,
2456 ret_ty: Inst.Ref,
2457 var_args: bool,
2458 cc: Inst.Ref,
2459 src: LazySrcLoc,
2460 ) !void {
2461 try stream.writeAll("[");
2462 for (param_types) |param_type, i| {
2463 if (i != 0) try stream.writeAll(", ");
2464 try self.writeInstRef(stream, param_type);
2465 }
2466 try stream.writeAll("], ");
2467 try self.writeInstRef(stream, ret_ty);
2468 try self.writeOptionalInstRef(stream, ", cc=", cc);
2469 try self.writeFlag(stream, ", var_args", var_args);
2470 try stream.writeAll(") ");
2471 try self.writeSrc(stream, src);
2472 }
2473
2474 fn writeSmallStr(
2475 self: *Writer,
2476 stream: anytype,
2477 inst: Inst.Index,
2478 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
2479 const str = self.code.instructions.items(.data)[inst].small_str.get();
2480 try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
2481 }
2482
2483 fn writeSwitchCapture(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2484 const inst_data = self.code.instructions.items(.data)[inst].switch_capture;
2485 try self.writeInstIndex(stream, inst_data.switch_inst);
2486 try stream.print(", {d})", .{inst_data.prong_index});
2487 }
2488
2489 fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void {
2490 var i: usize = @enumToInt(ref);
2491
2492 if (i < Inst.Ref.typed_value_map.len) {
2493 return stream.print("@{}", .{ref});
2494 }
2495 i -= Inst.Ref.typed_value_map.len;
2496
2497 if (i < self.param_count) {
2498 return stream.print("${d}", .{i});
2499 }
2500 i -= self.param_count;
2501
2502 return self.writeInstIndex(stream, @intCast(Inst.Index, i));
2503 }
2504
2505 fn writeInstIndex(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2506 return stream.print("%{d}", .{inst});
2507 }
2508
2509 fn writeOptionalInstRef(
2510 self: *Writer,
2511 stream: anytype,
2512 prefix: []const u8,
2513 inst: Inst.Ref,
2514 ) !void {
2515 if (inst == .none) return;
2516 try stream.writeAll(prefix);
2517 try self.writeInstRef(stream, inst);
2518 }
2519
2520 fn writeFlag(
2521 self: *Writer,
2522 stream: anytype,
2523 name: []const u8,
2524 flag: bool,
2525 ) !void {
2526 if (!flag) return;
2527 try stream.writeAll(name);
2528 }
2529
2530 fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void {
2531 const tree = self.scope.tree();
2532 const src_loc = src.toSrcLoc(self.scope);
2533 const abs_byte_off = try src_loc.byteOffset();
2534 const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off);
2535 try stream.print("{s}:{d}:{d}", .{
2536 @tagName(src), delta_line.line + 1, delta_line.column + 1,
2537 });
2538 }
2539
2540 fn writeBody(self: *Writer, stream: anytype, body: []const Inst.Index) !void {
2541 for (body) |inst| {
2542 try stream.writeByteNTimes(' ', self.indent);
2543 try stream.print("%{d} ", .{inst});
2544 try self.writeInstToStream(stream, inst);
2545 try stream.writeByte('\n');
2546 }
2547 }
2548};