Commit 8895025688

Robin Voetter <robin@voetter.nl>
2023-09-19 20:26:30
spirv: air wrap_errunion_payload
1 parent 4f215a6
Changed files (2)
src
codegen
test
behavior
src/codegen/spirv.zig
@@ -1734,6 +1734,7 @@ pub const DeclGen = struct {
             .unwrap_errunion_err => try self.airErrUnionErr(inst),
             .unwrap_errunion_payload => try self.airErrUnionPayload(inst),
             .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
+            .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
 
             .is_null     => try self.airIsNull(inst, .is_null),
             .is_non_null => try self.airIsNull(inst, .is_non_null),
@@ -3216,20 +3217,35 @@ pub const DeclGen = struct {
         }
 
         const payload_ty_ref = try self.resolveType(payload_ty, .indirect);
-        var members = std.BoundedArray(IdRef, 2){};
-        const payload_id = try self.spv.constUndef(payload_ty_ref);
-        if (eu_layout.error_first) {
-            members.appendAssumeCapacity(operand_id);
-            members.appendAssumeCapacity(payload_id);
-            // TODO: ABI padding?
-        } else {
-            members.appendAssumeCapacity(payload_id);
-            members.appendAssumeCapacity(operand_id);
-            // TODO: ABI padding?
+
+        var members: [2]IdRef = undefined;
+        members[eu_layout.errorFieldIndex()] = operand_id;
+        members[eu_layout.payloadFieldIndex()] = try self.spv.constUndef(payload_ty_ref);
+
+        const err_union_ty_ref = try self.resolveType(err_union_ty, .direct);
+        return try self.constructStruct(err_union_ty_ref, &members);
+    }
+
+    fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
+        if (self.liveness.isUnused(inst)) return null;
+
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const err_union_ty = self.typeOfIndex(inst);
+        const operand_id = try self.resolve(ty_op.operand);
+        const payload_ty = self.typeOf(ty_op.operand);
+        const err_ty_ref = try self.resolveType(Type.anyerror, .direct);
+        const eu_layout = self.errorUnionLayout(payload_ty);
+
+        if (!eu_layout.payload_has_bits) {
+            return try self.constInt(err_ty_ref, 0);
         }
 
+        var members: [2]IdRef = undefined;
+        members[eu_layout.errorFieldIndex()] = try self.constInt(err_ty_ref, 0);
+        members[eu_layout.payloadFieldIndex()] = try self.convertToIndirect(payload_ty, operand_id);
+
         const err_union_ty_ref = try self.resolveType(err_union_ty, .direct);
-        return try self.constructStruct(err_union_ty_ref, members.slice());
+        return try self.constructStruct(err_union_ty_ref, &members);
     }
 
     fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef {
test/behavior/error.zig
@@ -30,7 +30,6 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void {
 
 test "error binary operator" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const a = errBinaryOperatorG(true) catch 3;
     const b = errBinaryOperatorG(false) catch 3;
@@ -62,14 +61,12 @@ pub fn baz() anyerror!i32 {
 
 test "error wrapping" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     try expect((baz() catch unreachable) == 15);
 }
 
 test "unwrap simple value from error" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const i = unwrapSimpleValueFromErrorDo() catch unreachable;
     try expect(i == 13);
@@ -80,7 +77,6 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize {
 
 test "error return in assignment" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     doErrReturnInAssignment() catch unreachable;
 }
@@ -103,7 +99,6 @@ test "syntax: optional operator in front of error union operator" {
 test "widen cast integer payload of error union function call" {
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const S = struct {
         fn errorable() !u64 {
@@ -150,7 +145,6 @@ test "implicit cast to optional to error union to return result loc" {
 }
 
 test "fn returning empty error set can be passed as fn returning any error" {
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
     entry();
     comptime entry();
 }
@@ -243,7 +237,6 @@ fn testExplicitErrorSetCast(set1: Set1) !void {
 
 test "comptime test error for empty error set" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     try testComptimeTestErrorEmptySet(1234);
     try comptime testComptimeTestErrorEmptySet(1234);
@@ -279,7 +272,6 @@ test "inferred empty error set comptime catch" {
 }
 
 test "error inference with an empty set" {
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
     const S = struct {
         const Struct = struct {
             pub fn func() (error{})!usize {
@@ -334,7 +326,6 @@ fn quux_1() !i32 {
 
 test "error: Zero sized error set returned with value payload crash" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     _ = try foo3(0);
     _ = try comptime foo3(0);
@@ -434,7 +425,6 @@ test "nested error union function call in optional unwrap" {
 test "return function call to error set from error union function" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const S = struct {
         fn errorable() anyerror!i32 {
@@ -670,7 +660,6 @@ test "peer type resolution of two different error unions" {
 }
 
 test "coerce error set to the current inferred error set" {
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
     const S = struct {
         fn foo() !void {
             var a = false;
@@ -862,8 +851,6 @@ fn non_errorable() void {
 }
 
 test "catch within a function that calls no errorable functions" {
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
-
     non_errorable();
 }
 
@@ -895,7 +882,6 @@ test "field access of anyerror results in smaller error set" {
 test "optional error union return type" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
 
     const S = struct {
         fn foo() ?anyerror!u32 {