InternPool: add repeated aggregate storage

This commit is contained in:
Jacob Young
2023-05-19 21:35:55 -04:00
committed by Andrew Kelley
parent 9ff514b6a3
commit d28fc5bacb
4 changed files with 104 additions and 24 deletions

View File

@@ -506,7 +506,12 @@ pub const Key = union(enum) {
pub const Aggregate = struct {
ty: Index,
fields: []const Index,
storage: Storage,
pub const Storage = union(enum) {
elems: []const Index,
repeated_elem: Index,
};
};
pub fn hash32(key: Key) u32 {
@@ -578,7 +583,14 @@ pub const Key = union(enum) {
.aggregate => |aggregate| {
std.hash.autoHash(hasher, aggregate.ty);
for (aggregate.fields) |field| std.hash.autoHash(hasher, field);
std.hash.autoHash(hasher, @as(
@typeInfo(Key.Aggregate.Storage).Union.tag_type.?,
aggregate.storage,
));
switch (aggregate.storage) {
.elems => |elems| for (elems) |elem| std.hash.autoHash(hasher, elem),
.repeated_elem => |elem| std.hash.autoHash(hasher, elem),
}
},
.error_set_type => |error_set_type| {
@@ -756,7 +768,14 @@ pub const Key = union(enum) {
.aggregate => |a_info| {
const b_info = b.aggregate;
if (a_info.ty != b_info.ty) return false;
return std.mem.eql(Index, a_info.fields, b_info.fields);
const StorageTag = @typeInfo(Key.Aggregate.Storage).Union.tag_type.?;
if (@as(StorageTag, a_info.storage) != @as(StorageTag, b_info.storage)) return false;
return switch (a_info.storage) {
.elems => |a_elems| std.mem.eql(Index, a_elems, b_info.storage.elems),
.repeated_elem => |a_elem| a_elem == b_info.storage.repeated_elem,
};
},
.anon_struct_type => |a_info| {
const b_info = b.anon_struct_type;
@@ -1407,6 +1426,9 @@ pub const Tag = enum(u8) {
/// An instance of a struct, array, or vector.
/// data is extra index to `Aggregate`.
aggregate,
/// An instance of an array or vector with every element being the same value.
/// data is extra index to `Repeated`.
repeated,
};
/// Trailing:
@@ -1446,6 +1468,13 @@ pub const Aggregate = struct {
ty: Index,
};
pub const Repeated = struct {
/// The type of the aggregate.
ty: Index,
/// The value of every element.
elem_val: Index,
};
/// Trailing:
/// 0. type: Index for each fields_len
/// 1. value: Index for each fields_len
@@ -2049,13 +2078,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
// as the tuple case below).
.struct_type => .{ .aggregate = .{
.ty = ty,
.fields = &.{},
.storage = .{ .elems = &.{} },
} },
// There is only one possible value precisely due to the
// fact that this values slice is fully populated!
.anon_struct_type => |anon_struct_type| .{ .aggregate = .{
.ty = ty,
.fields = anon_struct_type.values,
.storage = .{ .elems = anon_struct_type.values },
} },
else => unreachable,
};
@@ -2066,7 +2095,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
const fields = @ptrCast([]const Index, ip.extra.items[extra.end..][0..len]);
return .{ .aggregate = .{
.ty = extra.data.ty,
.fields = fields,
.storage = .{ .elems = fields },
} };
},
.repeated => {
const extra = ip.extraData(Repeated, data);
return .{ .aggregate = .{
.ty = extra.ty,
.storage = .{ .repeated_elem = extra.elem_val },
} };
},
.union_value => .{ .un = ip.extraData(Key.Union, data) },
@@ -2663,10 +2699,18 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.aggregate => |aggregate| {
assert(aggregate.ty != .none);
for (aggregate.fields) |elem| assert(elem != .none);
assert(aggregate.fields.len == ip.aggregateTypeLen(aggregate.ty));
const aggregate_len = ip.aggregateTypeLen(aggregate.ty);
switch (aggregate.storage) {
.elems => |elems| {
assert(elems.len == aggregate_len);
for (elems) |elem| assert(elem != .none);
},
.repeated_elem => |elem| {
assert(elem != .none);
},
}
if (aggregate.fields.len == 0) {
if (aggregate_len == 0) {
ip.items.appendAssumeCapacity(.{
.tag = .only_possible_value,
.data = @enumToInt(aggregate.ty),
@@ -2676,7 +2720,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
switch (ip.indexToKey(aggregate.ty)) {
.anon_struct_type => |anon_struct_type| {
if (std.mem.eql(Index, anon_struct_type.values, aggregate.fields)) {
if (switch (aggregate.storage) {
.elems => |elems| std.mem.eql(Index, anon_struct_type.values, elems),
.repeated_elem => |elem| for (anon_struct_type.values) |value| {
if (value != elem) break false;
} else true,
}) {
// This encoding works thanks to the fact that, as we just verified,
// the type itself contains a slice of values that can be provided
// in the aggregate fields.
@@ -2690,9 +2739,33 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
else => {},
}
if (switch (aggregate.storage) {
.elems => |elems| for (elems[1..]) |elem| {
if (elem != elems[0]) break false;
} else true,
.repeated_elem => true,
}) {
try ip.extra.ensureUnusedCapacity(
gpa,
@typeInfo(Repeated).Struct.fields.len,
);
ip.items.appendAssumeCapacity(.{
.tag = .repeated,
.data = ip.addExtraAssumeCapacity(Repeated{
.ty = aggregate.ty,
.elem_val = switch (aggregate.storage) {
.elems => |elems| elems[0],
.repeated_elem => |elem| elem,
},
}),
});
return @intToEnum(Index, ip.items.len - 1);
}
try ip.extra.ensureUnusedCapacity(
gpa,
@typeInfo(Aggregate).Struct.fields.len + aggregate.fields.len,
@typeInfo(Aggregate).Struct.fields.len + aggregate_len,
);
ip.items.appendAssumeCapacity(.{
@@ -2701,7 +2774,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.ty = aggregate.ty,
}),
});
ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, aggregate.fields));
ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, aggregate.storage.elems));
},
.un => |un| {
@@ -3417,6 +3490,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
const fields_len = @intCast(u32, ip.aggregateTypeLen(info.ty));
break :b @sizeOf(Aggregate) + (@sizeOf(u32) * fields_len);
},
.repeated => @sizeOf(Repeated),
.float_f16 => 0,
.float_f32 => 0,

View File

@@ -12671,7 +12671,7 @@ fn analyzeTupleCat(
const runtime_src = opt_runtime_src orelse {
const tuple_val = try mod.intern(.{ .aggregate = .{
.ty = tuple_ty,
.fields = values,
.storage = .{ .elems = values },
} });
return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
};
@@ -12989,7 +12989,7 @@ fn analyzeTupleMul(
const runtime_src = opt_runtime_src orelse {
const tuple_val = try mod.intern(.{ .aggregate = .{
.ty = tuple_ty,
.fields = values,
.storage = .{ .elems = values },
} });
return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
};
@@ -18227,7 +18227,7 @@ fn zirStructInitAnon(
const runtime_index = opt_runtime_index orelse {
const tuple_val = try mod.intern(.{ .aggregate = .{
.ty = tuple_ty,
.fields = values,
.storage = .{ .elems = values },
} });
return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
};
@@ -18442,7 +18442,7 @@ fn zirArrayInitAnon(
const runtime_src = opt_runtime_src orelse {
const tuple_val = try mod.intern(.{ .aggregate = .{
.ty = tuple_ty,
.fields = values,
.storage = .{ .elems = values },
} });
return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
};
@@ -29176,7 +29176,7 @@ fn coerceTupleToTuple(
tuple_ty,
(try mod.intern(.{ .aggregate = .{
.ty = tuple_ty.ip_index,
.fields = field_vals,
.storage = .{ .elems = field_vals },
} })).toValue(),
);
}
@@ -33085,7 +33085,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
// one-possible-value in type.zig.
const empty = try mod.intern(.{ .aggregate = .{
.ty = ty.ip_index,
.fields = &.{},
.storage = .{ .elems = &.{} },
} });
return empty.toValue();
},
@@ -33098,7 +33098,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
// therefore has one possible value.
return (try mod.intern(.{ .aggregate = .{
.ty = ty.ip_index,
.fields = tuple.values,
.storage = .{ .elems = tuple.values },
} })).toValue();
},

View File

@@ -2738,7 +2738,7 @@ pub const Type = struct {
// one-possible-value logic in Sema.zig.
const empty = try mod.intern(.{ .aggregate = .{
.ty = ty.ip_index,
.fields = &.{},
.storage = .{ .elems = &.{} },
} });
return empty.toValue();
},
@@ -2751,7 +2751,7 @@ pub const Type = struct {
// therefore has one possible value.
return (try mod.intern(.{ .aggregate = .{
.ty = ty.ip_index,
.fields = tuple.values,
.storage = .{ .elems = tuple.values },
} })).toValue();
},

View File

@@ -2665,7 +2665,10 @@ pub const Value = struct {
else => unreachable,
},
else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
.aggregate => |aggregate| aggregate.fields[index].toValue(),
.aggregate => |aggregate| switch (aggregate.storage) {
.elems => |elems| elems[index],
.repeated_elem => |elem| elem,
}.toValue(),
else => unreachable,
},
}
@@ -2753,8 +2756,11 @@ pub const Value = struct {
else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
.undef => return true,
.simple_value => |v| if (v == .undefined) return true,
.aggregate => |aggregate| for (aggregate.fields) |field| {
if (try anyUndef(field.toValue(), mod)) return true;
.aggregate => |aggregate| switch (aggregate.storage) {
.elems => |elems| for (elems) |elem| {
if (try anyUndef(elem.toValue(), mod)) return true;
},
.repeated_elem => |elem| if (try anyUndef(elem.toValue(), mod)) return true,
},
else => {},
},