authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-08 11:51:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:42:30-07:00
log68b95a39b1fe734b938ec02fa2b16bbb63170f87
treeb86f3f97c04c23ad7e23d910d0fe65d5b06f27b4
parentfd674d95bee4815783bb282c80ba6af369296706

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

4 files changed, 212 insertions(+), 71 deletions(-)

src/InternPool.zig+135-45
......@@ -55,6 +55,7 @@ pub const Key = union(enum) {
5555 lib_name: u32,
5656 },
5757 int: Key.Int,
58 ptr: Key.Ptr,
5859 enum_tag: struct {
5960 ty: Index,
6061 tag: BigIntConst,
......@@ -140,6 +141,16 @@ pub const Key = union(enum) {
140141 };
141142 };
142143
144 pub const Ptr = struct {
145 ty: Index,
146 addr: Addr,
147
148 pub const Addr = union(enum) {
149 decl: DeclIndex,
150 int: Index,
151 };
152 };
153
143154 pub fn hash32(key: Key) u32 {
144155 return @truncate(u32, key.hash64());
145156 }
......@@ -176,6 +187,16 @@ pub const Key = union(enum) {
176187 for (big_int.limbs) |limb| std.hash.autoHash(hasher, limb);
177188 },
178189
190 .ptr => |ptr| {
191 std.hash.autoHash(hasher, ptr.ty);
192 // Int-to-ptr pointers are hashed separately than decl-referencing pointers.
193 // This is sound due to pointer province rules.
194 switch (ptr.addr) {
195 .int => |int| std.hash.autoHash(hasher, int),
196 .decl => @panic("TODO"),
197 }
198 },
199
179200 .enum_tag => |enum_tag| {
180201 std.hash.autoHash(hasher, enum_tag.ty);
181202 std.hash.autoHash(hasher, enum_tag.tag.positive);
......@@ -237,8 +258,30 @@ pub const Key = union(enum) {
237258 return std.meta.eql(a_info, b_info);
238259 },
239260
261 .ptr => |a_info| {
262 const b_info = b.ptr;
263
264 if (a_info.ty != b_info.ty)
265 return false;
266
267 return switch (a_info.addr) {
268 .int => |a_int| switch (b_info.addr) {
269 .int => |b_int| a_int == b_int,
270 .decl => false,
271 },
272 .decl => |a_decl| switch (b_info.addr) {
273 .int => false,
274 .decl => |b_decl| a_decl == b_decl,
275 },
276 };
277 },
278
240279 .int => |a_info| {
241280 const b_info = b.int;
281
282 if (a_info.ty != b_info.ty)
283 return false;
284
242285 return switch (a_info.storage) {
243286 .u64 => |aa| switch (b_info.storage) {
244287 .u64 => |bb| aa == bb,
......@@ -298,9 +341,11 @@ pub const Key = union(enum) {
298341 .union_type,
299342 => return .type_type,
300343
301 .int => |x| return x.ty,
302 .extern_func => |x| return x.ty,
303 .enum_tag => |x| return x.ty,
344 inline .ptr,
345 .int,
346 .extern_func,
347 .enum_tag,
348 => |x| return x.ty,
304349
305350 .simple_value => |s| switch (s) {
306351 .undefined => return .undefined_type,
......@@ -724,6 +769,9 @@ pub const Tag = enum(u8) {
724769 /// only an enum tag, but will be presented via the API with a different Key.
725770 /// data is SimpleInternal enum value.
726771 simple_internal,
772 /// A pointer to an integer value.
773 /// data is extra index of PtrInt, which contains the type and address.
774 ptr_int,
727775 /// Type: u8
728776 /// data is integer value
729777 int_u8,
......@@ -897,16 +945,13 @@ pub const Array = struct {
897945 child: Index,
898946 sentinel: Index,
899947
900 pub const Length = packed struct(u64) {
901 len0: u32,
902 len1: u32,
903 };
948 pub const Length = PackedU64;
904949
905950 pub fn getLength(a: Array) u64 {
906 return @bitCast(u64, Length{
907 .len0 = a.len0,
908 .len1 = a.len1,
909 });
951 return (PackedU64{
952 .a = a.len0,
953 .b = a.len1,
954 }).get();
910955 }
911956};
912957
......@@ -929,6 +974,24 @@ pub const EnumSimple = struct {
929974 fields_len: u32,
930975};
931976
977pub const PackedU64 = packed struct(u64) {
978 a: u32,
979 b: u32,
980
981 pub fn get(x: PackedU64) u64 {
982 return @bitCast(u64, x);
983 }
984
985 pub fn init(x: u64) PackedU64 {
986 return @bitCast(PackedU64, x);
987 }
988};
989
990pub const PtrInt = struct {
991 ty: Index,
992 addr: Index,
993};
994
932995/// Trailing: Limb for every limbs_len
933996pub const Int = struct {
934997 ty: Index,
......@@ -1066,6 +1129,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
10661129 .fields_len = 0,
10671130 } },
10681131 },
1132 .ptr_int => {
1133 const info = ip.extraData(PtrInt, data);
1134 return .{ .ptr = .{
1135 .ty = info.ty,
1136 .addr = .{ .int = info.addr },
1137 } };
1138 },
10691139 .int_u8 => .{ .int = .{
10701140 .ty = .u8_type,
10711141 .storage = .{ .u64 = data },
......@@ -1188,12 +1258,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
11881258 }
11891259 }
11901260
1191 const length = @bitCast(Array.Length, array_type.len);
1261 const length = Array.Length.init(array_type.len);
11921262 ip.items.appendAssumeCapacity(.{
11931263 .tag = .type_array_big,
11941264 .data = try ip.addExtra(gpa, Array{
1195 .len0 = length.len0,
1196 .len1 = length.len1,
1265 .len0 = length.a,
1266 .len1 = length.b,
11971267 .child = array_type.child,
11981268 .sentinel = array_type.sentinel,
11991269 }),
......@@ -1237,6 +1307,20 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
12371307 },
12381308 .extern_func => @panic("TODO"),
12391309
1310 .ptr => |ptr| switch (ptr.addr) {
1311 .decl => @panic("TODO"),
1312 .int => |int| {
1313 assert(ptr.ty != .none);
1314 ip.items.appendAssumeCapacity(.{
1315 .tag = .ptr_int,
1316 .data = try ip.addExtra(gpa, PtrInt{
1317 .ty = ptr.ty,
1318 .addr = int,
1319 }),
1320 });
1321 },
1322 },
1323
12401324 .int => |int| b: {
12411325 switch (int.ty) {
12421326 .none => unreachable,
......@@ -1620,38 +1704,43 @@ pub fn slicePtrType(ip: InternPool, i: Index) Index {
16201704 }
16211705}
16221706
1623/// Given an existing integer value, returns the same numerical value but with
1624/// the supplied type.
1625pub fn getCoercedInt(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
1626 const key = ip.indexToKey(val);
1627 // The key cannot be passed directly to `get`, otherwise in the case of
1628 // big_int storage, the limbs would be invalidated before they are read.
1629 // Here we pre-reserve the limbs to ensure that the logic in `addInt` will
1630 // not use an invalidated limbs pointer.
1631 switch (key.int.storage) {
1632 .u64 => |x| return ip.get(gpa, .{ .int = .{
1633 .ty = new_ty,
1634 .storage = .{ .u64 = x },
1635 } }),
1636 .i64 => |x| return ip.get(gpa, .{ .int = .{
1637 .ty = new_ty,
1638 .storage = .{ .i64 = x },
1639 } }),
1640
1641 .big_int => |big_int| {
1642 const positive = big_int.positive;
1643 const limbs = ip.limbsSliceToIndex(big_int.limbs);
1644 // This line invalidates the limbs slice, but the indexes computed in the
1645 // previous line are still correct.
1646 try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len);
1647 return ip.get(gpa, .{ .int = .{
1648 .ty = new_ty,
1649 .storage = .{ .big_int = .{
1650 .limbs = ip.limbsIndexToSlice(limbs),
1651 .positive = positive,
1652 } },
1653 } });
1707/// Given an existing value, returns the same value but with the supplied type.
1708/// Only some combinations are allowed:
1709/// * int to int
1710pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
1711 switch (ip.indexToKey(val)) {
1712 .int => |int| {
1713 // The key cannot be passed directly to `get`, otherwise in the case of
1714 // big_int storage, the limbs would be invalidated before they are read.
1715 // Here we pre-reserve the limbs to ensure that the logic in `addInt` will
1716 // not use an invalidated limbs pointer.
1717 switch (int.storage) {
1718 .u64 => |x| return ip.get(gpa, .{ .int = .{
1719 .ty = new_ty,
1720 .storage = .{ .u64 = x },
1721 } }),
1722 .i64 => |x| return ip.get(gpa, .{ .int = .{
1723 .ty = new_ty,
1724 .storage = .{ .i64 = x },
1725 } }),
1726
1727 .big_int => |big_int| {
1728 const positive = big_int.positive;
1729 const limbs = ip.limbsSliceToIndex(big_int.limbs);
1730 // This line invalidates the limbs slice, but the indexes computed in the
1731 // previous line are still correct.
1732 try reserveLimbs(ip, gpa, @typeInfo(Int).Struct.fields.len + big_int.limbs.len);
1733 return ip.get(gpa, .{ .int = .{
1734 .ty = new_ty,
1735 .storage = .{ .big_int = .{
1736 .limbs = ip.limbsIndexToSlice(limbs),
1737 .positive = positive,
1738 } },
1739 } });
1740 },
1741 }
16541742 },
1743 else => unreachable,
16551744 }
16561745}
16571746
......@@ -1708,6 +1797,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void {
17081797 .simple_type => 0,
17091798 .simple_value => 0,
17101799 .simple_internal => 0,
1800 .ptr_int => @sizeOf(PtrInt),
17111801 .int_u8 => 0,
17121802 .int_u16 => 0,
17131803 .int_u32 => 0,
src/Module.zig+12-6
......@@ -6887,17 +6887,23 @@ pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
68876887 return ptrType(mod, .{ .elem_type = child_type.ip_index, .is_const = true });
68886888}
68896889
6890pub fn ptrIntValue(mod: *Module, ty: Type, x: u64) Allocator.Error!Value {
6891 assert(ty.zigTypeTag(mod) == .Pointer);
6892 const i = try intern(mod, .{ .ptr = .{
6893 .ty = ty.ip_index,
6894 .addr = .{ .int = try intern(mod, .{ .int = .{
6895 .ty = ty.ip_index,
6896 .storage = .{ .u64 = x },
6897 } }) },
6898 } });
6899 return i.toValue();
6900}
6901
68906902pub fn intValue(mod: *Module, ty: Type, x: anytype) Allocator.Error!Value {
68916903 if (std.debug.runtime_safety) {
6892 // TODO: decide if this also works for ABI int types like enums
68936904 const tag = ty.zigTypeTag(mod);
68946905 assert(tag == .Int or tag == .ComptimeInt);
68956906 }
6896 if (@TypeOf(x) == comptime_int) {
6897 if (comptime std.math.cast(u64, x)) |casted| return intValue_u64(mod, ty, casted);
6898 if (comptime std.math.cast(i64, x)) |casted| return intValue_i64(mod, ty, casted);
6899 @compileError("Out-of-range comptime_int passed to Module.intValue");
6900 }
69016907 if (std.math.cast(u64, x)) |casted| return intValue_u64(mod, ty, casted);
69026908 if (std.math.cast(i64, x)) |casted| return intValue_i64(mod, ty, casted);
69036909 var limbs_buffer: [4]usize = undefined;
src/Sema.zig+30-9
......@@ -15096,7 +15096,7 @@ fn analyzePtrArithmetic(
1509615096 .ptr_sub => addr - elem_size * offset_int,
1509715097 else => unreachable,
1509815098 };
15099 const new_ptr_val = try mod.intValue(new_ptr_ty, new_addr);
15099 const new_ptr_val = try mod.ptrIntValue(new_ptr_ty, new_addr);
1510015100 return sema.addConstant(new_ptr_ty, new_ptr_val);
1510115101 }
1510215102 if (air_tag == .ptr_sub) {
......@@ -19931,7 +19931,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1993119931 if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0)
1993219932 return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
1993319933
19934 return sema.addConstant(ptr_ty, try mod.intValue(ptr_ty, addr));
19934 return sema.addConstant(ptr_ty, try mod.ptrIntValue(ptr_ty, addr));
1993519935 }
1993619936
1993719937 try sema.requireRuntimeBlock(block, src, operand_src);
......@@ -25640,8 +25640,13 @@ fn coerceExtra(
2564025640 var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
2564125641 if (in_memory_result == .ok) {
2564225642 if (maybe_inst_val) |val| {
25643 // Keep the comptime Value representation; take the new type.
25644 return sema.addConstant(dest_ty, val);
25643 if (val.ip_index == .none or val.ip_index == .null_value) {
25644 // Keep the comptime Value representation; take the new type.
25645 return sema.addConstant(dest_ty, val);
25646 } else {
25647 const new_val = try mod.intern_pool.getCoerced(mod.gpa, val.ip_index, dest_ty.ip_index);
25648 return sema.addConstant(dest_ty, new_val.toValue());
25649 }
2564525650 }
2564625651 try sema.requireRuntimeBlock(block, inst_src, null);
2564725652 return block.addBitCast(dest_ty, inst);
......@@ -26014,7 +26019,7 @@ fn coerceExtra(
2601426019 if (!opts.report_err) return error.NotCoercible;
2601526020 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
2601626021 }
26017 const new_val = try mod.intern_pool.getCoercedInt(sema.gpa, val.ip_index, dest_ty.ip_index);
26022 const new_val = try mod.intern_pool.getCoerced(sema.gpa, val.ip_index, dest_ty.ip_index);
2601826023 return try sema.addConstant(dest_ty, new_val.toValue());
2601926024 }
2602026025 if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
......@@ -31673,10 +31678,13 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3167331678 },
3167431679 .struct_type => @panic("TODO"),
3167531680 .union_type => @panic("TODO"),
31681
31682 // values, not types
3167631683 .simple_value => unreachable,
3167731684 .extern_func => unreachable,
3167831685 .int => unreachable,
31679 .enum_tag => unreachable, // it's a value, not a type
31686 .ptr => unreachable,
31687 .enum_tag => unreachable,
3168031688 },
3168131689 };
3168231690}
......@@ -33193,10 +33201,13 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3319333201 },
3319433202 .struct_type => @panic("TODO"),
3319533203 .union_type => @panic("TODO"),
33204
33205 // values, not types
3319633206 .simple_value => unreachable,
3319733207 .extern_func => unreachable,
3319833208 .int => unreachable,
33199 .enum_tag => unreachable, // it's a value, not a type
33209 .ptr => unreachable,
33210 .enum_tag => unreachable,
3320033211 },
3320133212 }
3320233213}
......@@ -33253,7 +33264,14 @@ pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
3325333264 const result = Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
3325433265 // This assertion can be removed when the `ty` parameter is removed from
3325533266 // this function thanks to the InternPool transition being complete.
33256 assert(Type.eql(sema.typeOf(result), ty, sema.mod));
33267 if (std.debug.runtime_safety) {
33268 const val_ty = sema.typeOf(result);
33269 if (!Type.eql(val_ty, ty, sema.mod)) {
33270 std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{
33271 ty.fmt(sema.mod), val_ty.fmt(sema.mod),
33272 });
33273 }
33274 }
3325733275 return result;
3325833276 }
3325933277 const ty_inst = try sema.addType(ty);
......@@ -33752,10 +33770,13 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
3375233770 },
3375333771 .struct_type => @panic("TODO"),
3375433772 .union_type => @panic("TODO"),
33773
33774 // values, not types
3375533775 .simple_value => unreachable,
3375633776 .extern_func => unreachable,
3375733777 .int => unreachable,
33758 .enum_tag => unreachable, // it's a value, not a type
33778 .ptr => unreachable,
33779 .enum_tag => unreachable,
3375933780 },
3376033781 };
3376133782}
src/type.zig+35-11
......@@ -142,11 +142,12 @@ pub const Type = struct {
142142 .var_args_param => unreachable,
143143 },
144144
145 .extern_func,
146 .int,
147 .enum_tag,
148 .simple_value,
149 => unreachable, // it's a value, not a type
145 // values, not types
146 .extern_func => unreachable,
147 .int => unreachable,
148 .ptr => unreachable,
149 .enum_tag => unreachable,
150 .simple_value => unreachable,
150151 },
151152 }
152153 }
......@@ -1576,6 +1577,7 @@ pub const Type = struct {
15761577 .simple_value => unreachable,
15771578 .extern_func => unreachable,
15781579 .int => unreachable,
1580 .ptr => unreachable,
15791581 .enum_tag => unreachable,
15801582 },
15811583 }
......@@ -1842,10 +1844,13 @@ pub const Type = struct {
18421844 },
18431845 .struct_type => @panic("TODO"),
18441846 .union_type => @panic("TODO"),
1847
1848 // values, not types
18451849 .simple_value => unreachable,
18461850 .extern_func => unreachable,
18471851 .int => unreachable,
1848 .enum_tag => unreachable, // it's a value, not a type
1852 .ptr => unreachable,
1853 .enum_tag => unreachable,
18491854 },
18501855 }
18511856 }
......@@ -1950,10 +1955,13 @@ pub const Type = struct {
19501955 },
19511956 .struct_type => @panic("TODO"),
19521957 .union_type => @panic("TODO"),
1958
1959 // values, not types
19531960 .simple_value => unreachable,
19541961 .extern_func => unreachable,
19551962 .int => unreachable,
1956 .enum_tag => unreachable, // it's a value, not a type
1963 .ptr => unreachable,
1964 .enum_tag => unreachable,
19571965 },
19581966 };
19591967 }
......@@ -2348,10 +2356,13 @@ pub const Type = struct {
23482356 },
23492357 .struct_type => @panic("TODO"),
23502358 .union_type => @panic("TODO"),
2359
2360 // values, not types
23512361 .simple_value => unreachable,
23522362 .extern_func => unreachable,
23532363 .int => unreachable,
2354 .enum_tag => unreachable, // it's a value, not a type
2364 .ptr => unreachable,
2365 .enum_tag => unreachable,
23552366 },
23562367 }
23572368 }
......@@ -2759,10 +2770,13 @@ pub const Type = struct {
27592770 },
27602771 .struct_type => @panic("TODO"),
27612772 .union_type => @panic("TODO"),
2773
2774 // values, not types
27622775 .simple_value => unreachable,
27632776 .extern_func => unreachable,
27642777 .int => unreachable,
2765 .enum_tag => unreachable, // it's a value, not a type
2778 .ptr => unreachable,
2779 .enum_tag => unreachable,
27662780 },
27672781 }
27682782 }
......@@ -2926,10 +2940,13 @@ pub const Type = struct {
29262940 },
29272941 .struct_type => @panic("TODO"),
29282942 .union_type => @panic("TODO"),
2943
2944 // values, not types
29292945 .simple_value => unreachable,
29302946 .extern_func => unreachable,
29312947 .int => unreachable,
2932 .enum_tag => unreachable, // it's a value, not a type
2948 .ptr => unreachable,
2949 .enum_tag => unreachable,
29332950 };
29342951
29352952 const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
......@@ -3780,9 +3797,12 @@ pub const Type = struct {
37803797 .simple_type => unreachable, // handled via Index enum tag above
37813798 .struct_type => @panic("TODO"),
37823799 .union_type => unreachable,
3800
3801 // values, not types
37833802 .simple_value => unreachable,
37843803 .extern_func => unreachable,
37853804 .int => unreachable,
3805 .ptr => unreachable,
37863806 .enum_tag => unreachable,
37873807 },
37883808 };
......@@ -4152,10 +4172,13 @@ pub const Type = struct {
41524172 },
41534173 .struct_type => @panic("TODO"),
41544174 .union_type => @panic("TODO"),
4175
4176 // values, not types
41554177 .simple_value => unreachable,
41564178 .extern_func => unreachable,
41574179 .int => unreachable,
4158 .enum_tag => unreachable, // it's a value, not a type
4180 .ptr => unreachable,
4181 .enum_tag => unreachable,
41594182 },
41604183 };
41614184 }
......@@ -4319,6 +4342,7 @@ pub const Type = struct {
43194342 .simple_value => unreachable,
43204343 .extern_func => unreachable,
43214344 .int => unreachable,
4345 .ptr => unreachable,
43224346 .enum_tag => unreachable, // it's a value, not a type
43234347 },
43244348 };