| ... | @@ -22,11 +22,10 @@ const IdResultType = spec.IdResultType; | ... | @@ -22,11 +22,10 @@ const IdResultType = spec.IdResultType; |
| 22 | const StorageClass = spec.StorageClass; | 22 | const StorageClass = spec.StorageClass; |
| 23 | | 23 | |
| 24 | const SpvModule = @import("spirv/Module.zig"); | 24 | const SpvModule = @import("spirv/Module.zig"); |
| 25 | const SpvCacheRef = SpvModule.TypeConstantCache.Ref; | 25 | const CacheRef = SpvModule.CacheRef; |
| 26 | const SpvCacheString = SpvModule.TypeConstantCache.String; | 26 | const CacheString = SpvModule.CacheString; |
| 27 | | 27 | |
| 28 | const SpvSection = @import("spirv/Section.zig"); | 28 | const SpvSection = @import("spirv/Section.zig"); |
| 29 | const SpvType = @import("spirv/type.zig").Type; | | |
| 30 | const SpvAssembler = @import("spirv/Assembler.zig"); | 29 | const SpvAssembler = @import("spirv/Assembler.zig"); |
| 31 | | 30 | |
| 32 | const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef); | 31 | const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef); |
| ... | @@ -380,74 +379,23 @@ pub const DeclGen = struct { | ... | @@ -380,74 +379,23 @@ pub const DeclGen = struct { |
| 380 | }; | 379 | }; |
| 381 | } | 380 | } |
| 382 | | 381 | |
| 383 | fn genConstInt(self: *DeclGen, ty_ref: SpvType.Ref, result_id: IdRef, value: anytype) !void { | 382 | /// Emits a bool constant in a particular representation. |
| 384 | const ty = self.spv.typeRefType(ty_ref); | | |
| 385 | const ty_id = self.typeId(ty_ref); | | |
| 386 | | | |
| 387 | const Lit = spec.LiteralContextDependentNumber; | | |
| 388 | const literal = switch (ty.intSignedness()) { | | |
| 389 | .signed => switch (ty.intFloatBits()) { | | |
| 390 | 1...32 => Lit{ .int32 = @intCast(i32, value) }, | | |
| 391 | 33...64 => Lit{ .int64 = @intCast(i64, value) }, | | |
| 392 | else => unreachable, // TODO: composite integer literals | | |
| 393 | }, | | |
| 394 | .unsigned => switch (ty.intFloatBits()) { | | |
| 395 | 1...32 => Lit{ .uint32 = @intCast(u32, value) }, | | |
| 396 | 33...64 => Lit{ .uint64 = @intCast(u64, value) }, | | |
| 397 | else => unreachable, | | |
| 398 | }, | | |
| 399 | }; | | |
| 400 | | | |
| 401 | try self.spv.emitConstant(ty_id, result_id, literal); | | |
| 402 | } | | |
| 403 | | | |
| 404 | fn constInt(self: *DeclGen, ty_ref: SpvType.Ref, value: anytype) !IdRef { | | |
| 405 | const result_id = self.spv.allocId(); | | |
| 406 | try self.genConstInt(ty_ref, result_id, value); | | |
| 407 | return result_id; | | |
| 408 | } | | |
| 409 | | | |
| 410 | fn constUndef(self: *DeclGen, ty_ref: SpvType.Ref) !IdRef { | | |
| 411 | const result_id = self.spv.allocId(); | | |
| 412 | try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpUndef, .{ | | |
| 413 | .id_result_type = self.typeId(ty_ref), | | |
| 414 | .id_result = result_id, | | |
| 415 | }); | | |
| 416 | return result_id; | | |
| 417 | } | | |
| 418 | | | |
| 419 | fn constNull(self: *DeclGen, ty_ref: SpvType.Ref) !IdRef { | | |
| 420 | const result_id = self.spv.allocId(); | | |
| 421 | try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpConstantNull, .{ | | |
| 422 | .id_result_type = self.typeId(ty_ref), | | |
| 423 | .id_result = result_id, | | |
| 424 | }); | | |
| 425 | return result_id; | | |
| 426 | } | | |
| 427 | | | |
| 428 | fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef { | 383 | fn constBool(self: *DeclGen, value: bool, repr: Repr) !IdRef { |
| 429 | switch (repr) { | 384 | switch (repr) { |
| 430 | .indirect => { | 385 | .indirect => { |
| 431 | const int_ty_ref = try self.intType(.unsigned, 1); | 386 | const int_ty_ref = try self.intType(.unsigned, 1); |
| 432 | return self.constInt(int_ty_ref, @boolToInt(value)); | 387 | return self.spv.constInt(int_ty_ref, @boolToInt(value)); |
| 433 | }, | 388 | }, |
| 434 | .direct => { | 389 | .direct => { |
| 435 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); | 390 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| 436 | const result_id = self.spv.allocId(); | 391 | return self.spv.constBool(bool_ty_ref, value); |
| 437 | const operands = .{ .id_result_type = self.typeId(bool_ty_ref), .id_result = result_id }; | | |
| 438 | if (value) { | | |
| 439 | try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpConstantTrue, operands); | | |
| 440 | } else { | | |
| 441 | try self.spv.sections.types_globals_constants.emit(self.spv.gpa, .OpConstantFalse, operands); | | |
| 442 | } | | |
| 443 | return result_id; | | |
| 444 | }, | 392 | }, |
| 445 | } | 393 | } |
| 446 | } | 394 | } |
| 447 | | 395 | |
| 448 | /// Construct a struct at runtime. | 396 | /// Construct a struct at runtime. |
| 449 | /// result_ty_ref must be a struct type. | 397 | /// result_ty_ref must be a struct type. |
| 450 | fn constructStruct(self: *DeclGen, result_ty_ref: SpvType.Ref, constituents: []const IdRef) !IdRef { | 398 | fn constructStruct(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { |
| 451 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' | 399 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 452 | // operands are not constant. | 400 | // operands are not constant. |
| 453 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 | 401 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| ... | @@ -456,11 +404,13 @@ pub const DeclGen = struct { | ... | @@ -456,11 +404,13 @@ pub const DeclGen = struct { |
| 456 | const ptr_composite_id = try self.alloc(result_ty_ref, null); | 404 | const ptr_composite_id = try self.alloc(result_ty_ref, null); |
| 457 | // Note: using 32-bit ints here because usize crashes the translator as well | 405 | // Note: using 32-bit ints here because usize crashes the translator as well |
| 458 | const index_ty_ref = try self.intType(.unsigned, 32); | 406 | const index_ty_ref = try self.intType(.unsigned, 32); |
| 459 | const spv_composite_ty = self.spv.typeRefType(result_ty_ref); | 407 | |
| 460 | const members = spv_composite_ty.payload(.@"struct").members; | 408 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).struct_type; |
| 461 | for (constituents, members, 0..) |constitent_id, member, index| { | 409 | const member_types = spv_composite_ty.member_types; |
| 462 | const index_id = try self.constInt(index_ty_ref, index); | 410 | |
| 463 | const ptr_member_ty_ref = try self.spv.ptrType(member.ty, .Generic, 0); | 411 | for (constituents, member_types, 0..) |constitent_id, member_ty_ref, index| { |
| | 412 | const index_id = try self.spv.constInt(index_ty_ref, index); |
| | 413 | const ptr_member_ty_ref = try self.spv.ptrType(member_ty_ref, .Generic); |
| 464 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id}); | 414 | const ptr_id = try self.accessChain(ptr_member_ty_ref, ptr_composite_id, &.{index_id}); |
| 465 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ | 415 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 466 | .pointer = ptr_id, | 416 | .pointer = ptr_id, |
| ... | @@ -481,11 +431,11 @@ pub const DeclGen = struct { | ... | @@ -481,11 +431,11 @@ pub const DeclGen = struct { |
| 481 | | 431 | |
| 482 | dg: *DeclGen, | 432 | dg: *DeclGen, |
| 483 | /// Cached reference of the u32 type. | 433 | /// Cached reference of the u32 type. |
| 484 | u32_ty_ref: SpvType.Ref, | 434 | u32_ty_ref: CacheRef, |
| 485 | /// Cached type id of the u32 type. | 435 | /// Cached type id of the u32 type. |
| 486 | u32_ty_id: IdRef, | 436 | u32_ty_id: IdRef, |
| 487 | /// The members of the resulting structure type | 437 | /// The members of the resulting structure type |
| 488 | members: std.ArrayList(SpvType.Payload.Struct.Member), | 438 | members: std.ArrayList(CacheRef), |
| 489 | /// The initializers of each of the members. | 439 | /// The initializers of each of the members. |
| 490 | initializers: std.ArrayList(IdRef), | 440 | initializers: std.ArrayList(IdRef), |
| 491 | /// The current size of the structure. Includes | 441 | /// The current size of the structure. Includes |
| ... | @@ -519,7 +469,7 @@ pub const DeclGen = struct { | ... | @@ -519,7 +469,7 @@ pub const DeclGen = struct { |
| 519 | const result_id = self.dg.spv.allocId(); | 469 | const result_id = self.dg.spv.allocId(); |
| 520 | // TODO: Integrate with caching mechanism | 470 | // TODO: Integrate with caching mechanism |
| 521 | try self.dg.spv.emitConstant(self.u32_ty_id, result_id, .{ .uint32 = word }); | 471 | try self.dg.spv.emitConstant(self.u32_ty_id, result_id, .{ .uint32 = word }); |
| 522 | try self.members.append(.{ .ty = self.u32_ty_ref }); | 472 | try self.members.append(self.u32_ty_ref); |
| 523 | try self.initializers.append(result_id); | 473 | try self.initializers.append(result_id); |
| 524 | | 474 | |
| 525 | self.partial_word.len = 0; | 475 | self.partial_word.len = 0; |
| ... | @@ -555,7 +505,7 @@ pub const DeclGen = struct { | ... | @@ -555,7 +505,7 @@ pub const DeclGen = struct { |
| 555 | } | 505 | } |
| 556 | } | 506 | } |
| 557 | | 507 | |
| 558 | fn addPtr(self: *@This(), ptr_ty_ref: SpvType.Ref, ptr_id: IdRef) !void { | 508 | fn addPtr(self: *@This(), ptr_ty_ref: CacheRef, ptr_id: IdRef) !void { |
| 559 | // TODO: Double check pointer sizes here. | 509 | // TODO: Double check pointer sizes here. |
| 560 | // shared pointers might be u32... | 510 | // shared pointers might be u32... |
| 561 | const target = self.dg.getTarget(); | 511 | const target = self.dg.getTarget(); |
| ... | @@ -563,12 +513,12 @@ pub const DeclGen = struct { | ... | @@ -563,12 +513,12 @@ pub const DeclGen = struct { |
| 563 | if (self.size % width != 0) { | 513 | if (self.size % width != 0) { |
| 564 | return self.dg.todo("misaligned pointer constants", .{}); | 514 | return self.dg.todo("misaligned pointer constants", .{}); |
| 565 | } | 515 | } |
| 566 | try self.members.append(.{ .ty = ptr_ty_ref }); | 516 | try self.members.append(ptr_ty_ref); |
| 567 | try self.initializers.append(ptr_id); | 517 | try self.initializers.append(ptr_id); |
| 568 | self.size += width; | 518 | self.size += width; |
| 569 | } | 519 | } |
| 570 | | 520 | |
| 571 | fn addNullPtr(self: *@This(), ptr_ty_ref: SpvType.Ref) !void { | 521 | fn addNullPtr(self: *@This(), ptr_ty_ref: CacheRef) !void { |
| 572 | const result_id = self.dg.spv.allocId(); | 522 | const result_id = self.dg.spv.allocId(); |
| 573 | try self.dg.spv.sections.types_globals_constants.emit(self.dg.spv.gpa, .OpConstantNull, .{ | 523 | try self.dg.spv.sections.types_globals_constants.emit(self.dg.spv.gpa, .OpConstantNull, .{ |
| 574 | .id_result_type = self.dg.typeId(ptr_ty_ref), | 524 | .id_result_type = self.dg.typeId(ptr_ty_ref), |
| ... | @@ -931,7 +881,7 @@ pub const DeclGen = struct { | ... | @@ -931,7 +881,7 @@ pub const DeclGen = struct { |
| 931 | const section = &self.spv.globals.section; | 881 | const section = &self.spv.globals.section; |
| 932 | | 882 | |
| 933 | const ty_ref = try self.resolveType(ty, .indirect); | 883 | const ty_ref = try self.resolveType(ty, .indirect); |
| 934 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class, 0); | 884 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class); |
| 935 | | 885 | |
| 936 | // const target = self.getTarget(); | 886 | // const target = self.getTarget(); |
| 937 | | 887 | |
| ... | @@ -960,7 +910,7 @@ pub const DeclGen = struct { | ... | @@ -960,7 +910,7 @@ pub const DeclGen = struct { |
| 960 | .dg = self, | 910 | .dg = self, |
| 961 | .u32_ty_ref = u32_ty_ref, | 911 | .u32_ty_ref = u32_ty_ref, |
| 962 | .u32_ty_id = self.typeId(u32_ty_ref), | 912 | .u32_ty_id = self.typeId(u32_ty_ref), |
| 963 | .members = std.ArrayList(SpvType.Payload.Struct.Member).init(self.gpa), | 913 | .members = std.ArrayList(CacheRef).init(self.gpa), |
| 964 | .initializers = std.ArrayList(IdRef).init(self.gpa), | 914 | .initializers = std.ArrayList(IdRef).init(self.gpa), |
| 965 | .decl_deps = std.AutoArrayHashMap(SpvModule.Decl.Index, void).init(self.gpa), | 915 | .decl_deps = std.AutoArrayHashMap(SpvModule.Decl.Index, void).init(self.gpa), |
| 966 | }; | 916 | }; |
| ... | @@ -972,8 +922,10 @@ pub const DeclGen = struct { | ... | @@ -972,8 +922,10 @@ pub const DeclGen = struct { |
| 972 | try icl.lower(ty, val); | 922 | try icl.lower(ty, val); |
| 973 | try icl.flush(); | 923 | try icl.flush(); |
| 974 | | 924 | |
| 975 | const constant_struct_ty_ref = try self.spv.simpleStructType(icl.members.items); | 925 | const constant_struct_ty_ref = try self.spv.resolve(.{ .struct_type = .{ |
| 976 | const ptr_constant_struct_ty_ref = try self.spv.ptrType(constant_struct_ty_ref, storage_class, 0); | 926 | .member_types = icl.members.items, |
| | 927 | } }); |
| | 928 | const ptr_constant_struct_ty_ref = try self.spv.ptrType(constant_struct_ty_ref, storage_class); |
| 977 | | 929 | |
| 978 | const constant_struct_id = self.spv.allocId(); | 930 | const constant_struct_id = self.spv.allocId(); |
| 979 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ | 931 | try section.emit(self.spv.gpa, .OpSpecConstantComposite, .{ |
| ... | @@ -1007,7 +959,7 @@ pub const DeclGen = struct { | ... | @@ -1007,7 +959,7 @@ pub const DeclGen = struct { |
| 1007 | }); | 959 | }); |
| 1008 | | 960 | |
| 1009 | if (cast_to_generic) { | 961 | if (cast_to_generic) { |
| 1010 | const generic_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic, 0); | 962 | const generic_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic); |
| 1011 | try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ | 963 | try section.emitSpecConstantOp(self.spv.gpa, .OpPtrCastToGeneric, .{ |
| 1012 | .id_result_type = self.typeId(generic_ptr_ty_ref), | 964 | .id_result_type = self.typeId(generic_ptr_ty_ref), |
| 1013 | .id_result = result_id, | 965 | .id_result = result_id, |
| ... | @@ -1044,9 +996,9 @@ pub const DeclGen = struct { | ... | @@ -1044,9 +996,9 @@ pub const DeclGen = struct { |
| 1044 | switch (ty.zigTypeTag()) { | 996 | switch (ty.zigTypeTag()) { |
| 1045 | .Int => { | 997 | .Int => { |
| 1046 | if (ty.isSignedInt()) { | 998 | if (ty.isSignedInt()) { |
| 1047 | return try self.constInt(result_ty_ref, val.toSignedInt(target)); | 999 | return try self.spv.constInt(result_ty_ref, val.toSignedInt(target)); |
| 1048 | } else { | 1000 | } else { |
| 1049 | return try self.constInt(result_ty_ref, val.toUnsignedInt(target)); | 1001 | return try self.spv.constInt(result_ty_ref, val.toUnsignedInt(target)); |
| 1050 | } | 1002 | } |
| 1051 | }, | 1003 | }, |
| 1052 | .Bool => switch (repr) { | 1004 | .Bool => switch (repr) { |
| ... | @@ -1060,7 +1012,7 @@ pub const DeclGen = struct { | ... | @@ -1060,7 +1012,7 @@ pub const DeclGen = struct { |
| 1060 | } | 1012 | } |
| 1061 | return result_id; | 1013 | return result_id; |
| 1062 | }, | 1014 | }, |
| 1063 | .indirect => return try self.constInt(result_ty_ref, @boolToInt(val.toBool())), | 1015 | .indirect => return try self.spv.constInt(result_ty_ref, @boolToInt(val.toBool())), |
| 1064 | }, | 1016 | }, |
| 1065 | .Float => { | 1017 | .Float => { |
| 1066 | const result_id = self.spv.allocId(); | 1018 | const result_id = self.spv.allocId(); |
| ... | @@ -1084,7 +1036,7 @@ pub const DeclGen = struct { | ... | @@ -1084,7 +1036,7 @@ pub const DeclGen = struct { |
| 1084 | else => unreachable, | 1036 | else => unreachable, |
| 1085 | }; | 1037 | }; |
| 1086 | | 1038 | |
| 1087 | return try self.constInt(result_ty_ref, value); | 1039 | return try self.spv.constInt(result_ty_ref, value); |
| 1088 | }, | 1040 | }, |
| 1089 | .ErrorUnion => { | 1041 | .ErrorUnion => { |
| 1090 | const payload_ty = ty.errorUnionPayload(); | 1042 | const payload_ty = ty.errorUnionPayload(); |
| ... | @@ -1143,45 +1095,31 @@ pub const DeclGen = struct { | ... | @@ -1143,45 +1095,31 @@ pub const DeclGen = struct { |
| 1143 | /// Turn a Zig type into a SPIR-V Type, and return its type result-id. | 1095 | /// Turn a Zig type into a SPIR-V Type, and return its type result-id. |
| 1144 | fn resolveTypeId(self: *DeclGen, ty: Type) !IdResultType { | 1096 | fn resolveTypeId(self: *DeclGen, ty: Type) !IdResultType { |
| 1145 | const type_ref = try self.resolveType(ty, .direct); | 1097 | const type_ref = try self.resolveType(ty, .direct); |
| 1146 | return self.typeId(type_ref); | 1098 | return self.spv.resultId(type_ref); |
| 1147 | } | 1099 | } |
| 1148 | | 1100 | |
| 1149 | fn typeId(self: *DeclGen, ty_ref: SpvType.Ref) IdRef { | 1101 | fn typeId(self: *DeclGen, ty_ref: CacheRef) IdRef { |
| 1150 | return self.spv.typeId(ty_ref); | 1102 | return self.spv.resultId(ty_ref); |
| 1151 | } | 1103 | } |
| 1152 | | 1104 | |
| 1153 | /// Create an integer type suitable for storing at least 'bits' bits. | 1105 | /// Create an integer type suitable for storing at least 'bits' bits. |
| 1154 | fn intType(self: *DeclGen, signedness: std.builtin.Signedness, bits: u16) !SpvType.Ref { | 1106 | /// The integer type that is returned by this function is the type that is used to perform |
| | 1107 | /// actual operations (as well as store) a Zig type of a particular number of bits. To create |
| | 1108 | /// a type with an exact size, use SpvModule.intType. |
| | 1109 | fn intType(self: *DeclGen, signedness: std.builtin.Signedness, bits: u16) !CacheRef { |
| 1155 | const backing_bits = self.backingIntBits(bits) orelse { | 1110 | const backing_bits = self.backingIntBits(bits) orelse { |
| 1156 | // TODO: Integers too big for any native type are represented as "composite integers": | 1111 | // TODO: Integers too big for any native type are represented as "composite integers": |
| 1157 | // An array of largestSupportedIntBits. | 1112 | // An array of largestSupportedIntBits. |
| 1158 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); | 1113 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); |
| 1159 | }; | 1114 | }; |
| 1160 | | 1115 | return self.spv.intType(signedness, backing_bits); |
| 1161 | return try self.spv.resolveType(try SpvType.int(self.spv.arena, signedness, backing_bits)); | | |
| 1162 | } | | |
| 1163 | | | |
| 1164 | fn intType2(self: *DeclGen, signedness: std.builtin.Signedness, bits: u16) !SpvCacheRef { | | |
| 1165 | const backing_bits = self.backingIntBits(bits) orelse { | | |
| 1166 | // TODO: Integers too big for any native type are represented as "composite integers": | | |
| 1167 | // An array of largestSupportedIntBits. | | |
| 1168 | return self.todo("Implement {s} composite int type of {} bits", .{ @tagName(signedness), bits }); | | |
| 1169 | }; | | |
| 1170 | return try self.spv.resolve(.{ .int_type = .{ | | |
| 1171 | .signedness = signedness, | | |
| 1172 | .bits = backing_bits, | | |
| 1173 | } }); | | |
| 1174 | } | 1116 | } |
| 1175 | | 1117 | |
| 1176 | /// Create an integer type that represents 'usize'. | 1118 | /// Create an integer type that represents 'usize'. |
| 1177 | fn sizeType(self: *DeclGen) !SpvType.Ref { | 1119 | fn sizeType(self: *DeclGen) !CacheRef { |
| 1178 | return try self.intType(.unsigned, self.getTarget().ptrBitWidth()); | 1120 | return try self.intType(.unsigned, self.getTarget().ptrBitWidth()); |
| 1179 | } | 1121 | } |
| 1180 | | 1122 | |
| 1181 | fn sizeType2(self: *DeclGen) !SpvCacheRef { | | |
| 1182 | return try self.intType2(.unsigned, self.getTarget().ptrBitWidth()); | | |
| 1183 | } | | |
| 1184 | | | |
| 1185 | /// Generate a union type, optionally with a known field. If the tag alignment is greater | 1123 | /// Generate a union type, optionally with a known field. If the tag alignment is greater |
| 1186 | /// than that of the payload, a regular union (non-packed, with both tag and payload), will | 1124 | /// than that of the payload, a regular union (non-packed, with both tag and payload), will |
| 1187 | /// be generated as follows: | 1125 | /// be generated as follows: |
| ... | @@ -1204,7 +1142,7 @@ pub const DeclGen = struct { | ... | @@ -1204,7 +1142,7 @@ pub const DeclGen = struct { |
| 1204 | /// If any of the fields' size is 0, it will be omitted. | 1142 | /// If any of the fields' size is 0, it will be omitted. |
| 1205 | /// NOTE: When the active field is set to something other than the most aligned field, the | 1143 | /// NOTE: When the active field is set to something other than the most aligned field, the |
| 1206 | /// resulting struct will be *underaligned*. | 1144 | /// resulting struct will be *underaligned*. |
| 1207 | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !SpvType.Ref { | 1145 | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { |
| 1208 | const target = self.getTarget(); | 1146 | const target = self.getTarget(); |
| 1209 | const layout = ty.unionGetLayout(target); | 1147 | const layout = ty.unionGetLayout(target); |
| 1210 | const union_ty = ty.cast(Type.Payload.Union).?.data; | 1148 | const union_ty = ty.cast(Type.Payload.Union).?.data; |
| ... | @@ -1218,7 +1156,8 @@ pub const DeclGen = struct { | ... | @@ -1218,7 +1156,8 @@ pub const DeclGen = struct { |
| 1218 | return try self.resolveType(union_ty.tag_ty, .indirect); | 1156 | return try self.resolveType(union_ty.tag_ty, .indirect); |
| 1219 | } | 1157 | } |
| 1220 | | 1158 | |
| 1221 | var members = std.BoundedArray(SpvType.Payload.Struct.Member, 4){}; | 1159 | var member_types = std.BoundedArray(CacheRef, 4){}; |
| | 1160 | var member_names = std.BoundedArray(CacheString, 4){}; |
| 1222 | | 1161 | |
| 1223 | const has_tag = layout.tag_size != 0; | 1162 | const has_tag = layout.tag_size != 0; |
| 1224 | const tag_first = layout.tag_align >= layout.payload_align; | 1163 | const tag_first = layout.tag_align >= layout.payload_align; |
| ... | @@ -1226,82 +1165,6 @@ pub const DeclGen = struct { | ... | @@ -1226,82 +1165,6 @@ pub const DeclGen = struct { |
| 1226 | | 1165 | |
| 1227 | if (has_tag and tag_first) { | 1166 | if (has_tag and tag_first) { |
| 1228 | const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect); | 1167 | const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect); |
| 1229 | members.appendAssumeCapacity(.{ .name = "tag", .ty = tag_ty_ref }); | | |
| 1230 | } | | |
| 1231 | | | |
| 1232 | const active_field = maybe_active_field orelse layout.most_aligned_field; | | |
| 1233 | const active_field_ty = union_ty.fields.values()[active_field].ty; | | |
| 1234 | | | |
| 1235 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime()) blk: { | | |
| 1236 | const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); | | |
| 1237 | members.appendAssumeCapacity(.{ .name = "payload", .ty = active_payload_ty_ref }); | | |
| 1238 | break :blk active_field_ty.abiSize(target); | | |
| 1239 | } else 0; | | |
| 1240 | | | |
| 1241 | const payload_padding_len = layout.payload_size - active_field_size; | | |
| 1242 | if (payload_padding_len != 0) { | | |
| 1243 | const payload_padding_ty_ref = try self.spv.arrayType(@intCast(u32, payload_padding_len), u8_ty_ref); | | |
| 1244 | members.appendAssumeCapacity(.{ .name = "padding_payload", .ty = payload_padding_ty_ref }); | | |
| 1245 | } | | |
| 1246 | | | |
| 1247 | if (has_tag and !tag_first) { | | |
| 1248 | const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect); | | |
| 1249 | members.appendAssumeCapacity(.{ .name = "tag", .ty = tag_ty_ref }); | | |
| 1250 | } | | |
| 1251 | | | |
| 1252 | if (layout.padding != 0) { | | |
| 1253 | const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref); | | |
| 1254 | members.appendAssumeCapacity(.{ .name = "padding", .ty = padding_ty_ref }); | | |
| 1255 | } | | |
| 1256 | | | |
| 1257 | return try self.spv.simpleStructType(members.slice()); | | |
| 1258 | } | | |
| 1259 | | | |
| 1260 | /// Generate a union type, optionally with a known field. If the tag alignment is greater | | |
| 1261 | /// than that of the payload, a regular union (non-packed, with both tag and payload), will | | |
| 1262 | /// be generated as follows: | | |
| 1263 | /// If the active field is known: | | |
| 1264 | /// struct { | | |
| 1265 | /// tag: TagType, | | |
| 1266 | /// payload: ActivePayloadType, | | |
| 1267 | /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8, | | |
| 1268 | /// padding: [padding_size]u8, | | |
| 1269 | /// } | | |
| 1270 | /// If the payload alignment is greater than that of the tag: | | |
| 1271 | /// struct { | | |
| 1272 | /// payload: ActivePayloadType, | | |
| 1273 | /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8, | | |
| 1274 | /// tag: TagType, | | |
| 1275 | /// padding: [padding_size]u8, | | |
| 1276 | /// } | | |
| 1277 | /// If the active payload is unknown, it will default back to the most aligned field. This is | | |
| 1278 | /// to make sure that the overal struct has the correct alignment in spir-v. | | |
| 1279 | /// If any of the fields' size is 0, it will be omitted. | | |
| 1280 | /// NOTE: When the active field is set to something other than the most aligned field, the | | |
| 1281 | /// resulting struct will be *underaligned*. | | |
| 1282 | fn resolveUnionType2(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !SpvCacheRef { | | |
| 1283 | const target = self.getTarget(); | | |
| 1284 | const layout = ty.unionGetLayout(target); | | |
| 1285 | const union_ty = ty.cast(Type.Payload.Union).?.data; | | |
| 1286 | | | |
| 1287 | if (union_ty.layout == .Packed) { | | |
| 1288 | return self.todo("packed union types", .{}); | | |
| 1289 | } | | |
| 1290 | | | |
| 1291 | if (layout.payload_size == 0) { | | |
| 1292 | // No payload, so represent this as just the tag type. | | |
| 1293 | return try self.resolveType2(union_ty.tag_ty, .indirect); | | |
| 1294 | } | | |
| 1295 | | | |
| 1296 | var member_types = std.BoundedArray(SpvCacheRef, 4){}; | | |
| 1297 | var member_names = std.BoundedArray(SpvCacheString, 4){}; | | |
| 1298 | | | |
| 1299 | const has_tag = layout.tag_size != 0; | | |
| 1300 | const tag_first = layout.tag_align >= layout.payload_align; | | |
| 1301 | const u8_ty_ref = try self.intType2(.unsigned, 8); // TODO: What if Int8Type is not enabled? | | |
| 1302 | | | |
| 1303 | if (has_tag and tag_first) { | | |
| 1304 | const tag_ty_ref = try self.resolveType2(union_ty.tag_ty, .indirect); | | |
| 1305 | member_types.appendAssumeCapacity(tag_ty_ref); | 1168 | member_types.appendAssumeCapacity(tag_ty_ref); |
| 1306 | member_names.appendAssumeCapacity(try self.spv.resolveString("tag")); | 1169 | member_names.appendAssumeCapacity(try self.spv.resolveString("tag")); |
| 1307 | } | 1170 | } |
| ... | @@ -1310,7 +1173,7 @@ pub const DeclGen = struct { | ... | @@ -1310,7 +1173,7 @@ pub const DeclGen = struct { |
| 1310 | const active_field_ty = union_ty.fields.values()[active_field].ty; | 1173 | const active_field_ty = union_ty.fields.values()[active_field].ty; |
| 1311 | | 1174 | |
| 1312 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime()) blk: { | 1175 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime()) blk: { |
| 1313 | const active_payload_ty_ref = try self.resolveType2(active_field_ty, .indirect); | 1176 | const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); |
| 1314 | member_types.appendAssumeCapacity(active_payload_ty_ref); | 1177 | member_types.appendAssumeCapacity(active_payload_ty_ref); |
| 1315 | member_names.appendAssumeCapacity(try self.spv.resolveString("payload")); | 1178 | member_names.appendAssumeCapacity(try self.spv.resolveString("payload")); |
| 1316 | break :blk active_field_ty.abiSize(target); | 1179 | break :blk active_field_ty.abiSize(target); |
| ... | @@ -1318,19 +1181,19 @@ pub const DeclGen = struct { | ... | @@ -1318,19 +1181,19 @@ pub const DeclGen = struct { |
| 1318 | | 1181 | |
| 1319 | const payload_padding_len = layout.payload_size - active_field_size; | 1182 | const payload_padding_len = layout.payload_size - active_field_size; |
| 1320 | if (payload_padding_len != 0) { | 1183 | if (payload_padding_len != 0) { |
| 1321 | const payload_padding_ty_ref = try self.spv.arrayType2(@intCast(u32, payload_padding_len), u8_ty_ref); | 1184 | const payload_padding_ty_ref = try self.spv.arrayType(@intCast(u32, payload_padding_len), u8_ty_ref); |
| 1322 | member_types.appendAssumeCapacity(payload_padding_ty_ref); | 1185 | member_types.appendAssumeCapacity(payload_padding_ty_ref); |
| 1323 | member_names.appendAssumeCapacity(try self.spv.resolveString("payload_padding")); | 1186 | member_names.appendAssumeCapacity(try self.spv.resolveString("payload_padding")); |
| 1324 | } | 1187 | } |
| 1325 | | 1188 | |
| 1326 | if (has_tag and !tag_first) { | 1189 | if (has_tag and !tag_first) { |
| 1327 | const tag_ty_ref = try self.resolveType2(union_ty.tag_ty, .indirect); | 1190 | const tag_ty_ref = try self.resolveType(union_ty.tag_ty, .indirect); |
| 1328 | member_types.appendAssumeCapacity(tag_ty_ref); | 1191 | member_types.appendAssumeCapacity(tag_ty_ref); |
| 1329 | member_names.appendAssumeCapacity(try self.spv.resolveString("tag")); | 1192 | member_names.appendAssumeCapacity(try self.spv.resolveString("tag")); |
| 1330 | } | 1193 | } |
| 1331 | | 1194 | |
| 1332 | if (layout.padding != 0) { | 1195 | if (layout.padding != 0) { |
| 1333 | const padding_ty_ref = try self.spv.arrayType2(layout.padding, u8_ty_ref); | 1196 | const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref); |
| 1334 | member_types.appendAssumeCapacity(padding_ty_ref); | 1197 | member_types.appendAssumeCapacity(padding_ty_ref); |
| 1335 | member_names.appendAssumeCapacity(try self.spv.resolveString("padding")); | 1198 | member_names.appendAssumeCapacity(try self.spv.resolveString("padding")); |
| 1336 | } | 1199 | } |
| ... | @@ -1341,22 +1204,24 @@ pub const DeclGen = struct { | ... | @@ -1341,22 +1204,24 @@ pub const DeclGen = struct { |
| 1341 | } }); | 1204 | } }); |
| 1342 | } | 1205 | } |
| 1343 | | 1206 | |
| 1344 | fn resolveType2(self: *DeclGen, ty: Type, repr: Repr) Error!SpvCacheRef { | 1207 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. |
| | 1208 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef { |
| | 1209 | log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); |
| 1345 | const target = self.getTarget(); | 1210 | const target = self.getTarget(); |
| 1346 | switch (ty.zigTypeTag()) { | 1211 | switch (ty.zigTypeTag()) { |
| 1347 | .Void, .NoReturn => return try self.spv.resolve(.void_type), | 1212 | .Void, .NoReturn => return try self.spv.resolve(.void_type), |
| 1348 | .Bool => switch (repr) { | 1213 | .Bool => switch (repr) { |
| 1349 | .direct => return try self.spv.resolve(.bool_type), | 1214 | .direct => return try self.spv.resolve(.bool_type), |
| 1350 | .indirect => return try self.intType2(.unsigned, 1), | 1215 | .indirect => return try self.intType(.unsigned, 1), |
| 1351 | }, | 1216 | }, |
| 1352 | .Int => { | 1217 | .Int => { |
| 1353 | const int_info = ty.intInfo(target); | 1218 | const int_info = ty.intInfo(target); |
| 1354 | return try self.intType2(int_info.signedness, int_info.bits); | 1219 | return try self.intType(int_info.signedness, int_info.bits); |
| 1355 | }, | 1220 | }, |
| 1356 | .Enum => { | 1221 | .Enum => { |
| 1357 | var buffer: Type.Payload.Bits = undefined; | 1222 | var buffer: Type.Payload.Bits = undefined; |
| 1358 | const tag_ty = ty.intTagType(&buffer); | 1223 | const tag_ty = ty.intTagType(&buffer); |
| 1359 | return self.resolveType2(tag_ty, repr); | 1224 | return self.resolveType(tag_ty, repr); |
| 1360 | }, | 1225 | }, |
| 1361 | .Float => { | 1226 | .Float => { |
| 1362 | // We can (and want) not really emulate floating points with other floating point types like with the integer types, | 1227 | // We can (and want) not really emulate floating points with other floating point types like with the integer types, |
| ... | @@ -1378,11 +1243,11 @@ pub const DeclGen = struct { | ... | @@ -1378,11 +1243,11 @@ pub const DeclGen = struct { |
| 1378 | }, | 1243 | }, |
| 1379 | .Array => { | 1244 | .Array => { |
| 1380 | const elem_ty = ty.childType(); | 1245 | const elem_ty = ty.childType(); |
| 1381 | const elem_ty_ref = try self.resolveType2(elem_ty, .direct); | 1246 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| 1382 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse { | 1247 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse { |
| 1383 | return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()}); | 1248 | return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()}); |
| 1384 | }; | 1249 | }; |
| 1385 | return self.spv.arrayType2(total_len, elem_ty_ref); | 1250 | return self.spv.arrayType(total_len, elem_ty_ref); |
| 1386 | }, | 1251 | }, |
| 1387 | .Fn => switch (repr) { | 1252 | .Fn => switch (repr) { |
| 1388 | .direct => { | 1253 | .direct => { |
| ... | @@ -1390,12 +1255,12 @@ pub const DeclGen = struct { | ... | @@ -1390,12 +1255,12 @@ pub const DeclGen = struct { |
| 1390 | if (ty.fnIsVarArgs()) | 1255 | if (ty.fnIsVarArgs()) |
| 1391 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); | 1256 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); |
| 1392 | | 1257 | |
| 1393 | const param_ty_refs = try self.gpa.alloc(SpvCacheRef, ty.fnParamLen()); | 1258 | const param_ty_refs = try self.gpa.alloc(CacheRef, ty.fnParamLen()); |
| 1394 | defer self.gpa.free(param_ty_refs); | 1259 | defer self.gpa.free(param_ty_refs); |
| 1395 | for (param_ty_refs, 0..) |*param_type, i| { | 1260 | for (param_ty_refs, 0..) |*param_type, i| { |
| 1396 | param_type.* = try self.resolveType2(ty.fnParamType(i), .direct); | 1261 | param_type.* = try self.resolveType(ty.fnParamType(i), .direct); |
| 1397 | } | 1262 | } |
| 1398 | const return_ty_ref = try self.resolveType2(ty.fnReturnType(), .direct); | 1263 | const return_ty_ref = try self.resolveType(ty.fnReturnType(), .direct); |
| 1399 | | 1264 | |
| 1400 | return try self.spv.resolve(.{ .function_type = .{ | 1265 | return try self.spv.resolve(.{ .function_type = .{ |
| 1401 | .return_type = return_ty_ref, | 1266 | .return_type = return_ty_ref, |
| ... | @@ -1405,14 +1270,14 @@ pub const DeclGen = struct { | ... | @@ -1405,14 +1270,14 @@ pub const DeclGen = struct { |
| 1405 | .indirect => { | 1270 | .indirect => { |
| 1406 | // TODO: Represent function pointers properly. | 1271 | // TODO: Represent function pointers properly. |
| 1407 | // For now, just use an usize type. | 1272 | // For now, just use an usize type. |
| 1408 | return try self.sizeType2(); | 1273 | return try self.sizeType(); |
| 1409 | }, | 1274 | }, |
| 1410 | }, | 1275 | }, |
| 1411 | .Pointer => { | 1276 | .Pointer => { |
| 1412 | const ptr_info = ty.ptrInfo().data; | 1277 | const ptr_info = ty.ptrInfo().data; |
| 1413 | | 1278 | |
| 1414 | const storage_class = spvStorageClass(ptr_info.@"addrspace"); | 1279 | const storage_class = spvStorageClass(ptr_info.@"addrspace"); |
| 1415 | const child_ty_ref = try self.resolveType2(ptr_info.pointee_type, .indirect); | 1280 | const child_ty_ref = try self.resolveType(ptr_info.pointee_type, .indirect); |
| 1416 | const ptr_ty_ref = try self.spv.resolve(.{ .ptr_type = .{ | 1281 | const ptr_ty_ref = try self.spv.resolve(.{ .ptr_type = .{ |
| 1417 | .storage_class = storage_class, | 1282 | .storage_class = storage_class, |
| 1418 | .child_type = child_ty_ref, | 1283 | .child_type = child_ty_ref, |
| ... | @@ -1420,7 +1285,15 @@ pub const DeclGen = struct { | ... | @@ -1420,7 +1285,15 @@ pub const DeclGen = struct { |
| 1420 | if (ptr_info.size != .Slice) { | 1285 | if (ptr_info.size != .Slice) { |
| 1421 | return ptr_ty_ref; | 1286 | return ptr_ty_ref; |
| 1422 | } | 1287 | } |
| 1423 | unreachable; // TODO | 1288 | |
| | 1289 | const size_ty_ref = try self.sizeType(); |
| | 1290 | return self.spv.resolve(.{ .struct_type = .{ |
| | 1291 | .member_types = &.{ ptr_ty_ref, size_ty_ref }, |
| | 1292 | .member_names = &.{ |
| | 1293 | try self.spv.resolveString("ptr"), |
| | 1294 | try self.spv.resolveString("len"), |
| | 1295 | }, |
| | 1296 | } }); |
| 1424 | }, | 1297 | }, |
| 1425 | .Vector => { | 1298 | .Vector => { |
| 1426 | // Although not 100% the same, Zig vectors map quite neatly to SPIR-V vectors (including many integer and float operations | 1299 | // Although not 100% the same, Zig vectors map quite neatly to SPIR-V vectors (including many integer and float operations |
| ... | @@ -1433,33 +1306,47 @@ pub const DeclGen = struct { | ... | @@ -1433,33 +1306,47 @@ pub const DeclGen = struct { |
| 1433 | // TODO: Properly verify sizes and child type. | 1306 | // TODO: Properly verify sizes and child type. |
| 1434 | | 1307 | |
| 1435 | return try self.spv.resolve(.{ .vector_type = .{ | 1308 | return try self.spv.resolve(.{ .vector_type = .{ |
| 1436 | .component_type = try self.resolveType2(ty.elemType(), repr), | 1309 | .component_type = try self.resolveType(ty.elemType(), repr), |
| 1437 | .component_count = @intCast(u32, ty.vectorLen()), | 1310 | .component_count = @intCast(u32, ty.vectorLen()), |
| 1438 | } }); | 1311 | } }); |
| 1439 | }, | 1312 | }, |
| 1440 | .Struct => { | 1313 | .Struct => { |
| 1441 | if (ty.isSimpleTupleOrAnonStruct()) { | 1314 | if (ty.isSimpleTupleOrAnonStruct()) { |
| 1442 | unreachable; // TODO | 1315 | const tuple = ty.tupleFields(); |
| | 1316 | const member_types = try self.gpa.alloc(CacheRef, tuple.types.len); |
| | 1317 | defer self.gpa.free(member_types); |
| | 1318 | |
| | 1319 | var member_index: usize = 0; |
| | 1320 | for (tuple.types, 0..) |field_ty, i| { |
| | 1321 | const field_val = tuple.values[i]; |
| | 1322 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBits()) continue; |
| | 1323 | |
| | 1324 | member_types[member_index] = try self.resolveType(field_ty, .indirect); |
| | 1325 | member_index += 1; |
| | 1326 | } |
| | 1327 | |
| | 1328 | return try self.spv.resolve(.{ .struct_type = .{ |
| | 1329 | .member_types = member_types[0..member_index], |
| | 1330 | } }); |
| 1443 | } | 1331 | } |
| 1444 | | 1332 | |
| 1445 | const struct_ty = ty.castTag(.@"struct").?.data; | 1333 | const struct_ty = ty.castTag(.@"struct").?.data; |
| 1446 | | 1334 | |
| 1447 | if (struct_ty.layout == .Packed) { | 1335 | if (struct_ty.layout == .Packed) { |
| 1448 | return try self.resolveType2(struct_ty.backing_int_ty, .direct); | 1336 | return try self.resolveType(struct_ty.backing_int_ty, .direct); |
| 1449 | } | 1337 | } |
| 1450 | | 1338 | |
| 1451 | const member_types = try self.gpa.alloc(SpvCacheRef, struct_ty.fields.count()); | 1339 | const member_types = try self.gpa.alloc(CacheRef, struct_ty.fields.count()); |
| 1452 | defer self.gpa.free(member_types); | 1340 | defer self.gpa.free(member_types); |
| 1453 | | 1341 | |
| 1454 | const member_names = try self.gpa.alloc(SpvCacheString, struct_ty.fields.count()); | 1342 | const member_names = try self.gpa.alloc(CacheString, struct_ty.fields.count()); |
| 1455 | defer self.gpa.free(member_names); | 1343 | defer self.gpa.free(member_names); |
| 1456 | | 1344 | |
| 1457 | // const members = try self.spv.arena.alloc(SpvType.Payload.Struct.Member, struct_ty.fields.count()); | | |
| 1458 | var member_index: usize = 0; | 1345 | var member_index: usize = 0; |
| 1459 | for (struct_ty.fields.values(), 0..) |field, i| { | 1346 | for (struct_ty.fields.values(), 0..) |field, i| { |
| 1460 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | 1347 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; |
| 1461 | | 1348 | |
| 1462 | member_types[member_index] = try self.resolveType2(field.ty, .indirect); | 1349 | member_types[member_index] = try self.resolveType(field.ty, .indirect); |
| 1463 | member_names[member_index] = try self.spv.resolveString(struct_ty.fields.keys()[i]); | 1350 | member_names[member_index] = try self.spv.resolveString(struct_ty.fields.keys()[i]); |
| 1464 | member_index += 1; | 1351 | member_index += 1; |
| 1465 | } | 1352 | } |
| ... | @@ -1480,16 +1367,16 @@ pub const DeclGen = struct { | ... | @@ -1480,16 +1367,16 @@ pub const DeclGen = struct { |
| 1480 | // Just use a bool. | 1367 | // Just use a bool. |
| 1481 | // Note: Always generate the bool with indirect format, to save on some sanity | 1368 | // Note: Always generate the bool with indirect format, to save on some sanity |
| 1482 | // Perform the conversion to a direct bool when the field is extracted. | 1369 | // Perform the conversion to a direct bool when the field is extracted. |
| 1483 | return try self.resolveType2(Type.bool, .indirect); | 1370 | return try self.resolveType(Type.bool, .indirect); |
| 1484 | } | 1371 | } |
| 1485 | | 1372 | |
| 1486 | const payload_ty_ref = try self.resolveType2(payload_ty, .indirect); | 1373 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| 1487 | if (ty.optionalReprIsPayload()) { | 1374 | if (ty.optionalReprIsPayload()) { |
| 1488 | // Optional is actually a pointer or a slice. | 1375 | // Optional is actually a pointer or a slice. |
| 1489 | return payload_ty_ref; | 1376 | return payload_ty_ref; |
| 1490 | } | 1377 | } |
| 1491 | | 1378 | |
| 1492 | const bool_ty_ref = try self.resolveType2(Type.bool, .indirect); | 1379 | const bool_ty_ref = try self.resolveType(Type.bool, .indirect); |
| 1493 | | 1380 | |
| 1494 | return try self.spv.resolve(.{ .struct_type = .{ | 1381 | return try self.spv.resolve(.{ .struct_type = .{ |
| 1495 | .member_types = &.{ payload_ty_ref, bool_ty_ref }, | 1382 | .member_types = &.{ payload_ty_ref, bool_ty_ref }, |
| ... | @@ -1499,21 +1386,21 @@ pub const DeclGen = struct { | ... | @@ -1499,21 +1386,21 @@ pub const DeclGen = struct { |
| 1499 | }, | 1386 | }, |
| 1500 | } }); | 1387 | } }); |
| 1501 | }, | 1388 | }, |
| 1502 | .Union => return try self.resolveUnionType2(ty, null), | 1389 | .Union => return try self.resolveUnionType(ty, null), |
| 1503 | .ErrorSet => return try self.intType2(.unsigned, 16), | 1390 | .ErrorSet => return try self.intType(.unsigned, 16), |
| 1504 | .ErrorUnion => { | 1391 | .ErrorUnion => { |
| 1505 | const payload_ty = ty.errorUnionPayload(); | 1392 | const payload_ty = ty.errorUnionPayload(); |
| 1506 | const error_ty_ref = try self.resolveType2(Type.anyerror, .indirect); | 1393 | const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); |
| 1507 | | 1394 | |
| 1508 | const eu_layout = self.errorUnionLayout(payload_ty); | 1395 | const eu_layout = self.errorUnionLayout(payload_ty); |
| 1509 | if (!eu_layout.payload_has_bits) { | 1396 | if (!eu_layout.payload_has_bits) { |
| 1510 | return error_ty_ref; | 1397 | return error_ty_ref; |
| 1511 | } | 1398 | } |
| 1512 | | 1399 | |
| 1513 | const payload_ty_ref = try self.resolveType2(payload_ty, .indirect); | 1400 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| 1514 | | 1401 | |
| 1515 | var member_types: [2]SpvCacheRef = undefined; | 1402 | var member_types: [2]CacheRef = undefined; |
| 1516 | var member_names: [2]SpvCacheString = undefined; | 1403 | var member_names: [2]CacheString = undefined; |
| 1517 | if (eu_layout.error_first) { | 1404 | if (eu_layout.error_first) { |
| 1518 | // Put the error first | 1405 | // Put the error first |
| 1519 | member_types = .{ error_ty_ref, payload_ty_ref }; | 1406 | member_types = .{ error_ty_ref, payload_ty_ref }; |
| ... | @@ -1550,226 +1437,6 @@ pub const DeclGen = struct { | ... | @@ -1550,226 +1437,6 @@ pub const DeclGen = struct { |
| 1550 | } | 1437 | } |
| 1551 | } | 1438 | } |
| 1552 | | 1439 | |
| 1553 | /// Turn a Zig type into a SPIR-V Type, and return a reference to it. | | |
| 1554 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!SpvType.Ref { | | |
| 1555 | log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); | | |
| 1556 | _ = try self.resolveType2(ty, repr); | | |
| 1557 | const target = self.getTarget(); | | |
| 1558 | switch (ty.zigTypeTag()) { | | |
| 1559 | .Void, .NoReturn => return try self.spv.resolveType(SpvType.initTag(.void)), | | |
| 1560 | .Bool => switch (repr) { | | |
| 1561 | .direct => return try self.spv.resolveType(SpvType.initTag(.bool)), | | |
| 1562 | // SPIR-V booleans are opaque, which is fine for operations, but they cant be stored. | | |
| 1563 | // This function returns the *stored* type, for values directly we convert this into a bool when | | |
| 1564 | // it is loaded, and convert it back to this type when stored. | | |
| 1565 | .indirect => return try self.intType(.unsigned, 1), | | |
| 1566 | }, | | |
| 1567 | .Int => { | | |
| 1568 | const int_info = ty.intInfo(target); | | |
| 1569 | return try self.intType(int_info.signedness, int_info.bits); | | |
| 1570 | }, | | |
| 1571 | .Enum => { | | |
| 1572 | var buffer: Type.Payload.Bits = undefined; | | |
| 1573 | const tag_ty = ty.intTagType(&buffer); | | |
| 1574 | return self.resolveType(tag_ty, repr); | | |
| 1575 | }, | | |
| 1576 | .Float => { | | |
| 1577 | // We can (and want) not really emulate floating points with other floating point types like with the integer types, | | |
| 1578 | // so if the float is not supported, just return an error. | | |
| 1579 | const bits = ty.floatBits(target); | | |
| 1580 | const supported = switch (bits) { | | |
| 1581 | 16 => Target.spirv.featureSetHas(target.cpu.features, .Float16), | | |
| 1582 | // 32-bit floats are always supported (see spec, 2.16.1, Data rules). | | |
| 1583 | 32 => true, | | |
| 1584 | 64 => Target.spirv.featureSetHas(target.cpu.features, .Float64), | | |
| 1585 | else => false, | | |
| 1586 | }; | | |
| 1587 | | | |
| 1588 | if (!supported) { | | |
| 1589 | return self.fail("Floating point width of {} bits is not supported for the current SPIR-V feature set", .{bits}); | | |
| 1590 | } | | |
| 1591 | | | |
| 1592 | return try self.spv.resolveType(SpvType.float(bits)); | | |
| 1593 | }, | | |
| 1594 | .Array => { | | |
| 1595 | const elem_ty = ty.childType(); | | |
| 1596 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); | | |
| 1597 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse { | | |
| 1598 | return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()}); | | |
| 1599 | }; | | |
| 1600 | return try self.spv.arrayType(total_len, elem_ty_ref); | | |
| 1601 | }, | | |
| 1602 | .Fn => switch (repr) { | | |
| 1603 | .direct => { | | |
| 1604 | // TODO: Put this somewhere in Sema.zig | | |
| 1605 | if (ty.fnIsVarArgs()) | | |
| 1606 | return self.fail("VarArgs functions are unsupported for SPIR-V", .{}); | | |
| 1607 | | | |
| 1608 | // TODO: Parameter passing convention etc. | | |
| 1609 | | | |
| 1610 | const param_types = try self.spv.arena.alloc(SpvType.Ref, ty.fnParamLen()); | | |
| 1611 | for (param_types, 0..) |*param, i| { | | |
| 1612 | param.* = try self.resolveType(ty.fnParamType(i), .direct); | | |
| 1613 | } | | |
| 1614 | | | |
| 1615 | const return_type = try self.resolveType(ty.fnReturnType(), .direct); | | |
| 1616 | | | |
| 1617 | const payload = try self.spv.arena.create(SpvType.Payload.Function); | | |
| 1618 | payload.* = .{ .return_type = return_type, .parameters = param_types }; | | |
| 1619 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); | | |
| 1620 | }, | | |
| 1621 | .indirect => { | | |
| 1622 | // TODO: Represent function pointers properly. | | |
| 1623 | // For now, just use an usize type. | | |
| 1624 | return try self.sizeType(); | | |
| 1625 | }, | | |
| 1626 | }, | | |
| 1627 | .Pointer => { | | |
| 1628 | const ptr_info = ty.ptrInfo().data; | | |
| 1629 | | | |
| 1630 | const storage_class = spvStorageClass(ptr_info.@"addrspace"); | | |
| 1631 | const child_ty_ref = try self.resolveType(ptr_info.pointee_type, .indirect); | | |
| 1632 | const ptr_ty_ref = try self.spv.ptrType(child_ty_ref, storage_class, 0); | | |
| 1633 | | | |
| 1634 | if (ptr_info.size != .Slice) { | | |
| 1635 | return ptr_ty_ref; | | |
| 1636 | } | | |
| 1637 | | | |
| 1638 | return try self.spv.simpleStructType(&.{ | | |
| 1639 | .{ .ty = ptr_ty_ref, .name = "ptr" }, | | |
| 1640 | .{ .ty = try self.sizeType(), .name = "len" }, | | |
| 1641 | }); | | |
| 1642 | }, | | |
| 1643 | .Vector => { | | |
| 1644 | // Although not 100% the same, Zig vectors map quite neatly to SPIR-V vectors (including many integer and float operations | | |
| 1645 | // which work on them), so simply use those. | | |
| 1646 | // Note: SPIR-V vectors only support bools, ints and floats, so pointer vectors need to be supported another way. | | |
| 1647 | // "composite integers" (larger than the largest supported native type) can probably be represented by an array of vectors. | | |
| 1648 | // TODO: The SPIR-V spec mentions that vector sizes may be quite restricted! look into which we can use, and whether OpTypeVector | | |
| 1649 | // is adequate at all for this. | | |
| 1650 | | | |
| 1651 | // TODO: Properly verify sizes and child type. | | |
| 1652 | | | |
| 1653 | const payload = try self.spv.arena.create(SpvType.Payload.Vector); | | |
| 1654 | payload.* = .{ | | |
| 1655 | .component_type = try self.resolveType(ty.elemType(), repr), | | |
| 1656 | .component_count = @intCast(u32, ty.vectorLen()), | | |
| 1657 | }; | | |
| 1658 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); | | |
| 1659 | }, | | |
| 1660 | .Struct => { | | |
| 1661 | if (ty.isSimpleTupleOrAnonStruct()) { | | |
| 1662 | const tuple = ty.tupleFields(); | | |
| 1663 | const members = try self.spv.arena.alloc(SpvType.Payload.Struct.Member, tuple.types.len); | | |
| 1664 | var member_index: u32 = 0; | | |
| 1665 | for (tuple.types, 0..) |field_ty, i| { | | |
| 1666 | const field_val = tuple.values[i]; | | |
| 1667 | if (field_val.tag() != .unreachable_value or !field_ty.hasRuntimeBitsIgnoreComptime()) continue; | | |
| 1668 | members[member_index] = .{ | | |
| 1669 | .ty = try self.resolveType(field_ty, .indirect), | | |
| 1670 | }; | | |
| 1671 | member_index += 1; | | |
| 1672 | } | | |
| 1673 | const payload = try self.spv.arena.create(SpvType.Payload.Struct); | | |
| 1674 | payload.* = .{ | | |
| 1675 | .members = members[0..member_index], | | |
| 1676 | }; | | |
| 1677 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); | | |
| 1678 | } | | |
| 1679 | | | |
| 1680 | const struct_ty = ty.castTag(.@"struct").?.data; | | |
| 1681 | | | |
| 1682 | if (struct_ty.layout == .Packed) { | | |
| 1683 | return try self.resolveType(struct_ty.backing_int_ty, .indirect); | | |
| 1684 | } | | |
| 1685 | | | |
| 1686 | const members = try self.spv.arena.alloc(SpvType.Payload.Struct.Member, struct_ty.fields.count()); | | |
| 1687 | var member_index: usize = 0; | | |
| 1688 | for (struct_ty.fields.values(), 0..) |field, i| { | | |
| 1689 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | | |
| 1690 | | | |
| 1691 | members[member_index] = .{ | | |
| 1692 | .ty = try self.resolveType(field.ty, .indirect), | | |
| 1693 | .name = struct_ty.fields.keys()[i], | | |
| 1694 | }; | | |
| 1695 | member_index += 1; | | |
| 1696 | } | | |
| 1697 | | | |
| 1698 | const name = try struct_ty.getFullyQualifiedName(self.module); | | |
| 1699 | defer self.module.gpa.free(name); | | |
| 1700 | | | |
| 1701 | const payload = try self.spv.arena.create(SpvType.Payload.Struct); | | |
| 1702 | payload.* = .{ | | |
| 1703 | .members = members[0..member_index], | | |
| 1704 | .name = try self.spv.arena.dupe(u8, name), | | |
| 1705 | }; | | |
| 1706 | return try self.spv.resolveType(SpvType.initPayload(&payload.base)); | | |
| 1707 | }, | | |
| 1708 | .Optional => { | | |
| 1709 | var buf: Type.Payload.ElemType = undefined; | | |
| 1710 | const payload_ty = ty.optionalChild(&buf); | | |
| 1711 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | | |
| 1712 | // Just use a bool. | | |
| 1713 | // Note: Always generate the bool with indirect format, to save on some sanity | | |
| 1714 | // Perform the converison to a direct bool when the field is extracted. | | |
| 1715 | return try self.resolveType(Type.bool, .indirect); | | |
| 1716 | } | | |
| 1717 | | | |
| 1718 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); | | |
| 1719 | if (ty.optionalReprIsPayload()) { | | |
| 1720 | // Optional is actually a pointer or a slice. | | |
| 1721 | return payload_ty_ref; | | |
| 1722 | } | | |
| 1723 | | | |
| 1724 | const bool_ty_ref = try self.resolveType(Type.bool, .indirect); | | |
| 1725 | | | |
| 1726 | // its an actual optional | | |
| 1727 | return try self.spv.simpleStructType(&.{ | | |
| 1728 | .{ .ty = payload_ty_ref, .name = "payload" }, | | |
| 1729 | .{ .ty = bool_ty_ref, .name = "valid" }, | | |
| 1730 | }); | | |
| 1731 | }, | | |
| 1732 | .Union => return try self.resolveUnionType(ty, null), | | |
| 1733 | .ErrorSet => return try self.intType(.unsigned, 16), | | |
| 1734 | .ErrorUnion => { | | |
| 1735 | const payload_ty = ty.errorUnionPayload(); | | |
| 1736 | const error_ty_ref = try self.resolveType(Type.anyerror, .indirect); | | |
| 1737 | | | |
| 1738 | const eu_layout = self.errorUnionLayout(payload_ty); | | |
| 1739 | if (!eu_layout.payload_has_bits) { | | |
| 1740 | return error_ty_ref; | | |
| 1741 | } | | |
| 1742 | | | |
| 1743 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); | | |
| 1744 | | | |
| 1745 | var members = std.BoundedArray(SpvType.Payload.Struct.Member, 2){}; | | |
| 1746 | if (eu_layout.error_first) { | | |
| 1747 | // Put the error first | | |
| 1748 | members.appendAssumeCapacity(.{ .ty = error_ty_ref, .name = "error" }); | | |
| 1749 | members.appendAssumeCapacity(.{ .ty = payload_ty_ref, .name = "payload" }); | | |
| 1750 | // TODO: ABI padding? | | |
| 1751 | } else { | | |
| 1752 | // Put the payload first. | | |
| 1753 | members.appendAssumeCapacity(.{ .ty = payload_ty_ref, .name = "payload" }); | | |
| 1754 | members.appendAssumeCapacity(.{ .ty = error_ty_ref, .name = "error" }); | | |
| 1755 | // TODO: ABI padding? | | |
| 1756 | } | | |
| 1757 | | | |
| 1758 | return try self.spv.simpleStructType(members.slice()); | | |
| 1759 | }, | | |
| 1760 | | | |
| 1761 | .Null, | | |
| 1762 | .Undefined, | | |
| 1763 | .EnumLiteral, | | |
| 1764 | .ComptimeFloat, | | |
| 1765 | .ComptimeInt, | | |
| 1766 | .Type, | | |
| 1767 | => unreachable, // Must be comptime. | | |
| 1768 | | | |
| 1769 | else => |tag| return self.todo("Implement zig type '{}'", .{tag}), | | |
| 1770 | } | | |
| 1771 | } | | |
| 1772 | | | |
| 1773 | fn spvStorageClass(as: std.builtin.AddressSpace) StorageClass { | 1440 | fn spvStorageClass(as: std.builtin.AddressSpace) StorageClass { |
| 1774 | return switch (as) { | 1441 | return switch (as) { |
| 1775 | .generic => .Generic, | 1442 | .generic => .Generic, |
| ... | @@ -1839,17 +1506,13 @@ pub const DeclGen = struct { | ... | @@ -1839,17 +1506,13 @@ pub const DeclGen = struct { |
| 1839 | /// the name of an error in the text executor. | 1506 | /// the name of an error in the text executor. |
| 1840 | fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { | 1507 | fn generateTestEntryPoint(self: *DeclGen, name: []const u8, spv_test_decl_index: SpvModule.Decl.Index) !void { |
| 1841 | const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct); | 1508 | const anyerror_ty_ref = try self.resolveType(Type.anyerror, .direct); |
| 1842 | const ptr_anyerror_ty_ref = try self.spv.ptrType(anyerror_ty_ref, .CrossWorkgroup, 0); | 1509 | const ptr_anyerror_ty_ref = try self.spv.ptrType(anyerror_ty_ref, .CrossWorkgroup); |
| 1843 | const void_ty_ref = try self.resolveType(Type.void, .direct); | 1510 | const void_ty_ref = try self.resolveType(Type.void, .direct); |
| 1844 | | 1511 | |
| 1845 | const kernel_proto_ty_ref = blk: { | 1512 | const kernel_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ |
| 1846 | const proto_payload = try self.spv.arena.create(SpvType.Payload.Function); | 1513 | .return_type = void_ty_ref, |
| 1847 | proto_payload.* = .{ | 1514 | .parameters = &.{ptr_anyerror_ty_ref}, |
| 1848 | .return_type = void_ty_ref, | 1515 | } }); |
| 1849 | .parameters = try self.spv.arena.dupe(SpvType.Ref, &.{ptr_anyerror_ty_ref}), | | |
| 1850 | }; | | |
| 1851 | break :blk try self.spv.resolveType(SpvType.initPayload(&proto_payload.base)); | | |
| 1852 | }; | | |
| 1853 | | 1516 | |
| 1854 | const test_id = self.spv.declPtr(spv_test_decl_index).result_id; | 1517 | const test_id = self.spv.declPtr(spv_test_decl_index).result_id; |
| 1855 | | 1518 | |
| ... | @@ -1983,9 +1646,9 @@ pub const DeclGen = struct { | ... | @@ -1983,9 +1646,9 @@ pub const DeclGen = struct { |
| 1983 | } | 1646 | } |
| 1984 | } | 1647 | } |
| 1985 | | 1648 | |
| 1986 | fn boolToInt(self: *DeclGen, result_ty_ref: SpvType.Ref, condition_id: IdRef) !IdRef { | 1649 | fn boolToInt(self: *DeclGen, result_ty_ref: CacheRef, condition_id: IdRef) !IdRef { |
| 1987 | const zero_id = try self.constInt(result_ty_ref, 0); | 1650 | const zero_id = try self.spv.constInt(result_ty_ref, 0); |
| 1988 | const one_id = try self.constInt(result_ty_ref, 1); | 1651 | const one_id = try self.spv.constInt(result_ty_ref, 1); |
| 1989 | const result_id = self.spv.allocId(); | 1652 | const result_id = self.spv.allocId(); |
| 1990 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ | 1653 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ |
| 1991 | .id_result_type = self.typeId(result_ty_ref), | 1654 | .id_result_type = self.typeId(result_ty_ref), |
| ... | @@ -2004,7 +1667,7 @@ pub const DeclGen = struct { | ... | @@ -2004,7 +1667,7 @@ pub const DeclGen = struct { |
| 2004 | .Bool => blk: { | 1667 | .Bool => blk: { |
| 2005 | const direct_bool_ty_ref = try self.resolveType(ty, .direct); | 1668 | const direct_bool_ty_ref = try self.resolveType(ty, .direct); |
| 2006 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); | 1669 | const indirect_bool_ty_ref = try self.resolveType(ty, .indirect); |
| 2007 | const zero_id = try self.constInt(indirect_bool_ty_ref, 0); | 1670 | const zero_id = try self.spv.constInt(indirect_bool_ty_ref, 0); |
| 2008 | const result_id = self.spv.allocId(); | 1671 | const result_id = self.spv.allocId(); |
| 2009 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ | 1672 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| 2010 | .id_result_type = self.typeId(direct_bool_ty_ref), | 1673 | .id_result_type = self.typeId(direct_bool_ty_ref), |
| ... | @@ -2242,10 +1905,10 @@ pub const DeclGen = struct { | ... | @@ -2242,10 +1905,10 @@ pub const DeclGen = struct { |
| 2242 | return result_id; | 1905 | return result_id; |
| 2243 | } | 1906 | } |
| 2244 | | 1907 | |
| 2245 | fn maskStrangeInt(self: *DeclGen, ty_ref: SpvType.Ref, value_id: IdRef, bits: u16) !IdRef { | 1908 | fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef { |
| 2246 | const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @intCast(u6, bits)) - 1; | 1909 | const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @intCast(u6, bits)) - 1; |
| 2247 | const result_id = self.spv.allocId(); | 1910 | const result_id = self.spv.allocId(); |
| 2248 | const mask_id = try self.constInt(ty_ref, mask_value); | 1911 | const mask_id = try self.spv.constInt(ty_ref, mask_value); |
| 2249 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ | 1912 | try self.func.body.emit(self.spv.gpa, .OpBitwiseAnd, .{ |
| 2250 | .id_result_type = self.typeId(ty_ref), | 1913 | .id_result_type = self.typeId(ty_ref), |
| 2251 | .id_result = result_id, | 1914 | .id_result = result_id, |
| ... | @@ -2384,7 +2047,7 @@ pub const DeclGen = struct { | ... | @@ -2384,7 +2047,7 @@ pub const DeclGen = struct { |
| 2384 | // Note that signed overflow is also wrapping in spir-v. | 2047 | // Note that signed overflow is also wrapping in spir-v. |
| 2385 | | 2048 | |
| 2386 | const rhs_lt_zero_id = self.spv.allocId(); | 2049 | const rhs_lt_zero_id = self.spv.allocId(); |
| 2387 | const zero_id = try self.constInt(operand_ty_ref, 0); | 2050 | const zero_id = try self.spv.constInt(operand_ty_ref, 0); |
| 2388 | try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ | 2051 | try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ |
| 2389 | .id_result_type = self.typeId(bool_ty_ref), | 2052 | .id_result_type = self.typeId(bool_ty_ref), |
| 2390 | .id_result = rhs_lt_zero_id, | 2053 | .id_result = rhs_lt_zero_id, |
| ... | @@ -2463,7 +2126,7 @@ pub const DeclGen = struct { | ... | @@ -2463,7 +2126,7 @@ pub const DeclGen = struct { |
| 2463 | /// is the latter and PtrAccessChain is the former. | 2126 | /// is the latter and PtrAccessChain is the former. |
| 2464 | fn accessChain( | 2127 | fn accessChain( |
| 2465 | self: *DeclGen, | 2128 | self: *DeclGen, |
| 2466 | result_ty_ref: SpvType.Ref, | 2129 | result_ty_ref: CacheRef, |
| 2467 | base: IdRef, | 2130 | base: IdRef, |
| 2468 | indexes: []const IdRef, | 2131 | indexes: []const IdRef, |
| 2469 | ) !IdRef { | 2132 | ) !IdRef { |
| ... | @@ -2479,7 +2142,7 @@ pub const DeclGen = struct { | ... | @@ -2479,7 +2142,7 @@ pub const DeclGen = struct { |
| 2479 | | 2142 | |
| 2480 | fn ptrAccessChain( | 2143 | fn ptrAccessChain( |
| 2481 | self: *DeclGen, | 2144 | self: *DeclGen, |
| 2482 | result_ty_ref: SpvType.Ref, | 2145 | result_ty_ref: CacheRef, |
| 2483 | base: IdRef, | 2146 | base: IdRef, |
| 2484 | element: IdRef, | 2147 | element: IdRef, |
| 2485 | indexes: []const IdRef, | 2148 | indexes: []const IdRef, |
| ... | @@ -2854,7 +2517,7 @@ pub const DeclGen = struct { | ... | @@ -2854,7 +2517,7 @@ pub const DeclGen = struct { |
| 2854 | // Construct new pointer type for the resulting pointer | 2517 | // Construct new pointer type for the resulting pointer |
| 2855 | const elem_ty = ptr_ty.elemType2(); // use elemType() so that we get T for *[N]T. | 2518 | const elem_ty = ptr_ty.elemType2(); // use elemType() so that we get T for *[N]T. |
| 2856 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); | 2519 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); |
| 2857 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace()), 0); | 2520 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace())); |
| 2858 | if (ptr_ty.isSinglePointer()) { | 2521 | if (ptr_ty.isSinglePointer()) { |
| 2859 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | 2522 | // Pointer-to-array. In this case, the resulting pointer is not of the same type |
| 2860 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. | 2523 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. |
| ... | @@ -2970,7 +2633,7 @@ pub const DeclGen = struct { | ... | @@ -2970,7 +2633,7 @@ pub const DeclGen = struct { |
| 2970 | fn makePointerConstant( | 2633 | fn makePointerConstant( |
| 2971 | self: *DeclGen, | 2634 | self: *DeclGen, |
| 2972 | section: *SpvSection, | 2635 | section: *SpvSection, |
| 2973 | ptr_ty_ref: SpvType.Ref, | 2636 | ptr_ty_ref: CacheRef, |
| 2974 | ptr_id: IdRef, | 2637 | ptr_id: IdRef, |
| 2975 | ) !IdRef { | 2638 | ) !IdRef { |
| 2976 | const result_id = self.spv.allocId(); | 2639 | const result_id = self.spv.allocId(); |
| ... | @@ -2988,11 +2651,11 @@ pub const DeclGen = struct { | ... | @@ -2988,11 +2651,11 @@ pub const DeclGen = struct { |
| 2988 | // placed in the Function address space. | 2651 | // placed in the Function address space. |
| 2989 | fn alloc( | 2652 | fn alloc( |
| 2990 | self: *DeclGen, | 2653 | self: *DeclGen, |
| 2991 | ty_ref: SpvType.Ref, | 2654 | ty_ref: CacheRef, |
| 2992 | initializer: ?IdRef, | 2655 | initializer: ?IdRef, |
| 2993 | ) !IdRef { | 2656 | ) !IdRef { |
| 2994 | const fn_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Function, 0); | 2657 | const fn_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Function); |
| 2995 | const general_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic, 0); | 2658 | const general_ptr_ty_ref = try self.spv.ptrType(ty_ref, .Generic); |
| 2996 | | 2659 | |
| 2997 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to | 2660 | // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to |
| 2998 | // directly generate them into func.prologue instead of the body. | 2661 | // directly generate them into func.prologue instead of the body. |
| ... | @@ -3146,7 +2809,7 @@ pub const DeclGen = struct { | ... | @@ -3146,7 +2809,7 @@ pub const DeclGen = struct { |
| 3146 | | 2809 | |
| 3147 | const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; | 2810 | const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; |
| 3148 | if (val_is_undef) { | 2811 | if (val_is_undef) { |
| 3149 | const undef = try self.constUndef(ptr_ty_ref); | 2812 | const undef = try self.spv.constUndef(ptr_ty_ref); |
| 3150 | try self.store(ptr_ty, ptr, undef); | 2813 | try self.store(ptr_ty, ptr, undef); |
| 3151 | } else { | 2814 | } else { |
| 3152 | try self.store(ptr_ty, ptr, value); | 2815 | try self.store(ptr_ty, ptr, value); |
| ... | @@ -3217,7 +2880,7 @@ pub const DeclGen = struct { | ... | @@ -3217,7 +2880,7 @@ pub const DeclGen = struct { |
| 3217 | else | 2880 | else |
| 3218 | err_union_id; | 2881 | err_union_id; |
| 3219 | | 2882 | |
| 3220 | const zero_id = try self.constInt(err_ty_ref, 0); | 2883 | const zero_id = try self.spv.constInt(err_ty_ref, 0); |
| 3221 | const is_err_id = self.spv.allocId(); | 2884 | const is_err_id = self.spv.allocId(); |
| 3222 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ | 2885 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| 3223 | .id_result_type = self.typeId(bool_ty_ref), | 2886 | .id_result_type = self.typeId(bool_ty_ref), |
| ... | @@ -3266,7 +2929,7 @@ pub const DeclGen = struct { | ... | @@ -3266,7 +2929,7 @@ pub const DeclGen = struct { |
| 3266 | | 2929 | |
| 3267 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 2930 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { |
| 3268 | // No error possible, so just return undefined. | 2931 | // No error possible, so just return undefined. |
| 3269 | return try self.constUndef(err_ty_ref); | 2932 | return try self.spv.constUndef(err_ty_ref); |
| 3270 | } | 2933 | } |
| 3271 | | 2934 | |
| 3272 | const payload_ty = err_union_ty.errorUnionPayload(); | 2935 | const payload_ty = err_union_ty.errorUnionPayload(); |
| ... | @@ -3295,7 +2958,7 @@ pub const DeclGen = struct { | ... | @@ -3295,7 +2958,7 @@ pub const DeclGen = struct { |
| 3295 | | 2958 | |
| 3296 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); | 2959 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| 3297 | var members = std.BoundedArray(IdRef, 2){}; | 2960 | var members = std.BoundedArray(IdRef, 2){}; |
| 3298 | const payload_id = try self.constUndef(payload_ty_ref); | 2961 | const payload_id = try self.spv.constUndef(payload_ty_ref); |
| 3299 | if (eu_layout.error_first) { | 2962 | if (eu_layout.error_first) { |
| 3300 | members.appendAssumeCapacity(operand_id); | 2963 | members.appendAssumeCapacity(operand_id); |
| 3301 | members.appendAssumeCapacity(payload_id); | 2964 | members.appendAssumeCapacity(payload_id); |
| ... | @@ -3337,7 +3000,7 @@ pub const DeclGen = struct { | ... | @@ -3337,7 +3000,7 @@ pub const DeclGen = struct { |
| 3337 | operand_id; | 3000 | operand_id; |
| 3338 | | 3001 | |
| 3339 | const payload_ty_ref = try self.resolveType(ptr_ty, .direct); | 3002 | const payload_ty_ref = try self.resolveType(ptr_ty, .direct); |
| 3340 | const null_id = try self.constNull(payload_ty_ref); | 3003 | const null_id = try self.spv.constNull(payload_ty_ref); |
| 3341 | const result_id = self.spv.allocId(); | 3004 | const result_id = self.spv.allocId(); |
| 3342 | const operands = .{ | 3005 | const operands = .{ |
| 3343 | .id_result_type = self.typeId(bool_ty_ref), | 3006 | .id_result_type = self.typeId(bool_ty_ref), |