authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-09-17 02:54:53+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 12:36:44-07:00
log06d9e3b2eb7a5c44edfce672b61feb2efc7234a6
tree36c32a99b29f73350c4f3809186b6e6af75e5413
parent18d0909adaac1ba67a06d92632423a435e4458f4

spirv: always emit unsigned integers

This is required for SPIR-V in Kernel mode. The Intel implementation just didn't care about this fact.

1 files changed, 39 insertions(+), 21 deletions(-)

src/codegen/spirv.zig+39-21
...@@ -408,7 +408,7 @@ pub const DeclGen = struct {...@@ -408,7 +408,7 @@ pub const DeclGen = struct {
408 switch (repr) {408 switch (repr) {
409 .indirect => {409 .indirect => {
410 const int_ty_ref = try self.intType(.unsigned, 1);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 .direct => {413 .direct => {
414 const bool_ty_ref = try self.resolveType(Type.bool, .direct);414 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
...@@ -417,6 +417,25 @@ pub const DeclGen = struct {...@@ -417,6 +417,25 @@ pub const DeclGen = struct {
417 }417 }
418 }418 }
419419
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 /// Construct a struct at runtime.439 /// Construct a struct at runtime.
421 /// result_ty_ref must be a struct type.440 /// result_ty_ref must be a struct type.
422 fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef {441 fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef {
...@@ -434,7 +453,7 @@ pub const DeclGen = struct {...@@ -434,7 +453,7 @@ pub const DeclGen = struct {
434 const member_types = spv_composite_ty.member_types;453 const member_types = spv_composite_ty.member_types;
435454
436 for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| {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 const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Generic);457 const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Generic);
439 const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id});458 const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id});
440 try self.func.body.emit(self.spv.gpa, .OpStore, .{459 try self.func.body.emit(self.spv.gpa, .OpStore, .{
...@@ -469,7 +488,7 @@ pub const DeclGen = struct {...@@ -469,7 +488,7 @@ pub const DeclGen = struct {
469 const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic);488 const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic);
470489
471 for (constituents, 0..) |constitent_id, index| {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 const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id});492 const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id});
474 try self.func.body.emit(self.spv.gpa, .OpStore, .{493 try self.func.body.emit(self.spv.gpa, .OpStore, .{
475 .pointer = ptr_id,494 .pointer = ptr_id,
...@@ -580,17 +599,14 @@ pub const DeclGen = struct {...@@ -580,17 +599,14 @@ pub const DeclGen = struct {
580 .generic_poison,599 .generic_poison,
581 => unreachable, // non-runtime values600 => unreachable, // non-runtime values
582601
583 .false, .true => switch (repr) {602 .false, .true => return try self.constBool(val.toBool(), 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 },
587 },603 },
588604
589 .int => {605 .int => {
590 if (ty.isSignedInt(mod)) {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 } else {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 .float => return switch (ty.floatBits(target)) {612 .float => return switch (ty.floatBits(target)) {
...@@ -602,7 +618,7 @@ pub const DeclGen = struct {...@@ -602,7 +618,7 @@ pub const DeclGen = struct {
602 },618 },
603 .err => |err| {619 .err => |err| {
604 const value = try mod.getErrorValue(err.name);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 .error_union => |error_union| {623 .error_union => |error_union| {
608 // TODO: Error unions may be constructed with constant instructions if the payload type624 // TODO: Error unions may be constructed with constant instructions if the payload type
...@@ -716,7 +732,7 @@ pub const DeclGen = struct {...@@ -716,7 +732,7 @@ pub const DeclGen = struct {
716 // TODO: This is really space inefficient, perhaps there is a better732 // TODO: This is really space inefficient, perhaps there is a better
717 // way to do it?733 // way to do it?
718 for (bytes, 0..) |byte, i| {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 .elems => |elems| {738 .elems => |elems| {
...@@ -794,7 +810,7 @@ pub const DeclGen = struct {...@@ -794,7 +810,7 @@ pub const DeclGen = struct {
794 const index_ty_ref = try self.intType(.unsigned, 32);810 const index_ty_ref = try self.intType(.unsigned, 32);
795811
796 if (layout.tag_size != 0) {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 const tag_ty = ty.unionTagTypeSafety(mod).?;814 const tag_ty = ty.unionTagTypeSafety(mod).?;
799 const tag_ty_ref = try self.resolveType(tag_ty, .indirect);815 const tag_ty_ref = try self.resolveType(tag_ty, .indirect);
800 const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function);816 const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function);
...@@ -807,7 +823,7 @@ pub const DeclGen = struct {...@@ -807,7 +823,7 @@ pub const DeclGen = struct {
807 }823 }
808824
809 if (layout.active_field_size != 0) {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 const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect);827 const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect);
812 const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function);828 const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function);
813 const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id});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,7 +886,9 @@ pub const DeclGen = struct {
870 // An array of largestSupportedIntBits.886 // An array of largestSupportedIntBits.
871 return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits });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 }
875893
876 /// Create an integer type that represents 'usize'.894 /// Create an integer type that represents 'usize'.
...@@ -1568,8 +1586,8 @@ pub const DeclGen = struct {...@@ -1568,8 +1586,8 @@ pub const DeclGen = struct {
1568 }1586 }
15691587
1570 fn intFromBool(self: *DeclGen, result_ty_ref: CacheRef, condition_id: IdRef) !IdRef {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);1589 const zero_id = try self.constInt(result_ty_ref, 0);
1572 const one_id = try self.spv.constInt(result_ty_ref, 1);1590 const one_id = try self.constInt(result_ty_ref, 1);
1573 const result_id = self.spv.allocId();1591 const result_id = self.spv.allocId();
1574 try self.func.body.emit(self.spv.gpa, .OpSelect, .{1592 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
1575 .id_result_type = self.typeId(result_ty_ref),1593 .id_result_type = self.typeId(result_ty_ref),
...@@ -1589,7 +1607,7 @@ pub const DeclGen = struct {...@@ -1589,7 +1607,7 @@ pub const DeclGen = struct {
1589 .Bool => blk: {1607 .Bool => blk: {
1590 const direct_bool_ty_ref = try self.resolveType(ty, .direct);1608 const direct_bool_ty_ref = try self.resolveType(ty, .direct);
1591 const indirect_bool_ty_ref = try self.resolveType(ty, .indirect);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 const result_id = self.spv.allocId();1611 const result_id = self.spv.allocId();
1594 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{1612 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
1595 .id_result_type = self.typeId(direct_bool_ty_ref),1613 .id_result_type = self.typeId(direct_bool_ty_ref),
...@@ -1832,7 +1850,7 @@ pub const DeclGen = struct {...@@ -1832,7 +1850,7 @@ pub const DeclGen = struct {
1832 fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef {1850 fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef {
1833 const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1;1851 const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1;
1834 const result_id = self.spv.allocId();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 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{1854 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{
1837 .id_result_type = self.typeId(ty_ref),1855 .id_result_type = self.typeId(ty_ref),
1838 .id_result = result_id,1856 .id_result = result_id,
...@@ -1971,7 +1989,7 @@ pub const DeclGen = struct {...@@ -1971,7 +1989,7 @@ pub const DeclGen = struct {
1971 // Note that signed overflow is also wrapping in spir-v.1989 // Note that signed overflow is also wrapping in spir-v.
19721990
1973 const rhs_lt_zero_id = self.spv.allocId();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 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{1993 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
1976 .id_result_type = self.typeId(bool_ty_ref),1994 .id_result_type = self.typeId(bool_ty_ref),
1977 .id_result = rhs_lt_zero_id,1995 .id_result = rhs_lt_zero_id,
...@@ -2540,7 +2558,7 @@ pub const DeclGen = struct {...@@ -2540,7 +2558,7 @@ pub const DeclGen = struct {
2540 .Packed => unreachable, // TODO2558 .Packed => unreachable, // TODO
2541 else => {2559 else => {
2542 const field_index_ty_ref = try self.intType(.unsigned, 32);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 const result_ty_ref = try self.resolveType(result_ptr_ty, .direct);2562 const result_ty_ref = try self.resolveType(result_ptr_ty, .direct);
2545 return try self.accessChain(result_ty_ref, object_ptr, &.{field_index_id});2563 return try self.accessChain(result_ty_ref, object_ptr, &.{field_index_id});
2546 },2564 },
...@@ -2822,7 +2840,7 @@ pub const DeclGen = struct {...@@ -2822,7 +2840,7 @@ pub const DeclGen = struct {
2822 else2840 else
2823 err_union_id;2841 err_union_id;
28242842
2825 const zero_id = try self.spv.constInt(err_ty_ref, 0);2843 const zero_id = try self.constInt(err_ty_ref, 0);
2826 const is_err_id = self.spv.allocId();2844 const is_err_id = self.spv.allocId();
2827 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{2845 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
2828 .id_result_type = self.typeId(bool_ty_ref),2846 .id_result_type = self.typeId(bool_ty_ref),