| 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,6 +11,7 @@ const std = @import("std"); |
| 11 | const Allocator = std.mem.Allocator; | 11 | const Allocator = std.mem.Allocator; |
| 12 | const assert = std.debug.assert; | 12 | const assert = std.debug.assert; |
| 13 | const BigIntConst = std.math.big.int.Const; | 13 | const BigIntConst = std.math.big.int.Const; |
| 14 | const BigIntMutable = std.math.big.int.Mutable; | ||
| 14 | 15 | ||
| 15 | const InternPool = @This(); | 16 | const InternPool = @This(); |
| 16 | const DeclIndex = enum(u32) { _ }; | 17 | const DeclIndex = enum(u32) { _ }; |
| ... | @@ -50,10 +51,7 @@ pub const Key = union(enum) { | ... | @@ -50,10 +51,7 @@ pub const Key = union(enum) { |
| 50 | /// Index into the string table bytes. | 51 | /// Index into the string table bytes. |
| 51 | lib_name: u32, | 52 | lib_name: u32, |
| 52 | }, | 53 | }, |
| 53 | int: struct { | 54 | int: Key.Int, |
| 54 | ty: Index, | ||
| 55 | big_int: BigIntConst, | ||
| 56 | }, | ||
| 57 | enum_tag: struct { | 55 | enum_tag: struct { |
| 58 | ty: Index, | 56 | ty: Index, |
| 59 | tag: BigIntConst, | 57 | tag: BigIntConst, |
| ... | @@ -110,6 +108,32 @@ pub const Key = union(enum) { | ... | @@ -110,6 +108,32 @@ pub const Key = union(enum) { |
| 110 | child: Index, | 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 | pub fn hash32(key: Key) u32 { | 137 | pub fn hash32(key: Key) u32 { |
| 114 | return @truncate(u32, key.hash64()); | 138 | return @truncate(u32, key.hash64()); |
| 115 | } | 139 | } |
| ... | @@ -137,9 +161,13 @@ pub const Key = union(enum) { | ... | @@ -137,9 +161,13 @@ pub const Key = union(enum) { |
| 137 | => |info| std.hash.autoHash(hasher, info), | 161 | => |info| std.hash.autoHash(hasher, info), |
| 138 | 162 | ||
| 139 | .int => |int| { | 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 | std.hash.autoHash(hasher, int.ty); | 168 | std.hash.autoHash(hasher, int.ty); |
| 141 | std.hash.autoHash(hasher, int.big_int.positive); | 169 | std.hash.autoHash(hasher, big_int.positive); |
| 142 | for (int.big_int.limbs) |limb| std.hash.autoHash(hasher, limb); | 170 | for (big_int.limbs) |limb| std.hash.autoHash(hasher, limb); |
| 143 | }, | 171 | }, |
| 144 | 172 | ||
| 145 | .enum_tag => |enum_tag| { | 173 | .enum_tag => |enum_tag| { |
| ... | @@ -573,42 +601,27 @@ pub const static_keys = [_]Key{ | ... | @@ -573,42 +601,27 @@ pub const static_keys = [_]Key{ |
| 573 | 601 | ||
| 574 | .{ .int = .{ | 602 | .{ .int = .{ |
| 575 | .ty = .comptime_int_type, | 603 | .ty = .comptime_int_type, |
| 576 | .big_int = .{ | 604 | .storage = .{ .u64 = 0 }, |
| 577 | .limbs = &.{0}, | ||
| 578 | .positive = true, | ||
| 579 | }, | ||
| 580 | } }, | 605 | } }, |
| 581 | 606 | ||
| 582 | .{ .int = .{ | 607 | .{ .int = .{ |
| 583 | .ty = .usize_type, | 608 | .ty = .usize_type, |
| 584 | .big_int = .{ | 609 | .storage = .{ .u64 = 0 }, |
| 585 | .limbs = &.{0}, | ||
| 586 | .positive = true, | ||
| 587 | }, | ||
| 588 | } }, | 610 | } }, |
| 589 | 611 | ||
| 590 | .{ .int = .{ | 612 | .{ .int = .{ |
| 591 | .ty = .u8_type, | 613 | .ty = .u8_type, |
| 592 | .big_int = .{ | 614 | .storage = .{ .u64 = 0 }, |
| 593 | .limbs = &.{0}, | ||
| 594 | .positive = true, | ||
| 595 | }, | ||
| 596 | } }, | 615 | } }, |
| 597 | 616 | ||
| 598 | .{ .int = .{ | 617 | .{ .int = .{ |
| 599 | .ty = .comptime_int_type, | 618 | .ty = .comptime_int_type, |
| 600 | .big_int = .{ | 619 | .storage = .{ .u64 = 1 }, |
| 601 | .limbs = &.{1}, | ||
| 602 | .positive = true, | ||
| 603 | }, | ||
| 604 | } }, | 620 | } }, |
| 605 | 621 | ||
| 606 | .{ .int = .{ | 622 | .{ .int = .{ |
| 607 | .ty = .usize_type, | 623 | .ty = .usize_type, |
| 608 | .big_int = .{ | 624 | .storage = .{ .u64 = 1 }, |
| 609 | .limbs = &.{1}, | ||
| 610 | .positive = true, | ||
| 611 | }, | ||
| 612 | } }, | 625 | } }, |
| 613 | 626 | ||
| 614 | .{ .enum_tag = .{ | 627 | .{ .enum_tag = .{ |
| ... | @@ -680,19 +693,19 @@ pub const Tag = enum(u8) { | ... | @@ -680,19 +693,19 @@ pub const Tag = enum(u8) { |
| 680 | simple_internal, | 693 | simple_internal, |
| 681 | /// Type: u32 | 694 | /// Type: u32 |
| 682 | /// data is integer value | 695 | /// data is integer value |
| 683 | int_small_u32, | 696 | int_u32, |
| 684 | /// Type: i32 | 697 | /// Type: i32 |
| 685 | /// data is integer value bitcasted to u32. | 698 | /// data is integer value bitcasted to u32. |
| 686 | int_small_i32, | 699 | int_i32, |
| 687 | /// A usize that fits in 32 bits. | 700 | /// A usize that fits in 32 bits. |
| 688 | /// data is integer value. | 701 | /// data is integer value. |
| 689 | int_small_usize, | 702 | int_usize, |
| 690 | /// A comptime_int that fits in a u32. | 703 | /// A comptime_int that fits in a u32. |
| 691 | /// data is integer value. | 704 | /// data is integer value. |
| 692 | int_small_comptime_unsigned, | 705 | int_comptime_int_u32, |
| 693 | /// A comptime_int that fits in an i32. | 706 | /// A comptime_int that fits in an i32. |
| 694 | /// data is integer value bitcasted to u32. | 707 | /// data is integer value bitcasted to u32. |
| 695 | int_small_comptime_signed, | 708 | int_comptime_int_i32, |
| 696 | /// A positive integer value. | 709 | /// A positive integer value. |
| 697 | /// data is a limbs index to Int. | 710 | /// data is a limbs index to Int. |
| 698 | int_positive, | 711 | int_positive, |
| ... | @@ -932,11 +945,26 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { | ... | @@ -932,11 +945,26 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 932 | .type_error_union => @panic("TODO"), | 945 | .type_error_union => @panic("TODO"), |
| 933 | .type_enum_simple => @panic("TODO"), | 946 | .type_enum_simple => @panic("TODO"), |
| 934 | .simple_internal => @panic("TODO"), | 947 | .simple_internal => @panic("TODO"), |
| 935 | .int_small_u32 => @panic("TODO"), | 948 | .int_u32 => return .{ .int = .{ |
| 936 | .int_small_i32 => @panic("TODO"), | 949 | .ty = .u32_type, |
| 937 | .int_small_usize => @panic("TODO"), | 950 | .storage = .{ .u64 = data }, |
| 938 | .int_small_comptime_unsigned => @panic("TODO"), | 951 | } }, |
| 939 | .int_small_comptime_signed => @panic("TODO"), | 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 | .int_positive => @panic("TODO"), | 968 | .int_positive => @panic("TODO"), |
| 941 | .int_negative => @panic("TODO"), | 969 | .int_negative => @panic("TODO"), |
| 942 | .enum_tag_positive => @panic("TODO"), | 970 | .enum_tag_positive => @panic("TODO"), |
| ... | @@ -1041,54 +1069,114 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { | ... | @@ -1041,54 +1069,114 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 1041 | 1069 | ||
| 1042 | .int => |int| b: { | 1070 | .int => |int| b: { |
| 1043 | switch (int.ty) { | 1071 | switch (int.ty) { |
| 1044 | .u32_type => { | 1072 | .u32_type => switch (int.storage) { |
| 1045 | if (int.big_int.fits(u32)) { | 1073 | .big_int => |big_int| { |
| 1046 | ip.items.appendAssumeCapacity(.{ | 1074 | if (big_int.to(u32)) |casted| { |
| 1047 | .tag = .int_small_u32, | 1075 | ip.items.appendAssumeCapacity(.{ |
| 1048 | .data = int.big_int.to(u32) catch unreachable, | 1076 | .tag = .int_u32, |
| 1049 | }); | 1077 | .data = casted, |
| 1050 | break :b; | 1078 | }); |
| 1051 | } | 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 => { | 1092 | .i32_type => switch (int.storage) { |
| 1054 | if (int.big_int.fits(i32)) { | 1093 | .big_int => |big_int| { |
| 1055 | ip.items.appendAssumeCapacity(.{ | 1094 | if (big_int.to(i32)) |casted| { |
| 1056 | .tag = .int_small_i32, | 1095 | ip.items.appendAssumeCapacity(.{ |
| 1057 | .data = @bitCast(u32, int.big_int.to(i32) catch unreachable), | 1096 | .tag = .int_i32, |
| 1058 | }); | 1097 | .data = @bitCast(u32, casted), |
| 1059 | break :b; | 1098 | }); |
| 1060 | } | 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 => { | 1112 | .usize_type => switch (int.storage) { |
| 1063 | if (int.big_int.fits(u32)) { | 1113 | .big_int => |big_int| { |
| 1064 | ip.items.appendAssumeCapacity(.{ | 1114 | if (big_int.to(u32)) |casted| { |
| 1065 | .tag = .int_small_usize, | 1115 | ip.items.appendAssumeCapacity(.{ |
| 1066 | .data = int.big_int.to(u32) catch unreachable, | 1116 | .tag = .int_usize, |
| 1067 | }); | 1117 | .data = casted, |
| 1068 | break :b; | 1118 | }); |
| 1069 | } | 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 => { | 1132 | .comptime_int_type => switch (int.storage) { |
| 1072 | if (int.big_int.fits(u32)) { | 1133 | .big_int => |big_int| { |
| 1073 | ip.items.appendAssumeCapacity(.{ | 1134 | if (big_int.to(u32)) |casted| { |
| 1074 | .tag = .int_small_comptime_unsigned, | 1135 | ip.items.appendAssumeCapacity(.{ |
| 1075 | .data = int.big_int.to(u32) catch unreachable, | 1136 | .tag = .int_comptime_int_u32, |
| 1076 | }); | 1137 | .data = casted, |
| 1077 | break :b; | 1138 | }); |
| 1078 | } | 1139 | break :b; |
| 1079 | if (int.big_int.fits(i32)) { | 1140 | } else |_| {} |
| 1080 | ip.items.appendAssumeCapacity(.{ | 1141 | if (big_int.to(i32)) |casted| { |
| 1081 | .tag = .int_small_comptime_signed, | 1142 | ip.items.appendAssumeCapacity(.{ |
| 1082 | .data = @bitCast(u32, int.big_int.to(i32) catch unreachable), | 1143 | .tag = .int_comptime_int_i32, |
| 1083 | }); | 1144 | .data = @bitCast(u32, casted), |
| 1084 | break :b; | 1145 | }); |
| 1085 | } | 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 | else => {}, | 1166 | else => {}, |
| 1088 | } | 1167 | } |
| 1089 | 1168 | switch (int.storage) { | |
| 1090 | const tag: Tag = if (int.big_int.positive) .int_positive else .int_negative; | 1169 | .big_int => |big_int| { |
| 1091 | try addInt(ip, gpa, int.ty, tag, int.big_int.limbs); | 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 | .enum_tag => |enum_tag| { | 1182 | .enum_tag => |enum_tag| { |
src/Sema.zig+3-3| ... | @@ -1981,7 +1981,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( | ... | @@ -1981,7 +1981,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( |
| 1981 | if (air_tags[i] == .constant) { | 1981 | if (air_tags[i] == .constant) { |
| 1982 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; | 1982 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; |
| 1983 | const val = sema.air_values.items[ty_pl.payload]; | 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 | return opv; | 1986 | return opv; |
| 1987 | } | 1987 | } |
| ... | @@ -5033,7 +5033,7 @@ fn storeToInferredAllocComptime( | ... | @@ -5033,7 +5033,7 @@ fn storeToInferredAllocComptime( |
| 5033 | // There will be only one store_to_inferred_ptr because we are running at comptime. | 5033 | // There will be only one store_to_inferred_ptr because we are running at comptime. |
| 5034 | // The alloc will turn into a Decl. | 5034 | // The alloc will turn into a Decl. |
| 5035 | if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: { | 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 | var anon_decl = try block.startAnonDecl(); | 5037 | var anon_decl = try block.startAnonDecl(); |
| 5038 | defer anon_decl.deinit(); | 5038 | defer anon_decl.deinit(); |
| 5039 | iac.data.decl_index = try anon_decl.finish( | 5039 | iac.data.decl_index = try anon_decl.finish( |
| ... | @@ -28125,7 +28125,7 @@ fn beginComptimePtrLoad( | ... | @@ -28125,7 +28125,7 @@ fn beginComptimePtrLoad( |
| 28125 | const is_mutable = ptr_val.tag() == .decl_ref_mut; | 28125 | const is_mutable = ptr_val.tag() == .decl_ref_mut; |
| 28126 | const decl = sema.mod.declPtr(decl_index); | 28126 | const decl = sema.mod.declPtr(decl_index); |
| 28127 | const decl_tv = try decl.typedValue(); | 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 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); | 28130 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); |
| 28131 | break :blk ComptimePtrLoadKit{ | 28131 | break :blk ComptimePtrLoadKit{ |
src/value.zig+88-54| ... | @@ -796,17 +796,17 @@ pub const Value = struct { | ... | @@ -796,17 +796,17 @@ pub const Value = struct { |
| 796 | mod: *const Module, | 796 | mod: *const Module, |
| 797 | opt_sema: ?*Sema, | 797 | opt_sema: ?*Sema, |
| 798 | ) Module.CompileError!BigIntConst { | 798 | ) Module.CompileError!BigIntConst { |
| 799 | switch (val.ip_index) { | 799 | return switch (val.ip_index) { |
| 800 | .bool_false => return BigIntMutable.init(&space.limbs, 0).toConst(), | 800 | .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(), |
| 801 | .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(), | 801 | .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(), |
| 802 | .undef => unreachable, | 802 | .undef => unreachable, |
| 803 | .null_value => return BigIntMutable.init(&space.limbs, 0).toConst(), | 803 | .null_value => BigIntMutable.init(&space.limbs, 0).toConst(), |
| 804 | .none => switch (val.tag()) { | 804 | .none => switch (val.tag()) { |
| 805 | .zero, | 805 | .zero, |
| 806 | .the_only_possible_value, // i0, u0 | 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 | .enum_field_index => { | 811 | .enum_field_index => { |
| 812 | const index = val.castTag(.enum_field_index).?.data; | 812 | const index = val.castTag(.enum_field_index).?.data; |
| ... | @@ -816,10 +816,10 @@ pub const Value = struct { | ... | @@ -816,10 +816,10 @@ pub const Value = struct { |
| 816 | const sub_val = val.castTag(.runtime_value).?.data; | 816 | const sub_val = val.castTag(.runtime_value).?.data; |
| 817 | return sub_val.toBigIntAdvanced(space, mod, opt_sema); | 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(), | 819 | .int_u64 => BigIntMutable.init(&space.limbs, val.castTag(.int_u64).?.data).toConst(), |
| 820 | .int_i64 => return BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(), | 820 | .int_i64 => BigIntMutable.init(&space.limbs, val.castTag(.int_i64).?.data).toConst(), |
| 821 | .int_big_positive => return val.castTag(.int_big_positive).?.asBigInt(), | 821 | .int_big_positive => val.castTag(.int_big_positive).?.asBigInt(), |
| 822 | .int_big_negative => return val.castTag(.int_big_negative).?.asBigInt(), | 822 | .int_big_negative => val.castTag(.int_big_negative).?.asBigInt(), |
| 823 | 823 | ||
| 824 | .lazy_align => { | 824 | .lazy_align => { |
| 825 | const ty = val.castTag(.lazy_align).?.data; | 825 | const ty = val.castTag(.lazy_align).?.data; |
| ... | @@ -849,10 +849,10 @@ pub const Value = struct { | ... | @@ -849,10 +849,10 @@ pub const Value = struct { |
| 849 | else => unreachable, | 849 | else => unreachable, |
| 850 | }, | 850 | }, |
| 851 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | 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 | else => unreachable, | 853 | else => unreachable, |
| 854 | }, | 854 | }, |
| 855 | } | 855 | }; |
| 856 | } | 856 | } |
| 857 | 857 | ||
| 858 | /// If the value fits in a u64, return it, otherwise null. | 858 | /// If the value fits in a u64, return it, otherwise null. |
| ... | @@ -900,7 +900,11 @@ pub const Value = struct { | ... | @@ -900,7 +900,11 @@ pub const Value = struct { |
| 900 | else => return null, | 900 | else => return null, |
| 901 | }, | 901 | }, |
| 902 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { | 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 | else => null, | 908 | else => null, |
| 905 | }, | 909 | }, |
| 906 | } | 910 | } |
| ... | @@ -940,18 +944,22 @@ pub const Value = struct { | ... | @@ -940,18 +944,22 @@ pub const Value = struct { |
| 940 | 944 | ||
| 941 | else => unreachable, | 945 | else => unreachable, |
| 942 | }, | 946 | }, |
| 943 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | 947 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 944 | .int => |int| return int.big_int.to(i64) catch unreachable, | 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 | else => unreachable, | 953 | else => unreachable, |
| 946 | }, | 954 | }, |
| 947 | } | 955 | } |
| 948 | } | 956 | } |
| 949 | 957 | ||
| 950 | pub fn toBool(val: Value, mod: *const Module) bool { | 958 | pub fn toBool(val: Value, mod: *const Module) bool { |
| 951 | switch (val.ip_index) { | 959 | return switch (val.ip_index) { |
| 952 | .bool_true => return true, | 960 | .bool_true => true, |
| 953 | .bool_false => return false, | 961 | .bool_false => false, |
| 954 | .none => return switch (val.tag()) { | 962 | .none => switch (val.tag()) { |
| 955 | .one => true, | 963 | .one => true, |
| 956 | .zero => false, | 964 | .zero => false, |
| 957 | 965 | ||
| ... | @@ -968,10 +976,13 @@ pub const Value = struct { | ... | @@ -968,10 +976,13 @@ pub const Value = struct { |
| 968 | else => unreachable, | 976 | else => unreachable, |
| 969 | }, | 977 | }, |
| 970 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | 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 | else => unreachable, | 983 | else => unreachable, |
| 973 | }, | 984 | }, |
| 974 | } | 985 | }; |
| 975 | } | 986 | } |
| 976 | 987 | ||
| 977 | fn isDeclRef(val: Value) bool { | 988 | fn isDeclRef(val: Value) bool { |
| ... | @@ -1483,12 +1494,12 @@ pub const Value = struct { | ... | @@ -1483,12 +1494,12 @@ pub const Value = struct { |
| 1483 | 1494 | ||
| 1484 | pub fn clz(val: Value, ty: Type, mod: *const Module) u64 { | 1495 | pub fn clz(val: Value, ty: Type, mod: *const Module) u64 { |
| 1485 | const ty_bits = ty.intInfo(mod).bits; | 1496 | const ty_bits = ty.intInfo(mod).bits; |
| 1486 | switch (val.ip_index) { | 1497 | return switch (val.ip_index) { |
| 1487 | .bool_false => return ty_bits, | 1498 | .bool_false => ty_bits, |
| 1488 | .bool_true => return ty_bits - 1, | 1499 | .bool_true => ty_bits - 1, |
| 1489 | .none => switch (val.tag()) { | 1500 | .none => switch (val.tag()) { |
| 1490 | .zero => return ty_bits, | 1501 | .zero => ty_bits, |
| 1491 | .one => return ty_bits - 1, | 1502 | .one => ty_bits - 1, |
| 1492 | 1503 | ||
| 1493 | .int_u64 => { | 1504 | .int_u64 => { |
| 1494 | const big = @clz(val.castTag(.int_u64).?.data); | 1505 | const big = @clz(val.castTag(.int_u64).?.data); |
| ... | @@ -1519,20 +1530,24 @@ pub const Value = struct { | ... | @@ -1519,20 +1530,24 @@ pub const Value = struct { |
| 1519 | else => unreachable, | 1530 | else => unreachable, |
| 1520 | }, | 1531 | }, |
| 1521 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | 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 | else => unreachable, | 1538 | else => unreachable, |
| 1524 | }, | 1539 | }, |
| 1525 | } | 1540 | }; |
| 1526 | } | 1541 | } |
| 1527 | 1542 | ||
| 1528 | pub fn ctz(val: Value, ty: Type, mod: *const Module) u64 { | 1543 | pub fn ctz(val: Value, ty: Type, mod: *const Module) u64 { |
| 1529 | const ty_bits = ty.intInfo(mod).bits; | 1544 | const ty_bits = ty.intInfo(mod).bits; |
| 1530 | switch (val.ip_index) { | 1545 | return switch (val.ip_index) { |
| 1531 | .bool_false => return ty_bits, | 1546 | .bool_false => ty_bits, |
| 1532 | .bool_true => return 0, | 1547 | .bool_true => 0, |
| 1533 | .none => switch (val.tag()) { | 1548 | .none => switch (val.tag()) { |
| 1534 | .zero => return ty_bits, | 1549 | .zero => ty_bits, |
| 1535 | .one => return 0, | 1550 | .one => 0, |
| 1536 | 1551 | ||
| 1537 | .int_u64 => { | 1552 | .int_u64 => { |
| 1538 | const big = @ctz(val.castTag(.int_u64).?.data); | 1553 | const big = @ctz(val.castTag(.int_u64).?.data); |
| ... | @@ -1563,10 +1578,17 @@ pub const Value = struct { | ... | @@ -1563,10 +1578,17 @@ pub const Value = struct { |
| 1563 | else => unreachable, | 1578 | else => unreachable, |
| 1564 | }, | 1579 | }, |
| 1565 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | 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 | else => unreachable, | 1589 | else => unreachable, |
| 1568 | }, | 1590 | }, |
| 1569 | } | 1591 | }; |
| 1570 | } | 1592 | } |
| 1571 | 1593 | ||
| 1572 | pub fn popCount(val: Value, ty: Type, mod: *const Module) u64 { | 1594 | pub fn popCount(val: Value, ty: Type, mod: *const Module) u64 { |
| ... | @@ -1591,7 +1613,9 @@ pub const Value = struct { | ... | @@ -1591,7 +1613,9 @@ pub const Value = struct { |
| 1591 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | 1613 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 1592 | .int => |int| { | 1614 | .int => |int| { |
| 1593 | const info = ty.intInfo(mod); | 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 | else => unreachable, | 1620 | else => unreachable, |
| 1597 | }, | 1621 | }, |
| ... | @@ -1641,23 +1665,23 @@ pub const Value = struct { | ... | @@ -1641,23 +1665,23 @@ pub const Value = struct { |
| 1641 | /// Returns the number of bits the value requires to represent stored in twos complement form. | 1665 | /// Returns the number of bits the value requires to represent stored in twos complement form. |
| 1642 | pub fn intBitCountTwosComp(self: Value, mod: *const Module) usize { | 1666 | pub fn intBitCountTwosComp(self: Value, mod: *const Module) usize { |
| 1643 | const target = mod.getTarget(); | 1667 | const target = mod.getTarget(); |
| 1644 | switch (self.ip_index) { | 1668 | return switch (self.ip_index) { |
| 1645 | .bool_false => return 0, | 1669 | .bool_false => 0, |
| 1646 | .bool_true => return 1, | 1670 | .bool_true => 1, |
| 1647 | .none => switch (self.tag()) { | 1671 | .none => switch (self.tag()) { |
| 1648 | .zero, | 1672 | .zero, |
| 1649 | .the_only_possible_value, | 1673 | .the_only_possible_value, |
| 1650 | => return 0, | 1674 | => 0, |
| 1651 | 1675 | ||
| 1652 | .one => return 1, | 1676 | .one => 1, |
| 1653 | 1677 | ||
| 1654 | .int_u64 => { | 1678 | .int_u64 => { |
| 1655 | const x = self.castTag(.int_u64).?.data; | 1679 | const x = self.castTag(.int_u64).?.data; |
| 1656 | if (x == 0) return 0; | 1680 | if (x == 0) return 0; |
| 1657 | return @intCast(usize, std.math.log2(x) + 1); | 1681 | return @intCast(usize, std.math.log2(x) + 1); |
| 1658 | }, | 1682 | }, |
| 1659 | .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(), | 1683 | .int_big_positive => self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(), |
| 1660 | .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(), | 1684 | .int_big_negative => self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(), |
| 1661 | 1685 | ||
| 1662 | .decl_ref_mut, | 1686 | .decl_ref_mut, |
| 1663 | .comptime_field_ptr, | 1687 | .comptime_field_ptr, |
| ... | @@ -1667,7 +1691,7 @@ pub const Value = struct { | ... | @@ -1667,7 +1691,7 @@ pub const Value = struct { |
| 1667 | .variable, | 1691 | .variable, |
| 1668 | .eu_payload_ptr, | 1692 | .eu_payload_ptr, |
| 1669 | .opt_payload_ptr, | 1693 | .opt_payload_ptr, |
| 1670 | => return target.ptrBitWidth(), | 1694 | => target.ptrBitWidth(), |
| 1671 | 1695 | ||
| 1672 | else => { | 1696 | else => { |
| 1673 | var buffer: BigIntSpace = undefined; | 1697 | var buffer: BigIntSpace = undefined; |
| ... | @@ -1675,10 +1699,18 @@ pub const Value = struct { | ... | @@ -1675,10 +1699,18 @@ pub const Value = struct { |
| 1675 | }, | 1699 | }, |
| 1676 | }, | 1700 | }, |
| 1677 | else => switch (mod.intern_pool.indexToKey(self.ip_index)) { | 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 | else => unreachable, | 1711 | else => unreachable, |
| 1680 | }, | 1712 | }, |
| 1681 | } | 1713 | }; |
| 1682 | } | 1714 | } |
| 1683 | 1715 | ||
| 1684 | /// Converts an integer or a float to a float. May result in a loss of information. | 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,8 +1830,11 @@ pub const Value = struct { |
| 1798 | 1830 | ||
| 1799 | else => unreachable, | 1831 | else => unreachable, |
| 1800 | }, | 1832 | }, |
| 1801 | else => switch (mod.intern_pool.indexToKey(lhs.ip_index)) { | 1833 | else => return switch (mod.intern_pool.indexToKey(lhs.ip_index)) { |
| 1802 | .int => |int| return int.big_int.orderAgainstScalar(0), | 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 | else => unreachable, | 1838 | else => unreachable, |
| 1804 | }, | 1839 | }, |
| 1805 | } | 1840 | } |
| ... | @@ -2777,6 +2812,10 @@ pub const Value = struct { | ... | @@ -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 | /// Returns true if a Value is backed by a variable | 2819 | /// Returns true if a Value is backed by a variable |
| 2781 | pub fn isVariable(val: Value, mod: *Module) bool { | 2820 | pub fn isVariable(val: Value, mod: *Module) bool { |
| 2782 | return switch (val.ip_index) { | 2821 | return switch (val.ip_index) { |
| ... | @@ -5399,12 +5438,7 @@ pub const Value = struct { | ... | @@ -5399,12 +5438,7 @@ pub const Value = struct { |
| 5399 | }; | 5438 | }; |
| 5400 | }; | 5439 | }; |
| 5401 | 5440 | ||
| 5402 | /// Big enough to fit any non-BigInt value | 5441 | pub const BigIntSpace = InternPool.Key.Int.Storage.BigIntSpace; |
| 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 | }; | ||
| 5408 | 5442 | ||
| 5409 | pub const zero = initTag(.zero); | 5443 | pub const zero = initTag(.zero); |
| 5410 | pub const one = initTag(.one); | 5444 | pub const one = initTag(.one); |