aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/spirv.zig
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2023-04-09 01:30:06 +0200
committerRobin Voetter <robin@voetter.nl>2023-04-09 01:51:53 +0200
commit719d47d823a7e27ba0902b2878835297a6001fd0 (patch)
tree4cbe958c228ac520423879deb94d98643616acdb /src/codegen/spirv.zig
parent8bbfbfc956af163434c734e196d5c2a77e77ff07 (diff)
downloadzig-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.zig70
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,