authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-19 21:35:55-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:53-07:00
logd28fc5bacb2b27ba3f2a5ed17475b9b790be3ed5
tree84560d77289cec63fa1711414ce53d575069a85e
parent9ff514b6a35b7201f45f8bff31c61b4f8cfa7a7a

InternPool: add repeated aggregate storage


4 files changed, 104 insertions(+), 24 deletions(-)

src/InternPool.zig+86-12
...@@ -506,7 +506,12 @@ pub const Key = union(enum) {...@@ -506,7 +506,12 @@ pub const Key = union(enum) {
506506
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 };
511516
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) {
578583
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 },
583595
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};
14111433
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};
14481470
1471pub 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_len1479/// 0. type: Index for each fields_len
1451/// 1. value: Index for each fields_len1480/// 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 the2083 // 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 {
26632699
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 }
26682712
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 {
26762720
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 provided2730 // 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 }
26922741
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 );
26972770
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 },
27062779
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),
34203494
3421 .float_f16 => 0,3495 .float_f16 => 0,
3422 .float_f32 => 0,3496 .float_f32 => 0,
src/Sema.zig+7-7
...@@ -12671,7 +12671,7 @@ fn analyzeTupleCat(...@@ -12671,7 +12671,7 @@ fn analyzeTupleCat(
12671 const runtime_src = opt_runtime_src orelse {12671 const runtime_src = opt_runtime_src orelse {
12672 const tuple_val = try mod.intern(.{ .aggregate = .{12672 const tuple_val = try mod.intern(.{ .aggregate = .{
12673 .ty = tuple_ty,12673 .ty = tuple_ty,
12674 .fields = values,12674 .storage = .{ .elems = values },
12675 } });12675 } });
12676 return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());12676 return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
12677 };12677 };
...@@ -12989,7 +12989,7 @@ fn analyzeTupleMul(...@@ -12989,7 +12989,7 @@ fn analyzeTupleMul(
12989 const runtime_src = opt_runtime_src orelse {12989 const runtime_src = opt_runtime_src orelse {
12990 const tuple_val = try mod.intern(.{ .aggregate = .{12990 const tuple_val = try mod.intern(.{ .aggregate = .{
12991 .ty = tuple_ty,12991 .ty = tuple_ty,
12992 .fields = values,12992 .storage = .{ .elems = values },
12993 } });12993 } });
12994 return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());12994 return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
12995 };12995 };
...@@ -18227,7 +18227,7 @@ fn zirStructInitAnon(...@@ -18227,7 +18227,7 @@ fn zirStructInitAnon(
18227 const runtime_index = opt_runtime_index orelse {18227 const runtime_index = opt_runtime_index orelse {
18228 const tuple_val = try mod.intern(.{ .aggregate = .{18228 const tuple_val = try mod.intern(.{ .aggregate = .{
18229 .ty = tuple_ty,18229 .ty = tuple_ty,
18230 .fields = values,18230 .storage = .{ .elems = values },
18231 } });18231 } });
18232 return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);18232 return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
18233 };18233 };
...@@ -18442,7 +18442,7 @@ fn zirArrayInitAnon(...@@ -18442,7 +18442,7 @@ fn zirArrayInitAnon(
18442 const runtime_src = opt_runtime_src orelse {18442 const runtime_src = opt_runtime_src orelse {
18443 const tuple_val = try mod.intern(.{ .aggregate = .{18443 const tuple_val = try mod.intern(.{ .aggregate = .{
18444 .ty = tuple_ty,18444 .ty = tuple_ty,
18445 .fields = values,18445 .storage = .{ .elems = values },
18446 } });18446 } });
18447 return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);18447 return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
18448 };18448 };
...@@ -29176,7 +29176,7 @@ fn coerceTupleToTuple(...@@ -29176,7 +29176,7 @@ fn coerceTupleToTuple(
29176 tuple_ty,29176 tuple_ty,
29177 (try mod.intern(.{ .aggregate = .{29177 (try mod.intern(.{ .aggregate = .{
29178 .ty = tuple_ty.ip_index,29178 .ty = tuple_ty.ip_index,
29179 .fields = field_vals,29179 .storage = .{ .elems = field_vals },
29180 } })).toValue(),29180 } })).toValue(),
29181 );29181 );
29182}29182}
...@@ -33085,7 +33085,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33085,7 +33085,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33085 // one-possible-value in type.zig.33085 // one-possible-value in type.zig.
33086 const empty = try mod.intern(.{ .aggregate = .{33086 const empty = try mod.intern(.{ .aggregate = .{
33087 .ty = ty.ip_index,33087 .ty = ty.ip_index,
33088 .fields = &.{},33088 .storage = .{ .elems = &.{} },
33089 } });33089 } });
33090 return empty.toValue();33090 return empty.toValue();
33091 },33091 },
...@@ -33098,7 +33098,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33098,7 +33098,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33098 // therefore has one possible value.33098 // therefore has one possible value.
33099 return (try mod.intern(.{ .aggregate = .{33099 return (try mod.intern(.{ .aggregate = .{
33100 .ty = ty.ip_index,33100 .ty = ty.ip_index,
33101 .fields = tuple.values,33101 .storage = .{ .elems = tuple.values },
33102 } })).toValue();33102 } })).toValue();
33103 },33103 },
3310433104
src/type.zig+2-2
...@@ -2738,7 +2738,7 @@ pub const Type = struct {...@@ -2738,7 +2738,7 @@ pub const Type = struct {
2738 // one-possible-value logic in Sema.zig.2738 // one-possible-value logic in Sema.zig.
2739 const empty = try mod.intern(.{ .aggregate = .{2739 const empty = try mod.intern(.{ .aggregate = .{
2740 .ty = ty.ip_index,2740 .ty = ty.ip_index,
2741 .fields = &.{},2741 .storage = .{ .elems = &.{} },
2742 } });2742 } });
2743 return empty.toValue();2743 return empty.toValue();
2744 },2744 },
...@@ -2751,7 +2751,7 @@ pub const Type = struct {...@@ -2751,7 +2751,7 @@ pub const Type = struct {
2751 // therefore has one possible value.2751 // therefore has one possible value.
2752 return (try mod.intern(.{ .aggregate = .{2752 return (try mod.intern(.{ .aggregate = .{
2753 .ty = ty.ip_index,2753 .ty = ty.ip_index,
2754 .fields = tuple.values,2754 .storage = .{ .elems = tuple.values },
2755 } })).toValue();2755 } })).toValue();
2756 },2756 },
27572757
src/value.zig+9-3
...@@ -2665,7 +2665,10 @@ pub const Value = struct {...@@ -2665,7 +2665,10 @@ pub const Value = struct {
2665 else => unreachable,2665 else => unreachable,
2666 },2666 },
2667 else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {2667 else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
2668 .aggregate => |aggregate| aggregate.fields[index].toValue(),2668 .aggregate => |aggregate| switch (aggregate.storage) {
2669 .elems => |elems| elems[index],
2670 .repeated_elem => |elem| elem,
2671 }.toValue(),
2669 else => unreachable,2672 else => unreachable,
2670 },2673 },
2671 }2674 }
...@@ -2753,8 +2756,11 @@ pub const Value = struct {...@@ -2753,8 +2756,11 @@ pub const Value = struct {
2753 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {2756 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
2754 .undef => return true,2757 .undef => return true,
2755 .simple_value => |v| if (v == .undefined) return true,2758 .simple_value => |v| if (v == .undefined) return true,
2756 .aggregate => |aggregate| for (aggregate.fields) |field| {2759 .aggregate => |aggregate| switch (aggregate.storage) {
2757 if (try anyUndef(field.toValue(), mod)) return true;2760 .elems => |elems| for (elems) |elem| {
2761 if (try anyUndef(elem.toValue(), mod)) return true;
2762 },
2763 .repeated_elem => |elem| if (try anyUndef(elem.toValue(), mod)) return true,
2758 },2764 },
2759 else => {},2765 else => {},
2760 },2766 },