| author | |
| committer | |
| log | 180dae419630114b56f2ccd3a80d72c38bd8cad8 |
| tree | 7197650ca92db5ece9416b1fb1da99886cb6bc6e |
| parent | 0c601965ab6600fdaf5be3c017176a6871413026 |
* 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 | 34 | * enum literals can use small strings |
| 35 | 35 | * string literals can use small strings |
| 36 | 36 | * 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 | 1013 | .cc = args.cc, |
| 1014 | 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); | |
| 1017 | 1017 | |
| 1018 | 1018 | const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); |
| 1019 | 1019 | gz.zir_code.instructions.appendAssumeCapacity(.{ |
| ... | ... | @@ -1024,7 +1024,7 @@ pub const Scope = struct { |
| 1024 | 1024 | } }, |
| 1025 | 1025 | }); |
| 1026 | 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 | } |
| 1029 | 1029 | |
| 1030 | 1030 | pub fn addFnType( |
| ... | ... | @@ -1043,7 +1043,7 @@ pub const Scope = struct { |
| 1043 | 1043 | const payload_index = gz.zir_code.addExtraAssumeCapacity(zir.Inst.FnType{ |
| 1044 | 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); | |
| 1047 | 1047 | |
| 1048 | 1048 | const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); |
| 1049 | 1049 | gz.zir_code.instructions.appendAssumeCapacity(.{ |
| ... | ... | @@ -1054,7 +1054,7 @@ pub const Scope = struct { |
| 1054 | 1054 | } }, |
| 1055 | 1055 | }); |
| 1056 | 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 | } |
| 1059 | 1059 | |
| 1060 | 1060 | pub fn addCall( |
| ... | ... | @@ -1077,7 +1077,7 @@ pub const Scope = struct { |
| 1077 | 1077 | .callee = callee, |
| 1078 | 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); | |
| 1081 | 1081 | |
| 1082 | 1082 | const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); |
| 1083 | 1083 | gz.zir_code.instructions.appendAssumeCapacity(.{ |
| ... | ... | @@ -1088,7 +1088,7 @@ pub const Scope = struct { |
| 1088 | 1088 | } }, |
| 1089 | 1089 | }); |
| 1090 | 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 | } |
| 1093 | 1093 | |
| 1094 | 1094 | /// Note that this returns a `zir.Inst.Index` not a ref. |
| ... | ... | @@ -1160,7 +1160,7 @@ pub const Scope = struct { |
| 1160 | 1160 | } }, |
| 1161 | 1161 | }); |
| 1162 | 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 | } |
| 1165 | 1165 | |
| 1166 | 1166 | pub fn addArrayTypeSentinel( |
| ... | ... | @@ -1186,7 +1186,7 @@ pub const Scope = struct { |
| 1186 | 1186 | } }, |
| 1187 | 1187 | }); |
| 1188 | 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 | } |
| 1191 | 1191 | |
| 1192 | 1192 | pub fn addUnTok( |
| ... | ... | @@ -1317,7 +1317,7 @@ pub const Scope = struct { |
| 1317 | 1317 | const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len); |
| 1318 | 1318 | gz.zir_code.instructions.appendAssumeCapacity(inst); |
| 1319 | 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 | }; |
| 1323 | 1323 | |
| ... | ... | @@ -1366,9 +1366,9 @@ pub const WipZirCode = struct { |
| 1366 | 1366 | instructions: std.MultiArrayList(zir.Inst) = .{}, |
| 1367 | 1367 | string_bytes: std.ArrayListUnmanaged(u8) = .{}, |
| 1368 | 1368 | extra: std.ArrayListUnmanaged(u32) = .{}, |
| 1369 | /// We need to keep track of this count in order to convert between | |
| 1370 | /// `zir.Inst.Ref` and `zir.Inst.Index` types. | |
| 1371 | param_count: u32 = 0, | |
| 1369 | /// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert | |
| 1370 | /// to `zir.Inst.Index`. The default here is correct if there are 0 parameters. | |
| 1371 | ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len, | |
| 1372 | 1372 | decl: *Decl, |
| 1373 | 1373 | gpa: *Allocator, |
| 1374 | 1374 | arena: *Allocator, |
| ... | ... | @@ -1386,20 +1386,43 @@ pub const WipZirCode = struct { |
| 1386 | 1386 | wzc.extra.appendAssumeCapacity(switch (field.field_type) { |
| 1387 | 1387 | u32 => @field(extra, field.name), |
| 1388 | 1388 | zir.Inst.Ref => @enumToInt(@field(extra, field.name)), |
| 1389 | else => unreachable, | |
| 1389 | else => @compileError("bad field type"), | |
| 1390 | 1390 | }); |
| 1391 | 1391 | } |
| 1392 | 1392 | return result; |
| 1393 | 1393 | } |
| 1394 | 1394 | |
| 1395 | pub fn refIsNoReturn(wzc: WipZirCode, zir_inst_ref: zir.Inst.Ref) bool { | |
| 1396 | if (zir_inst_ref == .unreachable_value) return true; | |
| 1397 | if (zir_inst_ref.toIndex(wzc.param_count)) |zir_inst| { | |
| 1398 | return wzc.instructions.items(.tag)[zir_inst].isNoReturn(); | |
| 1395 | pub fn appendRefs(wzc: *WipZirCode, refs: []const zir.Inst.Ref) !void { | |
| 1396 | const coerced = @bitCast([]const u32, refs); | |
| 1397 | return wzc.extra.appendSlice(wzc.gpa, coerced); | |
| 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 | 1410 | return false; |
| 1401 | 1411 | } |
| 1402 | 1412 | |
| 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 | 1426 | pub fn deinit(wzc: *WipZirCode) void { |
| 1404 | 1427 | wzc.instructions.deinit(wzc.gpa); |
| 1405 | 1428 | wzc.extra.deinit(wzc.gpa); |
| ... | ... | @@ -2075,7 +2098,7 @@ fn astgenAndSemaFn( |
| 2075 | 2098 | // The AST params array does not contain anytype and ... parameters. |
| 2076 | 2099 | // We must iterate to count how many param types to allocate. |
| 2077 | 2100 | const param_count = blk: { |
| 2078 | var count: u32 = 0; | |
| 2101 | var count: usize = 0; | |
| 2079 | 2102 | var it = fn_proto.iterate(tree); |
| 2080 | 2103 | while (it.next()) |param| { |
| 2081 | 2104 | if (param.anytype_ellipsis3) |some| if (token_tags[some] == .ellipsis3) break; |
| ... | ... | @@ -2297,7 +2320,7 @@ fn astgenAndSemaFn( |
| 2297 | 2320 | .decl = decl, |
| 2298 | 2321 | .arena = &decl_arena.allocator, |
| 2299 | 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 | 2325 | defer wip_zir_code.deinit(); |
| 2303 | 2326 | |
| ... | ... | @@ -2314,7 +2337,7 @@ fn astgenAndSemaFn( |
| 2314 | 2337 | try wip_zir_code.extra.ensureCapacity(mod.gpa, param_count); |
| 2315 | 2338 | |
| 2316 | 2339 | var params_scope = &gen_scope.base; |
| 2317 | var i: u32 = 0; | |
| 2340 | var i: usize = 0; | |
| 2318 | 2341 | var it = fn_proto.iterate(tree); |
| 2319 | 2342 | while (it.next()) |param| : (i += 1) { |
| 2320 | 2343 | const name_token = param.name_token.?; |
| ... | ... | @@ -2325,7 +2348,7 @@ fn astgenAndSemaFn( |
| 2325 | 2348 | .gen_zir = &gen_scope, |
| 2326 | 2349 | .name = param_name, |
| 2327 | 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 | 2352 | .src = decl.tokSrcLoc(name_token), |
| 2330 | 2353 | }; |
| 2331 | 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 | 300 | } |
| 301 | 301 | |
| 302 | 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. | |
| 304 | 303 | pub fn resolveInst(sema: *Sema, zir_ref: zir.Inst.Ref) error{OutOfMemory}!*ir.Inst { |
| 305 | if (zir_ref.toTypedValue()) |typed_value| { | |
| 306 | return sema.mod.constInst(sema.arena, .unneeded, typed_value); | |
| 304 | var i: usize = @enumToInt(zir_ref); | |
| 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; | |
| 308 | 316 | |
| 309 | const param_count = @intCast(u32, sema.param_inst_list.len); | |
| 310 | if (zir_ref.toParam(param_count)) |param| { | |
| 311 | return sema.param_inst_list[param]; | |
| 317 | // Next section of indexes correspond to function parameters, if any. | |
| 318 | if (i < sema.param_inst_list.len) { | |
| 319 | return sema.param_inst_list[i]; | |
| 312 | 320 | } |
| 321 | i -= sema.param_inst_list.len; | |
| 313 | 322 | |
| 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 | } |
| 316 | 326 | |
| 317 | 327 | fn resolveConstString( |
| ... | ... | @@ -753,8 +763,7 @@ fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerEr |
| 753 | 763 | |
| 754 | 764 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 755 | 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]; | |
| 757 | const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args)); | |
| 766 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); | |
| 758 | 767 | |
| 759 | 768 | for (args) |arg_ref, i| { |
| 760 | 769 | if (i != 0) try writer.print(", ", .{}); |
| ... | ... | @@ -1105,8 +1114,7 @@ fn zirCall( |
| 1105 | 1114 | const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node }; |
| 1106 | 1115 | const call_src = inst_data.src(); |
| 1107 | 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]; | |
| 1109 | const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args)); | |
| 1117 | const args = sema.code.refSlice(extra.end, extra.data.args_len); | |
| 1110 | 1118 | |
| 1111 | 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 | 1741 | |
| 1734 | 1742 | const inst_data = sema.code.instructions.items(.data)[inst].fn_type; |
| 1735 | 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]; | |
| 1737 | const param_types = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_param_types)); | |
| 1744 | const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len); | |
| 1738 | 1745 | |
| 1739 | 1746 | return sema.fnTypeCommon( |
| 1740 | 1747 | block, |
| ... | ... | @@ -1752,8 +1759,7 @@ fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index, var_args: |
| 1752 | 1759 | |
| 1753 | 1760 | const inst_data = sema.code.instructions.items(.data)[inst].fn_type; |
| 1754 | 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]; | |
| 1756 | const param_types = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_param_types)); | |
| 1762 | const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len); | |
| 1757 | 1763 | |
| 1758 | 1764 | const cc_tv = try sema.resolveInstConst(block, .todo, extra.data.cc); |
| 1759 | 1765 | // 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 | 2774 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 2769 | 2775 | const src = inst_data.src(); |
| 2770 | 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]; | |
| 2772 | const args = mem.bytesAsSlice(zir.Inst.Ref, mem.sliceAsBytes(raw_args)); | |
| 2777 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); | |
| 2773 | 2778 | |
| 2774 | 2779 | const inst_list = try sema.gpa.alloc(*ir.Inst, extra.data.operands_len); |
| 2775 | 2780 | defer sema.gpa.free(inst_list); |
src/astgen.zig+11-11| ... | ... | @@ -926,7 +926,7 @@ fn labeledBlockExpr( |
| 926 | 926 | // would be better still to elide the ones that are in this list. |
| 927 | 927 | try block_scope.setBlockBody(block_inst); |
| 928 | 928 | |
| 929 | return zir.Inst.Ref.fromIndex(block_inst, gz.zir_code.param_count); | |
| 929 | return gz.zir_code.indexToRef(block_inst); | |
| 930 | 930 | }, |
| 931 | 931 | .break_operand => { |
| 932 | 932 | // All break operands are values that did not use the result location pointer. |
| ... | ... | @@ -939,7 +939,7 @@ fn labeledBlockExpr( |
| 939 | 939 | // would be better still to elide the ones that are in this list. |
| 940 | 940 | } |
| 941 | 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 | 943 | switch (rl) { |
| 944 | 944 | .ref => return block_ref, |
| 945 | 945 | else => return rvalue(mod, parent_scope, rl, block_ref, block_node), |
| ... | ... | @@ -991,7 +991,7 @@ fn blockExprStmts( |
| 991 | 991 | // We need to emit an error if the result is not `noreturn` or `void`, but |
| 992 | 992 | // we want to avoid adding the ZIR instruction if possible for performance. |
| 993 | 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 | 995 | // Note that this array becomes invalid after appending more items to it |
| 996 | 996 | // in the above while loop. |
| 997 | 997 | const zir_tags = gz.zir_code.instructions.items(.tag); |
| ... | ... | @@ -1292,7 +1292,7 @@ fn varDecl( |
| 1292 | 1292 | const expected_len = parent_zir.items.len + init_scope.instructions.items.len - 2; |
| 1293 | 1293 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| 1294 | 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 | 1296 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 1297 | 1297 | if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) continue; |
| 1298 | 1298 | } |
| ... | ... | @@ -1525,7 +1525,7 @@ fn ptrType( |
| 1525 | 1525 | } |
| 1526 | 1526 | |
| 1527 | 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 | 1529 | gz.zir_code.instructions.appendAssumeCapacity(.{ .tag = .ptr_type, .data = .{ |
| 1530 | 1530 | .ptr_type = .{ |
| 1531 | 1531 | .flags = .{ |
| ... | ... | @@ -1782,7 +1782,7 @@ fn finishThenElseBlock( |
| 1782 | 1782 | } |
| 1783 | 1783 | assert(!strat.elide_store_to_block_ptr_instructions); |
| 1784 | 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 | 1787 | .break_operand => { |
| 1788 | 1788 | if (!wzc.refIsNoReturn(then_result)) { |
| ... | ... | @@ -1818,7 +1818,7 @@ fn finishThenElseBlock( |
| 1818 | 1818 | } else { |
| 1819 | 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 | 1822 | switch (rl) { |
| 1823 | 1823 | .ref => return block_ref, |
| 1824 | 1824 | else => return rvalue(mod, parent_scope, rl, block_ref, node), |
| ... | ... | @@ -1981,7 +1981,7 @@ fn boolBinOp( |
| 1981 | 1981 | _ = try rhs_scope.addUnNode(.break_flat, rhs, node); |
| 1982 | 1982 | try rhs_scope.setBoolBrBody(bool_br); |
| 1983 | 1983 | |
| 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 | 1985 | return rvalue(mod, scope, rl, block_ref, node); |
| 1986 | 1986 | } |
| 1987 | 1987 | |
| ... | ... | @@ -3092,7 +3092,7 @@ fn asmExpr( |
| 3092 | 3092 | |
| 3093 | 3093 | try gz.zir_code.extra.ensureCapacity(mod.gpa, gz.zir_code.extra.items.len + |
| 3094 | 3094 | args.len + constraints.len); |
| 3095 | gz.zir_code.extra.appendSliceAssumeCapacity(mem.bytesAsSlice(u32, mem.sliceAsBytes(args))); | |
| 3095 | gz.zir_code.appendRefsAssumeCapacity(args); | |
| 3096 | 3096 | gz.zir_code.extra.appendSliceAssumeCapacity(constraints); |
| 3097 | 3097 | |
| 3098 | 3098 | return rvalue(mod, scope, rl, result, node); |
| ... | ... | @@ -3164,7 +3164,7 @@ fn asRlPtr( |
| 3164 | 3164 | const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2; |
| 3165 | 3165 | try parent_zir.ensureCapacity(mod.gpa, expected_len); |
| 3166 | 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 | 3168 | if (zir_tags[src_inst] == .store_to_block_ptr) { |
| 3169 | 3169 | if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue; |
| 3170 | 3170 | } |
| ... | ... | @@ -3256,7 +3256,7 @@ fn typeOf( |
| 3256 | 3256 | } |
| 3257 | 3257 | |
| 3258 | 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); | |
| 3260 | 3260 | |
| 3261 | 3261 | return rvalue(mod, scope, rl, result, node); |
| 3262 | 3262 | } |
src/zir.zig+16-44| ... | ... | @@ -70,6 +70,11 @@ pub const Code = struct { |
| 70 | 70 | return code.string_bytes[index..end :0]; |
| 71 | 71 | } |
| 72 | 72 | |
| 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 | 78 | pub fn deinit(code: *Code, gpa: *Allocator) void { |
| 74 | 79 | code.instructions.deinit(gpa); |
| 75 | 80 | gpa.free(code.string_bytes); |
| ... | ... | @@ -767,16 +772,17 @@ pub const Inst = struct { |
| 767 | 772 | /// of the current function or a ZIR instruction. |
| 768 | 773 | /// |
| 769 | 774 | /// 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 | 777 | /// 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 | 780 | /// When adding a tag to this enum, consider adding a corresponding entry to |
| 776 | 781 | /// `simple_types` in astgen. |
| 777 | 782 | /// |
| 778 | /// This is packed so that it is safe to cast between `[]u32` and `[]Ref`. | |
| 779 | pub const Ref = packed enum(u32) { | |
| 783 | /// The tag type is specified so that it is safe to bitcast between `[]u32` | |
| 784 | /// and `[]Ref`. | |
| 785 | pub const Ref = enum(u32) { | |
| 780 | 786 | /// This Ref does not correspond to any ZIR instruction or constant |
| 781 | 787 | /// value and may instead be used as a sentinel to indicate null. |
| 782 | 788 | none, |
| ... | ... | @@ -841,8 +847,7 @@ pub const Inst = struct { |
| 841 | 847 | |
| 842 | 848 | _, |
| 843 | 849 | |
| 844 | pub const typed_value_count = @as(u32, typed_value_map.len); | |
| 845 | const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{ | |
| 850 | pub const typed_value_map = std.enums.directEnumArray(Ref, TypedValue, 0, .{ | |
| 846 | 851 | .none = undefined, |
| 847 | 852 | |
| 848 | 853 | .u8_type = .{ |
| ... | ... | @@ -1039,36 +1044,6 @@ pub const Inst = struct { |
| 1039 | 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 | }; |
| 1073 | 1048 | |
| 1074 | 1049 | /// All instructions have an 8-byte payload, which is contained within |
| ... | ... | @@ -1672,8 +1647,7 @@ const Writer = struct { |
| 1672 | 1647 | fn writePlNodeCall(self: *Writer, stream: anytype, inst: Inst.Index) !void { |
| 1673 | 1648 | const inst_data = self.code.instructions.items(.data)[inst].pl_node; |
| 1674 | 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]; | |
| 1676 | const args = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_args)); | |
| 1650 | const args = self.code.refSlice(extra.end, extra.data.args_len); | |
| 1677 | 1651 | |
| 1678 | 1652 | try self.writeInstRef(stream, extra.data.callee); |
| 1679 | 1653 | try stream.writeAll(", ["); |
| ... | ... | @@ -1767,8 +1741,7 @@ const Writer = struct { |
| 1767 | 1741 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1768 | 1742 | const inst_data = self.code.instructions.items(.data)[inst].fn_type; |
| 1769 | 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]; | |
| 1771 | const param_types = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_param_types)); | |
| 1744 | const param_types = self.code.refSlice(extra.end, extra.data.param_types_len); | |
| 1772 | 1745 | return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, .none); |
| 1773 | 1746 | } |
| 1774 | 1747 | |
| ... | ... | @@ -1793,8 +1766,7 @@ const Writer = struct { |
| 1793 | 1766 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { |
| 1794 | 1767 | const inst_data = self.code.instructions.items(.data)[inst].fn_type; |
| 1795 | 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]; | |
| 1797 | const param_types = mem.bytesAsSlice(Inst.Ref, mem.sliceAsBytes(raw_param_types)); | |
| 1769 | const param_types = self.code.refSlice(extra.end, extra.data.param_types_len); | |
| 1798 | 1770 | const cc = extra.data.cc; |
| 1799 | 1771 | return self.writeFnTypeCommon(stream, param_types, inst_data.return_type, var_args, cc); |
| 1800 | 1772 | } |
| ... | ... | @@ -1864,10 +1836,10 @@ const Writer = struct { |
| 1864 | 1836 | fn writeInstRef(self: *Writer, stream: anytype, ref: Inst.Ref) !void { |
| 1865 | 1837 | var i: usize = @enumToInt(ref); |
| 1866 | 1838 | |
| 1867 | if (i < Inst.Ref.typed_value_count) { | |
| 1839 | if (i < Inst.Ref.typed_value_map.len) { | |
| 1868 | 1840 | return stream.print("@{}", .{ref}); |
| 1869 | 1841 | } |
| 1870 | i -= Inst.Ref.typed_value_count; | |
| 1842 | i -= Inst.Ref.typed_value_map.len; | |
| 1871 | 1843 | |
| 1872 | 1844 | if (i < self.param_count) { |
| 1873 | 1845 | return stream.print("${d}", .{i}); |