authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-08 12:09:25+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-15 14:00:07+02:00
logf858bf161602d72584da9e950c5a9eeadfe8b29d
treedf67f8739601d0dddf98204f8e5cd0bd51dc8e58
parent0af16a58a0af20efa063057e90f8f448b010afd1
signature Signed by SSH key SHA256:CQ99aPxq+RueiL9u7z0FEki5Fm7V6T8q4PrEGmINrA4

spirv: air bitcast for non-numeric non-pointer types


3 files changed, 38 insertions(+), 6 deletions(-)

src/codegen/spirv.zig+31-4
...@@ -2578,25 +2578,52 @@ const DeclGen = struct {...@@ -2578,25 +2578,52 @@ const DeclGen = struct {
2578 return src_id;2578 return src_id;
2579 }2579 }
25802580
2581 const result_id = self.spv.allocId();
2582
2583 // TODO: Some more cases are missing here2581 // TODO: Some more cases are missing here
2584 // See fn bitCast in llvm.zig2582 // See fn bitCast in llvm.zig
25852583
2586 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {2584 if (src_ty.zigTypeTag(mod) == .Int and dst_ty.isPtrAtRuntime(mod)) {
2585 const result_id = self.spv.allocId();
2587 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{2586 try self.func.body.emit(self.spv.gpa, .OpConvertUToPtr, .{
2588 .id_result_type = self.typeId(dst_ty_ref),2587 .id_result_type = self.typeId(dst_ty_ref),
2589 .id_result = result_id,2588 .id_result = result_id,
2590 .integer_value = src_id,2589 .integer_value = src_id,
2591 });2590 });
2592 } else {2591 return result_id;
2592 }
2593
2594 // We can only use OpBitcast for specific conversions: between numerical types, and
2595 // between pointers. If the resolved spir-v types fall into this category then emit OpBitcast,
2596 // otherwise use a temporary and perform a pointer cast.
2597 const src_key = self.spv.cache.lookup(src_ty_ref);
2598 const dst_key = self.spv.cache.lookup(dst_ty_ref);
2599
2600 if ((src_key.isNumericalType() and dst_key.isNumericalType()) or (src_key == .ptr_type and dst_key == .ptr_type)) {
2601 const result_id = self.spv.allocId();
2593 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{2602 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
2594 .id_result_type = self.typeId(dst_ty_ref),2603 .id_result_type = self.typeId(dst_ty_ref),
2595 .id_result = result_id,2604 .id_result = result_id,
2596 .operand = src_id,2605 .operand = src_id,
2597 });2606 });
2607 return result_id;
2598 }2608 }
2599 return result_id;2609
2610 const src_ptr_ty_ref = try self.spv.ptrType(src_ty_ref, .Function);
2611 const dst_ptr_ty_ref = try self.spv.ptrType(dst_ty_ref, .Function);
2612
2613 const tmp_id = self.spv.allocId();
2614 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{
2615 .id_result_type = self.typeId(src_ptr_ty_ref),
2616 .id_result = tmp_id,
2617 .storage_class = .Function,
2618 });
2619 try self.store(src_ty, tmp_id, src_id, false);
2620 const casted_ptr_id = self.spv.allocId();
2621 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
2622 .id_result_type = self.typeId(dst_ptr_ty_ref),
2623 .id_result = casted_ptr_id,
2624 .operand = tmp_id,
2625 });
2626 return try self.load(dst_ty, casted_ptr_id, false);
2600 }2627 }
26012628
2602 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2629 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
src/codegen/spirv/Cache.zig+7
...@@ -435,6 +435,13 @@ pub const Key = union(enum) {...@@ -435,6 +435,13 @@ pub const Key = union(enum) {
435 else => unreachable,435 else => unreachable,
436 };436 };
437 }437 }
438
439 pub fn isNumericalType(self: Key) bool {
440 return switch (self) {
441 .int_type, .float_type => true,
442 else => false,
443 };
444 }
438};445};
439446
440pub fn deinit(self: *Self, spv: *const Module) void {447pub fn deinit(self: *Self, spv: *const Module) void {
test/behavior/cast.zig-2
...@@ -899,7 +899,6 @@ test "peer cast [:x]T to []T" {...@@ -899,7 +899,6 @@ test "peer cast [:x]T to []T" {
899test "peer cast [N:x]T to [N]T" {899test "peer cast [N:x]T to [N]T" {
900 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;900 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
901 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO901 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
902 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
903902
904 const S = struct {903 const S = struct {
905 fn doTheTest() !void {904 fn doTheTest() !void {
...@@ -1728,7 +1727,6 @@ test "peer type resolution: error union and optional of same type" {...@@ -1728,7 +1727,6 @@ test "peer type resolution: error union and optional of same type" {
1728 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1727 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1729 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1728 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1730 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1729 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1731 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
17321730
1733 const E = error{Foo};1731 const E = error{Foo};
1734 var a: E!*u8 = error.Foo;1732 var a: E!*u8 = error.Foo;