| ... | ... | @@ -722,10 +722,10 @@ pub const Tag = enum(u8) { |
| 722 | 722 | /// data is float value bitcasted to u32. |
| 723 | 723 | float_f32, |
| 724 | 724 | /// An f64 value. |
| 725 | | /// data is payload index to Float64. |
| 725 | /// data is extra index to Float64. |
| 726 | 726 | float_f64, |
| 727 | 727 | /// An f128 value. |
| 728 | | /// data is payload index to Float128. |
| 728 | /// data is extra index to Float128. |
| 729 | 729 | float_f128, |
| 730 | 730 | /// An extern function. |
| 731 | 731 | extern_func, |
| ... | ... | @@ -877,6 +877,33 @@ pub const Int = struct { |
| 877 | 877 | limbs_len: u32, |
| 878 | 878 | }; |
| 879 | 879 | |
| 880 | /// A f64 value, broken up into 2 u32 parts. |
| 881 | pub const Float64 = struct { |
| 882 | piece0: u32, |
| 883 | piece1: u32, |
| 884 | |
| 885 | pub fn get(self: Float64) f64 { |
| 886 | const int_bits = @as(u64, self.piece0) | (@as(u64, self.piece1) << 32); |
| 887 | return @bitCast(u64, int_bits); |
| 888 | } |
| 889 | }; |
| 890 | |
| 891 | /// A f128 value, broken up into 4 u32 parts. |
| 892 | pub const Float128 = struct { |
| 893 | piece0: u32, |
| 894 | piece1: u32, |
| 895 | piece2: u32, |
| 896 | piece3: u32, |
| 897 | |
| 898 | pub fn get(self: Float128) f128 { |
| 899 | const int_bits = @as(u128, self.piece0) | |
| 900 | (@as(u128, self.piece1) << 32) | |
| 901 | (@as(u128, self.piece2) << 64) | |
| 902 | (@as(u128, self.piece3) << 96); |
| 903 | return @bitCast(f128, int_bits); |
| 904 | } |
| 905 | }; |
| 906 | |
| 880 | 907 | pub fn init(ip: *InternPool, gpa: Allocator) !void { |
| 881 | 908 | assert(ip.items.len == 0); |
| 882 | 909 | |
| ... | ... | @@ -1293,20 +1320,42 @@ fn addLimbsAssumeCapacity(ip: *InternPool, limbs: []const usize) void { |
| 1293 | 1320 | } |
| 1294 | 1321 | |
| 1295 | 1322 | fn extraData(ip: InternPool, comptime T: type, index: usize) T { |
| 1296 | | const fields = std.meta.fields(T); |
| 1297 | | var i: usize = index; |
| 1298 | 1323 | var result: T = undefined; |
| 1299 | | inline for (fields) |field| { |
| 1324 | inline for (@typeInfo(T).Struct.fields, 0..) |field, i| { |
| 1325 | const int32 = ip.extra.items[i + index]; |
| 1300 | 1326 | @field(result, field.name) = switch (field.type) { |
| 1301 | | u32 => ip.extra.items[i], |
| 1302 | | Index => @intToEnum(Index, ip.extra.items[i]), |
| 1303 | | i32 => @bitCast(i32, ip.extra.items[i]), |
| 1304 | | Pointer.Flags => @bitCast(Pointer.Flags, ip.extra.items[i]), |
| 1305 | | Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, ip.extra.items[i]), |
| 1306 | | Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, ip.extra.items[i]), |
| 1327 | u32 => int32, |
| 1328 | Index => @intToEnum(Index, int32), |
| 1329 | i32 => @bitCast(i32, int32), |
| 1330 | Pointer.Flags => @bitCast(Pointer.Flags, int32), |
| 1331 | Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32), |
| 1332 | Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, int32), |
| 1333 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 1334 | }; |
| 1335 | } |
| 1336 | return result; |
| 1337 | } |
| 1338 | |
| 1339 | /// Asserts the struct has 32-bit fields and the number of fields is evenly divisible by 2. |
| 1340 | fn limbData(ip: InternPool, comptime T: type, index: usize) T { |
| 1341 | switch (@sizeOf(usize)) { |
| 1342 | @sizeOf(u32) => return extraData(ip, T, index), |
| 1343 | @sizeOf(u64) => {}, |
| 1344 | else => @compileError("unsupported host"), |
| 1345 | } |
| 1346 | var result: T = undefined; |
| 1347 | inline for (@typeInfo(T).Struct.fields, 0..) |field, i| { |
| 1348 | const host_int = ip.limbs.items[index + i / 2]; |
| 1349 | const int32 = if (i % 2 == 0) |
| 1350 | @truncate(u32, host_int) |
| 1351 | else |
| 1352 | @truncate(u32, host_int >> 32); |
| 1353 | |
| 1354 | @field(result, field.name) = switch (field.type) { |
| 1355 | u32 => int32, |
| 1356 | Index => @intToEnum(Index, int32), |
| 1307 | 1357 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 1308 | 1358 | }; |
| 1309 | | i += 1; |
| 1310 | 1359 | } |
| 1311 | 1360 | return result; |
| 1312 | 1361 | } |
| ... | ... | @@ -1350,3 +1399,85 @@ pub fn childType(ip: InternPool, i: Index) Index { |
| 1350 | 1399 | else => unreachable, |
| 1351 | 1400 | }; |
| 1352 | 1401 | } |
| 1402 | |
| 1403 | pub fn dump(ip: InternPool) void { |
| 1404 | dumpFallible(ip, std.heap.page_allocator) catch return; |
| 1405 | } |
| 1406 | |
| 1407 | fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 1408 | const items_size = (1 + 4) * ip.items.len; |
| 1409 | const extra_size = 4 * ip.extra.items.len; |
| 1410 | const limbs_size = 8 * ip.limbs.items.len; |
| 1411 | |
| 1412 | // TODO: map overhead size is not taken into account |
| 1413 | const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size; |
| 1414 | |
| 1415 | std.debug.print( |
| 1416 | \\InternPool size: {d} bytes |
| 1417 | \\ items: {d} bytes |
| 1418 | \\ extra: {d} bytes |
| 1419 | \\ limbs: {d} bytes |
| 1420 | \\ |
| 1421 | , .{ total_size, items_size, extra_size, limbs_size }); |
| 1422 | |
| 1423 | const tags = ip.items.items(.tag); |
| 1424 | const datas = ip.items.items(.data); |
| 1425 | const TagStats = struct { |
| 1426 | count: usize = 0, |
| 1427 | bytes: usize = 0, |
| 1428 | }; |
| 1429 | var counts = std.AutoArrayHashMap(Tag, TagStats).init(arena); |
| 1430 | for (tags, datas) |tag, data| { |
| 1431 | const gop = try counts.getOrPut(tag); |
| 1432 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 1433 | gop.value_ptr.count += 1; |
| 1434 | gop.value_ptr.bytes += 1 + 4 + @as(usize, switch (tag) { |
| 1435 | .type_int_signed => 0, |
| 1436 | .type_int_unsigned => 0, |
| 1437 | .type_array => @sizeOf(Vector), |
| 1438 | .type_vector => @sizeOf(Vector), |
| 1439 | .type_pointer => @sizeOf(Pointer), |
| 1440 | .type_optional => 0, |
| 1441 | .type_error_union => @sizeOf(ErrorUnion), |
| 1442 | .type_enum_simple => @sizeOf(EnumSimple), |
| 1443 | .simple_type => 0, |
| 1444 | .simple_value => 0, |
| 1445 | .simple_internal => 0, |
| 1446 | .int_u32 => 0, |
| 1447 | .int_i32 => 0, |
| 1448 | .int_usize => 0, |
| 1449 | .int_comptime_int_u32 => 0, |
| 1450 | .int_comptime_int_i32 => 0, |
| 1451 | |
| 1452 | .int_positive, |
| 1453 | .int_negative, |
| 1454 | .enum_tag_positive, |
| 1455 | .enum_tag_negative, |
| 1456 | => b: { |
| 1457 | const int = ip.limbData(Int, data); |
| 1458 | break :b @sizeOf(Int) + int.limbs_len * 8; |
| 1459 | }, |
| 1460 | |
| 1461 | .float_f32 => 0, |
| 1462 | .float_f64 => @sizeOf(Float64), |
| 1463 | .float_f128 => @sizeOf(Float128), |
| 1464 | .extern_func => @panic("TODO"), |
| 1465 | .func => @panic("TODO"), |
| 1466 | }); |
| 1467 | } |
| 1468 | const SortContext = struct { |
| 1469 | map: *std.AutoArrayHashMap(Tag, TagStats), |
| 1470 | pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool { |
| 1471 | const values = ctx.map.values(); |
| 1472 | return values[a_index].bytes > values[b_index].bytes; |
| 1473 | } |
| 1474 | }; |
| 1475 | counts.sort(SortContext{ .map = &counts }); |
| 1476 | const len = @min(50, tags.len); |
| 1477 | std.debug.print("top 50 tags:\n", .{}); |
| 1478 | for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| { |
| 1479 | std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{ |
| 1480 | @tagName(tag), stats.count, stats.bytes, |
| 1481 | }); |
| 1482 | } |
| 1483 | } |