authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-14 20:37:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:53-07:00
log6a9a918fbe4adc23dd7d7573c6f1e499f4be074e
treef94c3d80a82b04a905d725689740af1d8c90dc97
parentd18881de1be811c1dff52590223b92c916c4b773

stage2: encode one-possible-value tuple specially

Anonymous structs and anonymous tuples can be stored via a only_possible_value tag because their type encodings, by definition, will have every value specified, which can be used to populate the fields slice in `Key.Aggregate`. Also fix `isTupleOrAnonStruct`.

3 files changed, 52 insertions(+), 46 deletions(-)

src/InternPool.zig+33-11
...@@ -1166,10 +1166,10 @@ pub const Tag = enum(u8) {...@@ -1166,10 +1166,10 @@ pub const Tag = enum(u8) {
1166 /// Module.Struct object allocated for it.1166 /// Module.Struct object allocated for it.
1167 /// data is Module.Namespace.Index.1167 /// data is Module.Namespace.Index.
1168 type_struct_ns,1168 type_struct_ns,
1169 /// An AnonStructType which stores types, names, and values for each field.1169 /// An AnonStructType which stores types, names, and values for fields.
1170 /// data is extra index of `TypeStructAnon`.1170 /// data is extra index of `TypeStructAnon`.
1171 type_struct_anon,1171 type_struct_anon,
1172 /// An AnonStructType which has only types and values for each field.1172 /// An AnonStructType which has only types and values for fields.
1173 /// data is extra index of `TypeStructAnon`.1173 /// data is extra index of `TypeStructAnon`.
1174 type_tuple_anon,1174 type_tuple_anon,
1175 /// A tagged union type.1175 /// A tagged union type.
...@@ -1272,7 +1272,8 @@ pub const Tag = enum(u8) {...@@ -1272,7 +1272,8 @@ pub const Tag = enum(u8) {
1272 /// only one possible value. Not all only-possible-values are encoded this way;1272 /// only one possible value. Not all only-possible-values are encoded this way;
1273 /// for example structs which have all comptime fields are not encoded this way.1273 /// for example structs which have all comptime fields are not encoded this way.
1274 /// The set of values that are encoded this way is:1274 /// The set of values that are encoded this way is:
1275 /// * A struct which has 0 fields.1275 /// * An array or vector which has length 0.
1276 /// * A struct which has all fields comptime-known.
1276 /// data is Index of the type, which is known to be zero bits at runtime.1277 /// data is Index of the type, which is known to be zero bits at runtime.
1277 only_possible_value,1278 only_possible_value,
1278 /// data is extra index to Key.Union.1279 /// data is extra index to Key.Union.
...@@ -1863,10 +1864,21 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {...@@ -1863,10 +1864,21 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
1863 .only_possible_value => {1864 .only_possible_value => {
1864 const ty = @intToEnum(Index, data);1865 const ty = @intToEnum(Index, data);
1865 return switch (ip.indexToKey(ty)) {1866 return switch (ip.indexToKey(ty)) {
1867 // TODO: migrate structs to properly use the InternPool rather
1868 // than using the SegmentedList trick, then the struct type will
1869 // have a slice of comptime values that can be used here for when
1870 // the struct has one possible value due to all fields comptime (same
1871 // as the tuple case below).
1866 .struct_type => .{ .aggregate = .{1872 .struct_type => .{ .aggregate = .{
1867 .ty = ty,1873 .ty = ty,
1868 .fields = &.{},1874 .fields = &.{},
1869 } },1875 } },
1876 // There is only one possible value precisely due to the
1877 // fact that this values slice is fully populated!
1878 .anon_struct_type => |anon_struct_type| .{ .aggregate = .{
1879 .ty = ty,
1880 .fields = anon_struct_type.values,
1881 } },
1870 else => unreachable,1882 else => unreachable,
1871 };1883 };
1872 },1884 },
...@@ -2392,12 +2404,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -2392,12 +2404,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
2392 .aggregate => |aggregate| {2404 .aggregate => |aggregate| {
2393 assert(aggregate.ty != .none);2405 assert(aggregate.ty != .none);
2394 for (aggregate.fields) |elem| assert(elem != .none);2406 for (aggregate.fields) |elem| assert(elem != .none);
2395 if (aggregate.fields.len != ip.aggregateTypeLen(aggregate.ty)) {
2396 std.debug.print("aggregate fields len = {d}, type len = {d}\n", .{
2397 aggregate.fields.len,
2398 ip.aggregateTypeLen(aggregate.ty),
2399 });
2400 }
2401 assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty));2407 assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty));
24022408
2403 if (aggregate.fields.len == 0) {2409 if (aggregate.fields.len == 0) {
...@@ -2408,6 +2414,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -2408,6 +2414,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
2408 return @intToEnum(Index, ip.items.len - 1);2414 return @intToEnum(Index, ip.items.len - 1);
2409 }2415 }
24102416
2417 switch (ip.indexToKey(aggregate.ty)) {
2418 .anon_struct_type => |anon_struct_type| {
2419 if (std.mem.eql(Index, anon_struct_type.values, aggregate.fields)) {
2420 // This encoding works thanks to the fact that, as we just verified,
2421 // the type itself contains a slice of values that can be provided
2422 // in the aggregate fields.
2423 ip.items.appendAssumeCapacity(.{
2424 .tag = .only_possible_value,
2425 .data = @enumToInt(aggregate.ty),
2426 });
2427 return @intToEnum(Index, ip.items.len - 1);
2428 }
2429 },
2430 else => {},
2431 }
2432
2411 try ip.extra.ensureUnusedCapacity(2433 try ip.extra.ensureUnusedCapacity(
2412 gpa,2434 gpa,
2413 @typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len,2435 @typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len,
...@@ -3121,8 +3143,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {...@@ -3121,8 +3143,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
3121 }3143 }
3122 };3144 };
3123 counts.sort(SortContext{ .map = &counts });3145 counts.sort(SortContext{ .map = &counts });
3124 const len = @min(50, counts.count());3146 const len = @min(25, counts.count());
3125 std.debug.print(" top 50 tags:\n", .{});3147 std.debug.print(" top 25 tags:\n", .{});
3126 for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| {3148 for (counts.keys()[0..len], counts.values()[0..len]) |tag, stats| {
3127 std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{3149 std.debug.print(" {s}: {d} occurrences, {d} total bytes\n", .{
3128 @tagName(tag), stats.count, stats.bytes,3150 @tagName(tag), stats.count, stats.bytes,
src/Sema.zig+9-18
...@@ -18237,6 +18237,7 @@ fn zirStructInitAnon(...@@ -18237,6 +18237,7 @@ fn zirStructInitAnon(
18237 return sema.failWithOwnedErrorMsg(msg);18237 return sema.failWithOwnedErrorMsg(msg);
18238 }18238 }
18239 if (try sema.resolveMaybeUndefVal(init)) |init_val| {18239 if (try sema.resolveMaybeUndefVal(init)) |init_val| {
18240 assert(init_val.ip_index != .none);
18240 values[i] = init_val.ip_index;18241 values[i] = init_val.ip_index;
18241 } else {18242 } else {
18242 values[i] = .none;18243 values[i] = .none;
...@@ -33181,8 +33182,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33181,8 +33182,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33181 // TODO: this is incorrect for structs with comptime fields, I think33182 // TODO: this is incorrect for structs with comptime fields, I think
33182 // we should use a temporary allocator to construct an aggregate that33183 // we should use a temporary allocator to construct an aggregate that
33183 // is populated with the comptime values and then intern that value here.33184 // is populated with the comptime values and then intern that value here.
33184 // This TODO is repeated for anon_struct_type below, as well as33185 // This TODO is repeated in the redundant implementation of
33185 // in the redundant implementation of one-possible-value in type.zig.33186 // one-possible-value in type.zig.
33186 const empty = try mod.intern(.{ .aggregate = .{33187 const empty = try mod.intern(.{ .aggregate = .{
33187 .ty = ty.ip_index,33188 .ty = ty.ip_index,
33188 .fields = &.{},33189 .fields = &.{},
...@@ -33191,25 +33192,15 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -33191,25 +33192,15 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
33191 },33192 },
3319233193
33193 .anon_struct_type => |tuple| {33194 .anon_struct_type => |tuple| {
33194 for (tuple.types, tuple.values) |field_ty, val| {33195 for (tuple.values) |val| {
33195 const is_comptime = val != .none;33196 if (val == .none) return null;
33196 if (is_comptime) continue;
33197 if ((try sema.typeHasOnePossibleValue(field_ty.toType())) != null) continue;
33198 return null;
33199 }33197 }
33200 // In this case the struct has no runtime-known fields and33198 // In this case the struct has all comptime-known fields and
33201 // therefore has one possible value.33199 // therefore has one possible value.
3320233200 return (try mod.intern(.{ .aggregate = .{
33203 // TODO: this is incorrect for structs with comptime fields, I think
33204 // we should use a temporary allocator to construct an aggregate that
33205 // is populated with the comptime values and then intern that value here.
33206 // This TODO is repeated for struct_type above, as well as
33207 // in the redundant implementation of one-possible-value in type.zig.
33208 const empty = try mod.intern(.{ .aggregate = .{
33209 .ty = ty.ip_index,33201 .ty = ty.ip_index,
33210 .fields = &.{},33202 .fields = tuple.values,
33211 } });33203 } })).toValue();
33212 return empty.toValue();
33213 },33204 },
3321433205
33215 .union_type => |union_type| {33206 .union_type => |union_type| {
src/type.zig+10-17
...@@ -3583,8 +3583,8 @@ pub const Type = struct {...@@ -3583,8 +3583,8 @@ pub const Type = struct {
3583 // TODO: this is incorrect for structs with comptime fields, I think3583 // TODO: this is incorrect for structs with comptime fields, I think
3584 // we should use a temporary allocator to construct an aggregate that3584 // we should use a temporary allocator to construct an aggregate that
3585 // is populated with the comptime values and then intern that value here.3585 // is populated with the comptime values and then intern that value here.
3586 // This TODO is repeated for anon_struct_type below, as well as in3586 // This TODO is repeated in the redundant implementation of
3587 // the redundant implementation of one-possible-value logic in Sema.zig.3587 // one-possible-value logic in Sema.zig.
3588 const empty = try mod.intern(.{ .aggregate = .{3588 const empty = try mod.intern(.{ .aggregate = .{
3589 .ty = ty.ip_index,3589 .ty = ty.ip_index,
3590 .fields = &.{},3590 .fields = &.{},
...@@ -3593,22 +3593,15 @@ pub const Type = struct {...@@ -3593,22 +3593,15 @@ pub const Type = struct {
3593 },3593 },
35943594
3595 .anon_struct_type => |tuple| {3595 .anon_struct_type => |tuple| {
3596 for (tuple.types, tuple.values) |field_ty, val| {3596 for (tuple.values) |val| {
3597 if (val != .none) continue; // comptime field3597 if (val == .none) return null;
3598 if ((try field_ty.toType().onePossibleValue(mod)) != null) continue;
3599 return null;
3600 }3598 }
36013599 // In this case the struct has all comptime-known fields and
3602 // TODO: this is incorrect for structs with comptime fields, I think3600 // therefore has one possible value.
3603 // we should use a temporary allocator to construct an aggregate that3601 return (try mod.intern(.{ .aggregate = .{
3604 // is populated with the comptime values and then intern that value here.
3605 // This TODO is repeated for struct_type above, as well as in
3606 // the redundant implementation of one-possible-value logic in Sema.zig.
3607 const empty = try mod.intern(.{ .aggregate = .{
3608 .ty = ty.ip_index,3602 .ty = ty.ip_index,
3609 .fields = &.{},3603 .fields = tuple.values,
3610 } });3604 } })).toValue();
3611 return empty.toValue();
3612 },3605 },
36133606
3614 .union_type => |union_type| {3607 .union_type => |union_type| {
...@@ -4477,7 +4470,7 @@ pub const Type = struct {...@@ -4477,7 +4470,7 @@ pub const Type = struct {
4477 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;4470 const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
4478 return struct_obj.is_tuple;4471 return struct_obj.is_tuple;
4479 },4472 },
4480 .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0,4473 .anon_struct_type => true,
4481 else => false,4474 else => false,
4482 };4475 };
4483 }4476 }