| 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,3 +34,4 @@ Performance optimizations to look into: |
| 34 | * enum literals can use small strings | 34 | * enum literals can use small strings |
| 35 | * string literals can use small strings | 35 | * string literals can use small strings |
| 36 | * don't need the Sema coercion on condbr condition, it's done with result locations | 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,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); |
| 1017 | 1017 | ||
| 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 | } |
| 1029 | 1029 | ||
| 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); |
| 1047 | 1047 | ||
| 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 | } |
| 1059 | 1059 | ||
| 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); |
| 1081 | 1081 | ||
| 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 | } |
| 1093 | 1093 | ||
| 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 | } |
| 1165 | 1165 | ||
| 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 | } |
| 1191 | 1191 | ||
| 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 | }; |
| 1323 | 1323 | ||
| ... | @@ -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 between | 1369 | /// 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 | } |
| 1394 | 1394 | ||
| 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 | } |
| 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 | 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(); |
| 2303 | 2326 | ||
| ... | @@ -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); |
| 2315 | 2338 | ||
| 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 | } |
| 301 | 301 | ||
| 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. | ||
| 304 | pub fn resolveInst(sema: *Sema, zir_ref: zir.Inst.Ref) error{OutOfMemory}!*ir.Inst { | 303 | pub 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; | ||
| 308 | 316 | ||
| 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; | ||
| 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 | fn resolveConstString( | 327 | fn 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 |
| 753 | 763 | ||
| 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)); | ||
| 758 | 767 | ||
| 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)); | ||
| 1110 | 1118 | ||
| 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 |
| 1733 | 1741 | ||
| 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)); | ||
| 1738 | 1745 | ||
| 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: |
| 1752 | 1759 | ||
| 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)); | ||
| 1757 | 1763 | ||
| 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 from | 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,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)); | ||
| 2773 | 2778 | ||
| 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); |
| 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 | .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`, but | 991 | // 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 it | 995 | // 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 | } |
| 1526 | 1526 | ||
| 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); |
| 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 | return rvalue(mod, scope, rl, block_ref, node); | 1985 | return rvalue(mod, scope, rl, block_ref, node); |
| 1986 | } | 1986 | } |
| 1987 | 1987 | ||
| ... | @@ -3092,7 +3092,7 @@ fn asmExpr( | ... | @@ -3092,7 +3092,7 @@ fn asmExpr( |
| 3092 | 3092 | ||
| 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); |
| 3097 | 3097 | ||
| 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 | } |
| 3257 | 3257 | ||
| 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); |
| 3260 | 3260 | ||
| 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 | } |
| 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 | 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 be | 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 | /// All further values refer to ZIR instructions which may be derived by | 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 | /// When adding a tag to this enum, consider adding a corresponding entry to | 780 | /// 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 constant | 786 | /// 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 { |
| 841 | 847 | ||
| 842 | _, | 848 | _, |
| 843 | 849 | ||
| 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, |
| 847 | 852 | ||
| 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 | }; |
| 1073 | 1048 | ||
| 1074 | /// All instructions have an 8-byte payload, which is contained within | 1049 | /// 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)); | ||
| 1677 | 1651 | ||
| 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 | } |
| 1774 | 1747 | ||
| ... | @@ -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); |
| 1866 | 1838 | ||
| 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; |
| 1871 | 1843 | ||
| 1872 | if (i < self.param_count) { | 1844 | if (i < self.param_count) { |
| 1873 | return stream.print("${d}", .{i}); | 1845 | return stream.print("${d}", .{i}); |