| ... | ... | @@ -408,7 +408,7 @@ pub const DeclGen = struct { |
| 408 | 408 | switch (repr) { |
| 409 | 409 | .indirect => { |
| 410 | 410 | const int_ty_ref = try self.intType(.unsigned, 1); |
| 411 | | return self.spv.constInt(int_ty_ref, @intFromBool(value)); |
| 411 | return self.constInt(int_ty_ref, @intFromBool(value)); |
| 412 | 412 | }, |
| 413 | 413 | .direct => { |
| 414 | 414 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| ... | ... | @@ -417,6 +417,25 @@ pub const DeclGen = struct { |
| 417 | 417 | } |
| 418 | 418 | } |
| 419 | 419 | |
| 420 | /// Emits an integer constant. |
| 421 | /// This function, unlike SpvModule.constInt, takes care to bitcast |
| 422 | /// the value to an unsigned int first for Kernels. |
| 423 | fn constInt(self: *DeclGen, ty_ref: CacheRef, value: anytype) !IdRef { |
| 424 | if (value < 0) { |
| 425 | const ty = self.spv.cache.lookup(ty_ref).int_type; |
| 426 | // Manually truncate the value so that the resulting value |
| 427 | // fits within the unsigned type. |
| 428 | const bits: u64 = @bitCast(@as(i64, @intCast(value))); |
| 429 | const truncated_bits = if (ty.bits == 64) |
| 430 | bits |
| 431 | else |
| 432 | bits & (@as(u64, 1) << @intCast(ty.bits)) - 1; |
| 433 | return try self.spv.constInt(ty_ref, truncated_bits); |
| 434 | } else { |
| 435 | return try self.spv.constInt(ty_ref, value); |
| 436 | } |
| 437 | } |
| 438 | |
| 420 | 439 | /// Construct a struct at runtime. |
| 421 | 440 | /// result_ty_ref must be a struct type. |
| 422 | 441 | fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { |
| ... | ... | @@ -434,7 +453,7 @@ pub const DeclGen = struct { |
| 434 | 453 | const member_types = spv_composite_ty.member_types; |
| 435 | 454 | |
| 436 | 455 | for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { |
| 437 | | const index_id = try self.spv.constInt(index_ty_ref, index); |
| 456 | const index_id = try self.constInt(index_ty_ref, index); |
| 438 | 457 | const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Generic); |
| 439 | 458 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id}); |
| 440 | 459 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| ... | ... | @@ -469,7 +488,7 @@ pub const DeclGen = struct { |
| 469 | 488 | const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic); |
| 470 | 489 | |
| 471 | 490 | for (constituents, 0..) |constitent_id, index| { |
| 472 | | const index_id = try self.spv.constInt(index_ty_ref, index); |
| 491 | const index_id = try self.constInt(index_ty_ref, index); |
| 473 | 492 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id}); |
| 474 | 493 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 475 | 494 | .pointer = ptr_id, |
| ... | ... | @@ -580,17 +599,14 @@ pub const DeclGen = struct { |
| 580 | 599 | .generic_poison, |
| 581 | 600 | => unreachable, // non-runtime values |
| 582 | 601 | |
| 583 | | .false, .true => switch (repr) { |
| 584 | | .direct => return try self.spv.constBool(result_ty_ref, val.toBool()), |
| 585 | | .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())), |
| 586 | | }, |
| 602 | .false, .true => return try self.constBool(val.toBool(), repr), |
| 587 | 603 | }, |
| 588 | 604 | |
| 589 | 605 | .int => { |
| 590 | 606 | if (ty.isSignedInt(mod)) { |
| 591 | | return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod)); |
| 607 | return try self.constInt(result_ty_ref, val.toSignedInt(mod)); |
| 592 | 608 | } else { |
| 593 | | return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod)); |
| 609 | return try self.constInt(result_ty_ref, val.toUnsignedInt(mod)); |
| 594 | 610 | } |
| 595 | 611 | }, |
| 596 | 612 | .float => return switch (ty.floatBits(target)) { |
| ... | ... | @@ -602,7 +618,7 @@ pub const DeclGen = struct { |
| 602 | 618 | }, |
| 603 | 619 | .err => |err| { |
| 604 | 620 | const value = try mod.getErrorValue(err.name); |
| 605 | | return try self.spv.constInt(result_ty_ref, value); |
| 621 | return try self.constInt(result_ty_ref, value); |
| 606 | 622 | }, |
| 607 | 623 | .error_union => |error_union| { |
| 608 | 624 | // TODO: Error unions may be constructed with constant instructions if the payload type |
| ... | ... | @@ -716,7 +732,7 @@ pub const DeclGen = struct { |
| 716 | 732 | // TODO: This is really space inefficient, perhaps there is a better |
| 717 | 733 | // way to do it? |
| 718 | 734 | for (bytes, 0..) |byte, i| { |
| 719 | | constituents[i] = try self.spv.constInt(elem_ty_ref, byte); |
| 735 | constituents[i] = try self.constInt(elem_ty_ref, byte); |
| 720 | 736 | } |
| 721 | 737 | }, |
| 722 | 738 | .elems => |elems| { |
| ... | ... | @@ -794,7 +810,7 @@ pub const DeclGen = struct { |
| 794 | 810 | const index_ty_ref = try self.intType(.unsigned, 32); |
| 795 | 811 | |
| 796 | 812 | if (layout.tag_size != 0) { |
| 797 | | const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); |
| 813 | const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); |
| 798 | 814 | const tag_ty = ty.unionTagTypeSafety(mod).?; |
| 799 | 815 | const tag_ty_ref = try self.resolveType(tag_ty, .indirect); |
| 800 | 816 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); |
| ... | ... | @@ -807,7 +823,7 @@ pub const DeclGen = struct { |
| 807 | 823 | } |
| 808 | 824 | |
| 809 | 825 | if (layout.active_field_size != 0) { |
| 810 | | const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); |
| 826 | const index_id = try self.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); |
| 811 | 827 | const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 812 | 828 | const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); |
| 813 | 829 | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); |
| ... | ... | @@ -870,7 +886,9 @@ pub const DeclGen = struct { |
| 870 | 886 | // An array of largestSupportedIntBits. |
| 871 | 887 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); |
| 872 | 888 | }; |
| 873 | | return self.spv.intType(signedness, backing_bits); |
| 889 | // Kernel only supports unsigned ints. |
| 890 | // TODO: Only do this with Kernels |
| 891 | return self.spv.intType(.unsigned, backing_bits); |
| 874 | 892 | } |
| 875 | 893 | |
| 876 | 894 | /// Create an integer type that represents 'usize'. |
| ... | ... | @@ -1568,8 +1586,8 @@ pub const DeclGen = struct { |
| 1568 | 1586 | } |
| 1569 | 1587 | |
| 1570 | 1588 | fn intFromBool(self: *DeclGen, result_ty_ref: CacheRef, condition_id: IdRef) !IdRef { |
| 1571 | | const zero_id = try self.spv.constInt(result_ty_ref, 0); |
| 1572 | | const one_id = try self.spv.constInt(result_ty_ref, 1); |
| 1589 | const zero_id = try self.constInt(result_ty_ref, 0); |
| 1590 | const one_id = try self.constInt(result_ty_ref, 1); |
| 1573 | 1591 | const result_id = self.spv.allocId(); |
| 1574 | 1592 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ |
| 1575 | 1593 | .id_result_type = self.typeId(result_ty_ref), |
| ... | ... | @@ -1589,7 +1607,7 @@ pub const DeclGen = struct { |
| 1589 | 1607 | .Bool => blk: { |
| 1590 | 1608 | const direct_bool_ty_ref = try self.resolveType(ty, .direct); |
| 1591 | 1609 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| 1592 | | const zero_id = try self.spv.constInt(indirect_bool_ty_ref, 0); |
| 1610 | const zero_id = try self.constInt(indirect_bool_ty_ref, 0); |
| 1593 | 1611 | const result_id = self.spv.allocId(); |
| 1594 | 1612 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| 1595 | 1613 | .id_result_type = self.typeId(direct_bool_ty_ref), |
| ... | ... | @@ -1832,7 +1850,7 @@ pub const DeclGen = struct { |
| 1832 | 1850 | fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef { |
| 1833 | 1851 | const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1; |
| 1834 | 1852 | const result_id = self.spv.allocId(); |
| 1835 | | const mask_id = try self.spv.constInt(ty_ref, mask_value); |
| 1853 | const mask_id = try self.constInt(ty_ref, mask_value); |
| 1836 | 1854 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ |
| 1837 | 1855 | .id_result_type = self.typeId(ty_ref), |
| 1838 | 1856 | .id_result = result_id, |
| ... | ... | @@ -1971,7 +1989,7 @@ pub const DeclGen = struct { |
| 1971 | 1989 | // Note that signed overflow is also wrapping in spir-v. |
| 1972 | 1990 | |
| 1973 | 1991 | const rhs_lt_zero_id = self.spv.allocId(); |
| 1974 | | const zero_id = try self.spv.constInt(operand_ty_ref, 0); |
| 1992 | const zero_id = try self.constInt(operand_ty_ref, 0); |
| 1975 | 1993 | try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ |
| 1976 | 1994 | .id_result_type = self.typeId(bool_ty_ref), |
| 1977 | 1995 | .id_result = rhs_lt_zero_id, |
| ... | ... | @@ -2540,7 +2558,7 @@ pub const DeclGen = struct { |
| 2540 | 2558 | .Packed => unreachable, // TODO |
| 2541 | 2559 | else => { |
| 2542 | 2560 | const field_index_ty_ref = try self.intType(.unsigned, 32); |
| 2543 | | const field_index_id = try self.spv.constInt(field_index_ty_ref, field_index); |
| 2561 | const field_index_id = try self.constInt(field_index_ty_ref, field_index); |
| 2544 | 2562 | const result_ty_ref = try self.resolveType(result_ptr_ty, .direct); |
| 2545 | 2563 | return try self.accessChain(result_ty_ref, object_ptr, &.{field_index_id}); |
| 2546 | 2564 | }, |
| ... | ... | @@ -2822,7 +2840,7 @@ pub const DeclGen = struct { |
| 2822 | 2840 | else |
| 2823 | 2841 | err_union_id; |
| 2824 | 2842 | |
| 2825 | | const zero_id = try self.spv.constInt(err_ty_ref, 0); |
| 2843 | const zero_id = try self.constInt(err_ty_ref, 0); |
| 2826 | 2844 | const is_err_id = self.spv.allocId(); |
| 2827 | 2845 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| 2828 | 2846 | .id_result_type = self.typeId(bool_ty_ref), |