authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-20 18:02:30+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-20 18:02:30+02:00
logc92cc5798f0ea72ab1c77ae12c6124e5ab090730
treed94372b5d0575be57dde8bfb072d4fd519951490
parent65157d30ab90de01da583dd97ee2409d8ad8aeb0
signaturelock-open Commit is signed but in an unrecognized format.

spirv: make constant handle float, errorset, errorunion

This is in preparation of removing indirect lowering again. Also modifies constant() to accept a repr so that both direct as well as indirect representations can be generated. Indirect is not yet used, but will be used for globals.

2 files changed, 76 insertions(+), 13 deletions(-)

src/codegen/spirv.zig+66-13
...@@ -242,7 +242,7 @@ pub const DeclGen = struct {...@@ -242,7 +242,7 @@ pub const DeclGen = struct {
242 return self.spv.declPtr(spv_decl_index).result_id;242 return self.spv.declPtr(spv_decl_index).result_id;
243 }243 }
244244
245 return try self.constant(ty, val);245 return try self.constant(ty, val, .direct);
246 }246 }
247 const index = Air.refToIndex(inst).?;247 const index = Air.refToIndex(inst).?;
248 return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage.248 return self.inst_results.get(index).?; // Assertion means instruction does not dominate usage.
...@@ -1021,14 +1021,16 @@ pub const DeclGen = struct {...@@ -1021,14 +1021,16 @@ pub const DeclGen = struct {
1021 /// the constant is more complicated however, it needs to be lowered to an indirect constant, which1021 /// the constant is more complicated however, it needs to be lowered to an indirect constant, which
1022 /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default.1022 /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default.
1023 /// This function should only be called during function code generation.1023 /// This function should only be called during function code generation.
1024 fn constant(self: *DeclGen, ty: Type, val: Value) !IdRef {1024 fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef {
1025 const target = self.getTarget();1025 const target = self.getTarget();
1026 const section = &self.spv.sections.types_globals_constants;1026 const section = &self.spv.sections.types_globals_constants;
1027 const result_ty_ref = try self.resolveType(ty, .direct);1027 const result_ty_ref = try self.resolveType(ty, repr);
1028 const result_ty_id = self.typeId(result_ty_ref);1028 const result_ty_id = self.typeId(result_ty_ref);
1029 const result_id = self.spv.allocId();1029
1030 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
10301031
1031 if (val.isUndef()) {1032 if (val.isUndef()) {
1033 const result_id = self.spv.allocId();
1032 try section.emit(self.spv.gpa, .OpUndef, .{1034 try section.emit(self.spv.gpa, .OpUndef, .{
1033 .id_result_type = result_ty_id,1035 .id_result_type = result_ty_id,
1034 .id_result = result_id,1036 .id_result = result_id,
...@@ -1039,24 +1041,76 @@ pub const DeclGen = struct {...@@ -1039,24 +1041,76 @@ pub const DeclGen = struct {
1039 switch (ty.zigTypeTag()) {1041 switch (ty.zigTypeTag()) {
1040 .Int => {1042 .Int => {
1041 if (ty.isSignedInt()) {1043 if (ty.isSignedInt()) {
1042 try self.genConstInt(result_ty_ref, result_id, val.toSignedInt(target));1044 return try self.constInt(result_ty_ref, val.toSignedInt(target));
1043 } else {1045 } else {
1044 try self.genConstInt(result_ty_ref, result_id, val.toUnsignedInt(target));1046 return try self.constInt(result_ty_ref, val.toUnsignedInt(target));
1047 }
1048 },
1049 .Bool => switch (repr) {
1050 .direct => {
1051 const result_id = self.spv.allocId();
1052 const operands = .{ .id_result_type = result_ty_id, .id_result = result_id };
1053 if (val.toBool()) {
1054 try section.emit(self.spv.gpa, .OpConstantTrue, operands);
1055 } else {
1056 try section.emit(self.spv.gpa, .OpConstantFalse, operands);
1057 }
1058 return result_id;
1059 },
1060 .indirect => return try self.constInt(result_ty_ref, @boolToInt(val.toBool())),
1061 },
1062 .Float => {
1063 const result_id = self.spv.allocId();
1064 switch (ty.floatBits(target)) {
1065 16 => try self.spv.emitConstant(result_ty_id, result_id, .{ .float32 = val.toFloat(f16) }),
1066 32 => try self.spv.emitConstant(result_ty_id, result_id, .{ .float32 = val.toFloat(f32) }),
1067 64 => try self.spv.emitConstant(result_ty_id, result_id, .{ .float64 = val.toFloat(f64) }),
1068 80, 128 => unreachable, // TODO
1069 else => unreachable,
1045 }1070 }
1071 return result_id;
1046 },1072 },
1047 .Bool => {1073 .ErrorSet => {
1048 const operands = .{ .id_result_type = result_ty_id, .id_result = result_id };1074 const value = switch (val.tag()) {
1049 if (val.toBool()) {1075 .@"error" => blk: {
1050 try section.emit(self.spv.gpa, .OpConstantTrue, operands);1076 const err_name = val.castTag(.@"error").?.data.name;
1077 const kv = try self.module.getErrorValue(err_name);
1078 break :blk @intCast(u16, kv.value);
1079 },
1080 .zero => 0,
1081 else => unreachable,
1082 };
1083
1084 return try self.constInt(result_ty_ref, value);
1085 },
1086 .ErrorUnion => {
1087 const payload_ty = ty.errorUnionPayload();
1088 const is_pl = val.errorUnionIsPayload();
1089 const error_val = if (!is_pl) val else Value.initTag(.zero);
1090
1091 const eu_layout = self.errorUnionLayout(payload_ty);
1092 if (!eu_layout.payload_has_bits) {
1093 return try self.constant(Type.anyerror, error_val, repr);
1094 }
1095
1096 const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
1097
1098 var members: [2]IdRef = undefined;
1099 if (eu_layout.error_first) {
1100 members[0] = try self.constant(Type.anyerror, error_val, .indirect);
1101 members[1] = try self.constant(payload_ty, payload_val, .indirect);
1051 } else {1102 } else {
1052 try section.emit(self.spv.gpa, .OpConstantFalse, operands);1103 members[0] = try self.constant(payload_ty, payload_val, .indirect);
1104 members[1] = try self.constant(Type.anyerror, error_val, .indirect);
1053 }1105 }
1106 return try self.spv.constComposite(result_ty_ref, &members);
1054 },1107 },
1055 // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra1108 // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra
1056 // OpVariable that is not really required.1109 // OpVariable that is not really required.
1057 else => {1110 else => {
1058 // The value cannot be generated directly, so generate it as an indirect constant,1111 // The value cannot be generated directly, so generate it as an indirect constant,
1059 // and then perform an OpLoad.1112 // and then perform an OpLoad.
1113 const result_id = self.spv.allocId();
1060 const alignment = ty.abiAlignment(target);1114 const alignment = ty.abiAlignment(target);
1061 const spv_decl_index = try self.spv.allocDecl(.global);1115 const spv_decl_index = try self.spv.allocDecl(.global);
10621116
...@@ -1078,10 +1132,9 @@ pub const DeclGen = struct {...@@ -1078,10 +1132,9 @@ pub const DeclGen = struct {
1078 });1132 });
1079 // TODO: Convert bools? This logic should hook into `load`. It should be a dead1133 // TODO: Convert bools? This logic should hook into `load`. It should be a dead
1080 // path though considering .Bool is handled above.1134 // path though considering .Bool is handled above.
1135 return result_id;
1081 },1136 },
1082 }1137 }
1083
1084 return result_id;
1085 }1138 }
10861139
1087 /// Turn a Zig type into a SPIR-V Type, and return its type result-id.1140 /// Turn a Zig type into a SPIR-V Type, and return its type result-id.
src/codegen/spirv/Module.zig+10
...@@ -774,6 +774,16 @@ pub fn changePtrStorageClass(self: *Module, ptr_ty_ref: Type.Ref, new_storage_cl...@@ -774,6 +774,16 @@ pub fn changePtrStorageClass(self: *Module, ptr_ty_ref: Type.Ref, new_storage_cl
774 return try self.resolveType(Type.initPayload(&payload.base));774 return try self.resolveType(Type.initPayload(&payload.base));
775}775}
776776
777pub fn constComposite(self: *Module, ty_ref: Type.Ref, members: []const IdRef) !IdRef {
778 const result_id = self.allocId();
779 try self.sections.types_globals_constants.emit(self.gpa, .OpSpecConstantComposite, .{
780 .id_result_type = self.typeId(ty_ref),
781 .id_result = result_id,
782 .constituents = members,
783 });
784 return result_id;
785}
786
777pub fn emitConstant(787pub fn emitConstant(
778 self: *Module,788 self: *Module,
779 ty_id: IdRef,789 ty_id: IdRef,