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 {
408408 switch (repr) {
409409 .indirect => {
410410 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));
412412 },
413413 .direct => {
414414 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
......@@ -417,6 +417,25 @@ pub const DeclGen = struct {
417417 }
418418 }
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
420439 /// Construct a struct at runtime.
421440 /// result_ty_ref must be a struct type.
422441 fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef {
......@@ -434,7 +453,7 @@ pub const DeclGen = struct {
434453 const member_types = spv_composite_ty.member_types;
435454
436455 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);
438457 const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Generic);
439458 const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id});
440459 try self.func.body.emit(self.spv.gpa, .OpStore, .{
......@@ -469,7 +488,7 @@ pub const DeclGen = struct {
469488 const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic);
470489
471490 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);
473492 const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id});
474493 try self.func.body.emit(self.spv.gpa, .OpStore, .{
475494 .pointer = ptr_id,
......@@ -580,17 +599,14 @@ pub const DeclGen = struct {
580599 .generic_poison,
581600 => unreachable, // non-runtime values
582601
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),
587603 },
588604
589605 .int => {
590606 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));
592608 } else {
593 return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod));
609 return try self.constInt(result_ty_ref, val.toUnsignedInt(mod));
594610 }
595611 },
596612 .float => return switch (ty.floatBits(target)) {
......@@ -602,7 +618,7 @@ pub const DeclGen = struct {
602618 },
603619 .err => |err| {
604620 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);
606622 },
607623 .error_union => |error_union| {
608624 // TODO: Error unions may be constructed with constant instructions if the payload type
......@@ -716,7 +732,7 @@ pub const DeclGen = struct {
716732 // TODO: This is really space inefficient, perhaps there is a better
717733 // way to do it?
718734 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);
720736 }
721737 },
722738 .elems => |elems| {
......@@ -794,7 +810,7 @@ pub const DeclGen = struct {
794810 const index_ty_ref = try self.intType(.unsigned, 32);
795811
796812 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)));
798814 const tag_ty = ty.unionTagTypeSafety(mod).?;
799815 const tag_ty_ref = try self.resolveType(tag_ty, .indirect);
800816 const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function);
......@@ -807,7 +823,7 @@ pub const DeclGen = struct {
807823 }
808824
809825 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)));
811827 const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect);
812828 const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function);
813829 const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id});
......@@ -870,7 +886,9 @@ pub const DeclGen = struct {
870886 // An array of largestSupportedIntBits.
871887 return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits });
872888 };
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);
874892 }
875893
876894 /// Create an integer type that represents 'usize'.
......@@ -1568,8 +1586,8 @@ pub const DeclGen = struct {
15681586 }
15691587
15701588 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);
15731591 const result_id = self.spv.allocId();
15741592 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
15751593 .id_result_type = self.typeId(result_ty_ref),
......@@ -1589,7 +1607,7 @@ pub const DeclGen = struct {
15891607 .Bool => blk: {
15901608 const direct_bool_ty_ref = try self.resolveType(ty, .direct);
15911609 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);
15931611 const result_id = self.spv.allocId();
15941612 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
15951613 .id_result_type = self.typeId(direct_bool_ty_ref),
......@@ -1832,7 +1850,7 @@ pub const DeclGen = struct {
18321850 fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef {
18331851 const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1;
18341852 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);
18361854 try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{
18371855 .id_result_type = self.typeId(ty_ref),
18381856 .id_result = result_id,
......@@ -1971,7 +1989,7 @@ pub const DeclGen = struct {
19711989 // Note that signed overflow is also wrapping in spir-v.
19721990
19731991 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);
19751993 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
19761994 .id_result_type = self.typeId(bool_ty_ref),
19771995 .id_result = rhs_lt_zero_id,
......@@ -2540,7 +2558,7 @@ pub const DeclGen = struct {
25402558 .Packed => unreachable, // TODO
25412559 else => {
25422560 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);
25442562 const result_ty_ref = try self.resolveType(result_ptr_ty, .direct);
25452563 return try self.accessChain(result_ty_ref, object_ptr, &.{field_index_id});
25462564 },
......@@ -2822,7 +2840,7 @@ pub const DeclGen = struct {
28222840 else
28232841 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);
28262844 const is_err_id = self.spv.allocId();
28272845 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
28282846 .id_result_type = self.typeId(bool_ty_ref),