| ... | @@ -30,6 +30,7 @@ const SpvAssembler = @import("spirv/Assembler.zig"); | ... | @@ -30,6 +30,7 @@ const SpvAssembler = @import("spirv/Assembler.zig"); |
| 30 | const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef); | 30 | const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef); |
| 31 | | 31 | |
| 32 | pub const zig_call_abi_ver = 3; | 32 | pub const zig_call_abi_ver = 3; |
| | 33 | pub const big_int_bits = 32; |
| 33 | | 34 | |
| 34 | const InternMap = std.AutoHashMapUnmanaged(struct { InternPool.Index, NavGen.Repr }, IdResult); | 35 | const InternMap = std.AutoHashMapUnmanaged(struct { InternPool.Index, NavGen.Repr }, IdResult); |
| 35 | const PtrTypeMap = std.AutoHashMapUnmanaged( | 36 | const PtrTypeMap = std.AutoHashMapUnmanaged( |
| ... | @@ -376,7 +377,7 @@ const NavGen = struct { | ... | @@ -376,7 +377,7 @@ const NavGen = struct { |
| 376 | /// The number of bits required to store the type. | 377 | /// The number of bits required to store the type. |
| 377 | /// For `integer` and `float`, this is equal to `bits`. | 378 | /// For `integer` and `float`, this is equal to `bits`. |
| 378 | /// For `strange_integer` and `bool` this is the size of the backing integer. | 379 | /// For `strange_integer` and `bool` this is the size of the backing integer. |
| 379 | /// For `composite_integer` this is 0 (TODO) | 380 | /// For `composite_integer` this is the elements count. |
| 380 | backing_bits: u16, | 381 | backing_bits: u16, |
| 381 | | 382 | |
| 382 | /// Null if this type is a scalar, or the length | 383 | /// Null if this type is a scalar, or the length |
| ... | @@ -579,11 +580,13 @@ const NavGen = struct { | ... | @@ -579,11 +580,13 @@ const NavGen = struct { |
| 579 | /// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits. | 580 | /// The backing type will be chosen as the smallest supported integer larger or equal to it in number of bits. |
| 580 | /// The result is valid to be used with OpTypeInt. | 581 | /// The result is valid to be used with OpTypeInt. |
| 581 | /// TODO: Should the result of this function be cached? | 582 | /// TODO: Should the result of this function be cached? |
| 582 | fn backingIntBits(self: *NavGen, bits: u16) ?u16 { | 583 | fn backingIntBits(self: *NavGen, bits: u16) struct { u16, bool } { |
| 583 | // The backend will never be asked to compiler a 0-bit integer, so we won't have to handle those in this function. | 584 | // The backend will never be asked to compiler a 0-bit integer, so we won't have to handle those in this function. |
| 584 | assert(bits != 0); | 585 | assert(bits != 0); |
| 585 | | 586 | |
| 586 | if (self.spv.hasFeature(.arbitrary_precision_integers) and bits <= 32) return bits; | 587 | if (self.spv.hasFeature(.arbitrary_precision_integers) and bits <= 32) { |
| | 588 | return .{ bits, false }; |
| | 589 | } |
| 587 | | 590 | |
| 588 | // We require Int8 and Int16 capabilities and benefit Int64 when available. | 591 | // We require Int8 and Int16 capabilities and benefit Int64 when available. |
| 589 | // 32-bit integers are always supported (see spec, 2.16.1, Data rules). | 592 | // 32-bit integers are always supported (see spec, 2.16.1, Data rules). |
| ... | @@ -596,10 +599,11 @@ const NavGen = struct { | ... | @@ -596,10 +599,11 @@ const NavGen = struct { |
| 596 | | 599 | |
| 597 | for (ints) |int| { | 600 | for (ints) |int| { |
| 598 | const has_feature = if (int.feature) |feature| self.spv.hasFeature(feature) else true; | 601 | const has_feature = if (int.feature) |feature| self.spv.hasFeature(feature) else true; |
| 599 | if (bits <= int.bits and has_feature) return int.bits; | 602 | if (bits <= int.bits and has_feature) return .{ int.bits, false }; |
| 600 | } | 603 | } |
| 601 | | 604 | |
| 602 | return null; | 605 | // Big int |
| | 606 | return .{ std.mem.alignForward(u16, bits, big_int_bits), true }; |
| 603 | } | 607 | } |
| 604 | | 608 | |
| 605 | /// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if | 609 | /// Return the amount of bits in the largest supported integer type. This is either 32 (always supported), or 64 (if |
| ... | @@ -623,7 +627,7 @@ const NavGen = struct { | ... | @@ -623,7 +627,7 @@ const NavGen = struct { |
| 623 | return switch (scalar_ty.zigTypeTag(zcu)) { | 627 | return switch (scalar_ty.zigTypeTag(zcu)) { |
| 624 | .bool => .{ | 628 | .bool => .{ |
| 625 | .bits = 1, // Doesn't matter for this class. | 629 | .bits = 1, // Doesn't matter for this class. |
| 626 | .backing_bits = self.backingIntBits(1).?, | 630 | .backing_bits = self.backingIntBits(1).@"0", |
| 627 | .vector_len = vector_len, | 631 | .vector_len = vector_len, |
| 628 | .signedness = .unsigned, // Technically, but doesn't matter for this class. | 632 | .signedness = .unsigned, // Technically, but doesn't matter for this class. |
| 629 | .class = .bool, | 633 | .class = .bool, |
| ... | @@ -638,19 +642,16 @@ const NavGen = struct { | ... | @@ -638,19 +642,16 @@ const NavGen = struct { |
| 638 | .int => blk: { | 642 | .int => blk: { |
| 639 | const int_info = scalar_ty.intInfo(zcu); | 643 | const int_info = scalar_ty.intInfo(zcu); |
| 640 | // TODO: Maybe it's useful to also return this value. | 644 | // TODO: Maybe it's useful to also return this value. |
| 641 | const maybe_backing_bits = self.backingIntBits(int_info.bits); | 645 | const backing_bits, const big_int = self.backingIntBits(int_info.bits); |
| 642 | break :blk .{ | 646 | break :blk .{ |
| 643 | .bits = int_info.bits, | 647 | .bits = int_info.bits, |
| 644 | .backing_bits = maybe_backing_bits orelse 0, | 648 | .backing_bits = backing_bits, |
| 645 | .vector_len = vector_len, | 649 | .vector_len = vector_len, |
| 646 | .signedness = int_info.signedness, | 650 | .signedness = int_info.signedness, |
| 647 | .class = if (maybe_backing_bits) |backing_bits| | 651 | .class = class: { |
| 648 | if (backing_bits == int_info.bits) | 652 | if (big_int) break :class .composite_integer; |
| 649 | .integer | 653 | break :class if (backing_bits == int_info.bits) .integer else .strange_integer; |
| 650 | else | 654 | }, |
| 651 | .strange_integer | | |
| 652 | else | | |
| 653 | .composite_integer, | | |
| 654 | }; | 655 | }; |
| 655 | }, | 656 | }, |
| 656 | .@"enum" => unreachable, | 657 | .@"enum" => unreachable, |
| ... | @@ -659,6 +660,34 @@ const NavGen = struct { | ... | @@ -659,6 +660,34 @@ const NavGen = struct { |
| 659 | }; | 660 | }; |
| 660 | } | 661 | } |
| 661 | | 662 | |
| | 663 | /// Checks whether the type can be directly translated to SPIR-V vectors |
| | 664 | fn isSpvVector(self: *NavGen, ty: Type) bool { |
| | 665 | const zcu = self.pt.zcu; |
| | 666 | if (ty.zigTypeTag(zcu) != .vector) return false; |
| | 667 | |
| | 668 | // TODO: This check must be expanded for types that can be represented |
| | 669 | // as integers (enums / packed structs?) and types that are represented |
| | 670 | // by multiple SPIR-V values. |
| | 671 | const scalar_ty = ty.scalarType(zcu); |
| | 672 | switch (scalar_ty.zigTypeTag(zcu)) { |
| | 673 | .bool, |
| | 674 | .int, |
| | 675 | .float, |
| | 676 | => {}, |
| | 677 | else => return false, |
| | 678 | } |
| | 679 | |
| | 680 | const elem_ty = ty.childType(zcu); |
| | 681 | const len = ty.vectorLen(zcu); |
| | 682 | |
| | 683 | if (elem_ty.isNumeric(zcu) or elem_ty.toIntern() == .bool_type) { |
| | 684 | if (len > 1 and len <= 4) return true; |
| | 685 | if (self.spv.hasFeature(.vector16)) return (len == 8 or len == 16); |
| | 686 | } |
| | 687 | |
| | 688 | return false; |
| | 689 | } |
| | 690 | |
| 662 | /// Emits a bool constant in a particular representation. | 691 | /// Emits a bool constant in a particular representation. |
| 663 | fn constBool(self: *NavGen, value: bool, repr: Repr) !IdRef { | 692 | fn constBool(self: *NavGen, value: bool, repr: Repr) !IdRef { |
| 664 | return switch (repr) { | 693 | return switch (repr) { |
| ... | @@ -675,14 +704,26 @@ const NavGen = struct { | ... | @@ -675,14 +704,26 @@ const NavGen = struct { |
| 675 | const scalar_ty = ty.scalarType(zcu); | 704 | const scalar_ty = ty.scalarType(zcu); |
| 676 | const int_info = scalar_ty.intInfo(zcu); | 705 | const int_info = scalar_ty.intInfo(zcu); |
| 677 | // Use backing bits so that negatives are sign extended | 706 | // Use backing bits so that negatives are sign extended |
| 678 | const backing_bits = self.backingIntBits(int_info.bits).?; // Assertion failure means big int | 707 | const backing_bits, const big_int = self.backingIntBits(int_info.bits); |
| 679 | assert(backing_bits != 0); // u0 is comptime | 708 | assert(backing_bits != 0); // u0 is comptime |
| 680 | | 709 | |
| | 710 | const result_ty_id = try self.resolveType(scalar_ty, .indirect); |
| 681 | const signedness: Signedness = switch (@typeInfo(@TypeOf(value))) { | 711 | const signedness: Signedness = switch (@typeInfo(@TypeOf(value))) { |
| 682 | .int => |int| int.signedness, | 712 | .int => |int| int.signedness, |
| 683 | .comptime_int => if (value < 0) .signed else .unsigned, | 713 | .comptime_int => if (value < 0) .signed else .unsigned, |
| 684 | else => unreachable, | 714 | else => unreachable, |
| 685 | }; | 715 | }; |
| | 716 | if (@sizeOf(@TypeOf(value)) >= 4 and big_int) { |
| | 717 | const value64: u64 = switch (signedness) { |
| | 718 | .signed => @bitCast(@as(i64, @intCast(value))), |
| | 719 | .unsigned => @as(u64, @intCast(value)), |
| | 720 | }; |
| | 721 | assert(backing_bits == 64); |
| | 722 | return self.constructComposite(result_ty_id, &.{ |
| | 723 | try self.constInt(.u32, @as(u32, @truncate(value64))), |
| | 724 | try self.constInt(.u32, @as(u32, @truncate(value64 << 32))), |
| | 725 | }); |
| | 726 | } |
| 686 | | 727 | |
| 687 | const final_value: spec.LiteralContextDependentNumber = blk: { | 728 | const final_value: spec.LiteralContextDependentNumber = blk: { |
| 688 | if (self.spv.hasFeature(.kernel)) { | 729 | if (self.spv.hasFeature(.kernel)) { |
| ... | @@ -700,18 +741,17 @@ const NavGen = struct { | ... | @@ -700,18 +741,17 @@ const NavGen = struct { |
| 700 | break :blk switch (backing_bits) { | 741 | break :blk switch (backing_bits) { |
| 701 | 1...32 => .{ .uint32 = @truncate(truncated_value) }, | 742 | 1...32 => .{ .uint32 = @truncate(truncated_value) }, |
| 702 | 33...64 => .{ .uint64 = truncated_value }, | 743 | 33...64 => .{ .uint64 = truncated_value }, |
| 703 | else => unreachable, // TODO: Large integer constants | 744 | else => unreachable, |
| 704 | }; | 745 | }; |
| 705 | } | 746 | } |
| 706 | | 747 | |
| 707 | break :blk switch (backing_bits) { | 748 | break :blk switch (backing_bits) { |
| 708 | 1...32 => if (signedness == .signed) .{ .int32 = @intCast(value) } else .{ .uint32 = @intCast(value) }, | 749 | 1...32 => if (signedness == .signed) .{ .int32 = @intCast(value) } else .{ .uint32 = @intCast(value) }, |
| 709 | 33...64 => if (signedness == .signed) .{ .int64 = value } else .{ .uint64 = value }, | 750 | 33...64 => if (signedness == .signed) .{ .int64 = value } else .{ .uint64 = value }, |
| 710 | else => unreachable, // TODO: Large integer constants | 751 | else => unreachable, |
| 711 | }; | 752 | }; |
| 712 | }; | 753 | }; |
| 713 | | 754 | |
| 714 | const result_ty_id = try self.resolveType(scalar_ty, .indirect); | | |
| 715 | const result_id = try self.spv.constant(result_ty_id, final_value); | 755 | const result_id = try self.spv.constant(result_ty_id, final_value); |
| 716 | | 756 | |
| 717 | if (!ty.isVector(zcu)) return result_id; | 757 | if (!ty.isVector(zcu)) return result_id; |
| ... | @@ -949,7 +989,7 @@ const NavGen = struct { | ... | @@ -949,7 +989,7 @@ const NavGen = struct { |
| 949 | // TODO: composite int | 989 | // TODO: composite int |
| 950 | // TODO: endianness | 990 | // TODO: endianness |
| 951 | const bits: u16 = @intCast(ty.bitSize(zcu)); | 991 | const bits: u16 = @intCast(ty.bitSize(zcu)); |
| 952 | const bytes = std.mem.alignForward(u16, self.backingIntBits(bits).?, 8) / 8; | 992 | const bytes = std.mem.alignForward(u16, self.backingIntBits(bits).@"0", 8) / 8; |
| 953 | var limbs: [8]u8 = undefined; | 993 | var limbs: [8]u8 = undefined; |
| 954 | @memset(&limbs, 0); | 994 | @memset(&limbs, 0); |
| 955 | val.writeToPackedMemory(ty, pt, limbs[0..bytes], 0) catch unreachable; | 995 | val.writeToPackedMemory(ty, pt, limbs[0..bytes], 0) catch unreachable; |
| ... | @@ -1068,19 +1108,11 @@ const NavGen = struct { | ... | @@ -1068,19 +1108,11 @@ const NavGen = struct { |
| 1068 | const parent_ptr_id = try self.derivePtr(oac.parent.*); | 1108 | const parent_ptr_id = try self.derivePtr(oac.parent.*); |
| 1069 | const parent_ptr_ty = try oac.parent.ptrType(pt); | 1109 | const parent_ptr_ty = try oac.parent.ptrType(pt); |
| 1070 | const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct); | 1110 | const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct); |
| | 1111 | const child_size = oac.new_ptr_ty.childType(zcu).abiSize(zcu); |
| 1071 | | 1112 | |
| 1072 | if (oac.byte_offset != 0) { | 1113 | if (parent_ptr_ty.childType(zcu).isVector(zcu) and oac.byte_offset % child_size == 0) { |
| 1073 | const child_size = oac.new_ptr_ty.childType(zcu).abiSize(zcu); | | |
| 1074 | if (oac.byte_offset % child_size != 0) { | | |
| 1075 | return self.fail("cannot perform pointer cast: '{}' to '{}'", .{ | | |
| 1076 | parent_ptr_ty.fmt(pt), | | |
| 1077 | oac.new_ptr_ty.fmt(pt), | | |
| 1078 | }); | | |
| 1079 | } | | |
| 1080 | | | |
| 1081 | // Vector element ptr accesses are derived as offset_and_cast. | 1114 | // Vector element ptr accesses are derived as offset_and_cast. |
| 1082 | // We can just use OpAccessChain. | 1115 | // We can just use OpAccessChain. |
| 1083 | assert(parent_ptr_ty.childType(zcu).zigTypeTag(zcu) == .vector); | | |
| 1084 | return self.accessChain( | 1116 | return self.accessChain( |
| 1085 | result_ty_id, | 1117 | result_ty_id, |
| 1086 | parent_ptr_id, | 1118 | parent_ptr_id, |
| ... | @@ -1088,15 +1120,22 @@ const NavGen = struct { | ... | @@ -1088,15 +1120,22 @@ const NavGen = struct { |
| 1088 | ); | 1120 | ); |
| 1089 | } | 1121 | } |
| 1090 | | 1122 | |
| 1091 | // Allow changing the pointer type child only to restructure arrays. | 1123 | if (oac.byte_offset == 0) { |
| 1092 | // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T. | 1124 | // Allow changing the pointer type child only to restructure arrays. |
| 1093 | const result_ptr_id = self.spv.allocId(); | 1125 | // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T. |
| 1094 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ | 1126 | const result_ptr_id = self.spv.allocId(); |
| 1095 | .id_result_type = result_ty_id, | 1127 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 1096 | .id_result = result_ptr_id, | 1128 | .id_result_type = result_ty_id, |
| 1097 | .operand = parent_ptr_id, | 1129 | .id_result = result_ptr_id, |
| | 1130 | .operand = parent_ptr_id, |
| | 1131 | }); |
| | 1132 | return result_ptr_id; |
| | 1133 | } |
| | 1134 | |
| | 1135 | return self.fail("cannot perform pointer cast: '{}' to '{}'", .{ |
| | 1136 | parent_ptr_ty.fmt(pt), |
| | 1137 | oac.new_ptr_ty.fmt(pt), |
| 1098 | }); | 1138 | }); |
| 1099 | return result_ptr_id; | | |
| 1100 | }, | 1139 | }, |
| 1101 | } | 1140 | } |
| 1102 | } | 1141 | } |
| ... | @@ -1217,11 +1256,14 @@ const NavGen = struct { | ... | @@ -1217,11 +1256,14 @@ const NavGen = struct { |
| 1217 | /// actual operations (as well as store) a Zig type of a particular number of bits. To create | 1256 | /// actual operations (as well as store) a Zig type of a particular number of bits. To create |
| 1218 | /// a type with an exact size, use SpvModule.intType. | 1257 | /// a type with an exact size, use SpvModule.intType. |
| 1219 | fn intType(self: *NavGen, signedness: std.builtin.Signedness, bits: u16) !IdRef { | 1258 | fn intType(self: *NavGen, signedness: std.builtin.Signedness, bits: u16) !IdRef { |
| 1220 | const backing_bits = self.backingIntBits(bits) orelse { | 1259 | const backing_bits, const big_int = self.backingIntBits(bits); |
| 1221 | // TODO: Integers too big for any native type are represented as "composite integers": | 1260 | if (big_int) { |
| 1222 | // An array of largestSupportedIntBits. | 1261 | if (backing_bits > 64) { |
| 1223 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); | 1262 | return self.fail("composite integers larger than 64bit aren't supported", .{}); |
| 1224 | }; | 1263 | } |
| | 1264 | const int_ty = try self.resolveType(.u32, .direct); |
| | 1265 | return self.arrayType(backing_bits / big_int_bits, int_ty); |
| | 1266 | } |
| 1225 | | 1267 | |
| 1226 | // Kernel only supports unsigned ints. | 1268 | // Kernel only supports unsigned ints. |
| 1227 | if (self.spv.hasFeature(.kernel)) { | 1269 | if (self.spv.hasFeature(.kernel)) { |
| ... | @@ -1509,6 +1551,17 @@ const NavGen = struct { | ... | @@ -1509,6 +1551,17 @@ const NavGen = struct { |
| 1509 | return result_id; | 1551 | return result_id; |
| 1510 | } | 1552 | } |
| 1511 | }, | 1553 | }, |
| | 1554 | .vector => { |
| | 1555 | const elem_ty = ty.childType(zcu); |
| | 1556 | const elem_ty_id = try self.resolveType(elem_ty, repr); |
| | 1557 | const len = ty.vectorLen(zcu); |
| | 1558 | |
| | 1559 | if (self.isSpvVector(ty)) { |
| | 1560 | return try self.spv.vectorType(len, elem_ty_id); |
| | 1561 | } else { |
| | 1562 | return try self.arrayType(len, elem_ty_id); |
| | 1563 | } |
| | 1564 | }, |
| 1512 | .@"fn" => switch (repr) { | 1565 | .@"fn" => switch (repr) { |
| 1513 | .direct => { | 1566 | .direct => { |
| 1514 | const fn_info = zcu.typeToFunc(ty).?; | 1567 | const fn_info = zcu.typeToFunc(ty).?; |
| ... | @@ -1577,12 +1630,6 @@ const NavGen = struct { | ... | @@ -1577,12 +1630,6 @@ const NavGen = struct { |
| 1577 | ); | 1630 | ); |
| 1578 | return result_id; | 1631 | return result_id; |
| 1579 | }, | 1632 | }, |
| 1580 | .vector => { | | |
| 1581 | const elem_ty = ty.childType(zcu); | | |
| 1582 | const elem_ty_id = try self.resolveType(elem_ty, repr); | | |
| 1583 | const len = ty.vectorLen(zcu); | | |
| 1584 | return self.arrayType(len, elem_ty_id); | | |
| 1585 | }, | | |
| 1586 | .@"struct" => { | 1633 | .@"struct" => { |
| 1587 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { | 1634 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { |
| 1588 | .tuple_type => |tuple| { | 1635 | .tuple_type => |tuple| { |
| ... | @@ -3378,8 +3425,7 @@ const NavGen = struct { | ... | @@ -3378,8 +3425,7 @@ const NavGen = struct { |
| 3378 | const zcu = self.pt.zcu; | 3425 | const zcu = self.pt.zcu; |
| 3379 | const ty = value.ty; | 3426 | const ty = value.ty; |
| 3380 | switch (info.class) { | 3427 | switch (info.class) { |
| 3381 | .integer, .bool, .float => return value, | 3428 | .composite_integer, .integer, .bool, .float => return value, |
| 3382 | .composite_integer => unreachable, // TODO | | |
| 3383 | .strange_integer => switch (info.signedness) { | 3429 | .strange_integer => switch (info.signedness) { |
| 3384 | .unsigned => { | 3430 | .unsigned => { |
| 3385 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; | 3431 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| ... | @@ -5039,7 +5085,7 @@ const NavGen = struct { | ... | @@ -5039,7 +5085,7 @@ const NavGen = struct { |
| 5039 | const mask_id = try self.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); | 5085 | const mask_id = try self.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); |
| 5040 | const masked = try self.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } }); | 5086 | const masked = try self.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } }); |
| 5041 | const result_id = blk: { | 5087 | const result_id = blk: { |
| 5042 | if (self.backingIntBits(field_bit_size).? == self.backingIntBits(@intCast(object_ty.bitSize(zcu))).?) | 5088 | if (self.backingIntBits(field_bit_size).@"0" == self.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0") |
| 5043 | break :blk try self.bitCast(field_int_ty, object_ty, try masked.materialize(self)); | 5089 | break :blk try self.bitCast(field_int_ty, object_ty, try masked.materialize(self)); |
| 5044 | const trunc = try self.buildConvert(field_int_ty, masked); | 5090 | const trunc = try self.buildConvert(field_int_ty, masked); |
| 5045 | break :blk try trunc.materialize(self); | 5091 | break :blk try trunc.materialize(self); |
| ... | @@ -5063,7 +5109,7 @@ const NavGen = struct { | ... | @@ -5063,7 +5109,7 @@ const NavGen = struct { |
| 5063 | .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } }, | 5109 | .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } }, |
| 5064 | ); | 5110 | ); |
| 5065 | const result_id = blk: { | 5111 | const result_id = blk: { |
| 5066 | if (self.backingIntBits(field_bit_size).? == self.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).?) | 5112 | if (self.backingIntBits(field_bit_size).@"0" == self.backingIntBits(@intCast(backing_int_ty.bitSize(zcu))).@"0") |
| 5067 | break :blk try self.bitCast(int_ty, backing_int_ty, try masked.materialize(self)); | 5113 | break :blk try self.bitCast(int_ty, backing_int_ty, try masked.materialize(self)); |
| 5068 | const trunc = try self.buildConvert(int_ty, masked); | 5114 | const trunc = try self.buildConvert(int_ty, masked); |
| 5069 | break :blk try trunc.materialize(self); | 5115 | break :blk try trunc.materialize(self); |
| ... | @@ -6100,17 +6146,15 @@ const NavGen = struct { | ... | @@ -6100,17 +6146,15 @@ const NavGen = struct { |
| 6100 | .bool, .error_set => 1, | 6146 | .bool, .error_set => 1, |
| 6101 | .int => blk: { | 6147 | .int => blk: { |
| 6102 | const bits = cond_ty.intInfo(zcu).bits; | 6148 | const bits = cond_ty.intInfo(zcu).bits; |
| 6103 | const backing_bits = self.backingIntBits(bits) orelse { | 6149 | const backing_bits, const big_int = self.backingIntBits(bits); |
| 6104 | return self.todo("implement composite int switch", .{}); | 6150 | if (big_int) return self.todo("implement composite int switch", .{}); |
| 6105 | }; | | |
| 6106 | break :blk if (backing_bits <= 32) 1 else 2; | 6151 | break :blk if (backing_bits <= 32) 1 else 2; |
| 6107 | }, | 6152 | }, |
| 6108 | .@"enum" => blk: { | 6153 | .@"enum" => blk: { |
| 6109 | const int_ty = cond_ty.intTagType(zcu); | 6154 | const int_ty = cond_ty.intTagType(zcu); |
| 6110 | const int_info = int_ty.intInfo(zcu); | 6155 | const int_info = int_ty.intInfo(zcu); |
| 6111 | const backing_bits = self.backingIntBits(int_info.bits) orelse { | 6156 | const backing_bits, const big_int = self.backingIntBits(int_info.bits); |
| 6112 | return self.todo("implement composite int switch", .{}); | 6157 | if (big_int) return self.todo("implement composite int switch", .{}); |
| 6113 | }; | | |
| 6114 | break :blk if (backing_bits <= 32) 1 else 2; | 6158 | break :blk if (backing_bits <= 32) 1 else 2; |
| 6115 | }, | 6159 | }, |
| 6116 | .pointer => blk: { | 6160 | .pointer => blk: { |