diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index c46be03548..aa5b56f58a 100644 --- a/src/codegen/spirv.zig +++ b/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.slice()); + 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); } fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_null, is_non_null }) !?IdRef { diff --git a/test/behavior/error.zig b/test/behavior/error.zig index dc4cd838ec..038bd94dfa 100644 --- a/test/behavior/error.zig +++ b/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 {