| author | |
| committer | |
| log | ac07ddadeb36019c262b4f28a4fa3884f6f50b32 |
| tree | 3dc3f2ea03f2faa5b110001b6dd0d9dff567de0e |
| parent | 75cf06c187d9d0288c2ea31f34b18c3a7da4bd1d |
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"); |
| 11 | 11 | const Allocator = std.mem.Allocator; |
| 12 | 12 | const assert = std.debug.assert; |
| 13 | 13 | const BigIntConst = std.math.big.int.Const; |
| 14 | const BigIntMutable = std.math.big.int.Mutable; | |
| 14 | 15 | |
| 15 | 16 | const InternPool = @This(); |
| 16 | 17 | const DeclIndex = enum(u32) { _ }; |
| ... | ... | @@ -50,10 +51,7 @@ pub const Key = union(enum) { |
| 50 | 51 | /// Index into the string table bytes. |
| 51 | 52 | lib_name: u32, |
| 52 | 53 | }, |
| 53 | int: struct { | |
| 54 | ty: Index, | |
| 55 | big_int: BigIntConst, | |
| 56 | }, | |
| 54 | int: Key.Int, | |
| 57 | 55 | enum_tag: struct { |
| 58 | 56 | ty: Index, |
| 59 | 57 | tag: BigIntConst, |
| ... | ... | @@ -110,6 +108,32 @@ pub const Key = union(enum) { |
| 110 | 108 | child: Index, |
| 111 | 109 | }; |
| 112 | 110 | |
| 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 | ||
| 113 | 137 | pub fn hash32(key: Key) u32 { |
| 114 | 138 | return @truncate(u32, key.hash64()); |
| 115 | 139 | } |
| ... | ... | @@ -137,9 +161,13 @@ pub const Key = union(enum) { |
| 137 | 161 | => |info| std.hash.autoHash(hasher, info), |
| 138 | 162 | |
| 139 | 163 | .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 | ||
| 140 | 168 | 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); | |
| 143 | 171 | }, |
| 144 | 172 | |
| 145 | 173 | .enum_tag => |enum_tag| { |
| ... | ... | @@ -573,42 +601,27 @@ pub const static_keys = [_]Key{ |
| 573 | 601 | |
| 574 | 602 | .{ .int = .{ |
| 575 | 603 | .ty = .comptime_int_type, |
| 576 | .big_int = .{ | |
| 577 | .limbs = &.{0}, | |
| 578 | .positive = true, | |
| 579 | }, | |
| 604 | .storage = .{ .u64 = 0 }, | |
| 580 | 605 | } }, |
| 581 | 606 | |
| 582 | 607 | .{ .int = .{ |
| 583 | 608 | .ty = .usize_type, |
| 584 | .big_int = .{ | |
| 585 | .limbs = &.{0}, | |
| 586 | .positive = true, | |
| 587 | }, | |
| 609 | .storage = .{ .u64 = 0 }, | |
| 588 | 610 | } }, |
| 589 | 611 | |
| 590 | 612 | .{ .int = .{ |
| 591 | 613 | .ty = .u8_type, |
| 592 | .big_int = .{ | |
| 593 | .limbs = &.{0}, | |
| 594 | .positive = true, | |
| 595 | }, | |
| 614 | .storage = .{ .u64 = 0 }, | |
| 596 | 615 | } }, |
| 597 | 616 | |
| 598 | 617 | .{ .int = .{ |
| 599 | 618 | .ty = .comptime_int_type, |
| 600 | .big_int = .{ | |
| 601 | .limbs = &.{1}, | |
| 602 | .positive = true, | |
| 603 | }, | |
| 619 | .storage = .{ .u64 = 1 }, | |
| 604 | 620 | } }, |
| 605 | 621 | |
| 606 | 622 | .{ .int = .{ |
| 607 | 623 | .ty = .usize_type, |
| 608 | .big_int = .{ | |
| 609 | .limbs = &.{1}, | |
| 610 | .positive = true, | |
| 611 | }, | |
| 624 | .storage = .{ .u64 = 1 }, | |
| 612 | 625 | } }, |
| 613 | 626 | |
| 614 | 627 | .{ .enum_tag = .{ |
| ... | ... | @@ -680,19 +693,19 @@ pub const Tag = enum(u8) { |
| 680 | 693 | simple_internal, |
| 681 | 694 | /// Type: u32 |
| 682 | 695 | /// data is integer value |
| 683 | int_small_u32, | |
| 696 | int_u32, | |
| 684 | 697 | /// Type: i32 |
| 685 | 698 | /// data is integer value bitcasted to u32. |
| 686 | int_small_i32, | |
| 699 | int_i32, | |
| 687 | 700 | /// A usize that fits in 32 bits. |
| 688 | 701 | /// data is integer value. |
| 689 | int_small_usize, | |
| 702 | int_usize, | |
| 690 | 703 | /// A comptime_int that fits in a u32. |
| 691 | 704 | /// data is integer value. |
| 692 | int_small_comptime_unsigned, | |
| 705 | int_comptime_int_u32, | |
| 693 | 706 | /// A comptime_int that fits in an i32. |
| 694 | 707 | /// data is integer value bitcasted to u32. |
| 695 | int_small_comptime_signed, | |
| 708 | int_comptime_int_i32, | |
| 696 | 709 | /// A positive integer value. |
| 697 | 710 | /// data is a limbs index to Int. |
| 698 | 711 | int_positive, |
| ... | ... | @@ -932,11 +945,26 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 932 | 945 | .type_error_union => @panic("TODO"), |
| 933 | 946 | .type_enum_simple => @panic("TODO"), |
| 934 | 947 | .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 | } }, | |
| 940 | 968 | .int_positive => @panic("TODO"), |
| 941 | 969 | .int_negative => @panic("TODO"), |
| 942 | 970 | .enum_tag_positive => @panic("TODO"), |
| ... | ... | @@ -1041,54 +1069,114 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 1041 | 1069 | |
| 1042 | 1070 | .int => |int| b: { |
| 1043 | 1071 | 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 | }, | |
| 1052 | 1091 | }, |
| 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 | }, | |
| 1061 | 1111 | }, |
| 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 | }, | |
| 1070 | 1131 | }, |
| 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 | }, | |
| 1086 | 1165 | }, |
| 1087 | 1166 | else => {}, |
| 1088 | 1167 | } |
| 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 | } | |
| 1092 | 1180 | }, |
| 1093 | 1181 | |
| 1094 | 1182 | .enum_tag => |enum_tag| { |
src/Sema.zig+3-3| ... | ... | @@ -1981,7 +1981,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( |
| 1981 | 1981 | if (air_tags[i] == .constant) { |
| 1982 | 1982 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; |
| 1983 | 1983 | const val = sema.air_values.items[ty_pl.payload]; |
| 1984 | if (val.tag() == .variable) return val; | |
| 1984 | if (val.tagIsVariable()) return val; | |
| 1985 | 1985 | } |
| 1986 | 1986 | return opv; |
| 1987 | 1987 | } |
| ... | ... | @@ -5033,7 +5033,7 @@ fn storeToInferredAllocComptime( |
| 5033 | 5033 | // There will be only one store_to_inferred_ptr because we are running at comptime. |
| 5034 | 5034 | // The alloc will turn into a Decl. |
| 5035 | 5035 | if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: { |
| 5036 | if (operand_val.tag() == .variable) break :store; | |
| 5036 | if (operand_val.tagIsVariable()) break :store; | |
| 5037 | 5037 | var anon_decl = try block.startAnonDecl(); |
| 5038 | 5038 | defer anon_decl.deinit(); |
| 5039 | 5039 | iac.data.decl_index = try anon_decl.finish( |
| ... | ... | @@ -28125,7 +28125,7 @@ fn beginComptimePtrLoad( |
| 28125 | 28125 | const is_mutable = ptr_val.tag() == .decl_ref_mut; |
| 28126 | 28126 | const decl = sema.mod.declPtr(decl_index); |
| 28127 | 28127 | 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; | |
| 28129 | 28129 | |
| 28130 | 28130 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); |
| 28131 | 28131 | break :blk ComptimePtrLoadKit{ |
src/value.zig+88-54| ... | ... | @@ -796,17 +796,17 @@ pub const Value = struct { |
| 796 | 796 | mod: *const Module, |
| 797 | 797 | opt_sema: ?*Sema, |
| 798 | 798 | ) 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(), | |
| 802 | 802 | .undef => unreachable, |
| 803 | .null_value => return BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 803 | .null_value => BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 804 | 804 | .none => switch (val.tag()) { |
| 805 | 805 | .zero, |
| 806 | 806 | .the_only_possible_value, // i0, u0 |
| 807 | => return BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 807 | => BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 808 | 808 | |
| 809 | .one => return BigIntMutable.init(&space.limbs, 1).toConst(), | |
| 809 | .one => BigIntMutable.init(&space.limbs, 1).toConst(), | |
| 810 | 810 | |
| 811 | 811 | .enum_field_index => { |
| 812 | 812 | const index = val.castTag(.enum_field_index).?.data; |
| ... | ... | @@ -816,10 +816,10 @@ pub const Value = struct { |
| 816 | 816 | const sub_val = val.castTag(.runtime_value).?.data; |
| 817 | 817 | return sub_val.toBigIntAdvanced(space, mod, opt_sema); |
| 818 | 818 | }, |
| 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(), | |
| 823 | 823 | |
| 824 | 824 | .lazy_align => { |
| 825 | 825 | const ty = val.castTag(.lazy_align).?.data; |
| ... | ... | @@ -849,10 +849,10 @@ pub const Value = struct { |
| 849 | 849 | else => unreachable, |
| 850 | 850 | }, |
| 851 | 851 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 852 | .int => |int| return int.big_int, | |
| 852 | .int => |int| int.storage.toBigInt(space), | |
| 853 | 853 | else => unreachable, |
| 854 | 854 | }, |
| 855 | } | |
| 855 | }; | |
| 856 | 856 | } |
| 857 | 857 | |
| 858 | 858 | /// If the value fits in a u64, return it, otherwise null. |
| ... | ... | @@ -900,7 +900,11 @@ pub const Value = struct { |
| 900 | 900 | else => return null, |
| 901 | 901 | }, |
| 902 | 902 | 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 | }, | |
| 904 | 908 | else => null, |
| 905 | 909 | }, |
| 906 | 910 | } |
| ... | ... | @@ -940,18 +944,22 @@ pub const Value = struct { |
| 940 | 944 | |
| 941 | 945 | else => unreachable, |
| 942 | 946 | }, |
| 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 | }, | |
| 945 | 953 | else => unreachable, |
| 946 | 954 | }, |
| 947 | 955 | } |
| 948 | 956 | } |
| 949 | 957 | |
| 950 | 958 | 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()) { | |
| 955 | 963 | .one => true, |
| 956 | 964 | .zero => false, |
| 957 | 965 | |
| ... | ... | @@ -968,10 +976,13 @@ pub const Value = struct { |
| 968 | 976 | else => unreachable, |
| 969 | 977 | }, |
| 970 | 978 | 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 | }, | |
| 972 | 983 | else => unreachable, |
| 973 | 984 | }, |
| 974 | } | |
| 985 | }; | |
| 975 | 986 | } |
| 976 | 987 | |
| 977 | 988 | fn isDeclRef(val: Value) bool { |
| ... | ... | @@ -1483,12 +1494,12 @@ pub const Value = struct { |
| 1483 | 1494 | |
| 1484 | 1495 | pub fn clz(val: Value, ty: Type, mod: *const Module) u64 { |
| 1485 | 1496 | 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, | |
| 1489 | 1500 | .none => switch (val.tag()) { |
| 1490 | .zero => return ty_bits, | |
| 1491 | .one => return ty_bits - 1, | |
| 1501 | .zero => ty_bits, | |
| 1502 | .one => ty_bits - 1, | |
| 1492 | 1503 | |
| 1493 | 1504 | .int_u64 => { |
| 1494 | 1505 | const big = @clz(val.castTag(.int_u64).?.data); |
| ... | ... | @@ -1519,20 +1530,24 @@ pub const Value = struct { |
| 1519 | 1530 | else => unreachable, |
| 1520 | 1531 | }, |
| 1521 | 1532 | 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 | }, | |
| 1523 | 1538 | else => unreachable, |
| 1524 | 1539 | }, |
| 1525 | } | |
| 1540 | }; | |
| 1526 | 1541 | } |
| 1527 | 1542 | |
| 1528 | 1543 | pub fn ctz(val: Value, ty: Type, mod: *const Module) u64 { |
| 1529 | 1544 | 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, | |
| 1533 | 1548 | .none => switch (val.tag()) { |
| 1534 | .zero => return ty_bits, | |
| 1535 | .one => return 0, | |
| 1549 | .zero => ty_bits, | |
| 1550 | .one => 0, | |
| 1536 | 1551 | |
| 1537 | 1552 | .int_u64 => { |
| 1538 | 1553 | const big = @ctz(val.castTag(.int_u64).?.data); |
| ... | ... | @@ -1563,10 +1578,17 @@ pub const Value = struct { |
| 1563 | 1578 | else => unreachable, |
| 1564 | 1579 | }, |
| 1565 | 1580 | 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 | }, | |
| 1567 | 1589 | else => unreachable, |
| 1568 | 1590 | }, |
| 1569 | } | |
| 1591 | }; | |
| 1570 | 1592 | } |
| 1571 | 1593 | |
| 1572 | 1594 | pub fn popCount(val: Value, ty: Type, mod: *const Module) u64 { |
| ... | ... | @@ -1591,7 +1613,9 @@ pub const Value = struct { |
| 1591 | 1613 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 1592 | 1614 | .int => |int| { |
| 1593 | 1615 | 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)); | |
| 1595 | 1619 | }, |
| 1596 | 1620 | else => unreachable, |
| 1597 | 1621 | }, |
| ... | ... | @@ -1641,23 +1665,23 @@ pub const Value = struct { |
| 1641 | 1665 | /// Returns the number of bits the value requires to represent stored in twos complement form. |
| 1642 | 1666 | pub fn intBitCountTwosComp(self: Value, mod: *const Module) usize { |
| 1643 | 1667 | 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, | |
| 1647 | 1671 | .none => switch (self.tag()) { |
| 1648 | 1672 | .zero, |
| 1649 | 1673 | .the_only_possible_value, |
| 1650 | => return 0, | |
| 1674 | => 0, | |
| 1651 | 1675 | |
| 1652 | .one => return 1, | |
| 1676 | .one => 1, | |
| 1653 | 1677 | |
| 1654 | 1678 | .int_u64 => { |
| 1655 | 1679 | const x = self.castTag(.int_u64).?.data; |
| 1656 | 1680 | if (x == 0) return 0; |
| 1657 | 1681 | return @intCast(usize, std.math.log2(x) + 1); |
| 1658 | 1682 | }, |
| 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(), | |
| 1661 | 1685 | |
| 1662 | 1686 | .decl_ref_mut, |
| 1663 | 1687 | .comptime_field_ptr, |
| ... | ... | @@ -1667,7 +1691,7 @@ pub const Value = struct { |
| 1667 | 1691 | .variable, |
| 1668 | 1692 | .eu_payload_ptr, |
| 1669 | 1693 | .opt_payload_ptr, |
| 1670 | => return target.ptrBitWidth(), | |
| 1694 | => target.ptrBitWidth(), | |
| 1671 | 1695 | |
| 1672 | 1696 | else => { |
| 1673 | 1697 | var buffer: BigIntSpace = undefined; |
| ... | ... | @@ -1675,10 +1699,18 @@ pub const Value = struct { |
| 1675 | 1699 | }, |
| 1676 | 1700 | }, |
| 1677 | 1701 | 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 | }, | |
| 1679 | 1711 | else => unreachable, |
| 1680 | 1712 | }, |
| 1681 | } | |
| 1713 | }; | |
| 1682 | 1714 | } |
| 1683 | 1715 | |
| 1684 | 1716 | /// Converts an integer or a float to a float. May result in a loss of information. |
| ... | ... | @@ -1798,8 +1830,11 @@ pub const Value = struct { |
| 1798 | 1830 | |
| 1799 | 1831 | else => unreachable, |
| 1800 | 1832 | }, |
| 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 | }, | |
| 1803 | 1838 | else => unreachable, |
| 1804 | 1839 | }, |
| 1805 | 1840 | } |
| ... | ... | @@ -2777,6 +2812,10 @@ pub const Value = struct { |
| 2777 | 2812 | } |
| 2778 | 2813 | } |
| 2779 | 2814 | |
| 2815 | pub fn tagIsVariable(val: Value) bool { | |
| 2816 | return val.ip_index == .none and val.tag() == .variable; | |
| 2817 | } | |
| 2818 | ||
| 2780 | 2819 | /// Returns true if a Value is backed by a variable |
| 2781 | 2820 | pub fn isVariable(val: Value, mod: *Module) bool { |
| 2782 | 2821 | return switch (val.ip_index) { |
| ... | ... | @@ -5399,12 +5438,7 @@ pub const Value = struct { |
| 5399 | 5438 | }; |
| 5400 | 5439 | }; |
| 5401 | 5440 | |
| 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; | |
| 5408 | 5442 | |
| 5409 | 5443 | pub const zero = initTag(.zero); |
| 5410 | 5444 | pub const one = initTag(.one); |