authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-05 13:26:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:42:28-07:00
logac07ddadeb36019c262b4f28a4fa3884f6f50b32
tree3dc3f2ea03f2faa5b110001b6dd0d9dff567de0e
parent75cf06c187d9d0288c2ea31f34b18c3a7da4bd1d

InternPool: enhance integer values

The Key struct now has a Storage tagged union which can store a u64, i64, or big int. This is needed so that indexToKey can be implemented for integers stored compactly in the data structure.

3 files changed, 257 insertions(+), 135 deletions(-)

src/InternPool.zig+166-78
......@@ -11,6 +11,7 @@ const std = @import("std");
1111const Allocator = std.mem.Allocator;
1212const assert = std.debug.assert;
1313const BigIntConst = std.math.big.int.Const;
14const BigIntMutable = std.math.big.int.Mutable;
1415
1516const InternPool = @This();
1617const DeclIndex = enum(u32) { _ };
......@@ -50,10 +51,7 @@ pub const Key = union(enum) {
5051 /// Index into the string table bytes.
5152 lib_name: u32,
5253 },
53 int: struct {
54 ty: Index,
55 big_int: BigIntConst,
56 },
54 int: Key.Int,
5755 enum_tag: struct {
5856 ty: Index,
5957 tag: BigIntConst,
......@@ -110,6 +108,32 @@ pub const Key = union(enum) {
110108 child: Index,
111109 };
112110
111 pub const Int = struct {
112 ty: Index,
113 storage: Storage,
114
115 pub const Storage = union(enum) {
116 u64: u64,
117 i64: i64,
118 big_int: BigIntConst,
119
120 /// Big enough to fit any non-BigInt value
121 pub const BigIntSpace = struct {
122 /// The +1 is headroom so that operations such as incrementing once
123 /// or decrementing once are possible without using an allocator.
124 limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb,
125 };
126
127 pub fn toBigInt(storage: Storage, space: *BigIntSpace) BigIntConst {
128 return switch (storage) {
129 .big_int => |x| x,
130 .u64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),
131 .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),
132 };
133 }
134 };
135 };
136
113137 pub fn hash32(key: Key) u32 {
114138 return @truncate(u32, key.hash64());
115139 }
......@@ -137,9 +161,13 @@ pub const Key = union(enum) {
137161 => |info| std.hash.autoHash(hasher, info),
138162
139163 .int => |int| {
164 // Canonicalize all integers by converting them to BigIntConst.
165 var buffer: Key.Int.Storage.BigIntSpace = undefined;
166 const big_int = int.storage.toBigInt(&buffer);
167
140168 std.hash.autoHash(hasher, int.ty);
141 std.hash.autoHash(hasher, int.big_int.positive);
142 for (int.big_int.limbs) |limb| std.hash.autoHash(hasher, limb);
169 std.hash.autoHash(hasher, big_int.positive);
170 for (big_int.limbs) |limb| std.hash.autoHash(hasher, limb);
143171 },
144172
145173 .enum_tag => |enum_tag| {
......@@ -573,42 +601,27 @@ pub const static_keys = [_]Key{
573601
574602 .{ .int = .{
575603 .ty = .comptime_int_type,
576 .big_int = .{
577 .limbs = &.{0},
578 .positive = true,
579 },
604 .storage = .{ .u64 = 0 },
580605 } },
581606
582607 .{ .int = .{
583608 .ty = .usize_type,
584 .big_int = .{
585 .limbs = &.{0},
586 .positive = true,
587 },
609 .storage = .{ .u64 = 0 },
588610 } },
589611
590612 .{ .int = .{
591613 .ty = .u8_type,
592 .big_int = .{
593 .limbs = &.{0},
594 .positive = true,
595 },
614 .storage = .{ .u64 = 0 },
596615 } },
597616
598617 .{ .int = .{
599618 .ty = .comptime_int_type,
600 .big_int = .{
601 .limbs = &.{1},
602 .positive = true,
603 },
619 .storage = .{ .u64 = 1 },
604620 } },
605621
606622 .{ .int = .{
607623 .ty = .usize_type,
608 .big_int = .{
609 .limbs = &.{1},
610 .positive = true,
611 },
624 .storage = .{ .u64 = 1 },
612625 } },
613626
614627 .{ .enum_tag = .{
......@@ -680,19 +693,19 @@ pub const Tag = enum(u8) {
680693 simple_internal,
681694 /// Type: u32
682695 /// data is integer value
683 int_small_u32,
696 int_u32,
684697 /// Type: i32
685698 /// data is integer value bitcasted to u32.
686 int_small_i32,
699 int_i32,
687700 /// A usize that fits in 32 bits.
688701 /// data is integer value.
689 int_small_usize,
702 int_usize,
690703 /// A comptime_int that fits in a u32.
691704 /// data is integer value.
692 int_small_comptime_unsigned,
705 int_comptime_int_u32,
693706 /// A comptime_int that fits in an i32.
694707 /// data is integer value bitcasted to u32.
695 int_small_comptime_signed,
708 int_comptime_int_i32,
696709 /// A positive integer value.
697710 /// data is a limbs index to Int.
698711 int_positive,
......@@ -932,11 +945,26 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
932945 .type_error_union => @panic("TODO"),
933946 .type_enum_simple => @panic("TODO"),
934947 .simple_internal => @panic("TODO"),
935 .int_small_u32 => @panic("TODO"),
936 .int_small_i32 => @panic("TODO"),
937 .int_small_usize => @panic("TODO"),
938 .int_small_comptime_unsigned => @panic("TODO"),
939 .int_small_comptime_signed => @panic("TODO"),
948 .int_u32 => return .{ .int = .{
949 .ty = .u32_type,
950 .storage = .{ .u64 = data },
951 } },
952 .int_i32 => return .{ .int = .{
953 .ty = .i32_type,
954 .storage = .{ .i64 = @bitCast(i32, data) },
955 } },
956 .int_usize => return .{ .int = .{
957 .ty = .usize_type,
958 .storage = .{ .u64 = data },
959 } },
960 .int_comptime_int_u32 => return .{ .int = .{
961 .ty = .comptime_int_type,
962 .storage = .{ .u64 = data },
963 } },
964 .int_comptime_int_i32 => return .{ .int = .{
965 .ty = .comptime_int_type,
966 .storage = .{ .i64 = @bitCast(i32, data) },
967 } },
940968 .int_positive => @panic("TODO"),
941969 .int_negative => @panic("TODO"),
942970 .enum_tag_positive => @panic("TODO"),
......@@ -1041,54 +1069,114 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
10411069
10421070 .int => |int| b: {
10431071 switch (int.ty) {
1044 .u32_type => {
1045 if (int.big_int.fits(u32)) {
1046 ip.items.appendAssumeCapacity(.{
1047 .tag = .int_small_u32,
1048 .data = int.big_int.to(u32) catch unreachable,
1049 });
1050 break :b;
1051 }
1072 .u32_type => switch (int.storage) {
1073 .big_int => |big_int| {
1074 if (big_int.to(u32)) |casted| {
1075 ip.items.appendAssumeCapacity(.{
1076 .tag = .int_u32,
1077 .data = casted,
1078 });
1079 break :b;
1080 } else |_| {}
1081 },
1082 inline .u64, .i64 => |x| {
1083 if (std.math.cast(u32, x)) |casted| {
1084 ip.items.appendAssumeCapacity(.{
1085 .tag = .int_u32,
1086 .data = casted,
1087 });
1088 break :b;
1089 }
1090 },
10521091 },
1053 .i32_type => {
1054 if (int.big_int.fits(i32)) {
1055 ip.items.appendAssumeCapacity(.{
1056 .tag = .int_small_i32,
1057 .data = @bitCast(u32, int.big_int.to(i32) catch unreachable),
1058 });
1059 break :b;
1060 }
1092 .i32_type => switch (int.storage) {
1093 .big_int => |big_int| {
1094 if (big_int.to(i32)) |casted| {
1095 ip.items.appendAssumeCapacity(.{
1096 .tag = .int_i32,
1097 .data = @bitCast(u32, casted),
1098 });
1099 break :b;
1100 } else |_| {}
1101 },
1102 inline .u64, .i64 => |x| {
1103 if (std.math.cast(i32, x)) |casted| {
1104 ip.items.appendAssumeCapacity(.{
1105 .tag = .int_u32,
1106 .data = @bitCast(u32, casted),
1107 });
1108 break :b;
1109 }
1110 },
10611111 },
1062 .usize_type => {
1063 if (int.big_int.fits(u32)) {
1064 ip.items.appendAssumeCapacity(.{
1065 .tag = .int_small_usize,
1066 .data = int.big_int.to(u32) catch unreachable,
1067 });
1068 break :b;
1069 }
1112 .usize_type => switch (int.storage) {
1113 .big_int => |big_int| {
1114 if (big_int.to(u32)) |casted| {
1115 ip.items.appendAssumeCapacity(.{
1116 .tag = .int_usize,
1117 .data = casted,
1118 });
1119 break :b;
1120 } else |_| {}
1121 },
1122 inline .u64, .i64 => |x| {
1123 if (std.math.cast(u32, x)) |casted| {
1124 ip.items.appendAssumeCapacity(.{
1125 .tag = .int_usize,
1126 .data = casted,
1127 });
1128 break :b;
1129 }
1130 },
10701131 },
1071 .comptime_int_type => {
1072 if (int.big_int.fits(u32)) {
1073 ip.items.appendAssumeCapacity(.{
1074 .tag = .int_small_comptime_unsigned,
1075 .data = int.big_int.to(u32) catch unreachable,
1076 });
1077 break :b;
1078 }
1079 if (int.big_int.fits(i32)) {
1080 ip.items.appendAssumeCapacity(.{
1081 .tag = .int_small_comptime_signed,
1082 .data = @bitCast(u32, int.big_int.to(i32) catch unreachable),
1083 });
1084 break :b;
1085 }
1132 .comptime_int_type => switch (int.storage) {
1133 .big_int => |big_int| {
1134 if (big_int.to(u32)) |casted| {
1135 ip.items.appendAssumeCapacity(.{
1136 .tag = .int_comptime_int_u32,
1137 .data = casted,
1138 });
1139 break :b;
1140 } else |_| {}
1141 if (big_int.to(i32)) |casted| {
1142 ip.items.appendAssumeCapacity(.{
1143 .tag = .int_comptime_int_i32,
1144 .data = @bitCast(u32, casted),
1145 });
1146 break :b;
1147 } else |_| {}
1148 },
1149 inline .u64, .i64 => |x| {
1150 if (std.math.cast(u32, x)) |casted| {
1151 ip.items.appendAssumeCapacity(.{
1152 .tag = .int_comptime_int_u32,
1153 .data = casted,
1154 });
1155 break :b;
1156 }
1157 if (std.math.cast(i32, x)) |casted| {
1158 ip.items.appendAssumeCapacity(.{
1159 .tag = .int_comptime_int_i32,
1160 .data = @bitCast(u32, casted),
1161 });
1162 break :b;
1163 }
1164 },
10861165 },
10871166 else => {},
10881167 }
1089
1090 const tag: Tag = if (int.big_int.positive) .int_positive else .int_negative;
1091 try addInt(ip, gpa, int.ty, tag, int.big_int.limbs);
1168 switch (int.storage) {
1169 .big_int => |big_int| {
1170 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
1171 try addInt(ip, gpa, int.ty, tag, big_int.limbs);
1172 },
1173 inline .i64, .u64 => |x| {
1174 var buf: [2]usize = undefined;
1175 const big_int = BigIntMutable.init(&buf, x).toConst();
1176 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
1177 try addInt(ip, gpa, int.ty, tag, big_int.limbs);
1178 },
1179 }
10921180 },
10931181
10941182 .enum_tag => |enum_tag| {
src/Sema.zig+3-3
......@@ -1981,7 +1981,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
19811981 if (air_tags[i] == .constant) {
19821982 const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
19831983 const val = sema.air_values.items[ty_pl.payload];
1984 if (val.tag() == .variable) return val;
1984 if (val.tagIsVariable()) return val;
19851985 }
19861986 return opv;
19871987 }
......@@ -5033,7 +5033,7 @@ fn storeToInferredAllocComptime(
50335033 // There will be only one store_to_inferred_ptr because we are running at comptime.
50345034 // The alloc will turn into a Decl.
50355035 if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: {
5036 if (operand_val.tag() == .variable) break :store;
5036 if (operand_val.tagIsVariable()) break :store;
50375037 var anon_decl = try block.startAnonDecl();
50385038 defer anon_decl.deinit();
50395039 iac.data.decl_index = try anon_decl.finish(
......@@ -28125,7 +28125,7 @@ fn beginComptimePtrLoad(
2812528125 const is_mutable = ptr_val.tag() == .decl_ref_mut;
2812628126 const decl = sema.mod.declPtr(decl_index);
2812728127 const decl_tv = try decl.typedValue();
28128 if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;
28128 if (decl_tv.val.tagIsVariable()) return error.RuntimeLoad;
2812928129
2813028130 const layout_defined = decl.ty.hasWellDefinedLayout(mod);
2813128131 break :blk ComptimePtrLoadKit{
src/value.zig+88-54
......@@ -796,17 +796,17 @@ pub const Value = struct {
796796 mod: *const Module,
797797 opt_sema: ?*Sema,
798798 ) Module.CompileError!BigIntConst {
799 switch (val.ip_index) {
800 .bool_false => return BigIntMutable.init(&space.limbs, 0).toConst(),
801 .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(),
799 return switch (val.ip_index) {
800 .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),
801 .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),
802802 .undef => unreachable,
803 .null_value => return BigIntMutable.init(&space.limbs, 0).toConst(),
803 .null_value => BigIntMutable.init(&space.limbs, 0).toConst(),
804804 .none => switch (val.tag()) {
805805 .zero,
806806 .the_only_possible_value, // i0, u0
807 => return BigIntMutable.init(&space.limbs, 0).toConst(),
807 => BigIntMutable.init(&space.limbs, 0).toConst(),
808808
809 .one => return BigIntMutable.init(&space.limbs, 1).toConst(),
809 .one => BigIntMutable.init(&space.limbs, 1).toConst(),
810810
811811 .enum_field_index => {
812812 const index = val.castTag(.enum_field_index).?.data;
......@@ -816,10 +816,10 @@ pub const Value = struct {
816816 const sub_val = val.castTag(.runtime_value).?.data;
817817 return sub_val.toBigIntAdvanced(space, mod, opt_sema);
818818 },
819 .int_u64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(),
820 .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(),
821 .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(),
822 .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(),
819 .int_u64 => BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(),
820 .int_i64 => BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(),
821 .int_big_positive => val.castTag(.int_big_positive).?.asBigInt(),
822 .int_big_negative => val.castTag(.int_big_negative).?.asBigInt(),
823823
824824 .lazy_align => {
825825 const ty = val.castTag(.lazy_align).?.data;
......@@ -849,10 +849,10 @@ pub const Value = struct {
849849 else => unreachable,
850850 },
851851 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
852 .int => |int| return int.big_int,
852 .int => |int| int.storage.toBigInt(space),
853853 else => unreachable,
854854 },
855 }
855 };
856856 }
857857
858858 /// If the value fits in a u64, return it, otherwise null.
......@@ -900,7 +900,11 @@ pub const Value = struct {
900900 else => return null,
901901 },
902902 else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
903 .int => |int| int.big_int.to(u64) catch null,
903 .int => |int| switch (int.storage) {
904 .big_int => |big_int| big_int.to(u64) catch null,
905 .u64 => |x| x,
906 .i64 => |x| std.math.cast(u64, x),
907 },
904908 else => null,
905909 },
906910 }
......@@ -940,18 +944,22 @@ pub const Value = struct {
940944
941945 else => unreachable,
942946 },
943 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
944 .int => |int| return int.big_int.to(i64) catch unreachable,
947 else => return switch (mod.intern_pool.indexToKey(val.ip_index)) {
948 .int => |int| switch (int.storage) {
949 .big_int => |big_int| big_int.to(i64) catch unreachable,
950 .i64 => |x| x,
951 .u64 => |x| @intCast(i64, x),
952 },
945953 else => unreachable,
946954 },
947955 }
948956 }
949957
950958 pub fn toBool(val: Value, mod: *const Module) bool {
951 switch (val.ip_index) {
952 .bool_true => return true,
953 .bool_false => return false,
954 .none => return switch (val.tag()) {
959 return switch (val.ip_index) {
960 .bool_true => true,
961 .bool_false => false,
962 .none => switch (val.tag()) {
955963 .one => true,
956964 .zero => false,
957965
......@@ -968,10 +976,13 @@ pub const Value = struct {
968976 else => unreachable,
969977 },
970978 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
971 .int => |int| return !int.big_int.eqZero(),
979 .int => |int| switch (int.storage) {
980 .big_int => |big_int| !big_int.eqZero(),
981 inline .u64, .i64 => |x| x != 0,
982 },
972983 else => unreachable,
973984 },
974 }
985 };
975986 }
976987
977988 fn isDeclRef(val: Value) bool {
......@@ -1483,12 +1494,12 @@ pub const Value = struct {
14831494
14841495 pub fn clz(val: Value, ty: Type, mod: *const Module) u64 {
14851496 const ty_bits = ty.intInfo(mod).bits;
1486 switch (val.ip_index) {
1487 .bool_false => return ty_bits,
1488 .bool_true => return ty_bits - 1,
1497 return switch (val.ip_index) {
1498 .bool_false => ty_bits,
1499 .bool_true => ty_bits - 1,
14891500 .none => switch (val.tag()) {
1490 .zero => return ty_bits,
1491 .one => return ty_bits - 1,
1501 .zero => ty_bits,
1502 .one => ty_bits - 1,
14921503
14931504 .int_u64 => {
14941505 const big = @clz(val.castTag(.int_u64).?.data);
......@@ -1519,20 +1530,24 @@ pub const Value = struct {
15191530 else => unreachable,
15201531 },
15211532 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
1522 .int => |int| return int.big_int.clz(ty_bits),
1533 .int => |int| switch (int.storage) {
1534 .big_int => |big_int| big_int.clz(ty_bits),
1535 .u64 => |x| @clz(x) + ty_bits - 64,
1536 .i64 => @panic("TODO implement i64 Value clz"),
1537 },
15231538 else => unreachable,
15241539 },
1525 }
1540 };
15261541 }
15271542
15281543 pub fn ctz(val: Value, ty: Type, mod: *const Module) u64 {
15291544 const ty_bits = ty.intInfo(mod).bits;
1530 switch (val.ip_index) {
1531 .bool_false => return ty_bits,
1532 .bool_true => return 0,
1545 return switch (val.ip_index) {
1546 .bool_false => ty_bits,
1547 .bool_true => 0,
15331548 .none => switch (val.tag()) {
1534 .zero => return ty_bits,
1535 .one => return 0,
1549 .zero => ty_bits,
1550 .one => 0,
15361551
15371552 .int_u64 => {
15381553 const big = @ctz(val.castTag(.int_u64).?.data);
......@@ -1563,10 +1578,17 @@ pub const Value = struct {
15631578 else => unreachable,
15641579 },
15651580 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
1566 .int => |int| return int.big_int.ctz(),
1581 .int => |int| switch (int.storage) {
1582 .big_int => |big_int| big_int.ctz(),
1583 .u64 => |x| {
1584 const big = @ctz(x);
1585 return if (big == 64) ty_bits else big;
1586 },
1587 .i64 => @panic("TODO implement i64 Value ctz"),
1588 },
15671589 else => unreachable,
15681590 },
1569 }
1591 };
15701592 }
15711593
15721594 pub fn popCount(val: Value, ty: Type, mod: *const Module) u64 {
......@@ -1591,7 +1613,9 @@ pub const Value = struct {
15911613 else => switch (mod.intern_pool.indexToKey(val.ip_index)) {
15921614 .int => |int| {
15931615 const info = ty.intInfo(mod);
1594 return int.big_int.popCount(info.bits);
1616 var buffer: Value.BigIntSpace = undefined;
1617 const big_int = int.storage.toBigInt(&buffer);
1618 return @intCast(u64, big_int.popCount(info.bits));
15951619 },
15961620 else => unreachable,
15971621 },
......@@ -1641,23 +1665,23 @@ pub const Value = struct {
16411665 /// Returns the number of bits the value requires to represent stored in twos complement form.
16421666 pub fn intBitCountTwosComp(self: Value, mod: *const Module) usize {
16431667 const target = mod.getTarget();
1644 switch (self.ip_index) {
1645 .bool_false => return 0,
1646 .bool_true => return 1,
1668 return switch (self.ip_index) {
1669 .bool_false => 0,
1670 .bool_true => 1,
16471671 .none => switch (self.tag()) {
16481672 .zero,
16491673 .the_only_possible_value,
1650 => return 0,
1674 => 0,
16511675
1652 .one => return 1,
1676 .one => 1,
16531677
16541678 .int_u64 => {
16551679 const x = self.castTag(.int_u64).?.data;
16561680 if (x == 0) return 0;
16571681 return @intCast(usize, std.math.log2(x) + 1);
16581682 },
1659 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1660 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
1683 .int_big_positive => self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1684 .int_big_negative => self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
16611685
16621686 .decl_ref_mut,
16631687 .comptime_field_ptr,
......@@ -1667,7 +1691,7 @@ pub const Value = struct {
16671691 .variable,
16681692 .eu_payload_ptr,
16691693 .opt_payload_ptr,
1670 => return target.ptrBitWidth(),
1694 => target.ptrBitWidth(),
16711695
16721696 else => {
16731697 var buffer: BigIntSpace = undefined;
......@@ -1675,10 +1699,18 @@ pub const Value = struct {
16751699 },
16761700 },
16771701 else => switch (mod.intern_pool.indexToKey(self.ip_index)) {
1678 .int => |int| return int.big_int.bitCountTwosComp(),
1702 .int => |int| switch (int.storage) {
1703 .big_int => |big_int| big_int.bitCountTwosComp(),
1704 .u64 => |x| if (x == 0) 0 else @intCast(usize, std.math.log2(x) + 1),
1705 .i64 => {
1706 var buffer: Value.BigIntSpace = undefined;
1707 const big_int = int.storage.toBigInt(&buffer);
1708 return big_int.bitCountTwosComp();
1709 },
1710 },
16791711 else => unreachable,
16801712 },
1681 }
1713 };
16821714 }
16831715
16841716 /// Converts an integer or a float to a float. May result in a loss of information.
......@@ -1798,8 +1830,11 @@ pub const Value = struct {
17981830
17991831 else => unreachable,
18001832 },
1801 else => switch (mod.intern_pool.indexToKey(lhs.ip_index)) {
1802 .int => |int| return int.big_int.orderAgainstScalar(0),
1833 else => return switch (mod.intern_pool.indexToKey(lhs.ip_index)) {
1834 .int => |int| switch (int.storage) {
1835 .big_int => |big_int| big_int.orderAgainstScalar(0),
1836 inline .u64, .i64 => |x| std.math.order(x, 0),
1837 },
18031838 else => unreachable,
18041839 },
18051840 }
......@@ -2777,6 +2812,10 @@ pub const Value = struct {
27772812 }
27782813 }
27792814
2815 pub fn tagIsVariable(val: Value) bool {
2816 return val.ip_index == .none and val.tag() == .variable;
2817 }
2818
27802819 /// Returns true if a Value is backed by a variable
27812820 pub fn isVariable(val: Value, mod: *Module) bool {
27822821 return switch (val.ip_index) {
......@@ -5399,12 +5438,7 @@ pub const Value = struct {
53995438 };
54005439 };
54015440
5402 /// Big enough to fit any non-BigInt value
5403 pub const BigIntSpace = struct {
5404 /// The +1 is headroom so that operations such as incrementing once or decrementing once
5405 /// are possible without using an allocator.
5406 limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb,
5407 };
5441 pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace;
54085442
54095443 pub const zero = initTag(.zero);
54105444 pub const one = initTag(.one);