aboutsummaryrefslogtreecommitdiff
path: root/src/InternPool.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2023-05-08 11:51:32 -0700
committerAndrew Kelley <andrew@ziglang.org>2023-06-10 20:42:30 -0700
commit68b95a39b1fe734b938ec02fa2b16bbb63170f87 (patch)
treeb86f3f97c04c23ad7e23d910d0fe65d5b06f27b4 /src/InternPool.zig
parentfd674d95bee4815783bb282c80ba6af369296706 (diff)
downloadzig-68b95a39b1fe734b938ec02fa2b16bbb63170f87.tar.gz
zig-68b95a39b1fe734b938ec02fa2b16bbb63170f87.zip
InternPool: add ptr-to-int value
Also modify coercion in Sema to be InternPool-aware by calling getCoerced. The unnecessary comptime logic in mod.intValue is deleted too
Diffstat (limited to 'src/InternPool.zig')
-rw-r--r--src/InternPool.zig180
1 files changed, 135 insertions, 45 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig
index a49b98bd50..27d0fb9445 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -55,6 +55,7 @@ pub const Key = union(enum) {
lib_name: u32,
},
int: Key.Int,
+ ptr: Key.Ptr,
enum_tag: struct {
ty: Index,
tag: BigIntConst,
@@ -140,6 +141,16 @@ pub const Key = union(enum) {
};
};
+ pub const Ptr = struct {
+ ty: Index,
+ addr: Addr,
+
+ pub const Addr = union(enum) {
+ decl: DeclIndex,
+ int: Index,
+ };
+ };
+
pub fn hash32(key: Key) u32 {
return @truncate(u32, key.hash64());
}
@@ -176,6 +187,16 @@ pub const Key = union(enum) {
for (big_int.limbs) |limb| std.hash.autoHash(hasher, limb);
},
+ .ptr => |ptr| {
+ std.hash.autoHash(hasher, ptr.ty);
+ // Int-to-ptr pointers are hashed separately than decl-referencing pointers.
+ // This is sound due to pointer province rules.
+ switch (ptr.addr) {
+ .int => |int| std.hash.autoHash(hasher, int),
+ .decl => @panic("TODO"),
+ }
+ },
+
.enum_tag => |enum_tag| {
std.hash.autoHash(hasher, enum_tag.ty);
std.hash.autoHash(hasher, enum_tag.tag.positive);
@@ -237,8 +258,30 @@ pub const Key = union(enum) {
return std.meta.eql(a_info, b_info);
},
+ .ptr => |a_info| {
+ const b_info = b.ptr;
+
+ if (a_info.ty != b_info.ty)
+ return false;
+
+ return switch (a_info.addr) {
+ .int => |a_int| switch (b_info.addr) {
+ .int => |b_int| a_int == b_int,
+ .decl => false,
+ },
+ .decl => |a_decl| switch (b_info.addr) {
+ .int => false,
+ .decl => |b_decl| a_decl == b_decl,
+ },
+ };
+ },
+
.int => |a_info| {
const b_info = b.int;
+
+ if (a_info.ty != b_info.ty)
+ return false;
+
return switch (a_info.storage) {
.u64 => |aa| switch (b_info.storage) {
.u64 => |bb| aa == bb,
@@ -298,9 +341,11 @@ pub const Key = union(enum) {
.union_type,
=> return .type_type,
- .int => |x| return x.ty,
- .extern_func => |x| return x.ty,
- .enum_tag => |x| return x.ty,
+ inline .ptr,
+ .int,
+ .extern_func,
+ .enum_tag,
+ => |x| return x.ty,
.simple_value => |s| switch (s) {
.undefined => return .undefined_type,
@@ -724,6 +769,9 @@ pub const Tag = enum(u8) {
/// only an enum tag, but will be presented via the API with a different Key.
/// data is SimpleInternal enum value.
simple_internal,
+ /// A pointer to an integer value.
+ /// data is extra index of PtrInt, which contains the type and address.
+ ptr_int,
/// Type: u8
/// data is integer value
int_u8,
@@ -897,16 +945,13 @@ pub const Array = struct {
child: Index,
sentinel: Index,
- pub const Length = packed struct(u64) {
- len0: u32,
- len1: u32,
- };
+ pub const Length = PackedU64;
pub fn getLength(a: Array) u64 {
- return @bitCast(u64, Length{
- .len0 = a.len0,
- .len1 = a.len1,
- });
+ return (PackedU64{
+ .a = a.len0,
+ .b = a.len1,
+ }).get();
}
};
@@ -929,6 +974,24 @@ pub const EnumSimple = struct {
fields_len: u32,
};
+pub const PackedU64 = packed struct(u64) {
+ a: u32,
+ b: u32,
+
+ pub fn get(x: PackedU64) u64 {
+ return @bitCast(u64, x);
+ }
+
+ pub fn init(x: u64) PackedU64 {
+ return @bitCast(PackedU64, x);
+ }
+};
+
+pub const PtrInt = struct {
+ ty: Index,
+ addr: Index,
+};
+
/// Trailing: Limb for every limbs_len
pub const Int = struct {
ty: Index,
@@ -1066,6 +1129,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.fields_len = 0,
} },
},
+ .ptr_int => {
+ const info = ip.extraData(PtrInt, data);
+ return .{ .ptr = .{
+ .ty = info.ty,
+ .addr = .{ .int = info.addr },
+ } };
+ },
.int_u8 => .{ .int = .{
.ty = .u8_type,
.storage = .{ .u64 = data },
@@ -1188,12 +1258,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
}
}
- const length = @bitCast(Array.Length, array_type.len);
+ const length = Array.Length.init(array_type.len);
ip.items.appendAssumeCapacity(.{
.tag = .type_array_big,
.data = try ip.addExtra(gpa, Array{
- .len0 = length.len0,
- .len1 = length.len1,
+ .len0 = length.a,
+ .len1 = length.b,
.child = array_type.child,
.sentinel = array_type.sentinel,
}),
@@ -1237,6 +1307,20 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
},
.extern_func => @panic("TODO"),
+ .ptr => |ptr| switch (ptr.addr) {
+ .decl => @panic("TODO"),
+ .int => |int| {
+ assert(ptr.ty != .none);
+ ip.items.appendAssumeCapacity(.{
+ .tag = .ptr_int,
+ .data = try ip.addExtra(gpa, PtrInt{
+ .ty = ptr.ty,
+ .addr = int,
+ }),
+ });
+ },
+ },
+
.int => |int| b: {
switch (int.ty) {
.none => unreachable,
@@ -1620,38 +1704,43 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index {
}
}
-/// Given an existing integer value, returns the same numerical value but with
-/// the supplied type.
-pub fn getCoercedInt(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
- const key = ip.indexToKey(val);
- // The key cannot be passed directly to `get`, otherwise in the case of
- // big_int storage, the limbs would be invalidated before they are read.
- // Here we pre-reserve the limbs to ensure that the logic in `addInt` will
- // not use an invalidated limbs pointer.
- switch (key.int.storage) {
- .u64 => |x| return ip.get(gpa, .{ .int = .{
- .ty = new_ty,
- .storage = .{ .u64 = x },
- } }),
- .i64 => |x| return ip.get(gpa, .{ .int = .{
- .ty = new_ty,
- .storage = .{ .i64 = x },
- } }),
-
- .big_int => |big_int| {
- const positive = big_int.positive;
- const limbs = ip.limbsSliceToIndex(big_int.limbs);
- // This line invalidates the limbs slice, but the indexes computed in the
- // previous line are still correct.
- try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len);
- return ip.get(gpa, .{ .int = .{
- .ty = new_ty,
- .storage = .{ .big_int = .{
- .limbs = ip.limbsIndexToSlice(limbs),
- .positive = positive,
- } },
- } });
+/// Given an existing value, returns the same value but with the supplied type.
+/// Only some combinations are allowed:
+/// * int to int
+pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
+ switch (ip.indexToKey(val)) {
+ .int => |int| {
+ // The key cannot be passed directly to `get`, otherwise in the case of
+ // big_int storage, the limbs would be invalidated before they are read.
+ // Here we pre-reserve the limbs to ensure that the logic in `addInt` will
+ // not use an invalidated limbs pointer.
+ switch (int.storage) {
+ .u64 => |x| return ip.get(gpa, .{ .int = .{
+ .ty = new_ty,
+ .storage = .{ .u64 = x },
+ } }),
+ .i64 => |x| return ip.get(gpa, .{ .int = .{
+ .ty = new_ty,
+ .storage = .{ .i64 = x },
+ } }),
+
+ .big_int => |big_int| {
+ const positive = big_int.positive;
+ const limbs = ip.limbsSliceToIndex(big_int.limbs);
+ // This line invalidates the limbs slice, but the indexes computed in the
+ // previous line are still correct.
+ try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len);
+ return ip.get(gpa, .{ .int = .{
+ .ty = new_ty,
+ .storage = .{ .big_int = .{
+ .limbs = ip.limbsIndexToSlice(limbs),
+ .positive = positive,
+ } },
+ } });
+ },
+ }
},
+ else => unreachable,
}
}
@@ -1708,6 +1797,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
.simple_type => 0,
.simple_value => 0,
.simple_internal => 0,
+ .ptr_int => @sizeOf(PtrInt),
.int_u8 => 0,
.int_u16 => 0,
.int_u32 => 0,