InternPool: add repeated aggregate storage
This commit is contained in:
committed by
Andrew Kelley
parent
9ff514b6a3
commit
d28fc5bacb
@@ -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,
|
||||
|
||||
14
src/Sema.zig
14
src/Sema.zig
@@ -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();
|
||||
},
|
||||
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
|
||||
@@ -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 => {},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user