diff options
| author | Robin Voetter <robin@voetter.nl> | 2023-04-09 01:30:06 +0200 |
|---|---|---|
| committer | Robin Voetter <robin@voetter.nl> | 2023-04-09 01:51:53 +0200 |
| commit | 719d47d823a7e27ba0902b2878835297a6001fd0 (patch) | |
| tree | 4cbe958c228ac520423879deb94d98643616acdb /src/codegen/spirv.zig | |
| parent | 8bbfbfc956af163434c734e196d5c2a77e77ff07 (diff) | |
| download | zig-719d47d823a7e27ba0902b2878835297a6001fd0.tar.gz zig-719d47d823a7e27ba0902b2878835297a6001fd0.zip | |
spirv: implement error set and error unions
Implements lowering types and constants for error sets and error unions.
Diffstat (limited to 'src/codegen/spirv.zig')
| -rw-r--r-- | src/codegen/spirv.zig | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index b58f889f8e..3700b5bce5 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -763,6 +763,47 @@ pub const DeclGen = struct { try self.addUndef(layout.padding); }, + .ErrorSet => switch (val.tag()) { + .@"error" => { + const err_name = val.castTag(.@"error").?.data.name; + const kv = try dg.module.getErrorValue(err_name); + try self.addConstInt(u16, @intCast(u16, kv.value)); + }, + .zero => { + // Unactivated error set. + try self.addConstInt(u16, 0); + }, + else => unreachable, + }, + .ErrorUnion => { + const payload_ty = ty.errorUnionPayload(); + const is_pl = val.errorUnionIsPayload(); + const error_val = if (!is_pl) val else Value.initTag(.zero); + + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + return try self.lower(Type.anyerror, error_val); + } + + const payload_align = payload_ty.abiAlignment(target); + const error_align = Type.anyerror.abiAlignment(target); + + const payload_size = payload_ty.abiSize(target); + const error_size = Type.anyerror.abiAlignment(target); + const ty_size = ty.abiSize(target); + const padding = ty_size - payload_size - error_size; + + const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef); + + if (error_align > payload_align) { + try self.lower(Type.anyerror, error_val); + try self.lower(payload_ty, payload_val); + } else { + try self.lower(payload_ty, payload_val); + try self.lower(Type.anyerror, error_val); + } + + try self.addUndef(padding); + }, else => |tag| return dg.todo("indirect constant of type {s}", .{@tagName(tag)}), } } @@ -1209,6 +1250,35 @@ pub const DeclGen = struct { }); }, .Union => return try self.resolveUnionType(ty, null), + .ErrorSet => return try self.intType(.unsigned, 16), + .ErrorUnion => { + const payload_ty = ty.errorUnionPayload(); + const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + return error_ty_ref; + } + + const payload_ty_ref = try self.resolveType(payload_ty, .indirect); + + const payload_align = payload_ty.abiAlignment(target); + const error_align = Type.anyerror.abiAlignment(target); + + var members = std.BoundedArray(SpvType.Payload.Struct.Member, 2){}; + // Similar to unions, we're going to put the most aligned member first. + if (error_align > payload_align) { + // Put the error first + members.appendAssumeCapacity(.{ .ty = error_ty_ref, .name = "error" }); + members.appendAssumeCapacity(.{ .ty = payload_ty_ref, .name = "payload" }); + // TODO: ABI padding? + } else { + // Put the payload first. + members.appendAssumeCapacity(.{ .ty = payload_ty_ref, .name = "payload" }); + members.appendAssumeCapacity(.{ .ty = error_ty_ref, .name = "error" }); + // TODO: ABI padding? + } + + return try self.spv.simpleStructType(members.slice()); + }, .Null, .Undefined, |
