| ... | @@ -506,7 +506,12 @@ pub const Key = union(enum) { | ... | @@ -506,7 +506,12 @@ pub const Key = union(enum) { |
| 506 | | 506 | |
| 507 | pub const Aggregate = struct { | 507 | pub const Aggregate = struct { |
| 508 | ty: Index, | 508 | ty: Index, |
| 509 | fields: []const Index, | 509 | storage: Storage, |
| | 510 | |
| | 511 | pub const Storage = union(enum) { |
| | 512 | elems: []const Index, |
| | 513 | repeated_elem: Index, |
| | 514 | }; |
| 510 | }; | 515 | }; |
| 511 | | 516 | |
| 512 | pub fn hash32(key: Key) u32 { | 517 | pub fn hash32(key: Key) u32 { |
| ... | @@ -578,7 +583,14 @@ pub const Key = union(enum) { | ... | @@ -578,7 +583,14 @@ pub const Key = union(enum) { |
| 578 | | 583 | |
| 579 | .aggregate => |aggregate| { | 584 | .aggregate => |aggregate| { |
| 580 | std.hash.autoHash(hasher, aggregate.ty); | 585 | std.hash.autoHash(hasher, aggregate.ty); |
| 581 | for (aggregate.fields) |field| std.hash.autoHash(hasher, field); | 586 | std.hash.autoHash(hasher, @as( |
| | 587 | @typeInfo(Key.Aggregate.Storage).Union.tag_type.?, |
| | 588 | aggregate.storage, |
| | 589 | )); |
| | 590 | switch (aggregate.storage) { |
| | 591 | .elems => |elems| for (elems) |elem| std.hash.autoHash(hasher, elem), |
| | 592 | .repeated_elem => |elem| std.hash.autoHash(hasher, elem), |
| | 593 | } |
| 582 | }, | 594 | }, |
| 583 | | 595 | |
| 584 | .error_set_type => |error_set_type| { | 596 | .error_set_type => |error_set_type| { |
| ... | @@ -756,7 +768,14 @@ pub const Key = union(enum) { | ... | @@ -756,7 +768,14 @@ pub const Key = union(enum) { |
| 756 | .aggregate => |a_info| { | 768 | .aggregate => |a_info| { |
| 757 | const b_info = b.aggregate; | 769 | const b_info = b.aggregate; |
| 758 | if (a_info.ty != b_info.ty) return false; | 770 | if (a_info.ty != b_info.ty) return false; |
| 759 | return std.mem.eql(Index, a_info.fields, b_info.fields); | 771 | |
| | 772 | const StorageTag = @typeInfo(Key.Aggregate.Storage).Union.tag_type.?; |
| | 773 | if (@as(StorageTag, a_info.storage) != @as(StorageTag, b_info.storage)) return false; |
| | 774 | |
| | 775 | return switch (a_info.storage) { |
| | 776 | .elems => |a_elems| std.mem.eql(Index, a_elems, b_info.storage.elems), |
| | 777 | .repeated_elem => |a_elem| a_elem == b_info.storage.repeated_elem, |
| | 778 | }; |
| 760 | }, | 779 | }, |
| 761 | .anon_struct_type => |a_info| { | 780 | .anon_struct_type => |a_info| { |
| 762 | const b_info = b.anon_struct_type; | 781 | const b_info = b.anon_struct_type; |
| ... | @@ -1407,6 +1426,9 @@ pub const Tag = enum(u8) { | ... | @@ -1407,6 +1426,9 @@ pub const Tag = enum(u8) { |
| 1407 | /// An instance of a struct, array, or vector. | 1426 | /// An instance of a struct, array, or vector. |
| 1408 | /// data is extra index to `Aggregate`. | 1427 | /// data is extra index to `Aggregate`. |
| 1409 | aggregate, | 1428 | aggregate, |
| | 1429 | /// An instance of an array or vector with every element being the same value. |
| | 1430 | /// data is extra index to `Repeated`. |
| | 1431 | repeated, |
| 1410 | }; | 1432 | }; |
| 1411 | | 1433 | |
| 1412 | /// Trailing: | 1434 | /// Trailing: |
| ... | @@ -1446,6 +1468,13 @@ pub const Aggregate = struct { | ... | @@ -1446,6 +1468,13 @@ pub const Aggregate = struct { |
| 1446 | ty: Index, | 1468 | ty: Index, |
| 1447 | }; | 1469 | }; |
| 1448 | | 1470 | |
| | 1471 | pub const Repeated = struct { |
| | 1472 | /// The type of the aggregate. |
| | 1473 | ty: Index, |
| | 1474 | /// The value of every element. |
| | 1475 | elem_val: Index, |
| | 1476 | }; |
| | 1477 | |
| 1449 | /// Trailing: | 1478 | /// Trailing: |
| 1450 | /// 0. type: Index for each fields_len | 1479 | /// 0. type: Index for each fields_len |
| 1451 | /// 1. value: Index for each fields_len | 1480 | /// 1. value: Index for each fields_len |
| ... | @@ -2049,13 +2078,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -2049,13 +2078,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2049 | // as the tuple case below). | 2078 | // as the tuple case below). |
| 2050 | .struct_type => .{ .aggregate = .{ | 2079 | .struct_type => .{ .aggregate = .{ |
| 2051 | .ty = ty, | 2080 | .ty = ty, |
| 2052 | .fields = &.{}, | 2081 | .storage = .{ .elems = &.{} }, |
| 2053 | } }, | 2082 | } }, |
| 2054 | // There is only one possible value precisely due to the | 2083 | // There is only one possible value precisely due to the |
| 2055 | // fact that this values slice is fully populated! | 2084 | // fact that this values slice is fully populated! |
| 2056 | .anon_struct_type => |anon_struct_type| .{ .aggregate = .{ | 2085 | .anon_struct_type => |anon_struct_type| .{ .aggregate = .{ |
| 2057 | .ty = ty, | 2086 | .ty = ty, |
| 2058 | .fields = anon_struct_type.values, | 2087 | .storage = .{ .elems = anon_struct_type.values }, |
| 2059 | } }, | 2088 | } }, |
| 2060 | else => unreachable, | 2089 | else => unreachable, |
| 2061 | }; | 2090 | }; |
| ... | @@ -2066,7 +2095,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -2066,7 +2095,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2066 | const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]); | 2095 | const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]); |
| 2067 | return .{ .aggregate = .{ | 2096 | return .{ .aggregate = .{ |
| 2068 | .ty = extra.data.ty, | 2097 | .ty = extra.data.ty, |
| 2069 | .fields = fields, | 2098 | .storage = .{ .elems = fields }, |
| | 2099 | } }; |
| | 2100 | }, |
| | 2101 | .repeated => { |
| | 2102 | const extra = ip.extraData(Repeated, data); |
| | 2103 | return .{ .aggregate = .{ |
| | 2104 | .ty = extra.ty, |
| | 2105 | .storage = .{ .repeated_elem = extra.elem_val }, |
| 2070 | } }; | 2106 | } }; |
| 2071 | }, | 2107 | }, |
| 2072 | .union_value => .{ .un = ip.extraData(Key.Union, data) }, | 2108 | .union_value => .{ .un = ip.extraData(Key.Union, data) }, |
| ... | @@ -2663,10 +2699,18 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2663,10 +2699,18 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2663 | | 2699 | |
| 2664 | .aggregate => |aggregate| { | 2700 | .aggregate => |aggregate| { |
| 2665 | assert(aggregate.ty != .none); | 2701 | assert(aggregate.ty != .none); |
| 2666 | for (aggregate.fields) |elem| assert(elem != .none); | 2702 | const aggregate_len = ip.aggregateTypeLen(aggregate.ty); |
| 2667 | assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty)); | 2703 | switch (aggregate.storage) { |
| | 2704 | .elems => |elems| { |
| | 2705 | assert(elems.len == aggregate_len); |
| | 2706 | for (elems) |elem| assert(elem != .none); |
| | 2707 | }, |
| | 2708 | .repeated_elem => |elem| { |
| | 2709 | assert(elem != .none); |
| | 2710 | }, |
| | 2711 | } |
| 2668 | | 2712 | |
| 2669 | if (aggregate.fields.len == 0) { | 2713 | if (aggregate_len == 0) { |
| 2670 | ip.items.appendAssumeCapacity(.{ | 2714 | ip.items.appendAssumeCapacity(.{ |
| 2671 | .tag = .only_possible_value, | 2715 | .tag = .only_possible_value, |
| 2672 | .data = @enumToInt(aggregate.ty), | 2716 | .data = @enumToInt(aggregate.ty), |
| ... | @@ -2676,7 +2720,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2676,7 +2720,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2676 | | 2720 | |
| 2677 | switch (ip.indexToKey(aggregate.ty)) { | 2721 | switch (ip.indexToKey(aggregate.ty)) { |
| 2678 | .anon_struct_type => |anon_struct_type| { | 2722 | .anon_struct_type => |anon_struct_type| { |
| 2679 | if (std.mem.eql(Index, anon_struct_type.values, aggregate.fields)) { | 2723 | if (switch (aggregate.storage) { |
| | 2724 | .elems => |elems| std.mem.eql(Index, anon_struct_type.values, elems), |
| | 2725 | .repeated_elem => |elem| for (anon_struct_type.values) |value| { |
| | 2726 | if (value != elem) break false; |
| | 2727 | } else true, |
| | 2728 | }) { |
| 2680 | // This encoding works thanks to the fact that, as we just verified, | 2729 | // This encoding works thanks to the fact that, as we just verified, |
| 2681 | // the type itself contains a slice of values that can be provided | 2730 | // the type itself contains a slice of values that can be provided |
| 2682 | // in the aggregate fields. | 2731 | // in the aggregate fields. |
| ... | @@ -2690,9 +2739,33 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2690,9 +2739,33 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2690 | else => {}, | 2739 | else => {}, |
| 2691 | } | 2740 | } |
| 2692 | | 2741 | |
| | 2742 | if (switch (aggregate.storage) { |
| | 2743 | .elems => |elems| for (elems[1..]) |elem| { |
| | 2744 | if (elem != elems[0]) break false; |
| | 2745 | } else true, |
| | 2746 | .repeated_elem => true, |
| | 2747 | }) { |
| | 2748 | try ip.extra.ensureUnusedCapacity( |
| | 2749 | gpa, |
| | 2750 | @typeInfo(Repeated).Struct.fields.len, |
| | 2751 | ); |
| | 2752 | |
| | 2753 | ip.items.appendAssumeCapacity(.{ |
| | 2754 | .tag = .repeated, |
| | 2755 | .data = ip.addExtraAssumeCapacity(Repeated{ |
| | 2756 | .ty = aggregate.ty, |
| | 2757 | .elem_val = switch (aggregate.storage) { |
| | 2758 | .elems => |elems| elems[0], |
| | 2759 | .repeated_elem => |elem| elem, |
| | 2760 | }, |
| | 2761 | }), |
| | 2762 | }); |
| | 2763 | return @intToEnum(Index, ip.items.len - 1); |
| | 2764 | } |
| | 2765 | |
| 2693 | try ip.extra.ensureUnusedCapacity( | 2766 | try ip.extra.ensureUnusedCapacity( |
| 2694 | gpa, | 2767 | gpa, |
| 2695 | @typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len, | 2768 | @typeInfo(Aggregate).Struct.fields.len + aggregate_len, |
| 2696 | ); | 2769 | ); |
| 2697 | | 2770 | |
| 2698 | ip.items.appendAssumeCapacity(.{ | 2771 | ip.items.appendAssumeCapacity(.{ |
| ... | @@ -2701,7 +2774,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -2701,7 +2774,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2701 | .ty = aggregate.ty, | 2774 | .ty = aggregate.ty, |
| 2702 | }), | 2775 | }), |
| 2703 | }); | 2776 | }); |
| 2704 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, aggregate.fields)); | 2777 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, aggregate.storage.elems)); |
| 2705 | }, | 2778 | }, |
| 2706 | | 2779 | |
| 2707 | .un => |un| { | 2780 | .un => |un| { |
| ... | @@ -3417,6 +3490,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { | ... | @@ -3417,6 +3490,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3417 | const fields_len = @intCast(u32, ip.aggregateTypeLen(info.ty)); | 3490 | const fields_len = @intCast(u32, ip.aggregateTypeLen(info.ty)); |
| 3418 | break :b @sizeOf(Aggregate) + (@sizeOf(u32) * fields_len); | 3491 | break :b @sizeOf(Aggregate) + (@sizeOf(u32) * fields_len); |
| 3419 | }, | 3492 | }, |
| | 3493 | .repeated => @sizeOf(Repeated), |
| 3420 | | 3494 | |
| 3421 | .float_f16 => 0, | 3495 | .float_f16 => 0, |
| 3422 | .float_f32 => 0, | 3496 | .float_f32 => 0, |