Interner.zig (26780B) - Raw
1 const std = @import("std"); 2 const Allocator = std.mem.Allocator; 3 const assert = std.debug.assert; 4 const BigIntConst = std.math.big.int.Const; 5 const BigIntMutable = std.math.big.int.Mutable; 6 const Hash = std.hash.Wyhash; 7 const Limb = std.math.big.Limb; 8 9 const Interner = @This(); 10 11 map: std.AutoArrayHashMapUnmanaged(void, void) = .empty, 12 items: std.MultiArrayList(struct { 13 tag: Tag, 14 data: u32, 15 }) = .{}, 16 extra: std.ArrayListUnmanaged(u32) = .empty, 17 limbs: std.ArrayListUnmanaged(Limb) = .empty, 18 strings: std.ArrayListUnmanaged(u8) = .empty, 19 20 const KeyAdapter = struct { 21 interner: *const Interner, 22 23 pub fn eql(adapter: KeyAdapter, a: Key, b_void: void, b_map_index: usize) bool { 24 _ = b_void; 25 return adapter.interner.get(@as(Ref, @enumFromInt(b_map_index))).eql(a); 26 } 27 28 pub fn hash(adapter: KeyAdapter, a: Key) u32 { 29 _ = adapter; 30 return a.hash(); 31 } 32 }; 33 34 pub const Key = union(enum) { 35 int_ty: u16, 36 float_ty: u16, 37 complex_ty: u16, 38 ptr_ty, 39 noreturn_ty, 40 void_ty, 41 func_ty, 42 array_ty: struct { 43 len: u64, 44 child: Ref, 45 }, 46 vector_ty: struct { 47 len: u32, 48 child: Ref, 49 }, 50 record_ty: []const Ref, 51 /// May not be zero 52 null, 53 int: union(enum) { 54 u64: u64, 55 i64: i64, 56 big_int: BigIntConst, 57 58 pub fn toBigInt(repr: @This(), space: *Tag.Int.BigIntSpace) BigIntConst { 59 return switch (repr) { 60 .big_int => |x| x, 61 inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(), 62 }; 63 } 64 }, 65 float: Float, 66 complex: Complex, 67 bytes: []const u8, 68 69 pub const Float = union(enum) { 70 f16: f16, 71 f32: f32, 72 f64: f64, 73 f80: f80, 74 f128: f128, 75 }; 76 pub const Complex = union(enum) { 77 cf16: [2]f16, 78 cf32: [2]f32, 79 cf64: [2]f64, 80 cf80: [2]f80, 81 cf128: [2]f128, 82 }; 83 84 pub fn hash(key: Key) u32 { 85 var hasher = Hash.init(0); 86 const tag = std.meta.activeTag(key); 87 std.hash.autoHash(&hasher, tag); 88 switch (key) { 89 .bytes => |bytes| { 90 hasher.update(bytes); 91 }, 92 .record_ty => |elems| for (elems) |elem| { 93 std.hash.autoHash(&hasher, elem); 94 }, 95 .float => |repr| switch (repr) { 96 inline else => |data| std.hash.autoHash( 97 &hasher, 98 @as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)), 99 ), 100 }, 101 .complex => |repr| switch (repr) { 102 inline else => |data| std.hash.autoHash( 103 &hasher, 104 @as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(data))), @bitCast(data)), 105 ), 106 }, 107 .int => |repr| { 108 var space: Tag.Int.BigIntSpace = undefined; 109 const big = repr.toBigInt(&space); 110 std.hash.autoHash(&hasher, big.positive); 111 for (big.limbs) |limb| std.hash.autoHash(&hasher, limb); 112 }, 113 inline else => |info| { 114 std.hash.autoHash(&hasher, info); 115 }, 116 } 117 return @truncate(hasher.final()); 118 } 119 120 pub fn eql(a: Key, b: Key) bool { 121 const KeyTag = std.meta.Tag(Key); 122 const a_tag: KeyTag = a; 123 const b_tag: KeyTag = b; 124 if (a_tag != b_tag) return false; 125 switch (a) { 126 .record_ty => |a_elems| { 127 const b_elems = b.record_ty; 128 if (a_elems.len != b_elems.len) return false; 129 for (a_elems, b_elems) |a_elem, b_elem| { 130 if (a_elem != b_elem) return false; 131 } 132 return true; 133 }, 134 .bytes => |a_bytes| { 135 const b_bytes = b.bytes; 136 return std.mem.eql(u8, a_bytes, b_bytes); 137 }, 138 .int => |a_repr| { 139 var a_space: Tag.Int.BigIntSpace = undefined; 140 const a_big = a_repr.toBigInt(&a_space); 141 var b_space: Tag.Int.BigIntSpace = undefined; 142 const b_big = b.int.toBigInt(&b_space); 143 144 return a_big.eql(b_big); 145 }, 146 inline else => |a_info, tag| { 147 const b_info = @field(b, @tagName(tag)); 148 return std.meta.eql(a_info, b_info); 149 }, 150 } 151 } 152 153 fn toRef(key: Key) ?Ref { 154 switch (key) { 155 .int_ty => |bits| switch (bits) { 156 1 => return .i1, 157 8 => return .i8, 158 16 => return .i16, 159 32 => return .i32, 160 64 => return .i64, 161 128 => return .i128, 162 else => {}, 163 }, 164 .float_ty => |bits| switch (bits) { 165 16 => return .f16, 166 32 => return .f32, 167 64 => return .f64, 168 80 => return .f80, 169 128 => return .f128, 170 else => unreachable, 171 }, 172 .complex_ty => |bits| switch (bits) { 173 16 => return .cf16, 174 32 => return .cf32, 175 64 => return .cf64, 176 80 => return .cf80, 177 128 => return .cf128, 178 else => unreachable, 179 }, 180 .ptr_ty => return .ptr, 181 .func_ty => return .func, 182 .noreturn_ty => return .noreturn, 183 .void_ty => return .void, 184 .int => |repr| { 185 var space: Tag.Int.BigIntSpace = undefined; 186 const big = repr.toBigInt(&space); 187 if (big.eqlZero()) return .zero; 188 const big_one = BigIntConst{ .limbs = &.{1}, .positive = true }; 189 if (big.eql(big_one)) return .one; 190 }, 191 .float => |repr| switch (repr) { 192 inline else => |data| { 193 if (std.math.isPositiveZero(data)) return .zero; 194 if (data == 1) return .one; 195 }, 196 }, 197 .null => return .null, 198 else => {}, 199 } 200 return null; 201 } 202 }; 203 204 pub const Ref = enum(u32) { 205 const max = std.math.maxInt(u32); 206 207 ptr = max - 1, 208 noreturn = max - 2, 209 void = max - 3, 210 i1 = max - 4, 211 i8 = max - 5, 212 i16 = max - 6, 213 i32 = max - 7, 214 i64 = max - 8, 215 i128 = max - 9, 216 f16 = max - 10, 217 f32 = max - 11, 218 f64 = max - 12, 219 f80 = max - 13, 220 f128 = max - 14, 221 func = max - 15, 222 zero = max - 16, 223 one = max - 17, 224 null = max - 18, 225 cf16 = max - 19, 226 cf32 = max - 20, 227 cf64 = max - 21, 228 cf80 = max - 22, 229 cf128 = max - 23, 230 _, 231 }; 232 233 pub const OptRef = enum(u32) { 234 const max = std.math.maxInt(u32); 235 236 none = max - 0, 237 ptr = max - 1, 238 noreturn = max - 2, 239 void = max - 3, 240 i1 = max - 4, 241 i8 = max - 5, 242 i16 = max - 6, 243 i32 = max - 7, 244 i64 = max - 8, 245 i128 = max - 9, 246 f16 = max - 10, 247 f32 = max - 11, 248 f64 = max - 12, 249 f80 = max - 13, 250 f128 = max - 14, 251 func = max - 15, 252 zero = max - 16, 253 one = max - 17, 254 null = max - 18, 255 cf16 = max - 19, 256 cf32 = max - 20, 257 cf64 = max - 21, 258 cf80 = max - 22, 259 cf128 = max - 23, 260 _, 261 }; 262 263 pub const Tag = enum(u8) { 264 /// `data` is `u16` 265 int_ty, 266 /// `data` is `u16` 267 float_ty, 268 /// `data` is `u16` 269 complex_ty, 270 /// `data` is index to `Array` 271 array_ty, 272 /// `data` is index to `Vector` 273 vector_ty, 274 /// `data` is `u32` 275 u32, 276 /// `data` is `i32` 277 i32, 278 /// `data` is `Int` 279 int_positive, 280 /// `data` is `Int` 281 int_negative, 282 /// `data` is `f16` 283 f16, 284 /// `data` is `f32` 285 f32, 286 /// `data` is `F64` 287 f64, 288 /// `data` is `F80` 289 f80, 290 /// `data` is `F128` 291 f128, 292 /// `data` is `CF16` 293 cf16, 294 /// `data` is `CF32` 295 cf32, 296 /// `data` is `CF64` 297 cf64, 298 /// `data` is `CF80` 299 cf80, 300 /// `data` is `CF128` 301 cf128, 302 /// `data` is `Bytes` 303 bytes, 304 /// `data` is `Record` 305 record_ty, 306 307 pub const Array = struct { 308 len0: u32, 309 len1: u32, 310 child: Ref, 311 312 pub fn getLen(a: Array) u64 { 313 return (PackedU64{ 314 .a = a.len0, 315 .b = a.len1, 316 }).get(); 317 } 318 }; 319 320 pub const Vector = struct { 321 len: u32, 322 child: Ref, 323 }; 324 325 pub const Int = struct { 326 limbs_index: u32, 327 limbs_len: u32, 328 329 /// Big enough to fit any non-BigInt value 330 pub const BigIntSpace = struct { 331 /// The +1 is headroom so that operations such as incrementing once 332 /// or decrementing once are possible without using an allocator. 333 limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb, 334 }; 335 }; 336 337 pub const F64 = struct { 338 piece0: u32, 339 piece1: u32, 340 341 pub fn get(self: F64) f64 { 342 const int_bits = @as(u64, self.piece0) | (@as(u64, self.piece1) << 32); 343 return @bitCast(int_bits); 344 } 345 346 fn pack(val: f64) F64 { 347 const bits = @as(u64, @bitCast(val)); 348 return .{ 349 .piece0 = @as(u32, @truncate(bits)), 350 .piece1 = @as(u32, @truncate(bits >> 32)), 351 }; 352 } 353 }; 354 355 pub const F80 = struct { 356 piece0: u32, 357 piece1: u32, 358 piece2: u32, // u16 part, top bits 359 360 pub fn get(self: F80) f80 { 361 const int_bits = @as(u80, self.piece0) | 362 (@as(u80, self.piece1) << 32) | 363 (@as(u80, self.piece2) << 64); 364 return @bitCast(int_bits); 365 } 366 367 fn pack(val: f80) F80 { 368 const bits = @as(u80, @bitCast(val)); 369 return .{ 370 .piece0 = @as(u32, @truncate(bits)), 371 .piece1 = @as(u32, @truncate(bits >> 32)), 372 .piece2 = @as(u16, @truncate(bits >> 64)), 373 }; 374 } 375 }; 376 377 pub const F128 = struct { 378 piece0: u32, 379 piece1: u32, 380 piece2: u32, 381 piece3: u32, 382 383 pub fn get(self: F128) f128 { 384 const int_bits = @as(u128, self.piece0) | 385 (@as(u128, self.piece1) << 32) | 386 (@as(u128, self.piece2) << 64) | 387 (@as(u128, self.piece3) << 96); 388 return @bitCast(int_bits); 389 } 390 391 fn pack(val: f128) F128 { 392 const bits = @as(u128, @bitCast(val)); 393 return .{ 394 .piece0 = @as(u32, @truncate(bits)), 395 .piece1 = @as(u32, @truncate(bits >> 32)), 396 .piece2 = @as(u32, @truncate(bits >> 64)), 397 .piece3 = @as(u32, @truncate(bits >> 96)), 398 }; 399 } 400 }; 401 402 pub const CF16 = struct { 403 piece0: u32, 404 405 pub fn get(self: CF16) [2]f16 { 406 const real: f16 = @bitCast(@as(u16, @truncate(self.piece0 >> 16))); 407 const imag: f16 = @bitCast(@as(u16, @truncate(self.piece0))); 408 return .{ 409 real, 410 imag, 411 }; 412 } 413 414 fn pack(val: [2]f16) CF16 { 415 const real: u16 = @bitCast(val[0]); 416 const imag: u16 = @bitCast(val[1]); 417 return .{ 418 .piece0 = (@as(u32, real) << 16) | @as(u32, imag), 419 }; 420 } 421 }; 422 423 pub const CF32 = struct { 424 piece0: u32, 425 piece1: u32, 426 427 pub fn get(self: CF32) [2]f32 { 428 return .{ 429 @bitCast(self.piece0), 430 @bitCast(self.piece1), 431 }; 432 } 433 434 fn pack(val: [2]f32) CF32 { 435 return .{ 436 .piece0 = @bitCast(val[0]), 437 .piece1 = @bitCast(val[1]), 438 }; 439 } 440 }; 441 442 pub const CF64 = struct { 443 piece0: u32, 444 piece1: u32, 445 piece2: u32, 446 piece3: u32, 447 448 pub fn get(self: CF64) [2]f64 { 449 return .{ 450 (F64{ .piece0 = self.piece0, .piece1 = self.piece1 }).get(), 451 (F64{ .piece0 = self.piece2, .piece1 = self.piece3 }).get(), 452 }; 453 } 454 455 fn pack(val: [2]f64) CF64 { 456 const real = F64.pack(val[0]); 457 const imag = F64.pack(val[1]); 458 return .{ 459 .piece0 = real.piece0, 460 .piece1 = real.piece1, 461 .piece2 = imag.piece0, 462 .piece3 = imag.piece1, 463 }; 464 } 465 }; 466 467 /// TODO pack into 5 pieces 468 pub const CF80 = struct { 469 piece0: u32, 470 piece1: u32, 471 piece2: u32, // u16 part, top bits 472 piece3: u32, 473 piece4: u32, 474 piece5: u32, // u16 part, top bits 475 476 pub fn get(self: CF80) [2]f80 { 477 return .{ 478 (F80{ .piece0 = self.piece0, .piece1 = self.piece1, .piece2 = self.piece2 }).get(), 479 (F80{ .piece0 = self.piece3, .piece1 = self.piece4, .piece2 = self.piece5 }).get(), 480 }; 481 } 482 483 fn pack(val: [2]f80) CF80 { 484 const real = F80.pack(val[0]); 485 const imag = F80.pack(val[1]); 486 return .{ 487 .piece0 = real.piece0, 488 .piece1 = real.piece1, 489 .piece2 = real.piece2, 490 .piece3 = imag.piece0, 491 .piece4 = imag.piece1, 492 .piece5 = imag.piece2, 493 }; 494 } 495 }; 496 497 pub const CF128 = struct { 498 piece0: u32, 499 piece1: u32, 500 piece2: u32, 501 piece3: u32, 502 piece4: u32, 503 piece5: u32, 504 piece6: u32, 505 piece7: u32, 506 507 pub fn get(self: CF128) [2]f128 { 508 return .{ 509 (F128{ .piece0 = self.piece0, .piece1 = self.piece1, .piece2 = self.piece2, .piece3 = self.piece3 }).get(), 510 (F128{ .piece0 = self.piece4, .piece1 = self.piece5, .piece2 = self.piece6, .piece3 = self.piece7 }).get(), 511 }; 512 } 513 514 fn pack(val: [2]f128) CF128 { 515 const real = F128.pack(val[0]); 516 const imag = F128.pack(val[1]); 517 return .{ 518 .piece0 = real.piece0, 519 .piece1 = real.piece1, 520 .piece2 = real.piece2, 521 .piece3 = real.piece3, 522 .piece4 = imag.piece0, 523 .piece5 = imag.piece1, 524 .piece6 = imag.piece2, 525 .piece7 = imag.piece3, 526 }; 527 } 528 }; 529 530 pub const Bytes = struct { 531 strings_index: u32, 532 len: u32, 533 }; 534 535 pub const Record = struct { 536 elements_len: u32, 537 // trailing 538 // [elements_len]Ref 539 }; 540 }; 541 542 pub const PackedU64 = packed struct(u64) { 543 a: u32, 544 b: u32, 545 546 pub fn get(x: PackedU64) u64 { 547 return @bitCast(x); 548 } 549 550 pub fn init(x: u64) PackedU64 { 551 return @bitCast(x); 552 } 553 }; 554 555 pub fn deinit(i: *Interner, gpa: Allocator) void { 556 i.map.deinit(gpa); 557 i.items.deinit(gpa); 558 i.extra.deinit(gpa); 559 i.limbs.deinit(gpa); 560 i.strings.deinit(gpa); 561 } 562 563 pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref { 564 if (key.toRef()) |some| return some; 565 const adapter: KeyAdapter = .{ .interner = i }; 566 const gop = try i.map.getOrPutAdapted(gpa, key, adapter); 567 if (gop.found_existing) return @enumFromInt(gop.index); 568 try i.items.ensureUnusedCapacity(gpa, 1); 569 570 switch (key) { 571 .int_ty => |bits| { 572 i.items.appendAssumeCapacity(.{ 573 .tag = .int_ty, 574 .data = bits, 575 }); 576 }, 577 .float_ty => |bits| { 578 i.items.appendAssumeCapacity(.{ 579 .tag = .float_ty, 580 .data = bits, 581 }); 582 }, 583 .complex_ty => |bits| { 584 i.items.appendAssumeCapacity(.{ 585 .tag = .complex_ty, 586 .data = bits, 587 }); 588 }, 589 .array_ty => |info| { 590 const split_len = PackedU64.init(info.len); 591 i.items.appendAssumeCapacity(.{ 592 .tag = .array_ty, 593 .data = try i.addExtra(gpa, Tag.Array{ 594 .len0 = split_len.a, 595 .len1 = split_len.b, 596 .child = info.child, 597 }), 598 }); 599 }, 600 .vector_ty => |info| { 601 i.items.appendAssumeCapacity(.{ 602 .tag = .vector_ty, 603 .data = try i.addExtra(gpa, Tag.Vector{ 604 .len = info.len, 605 .child = info.child, 606 }), 607 }); 608 }, 609 .int => |repr| int: { 610 var space: Tag.Int.BigIntSpace = undefined; 611 const big = repr.toBigInt(&space); 612 switch (repr) { 613 .u64 => |data| if (std.math.cast(u32, data)) |small| { 614 i.items.appendAssumeCapacity(.{ 615 .tag = .u32, 616 .data = small, 617 }); 618 break :int; 619 }, 620 .i64 => |data| if (std.math.cast(i32, data)) |small| { 621 i.items.appendAssumeCapacity(.{ 622 .tag = .i32, 623 .data = @bitCast(small), 624 }); 625 break :int; 626 }, 627 .big_int => |data| { 628 if (data.fitsInTwosComp(.unsigned, 32)) { 629 i.items.appendAssumeCapacity(.{ 630 .tag = .u32, 631 .data = data.toInt(u32) catch unreachable, 632 }); 633 break :int; 634 } else if (data.fitsInTwosComp(.signed, 32)) { 635 i.items.appendAssumeCapacity(.{ 636 .tag = .i32, 637 .data = @bitCast(data.toInt(i32) catch unreachable), 638 }); 639 break :int; 640 } 641 }, 642 } 643 const limbs_index: u32 = @intCast(i.limbs.items.len); 644 try i.limbs.appendSlice(gpa, big.limbs); 645 i.items.appendAssumeCapacity(.{ 646 .tag = if (big.positive) .int_positive else .int_negative, 647 .data = try i.addExtra(gpa, Tag.Int{ 648 .limbs_index = limbs_index, 649 .limbs_len = @intCast(big.limbs.len), 650 }), 651 }); 652 }, 653 .float => |repr| switch (repr) { 654 .f16 => |data| i.items.appendAssumeCapacity(.{ 655 .tag = .f16, 656 .data = @as(u16, @bitCast(data)), 657 }), 658 .f32 => |data| i.items.appendAssumeCapacity(.{ 659 .tag = .f32, 660 .data = @as(u32, @bitCast(data)), 661 }), 662 .f64 => |data| i.items.appendAssumeCapacity(.{ 663 .tag = .f64, 664 .data = try i.addExtra(gpa, Tag.F64.pack(data)), 665 }), 666 .f80 => |data| i.items.appendAssumeCapacity(.{ 667 .tag = .f80, 668 .data = try i.addExtra(gpa, Tag.F80.pack(data)), 669 }), 670 .f128 => |data| i.items.appendAssumeCapacity(.{ 671 .tag = .f128, 672 .data = try i.addExtra(gpa, Tag.F128.pack(data)), 673 }), 674 }, 675 .complex => |repr| switch (repr) { 676 .cf16 => |data| i.items.appendAssumeCapacity(.{ 677 .tag = .cf16, 678 .data = try i.addExtra(gpa, Tag.CF16.pack(data)), 679 }), 680 .cf32 => |data| i.items.appendAssumeCapacity(.{ 681 .tag = .cf32, 682 .data = try i.addExtra(gpa, Tag.CF32.pack(data)), 683 }), 684 .cf64 => |data| i.items.appendAssumeCapacity(.{ 685 .tag = .cf64, 686 .data = try i.addExtra(gpa, Tag.CF64.pack(data)), 687 }), 688 .cf80 => |data| i.items.appendAssumeCapacity(.{ 689 .tag = .cf80, 690 .data = try i.addExtra(gpa, Tag.CF80.pack(data)), 691 }), 692 .cf128 => |data| i.items.appendAssumeCapacity(.{ 693 .tag = .cf128, 694 .data = try i.addExtra(gpa, Tag.CF128.pack(data)), 695 }), 696 }, 697 .bytes => |bytes| { 698 const strings_index: u32 = @intCast(i.strings.items.len); 699 try i.strings.appendSlice(gpa, bytes); 700 i.items.appendAssumeCapacity(.{ 701 .tag = .bytes, 702 .data = try i.addExtra(gpa, Tag.Bytes{ 703 .strings_index = strings_index, 704 .len = @intCast(bytes.len), 705 }), 706 }); 707 }, 708 .record_ty => |elems| { 709 try i.extra.ensureUnusedCapacity(gpa, @typeInfo(Tag.Record).@"struct".fields.len + 710 elems.len); 711 i.items.appendAssumeCapacity(.{ 712 .tag = .record_ty, 713 .data = i.addExtraAssumeCapacity(Tag.Record{ 714 .elements_len = @intCast(elems.len), 715 }), 716 }); 717 i.extra.appendSliceAssumeCapacity(@ptrCast(elems)); 718 }, 719 .ptr_ty, 720 .noreturn_ty, 721 .void_ty, 722 .func_ty, 723 .null, 724 => unreachable, 725 } 726 727 return @enumFromInt(gop.index); 728 } 729 730 fn addExtra(i: *Interner, gpa: Allocator, extra: anytype) Allocator.Error!u32 { 731 const fields = @typeInfo(@TypeOf(extra)).@"struct".fields; 732 try i.extra.ensureUnusedCapacity(gpa, fields.len); 733 return i.addExtraAssumeCapacity(extra); 734 } 735 736 fn addExtraAssumeCapacity(i: *Interner, extra: anytype) u32 { 737 const result = @as(u32, @intCast(i.extra.items.len)); 738 inline for (@typeInfo(@TypeOf(extra)).@"struct".fields) |field| { 739 i.extra.appendAssumeCapacity(switch (field.type) { 740 Ref => @intFromEnum(@field(extra, field.name)), 741 u32 => @field(extra, field.name), 742 else => @compileError("bad field type: " ++ @typeName(field.type)), 743 }); 744 } 745 return result; 746 } 747 748 pub fn get(i: *const Interner, ref: Ref) Key { 749 switch (ref) { 750 .ptr => return .ptr_ty, 751 .func => return .func_ty, 752 .noreturn => return .noreturn_ty, 753 .void => return .void_ty, 754 .i1 => return .{ .int_ty = 1 }, 755 .i8 => return .{ .int_ty = 8 }, 756 .i16 => return .{ .int_ty = 16 }, 757 .i32 => return .{ .int_ty = 32 }, 758 .i64 => return .{ .int_ty = 64 }, 759 .i128 => return .{ .int_ty = 128 }, 760 .f16 => return .{ .float_ty = 16 }, 761 .f32 => return .{ .float_ty = 32 }, 762 .f64 => return .{ .float_ty = 64 }, 763 .f80 => return .{ .float_ty = 80 }, 764 .f128 => return .{ .float_ty = 128 }, 765 .zero => return .{ .int = .{ .u64 = 0 } }, 766 .one => return .{ .int = .{ .u64 = 1 } }, 767 .null => return .null, 768 .cf16 => return .{ .complex_ty = 16 }, 769 .cf32 => return .{ .complex_ty = 32 }, 770 .cf64 => return .{ .complex_ty = 64 }, 771 .cf80 => return .{ .complex_ty = 80 }, 772 else => {}, 773 } 774 775 const item = i.items.get(@intFromEnum(ref)); 776 const data = item.data; 777 return switch (item.tag) { 778 .int_ty => .{ .int_ty = @intCast(data) }, 779 .float_ty => .{ .float_ty = @intCast(data) }, 780 .complex_ty => .{ .complex_ty = @intCast(data) }, 781 .array_ty => { 782 const array_ty = i.extraData(Tag.Array, data); 783 return .{ .array_ty = .{ 784 .len = array_ty.getLen(), 785 .child = array_ty.child, 786 } }; 787 }, 788 .vector_ty => { 789 const vector_ty = i.extraData(Tag.Vector, data); 790 return .{ .vector_ty = .{ 791 .len = vector_ty.len, 792 .child = vector_ty.child, 793 } }; 794 }, 795 .u32 => .{ .int = .{ .u64 = data } }, 796 .i32 => .{ .int = .{ .i64 = @as(i32, @bitCast(data)) } }, 797 .int_positive, .int_negative => { 798 const int_info = i.extraData(Tag.Int, data); 799 const limbs = i.limbs.items[int_info.limbs_index..][0..int_info.limbs_len]; 800 return .{ .int = .{ 801 .big_int = .{ 802 .positive = item.tag == .int_positive, 803 .limbs = limbs, 804 }, 805 } }; 806 }, 807 .f16 => .{ .float = .{ .f16 = @bitCast(@as(u16, @intCast(data))) } }, 808 .f32 => .{ .float = .{ .f32 = @bitCast(data) } }, 809 .f64 => { 810 const float = i.extraData(Tag.F64, data); 811 return .{ .float = .{ .f64 = float.get() } }; 812 }, 813 .f80 => { 814 const float = i.extraData(Tag.F80, data); 815 return .{ .float = .{ .f80 = float.get() } }; 816 }, 817 .f128 => { 818 const float = i.extraData(Tag.F128, data); 819 return .{ .float = .{ .f128 = float.get() } }; 820 }, 821 .cf16 => { 822 const components = i.extraData(Tag.CF16, data); 823 return .{ .complex = .{ .cf16 = components.get() } }; 824 }, 825 .cf32 => { 826 const components = i.extraData(Tag.CF32, data); 827 return .{ .complex = .{ .cf32 = components.get() } }; 828 }, 829 .cf64 => { 830 const components = i.extraData(Tag.CF64, data); 831 return .{ .complex = .{ .cf64 = components.get() } }; 832 }, 833 .cf80 => { 834 const components = i.extraData(Tag.CF80, data); 835 return .{ .complex = .{ .cf80 = components.get() } }; 836 }, 837 .cf128 => { 838 const components = i.extraData(Tag.CF128, data); 839 return .{ .complex = .{ .cf128 = components.get() } }; 840 }, 841 .bytes => { 842 const bytes = i.extraData(Tag.Bytes, data); 843 return .{ .bytes = i.strings.items[bytes.strings_index..][0..bytes.len] }; 844 }, 845 .record_ty => { 846 const extra = i.extraDataTrail(Tag.Record, data); 847 return .{ 848 .record_ty = @ptrCast(i.extra.items[extra.end..][0..extra.data.elements_len]), 849 }; 850 }, 851 }; 852 } 853 854 fn extraData(i: *const Interner, comptime T: type, index: usize) T { 855 return i.extraDataTrail(T, index).data; 856 } 857 858 fn extraDataTrail(i: *const Interner, comptime T: type, index: usize) struct { data: T, end: u32 } { 859 var result: T = undefined; 860 const fields = @typeInfo(T).@"struct".fields; 861 inline for (fields, 0..) |field, field_i| { 862 const int32 = i.extra.items[field_i + index]; 863 @field(result, field.name) = switch (field.type) { 864 Ref => @enumFromInt(int32), 865 u32 => int32, 866 else => @compileError("bad field type: " ++ @typeName(field.type)), 867 }; 868 } 869 return .{ 870 .data = result, 871 .end = @intCast(index + fields.len), 872 }; 873 }