authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-24 15:24:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-24 15:36:23-07:00
log180dae419630114b56f2ccd3a80d72c38bd8cad8
tree7197650ca92db5ece9416b1fb1da99886cb6bc6e
parent0c601965ab6600fdaf5be3c017176a6871413026

stage2: further cleanups regarding zir.Inst.Ref

* Introduce helper functions on Module.WipZirCode and zir.Code * Move some logic around * re-introduce ref_start_index * prefer usize for local variables + `@intCast` at the end. Empirically this is easier to optimize. * Avoid using mem.{bytesAsSlice,sliceAsBytes} because it incurs an unnecessary multiplication/division which may cause problems for the optimizer. * Use a regular enum, not packed, for `Ref`. Memory layout is guaranteed for enums which specify their tag type. Packed enums have ABI alignment of 1 byte which is too small.

5 files changed, 94 insertions(+), 93 deletions(-)

BRANCH_TODO+1
...@@ -34,3 +34,4 @@ Performance optimizations to look into:...@@ -34,3 +34,4 @@ Performance optimizations to look into:
34 * enum literals can use small strings34 * enum literals can use small strings
35 * string literals can use small strings35 * string literals can use small strings
36 * don't need the Sema coercion on condbr condition, it's done with result locations36 * don't need the Sema coercion on condbr condition, it's done with result locations
37 * remove unreachable_value
src/Module.zig+44-21
...@@ -1013,7 +1013,7 @@ pub const Scope = struct {...@@ -1013,7 +1013,7 @@ pub const Scope = struct {
1013 .cc = args.cc,1013 .cc = args.cc,
1014 .param_types_len = @intCast(u32, args.param_types.len),1014 .param_types_len = @intCast(u32, args.param_types.len),
1015 });1015 });
1016 gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args.param_types)));1016 gz.zir_code.appendRefsAssumeCapacity(args.param_types);
10171017
1018 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);1018 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1019 gz.zir_code.instructions.appendAssumeCapacity(.{1019 gz.zir_code.instructions.appendAssumeCapacity(.{
...@@ -1024,7 +1024,7 @@ pub const Scope = struct {...@@ -1024,7 +1024,7 @@ pub const Scope = struct {
1024 } },1024 } },
1025 });1025 });
1026 gz.instructions.appendAssumeCapacity(new_index);1026 gz.instructions.appendAssumeCapacity(new_index);
1027 return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);1027 return gz.zir_code.indexToRef(new_index);
1028 }1028 }
10291029
1030 pub fn addFnType(1030 pub fn addFnType(
...@@ -1043,7 +1043,7 @@ pub const Scope = struct {...@@ -1043,7 +1043,7 @@ pub const Scope = struct {
1043 const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.FnType{1043 const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.FnType{
1044 .param_types_len = @intCast(u32, param_types.len),1044 .param_types_len = @intCast(u32, param_types.len),
1045 });1045 });
1046 gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(param_types)));1046 gz.zir_code.appendRefsAssumeCapacity(param_types);
10471047
1048 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);1048 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1049 gz.zir_code.instructions.appendAssumeCapacity(.{1049 gz.zir_code.instructions.appendAssumeCapacity(.{
...@@ -1054,7 +1054,7 @@ pub const Scope = struct {...@@ -1054,7 +1054,7 @@ pub const Scope = struct {
1054 } },1054 } },
1055 });1055 });
1056 gz.instructions.appendAssumeCapacity(new_index);1056 gz.instructions.appendAssumeCapacity(new_index);
1057 return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);1057 return gz.zir_code.indexToRef(new_index);
1058 }1058 }
10591059
1060 pub fn addCall(1060 pub fn addCall(
...@@ -1077,7 +1077,7 @@ pub const Scope = struct {...@@ -1077,7 +1077,7 @@ pub const Scope = struct {
1077 .callee = callee,1077 .callee = callee,
1078 .args_len = @intCast(u32, args.len),1078 .args_len = @intCast(u32, args.len),
1079 });1079 });
1080 gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args)));1080 gz.zir_code.appendRefsAssumeCapacity(args);
10811081
1082 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);1082 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1083 gz.zir_code.instructions.appendAssumeCapacity(.{1083 gz.zir_code.instructions.appendAssumeCapacity(.{
...@@ -1088,7 +1088,7 @@ pub const Scope = struct {...@@ -1088,7 +1088,7 @@ pub const Scope = struct {
1088 } },1088 } },
1089 });1089 });
1090 gz.instructions.appendAssumeCapacity(new_index);1090 gz.instructions.appendAssumeCapacity(new_index);
1091 return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);1091 return gz.zir_code.indexToRef(new_index);
1092 }1092 }
10931093
1094 /// Note that this returns a `zir.Inst.Index` not a ref.1094 /// Note that this returns a `zir.Inst.Index` not a ref.
...@@ -1160,7 +1160,7 @@ pub const Scope = struct {...@@ -1160,7 +1160,7 @@ pub const Scope = struct {
1160 } },1160 } },
1161 });1161 });
1162 gz.instructions.appendAssumeCapacity(new_index);1162 gz.instructions.appendAssumeCapacity(new_index);
1163 return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);1163 return gz.zir_code.indexToRef(new_index);
1164 }1164 }
11651165
1166 pub fn addArrayTypeSentinel(1166 pub fn addArrayTypeSentinel(
...@@ -1186,7 +1186,7 @@ pub const Scope = struct {...@@ -1186,7 +1186,7 @@ pub const Scope = struct {
1186 } },1186 } },
1187 });1187 });
1188 gz.instructions.appendAssumeCapacity(new_index);1188 gz.instructions.appendAssumeCapacity(new_index);
1189 return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);1189 return gz.zir_code.indexToRef(new_index);
1190 }1190 }
11911191
1192 pub fn addUnTok(1192 pub fn addUnTok(
...@@ -1317,7 +1317,7 @@ pub const Scope = struct {...@@ -1317,7 +1317,7 @@ pub const Scope = struct {
1317 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);1317 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1318 gz.zir_code.instructions.appendAssumeCapacity(inst);1318 gz.zir_code.instructions.appendAssumeCapacity(inst);
1319 gz.instructions.appendAssumeCapacity(new_index);1319 gz.instructions.appendAssumeCapacity(new_index);
1320 return zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);1320 return gz.zir_code.indexToRef(new_index);
1321 }1321 }
1322 };1322 };
13231323
...@@ -1366,9 +1366,9 @@ pub const WipZirCode = struct {...@@ -1366,9 +1366,9 @@ pub const WipZirCode = struct {
1366 instructions: std.MultiArrayList(zir.Inst) = .{},1366 instructions: std.MultiArrayList(zir.Inst) = .{},
1367 string_bytes: std.ArrayListUnmanaged(u8) = .{},1367 string_bytes: std.ArrayListUnmanaged(u8) = .{},
1368 extra: std.ArrayListUnmanaged(u32) = .{},1368 extra: std.ArrayListUnmanaged(u32) = .{},
1369 /// We need to keep track of this count in order to convert between1369 /// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
1370 /// `zir.Inst.Ref` and `zir.Inst.Index` types.1370 /// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
1371 param_count: u32 = 0,1371 ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,
1372 decl: *Decl,1372 decl: *Decl,
1373 gpa: *Allocator,1373 gpa: *Allocator,
1374 arena: *Allocator,1374 arena: *Allocator,
...@@ -1386,20 +1386,43 @@ pub const WipZirCode = struct {...@@ -1386,20 +1386,43 @@ pub const WipZirCode = struct {
1386 wzc.extra.appendAssumeCapacity(switch (field.field_type) {1386 wzc.extra.appendAssumeCapacity(switch (field.field_type) {
1387 u32 => @field(extra, field.name),1387 u32 => @field(extra, field.name),
1388 zir.Inst.Ref => @enumToInt(@field(extra, field.name)),1388 zir.Inst.Ref => @enumToInt(@field(extra, field.name)),
1389 else => unreachable,1389 else => @compileError("bad field type"),
1390 });1390 });
1391 }1391 }
1392 return result;1392 return result;
1393 }1393 }
13941394
1395 pub fn refIsNoReturn(wzc: WipZirCode, zir_inst_ref: zir.Inst.Ref) bool {1395 pub fn appendRefs(wzc: *WipZirCode, refs: []const zir.Inst.Ref) !void {
1396 if (zir_inst_ref == .unreachable_value) return true;1396 const coerced = @bitCast([]const u32, refs);
1397 if (zir_inst_ref.toIndex(wzc.param_count)) |zir_inst| {1397 return wzc.extra.appendSlice(wzc.gpa, coerced);
1398 return wzc.instructions.items(.tag)[zir_inst].isNoReturn();1398 }
1399
1400 pub fn appendRefsAssumeCapacity(wzc: *WipZirCode, refs: []const zir.Inst.Ref) void {
1401 const coerced = @bitCast([]const u32, refs);
1402 wzc.extra.appendSliceAssumeCapacity(coerced);
1403 }
1404
1405 pub fn refIsNoReturn(wzc: WipZirCode, inst_ref: zir.Inst.Ref) bool {
1406 if (inst_ref == .unreachable_value) return true;
1407 if (wzc.refToIndex(inst_ref)) |inst_index| {
1408 return wzc.instructions.items(.tag)[inst_index].isNoReturn();
1399 }1409 }
1400 return false;1410 return false;
1401 }1411 }
14021412
1413 pub fn indexToRef(wzc: WipZirCode, inst: zir.Inst.Index) zir.Inst.Ref {
1414 return @intToEnum(zir.Inst.Ref, wzc.ref_start_index + inst);
1415 }
1416
1417 pub fn refToIndex(wzc: WipZirCode, inst: zir.Inst.Ref) ?zir.Inst.Index {
1418 const ref_int = @enumToInt(inst);
1419 if (ref_int >= wzc.ref_start_index) {
1420 return ref_int - wzc.ref_start_index;
1421 } else {
1422 return null;
1423 }
1424 }
1425
1403 pub fn deinit(wzc: *WipZirCode) void {1426 pub fn deinit(wzc: *WipZirCode) void {
1404 wzc.instructions.deinit(wzc.gpa);1427 wzc.instructions.deinit(wzc.gpa);
1405 wzc.extra.deinit(wzc.gpa);1428 wzc.extra.deinit(wzc.gpa);
...@@ -2075,7 +2098,7 @@ fn astgenAndSemaFn(...@@ -2075,7 +2098,7 @@ fn astgenAndSemaFn(
2075 // The AST params array does not contain anytype and ... parameters.2098 // The AST params array does not contain anytype and ... parameters.
2076 // We must iterate to count how many param types to allocate.2099 // We must iterate to count how many param types to allocate.
2077 const param_count = blk: {2100 const param_count = blk: {
2078 var count: u32 = 0;2101 var count: usize = 0;
2079 var it = fn_proto.iterate(tree);2102 var it = fn_proto.iterate(tree);
2080 while (it.next()) |param| {2103 while (it.next()) |param| {
2081 if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;2104 if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break;
...@@ -2297,7 +2320,7 @@ fn astgenAndSemaFn(...@@ -2297,7 +2320,7 @@ fn astgenAndSemaFn(
2297 .decl = decl,2320 .decl = decl,
2298 .arena = &decl_arena.allocator,2321 .arena = &decl_arena.allocator,
2299 .gpa = mod.gpa,2322 .gpa = mod.gpa,
2300 .param_count = param_count,2323 .ref_start_index = @intCast(u32, zir.Inst.Ref.typed_value_map.len + param_count),
2301 };2324 };
2302 defer wip_zir_code.deinit();2325 defer wip_zir_code.deinit();
23032326
...@@ -2314,7 +2337,7 @@ fn astgenAndSemaFn(...@@ -2314,7 +2337,7 @@ fn astgenAndSemaFn(
2314 try wip_zir_code.extra.ensureCapacity(mod.gpa, param_count);2337 try wip_zir_code.extra.ensureCapacity(mod.gpa, param_count);
23152338
2316 var params_scope = &gen_scope.base;2339 var params_scope = &gen_scope.base;
2317 var i: u32 = 0;2340 var i: usize = 0;
2318 var it = fn_proto.iterate(tree);2341 var it = fn_proto.iterate(tree);
2319 while (it.next()) |param| : (i += 1) {2342 while (it.next()) |param| : (i += 1) {
2320 const name_token = param.name_token.?;2343 const name_token = param.name_token.?;
...@@ -2325,7 +2348,7 @@ fn astgenAndSemaFn(...@@ -2325,7 +2348,7 @@ fn astgenAndSemaFn(
2325 .gen_zir = &gen_scope,2348 .gen_zir = &gen_scope,
2326 .name = param_name,2349 .name = param_name,
2327 // Implicit const list first, then implicit arg list.2350 // Implicit const list first, then implicit arg list.
2328 .inst = zir.Inst.Ref.fromParam(i),2351 .inst = @intToEnum(zir.Inst.Ref, @intCast(u32, zir.Inst.Ref.typed_value_map.len + i)),
2329 .src = decl.tokSrcLoc(name_token),2352 .src = decl.tokSrcLoc(name_token),
2330 };2353 };
2331 params_scope = &sub_scope.base;2354 params_scope = &sub_scope.base;
src/Sema.zig+22-17
...@@ -300,18 +300,28 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde...@@ -300,18 +300,28 @@ pub fn analyzeBody(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Inde
300}300}
301301
302/// TODO when we rework TZIR memory layout, this function will no longer have a possible error.302/// TODO when we rework TZIR memory layout, this function will no longer have a possible error.
303/// Until then we allocate memory for a new, mutable `ir.Inst` to match what TZIR expects.
304pub fn resolveInst(sema: *Sema, zir_ref: zir.Inst.Ref) error{OutOfMemory}!*ir.Inst {303pub fn resolveInst(sema: *Sema, zir_ref: zir.Inst.Ref) error{OutOfMemory}!*ir.Inst {
305 if (zir_ref.toTypedValue()) |typed_value| {304 var i: usize = @enumToInt(zir_ref);
306 return sema.mod.constInst(sema.arena, .unneeded, typed_value);305
306 // First section of indexes correspond to a set number of constant values.
307 if (i < zir.Inst.Ref.typed_value_map.len) {
308 // TODO when we rework TZIR memory layout, this function can be as simple as:
309 // if (zir_ref < zir.const_inst_list.len + sema.param_count)
310 // return zir_ref;
311 // Until then we allocate memory for a new, mutable `ir.Inst` to match what
312 // TZIR expects.
313 return sema.mod.constInst(sema.arena, .unneeded, zir.Inst.Ref.typed_value_map[i]);
307 }314 }
315 i -= zir.Inst.Ref.typed_value_map.len;
308316
309 const param_count = @intCast(u32, sema.param_inst_list.len);317 // Next section of indexes correspond to function parameters, if any.
310 if (zir_ref.toParam(param_count)) |param| {318 if (i < sema.param_inst_list.len) {
311 return sema.param_inst_list[param];319 return sema.param_inst_list[i];
312 }320 }
321 i -= sema.param_inst_list.len;
313322
314 return sema.inst_map[zir_ref.toIndex(param_count).?];323 // Finally, the last section of indexes refers to the map of ZIR=>TZIR.
324 return sema.inst_map[i];
315}325}
316326
317fn resolveConstString(327fn resolveConstString(
...@@ -753,8 +763,7 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr...@@ -753,8 +763,7 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr
753763
754 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;764 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
755 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);765 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
756 const raw_args = sema.code.extra[extra.end..][0..extra.data.operands_len];766 const args = sema.code.refSlice(extra.end, extra.data.operands_len);
757 const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args));
758767
759 for (args) |arg_ref, i| {768 for (args) |arg_ref, i| {
760 if (i != 0) try writer.print(", ", .{});769 if (i != 0) try writer.print(", ", .{});
...@@ -1105,8 +1114,7 @@ fn zirCall(...@@ -1105,8 +1114,7 @@ fn zirCall(
1105 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };1114 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
1106 const call_src = inst_data.src();1115 const call_src = inst_data.src();
1107 const extra = sema.code.extraData(zir.Inst.Call, inst_data.payload_index);1116 const extra = sema.code.extraData(zir.Inst.Call, inst_data.payload_index);
1108 const raw_args = sema.code.extra[extra.end..][0..extra.data.args_len];1117 const args = sema.code.refSlice(extra.end, extra.data.args_len);
1109 const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args));
11101118
1111 return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args);1119 return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, ensure_result_used, args);
1112}1120}
...@@ -1733,8 +1741,7 @@ fn zirFnType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: b...@@ -1733,8 +1741,7 @@ fn zirFnType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: b
17331741
1734 const inst_data = sema.code.instructions.items(.data)[inst].fn_type;1742 const inst_data = sema.code.instructions.items(.data)[inst].fn_type;
1735 const extra = sema.code.extraData(zir.Inst.FnType, inst_data.payload_index);1743 const extra = sema.code.extraData(zir.Inst.FnType, inst_data.payload_index);
1736 const raw_param_types = sema.code.extra[extra.end..][0..extra.data.param_types_len];1744 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
1737 const param_types = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_param_types));
17381745
1739 return sema.fnTypeCommon(1746 return sema.fnTypeCommon(
1740 block,1747 block,
...@@ -1752,8 +1759,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args:...@@ -1752,8 +1759,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args:
17521759
1753 const inst_data = sema.code.instructions.items(.data)[inst].fn_type;1760 const inst_data = sema.code.instructions.items(.data)[inst].fn_type;
1754 const extra = sema.code.extraData(zir.Inst.FnTypeCc, inst_data.payload_index);1761 const extra = sema.code.extraData(zir.Inst.FnTypeCc, inst_data.payload_index);
1755 const raw_param_types = sema.code.extra[extra.end..][0..extra.data.param_types_len];1762 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
1756 const param_types = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_param_types));
17571763
1758 const cc_tv = try sema.resolveInstConst(block, .todo, extra.data.cc);1764 const cc_tv = try sema.resolveInstConst(block, .todo, extra.data.cc);
1759 // TODO once we're capable of importing and analyzing decls from1765 // TODO once we're capable of importing and analyzing decls from
...@@ -2768,8 +2774,7 @@ fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr...@@ -2768,8 +2774,7 @@ fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr
2768 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;2774 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2769 const src = inst_data.src();2775 const src = inst_data.src();
2770 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);2776 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
2771 const raw_args = sema.code.extra[extra.end..][0..extra.data.operands_len];2777 const args = sema.code.refSlice(extra.end, extra.data.operands_len);
2772 const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args));
27732778
2774 const inst_list = try sema.gpa.alloc(*ir.Inst, extra.data.operands_len);2779 const inst_list = try sema.gpa.alloc(*ir.Inst, extra.data.operands_len);
2775 defer sema.gpa.free(inst_list);2780 defer sema.gpa.free(inst_list);
src/astgen.zig+11-11
...@@ -926,7 +926,7 @@ fn labeledBlockExpr(...@@ -926,7 +926,7 @@ fn labeledBlockExpr(
926 // would be better still to elide the ones that are in this list.926 // would be better still to elide the ones that are in this list.
927 try block_scope.setBlockBody(block_inst);927 try block_scope.setBlockBody(block_inst);
928928
929 return zir.Inst.Ref.fromIndex(block_inst, gz.zir_code.param_count);929 return gz.zir_code.indexToRef(block_inst);
930 },930 },
931 .break_operand => {931 .break_operand => {
932 // All break operands are values that did not use the result location pointer.932 // All break operands are values that did not use the result location pointer.
...@@ -939,7 +939,7 @@ fn labeledBlockExpr(...@@ -939,7 +939,7 @@ fn labeledBlockExpr(
939 // would be better still to elide the ones that are in this list.939 // would be better still to elide the ones that are in this list.
940 }940 }
941 try block_scope.setBlockBody(block_inst);941 try block_scope.setBlockBody(block_inst);
942 const block_ref = zir.Inst.Ref.fromIndex(block_inst, gz.zir_code.param_count);942 const block_ref = gz.zir_code.indexToRef(block_inst);
943 switch (rl) {943 switch (rl) {
944 .ref => return block_ref,944 .ref => return block_ref,
945 else => return rvalue(mod, parent_scope, rl, block_ref, block_node),945 else => return rvalue(mod, parent_scope, rl, block_ref, block_node),
...@@ -991,7 +991,7 @@ fn blockExprStmts(...@@ -991,7 +991,7 @@ fn blockExprStmts(
991 // We need to emit an error if the result is not `noreturn` or `void`, but991 // We need to emit an error if the result is not `noreturn` or `void`, but
992 // we want to avoid adding the ZIR instruction if possible for performance.992 // we want to avoid adding the ZIR instruction if possible for performance.
993 const maybe_unused_result = try expr(mod, scope, .none, statement);993 const maybe_unused_result = try expr(mod, scope, .none, statement);
994 const elide_check = if (maybe_unused_result.toIndex(gz.zir_code.param_count)) |inst| b: {994 const elide_check = if (gz.zir_code.refToIndex(maybe_unused_result)) |inst| b: {
995 // Note that this array becomes invalid after appending more items to it995 // Note that this array becomes invalid after appending more items to it
996 // in the above while loop.996 // in the above while loop.
997 const zir_tags = gz.zir_code.instructions.items(.tag);997 const zir_tags = gz.zir_code.instructions.items(.tag);
...@@ -1292,7 +1292,7 @@ fn varDecl(...@@ -1292,7 +1292,7 @@ fn varDecl(
1292 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;1292 const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2;
1293 try parent_zir.ensureCapacity(mod.gpa, expected_len);1293 try parent_zir.ensureCapacity(mod.gpa, expected_len);
1294 for (init_scope.instructions.items) |src_inst| {1294 for (init_scope.instructions.items) |src_inst| {
1295 if (zir.Inst.Ref.fromIndex(src_inst, wzc.param_count) == init_scope.rl_ptr) continue;1295 if (wzc.indexToRef(src_inst) == init_scope.rl_ptr) continue;
1296 if (zir_tags[src_inst] == .store_to_block_ptr) {1296 if (zir_tags[src_inst] == .store_to_block_ptr) {
1297 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;1297 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue;
1298 }1298 }
...@@ -1525,7 +1525,7 @@ fn ptrType(...@@ -1525,7 +1525,7 @@ fn ptrType(
1525 }1525 }
15261526
1527 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);1527 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1528 const result = zir.Inst.Ref.fromIndex(new_index, gz.zir_code.param_count);1528 const result = gz.zir_code.indexToRef(new_index);
1529 gz.zir_code.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{1529 gz.zir_code.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{
1530 .ptr_type = .{1530 .ptr_type = .{
1531 .flags = .{1531 .flags = .{
...@@ -1782,7 +1782,7 @@ fn finishThenElseBlock(...@@ -1782,7 +1782,7 @@ fn finishThenElseBlock(
1782 }1782 }
1783 assert(!strat.elide_store_to_block_ptr_instructions);1783 assert(!strat.elide_store_to_block_ptr_instructions);
1784 try setCondBrPayload(condbr, cond, then_scope, else_scope);1784 try setCondBrPayload(condbr, cond, then_scope, else_scope);
1785 return zir.Inst.Ref.fromIndex(main_block, wzc.param_count);1785 return wzc.indexToRef(main_block);
1786 },1786 },
1787 .break_operand => {1787 .break_operand => {
1788 if (!wzc.refIsNoReturn(then_result)) {1788 if (!wzc.refIsNoReturn(then_result)) {
...@@ -1818,7 +1818,7 @@ fn finishThenElseBlock(...@@ -1818,7 +1818,7 @@ fn finishThenElseBlock(
1818 } else {1818 } else {
1819 try setCondBrPayload(condbr, cond, then_scope, else_scope);1819 try setCondBrPayload(condbr, cond, then_scope, else_scope);
1820 }1820 }
1821 const block_ref = zir.Inst.Ref.fromIndex(main_block, wzc.param_count);1821 const block_ref = wzc.indexToRef(main_block);
1822 switch (rl) {1822 switch (rl) {
1823 .ref => return block_ref,1823 .ref => return block_ref,
1824 else => return rvalue(mod, parent_scope, rl, block_ref, node),1824 else => return rvalue(mod, parent_scope, rl, block_ref, node),
...@@ -1981,7 +1981,7 @@ fn boolBinOp(...@@ -1981,7 +1981,7 @@ fn boolBinOp(
1981 _ = try rhs_scope.addUnNode(.break_flat, rhs, node);1981 _ = try rhs_scope.addUnNode(.break_flat, rhs, node);
1982 try rhs_scope.setBoolBrBody(bool_br);1982 try rhs_scope.setBoolBrBody(bool_br);
19831983
1984 const block_ref = zir.Inst.Ref.fromIndex(bool_br, gz.zir_code.param_count);1984 const block_ref = gz.zir_code.indexToRef(bool_br);
1985 return rvalue(mod, scope, rl, block_ref, node);1985 return rvalue(mod, scope, rl, block_ref, node);
1986}1986}
19871987
...@@ -3092,7 +3092,7 @@ fn asmExpr(...@@ -3092,7 +3092,7 @@ fn asmExpr(
30923092
3093 try gz.zir_code.extra.ensureCapacity(mod.gpa, gz.zir_code.extra.items.len +3093 try gz.zir_code.extra.ensureCapacity(mod.gpa, gz.zir_code.extra.items.len +
3094 args.len + constraints.len);3094 args.len + constraints.len);
3095 gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args)));3095 gz.zir_code.appendRefsAssumeCapacity(args);
3096 gz.zir_code.extra.appendSliceAssumeCapacity(constraints);3096 gz.zir_code.extra.appendSliceAssumeCapacity(constraints);
30973097
3098 return rvalue(mod, scope, rl, result, node);3098 return rvalue(mod, scope, rl, result, node);
...@@ -3164,7 +3164,7 @@ fn asRlPtr(...@@ -3164,7 +3164,7 @@ fn asRlPtr(
3164 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;3164 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;
3165 try parent_zir.ensureCapacity(mod.gpa, expected_len);3165 try parent_zir.ensureCapacity(mod.gpa, expected_len);
3166 for (as_scope.instructions.items) |src_inst| {3166 for (as_scope.instructions.items) |src_inst| {
3167 if (zir.Inst.Ref.fromIndex(src_inst, wzc.param_count) == as_scope.rl_ptr) continue;3167 if (wzc.indexToRef(src_inst) == as_scope.rl_ptr) continue;
3168 if (zir_tags[src_inst] == .store_to_block_ptr) {3168 if (zir_tags[src_inst] == .store_to_block_ptr) {
3169 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;3169 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
3170 }3170 }
...@@ -3256,7 +3256,7 @@ fn typeOf(...@@ -3256,7 +3256,7 @@ fn typeOf(
3256 }3256 }
32573257
3258 const result = try gz.addPlNode(.typeof_peer, node, zir.Inst.MultiOp{ .operands_len = @intCast(u32, params.len) });3258 const result = try gz.addPlNode(.typeof_peer, node, zir.Inst.MultiOp{ .operands_len = @intCast(u32, params.len) });
3259 try gz.zir_code.extra.appendSlice(gz.zir_code.gpa, mem.bytesAsSlice(u32, mem.sliceAsBytes(items)));3259 try gz.zir_code.appendRefs(items);
32603260
3261 return rvalue(mod, scope, rl, result, node);3261 return rvalue(mod, scope, rl, result, node);
3262}3262}
src/zir.zig+16-44
...@@ -70,6 +70,11 @@ pub const Code = struct {...@@ -70,6 +70,11 @@ pub const Code = struct {
70 return code.string_bytes[index..end :0];70 return code.string_bytes[index..end :0];
71 }71 }
7272
73 pub fn refSlice(code: Code, start: usize, len: usize) []Inst.Ref {
74 const raw_slice = code.extra[start..][0..len];
75 return @bitCast([]Inst.Ref, raw_slice);
76 }
77
73 pub fn deinit(code: *Code, gpa: *Allocator) void {78 pub fn deinit(code: *Code, gpa: *Allocator) void {
74 code.instructions.deinit(gpa);79 code.instructions.deinit(gpa);
75 gpa.free(code.string_bytes);80 gpa.free(code.string_bytes);
...@@ -767,16 +772,17 @@ pub const Inst = struct {...@@ -767,16 +772,17 @@ pub const Inst = struct {
767 /// of the current function or a ZIR instruction.772 /// of the current function or a ZIR instruction.
768 ///773 ///
769 /// The first values after the the last tag refer to parameters which may be774 /// The first values after the the last tag refer to parameters which may be
770 /// derived by subtracting typed_value_count.775 /// derived by subtracting typed_value_map.len.
771 ///776 ///
772 /// All further values refer to ZIR instructions which may be derived by777 /// All further values refer to ZIR instructions which may be derived by
773 /// subtracting typed_value_count and the number of parameters.778 /// subtracting typed_value_map.len and the number of parameters.
774 ///779 ///
775 /// When adding a tag to this enum, consider adding a corresponding entry to780 /// When adding a tag to this enum, consider adding a corresponding entry to
776 /// `simple_types` in astgen.781 /// `simple_types` in astgen.
777 ///782 ///
778 /// This is packed so that it is safe to cast between `[]u32` and `[]Ref`.783 /// The tag type is specified so that it is safe to bitcast between `[]u32`
779 pub const Ref = packed enum(u32) {784 /// and `[]Ref`.
785 pub const Ref = enum(u32) {
780 /// This Ref does not correspond to any ZIR instruction or constant786 /// This Ref does not correspond to any ZIR instruction or constant
781 /// value and may instead be used as a sentinel to indicate null.787 /// value and may instead be used as a sentinel to indicate null.
782 none,788 none,
...@@ -841,8 +847,7 @@ pub const Inst = struct {...@@ -841,8 +847,7 @@ pub const Inst = struct {
841847
842 _,848 _,
843849
844 pub const typed_value_count = @as(u32, typed_value_map.len);850 pub const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{
845 const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{
846 .none = undefined,851 .none = undefined,
847852
848 .u8_type = .{853 .u8_type = .{
...@@ -1039,36 +1044,6 @@ pub const Inst = struct {...@@ -1039,36 +1044,6 @@ pub const Inst = struct {
1039 .val = Value.initTag(.bool_false),1044 .val = Value.initTag(.bool_false),
1040 },1045 },
1041 });1046 });
1042
1043 pub fn fromParam(param: u32) Ref {
1044 return @intToEnum(Ref, typed_value_count + param);
1045 }
1046
1047 pub fn fromIndex(index: Index, param_count: u32) Ref {
1048 return @intToEnum(Ref, typed_value_count + param_count + index);
1049 }
1050
1051 pub fn toTypedValue(ref: Ref) ?TypedValue {
1052 assert(ref != .none);
1053 if (@enumToInt(ref) >= typed_value_count) return null;
1054 return typed_value_map[@enumToInt(ref)];
1055 }
1056
1057 pub fn toParam(ref: Ref, param_count: u32) ?u32 {
1058 assert(ref != .none);
1059 if (@enumToInt(ref) < typed_value_count or
1060 @enumToInt(ref) >= typed_value_count + param_count)
1061 {
1062 return null;
1063 }
1064 return @enumToInt(ref) - typed_value_count;
1065 }
1066
1067 pub fn toIndex(ref: Ref, param_count: u32) ?Index {
1068 assert(ref != .none);
1069 if (@enumToInt(ref) < typed_value_count + param_count) return null;
1070 return @enumToInt(ref) - typed_value_count - param_count;
1071 }
1072 };1047 };
10731048
1074 /// All instructions have an 8-byte payload, which is contained within1049 /// All instructions have an 8-byte payload, which is contained within
...@@ -1672,8 +1647,7 @@ const Writer = struct {...@@ -1672,8 +1647,7 @@ const Writer = struct {
1672 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {1647 fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1673 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1648 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1674 const extra = self.code.extraData(Inst.Call, inst_data.payload_index);1649 const extra = self.code.extraData(Inst.Call, inst_data.payload_index);
1675 const raw_args = self.code.extra[extra.end..][0..extra.data.args_len];1650 const args = self.code.refSlice(extra.end, extra.data.args_len);
1676 const args = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_args));
16771651
1678 try self.writeInstRef(stream, extra.data.callee);1652 try self.writeInstRef(stream, extra.data.callee);
1679 try stream.writeAll(", [");1653 try stream.writeAll(", [");
...@@ -1767,8 +1741,7 @@ const Writer = struct {...@@ -1767,8 +1741,7 @@ const Writer = struct {
1767 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {1741 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1768 const inst_data = self.code.instructions.items(.data)[inst].fn_type;1742 const inst_data = self.code.instructions.items(.data)[inst].fn_type;
1769 const extra = self.code.extraData(Inst.FnType, inst_data.payload_index);1743 const extra = self.code.extraData(Inst.FnType, inst_data.payload_index);
1770 const raw_param_types = self.code.extra[extra.end..][0..extra.data.param_types_len];1744 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
1771 const param_types = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_param_types));
1772 return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, .none);1745 return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, .none);
1773 }1746 }
17741747
...@@ -1793,8 +1766,7 @@ const Writer = struct {...@@ -1793,8 +1766,7 @@ const Writer = struct {
1793 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {1766 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1794 const inst_data = self.code.instructions.items(.data)[inst].fn_type;1767 const inst_data = self.code.instructions.items(.data)[inst].fn_type;
1795 const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index);1768 const extra = self.code.extraData(Inst.FnTypeCc, inst_data.payload_index);
1796 const raw_param_types = self.code.extra[extra.end..][0..extra.data.param_types_len];1769 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);
1797 const param_types = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_param_types));
1798 const cc = extra.data.cc;1770 const cc = extra.data.cc;
1799 return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);1771 return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc);
1800 }1772 }
...@@ -1864,10 +1836,10 @@ const Writer = struct {...@@ -1864,10 +1836,10 @@ const Writer = struct {
1864 fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void {1836 fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void {
1865 var i: usize = @enumToInt(ref);1837 var i: usize = @enumToInt(ref);
18661838
1867 if (i < Inst.Ref.typed_value_count) {1839 if (i < Inst.Ref.typed_value_map.len) {
1868 return stream.print("@{}", .{ref});1840 return stream.print("@{}", .{ref});
1869 }1841 }
1870 i -= Inst.Ref.typed_value_count;1842 i -= Inst.Ref.typed_value_map.len;
18711843
1872 if (i < self.param_count) {1844 if (i < self.param_count) {
1873 return stream.print("${d}", .{i});1845 return stream.print("${d}", .{i});