authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-07-01 14:27:12+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-07-01 14:27:12+02:00
log8eee3928626f9469dbd5ca15127b836e48553bd3
treec6e4952a20fde8657ccfa7d00bce8ea35e6f1fdf
parent0a6cd257b9c8a9093b966e3851dc8261e19b531a
signaturebadge-check Signed by SSH key SHA256:CQ99aPxq+RueiL9u7z0FEki5Fm7V6T8q4PrEGmINrA4

spirv: fix up todos & errors from intern pool changes

This replaces the implementation of constant() which one that is directly based on the intern pool rather than the Zig type tag too.

1 files changed, 124 insertions(+), 56 deletions(-)

src/codegen/spirv.zig+124-56
......@@ -537,6 +537,12 @@ pub const DeclGen = struct {
537537
538538 fn addInt(self: *@This(), ty: Type, val: Value) !void {
539539 const mod = self.dg.module;
540 const len = ty.abiSize(mod);
541 if (val.isUndef(mod)) {
542 try self.addUndef(len);
543 return;
544 }
545
540546 const int_info = ty.intInfo(mod);
541547 const int_bits = switch (int_info.signedness) {
542548 .signed => @as(u64, @bitCast(val.toSignedInt(mod))),
......@@ -544,7 +550,6 @@ pub const DeclGen = struct {
544550 };
545551
546552 // TODO: Swap endianess if the compiler is big endian.
547 const len = ty.abiSize(mod);
548553 try self.addBytes(std.mem.asBytes(&int_bits)[0..@as(usize, @intCast(len))]);
549554 }
550555
......@@ -667,31 +672,41 @@ pub const DeclGen = struct {
667672 try self.addConstInt(u16, @as(u16, @intCast(int)));
668673 },
669674 .error_union => |error_union| {
675 const err_ty = switch (error_union.val) {
676 .err_name => ty.errorUnionSet(mod),
677 .payload => Type.err_int,
678 };
679 const err_val = switch (error_union.val) {
680 .err_name => |err_name| (try mod.intern(.{ .err = .{
681 .ty = ty.errorUnionSet(mod).toIntern(),
682 .name = err_name,
683 } })).toValue(),
684 .payload => try mod.intValue(Type.err_int, 0),
685 };
670686 const payload_ty = ty.errorUnionPayload(mod);
671 const is_pl = val.errorUnionIsPayload(mod);
672 const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0);
673
674687 const eu_layout = dg.errorUnionLayout(payload_ty);
675688 if (!eu_layout.payload_has_bits) {
676 return try self.lower(Type.anyerror, error_val);
689 // We use the error type directly as the type.
690 try self.lower(err_ty, err_val);
691 return;
677692 }
678693
679694 const payload_size = payload_ty.abiSize(mod);
680 const error_size = Type.anyerror.abiAlignment(mod);
695 const error_size = err_ty.abiSize(mod);
681696 const ty_size = ty.abiSize(mod);
682697 const padding = ty_size - payload_size - error_size;
683698
684699 const payload_val = switch (error_union.val) {
685 .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }),
700 .err_name => try mod.intern(.{ .undef = payload_ty.toIntern() }),
686701 .payload => |payload| payload,
687702 }.toValue();
688703
689704 if (eu_layout.error_first) {
690 try self.lower(Type.anyerror, error_val);
705 try self.lower(err_ty, err_val);
691706 try self.lower(payload_ty, payload_val);
692707 } else {
693708 try self.lower(payload_ty, payload_val);
694 try self.lower(Type.anyerror, error_val);
709 try self.lower(err_ty, err_val);
695710 }
696711
697712 try self.addUndef(padding);
......@@ -705,9 +720,14 @@ pub const DeclGen = struct {
705720 },
706721 .float => try self.addFloat(ty, val),
707722 .ptr => |ptr| {
723 const ptr_ty = switch (ptr.len) {
724 .none => ty,
725 else => ty.slicePtrFieldType(mod),
726 };
708727 switch (ptr.addr) {
709 .decl => |decl| try self.addDeclRef(ty, decl),
710 .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl),
728 .decl => |decl| try self.addDeclRef(ptr_ty, decl),
729 .mut_decl => |mut_decl| try self.addDeclRef(ptr_ty, mut_decl.decl),
730 .int => |int| try self.addInt(Type.usize, int.toValue()),
711731 else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}),
712732 }
713733 if (ptr.len != .none) {
......@@ -979,38 +999,84 @@ pub const DeclGen = struct {
979999 /// the constant is more complicated however, it needs to be lowered to an indirect constant, which
9801000 /// is then loaded using OpLoad. Such values are loaded into the UniformConstant storage class by default.
9811001 /// This function should only be called during function code generation.
982 fn constant(self: *DeclGen, ty: Type, val: Value, repr: Repr) !IdRef {
1002 fn constant(self: *DeclGen, ty: Type, arg_val: Value, repr: Repr) !IdRef {
9831003 const mod = self.module;
9841004 const target = self.getTarget();
9851005 const result_ty_ref = try self.resolveType(ty, repr);
9861006
987 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
1007 var val = arg_val;
1008 switch (mod.intern_pool.indexToKey(val.toIntern())) {
1009 .runtime_value => |rt| val = rt.val.toValue(),
1010 else => {},
1011 }
9881012
1013 log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) });
9891014 if (val.isUndef(mod)) {
9901015 return self.spv.constUndef(result_ty_ref);
9911016 }
9921017
993 switch (ty.zigTypeTag(mod)) {
994 .Int => {
1018 switch (mod.intern_pool.indexToKey(val.toIntern())) {
1019 .int_type,
1020 .ptr_type,
1021 .array_type,
1022 .vector_type,
1023 .opt_type,
1024 .anyframe_type,
1025 .error_union_type,
1026 .simple_type,
1027 .struct_type,
1028 .anon_struct_type,
1029 .union_type,
1030 .opaque_type,
1031 .enum_type,
1032 .func_type,
1033 .error_set_type,
1034 .inferred_error_set_type,
1035 => unreachable, // types, not values
1036
1037 .undef => unreachable, // handled above
1038 .runtime_value => unreachable, // ???
1039
1040 .variable,
1041 .extern_func,
1042 .func,
1043 .enum_literal,
1044 .empty_enum_value,
1045 => unreachable, // non-runtime values
1046
1047 .simple_value => |simple_value| switch (simple_value) {
1048 .undefined,
1049 .void,
1050 .null,
1051 .empty_struct,
1052 .@"unreachable",
1053 .generic_poison,
1054 => unreachable, // non-runtime values
1055
1056 .false, .true => switch (repr) {
1057 .direct => return try self.spv.constBool(result_ty_ref, val.toBool()),
1058 .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())),
1059 },
1060 },
1061
1062 .int => {
9951063 if (ty.isSignedInt(mod)) {
9961064 return try self.spv.constInt(result_ty_ref, val.toSignedInt(mod));
9971065 } else {
9981066 return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(mod));
9991067 }
10001068 },
1001 .Bool => switch (repr) {
1002 .direct => return try self.spv.constBool(result_ty_ref, val.toBool()),
1003 .indirect => return try self.spv.constInt(result_ty_ref, @intFromBool(val.toBool())),
1004 },
1005 .Float => return switch (ty.floatBits(target)) {
1069 .float => return switch (ty.floatBits(target)) {
10061070 16 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float16 = val.toFloat(f16, mod) } } }),
10071071 32 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float32 = val.toFloat(f32, mod) } } }),
10081072 64 => try self.spv.resolveId(.{ .float = .{ .ty = result_ty_ref, .value = .{ .float64 = val.toFloat(f64, mod) } } }),
10091073 80, 128 => unreachable, // TODO
10101074 else => unreachable,
10111075 },
1012 .ErrorSet => @panic("TODO"),
1013 .ErrorUnion => @panic("TODO"),
1076 .err => |err| {
1077 const value = try mod.getErrorValue(err.name);
1078 return try self.spv.constInt(result_ty_ref, value);
1079 },
10141080 // TODO: We can handle most pointers here (decl refs etc), because now they emit an extra
10151081 // OpVariable that is not really required.
10161082 else => {
......@@ -1263,51 +1329,53 @@ pub const DeclGen = struct {
12631329 } });
12641330 },
12651331 .Struct => {
1266 const struct_ty = mod.typeToStruct(ty).?;
1267 const fields = struct_ty.fields.values();
1268
1269 if (ty.isSimpleTupleOrAnonStruct(mod)) {
1270 const member_types = try self.gpa.alloc(CacheRef, fields.len);
1271 defer self.gpa.free(member_types);
1332 const struct_ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1333 .anon_struct_type => |tuple| {
1334 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
1335 defer self.gpa.free(member_types);
12721336
1273 var member_index: usize = 0;
1274 for (fields) |field| {
1275 if (field.ty.ip_index != .unreachable_value or !field.ty.hasRuntimeBits(mod)) continue;
1337 var member_index: usize = 0;
1338 for (tuple.types, tuple.values) |field_ty, field_val| {
1339 if (field_val != .none or !field_ty.toType().hasRuntimeBits(mod)) continue;
12761340
1277 member_types[member_index] = try self.resolveType(field.ty, .indirect);
1278 member_index += 1;
1279 }
1341 member_types[member_index] = try self.resolveType(field_ty.toType(), .indirect);
1342 member_index += 1;
1343 }
12801344
1281 return try self.spv.resolve(.{ .struct_type = .{
1282 .member_types = member_types[0..member_index],
1283 } });
1284 }
1345 return try self.spv.resolve(.{ .struct_type = .{
1346 .member_types = member_types[0..member_index],
1347 } });
1348 },
1349 .struct_type => |struct_ty| struct_ty,
1350 else => unreachable,
1351 };
12851352
1286 if (struct_ty.layout == .Packed) {
1287 return try self.resolveType(struct_ty.backing_int_ty, .direct);
1353 const struct_obj = mod.structPtrUnwrap(struct_ty.index).?;
1354 if (struct_obj.layout == .Packed) {
1355 return try self.resolveType(struct_obj.backing_int_ty, .direct);
12881356 }
12891357
1290 const member_types = try self.gpa.alloc(CacheRef, fields.len);
1291 defer self.gpa.free(member_types);
1292
1293 const member_names = try self.gpa.alloc(CacheString, fields.len);
1294 defer self.gpa.free(member_names);
1358 var member_types = std.ArrayList(CacheRef).init(self.gpa);
1359 defer member_types.deinit();
12951360
1296 var member_index: usize = 0;
1297 for (fields, 0..) |field, i| {
1298 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;
1361 var member_names = std.ArrayList(CacheString).init(self.gpa);
1362 defer member_names.deinit();
12991363
1300 member_types[member_index] = try self.resolveType(field.ty, .indirect);
1301 member_names[member_index] = try self.spv.resolveString(mod.intern_pool.stringToSlice(struct_ty.fields.keys()[i]));
1302 member_index += 1;
1364 var it = struct_obj.runtimeFieldIterator(mod);
1365 while (it.next()) |field_and_index| {
1366 const field = field_and_index.field;
1367 const index = field_and_index.index;
1368 const field_name = mod.intern_pool.stringToSlice(struct_obj.fields.keys()[index]);
1369 try member_types.append(try self.resolveType(field.ty, .indirect));
1370 try member_names.append(try self.spv.resolveString(field_name));
13031371 }
13041372
1305 const name = mod.intern_pool.stringToSlice(try struct_ty.getFullyQualifiedName(self.module));
1373 const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module));
13061374
13071375 return try self.spv.resolve(.{ .struct_type = .{
13081376 .name = try self.spv.resolveString(name),
1309 .member_types = member_types[0..member_index],
1310 .member_names = member_names[0..member_index],
1377 .member_types = member_types.items,
1378 .member_names = member_names.items,
13111379 } });
13121380 },
13131381 .Optional => {
......@@ -2512,9 +2580,9 @@ pub const DeclGen = struct {
25122580 // just an element.
25132581 var elem_ptr_info = ptr_ty.ptrInfo(mod);
25142582 elem_ptr_info.flags.size = .One;
2515 const elem_ptr_ty = elem_ptr_info.child.toType();
2583 const elem_ptr_ty = try mod.intern_pool.get(mod.gpa, .{ .ptr_type = elem_ptr_info });
25162584
2517 return try self.load(elem_ptr_ty, elem_ptr_id);
2585 return try self.load(elem_ptr_ty.toType(), elem_ptr_id);
25182586 }
25192587
25202588 fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {