authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-08-02 08:35:44+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2025-08-02 08:56:39+03:30
log5525a90a478e4c3d9e9b8cd2d78f9238d7b8795a
treec2a99d9b362f0c75bd2e1f466191668836fd52b2
parent31de2c873fa206a8fd491f7c9c959845fb86b0a1
signaturelock-open Commit is signed but in an unrecognized format.

spirv: remove deduplication ISel


7 files changed, 490 insertions(+), 995 deletions(-)

CMakeLists.txt-10
...@@ -553,11 +553,6 @@ set(ZIG_STAGE2_SOURCES...@@ -553,11 +553,6 @@ set(ZIG_STAGE2_SOURCES
553 src/codegen/c/Type.zig553 src/codegen/c/Type.zig
554 src/codegen/llvm.zig554 src/codegen/llvm.zig
555 src/codegen/llvm/bindings.zig555 src/codegen/llvm/bindings.zig
556 src/codegen/spirv.zig
557 src/codegen/spirv/Assembler.zig
558 src/codegen/spirv/Module.zig
559 src/codegen/spirv/Section.zig
560 src/codegen/spirv/spec.zig
561 src/crash_report.zig556 src/crash_report.zig
562 src/dev.zig557 src/dev.zig
563 src/libs/freebsd.zig558 src/libs/freebsd.zig
...@@ -620,11 +615,6 @@ set(ZIG_STAGE2_SOURCES...@@ -620,11 +615,6 @@ set(ZIG_STAGE2_SOURCES
620 src/link/Plan9.zig615 src/link/Plan9.zig
621 src/link/Plan9/aout.zig616 src/link/Plan9/aout.zig
622 src/link/Queue.zig617 src/link/Queue.zig
623 src/link/SpirV.zig
624 src/link/SpirV/BinaryModule.zig
625 src/link/SpirV/deduplicate.zig
626 src/link/SpirV/lower_invocation_globals.zig
627 src/link/SpirV/prune_unused.zig
628 src/link/StringTable.zig618 src/link/StringTable.zig
629 src/link/Wasm.zig619 src/link/Wasm.zig
630 src/link/Wasm/Archive.zig620 src/link/Wasm/Archive.zig
src/Zcu.zig+1-3
...@@ -3646,9 +3646,7 @@ pub fn errorSetBits(zcu: *const Zcu) u16 {...@@ -3646,9 +3646,7 @@ pub fn errorSetBits(zcu: *const Zcu) u16 {
36463646
3647 if (zcu.error_limit == 0) return 0;3647 if (zcu.error_limit == 0) return 0;
3648 if (target.cpu.arch.isSpirV()) {3648 if (target.cpu.arch.isSpirV()) {
3649 if (!target.cpu.has(.spirv, .storage_push_constant16)) {3649 if (zcu.comp.config.is_test) return 32;
3650 return 32;
3651 }
3652 }3650 }
36533651
3654 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;3652 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;
src/arch/spirv/Assembler.zig+3-4
...@@ -267,9 +267,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {...@@ -267,9 +267,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {
267 const ids = try gpa.alloc(Id, operands[1..].len);267 const ids = try gpa.alloc(Id, operands[1..].len);
268 defer gpa.free(ids);268 defer gpa.free(ids);
269 for (operands[1..], ids) |op, *id| id.* = try self.resolveRefId(op.ref_id);269 for (operands[1..], ids) |op, *id| id.* = try self.resolveRefId(op.ref_id);
270 const result_id = module.allocId();270 break :blk try module.structType(ids, null, null, .none);
271 try module.structType(result_id, ids, null);
272 break :blk result_id;
273 },271 },
274 .OpTypeImage => blk: {272 .OpTypeImage => blk: {
275 const sampled_type = try self.resolveRefId(operands[1].ref_id);273 const sampled_type = try self.resolveRefId(operands[1].ref_id);
...@@ -324,6 +322,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {...@@ -324,6 +322,7 @@ fn processTypeInstruction(self: *Assembler) !AsmValue {
324/// - Target section is determined from instruction type.322/// - Target section is determined from instruction type.
325fn processGenericInstruction(self: *Assembler) !?AsmValue {323fn processGenericInstruction(self: *Assembler) !?AsmValue {
326 const module = self.cg.module;324 const module = self.cg.module;
325 const target = module.zcu.getTarget();
327 const operands = self.inst.operands.items;326 const operands = self.inst.operands.items;
328 var maybe_spv_decl_index: ?Decl.Index = null;327 var maybe_spv_decl_index: ?Decl.Index = null;
329 const section = switch (self.inst.opcode.class()) {328 const section = switch (self.inst.opcode.class()) {
...@@ -337,7 +336,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {...@@ -337,7 +336,7 @@ fn processGenericInstruction(self: *Assembler) !?AsmValue {
337 const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);336 const storage_class: spec.StorageClass = @enumFromInt(operands[2].value);
338 if (storage_class == .function) break :section &self.cg.prologue;337 if (storage_class == .function) break :section &self.cg.prologue;
339 maybe_spv_decl_index = try module.allocDecl(.global);338 maybe_spv_decl_index = try module.allocDecl(.global);
340 if (!module.target.cpu.has(.spirv, .v1_4) and storage_class != .input and storage_class != .output) {339 if (!target.cpu.has(.spirv, .v1_4) and storage_class != .input and storage_class != .output) {
341 // Before version 1.4, the interface’s storage classes are limited to the Input and Output340 // Before version 1.4, the interface’s storage classes are limited to the Input and Output
342 break :section &module.sections.globals;341 break :section &module.sections.globals;
343 }342 }
src/arch/spirv/CodeGen.zig+215-296
...@@ -181,8 +181,7 @@ const Error = error{ CodegenFail, OutOfMemory };...@@ -181,8 +181,7 @@ const Error = error{ CodegenFail, OutOfMemory };
181181
182pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {182pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
183 const gpa = cg.module.gpa;183 const gpa = cg.module.gpa;
184 const pt = cg.pt;184 const zcu = cg.module.zcu;
185 const zcu = pt.zcu;
186 const ip = &zcu.intern_pool;185 const ip = &zcu.intern_pool;
187186
188 const nav = ip.getNav(cg.owner_nav);187 const nav = ip.getNav(cg.owner_nav);
...@@ -198,7 +197,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -198,7 +197,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
198 .func => {197 .func => {
199 const fn_info = zcu.typeToFunc(ty).?;198 const fn_info = zcu.typeToFunc(ty).?;
200 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));199 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
201 const is_test = cg.pt.zcu.test_functions.contains(cg.owner_nav);200 const is_test = zcu.test_functions.contains(cg.owner_nav);
202201
203 const func_result_id = if (is_test) cg.module.allocId() else result_id;202 const func_result_id = if (is_test) cg.module.allocId() else result_id;
204 const prototype_ty_id = try cg.resolveType(ty, .direct);203 const prototype_ty_id = try cg.resolveType(ty, .direct);
...@@ -354,7 +353,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -354,7 +353,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
354353
355pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {354pub fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
356 @branchHint(.cold);355 @branchHint(.cold);
357 const zcu = cg.pt.zcu;356 const zcu = cg.module.zcu;
358 const src_loc = zcu.navSrcLoc(cg.owner_nav);357 const src_loc = zcu.navSrcLoc(cg.owner_nav);
359 assert(cg.error_msg == null);358 assert(cg.error_msg == null);
360 cg.error_msg = try Zcu.ErrorMsg.create(zcu.gpa, src_loc, format, args);359 cg.error_msg = try Zcu.ErrorMsg.create(zcu.gpa, src_loc, format, args);
...@@ -368,7 +367,7 @@ pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {...@@ -368,7 +367,7 @@ pub fn todo(cg: *CodeGen, comptime format: []const u8, args: anytype) Error {
368/// This imports the "default" extended instruction set for the target367/// This imports the "default" extended instruction set for the target
369/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.368/// For OpenCL, OpenCL.std.100. For Vulkan and OpenGL, GLSL.std.450.
370fn importExtendedSet(cg: *CodeGen) !Id {369fn importExtendedSet(cg: *CodeGen) !Id {
371 const target = cg.module.target;370 const target = cg.module.zcu.getTarget();
372 return switch (target.os.tag) {371 return switch (target.os.tag) {
373 .opencl, .amdhsa => try cg.module.importInstructionSet(.@"OpenCL.std"),372 .opencl, .amdhsa => try cg.module.importInstructionSet(.@"OpenCL.std"),
374 .vulkan, .opengl => try cg.module.importInstructionSet(.@"GLSL.std.450"),373 .vulkan, .opengl => try cg.module.importInstructionSet(.@"GLSL.std.450"),
...@@ -379,7 +378,7 @@ fn importExtendedSet(cg: *CodeGen) !Id {...@@ -379,7 +378,7 @@ fn importExtendedSet(cg: *CodeGen) !Id {
379/// Fetch the result-id for a previously generated instruction or constant.378/// Fetch the result-id for a previously generated instruction or constant.
380fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {379fn resolve(cg: *CodeGen, inst: Air.Inst.Ref) !Id {
381 const pt = cg.pt;380 const pt = cg.pt;
382 const zcu = pt.zcu;381 const zcu = cg.module.zcu;
383 const ip = &zcu.intern_pool;382 const ip = &zcu.intern_pool;
384 if (try cg.air.value(inst, pt)) |val| {383 if (try cg.air.value(inst, pt)) |val| {
385 const ty = cg.typeOf(inst);384 const ty = cg.typeOf(inst);
...@@ -405,7 +404,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -405,7 +404,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
405404
406 // TODO: This cannot be a function at this point, but it should probably be handled anyway.405 // TODO: This cannot be a function at this point, but it should probably be handled anyway.
407406
408 const zcu = cg.pt.zcu;407 const zcu = cg.module.zcu;
409 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));408 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
410 const decl_ptr_ty_id = try cg.ptrType(ty, cg.module.storageClass(.generic), .indirect);409 const decl_ptr_ty_id = try cg.ptrType(ty, cg.module.storageClass(.generic), .indirect);
411410
...@@ -499,7 +498,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {...@@ -499,7 +498,8 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id {
499}498}
500499
501fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void {500fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void {
502 if (cg.module.target.cpu.has(.spirv, .v1_4)) {501 const target = cg.module.zcu.getTarget();
502 if (target.cpu.has(.spirv, .v1_4)) {
503 try cg.decl_deps.put(cg.module.gpa, decl_index, {});503 try cg.decl_deps.put(cg.module.gpa, decl_index, {});
504 } else {504 } else {
505 // Before version 1.4, the interface’s storage classes are limited to the Input and Output505 // Before version 1.4, the interface’s storage classes are limited to the Input and Output
...@@ -510,7 +510,8 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St...@@ -510,7 +510,8 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St
510}510}
511511
512fn castToGeneric(cg: *CodeGen, type_id: Id, ptr_id: Id) !Id {512fn castToGeneric(cg: *CodeGen, type_id: Id, ptr_id: Id) !Id {
513 if (cg.module.target.cpu.has(.spirv, .generic_pointer)) {513 const target = cg.module.zcu.getTarget();
514 if (target.cpu.has(.spirv, .generic_pointer)) {
514 const result_id = cg.module.allocId();515 const result_id = cg.module.allocId();
515 try cg.body.emit(cg.module.gpa, .OpPtrCastToGeneric, .{516 try cg.body.emit(cg.module.gpa, .OpPtrCastToGeneric, .{
516 .id_result_type = type_id,517 .id_result_type = type_id,
...@@ -541,10 +542,12 @@ fn beginSpvBlock(cg: *CodeGen, label: Id) !void {...@@ -541,10 +542,12 @@ fn beginSpvBlock(cg: *CodeGen, label: Id) !void {
541/// The result is valid to be used with OpTypeInt.542/// The result is valid to be used with OpTypeInt.
542/// TODO: Should the result of this function be cached?543/// TODO: Should the result of this function be cached?
543fn backingIntBits(cg: *CodeGen, bits: u16) struct { u16, bool } {544fn backingIntBits(cg: *CodeGen, bits: u16) struct { u16, bool } {
545 const target = cg.module.zcu.getTarget();
546
544 // The backend will never be asked to compiler a 0-bit integer, so we won't have to handle those in this function.547 // The backend will never be asked to compiler a 0-bit integer, so we won't have to handle those in this function.
545 assert(bits != 0);548 assert(bits != 0);
546549
547 if (cg.module.target.cpu.has(.spirv, .arbitrary_precision_integers) and bits <= 32) {550 if (target.cpu.has(.spirv, .arbitrary_precision_integers) and bits <= 32) {
548 return .{ bits, false };551 return .{ bits, false };
549 }552 }
550553
...@@ -556,7 +559,7 @@ fn backingIntBits(cg: *CodeGen, bits: u16) struct { u16, bool } {...@@ -556,7 +559,7 @@ fn backingIntBits(cg: *CodeGen, bits: u16) struct { u16, bool } {
556 .{ .bits = 32, .enabled = true },559 .{ .bits = 32, .enabled = true },
557 .{560 .{
558 .bits = 64,561 .bits = 64,
559 .enabled = cg.module.target.cpu.has(.spirv, .int64) or cg.module.target.cpu.arch == .spirv64,562 .enabled = target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64,
560 },563 },
561 };564 };
562565
...@@ -575,7 +578,8 @@ fn backingIntBits(cg: *CodeGen, bits: u16) struct { u16, bool } {...@@ -575,7 +578,8 @@ fn backingIntBits(cg: *CodeGen, bits: u16) struct { u16, bool } {
575/// is no way of knowing whether those are actually supported.578/// is no way of knowing whether those are actually supported.
576/// TODO: Maybe this should be cached?579/// TODO: Maybe this should be cached?
577fn largestSupportedIntBits(cg: *CodeGen) u16 {580fn largestSupportedIntBits(cg: *CodeGen) u16 {
578 if (cg.module.target.cpu.has(.spirv, .int64) or cg.module.target.cpu.arch == .spirv64) {581 const target = cg.module.zcu.getTarget();
582 if (target.cpu.has(.spirv, .int64) or target.cpu.arch == .spirv64) {
579 return 64;583 return 64;
580 }584 }
581 return 32;585 return 32;
...@@ -618,8 +622,8 @@ const ArithmeticTypeInfo = struct {...@@ -618,8 +622,8 @@ const ArithmeticTypeInfo = struct {
618};622};
619623
620fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {624fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
621 const zcu = cg.pt.zcu;625 const zcu = cg.module.zcu;
622 const target = cg.module.target;626 const target = cg.module.zcu.getTarget();
623 var scalar_ty = ty.scalarType(zcu);627 var scalar_ty = ty.scalarType(zcu);
624 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {628 if (scalar_ty.zigTypeTag(zcu) == .@"enum") {
625 scalar_ty = scalar_ty.intTagType(zcu);629 scalar_ty = scalar_ty.intTagType(zcu);
...@@ -663,7 +667,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {...@@ -663,7 +667,8 @@ fn arithmeticTypeInfo(cg: *CodeGen, ty: Type) ArithmeticTypeInfo {
663667
664/// Checks whether the type can be directly translated to SPIR-V vectors668/// Checks whether the type can be directly translated to SPIR-V vectors
665fn isSpvVector(cg: *CodeGen, ty: Type) bool {669fn isSpvVector(cg: *CodeGen, ty: Type) bool {
666 const zcu = cg.pt.zcu;670 const zcu = cg.module.zcu;
671 const target = cg.module.zcu.getTarget();
667 if (ty.zigTypeTag(zcu) != .vector) return false;672 if (ty.zigTypeTag(zcu) != .vector) return false;
668673
669 // TODO: This check must be expanded for types that can be represented674 // TODO: This check must be expanded for types that can be represented
...@@ -683,7 +688,7 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {...@@ -683,7 +688,7 @@ fn isSpvVector(cg: *CodeGen, ty: Type) bool {
683688
684 if (elem_ty.isNumeric(zcu) or elem_ty.toIntern() == .bool_type) {689 if (elem_ty.isNumeric(zcu) or elem_ty.toIntern() == .bool_type) {
685 if (len > 1 and len <= 4) return true;690 if (len > 1 and len <= 4) return true;
686 if (cg.module.target.cpu.has(.spirv, .vector16)) return (len == 8 or len == 16);691 if (target.cpu.has(.spirv, .vector16)) return (len == 8 or len == 16);
687 }692 }
688693
689 return false;694 return false;
...@@ -701,7 +706,8 @@ fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {...@@ -701,7 +706,8 @@ fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id {
701/// This function, unlike Module.constInt, takes care to bitcast706/// This function, unlike Module.constInt, takes care to bitcast
702/// the value to an unsigned int first for Kernels.707/// the value to an unsigned int first for Kernels.
703fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {708fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
704 const zcu = cg.pt.zcu;709 const zcu = cg.module.zcu;
710 const target = cg.module.zcu.getTarget();
705 const scalar_ty = ty.scalarType(zcu);711 const scalar_ty = ty.scalarType(zcu);
706 const int_info = scalar_ty.intInfo(zcu);712 const int_info = scalar_ty.intInfo(zcu);
707 // Use backing bits so that negatives are sign extended713 // Use backing bits so that negatives are sign extended
...@@ -726,7 +732,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {...@@ -726,7 +732,7 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id {
726 });732 });
727 }733 }
728734
729 const final_value: spec.LiteralContextDependentNumber = switch (cg.module.target.os.tag) {735 const final_value: spec.LiteralContextDependentNumber = switch (target.os.tag) {
730 .opencl, .amdhsa => blk: {736 .opencl, .amdhsa => blk: {
731 const value64: u64 = switch (signedness) {737 const value64: u64 = switch (signedness) {
732 .signed => @bitCast(@as(i64, @intCast(value))),738 .signed => @bitCast(@as(i64, @intCast(value))),
...@@ -773,7 +779,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const...@@ -773,7 +779,7 @@ pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const
773/// ty must be an aggregate type.779/// ty must be an aggregate type.
774fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {780fn constructCompositeSplat(cg: *CodeGen, ty: Type, constituent: Id) !Id {
775 const gpa = cg.module.gpa;781 const gpa = cg.module.gpa;
776 const zcu = cg.pt.zcu;782 const zcu = cg.module.zcu;
777 const n: usize = @intCast(ty.arrayLen(zcu));783 const n: usize = @intCast(ty.arrayLen(zcu));
778784
779 const constituents = try gpa.alloc(Id, n);785 const constituents = try gpa.alloc(Id, n);
...@@ -801,8 +807,8 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -801,8 +807,8 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
801 }807 }
802808
803 const pt = cg.pt;809 const pt = cg.pt;
804 const zcu = pt.zcu;810 const zcu = cg.module.zcu;
805 const target = cg.module.target;811 const target = cg.module.zcu.getTarget();
806 const result_ty_id = try cg.resolveType(ty, repr);812 const result_ty_id = try cg.resolveType(ty, repr);
807 const ip = &zcu.intern_pool;813 const ip = &zcu.intern_pool;
808814
...@@ -874,39 +880,35 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -874,39 +880,35 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
874 .error_union => |error_union| {880 .error_union => |error_union| {
875 // TODO: Error unions may be constructed with constant instructions if the payload type881 // TODO: Error unions may be constructed with constant instructions if the payload type
876 // allows it. For now, just generate it here regardless.882 // allows it. For now, just generate it here regardless.
877 const err_int_ty = try pt.errorIntType();883 const err_ty = ty.errorUnionSet(zcu);
878 const err_ty = switch (error_union.val) {
879 .err_name => ty.errorUnionSet(zcu),
880 .payload => err_int_ty,
881 };
882 const err_val = switch (error_union.val) {
883 .err_name => |err_name| Value.fromInterned(try pt.intern(.{ .err = .{
884 .ty = ty.errorUnionSet(zcu).toIntern(),
885 .name = err_name,
886 } })),
887 .payload => try pt.intValue(err_int_ty, 0),
888 };
889 const payload_ty = ty.errorUnionPayload(zcu);884 const payload_ty = ty.errorUnionPayload(zcu);
885 const err_val_id = switch (error_union.val) {
886 .err_name => |err_name| try cg.constInt(
887 err_ty,
888 try pt.getErrorValue(err_name),
889 ),
890 .payload => try cg.constInt(err_ty, 0),
891 };
890 const eu_layout = cg.errorUnionLayout(payload_ty);892 const eu_layout = cg.errorUnionLayout(payload_ty);
891 if (!eu_layout.payload_has_bits) {893 if (!eu_layout.payload_has_bits) {
892 // We use the error type directly as the type.894 // We use the error type directly as the type.
893 break :cache try cg.constant(err_ty, err_val, .indirect);895 break :cache err_val_id;
894 }896 }
895897
896 const payload_val: Value = .fromInterned(switch (error_union.val) {898 const payload_val_id = switch (error_union.val) {
897 .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }),899 .err_name => try cg.constant(payload_ty, .undef, .indirect),
898 .payload => |payload| payload,900 .payload => |p| try cg.constant(payload_ty, .fromInterned(p), .indirect),
899 });901 };
900902
901 var constituents: [2]Id = undefined;903 var constituents: [2]Id = undefined;
902 var types: [2]Type = undefined;904 var types: [2]Type = undefined;
903 if (eu_layout.error_first) {905 if (eu_layout.error_first) {
904 constituents[0] = try cg.constant(err_ty, err_val, .indirect);906 constituents[0] = err_val_id;
905 constituents[1] = try cg.constant(payload_ty, payload_val, .indirect);907 constituents[1] = payload_val_id;
906 types = .{ err_ty, payload_ty };908 types = .{ err_ty, payload_ty };
907 } else {909 } else {
908 constituents[0] = try cg.constant(payload_ty, payload_val, .indirect);910 constituents[0] = payload_val_id;
909 constituents[1] = try cg.constant(err_ty, err_val, .indirect);911 constituents[1] = err_val_id;
910 types = .{ payload_ty, err_ty };912 types = .{ payload_ty, err_ty };
911 }913 }
912914
...@@ -1055,10 +1057,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {...@@ -1055,10 +1057,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
10551057
1056fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {1058fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
1057 const pt = cg.pt;1059 const pt = cg.pt;
1060 const zcu = cg.module.zcu;
1058 const gpa = cg.module.gpa;1061 const gpa = cg.module.gpa;
10591062
1060 if (ptr_val.isUndef(pt.zcu)) {1063 if (ptr_val.isUndef(zcu)) {
1061 const result_ty = ptr_val.typeOf(pt.zcu);1064 const result_ty = ptr_val.typeOf(zcu);
1062 const result_ty_id = try cg.resolveType(result_ty, .direct);1065 const result_ty_id = try cg.resolveType(result_ty, .direct);
1063 return cg.module.constUndef(result_ty_id);1066 return cg.module.constUndef(result_ty_id);
1064 }1067 }
...@@ -1072,7 +1075,7 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {...@@ -1072,7 +1075,7 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
10721075
1073fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {1076fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id {
1074 const pt = cg.pt;1077 const pt = cg.pt;
1075 const zcu = pt.zcu;1078 const zcu = cg.module.zcu;
1076 switch (derivation) {1079 switch (derivation) {
1077 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,1080 .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
1078 .int => |int| {1081 .int => |int| {
...@@ -1152,8 +1155,7 @@ fn constantUavRef(...@@ -1152,8 +1155,7 @@ fn constantUavRef(
1152) !Id {1155) !Id {
1153 // TODO: Merge this function with constantDeclRef.1156 // TODO: Merge this function with constantDeclRef.
11541157
1155 const pt = cg.pt;1158 const zcu = cg.module.zcu;
1156 const zcu = pt.zcu;
1157 const ip = &zcu.intern_pool;1159 const ip = &zcu.intern_pool;
1158 const ty_id = try cg.resolveType(ty, .direct);1160 const ty_id = try cg.resolveType(ty, .direct);
1159 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));1161 const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
...@@ -1190,8 +1192,7 @@ fn constantUavRef(...@@ -1190,8 +1192,7 @@ fn constantUavRef(
1190}1192}
11911193
1192fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {1194fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
1193 const pt = cg.pt;1195 const zcu = cg.module.zcu;
1194 const zcu = pt.zcu;
1195 const ip = &zcu.intern_pool;1196 const ip = &zcu.intern_pool;
1196 const ty_id = try cg.resolveType(ty, .direct);1197 const ty_id = try cg.resolveType(ty, .direct);
1197 const nav = ip.getNav(nav_index);1198 const nav = ip.getNav(nav_index);
...@@ -1264,6 +1265,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {...@@ -1264,6 +1265,8 @@ fn resolveTypeName(cg: *CodeGen, ty: Type) ![]const u8 {
1264/// actual operations (as well as store) a Zig type of a particular number of bits. To create1265/// actual operations (as well as store) a Zig type of a particular number of bits. To create
1265/// a type with an exact size, use Module.intType.1266/// a type with an exact size, use Module.intType.
1266fn intType(cg: *CodeGen, signedness: std.builtin.Signedness, bits: u16) !Id {1267fn intType(cg: *CodeGen, signedness: std.builtin.Signedness, bits: u16) !Id {
1268 const target = cg.module.zcu.getTarget();
1269
1267 const backing_bits, const big_int = cg.backingIntBits(bits);1270 const backing_bits, const big_int = cg.backingIntBits(bits);
1268 if (big_int) {1271 if (big_int) {
1269 if (backing_bits > 64) {1272 if (backing_bits > 64) {
...@@ -1273,7 +1276,7 @@ fn intType(cg: *CodeGen, signedness: std.builtin.Signedness, bits: u16) !Id {...@@ -1273,7 +1276,7 @@ fn intType(cg: *CodeGen, signedness: std.builtin.Signedness, bits: u16) !Id {
1273 return cg.arrayType(backing_bits / big_int_bits, int_ty);1276 return cg.arrayType(backing_bits / big_int_bits, int_ty);
1274 }1277 }
12751278
1276 return switch (cg.module.target.os.tag) {1279 return switch (target.os.tag) {
1277 // Kernel only supports unsigned ints.1280 // Kernel only supports unsigned ints.
1278 .opencl, .amdhsa => return cg.module.intType(.unsigned, backing_bits),1281 .opencl, .amdhsa => return cg.module.intType(.unsigned, backing_bits),
1279 else => cg.module.intType(signedness, backing_bits),1282 else => cg.module.intType(signedness, backing_bits),
...@@ -1287,9 +1290,12 @@ fn arrayType(cg: *CodeGen, len: u32, child_ty: Id) !Id {...@@ -1287,9 +1290,12 @@ fn arrayType(cg: *CodeGen, len: u32, child_ty: Id) !Id {
12871290
1288fn ptrType(cg: *CodeGen, child_ty: Type, storage_class: StorageClass, child_repr: Repr) !Id {1291fn ptrType(cg: *CodeGen, child_ty: Type, storage_class: StorageClass, child_repr: Repr) !Id {
1289 const gpa = cg.module.gpa;1292 const gpa = cg.module.gpa;
1290 const zcu = cg.pt.zcu;1293 const zcu = cg.module.zcu;
1291 const ip = &zcu.intern_pool;1294 const ip = &zcu.intern_pool;
1292 const key = .{ child_ty.toIntern(), storage_class, child_repr };1295 const target = cg.module.zcu.getTarget();
1296
1297 const child_ty_id = try cg.resolveType(child_ty, child_repr);
1298 const key = .{ child_ty_id, storage_class };
1293 const entry = try cg.module.ptr_types.getOrPut(gpa, key);1299 const entry = try cg.module.ptr_types.getOrPut(gpa, key);
1294 if (entry.found_existing) {1300 if (entry.found_existing) {
1295 const fwd_id = entry.value_ptr.ty_id;1301 const fwd_id = entry.value_ptr.ty_id;
...@@ -1309,9 +1315,7 @@ fn ptrType(cg: *CodeGen, child_ty: Type, storage_class: StorageClass, child_repr...@@ -1309,9 +1315,7 @@ fn ptrType(cg: *CodeGen, child_ty: Type, storage_class: StorageClass, child_repr
1309 .fwd_emitted = false,1315 .fwd_emitted = false,
1310 };1316 };
13111317
1312 const child_ty_id = try cg.resolveType(child_ty, child_repr);1318 switch (target.os.tag) {
1313
1314 switch (cg.module.target.os.tag) {
1315 .vulkan, .opengl => {1319 .vulkan, .opengl => {
1316 if (child_ty.zigTypeTag(zcu) == .@"struct") {1320 if (child_ty.zigTypeTag(zcu) == .@"struct") {
1317 switch (storage_class) {1321 switch (storage_class) {
...@@ -1374,7 +1378,7 @@ fn functionType(cg: *CodeGen, return_ty: Type, param_types: []const Type) !Id {...@@ -1374,7 +1378,7 @@ fn functionType(cg: *CodeGen, return_ty: Type, param_types: []const Type) !Id {
1374/// If any of the fields' size is 0, it will be omitted.1378/// If any of the fields' size is 0, it will be omitted.
1375fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {1379fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
1376 const gpa = cg.module.gpa;1380 const gpa = cg.module.gpa;
1377 const zcu = cg.pt.zcu;1381 const zcu = cg.module.zcu;
1378 const ip = &zcu.intern_pool;1382 const ip = &zcu.intern_pool;
1379 const union_obj = zcu.typeToUnion(ty).?;1383 const union_obj = zcu.typeToUnion(ty).?;
13801384
...@@ -1417,8 +1421,12 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {...@@ -1417,8 +1421,12 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
1417 member_names[layout.padding_index] = "(padding)";1421 member_names[layout.padding_index] = "(padding)";
1418 }1422 }
14191423
1420 const result_id = cg.module.allocId();1424 const result_id = try cg.module.structType(
1421 try cg.module.structType(result_id, member_types[0..layout.total_fields], member_names[0..layout.total_fields]);1425 member_types[0..layout.total_fields],
1426 member_names[0..layout.total_fields],
1427 null,
1428 .none,
1429 );
14221430
1423 const type_name = try cg.resolveTypeName(ty);1431 const type_name = try cg.resolveTypeName(ty);
1424 defer gpa.free(type_name);1432 defer gpa.free(type_name);
...@@ -1428,7 +1436,7 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {...@@ -1428,7 +1436,7 @@ fn resolveUnionType(cg: *CodeGen, ty: Type) !Id {
1428}1436}
14291437
1430fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {1438fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1431 const zcu = cg.pt.zcu;1439 const zcu = cg.module.zcu;
1432 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1440 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1433 // If the return type is an error set or an error union, then we make this1441 // If the return type is an error set or an error union, then we make this
1434 // anyerror return type instead, so that it can be coerced into a function1442 // anyerror return type instead, so that it can be coerced into a function
...@@ -1443,28 +1451,14 @@ fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {...@@ -1443,28 +1451,14 @@ fn resolveFnReturnType(cg: *CodeGen, ret_ty: Type) !Id {
1443 return try cg.resolveType(ret_ty, .direct);1451 return try cg.resolveType(ret_ty, .direct);
1444}1452}
14451453
1446/// Turn a Zig type into a SPIR-V Type, and return a reference to it.1454fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1447fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) !Id {
1448 const gpa = cg.module.gpa;
1449
1450 if (cg.module.intern_map.get(.{ ty.toIntern(), repr })) |id| {
1451 return id;
1452 }
1453
1454 const id = try cg.resolveTypeInner(ty, repr);
1455 try cg.module.intern_map.put(gpa, .{ ty.toIntern(), repr }, id);
1456 return id;
1457}
1458
1459fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1460 const gpa = cg.module.gpa;1455 const gpa = cg.module.gpa;
1461 const pt = cg.pt;1456 const pt = cg.pt;
1462 const zcu = pt.zcu;1457 const zcu = cg.module.zcu;
1463 const ip = &zcu.intern_pool;1458 const ip = &zcu.intern_pool;
1464 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});1459 const target = cg.module.zcu.getTarget();
1465 const target = cg.module.target;
14661460
1467 const section = &cg.module.sections.globals;1461 log.debug("resolveType: ty = {f}", .{ty.fmt(pt)});
14681462
1469 switch (ty.zigTypeTag(zcu)) {1463 switch (ty.zigTypeTag(zcu)) {
1470 .noreturn => {1464 .noreturn => {
...@@ -1472,18 +1466,8 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1472,18 +1466,8 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1472 return try cg.module.voidType();1466 return try cg.module.voidType();
1473 },1467 },
1474 .void => switch (repr) {1468 .void => switch (repr) {
1475 .direct => {1469 .direct => return try cg.module.voidType(),
1476 return try cg.module.voidType();1470 .indirect => return try cg.module.opaqueType("void"),
1477 },
1478 // Pointers to void
1479 .indirect => {
1480 const result_id = cg.module.allocId();
1481 try section.emit(cg.module.gpa, .OpTypeOpaque, .{
1482 .id_result = result_id,
1483 .literal_string = "void",
1484 });
1485 return result_id;
1486 },
1487 },1471 },
1488 .bool => switch (repr) {1472 .bool => switch (repr) {
1489 .direct => return try cg.module.boolType(),1473 .direct => return try cg.module.boolType(),
...@@ -1492,36 +1476,26 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1492,36 +1476,26 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1492 .int => {1476 .int => {
1493 const int_info = ty.intInfo(zcu);1477 const int_info = ty.intInfo(zcu);
1494 if (int_info.bits == 0) {1478 if (int_info.bits == 0) {
1495 // Some times, the backend will be asked to generate a pointer to i0. OpTypeInt
1496 // with 0 bits is invalid, so return an opaque type in this case.
1497 assert(repr == .indirect);1479 assert(repr == .indirect);
1498 const result_id = cg.module.allocId();1480 return try cg.module.opaqueType("u0");
1499 try section.emit(cg.module.gpa, .OpTypeOpaque, .{
1500 .id_result = result_id,
1501 .literal_string = "u0",
1502 });
1503 return result_id;
1504 }1481 }
1505 return try cg.intType(int_info.signedness, int_info.bits);1482 return try cg.intType(int_info.signedness, int_info.bits);
1506 },1483 },
1507 .@"enum" => {1484 .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr),
1508 const tag_ty = ty.intTagType(zcu);
1509 return try cg.resolveType(tag_ty, repr);
1510 },
1511 .float => {1485 .float => {
1512 // We can (and want) not really emulate floating points with other floating point types like with the integer types,
1513 // so if the float is not supported, just return an error.
1514 const bits = ty.floatBits(target);1486 const bits = ty.floatBits(target);
1515 const supported = switch (bits) {1487 const supported = switch (bits) {
1516 16 => cg.module.target.cpu.has(.spirv, .float16),1488 16 => target.cpu.has(.spirv, .float16),
1517 // 32-bit floats are always supported (see spec, 2.16.1, Data rules).
1518 32 => true,1489 32 => true,
1519 64 => cg.module.target.cpu.has(.spirv, .float64),1490 64 => target.cpu.has(.spirv, .float64),
1520 else => false,1491 else => false,
1521 };1492 };
15221493
1523 if (!supported) {1494 if (!supported) {
1524 return cg.fail("Floating point width of {} bits is not supported for the current SPIR-V feature set", .{bits});1495 return cg.fail(
1496 "floating point width of {} bits is not supported for the current SPIR-V feature set",
1497 .{bits},
1498 );
1525 }1499 }
15261500
1527 return try cg.module.floatType(bits);1501 return try cg.module.floatType(bits);
...@@ -1534,36 +1508,27 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1534,36 +1508,27 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1534 };1508 };
15351509
1536 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1510 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1537 // The size of the array would be 0, but that is not allowed in SPIR-V.
1538 // This path can be reached when the backend is asked to generate a pointer to
1539 // an array of some zero-bit type. This should always be an indirect path.
1540 assert(repr == .indirect);1511 assert(repr == .indirect);
15411512 return try cg.module.opaqueType("zero-sized-array");
1542 // We cannot use the child type here, so just use an opaque type.
1543 const result_id = cg.module.allocId();
1544 try section.emit(cg.module.gpa, .OpTypeOpaque, .{
1545 .id_result = result_id,
1546 .literal_string = "zero-sized array",
1547 });
1548 return result_id;
1549 } else if (total_len == 0) {1513 } else if (total_len == 0) {
1550 // The size of the array would be 0, but that is not allowed in SPIR-V.1514 // The size of the array would be 0, but that is not allowed in SPIR-V.
1551 // This path can be reached for example when there is a slicing of a pointer1515 // This path can be reached for example when there is a slicing of a pointer
1552 // that produces a zero-length array. In all cases where this type can be generated,1516 // that produces a zero-length array. In all cases where this type can be generated,
1553 // this should be an indirect path.1517 // this should be an indirect path.
1554 assert(repr == .indirect);1518 assert(repr == .indirect);
1555
1556 // In this case, we have an array of a non-zero sized type. In this case,1519 // In this case, we have an array of a non-zero sized type. In this case,
1557 // generate an array of 1 element instead, so that ptr_elem_ptr instructions1520 // generate an array of 1 element instead, so that ptr_elem_ptr instructions
1558 // can be lowered to ptrAccessChain instead of manually performing the math.1521 // can be lowered to ptrAccessChain instead of manually performing the math.
1559 return try cg.arrayType(1, elem_ty_id);1522 return try cg.arrayType(1, elem_ty_id);
1560 } else {1523 } else {
1561 const result_id = try cg.arrayType(total_len, elem_ty_id);1524 const result_id = try cg.arrayType(total_len, elem_ty_id);
1562 switch (cg.module.target.os.tag) {1525 switch (target.os.tag) {
1563 .vulkan, .opengl => {1526 .vulkan, .opengl => {
1564 try cg.module.decorate(result_id, .{ .array_stride = .{1527 try cg.module.decorate(result_id, .{
1565 .array_stride = @intCast(elem_ty.abiSize(zcu)),1528 .array_stride = .{
1566 } });1529 .array_stride = @intCast(elem_ty.abiSize(zcu)),
1530 },
1531 });
1567 },1532 },
1568 else => {},1533 else => {},
1569 }1534 }
...@@ -1574,18 +1539,15 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1574,18 +1539,15 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1574 const elem_ty = ty.childType(zcu);1539 const elem_ty = ty.childType(zcu);
1575 const elem_ty_id = try cg.resolveType(elem_ty, repr);1540 const elem_ty_id = try cg.resolveType(elem_ty, repr);
1576 const len = ty.vectorLen(zcu);1541 const len = ty.vectorLen(zcu);
15771542 if (cg.isSpvVector(ty)) return try cg.module.vectorType(len, elem_ty_id);
1578 if (cg.isSpvVector(ty)) {1543 return try cg.arrayType(len, elem_ty_id);
1579 return try cg.module.vectorType(len, elem_ty_id);
1580 } else {
1581 return try cg.arrayType(len, elem_ty_id);
1582 }
1583 },1544 },
1584 .@"fn" => switch (repr) {1545 .@"fn" => switch (repr) {
1585 .direct => {1546 .direct => {
1586 const fn_info = zcu.typeToFunc(ty).?;1547 const fn_info = zcu.typeToFunc(ty).?;
15871548
1588 comptime assert(zig_call_abi_ver == 3);1549 comptime assert(zig_call_abi_ver == 3);
1550 assert(!fn_info.is_var_args);
1589 switch (fn_info.cc) {1551 switch (fn_info.cc) {
1590 .auto,1552 .auto,
1591 .spirv_kernel,1553 .spirv_kernel,
...@@ -1596,11 +1558,7 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1596,11 +1558,7 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1596 else => unreachable,1558 else => unreachable,
1597 }1559 }
15981560
1599 // Guaranteed by callConvSupportsVarArgs, there are no SPIR-V CCs which support1561 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));
1600 // varargs.
1601 assert(!fn_info.is_var_args);
1602
1603 // Note: Logic is different from functionType().
1604 const param_ty_ids = try gpa.alloc(Id, fn_info.param_types.len);1562 const param_ty_ids = try gpa.alloc(Id, fn_info.param_types.len);
1605 defer gpa.free(param_ty_ids);1563 defer gpa.free(param_ty_ids);
1606 var param_index: usize = 0;1564 var param_index: usize = 0;
...@@ -1612,16 +1570,7 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1612,16 +1570,7 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1612 param_index += 1;1570 param_index += 1;
1613 }1571 }
16141572
1615 const return_ty_id = try cg.resolveFnReturnType(.fromInterned(fn_info.return_type));1573 return try cg.module.functionType(return_ty_id, param_ty_ids[0..param_index]);
1616
1617 const result_id = cg.module.allocId();
1618 try section.emit(cg.module.gpa, .OpTypeFunction, .{
1619 .id_result = result_id,
1620 .return_type = return_ty_id,
1621 .id_ref_2 = param_ty_ids[0..param_index],
1622 });
1623
1624 return result_id;
1625 },1574 },
1626 .indirect => {1575 .indirect => {
1627 // TODO: Represent function pointers properly.1576 // TODO: Represent function pointers properly.
...@@ -1641,13 +1590,12 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1641,13 +1590,12 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1641 }1590 }
16421591
1643 const size_ty_id = try cg.resolveType(.usize, .direct);1592 const size_ty_id = try cg.resolveType(.usize, .direct);
1644 const result_id = cg.module.allocId();1593 return try cg.module.structType(
1645 try cg.module.structType(
1646 result_id,
1647 &.{ ptr_ty_id, size_ty_id },1594 &.{ ptr_ty_id, size_ty_id },
1648 &.{ "ptr", "len" },1595 &.{ "ptr", "len" },
1596 null,
1597 .none,
1649 );1598 );
1650 return result_id;
1651 },1599 },
1652 .@"struct" => {1600 .@"struct" => {
1653 const struct_type = switch (ip.indexToKey(ty.toIntern())) {1601 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
...@@ -1663,13 +1611,15 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1663,13 +1611,15 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1663 member_index += 1;1611 member_index += 1;
1664 }1612 }
16651613
1666 const result_id = cg.module.allocId();1614 const result_id = try cg.module.structType(
1667 try cg.module.structType(result_id, member_types[0..member_index], null);1615 member_types[0..member_index],
16681616 null,
1617 null,
1618 .none,
1619 );
1669 const type_name = try cg.resolveTypeName(ty);1620 const type_name = try cg.resolveTypeName(ty);
1670 defer gpa.free(type_name);1621 defer gpa.free(type_name);
1671 try cg.module.debugName(result_id, type_name);1622 try cg.module.debugName(result_id, type_name);
1672
1673 return result_id;1623 return result_id;
1674 },1624 },
1675 .struct_type => ip.loadStructType(ty.toIntern()),1625 .struct_type => ip.loadStructType(ty.toIntern()),
...@@ -1686,34 +1636,27 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1686,34 +1636,27 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1686 var member_names = std.ArrayList([]const u8).init(gpa);1636 var member_names = std.ArrayList([]const u8).init(gpa);
1687 defer member_names.deinit();1637 defer member_names.deinit();
16881638
1689 var index: u32 = 0;1639 var member_offsets = std.ArrayList(u32).init(gpa);
1640 defer member_offsets.deinit();
1641
1690 var it = struct_type.iterateRuntimeOrder(ip);1642 var it = struct_type.iterateRuntimeOrder(ip);
1691 const result_id = cg.module.allocId();
1692 while (it.next()) |field_index| {1643 while (it.next()) |field_index| {
1693 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);1644 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
1694 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1645 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1695 // This is a zero-bit field - we only needed it for the alignment.
1696 continue;
1697 }
1698
1699 switch (cg.module.target.os.tag) {
1700 .vulkan, .opengl => {
1701 try cg.module.decorateMember(result_id, index, .{ .offset = .{
1702 .byte_offset = @intCast(ty.structFieldOffset(field_index, zcu)),
1703 } });
1704 },
1705 else => {},
1706 }
17071646
1708 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse1647 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
1709 try ip.getOrPutStringFmt(zcu.gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);1648 try ip.getOrPutStringFmt(zcu.gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls);
1710 try member_types.append(try cg.resolveType(field_ty, .indirect));1649 try member_types.append(try cg.resolveType(field_ty, .indirect));
1711 try member_names.append(field_name.toSlice(ip));1650 try member_names.append(field_name.toSlice(ip));
17121651 try member_offsets.append(@intCast(ty.structFieldOffset(field_index, zcu)));
1713 index += 1;
1714 }1652 }
17151653
1716 try cg.module.structType(result_id, member_types.items, member_names.items);1654 const result_id = try cg.module.structType(
1655 member_types.items,
1656 member_names.items,
1657 member_offsets.items,
1658 ty.toIntern(),
1659 );
17171660
1718 const type_name = try cg.resolveTypeName(ty);1661 const type_name = try cg.resolveTypeName(ty);
1719 defer gpa.free(type_name);1662 defer gpa.free(type_name);
...@@ -1738,13 +1681,12 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1738,13 +1681,12 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
17381681
1739 const bool_ty_id = try cg.resolveType(.bool, .indirect);1682 const bool_ty_id = try cg.resolveType(.bool, .indirect);
17401683
1741 const result_id = cg.module.allocId();1684 return try cg.module.structType(
1742 try cg.module.structType(
1743 result_id,
1744 &.{ payload_ty_id, bool_ty_id },1685 &.{ payload_ty_id, bool_ty_id },
1745 &.{ "payload", "valid" },1686 &.{ "payload", "valid" },
1687 null,
1688 .none,
1746 );1689 );
1747 return result_id;
1748 },1690 },
1749 .@"union" => return try cg.resolveUnionType(ty),1691 .@"union" => return try cg.resolveUnionType(ty),
1750 .error_set => {1692 .error_set => {
...@@ -1753,7 +1695,8 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1753,7 +1695,8 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1753 },1695 },
1754 .error_union => {1696 .error_union => {
1755 const payload_ty = ty.errorUnionPayload(zcu);1697 const payload_ty = ty.errorUnionPayload(zcu);
1756 const error_ty_id = try cg.resolveType(.anyerror, .indirect);1698 const err_ty = ty.errorUnionSet(zcu);
1699 const error_ty_id = try cg.resolveType(err_ty, .indirect);
17571700
1758 const eu_layout = cg.errorUnionLayout(payload_ty);1701 const eu_layout = cg.errorUnionLayout(payload_ty);
1759 if (!eu_layout.payload_has_bits) {1702 if (!eu_layout.payload_has_bits) {
...@@ -1776,20 +1719,12 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1776,20 +1719,12 @@ fn resolveTypeInner(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1776 // TODO: ABI padding?1719 // TODO: ABI padding?
1777 }1720 }
17781721
1779 const result_id = cg.module.allocId();1722 return try cg.module.structType(&member_types, &member_names, null, .none);
1780 try cg.module.structType(result_id, &member_types, &member_names);
1781 return result_id;
1782 },1723 },
1783 .@"opaque" => {1724 .@"opaque" => {
1784 const type_name = try cg.resolveTypeName(ty);1725 const type_name = try cg.resolveTypeName(ty);
1785 defer gpa.free(type_name);1726 defer gpa.free(type_name);
17861727 return try cg.module.opaqueType(type_name);
1787 const result_id = cg.module.allocId();
1788 try section.emit(cg.module.gpa, .OpTypeOpaque, .{
1789 .id_result = result_id,
1790 .literal_string = type_name,
1791 });
1792 return result_id;
1793 },1728 },
17941729
1795 .null,1730 .null,
...@@ -1820,8 +1755,7 @@ const ErrorUnionLayout = struct {...@@ -1820,8 +1755,7 @@ const ErrorUnionLayout = struct {
1820};1755};
18211756
1822fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {1757fn errorUnionLayout(cg: *CodeGen, payload_ty: Type) ErrorUnionLayout {
1823 const pt = cg.pt;1758 const zcu = cg.module.zcu;
1824 const zcu = pt.zcu;
18251759
1826 const error_align = Type.abiAlignment(.anyerror, zcu);1760 const error_align = Type.abiAlignment(.anyerror, zcu);
1827 const payload_align = payload_ty.abiAlignment(zcu);1761 const payload_align = payload_ty.abiAlignment(zcu);
...@@ -1852,8 +1786,7 @@ const UnionLayout = struct {...@@ -1852,8 +1786,7 @@ const UnionLayout = struct {
1852};1786};
18531787
1854fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {1788fn unionLayout(cg: *CodeGen, ty: Type) UnionLayout {
1855 const pt = cg.pt;1789 const zcu = cg.module.zcu;
1856 const zcu = pt.zcu;
1857 const ip = &zcu.intern_pool;1790 const ip = &zcu.intern_pool;
1858 const layout = ty.unionGetLayout(zcu);1791 const layout = ty.unionGetLayout(zcu);
1859 const union_obj = zcu.typeToUnion(ty).?;1792 const union_obj = zcu.typeToUnion(ty).?;
...@@ -1944,7 +1877,7 @@ const Temporary = struct {...@@ -1944,7 +1877,7 @@ const Temporary = struct {
19441877
1945 fn materialize(temp: Temporary, cg: *CodeGen) !Id {1878 fn materialize(temp: Temporary, cg: *CodeGen) !Id {
1946 const gpa = cg.module.gpa;1879 const gpa = cg.module.gpa;
1947 const zcu = cg.pt.zcu;1880 const zcu = cg.module.zcu;
1948 switch (temp.value) {1881 switch (temp.value) {
1949 .singleton => |id| return id,1882 .singleton => |id| return id,
1950 .exploded_vector => |range| {1883 .exploded_vector => |range| {
...@@ -1975,7 +1908,7 @@ const Temporary = struct {...@@ -1975,7 +1908,7 @@ const Temporary = struct {
1975 /// 'Explode' a temporary into separate elements. This turns a vector1908 /// 'Explode' a temporary into separate elements. This turns a vector
1976 /// into a bag of elements.1909 /// into a bag of elements.
1977 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {1910 fn explode(temp: Temporary, cg: *CodeGen) !IdRange {
1978 const zcu = cg.pt.zcu;1911 const zcu = cg.module.zcu;
19791912
1980 // If the value is a scalar, then this is a no-op.1913 // If the value is a scalar, then this is a no-op.
1981 if (!temp.ty.isVector(zcu)) {1914 if (!temp.ty.isVector(zcu)) {
...@@ -2029,7 +1962,7 @@ const Vectorization = union(enum) {...@@ -2029,7 +1962,7 @@ const Vectorization = union(enum) {
20291962
2030 /// Derive a vectorization from a particular type1963 /// Derive a vectorization from a particular type
2031 fn fromType(ty: Type, cg: *CodeGen) Vectorization {1964 fn fromType(ty: Type, cg: *CodeGen) Vectorization {
2032 const zcu = cg.pt.zcu;1965 const zcu = cg.module.zcu;
2033 if (!ty.isVector(zcu)) return .scalar;1966 if (!ty.isVector(zcu)) return .scalar;
2034 return .{ .unrolled = ty.vectorLen(zcu) };1967 return .{ .unrolled = ty.vectorLen(zcu) };
2035 }1968 }
...@@ -2063,7 +1996,8 @@ const Vectorization = union(enum) {...@@ -2063,7 +1996,8 @@ const Vectorization = union(enum) {
2063 /// `ty` may be a scalar or vector, it doesn't matter.1996 /// `ty` may be a scalar or vector, it doesn't matter.
2064 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {1997 fn resultType(vec: Vectorization, cg: *CodeGen, ty: Type) !Type {
2065 const pt = cg.pt;1998 const pt = cg.pt;
2066 const scalar_ty = ty.scalarType(pt.zcu);1999 const zcu = cg.module.zcu;
2000 const scalar_ty = ty.scalarType(zcu);
2067 return switch (vec) {2001 return switch (vec) {
2068 .scalar => scalar_ty,2002 .scalar => scalar_ty,
2069 .unrolled => |n| try pt.vectorType(.{ .len = n, .child = scalar_ty.toIntern() }),2003 .unrolled => |n| try pt.vectorType(.{ .len = n, .child = scalar_ty.toIntern() }),
...@@ -2074,8 +2008,8 @@ const Vectorization = union(enum) {...@@ -2074,8 +2008,8 @@ const Vectorization = union(enum) {
2074 /// this setup, and returns a new type that holds the relevant information on how to access2008 /// this setup, and returns a new type that holds the relevant information on how to access
2075 /// elements of the input.2009 /// elements of the input.
2076 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {2010 fn prepare(vec: Vectorization, cg: *CodeGen, tmp: Temporary) !PreparedOperand {
2077 const pt = cg.pt;2011 const zcu = cg.module.zcu;
2078 const is_vector = tmp.ty.isVector(pt.zcu);2012 const is_vector = tmp.ty.isVector(zcu);
2079 const value: PreparedOperand.Value = switch (tmp.value) {2013 const value: PreparedOperand.Value = switch (tmp.value) {
2080 .singleton => |id| switch (vec) {2014 .singleton => |id| switch (vec) {
2081 .scalar => blk: {2015 .scalar => blk: {
...@@ -2174,7 +2108,7 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {...@@ -2174,7 +2108,7 @@ fn vectorization(cg: *CodeGen, args: anytype) Vectorization {
2174/// This function builds an OpSConvert of OpUConvert depending on the2108/// This function builds an OpSConvert of OpUConvert depending on the
2175/// signedness of the types.2109/// signedness of the types.
2176fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {2110fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
2177 const zcu = cg.pt.zcu;2111 const zcu = cg.module.zcu;
21782112
2179 const dst_ty_id = try cg.resolveType(dst_ty.scalarType(zcu), .direct);2113 const dst_ty_id = try cg.resolveType(dst_ty.scalarType(zcu), .direct);
2180 const src_ty_id = try cg.resolveType(src.ty.scalarType(zcu), .direct);2114 const src_ty_id = try cg.resolveType(src.ty.scalarType(zcu), .direct);
...@@ -2217,8 +2151,8 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {...@@ -2217,8 +2151,8 @@ fn buildConvert(cg: *CodeGen, dst_ty: Type, src: Temporary) !Temporary {
2217}2151}
22182152
2219fn buildFma(cg: *CodeGen, a: Temporary, b: Temporary, c: Temporary) !Temporary {2153fn buildFma(cg: *CodeGen, a: Temporary, b: Temporary, c: Temporary) !Temporary {
2220 const zcu = cg.pt.zcu;2154 const zcu = cg.module.zcu;
2221 const target = cg.module.target;2155 const target = cg.module.zcu.getTarget();
22222156
2223 const v = cg.vectorization(.{ a, b, c });2157 const v = cg.vectorization(.{ a, b, c });
2224 const ops = v.components();2158 const ops = v.components();
...@@ -2258,7 +2192,7 @@ fn buildFma(cg: *CodeGen, a: Temporary, b: Temporary, c: Temporary) !Temporary {...@@ -2258,7 +2192,7 @@ fn buildFma(cg: *CodeGen, a: Temporary, b: Temporary, c: Temporary) !Temporary {
2258}2192}
22592193
2260fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary {2194fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporary) !Temporary {
2261 const zcu = cg.pt.zcu;2195 const zcu = cg.module.zcu;
22622196
2263 const v = cg.vectorization(.{ condition, lhs, rhs });2197 const v = cg.vectorization(.{ condition, lhs, rhs });
2264 const ops = v.components();2198 const ops = v.components();
...@@ -2377,8 +2311,8 @@ const UnaryOp = enum {...@@ -2377,8 +2311,8 @@ const UnaryOp = enum {
2377};2311};
23782312
2379fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {2313fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary {
2380 const zcu = cg.pt.zcu;2314 const zcu = cg.module.zcu;
2381 const target = cg.module.target;2315 const target = cg.module.zcu.getTarget();
2382 const v = cg.vectorization(.{operand});2316 const v = cg.vectorization(.{operand});
2383 const ops = v.components();2317 const ops = v.components();
2384 const results = cg.module.allocIds(ops);2318 const results = cg.module.allocIds(ops);
...@@ -2497,8 +2431,8 @@ const BinaryOp = enum {...@@ -2497,8 +2431,8 @@ const BinaryOp = enum {
2497};2431};
24982432
2499fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temporary {2433fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temporary {
2500 const zcu = cg.pt.zcu;2434 const zcu = cg.module.zcu;
2501 const target = cg.module.target;2435 const target = cg.module.zcu.getTarget();
25022436
2503 const v = cg.vectorization(.{ lhs, rhs });2437 const v = cg.vectorization(.{ lhs, rhs });
2504 const ops = v.components();2438 const ops = v.components();
...@@ -2595,8 +2529,8 @@ fn buildWideMul(...@@ -2595,8 +2529,8 @@ fn buildWideMul(
2595 rhs: Temporary,2529 rhs: Temporary,
2596) !struct { Temporary, Temporary } {2530) !struct { Temporary, Temporary } {
2597 const pt = cg.pt;2531 const pt = cg.pt;
2598 const zcu = pt.zcu;2532 const zcu = cg.module.zcu;
2599 const target = cg.module.target;2533 const target = cg.module.zcu.getTarget();
2600 const ip = &zcu.intern_pool;2534 const ip = &zcu.intern_pool;
26012535
2602 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));2536 const v = lhs.vectorization(cg).unify(rhs.vectorization(cg));
...@@ -2718,8 +2652,8 @@ fn generateTestEntryPoint(...@@ -2718,8 +2652,8 @@ fn generateTestEntryPoint(
2718 test_id: Id,2652 test_id: Id,
2719) !void {2653) !void {
2720 const gpa = cg.module.gpa;2654 const gpa = cg.module.gpa;
2721 const zcu = cg.pt.zcu;2655 const zcu = cg.module.zcu;
2722 const target = cg.module.target;2656 const target = cg.module.zcu.getTarget();
27232657
2724 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);2658 const anyerror_ty_id = try cg.resolveType(.anyerror, .direct);
2725 const ptr_anyerror_ty = try cg.pt.ptrType(.{2659 const ptr_anyerror_ty = try cg.pt.ptrType(.{
...@@ -2762,8 +2696,12 @@ fn generateTestEntryPoint(...@@ -2762,8 +2696,12 @@ fn generateTestEntryPoint(
2762 const spv_err_decl_index = try cg.module.allocDecl(.global);2696 const spv_err_decl_index = try cg.module.allocDecl(.global);
2763 try cg.module.declareDeclDeps(spv_err_decl_index, &.{});2697 try cg.module.declareDeclDeps(spv_err_decl_index, &.{});
27642698
2765 const buffer_struct_ty_id = cg.module.allocId();2699 const buffer_struct_ty_id = try cg.module.structType(
2766 try cg.module.structType(buffer_struct_ty_id, &.{anyerror_ty_id}, &.{"error_out"});2700 &.{anyerror_ty_id},
2701 &.{"error_out"},
2702 null,
2703 .none,
2704 );
2767 try cg.module.decorate(buffer_struct_ty_id, .block);2705 try cg.module.decorate(buffer_struct_ty_id, .block);
2768 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });2706 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
27692707
...@@ -2871,14 +2809,14 @@ fn intFromBool2(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {...@@ -2871,14 +2809,14 @@ fn intFromBool2(cg: *CodeGen, value: Temporary, result_ty: Type) !Temporary {
2871/// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct).2809/// This converts the argument type from resolveType(ty, .indirect) to resolveType(ty, .direct).
2872fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {2810fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
2873 const pt = cg.pt;2811 const pt = cg.pt;
2874 const zcu = pt.zcu;2812 const zcu = cg.module.zcu;
2875 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {2813 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
2876 .bool => {2814 .bool => {
2877 const false_id = try cg.constBool(false, .indirect);2815 const false_id = try cg.constBool(false, .indirect);
2878 const operand_ty = blk: {2816 const operand_ty = blk: {
2879 if (!ty.isVector(pt.zcu)) break :blk Type.u1;2817 if (!ty.isVector(zcu)) break :blk Type.u1;
2880 break :blk try pt.vectorType(.{2818 break :blk try pt.vectorType(.{
2881 .len = ty.vectorLen(pt.zcu),2819 .len = ty.vectorLen(zcu),
2882 .child = .u1_type,2820 .child = .u1_type,
2883 });2821 });
2884 };2822 };
...@@ -2897,7 +2835,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {...@@ -2897,7 +2835,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
2897/// Convert representation from direct (in 'register) to direct (in memory)2835/// Convert representation from direct (in 'register) to direct (in memory)
2898/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).2836/// This converts the argument type from resolveType(ty, .direct) to resolveType(ty, .indirect).
2899fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {2837fn convertToIndirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id {
2900 const zcu = cg.pt.zcu;2838 const zcu = cg.module.zcu;
2901 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {2839 switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
2902 .bool => {2840 .bool => {
2903 const result = try cg.intFromBool(Temporary.init(ty, operand_id));2841 const result = try cg.intFromBool(Temporary.init(ty, operand_id));
...@@ -2940,7 +2878,7 @@ const MemoryOptions = struct {...@@ -2940,7 +2878,7 @@ const MemoryOptions = struct {
2940};2878};
29412879
2942fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {2880fn load(cg: *CodeGen, value_ty: Type, ptr_id: Id, options: MemoryOptions) !Id {
2943 const zcu = cg.pt.zcu;2881 const zcu = cg.module.zcu;
2944 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);2882 const alignment: u32 = @intCast(value_ty.abiAlignment(zcu).toByteUnits().?);
2945 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);2883 const indirect_value_ty_id = try cg.resolveType(value_ty, .indirect);
2946 const result_id = cg.module.allocId();2884 const result_id = cg.module.allocId();
...@@ -2975,7 +2913,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {...@@ -2975,7 +2913,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) !void {
29752913
2976fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {2914fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
2977 const gpa = cg.module.gpa;2915 const gpa = cg.module.gpa;
2978 const zcu = cg.pt.zcu;2916 const zcu = cg.module.zcu;
2979 const ip = &zcu.intern_pool;2917 const ip = &zcu.intern_pool;
2980 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))2918 if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip))
2981 return;2919 return;
...@@ -3159,7 +3097,7 @@ fn airBinOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: BinaryOp) !?Id {...@@ -3159,7 +3097,7 @@ fn airBinOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: BinaryOp) !?Id {
3159}3097}
31603098
3161fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: BinaryOp, signed: BinaryOp) !?Id {3099fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: BinaryOp, signed: BinaryOp) !?Id {
3162 const zcu = cg.pt.zcu;3100 const zcu = cg.module.zcu;
3163 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3101 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
31643102
3165 if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) {3103 if (cg.typeOf(bin_op.lhs).isVector(zcu) and !cg.typeOf(bin_op.rhs).isVector(zcu)) {
...@@ -3241,7 +3179,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {...@@ -3241,7 +3179,7 @@ fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary {
3241/// All other values are returned unmodified (this makes strange integer3179/// All other values are returned unmodified (this makes strange integer
3242/// wrapping easier to use in generic operations).3180/// wrapping easier to use in generic operations).
3243fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {3181fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporary {
3244 const zcu = cg.pt.zcu;3182 const zcu = cg.module.zcu;
3245 const ty = value.ty;3183 const ty = value.ty;
3246 switch (info.class) {3184 switch (info.class) {
3247 .composite_integer, .integer, .bool, .float => return value,3185 .composite_integer, .integer, .bool, .float => return value,
...@@ -3391,7 +3329,8 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3391,7 +3329,8 @@ fn airAbs(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3391}3329}
33923330
3393fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {3331fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
3394 const zcu = cg.pt.zcu;3332 const zcu = cg.module.zcu;
3333 const target = cg.module.zcu.getTarget();
3395 const operand_info = cg.arithmeticTypeInfo(value.ty);3334 const operand_info = cg.arithmeticTypeInfo(value.ty);
33963335
3397 switch (operand_info.class) {3336 switch (operand_info.class) {
...@@ -3399,7 +3338,7 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {...@@ -3399,7 +3338,7 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary {
3399 .integer, .strange_integer => {3338 .integer, .strange_integer => {
3400 const abs_value = try cg.buildUnary(.i_abs, value);3339 const abs_value = try cg.buildUnary(.i_abs, value);
34013340
3402 switch (cg.module.target.os.tag) {3341 switch (target.os.tag) {
3403 .vulkan, .opengl => {3342 .vulkan, .opengl => {
3404 if (value.ty.intInfo(zcu).signedness == .signed) {3343 if (value.ty.intInfo(zcu).signedness == .signed) {
3405 return cg.todo("perform bitcast after @abs", .{});3344 return cg.todo("perform bitcast after @abs", .{});
...@@ -3657,7 +3596,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3657,7 +3596,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3657}3596}
36583597
3659fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {3598fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3660 const zcu = cg.pt.zcu;3599 const zcu = cg.module.zcu;
36613600
3662 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3601 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3663 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;3602 const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data;
...@@ -3716,7 +3655,7 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3716,7 +3655,7 @@ fn airMulAdd(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3716fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {3655fn airClzCtz(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id {
3717 if (cg.liveness.isUnused(inst)) return null;3656 if (cg.liveness.isUnused(inst)) return null;
37183657
3719 const zcu = cg.pt.zcu;3658 const zcu = cg.module.zcu;
3720 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3659 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3721 const operand = try cg.temporary(ty_op.operand);3660 const operand = try cg.temporary(ty_op.operand);
37223661
...@@ -3759,7 +3698,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3759,7 +3698,7 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3759}3698}
37603699
3761fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {3700fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3762 const zcu = cg.pt.zcu;3701 const zcu = cg.module.zcu;
3763 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;3702 const reduce = cg.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
3764 const operand = try cg.resolve(reduce.operand);3703 const operand = try cg.resolve(reduce.operand);
3765 const operand_ty = cg.typeOf(reduce.operand);3704 const operand_ty = cg.typeOf(reduce.operand);
...@@ -3831,8 +3770,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3831,8 +3770,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3831}3770}
38323771
3833fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {3772fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3834 const pt = cg.pt;3773 const zcu = cg.module.zcu;
3835 const zcu = pt.zcu;
3836 const gpa = zcu.gpa;3774 const gpa = zcu.gpa;
38373775
3838 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);3776 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);
...@@ -3856,8 +3794,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -3856,8 +3794,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3856}3794}
38573795
3858fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {3796fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
3859 const pt = cg.pt;3797 const zcu = cg.module.zcu;
3860 const zcu = pt.zcu;
3861 const gpa = zcu.gpa;3798 const gpa = zcu.gpa;
38623799
3863 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);3800 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);
...@@ -3934,11 +3871,12 @@ fn ptrAccessChain(...@@ -3934,11 +3871,12 @@ fn ptrAccessChain(
3934 indices: []const u32,3871 indices: []const u32,
3935) !Id {3872) !Id {
3936 const gpa = cg.module.gpa;3873 const gpa = cg.module.gpa;
3874 const target = cg.module.zcu.getTarget();
3937 const ids = try cg.indicesToIds(indices);3875 const ids = try cg.indicesToIds(indices);
3938 defer gpa.free(ids);3876 defer gpa.free(ids);
39393877
3940 const result_id = cg.module.allocId();3878 const result_id = cg.module.allocId();
3941 switch (cg.module.target.os.tag) {3879 switch (target.os.tag) {
3942 .opencl, .amdhsa => {3880 .opencl, .amdhsa => {
3943 try cg.body.emit(cg.module.gpa, .OpInBoundsPtrAccessChain, .{3881 try cg.body.emit(cg.module.gpa, .OpInBoundsPtrAccessChain, .{
3944 .id_result_type = result_ty_id,3882 .id_result_type = result_ty_id,
...@@ -3962,7 +3900,7 @@ fn ptrAccessChain(...@@ -3962,7 +3900,7 @@ fn ptrAccessChain(
3962}3900}
39633901
3964fn ptrAdd(cg: *CodeGen, result_ty: Type, ptr_ty: Type, ptr_id: Id, offset_id: Id) !Id {3902fn ptrAdd(cg: *CodeGen, result_ty: Type, ptr_ty: Type, ptr_id: Id, offset_id: Id) !Id {
3965 const zcu = cg.pt.zcu;3903 const zcu = cg.module.zcu;
3966 const result_ty_id = try cg.resolveType(result_ty, .direct);3904 const result_ty_id = try cg.resolveType(result_ty, .direct);
39673905
3968 switch (ptr_ty.ptrSize(zcu)) {3906 switch (ptr_ty.ptrSize(zcu)) {
...@@ -4019,7 +3957,7 @@ fn cmp(...@@ -4019,7 +3957,7 @@ fn cmp(
4019 rhs: Temporary,3957 rhs: Temporary,
4020) !Temporary {3958) !Temporary {
4021 const pt = cg.pt;3959 const pt = cg.pt;
4022 const zcu = pt.zcu;3960 const zcu = cg.module.zcu;
4023 const ip = &zcu.intern_pool;3961 const ip = &zcu.intern_pool;
4024 const scalar_ty = lhs.ty.scalarType(zcu);3962 const scalar_ty = lhs.ty.scalarType(zcu);
4025 const is_vector = lhs.ty.isVector(zcu);3963 const is_vector = lhs.ty.isVector(zcu);
...@@ -4216,7 +4154,7 @@ fn bitCast(...@@ -4216,7 +4154,7 @@ fn bitCast(
4216 src_ty: Type,4154 src_ty: Type,
4217 src_id: Id,4155 src_id: Id,
4218) !Id {4156) !Id {
4219 const zcu = cg.pt.zcu;4157 const zcu = cg.module.zcu;
4220 const src_ty_id = try cg.resolveType(src_ty, .direct);4158 const src_ty_id = try cg.resolveType(src_ty, .direct);
4221 const dst_ty_id = try cg.resolveType(dst_ty, .direct);4159 const dst_ty_id = try cg.resolveType(dst_ty, .direct);
42224160
...@@ -4408,8 +4346,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4408,8 +4346,7 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4408}4346}
44094347
4410fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4348fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4411 const pt = cg.pt;4349 const zcu = cg.module.zcu;
4412 const zcu = pt.zcu;
4413 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4350 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4414 const array_ptr_ty = cg.typeOf(ty_op.operand);4351 const array_ptr_ty = cg.typeOf(ty_op.operand);
4415 const array_ty = array_ptr_ty.childType(zcu);4352 const array_ty = array_ptr_ty.childType(zcu);
...@@ -4445,8 +4382,9 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4445,8 +4382,9 @@ fn airSlice(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4445fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4382fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4446 const gpa = cg.module.gpa;4383 const gpa = cg.module.gpa;
4447 const pt = cg.pt;4384 const pt = cg.pt;
4448 const zcu = pt.zcu;4385 const zcu = cg.module.zcu;
4449 const ip = &zcu.intern_pool;4386 const ip = &zcu.intern_pool;
4387 const target = cg.module.zcu.getTarget();
4450 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4388 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4451 const result_ty = cg.typeOfIndex(inst);4389 const result_ty = cg.typeOfIndex(inst);
4452 const len: usize = @intCast(result_ty.arrayLen(zcu));4390 const len: usize = @intCast(result_ty.arrayLen(zcu));
...@@ -4467,7 +4405,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4467,7 +4405,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4467 const field_int_ty = try cg.pt.intType(.unsigned, ty_bit_size);4405 const field_int_ty = try cg.pt.intType(.unsigned, ty_bit_size);
4468 const field_int_id = blk: {4406 const field_int_id = blk: {
4469 if (field_ty.isPtrAtRuntime(zcu)) {4407 if (field_ty.isPtrAtRuntime(zcu)) {
4470 assert(cg.module.target.cpu.arch == .spirv64 and4408 assert(target.cpu.arch == .spirv64 and
4471 field_ty.ptrAddressSpace(zcu) == .storage_buffer);4409 field_ty.ptrAddressSpace(zcu) == .storage_buffer);
4472 break :blk try cg.intFromPtr(field_id);4410 break :blk try cg.intFromPtr(field_id);
4473 }4411 }
...@@ -4567,8 +4505,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4567,8 +4505,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4567}4505}
45684506
4569fn sliceOrArrayLen(cg: *CodeGen, operand_id: Id, ty: Type) !Id {4507fn sliceOrArrayLen(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
4570 const pt = cg.pt;4508 const zcu = cg.module.zcu;
4571 const zcu = pt.zcu;
4572 switch (ty.ptrSize(zcu)) {4509 switch (ty.ptrSize(zcu)) {
4573 .slice => return cg.extractField(.usize, operand_id, 1),4510 .slice => return cg.extractField(.usize, operand_id, 1),
4574 .one => {4511 .one => {
...@@ -4583,7 +4520,7 @@ fn sliceOrArrayLen(cg: *CodeGen, operand_id: Id, ty: Type) !Id {...@@ -4583,7 +4520,7 @@ fn sliceOrArrayLen(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
4583}4520}
45844521
4585fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id {4522fn sliceOrArrayPtr(cg: *CodeGen, operand_id: Id, ty: Type) !Id {
4586 const zcu = cg.pt.zcu;4523 const zcu = cg.module.zcu;
4587 if (ty.isSlice(zcu)) {4524 if (ty.isSlice(zcu)) {
4588 const ptr_ty = ty.slicePtrFieldType(zcu);4525 const ptr_ty = ty.slicePtrFieldType(zcu);
4589 return cg.extractField(ptr_ty, operand_id, 0);4526 return cg.extractField(ptr_ty, operand_id, 0);
...@@ -4620,7 +4557,7 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {...@@ -4620,7 +4557,7 @@ fn airSliceField(cg: *CodeGen, inst: Air.Inst.Index, field: u32) !?Id {
4620}4557}
46214558
4622fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4559fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4623 const zcu = cg.pt.zcu;4560 const zcu = cg.module.zcu;
4624 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4561 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4625 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;4562 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
4626 const slice_ty = cg.typeOf(bin_op.lhs);4563 const slice_ty = cg.typeOf(bin_op.lhs);
...@@ -4637,7 +4574,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4637,7 +4574,7 @@ fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4637}4574}
46384575
4639fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4576fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4640 const zcu = cg.pt.zcu;4577 const zcu = cg.module.zcu;
4641 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4578 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
4642 const slice_ty = cg.typeOf(bin_op.lhs);4579 const slice_ty = cg.typeOf(bin_op.lhs);
4643 if (!slice_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;4580 if (!slice_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;
...@@ -4654,7 +4591,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4654,7 +4591,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4654}4591}
46554592
4656fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {4593fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
4657 const zcu = cg.pt.zcu;4594 const zcu = cg.module.zcu;
4658 // Construct new pointer type for the resulting pointer4595 // Construct new pointer type for the resulting pointer
4659 const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.4596 const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.
4660 const elem_ptr_ty_id = try cg.ptrType(elem_ty, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)), .indirect);4597 const elem_ptr_ty_id = try cg.ptrType(elem_ty, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)), .indirect);
...@@ -4669,8 +4606,7 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {...@@ -4669,8 +4606,7 @@ fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
4669}4606}
46704607
4671fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4608fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4672 const pt = cg.pt;4609 const zcu = cg.module.zcu;
4673 const zcu = pt.zcu;
4674 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4610 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4675 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;4611 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
4676 const src_ptr_ty = cg.typeOf(bin_op.lhs);4612 const src_ptr_ty = cg.typeOf(bin_op.lhs);
...@@ -4687,7 +4623,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4687,7 +4623,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4687}4623}
46884624
4689fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4625fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4690 const zcu = cg.pt.zcu;4626 const zcu = cg.module.zcu;
4691 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4627 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
4692 const array_ty = cg.typeOf(bin_op.lhs);4628 const array_ty = cg.typeOf(bin_op.lhs);
4693 const elem_ty = array_ty.childType(zcu);4629 const elem_ty = array_ty.childType(zcu);
...@@ -4737,7 +4673,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4737,7 +4673,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4737}4673}
47384674
4739fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4675fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4740 const zcu = cg.pt.zcu;4676 const zcu = cg.module.zcu;
4741 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4677 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
4742 const ptr_ty = cg.typeOf(bin_op.lhs);4678 const ptr_ty = cg.typeOf(bin_op.lhs);
4743 const elem_ty = cg.typeOfIndex(inst);4679 const elem_ty = cg.typeOfIndex(inst);
...@@ -4748,7 +4684,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4748,7 +4684,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4748}4684}
47494685
4750fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void {4686fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void {
4751 const zcu = cg.pt.zcu;4687 const zcu = cg.module.zcu;
4752 const data = cg.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;4688 const data = cg.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;
4753 const extra = cg.air.extraData(Air.Bin, data.payload).data;4689 const extra = cg.air.extraData(Air.Bin, data.payload).data;
47544690
...@@ -4770,7 +4706,7 @@ fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -4770,7 +4706,7 @@ fn airVectorStoreElem(cg: *CodeGen, inst: Air.Inst.Index) !void {
4770}4706}
47714707
4772fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {4708fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !void {
4773 const zcu = cg.pt.zcu;4709 const zcu = cg.module.zcu;
4774 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;4710 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
4775 const un_ptr_ty = cg.typeOf(bin_op.lhs);4711 const un_ptr_ty = cg.typeOf(bin_op.lhs);
4776 const un_ty = un_ptr_ty.childType(zcu);4712 const un_ty = un_ptr_ty.childType(zcu);
...@@ -4796,7 +4732,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4796,7 +4732,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4796 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4732 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4797 const un_ty = cg.typeOf(ty_op.operand);4733 const un_ty = cg.typeOf(ty_op.operand);
47984734
4799 const zcu = cg.pt.zcu;4735 const zcu = cg.module.zcu;
4800 const layout = cg.unionLayout(un_ty);4736 const layout = cg.unionLayout(un_ty);
4801 if (layout.tag_size == 0) return null;4737 if (layout.tag_size == 0) return null;
48024738
...@@ -4820,7 +4756,7 @@ fn unionInit(...@@ -4820,7 +4756,7 @@ fn unionInit(
4820 // Note: The result here is not cached, because it generates runtime code.4756 // Note: The result here is not cached, because it generates runtime code.
48214757
4822 const pt = cg.pt;4758 const pt = cg.pt;
4823 const zcu = pt.zcu;4759 const zcu = cg.module.zcu;
4824 const ip = &zcu.intern_pool;4760 const ip = &zcu.intern_pool;
4825 const union_ty = zcu.typeToUnion(ty).?;4761 const union_ty = zcu.typeToUnion(ty).?;
4826 const tag_ty: Type = .fromInterned(union_ty.enum_tag_ty);4762 const tag_ty: Type = .fromInterned(union_ty.enum_tag_ty);
...@@ -4898,8 +4834,7 @@ fn unionInit(...@@ -4898,8 +4834,7 @@ fn unionInit(
4898}4834}
48994835
4900fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4836fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4901 const pt = cg.pt;4837 const zcu = cg.module.zcu;
4902 const zcu = pt.zcu;
4903 const ip = &zcu.intern_pool;4838 const ip = &zcu.intern_pool;
4904 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4839 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4905 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;4840 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
...@@ -4916,7 +4851,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4916,7 +4851,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
49164851
4917fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4852fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4918 const pt = cg.pt;4853 const pt = cg.pt;
4919 const zcu = pt.zcu;4854 const zcu = cg.module.zcu;
4920 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4855 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
4921 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;4856 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
49224857
...@@ -5000,8 +4935,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5000,8 +4935,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5000}4935}
50014936
5002fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {4937fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5003 const pt = cg.pt;4938 const zcu = cg.module.zcu;
5004 const zcu = pt.zcu;
5005 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;4939 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
5006 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;4940 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
50074941
...@@ -5041,7 +4975,7 @@ fn structFieldPtr(...@@ -5041,7 +4975,7 @@ fn structFieldPtr(
5041) !Id {4975) !Id {
5042 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);4976 const result_ty_id = try cg.resolveType(result_ptr_ty, .direct);
50434977
5044 const zcu = cg.pt.zcu;4978 const zcu = cg.module.zcu;
5045 const object_ty = object_ptr_ty.childType(zcu);4979 const object_ty = object_ptr_ty.childType(zcu);
5046 switch (object_ty.zigTypeTag(zcu)) {4980 switch (object_ty.zigTypeTag(zcu)) {
5047 .pointer => {4981 .pointer => {
...@@ -5106,6 +5040,7 @@ fn alloc(...@@ -5106,6 +5040,7 @@ fn alloc(
5106 ty: Type,5040 ty: Type,
5107 options: AllocOptions,5041 options: AllocOptions,
5108) !Id {5042) !Id {
5043 const target = cg.module.zcu.getTarget();
5109 const ptr_fn_ty_id = try cg.ptrType(ty, .function, .indirect);5044 const ptr_fn_ty_id = try cg.ptrType(ty, .function, .indirect);
51105045
5111 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to5046 // SPIR-V requires that OpVariable declarations for locals go into the first block, so we are just going to
...@@ -5118,7 +5053,7 @@ fn alloc(...@@ -5118,7 +5053,7 @@ fn alloc(
5118 .initializer = options.initializer,5053 .initializer = options.initializer,
5119 });5054 });
51205055
5121 switch (cg.module.target.os.tag) {5056 switch (target.os.tag) {
5122 .vulkan, .opengl => return var_id,5057 .vulkan, .opengl => return var_id,
5123 else => {},5058 else => {},
5124 }5059 }
...@@ -5135,7 +5070,7 @@ fn alloc(...@@ -5135,7 +5070,7 @@ fn alloc(
5135}5070}
51365071
5137fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5072fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5138 const zcu = cg.pt.zcu;5073 const zcu = cg.module.zcu;
5139 const ptr_ty = cg.typeOfIndex(inst);5074 const ptr_ty = cg.typeOfIndex(inst);
5140 const child_ty = ptr_ty.childType(zcu);5075 const child_ty = ptr_ty.childType(zcu);
5141 return try cg.alloc(child_ty, .{5076 return try cg.alloc(child_ty, .{
...@@ -5314,8 +5249,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -5314,8 +5249,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
5314 // ir.Block in a different SPIR-V block.5249 // ir.Block in a different SPIR-V block.
53155250
5316 const gpa = cg.module.gpa;5251 const gpa = cg.module.gpa;
5317 const pt = cg.pt;5252 const zcu = cg.module.zcu;
5318 const zcu = pt.zcu;
5319 const ty = cg.typeOfIndex(inst);5253 const ty = cg.typeOfIndex(inst);
5320 const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);5254 const have_block_result = ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu);
53215255
...@@ -5448,7 +5382,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)...@@ -5448,7 +5382,7 @@ fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index)
54485382
5449fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {5383fn airBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
5450 const gpa = cg.module.gpa;5384 const gpa = cg.module.gpa;
5451 const zcu = cg.pt.zcu;5385 const zcu = cg.module.zcu;
5452 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;5386 const br = cg.air.instructions.items(.data)[@intFromEnum(inst)].br;
5453 const operand_ty = cg.typeOf(br.operand);5387 const operand_ty = cg.typeOf(br.operand);
54545388
...@@ -5592,7 +5526,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5592,7 +5526,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) !void {
5592}5526}
55935527
5594fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5528fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5595 const zcu = cg.pt.zcu;5529 const zcu = cg.module.zcu;
5596 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5530 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5597 const ptr_ty = cg.typeOf(ty_op.operand);5531 const ptr_ty = cg.typeOf(ty_op.operand);
5598 const elem_ty = cg.typeOfIndex(inst);5532 const elem_ty = cg.typeOfIndex(inst);
...@@ -5603,7 +5537,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5603,7 +5537,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5603}5537}
56045538
5605fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {5539fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
5606 const zcu = cg.pt.zcu;5540 const zcu = cg.module.zcu;
5607 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;5541 const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
5608 const ptr_ty = cg.typeOf(bin_op.lhs);5542 const ptr_ty = cg.typeOf(bin_op.lhs);
5609 const elem_ty = ptr_ty.childType(zcu);5543 const elem_ty = ptr_ty.childType(zcu);
...@@ -5614,8 +5548,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5614,8 +5548,7 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
5614}5548}
56155549
5616fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {5550fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
5617 const pt = cg.pt;5551 const zcu = cg.module.zcu;
5618 const zcu = pt.zcu;
5619 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5552 const operand = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
5620 const ret_ty = cg.typeOf(operand);5553 const ret_ty = cg.typeOf(operand);
5621 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {5554 if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
...@@ -5636,8 +5569,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5636,8 +5569,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) !void {
5636}5569}
56375570
5638fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {5571fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
5639 const pt = cg.pt;5572 const zcu = cg.module.zcu;
5640 const zcu = pt.zcu;
5641 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5573 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
5642 const ptr_ty = cg.typeOf(un_op);5574 const ptr_ty = cg.typeOf(un_op);
5643 const ret_ty = ptr_ty.childType(zcu);5575 const ret_ty = ptr_ty.childType(zcu);
...@@ -5663,7 +5595,7 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5663,7 +5595,7 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) !void {
5663}5595}
56645596
5665fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5597fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5666 const zcu = cg.pt.zcu;5598 const zcu = cg.module.zcu;
5667 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;5599 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5668 const err_union_id = try cg.resolve(pl_op.operand);5600 const err_union_id = try cg.resolve(pl_op.operand);
5669 const extra = cg.air.extraData(Air.Try, pl_op.payload);5601 const extra = cg.air.extraData(Air.Try, pl_op.payload);
...@@ -5733,7 +5665,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5733,7 +5665,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5733}5665}
57345666
5735fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5667fn airErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5736 const zcu = cg.pt.zcu;5668 const zcu = cg.module.zcu;
5737 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5669 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5738 const operand_id = try cg.resolve(ty_op.operand);5670 const operand_id = try cg.resolve(ty_op.operand);
5739 const err_union_ty = cg.typeOf(ty_op.operand);5671 const err_union_ty = cg.typeOf(ty_op.operand);
...@@ -5769,7 +5701,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5769,7 +5701,7 @@ fn airErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5769}5701}
57705702
5771fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5703fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5772 const zcu = cg.pt.zcu;5704 const zcu = cg.module.zcu;
5773 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5705 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5774 const err_union_ty = cg.typeOfIndex(inst);5706 const err_union_ty = cg.typeOfIndex(inst);
5775 const payload_ty = err_union_ty.errorUnionPayload(zcu);5707 const payload_ty = err_union_ty.errorUnionPayload(zcu);
...@@ -5818,8 +5750,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5818,8 +5750,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5818}5750}
58195751
5820fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?Id {5752fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?Id {
5821 const pt = cg.pt;5753 const zcu = cg.module.zcu;
5822 const zcu = pt.zcu;
5823 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5754 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
5824 const operand_id = try cg.resolve(un_op);5755 const operand_id = try cg.resolve(un_op);
5825 const operand_ty = cg.typeOf(un_op);5756 const operand_ty = cg.typeOf(un_op);
...@@ -5895,7 +5826,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {...@@ -5895,7 +5826,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum {
5895}5826}
58965827
5897fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?Id {5828fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?Id {
5898 const zcu = cg.pt.zcu;5829 const zcu = cg.module.zcu;
5899 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;5830 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
5900 const operand_id = try cg.resolve(un_op);5831 const operand_id = try cg.resolve(un_op);
5901 const err_union_ty = cg.typeOf(un_op);5832 const err_union_ty = cg.typeOf(un_op);
...@@ -5933,8 +5864,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err...@@ -5933,8 +5864,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err
5933}5864}
59345865
5935fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5866fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5936 const pt = cg.pt;5867 const zcu = cg.module.zcu;
5937 const zcu = pt.zcu;
5938 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5868 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5939 const operand_id = try cg.resolve(ty_op.operand);5869 const operand_id = try cg.resolve(ty_op.operand);
5940 const optional_ty = cg.typeOf(ty_op.operand);5870 const optional_ty = cg.typeOf(ty_op.operand);
...@@ -5950,8 +5880,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5950,8 +5880,7 @@ fn airUnwrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5950}5880}
59515881
5952fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5882fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5953 const pt = cg.pt;5883 const zcu = cg.module.zcu;
5954 const zcu = pt.zcu;
5955 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5884 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5956 const operand_id = try cg.resolve(ty_op.operand);5885 const operand_id = try cg.resolve(ty_op.operand);
5957 const operand_ty = cg.typeOf(ty_op.operand);5886 const operand_ty = cg.typeOf(ty_op.operand);
...@@ -5975,8 +5904,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5975,8 +5904,7 @@ fn airUnwrapOptionalPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5975}5904}
59765905
5977fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {5906fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5978 const pt = cg.pt;5907 const zcu = cg.module.zcu;
5979 const zcu = pt.zcu;
5980 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;5908 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
5981 const payload_ty = cg.typeOf(ty_op.operand);5909 const payload_ty = cg.typeOf(ty_op.operand);
59825910
...@@ -6000,8 +5928,8 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6000,8 +5928,8 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6000fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {5928fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void {
6001 const gpa = cg.module.gpa;5929 const gpa = cg.module.gpa;
6002 const pt = cg.pt;5930 const pt = cg.pt;
6003 const zcu = pt.zcu;5931 const zcu = cg.module.zcu;
6004 const target = cg.module.target;5932 const target = cg.module.zcu.getTarget();
6005 const switch_br = cg.air.unwrapSwitch(inst);5933 const switch_br = cg.air.unwrapSwitch(inst);
6006 const cond_ty = cg.typeOf(switch_br.operand);5934 const cond_ty = cg.typeOf(switch_br.operand);
6007 const cond = try cg.resolve(switch_br.operand);5935 const cond = try cg.resolve(switch_br.operand);
...@@ -6157,29 +6085,21 @@ fn airUnreach(cg: *CodeGen) !void {...@@ -6157,29 +6085,21 @@ fn airUnreach(cg: *CodeGen) !void {
6157}6085}
61586086
6159fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {6087fn airDbgStmt(cg: *CodeGen, inst: Air.Inst.Index) !void {
6160 const gpa = cg.module.gpa;6088 const zcu = cg.module.zcu;
6161 const pt = cg.pt;
6162 const zcu = pt.zcu;
6163 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;6089 const dbg_stmt = cg.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
6164 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;6090 const path = zcu.navFileScope(cg.owner_nav).sub_file_path;
61656091
6166 if (cg.file_path_id == .none) {6092 if (zcu.comp.config.root_strip) return;
6167 cg.file_path_id = cg.module.allocId();
6168 try cg.module.sections.debug_strings.emit(gpa, .OpString, .{
6169 .id_result = cg.file_path_id,
6170 .string = path,
6171 });
6172 }
61736093
6174 try cg.body.emit(cg.module.gpa, .OpLine, .{6094 try cg.body.emit(cg.module.gpa, .OpLine, .{
6175 .file = cg.file_path_id,6095 .file = try cg.module.debugString(path),
6176 .line = cg.base_line + dbg_stmt.line + 1,6096 .line = cg.base_line + dbg_stmt.line + 1,
6177 .column = dbg_stmt.column + 1,6097 .column = dbg_stmt.column + 1,
6178 });6098 });
6179}6099}
61806100
6181fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6101fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6182 const zcu = cg.pt.zcu;6102 const zcu = cg.module.zcu;
6183 const inst_datas = cg.air.instructions.items(.data);6103 const inst_datas = cg.air.instructions.items(.data);
6184 const extra = cg.air.extraData(Air.DbgInlineBlock, inst_datas[@intFromEnum(inst)].ty_pl.payload);6104 const extra = cg.air.extraData(Air.DbgInlineBlock, inst_datas[@intFromEnum(inst)].ty_pl.payload);
6185 const old_base_line = cg.base_line;6105 const old_base_line = cg.base_line;
...@@ -6197,7 +6117,7 @@ fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -6197,7 +6117,7 @@ fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
61976117
6198fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {6118fn airAssembly(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6199 const gpa = cg.module.gpa;6119 const gpa = cg.module.gpa;
6200 const zcu = cg.pt.zcu;6120 const zcu = cg.module.zcu;
6201 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;6121 const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
6202 const extra = cg.air.extraData(Air.Asm, ty_pl.payload);6122 const extra = cg.air.extraData(Air.Asm, ty_pl.payload);
62036123
...@@ -6360,8 +6280,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie...@@ -6360,8 +6280,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifie
6360 _ = modifier;6280 _ = modifier;
63616281
6362 const gpa = cg.module.gpa;6282 const gpa = cg.module.gpa;
6363 const pt = cg.pt;6283 const zcu = cg.module.zcu;
6364 const zcu = pt.zcu;
6365 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6284 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
6366 const extra = cg.air.extraData(Air.Call, pl_op.payload);6285 const extra = cg.air.extraData(Air.Call, pl_op.payload);
6367 const args: []const Air.Inst.Ref = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.args_len]);6286 const args: []const Air.Inst.Ref = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.args_len]);
...@@ -6455,11 +6374,11 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -6455,11 +6374,11 @@ fn airWorkGroupId(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
6455}6374}
64566375
6457fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {6376fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
6458 const zcu = cg.pt.zcu;6377 const zcu = cg.module.zcu;
6459 return cg.air.typeOf(inst, &zcu.intern_pool);6378 return cg.air.typeOf(inst, &zcu.intern_pool);
6460}6379}
64616380
6462fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {6381fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
6463 const zcu = cg.pt.zcu;6382 const zcu = cg.module.zcu;
6464 return cg.air.typeOfIndex(inst, &zcu.intern_pool);6383 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
6465}6384}
src/arch/spirv/Module.zig+233-93
...@@ -7,67 +7,22 @@...@@ -7,67 +7,22 @@
7//! is detected by the magic word in the header. Therefore, we can ignore any byte7//! is detected by the magic word in the header. Therefore, we can ignore any byte
8//! order throughout the implementation, and just use the host byte order, and make8//! order throughout the implementation, and just use the host byte order, and make
9//! this a problem for the consumer.9//! this a problem for the consumer.
10const Module = @This();
11
12const std = @import("std");10const std = @import("std");
13const Allocator = std.mem.Allocator;11const Allocator = std.mem.Allocator;
14const assert = std.debug.assert;12const assert = std.debug.assert;
15const autoHashStrat = std.hash.autoHashStrat;
16const Wyhash = std.hash.Wyhash;
1713
14const Zcu = @import("../../Zcu.zig");
18const InternPool = @import("../../InternPool.zig");15const InternPool = @import("../../InternPool.zig");
16const Section = @import("Section.zig");
19const spec = @import("spec.zig");17const spec = @import("spec.zig");
20const Word = spec.Word;18const Word = spec.Word;
21const Id = spec.Id;19const Id = spec.Id;
2220
23const Section = @import("Section.zig");21const Module = @This();
24
25/// Declarations, both functions and globals, can have dependencies. These are used for 2 things:
26/// - Globals must be declared before they are used, also between globals. The compiler processes
27/// globals unordered, so we must use the dependencies here to figure out how to order the globals
28/// in the final module. The Globals structure is also used for that.
29/// - Entry points must declare the complete list of OpVariable instructions that they access.
30/// For these we use the same dependency structure.
31/// In this mechanism, globals will only depend on other globals, while functions may depend on
32/// globals or other functions.
33pub const Decl = struct {
34 /// Index to refer to a Decl by.
35 pub const Index = enum(u32) { _ };
36
37 /// Useful to tell what kind of decl this is, and hold the result-id or field index
38 /// to be used for this decl.
39 pub const Kind = enum {
40 func,
41 global,
42 invocation_global,
43 };
44
45 /// See comment on Kind
46 kind: Kind,
47 /// The result-id associated to this decl. The specific meaning of this depends on `kind`:
48 /// - For `func`, this is the result-id of the associated OpFunction instruction.
49 /// - For `global`, this is the result-id of the associated OpVariable instruction.
50 /// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
51 result_id: Id,
52 /// The offset of the first dependency of this decl in the `decl_deps` array.
53 begin_dep: u32,
54 /// The past-end offset of the dependencies of this decl in the `decl_deps` array.
55 end_dep: u32,
56};
57
58/// This models a kernel entry point.
59pub const EntryPoint = struct {
60 /// The declaration that should be exported.
61 decl_index: Decl.Index,
62 /// The name of the kernel to be exported.
63 name: []const u8,
64 /// Calling Convention
65 exec_model: spec.ExecutionModel,
66 exec_mode: ?spec.ExecutionMode = null,
67};
6822
69gpa: Allocator,23gpa: Allocator,
70target: *const std.Target,24arena: Allocator,
25zcu: *Zcu,
71nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty,26nav_link: std.AutoHashMapUnmanaged(InternPool.Nav.Index, Decl.Index) = .empty,
72uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty,27uav_link: std.AutoHashMapUnmanaged(struct { InternPool.Index, spec.StorageClass }, Decl.Index) = .empty,
73intern_map: std.AutoHashMapUnmanaged(struct { InternPool.Index, Repr }, Id) = .empty,28intern_map: std.AutoHashMapUnmanaged(struct { InternPool.Index, Repr }, Id) = .empty,
...@@ -81,7 +36,7 @@ entry_points: std.AutoArrayHashMapUnmanaged(Id, EntryPoint) = .empty,...@@ -81,7 +36,7 @@ entry_points: std.AutoArrayHashMapUnmanaged(Id, EntryPoint) = .empty,
81/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned36/// ID-equality for pointers, and pointers constructed via `ptrType()` aren't interned
82/// via the usual `intern_map` mechanism.37/// via the usual `intern_map` mechanism.
83ptr_types: std.AutoHashMapUnmanaged(38ptr_types: std.AutoHashMapUnmanaged(
84 struct { InternPool.Index, spec.StorageClass, Repr },39 struct { Id, spec.StorageClass },
85 struct { ty_id: Id, fwd_emitted: bool },40 struct { ty_id: Id, fwd_emitted: bool },
86) = .{},41) = .{},
87/// For test declarations compiled for Vulkan target, we have to add a buffer.42/// For test declarations compiled for Vulkan target, we have to add a buffer.
...@@ -101,18 +56,23 @@ next_result_id: Word = 1,...@@ -101,18 +56,23 @@ next_result_id: Word = 1,
101cache: struct {56cache: struct {
102 bool_type: ?Id = null,57 bool_type: ?Id = null,
103 void_type: ?Id = null,58 void_type: ?Id = null,
59 opaque_types: std.StringHashMapUnmanaged(Id) = .empty,
104 int_types: std.AutoHashMapUnmanaged(std.builtin.Type.Int, Id) = .empty,60 int_types: std.AutoHashMapUnmanaged(std.builtin.Type.Int, Id) = .empty,
105 float_types: std.AutoHashMapUnmanaged(std.builtin.Type.Float, Id) = .empty,61 float_types: std.AutoHashMapUnmanaged(std.builtin.Type.Float, Id) = .empty,
106 vector_types: std.AutoHashMapUnmanaged(struct { Id, u32 }, Id) = .empty,62 vector_types: std.AutoHashMapUnmanaged(struct { Id, u32 }, Id) = .empty,
107 array_types: std.AutoHashMapUnmanaged(struct { Id, Id }, Id) = .empty,63 array_types: std.AutoHashMapUnmanaged(struct { Id, Id }, Id) = .empty,
64 struct_types: std.ArrayHashMapUnmanaged(StructType, Id, StructType.HashContext, true) = .empty,
65 fn_types: std.ArrayHashMapUnmanaged(FnType, Id, FnType.HashContext, true) = .empty,
10866
109 capabilities: std.AutoHashMapUnmanaged(spec.Capability, void) = .empty,67 capabilities: std.AutoHashMapUnmanaged(spec.Capability, void) = .empty,
110 extensions: std.StringHashMapUnmanaged(void) = .empty,68 extensions: std.StringHashMapUnmanaged(void) = .empty,
111 extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,69 extended_instruction_set: std.AutoHashMapUnmanaged(spec.InstructionSet, Id) = .empty,
112 decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,70 decorations: std.AutoHashMapUnmanaged(struct { Id, spec.Decoration }, void) = .empty,
113 builtins: std.AutoHashMapUnmanaged(struct { Id, spec.BuiltIn }, Decl.Index) = .empty,71 builtins: std.AutoHashMapUnmanaged(struct { Id, spec.BuiltIn }, Decl.Index) = .empty,
72 strings: std.StringArrayHashMapUnmanaged(Id) = .empty,
11473
115 bool_const: [2]?Id = .{ null, null },74 bool_const: [2]?Id = .{ null, null },
75 constants: std.ArrayHashMapUnmanaged(Constant, Id, Constant.HashContext, true) = .empty,
116} = .{},76} = .{},
117/// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".77/// Module layout, according to SPIR-V Spec section 2.4, "Logical Layout of a Module".
118sections: struct {78sections: struct {
...@@ -138,6 +98,114 @@ pub const Repr = enum {...@@ -138,6 +98,114 @@ pub const Repr = enum {
138 indirect,98 indirect,
139};99};
140100
101/// Declarations, both functions and globals, can have dependencies. These are used for 2 things:
102/// - Globals must be declared before they are used, also between globals. The compiler processes
103/// globals unordered, so we must use the dependencies here to figure out how to order the globals
104/// in the final module. The Globals structure is also used for that.
105/// - Entry points must declare the complete list of OpVariable instructions that they access.
106/// For these we use the same dependency structure.
107/// In this mechanism, globals will only depend on other globals, while functions may depend on
108/// globals or other functions.
109pub const Decl = struct {
110 /// Index to refer to a Decl by.
111 pub const Index = enum(u32) { _ };
112
113 /// Useful to tell what kind of decl this is, and hold the result-id or field index
114 /// to be used for this decl.
115 pub const Kind = enum {
116 func,
117 global,
118 invocation_global,
119 };
120
121 /// See comment on Kind
122 kind: Kind,
123 /// The result-id associated to this decl. The specific meaning of this depends on `kind`:
124 /// - For `func`, this is the result-id of the associated OpFunction instruction.
125 /// - For `global`, this is the result-id of the associated OpVariable instruction.
126 /// - For `invocation_global`, this is the result-id of the associated InvocationGlobal instruction.
127 result_id: Id,
128 /// The offset of the first dependency of this decl in the `decl_deps` array.
129 begin_dep: u32,
130 /// The past-end offset of the dependencies of this decl in the `decl_deps` array.
131 end_dep: u32,
132};
133
134/// This models a kernel entry point.
135pub const EntryPoint = struct {
136 /// The declaration that should be exported.
137 decl_index: Decl.Index,
138 /// The name of the kernel to be exported.
139 name: []const u8,
140 /// Calling Convention
141 exec_model: spec.ExecutionModel,
142 exec_mode: ?spec.ExecutionMode = null,
143};
144
145const StructType = struct {
146 fields: []const Id,
147 ip_index: InternPool.Index,
148
149 const HashContext = struct {
150 pub fn hash(_: @This(), ty: StructType) u32 {
151 var hasher = std.hash.Wyhash.init(0);
152 hasher.update(std.mem.sliceAsBytes(ty.fields));
153 hasher.update(std.mem.asBytes(&ty.ip_index));
154 return @truncate(hasher.final());
155 }
156
157 pub fn eql(_: @This(), a: StructType, b: StructType, _: usize) bool {
158 return a.ip_index == b.ip_index and std.mem.eql(Id, a.fields, b.fields);
159 }
160 };
161};
162
163const FnType = struct {
164 return_ty: Id,
165 params: []const Id,
166
167 const HashContext = struct {
168 pub fn hash(_: @This(), ty: FnType) u32 {
169 var hasher = std.hash.Wyhash.init(0);
170 hasher.update(std.mem.asBytes(&ty.return_ty));
171 hasher.update(std.mem.sliceAsBytes(ty.params));
172 return @truncate(hasher.final());
173 }
174
175 pub fn eql(_: @This(), a: FnType, b: FnType, _: usize) bool {
176 return a.return_ty == b.return_ty and
177 std.mem.eql(Id, a.params, b.params);
178 }
179 };
180};
181
182const Constant = struct {
183 ty: Id,
184 value: spec.LiteralContextDependentNumber,
185
186 const HashContext = struct {
187 pub fn hash(_: @This(), value: Constant) u32 {
188 const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?;
189 var hasher = std.hash.Wyhash.init(0);
190 hasher.update(std.mem.asBytes(&value.ty));
191 hasher.update(std.mem.asBytes(&@as(Tag, value.value)));
192 switch (value.value) {
193 inline else => |v| hasher.update(std.mem.asBytes(&v)),
194 }
195 return @truncate(hasher.final());
196 }
197
198 pub fn eql(_: @This(), a: Constant, b: Constant, _: usize) bool {
199 if (a.ty != b.ty) return false;
200 const Tag = @typeInfo(spec.LiteralContextDependentNumber).@"union".tag_type.?;
201 if (@as(Tag, a.value) != @as(Tag, b.value)) return false;
202 return switch (a.value) {
203 inline else => |v, tag| v == @field(b.value, @tagName(tag)),
204 };
205 }
206 };
207};
208
141pub fn deinit(module: *Module) void {209pub fn deinit(module: *Module) void {
142 module.nav_link.deinit(module.gpa);210 module.nav_link.deinit(module.gpa);
143 module.uav_link.deinit(module.gpa);211 module.uav_link.deinit(module.gpa);
...@@ -155,15 +223,21 @@ pub fn deinit(module: *Module) void {...@@ -155,15 +223,21 @@ pub fn deinit(module: *Module) void {
155 module.sections.globals.deinit(module.gpa);223 module.sections.globals.deinit(module.gpa);
156 module.sections.functions.deinit(module.gpa);224 module.sections.functions.deinit(module.gpa);
157225
226 module.cache.opaque_types.deinit(module.gpa);
158 module.cache.int_types.deinit(module.gpa);227 module.cache.int_types.deinit(module.gpa);
159 module.cache.float_types.deinit(module.gpa);228 module.cache.float_types.deinit(module.gpa);
160 module.cache.vector_types.deinit(module.gpa);229 module.cache.vector_types.deinit(module.gpa);
161 module.cache.array_types.deinit(module.gpa);230 module.cache.array_types.deinit(module.gpa);
231 module.cache.struct_types.deinit(module.gpa);
232 module.cache.fn_types.deinit(module.gpa);
162 module.cache.capabilities.deinit(module.gpa);233 module.cache.capabilities.deinit(module.gpa);
163 module.cache.extensions.deinit(module.gpa);234 module.cache.extensions.deinit(module.gpa);
164 module.cache.extended_instruction_set.deinit(module.gpa);235 module.cache.extended_instruction_set.deinit(module.gpa);
165 module.cache.decorations.deinit(module.gpa);236 module.cache.decorations.deinit(module.gpa);
166 module.cache.builtins.deinit(module.gpa);237 module.cache.builtins.deinit(module.gpa);
238 module.cache.strings.deinit(module.gpa);
239
240 module.cache.constants.deinit(module.gpa);
167241
168 module.decls.deinit(module.gpa);242 module.decls.deinit(module.gpa);
169 module.decl_deps.deinit(module.gpa);243 module.decl_deps.deinit(module.gpa);
...@@ -234,6 +308,8 @@ pub fn addEntryPointDeps(...@@ -234,6 +308,8 @@ pub fn addEntryPointDeps(
234}308}
235309
236fn entryPoints(module: *Module) !Section {310fn entryPoints(module: *Module) !Section {
311 const target = module.zcu.getTarget();
312
237 var entry_points = Section{};313 var entry_points = Section{};
238 errdefer entry_points.deinit(module.gpa);314 errdefer entry_points.deinit(module.gpa);
239315
...@@ -256,7 +332,7 @@ fn entryPoints(module: *Module) !Section {...@@ -256,7 +332,7 @@ fn entryPoints(module: *Module) !Section {
256 });332 });
257333
258 if (entry_point.exec_mode == null and entry_point.exec_model == .fragment) {334 if (entry_point.exec_mode == null and entry_point.exec_model == .fragment) {
259 switch (module.target.os.tag) {335 switch (target.os.tag) {
260 .vulkan, .opengl => |tag| {336 .vulkan, .opengl => |tag| {
261 try module.sections.execution_modes.emit(module.gpa, .OpExecutionMode, .{337 try module.sections.execution_modes.emit(module.gpa, .OpExecutionMode, .{
262 .entry_point = entry_point_id,338 .entry_point = entry_point_id,
...@@ -273,7 +349,7 @@ fn entryPoints(module: *Module) !Section {...@@ -273,7 +349,7 @@ fn entryPoints(module: *Module) !Section {
273}349}
274350
275pub fn finalize(module: *Module, gpa: Allocator) ![]Word {351pub fn finalize(module: *Module, gpa: Allocator) ![]Word {
276 const target = module.target;352 const target = module.zcu.getTarget();
277353
278 // Emit capabilities and extensions354 // Emit capabilities and extensions
279 switch (target.os.tag) {355 switch (target.os.tag) {
...@@ -434,20 +510,6 @@ pub fn importInstructionSet(module: *Module, set: spec.InstructionSet) !Id {...@@ -434,20 +510,6 @@ pub fn importInstructionSet(module: *Module, set: spec.InstructionSet) !Id {
434 return result_id;510 return result_id;
435}511}
436512
437pub fn structType(module: *Module, result_id: Id, types: []const Id, maybe_names: ?[]const []const u8) !void {
438 try module.sections.globals.emit(module.gpa, .OpTypeStruct, .{
439 .id_result = result_id,
440 .id_ref = types,
441 });
442
443 if (maybe_names) |names| {
444 assert(names.len == types.len);
445 for (names, 0..) |name, i| {
446 try module.memberDebugName(result_id, @intCast(i), name);
447 }
448 }
449}
450
451pub fn boolType(module: *Module) !Id {513pub fn boolType(module: *Module) !Id {
452 if (module.cache.bool_type) |id| return id;514 if (module.cache.bool_type) |id| return id;
453515
...@@ -471,6 +533,19 @@ pub fn voidType(module: *Module) !Id {...@@ -471,6 +533,19 @@ pub fn voidType(module: *Module) !Id {
471 return result_id;533 return result_id;
472}534}
473535
536pub fn opaqueType(module: *Module, name: []const u8) !Id {
537 if (module.cache.opaque_types.get(name)) |id| return id;
538 const result_id = module.allocId();
539 const name_dup = try module.arena.dupe(u8, name);
540 try module.sections.globals.emit(module.gpa, .OpTypeOpaque, .{
541 .id_result = result_id,
542 .literal_string = name_dup,
543 });
544 try module.debugName(result_id, name_dup);
545 try module.cache.opaque_types.put(module.gpa, name_dup, result_id);
546 return result_id;
547}
548
474pub fn intType(module: *Module, signedness: std.builtin.Signedness, bits: u16) !Id {549pub fn intType(module: *Module, signedness: std.builtin.Signedness, bits: u16) !Id {
475 assert(bits > 0);550 assert(bits > 0);
476 const entry = try module.cache.int_types.getOrPut(module.gpa, .{ .signedness = signedness, .bits = bits });551 const entry = try module.cache.int_types.getOrPut(module.gpa, .{ .signedness = signedness, .bits = bits });
...@@ -537,27 +612,89 @@ pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id {...@@ -537,27 +612,89 @@ pub fn arrayType(module: *Module, len_id: Id, child_ty_id: Id) !Id {
537 return entry.value_ptr.*;612 return entry.value_ptr.*;
538}613}
539614
540pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const Id) !Id {615pub fn structType(
616 module: *Module,
617 types: []const Id,
618 maybe_names: ?[]const []const u8,
619 maybe_offsets: ?[]const u32,
620 ip_index: InternPool.Index,
621) !Id {
622 const target = module.zcu.getTarget();
623
624 if (module.cache.struct_types.get(.{ .fields = types, .ip_index = ip_index })) |id| return id;
541 const result_id = module.allocId();625 const result_id = module.allocId();
542 try module.sections.globals.emit(module.gpa, .OpTypeFunction, .{626 const types_dup = try module.arena.dupe(Id, types);
627 try module.sections.globals.emit(module.gpa, .OpTypeStruct, .{
543 .id_result = result_id,628 .id_result = result_id,
544 .return_type = return_ty_id,629 .id_ref = types_dup,
545 .id_ref_2 = param_type_ids,
546 });630 });
631
632 if (maybe_names) |names| {
633 assert(names.len == types.len);
634 for (names, 0..) |name, i| {
635 try module.memberDebugName(result_id, @intCast(i), name);
636 }
637 }
638
639 switch (target.os.tag) {
640 .vulkan, .opengl => {
641 if (maybe_offsets) |offsets| {
642 assert(offsets.len == types.len);
643 for (offsets, 0..) |offset, i| {
644 try module.decorateMember(
645 result_id,
646 @intCast(i),
647 .{ .offset = .{ .byte_offset = offset } },
648 );
649 }
650 }
651 },
652 else => {},
653 }
654
655 try module.cache.struct_types.put(
656 module.gpa,
657 .{
658 .fields = types_dup,
659 .ip_index = if (module.zcu.comp.config.root_strip) .none else ip_index,
660 },
661 result_id,
662 );
547 return result_id;663 return result_id;
548}664}
549665
550pub fn constant(module: *Module, result_ty_id: Id, value: spec.LiteralContextDependentNumber) !Id {666pub fn functionType(module: *Module, return_ty_id: Id, param_type_ids: []const Id) !Id {
667 if (module.cache.fn_types.get(.{
668 .return_ty = return_ty_id,
669 .params = param_type_ids,
670 })) |id| return id;
551 const result_id = module.allocId();671 const result_id = module.allocId();
552 const section = &module.sections.globals;672 const params_dup = try module.arena.dupe(Id, param_type_ids);
553 try section.emit(module.gpa, .OpConstant, .{673 try module.sections.globals.emit(module.gpa, .OpTypeFunction, .{
554 .id_result_type = result_ty_id,
555 .id_result = result_id,674 .id_result = result_id,
556 .value = value,675 .return_type = return_ty_id,
676 .id_ref_2 = params_dup,
557 });677 });
678 try module.cache.fn_types.put(module.gpa, .{
679 .return_ty = return_ty_id,
680 .params = params_dup,
681 }, result_id);
558 return result_id;682 return result_id;
559}683}
560684
685pub fn constant(module: *Module, ty_id: Id, value: spec.LiteralContextDependentNumber) !Id {
686 const entry = try module.cache.constants.getOrPut(module.gpa, .{ .ty = ty_id, .value = value });
687 if (!entry.found_existing) {
688 entry.value_ptr.* = module.allocId();
689 try module.sections.globals.emit(module.gpa, .OpConstant, .{
690 .id_result_type = ty_id,
691 .id_result = entry.value_ptr.*,
692 .value = value,
693 });
694 }
695 return entry.value_ptr.*;
696}
697
561pub fn constBool(module: *Module, value: bool) !Id {698pub fn constBool(module: *Module, value: bool) !Id {
562 if (module.cache.bool_const[@intFromBool(value)]) |b| return b;699 if (module.cache.bool_const[@intFromBool(value)]) |b| return b;
563700
...@@ -711,28 +848,31 @@ pub fn memberDebugName(module: *Module, target: Id, member: u32, name: []const u...@@ -711,28 +848,31 @@ pub fn memberDebugName(module: *Module, target: Id, member: u32, name: []const u
711 });848 });
712}849}
713850
851pub fn debugString(module: *Module, string: []const u8) !Id {
852 const entry = try module.cache.strings.getOrPut(module.gpa, string);
853 if (!entry.found_existing) {
854 entry.value_ptr.* = module.allocId();
855 try module.sections.debug_strings.emit(module.gpa, .OpString, .{
856 .id_result = entry.value_ptr.*,
857 .string = string,
858 });
859 }
860 return entry.value_ptr.*;
861}
862
714pub fn storageClass(module: *Module, as: std.builtin.AddressSpace) spec.StorageClass {863pub fn storageClass(module: *Module, as: std.builtin.AddressSpace) spec.StorageClass {
864 const target = module.zcu.getTarget();
715 return switch (as) {865 return switch (as) {
716 .generic => if (module.target.cpu.has(.spirv, .generic_pointer)) .generic else .function,866 .generic => if (target.cpu.has(.spirv, .generic_pointer)) .generic else .function,
717 .global => switch (module.target.os.tag) {867 .global => switch (target.os.tag) {
718 .opencl, .amdhsa => .cross_workgroup,868 .opencl, .amdhsa => .cross_workgroup,
719 else => .storage_buffer,869 else => .storage_buffer,
720 },870 },
721 .push_constant => {871 .push_constant => .push_constant,
722 return .push_constant;872 .output => .output,
723 },873 .uniform => .uniform,
724 .output => {874 .storage_buffer => .storage_buffer,
725 return .output;875 .physical_storage_buffer => .physical_storage_buffer,
726 },
727 .uniform => {
728 return .uniform;
729 },
730 .storage_buffer => {
731 return .storage_buffer;
732 },
733 .physical_storage_buffer => {
734 return .physical_storage_buffer;
735 },
736 .constant => .uniform_constant,876 .constant => .uniform_constant,
737 .shared => .workgroup,877 .shared => .workgroup,
738 .local => .function,878 .local => .function,
src/link/SpirV.zig+38-36
...@@ -46,8 +46,8 @@ pub fn createEmpty(...@@ -46,8 +46,8 @@ pub fn createEmpty(
46 else => unreachable, // Caught by Compilation.Config.resolve.46 else => unreachable, // Caught by Compilation.Config.resolve.
47 }47 }
4848
49 const self = try arena.create(Linker);49 const linker = try arena.create(Linker);
50 self.* = .{50 linker.* = .{
51 .base = .{51 .base = .{
52 .tag = .spirv,52 .tag = .spirv,
53 .comp = comp,53 .comp = comp,
...@@ -59,16 +59,20 @@ pub fn createEmpty(...@@ -59,16 +59,20 @@ pub fn createEmpty(
59 .file = null,59 .file = null,
60 .build_id = options.build_id,60 .build_id = options.build_id,
61 },61 },
62 .module = .{ .gpa = gpa, .target = comp.getTarget() },62 .module = .{
63 .gpa = gpa,
64 .arena = arena,
65 .zcu = comp.zcu.?,
66 },
63 };67 };
64 errdefer self.deinit();68 errdefer linker.deinit();
6569
66 self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{70 linker.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
67 .truncate = true,71 .truncate = true,
68 .read = true,72 .read = true,
69 });73 });
7074
71 return self;75 return linker;
72}76}
7377
74pub fn open(78pub fn open(
...@@ -80,12 +84,12 @@ pub fn open(...@@ -80,12 +84,12 @@ pub fn open(
80 return createEmpty(arena, comp, emit, options);84 return createEmpty(arena, comp, emit, options);
81}85}
8286
83pub fn deinit(self: *Linker) void {87pub fn deinit(linker: *Linker) void {
84 self.module.deinit();88 linker.module.deinit();
85}89}
8690
87fn genNav(91fn generate(
88 self: *Linker,92 linker: *Linker,
89 pt: Zcu.PerThread,93 pt: Zcu.PerThread,
90 nav_index: InternPool.Nav.Index,94 nav_index: InternPool.Nav.Index,
91 air: Air,95 air: Air,
...@@ -96,9 +100,9 @@ fn genNav(...@@ -96,9 +100,9 @@ fn genNav(
96 const gpa = zcu.gpa;100 const gpa = zcu.gpa;
97 const structured_cfg = zcu.navFileScope(nav_index).mod.?.structured_cfg;101 const structured_cfg = zcu.navFileScope(nav_index).mod.?.structured_cfg;
98102
99 var nav_gen: CodeGen = .{103 var cg: CodeGen = .{
100 .pt = pt,104 .pt = pt,
101 .module = &self.module,105 .module = &linker.module,
102 .owner_nav = nav_index,106 .owner_nav = nav_index,
103 .air = air,107 .air = air,
104 .liveness = liveness,108 .liveness = liveness,
...@@ -108,17 +112,17 @@ fn genNav(...@@ -108,17 +112,17 @@ fn genNav(
108 },112 },
109 .base_line = zcu.navSrcLine(nav_index),113 .base_line = zcu.navSrcLine(nav_index),
110 };114 };
111 defer nav_gen.deinit();115 defer cg.deinit();
112116
113 nav_gen.genNav(do_codegen) catch |err| switch (err) {117 cg.genNav(do_codegen) catch |err| switch (err) {
114 error.CodegenFail => switch (zcu.codegenFailMsg(nav_index, nav_gen.error_msg.?)) {118 error.CodegenFail => switch (zcu.codegenFailMsg(nav_index, cg.error_msg.?)) {
115 error.CodegenFail => {},119 error.CodegenFail => {},
116 error.OutOfMemory => |e| return e,120 error.OutOfMemory => |e| return e,
117 },121 },
118 else => |other| {122 else => |other| {
119 // There might be an error that happened *after* self.error_msg123 // There might be an error that happened *after* linker.error_msg
120 // was already allocated, so be sure to free it.124 // was already allocated, so be sure to free it.
121 if (nav_gen.error_msg) |error_msg| {125 if (cg.error_msg) |error_msg| {
122 error_msg.deinit(gpa);126 error_msg.deinit(gpa);
123 }127 }
124128
...@@ -128,7 +132,7 @@ fn genNav(...@@ -128,7 +132,7 @@ fn genNav(
128}132}
129133
130pub fn updateFunc(134pub fn updateFunc(
131 self: *Linker,135 linker: *Linker,
132 pt: Zcu.PerThread,136 pt: Zcu.PerThread,
133 func_index: InternPool.Index,137 func_index: InternPool.Index,
134 air: *const Air,138 air: *const Air,
...@@ -136,17 +140,17 @@ pub fn updateFunc(...@@ -136,17 +140,17 @@ pub fn updateFunc(
136) !void {140) !void {
137 const nav = pt.zcu.funcInfo(func_index).owner_nav;141 const nav = pt.zcu.funcInfo(func_index).owner_nav;
138 // TODO: Separate types for generating decls and functions?142 // TODO: Separate types for generating decls and functions?
139 try self.genNav(pt, nav, air.*, liveness.*.?, true);143 try linker.generate(pt, nav, air.*, liveness.*.?, true);
140}144}
141145
142pub fn updateNav(self: *Linker, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {146pub fn updateNav(linker: *Linker, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
143 const ip = &pt.zcu.intern_pool;147 const ip = &pt.zcu.intern_pool;
144 log.debug("lowering nav {f}({d})", .{ ip.getNav(nav).fqn.fmt(ip), nav });148 log.debug("lowering nav {f}({d})", .{ ip.getNav(nav).fqn.fmt(ip), nav });
145 try self.genNav(pt, nav, undefined, undefined, false);149 try linker.generate(pt, nav, undefined, undefined, false);
146}150}
147151
148pub fn updateExports(152pub fn updateExports(
149 self: *Linker,153 linker: *Linker,
150 pt: Zcu.PerThread,154 pt: Zcu.PerThread,
151 exported: Zcu.Exported,155 exported: Zcu.Exported,
152 export_indices: []const Zcu.Export.Index,156 export_indices: []const Zcu.Export.Index,
...@@ -163,7 +167,7 @@ pub fn updateExports(...@@ -163,7 +167,7 @@ pub fn updateExports(
163 const nav_ty = ip.getNav(nav_index).typeOf(ip);167 const nav_ty = ip.getNav(nav_index).typeOf(ip);
164 const target = zcu.getTarget();168 const target = zcu.getTarget();
165 if (ip.isFunctionType(nav_ty)) {169 if (ip.isFunctionType(nav_ty)) {
166 const spv_decl_index = try self.module.resolveNav(ip, nav_index);170 const spv_decl_index = try linker.module.resolveNav(ip, nav_index);
167 const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu);171 const cc = Type.fromInterned(nav_ty).fnCallingConvention(zcu);
168 const exec_model: spec.ExecutionModel = switch (target.os.tag) {172 const exec_model: spec.ExecutionModel = switch (target.os.tag) {
169 .vulkan, .opengl => switch (cc) {173 .vulkan, .opengl => switch (cc) {
...@@ -185,7 +189,7 @@ pub fn updateExports(...@@ -185,7 +189,7 @@ pub fn updateExports(
185189
186 for (export_indices) |export_idx| {190 for (export_indices) |export_idx| {
187 const exp = export_idx.ptr(zcu);191 const exp = export_idx.ptr(zcu);
188 try self.module.declareEntryPoint(192 try linker.module.declareEntryPoint(
189 spv_decl_index,193 spv_decl_index,
190 exp.opts.name.toSlice(ip),194 exp.opts.name.toSlice(ip),
191 exec_model,195 exec_model,
...@@ -198,7 +202,7 @@ pub fn updateExports(...@@ -198,7 +202,7 @@ pub fn updateExports(
198}202}
199203
200pub fn flush(204pub fn flush(
201 self: *Linker,205 linker: *Linker,
202 arena: Allocator,206 arena: Allocator,
203 tid: Zcu.PerThread.Id,207 tid: Zcu.PerThread.Id,
204 prog_node: std.Progress.Node,208 prog_node: std.Progress.Node,
...@@ -214,18 +218,18 @@ pub fn flush(...@@ -214,18 +218,18 @@ pub fn flush(
214 const sub_prog_node = prog_node.start("Flush Module", 0);218 const sub_prog_node = prog_node.start("Flush Module", 0);
215 defer sub_prog_node.end();219 defer sub_prog_node.end();
216220
217 const comp = self.base.comp;221 const comp = linker.base.comp;
218 const diags = &comp.link_diags;222 const diags = &comp.link_diags;
219 const gpa = comp.gpa;223 const gpa = comp.gpa;
220224
221 // We need to export the list of error names somewhere so that we can pretty-print them in the225 // We need to export the list of error names somewhere so that we can pretty-print them in the
222 // executor. This is not really an important thing though, so we can just dump it in any old226 // executor. This is not really an important thing though, so we can just dump it in any old
223 // nonsemantic instruction. For now, just put it in OpSourceExtension with a special name.227 // nonsemantic instruction. For now, just put it in OpSourceExtension with a special name.
224 var error_info: std.io.Writer.Allocating = .init(self.module.gpa);228 var error_info: std.io.Writer.Allocating = .init(linker.module.gpa);
225 defer error_info.deinit();229 defer error_info.deinit();
226230
227 error_info.writer.writeAll("zig_errors:") catch return error.OutOfMemory;231 error_info.writer.writeAll("zig_errors:") catch return error.OutOfMemory;
228 const ip = &self.base.comp.zcu.?.intern_pool;232 const ip = &linker.base.comp.zcu.?.intern_pool;
229 for (ip.global_error_set.getNamesFromMainThread()) |name| {233 for (ip.global_error_set.getNamesFromMainThread()) |name| {
230 // Errors can contain pretty much any character - to encode them in a string we must escape234 // Errors can contain pretty much any character - to encode them in a string we must escape
231 // them somehow. Easiest here is to use some established scheme, one which also preseves the235 // them somehow. Easiest here is to use some established scheme, one which also preseves the
...@@ -245,28 +249,27 @@ pub fn flush(...@@ -245,28 +249,27 @@ pub fn flush(
245 }.isValidChar,249 }.isValidChar,
246 ) catch return error.OutOfMemory;250 ) catch return error.OutOfMemory;
247 }251 }
248 try self.module.sections.debug_strings.emit(gpa, .OpSourceExtension, .{252 try linker.module.sections.debug_strings.emit(gpa, .OpSourceExtension, .{
249 .extension = error_info.getWritten(),253 .extension = error_info.getWritten(),
250 });254 });
251255
252 const module = try self.module.finalize(arena);256 const module = try linker.module.finalize(arena);
253 errdefer arena.free(module);257 errdefer arena.free(module);
254258
255 const linked_module = self.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {259 const linked_module = linker.linkModule(arena, module, sub_prog_node) catch |err| switch (err) {
256 error.OutOfMemory => return error.OutOfMemory,260 error.OutOfMemory => return error.OutOfMemory,
257 else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}),261 else => |other| return diags.fail("error while linking: {s}", .{@errorName(other)}),
258 };262 };
259263
260 self.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module)) catch |err|264 linker.base.file.?.writeAll(std.mem.sliceAsBytes(linked_module)) catch |err|
261 return diags.fail("failed to write: {s}", .{@errorName(err)});265 return diags.fail("failed to write: {s}", .{@errorName(err)});
262}266}
263267
264fn linkModule(self: *Linker, arena: Allocator, module: []Word, progress: std.Progress.Node) ![]Word {268fn linkModule(linker: *Linker, arena: Allocator, module: []Word, progress: std.Progress.Node) ![]Word {
265 _ = self;269 _ = linker;
266270
267 const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig");271 const lower_invocation_globals = @import("SpirV/lower_invocation_globals.zig");
268 const prune_unused = @import("SpirV/prune_unused.zig");272 const prune_unused = @import("SpirV/prune_unused.zig");
269 const dedup = @import("SpirV/deduplicate.zig");
270273
271 var parser = try BinaryModule.Parser.init(arena);274 var parser = try BinaryModule.Parser.init(arena);
272 defer parser.deinit();275 defer parser.deinit();
...@@ -274,7 +277,6 @@ fn linkModule(self: *Linker, arena: Allocator, module: []Word, progress: std.Pro...@@ -274,7 +277,6 @@ fn linkModule(self: *Linker, arena: Allocator, module: []Word, progress: std.Pro
274277
275 try lower_invocation_globals.run(&parser, &binary, progress);278 try lower_invocation_globals.run(&parser, &binary, progress);
276 try prune_unused.run(&parser, &binary, progress);279 try prune_unused.run(&parser, &binary, progress);
277 try dedup.run(&parser, &binary, progress);
278280
279 return binary.finalize(arena);281 return binary.finalize(arena);
280}282}
src/link/SpirV/deduplicate.zig deleted-553
...@@ -1,553 +0,0 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const log = std.log.scoped(.spirv_link);
4const assert = std.debug.assert;
5
6const BinaryModule = @import("BinaryModule.zig");
7const Section = @import("../../arch/spirv/Section.zig");
8const spec = @import("../../arch/spirv/spec.zig");
9const Opcode = spec.Opcode;
10const ResultId = spec.Id;
11const Word = spec.Word;
12
13fn canDeduplicate(opcode: Opcode) bool {
14 return switch (opcode) {
15 .OpTypeForwardPointer => false, // Don't need to handle these
16 .OpGroupDecorate, .OpGroupMemberDecorate => {
17 // These are deprecated, so don't bother supporting them for now.
18 return false;
19 },
20 // Debug decoration-style instructions
21 .OpName, .OpMemberName => true,
22 else => switch (opcode.class()) {
23 .type_declaration,
24 .constant_creation,
25 .annotation,
26 => true,
27 else => false,
28 },
29 };
30}
31
32const ModuleInfo = struct {
33 /// This models a type, decoration or constant instruction
34 /// and its dependencies.
35 const Entity = struct {
36 /// The type that this entity represents. This is just
37 /// the instruction opcode.
38 kind: Opcode,
39 /// The offset of this entity's operands, in
40 /// `binary.instructions`.
41 first_operand: u32,
42 /// The number of operands in this entity
43 num_operands: u16,
44 /// The (first_operand-relative) offset of the result-id,
45 /// or the entity that is affected by this entity if this entity
46 /// is a decoration.
47 result_id_index: u16,
48 /// The first decoration in `self.decorations`.
49 first_decoration: u32,
50
51 fn operands(self: Entity, binary: *const BinaryModule) []const Word {
52 return binary.instructions[self.first_operand..][0..self.num_operands];
53 }
54 };
55
56 /// Maps result-id to Entity's
57 entities: std.AutoArrayHashMapUnmanaged(ResultId, Entity),
58 /// A bit set that keeps track of which operands are result-ids.
59 /// Note: This also includes any result-id!
60 /// Because we need these values when recoding the module anyway,
61 /// it contains the status of ALL operands in the module.
62 operand_is_id: std.DynamicBitSetUnmanaged,
63 /// Store of decorations for each entity.
64 decorations: []const Entity,
65
66 pub fn parse(
67 arena: Allocator,
68 parser: *BinaryModule.Parser,
69 binary: BinaryModule,
70 ) !ModuleInfo {
71 var entities = std.AutoArrayHashMap(ResultId, Entity).init(arena);
72 var id_offsets = std.ArrayList(u16).init(arena);
73 var operand_is_id = try std.DynamicBitSetUnmanaged.initEmpty(arena, binary.instructions.len);
74 var decorations = std.MultiArrayList(struct { target_id: ResultId, entity: Entity }){};
75
76 var it = binary.iterateInstructions();
77 while (it.next()) |inst| {
78 id_offsets.items.len = 0;
79 try parser.parseInstructionResultIds(binary, inst, &id_offsets);
80
81 const first_operand_offset: u32 = @intCast(inst.offset + 1);
82 for (id_offsets.items) |offset| {
83 operand_is_id.set(first_operand_offset + offset);
84 }
85
86 if (!canDeduplicate(inst.opcode)) continue;
87
88 const result_id_index: u16 = switch (inst.opcode.class()) {
89 .type_declaration, .annotation, .debug => 0,
90 .constant_creation => 1,
91 else => unreachable,
92 };
93
94 const result_id: ResultId = @enumFromInt(inst.operands[id_offsets.items[result_id_index]]);
95 const entity = Entity{
96 .kind = inst.opcode,
97 .first_operand = first_operand_offset,
98 .num_operands = @intCast(inst.operands.len),
99 .result_id_index = result_id_index,
100 .first_decoration = undefined, // Filled in later
101 };
102
103 switch (inst.opcode.class()) {
104 .annotation, .debug => {
105 try decorations.append(arena, .{
106 .target_id = result_id,
107 .entity = entity,
108 });
109 },
110 .type_declaration, .constant_creation => {
111 const entry = try entities.getOrPut(result_id);
112 if (entry.found_existing) {
113 log.err("type or constant {f} has duplicate definition", .{result_id});
114 return error.DuplicateId;
115 }
116 entry.value_ptr.* = entity;
117 },
118 else => unreachable,
119 }
120 }
121
122 // Sort decorations by the index of the result-id in `entities.
123 // This ensures not only that the decorations of a particular reuslt-id
124 // are continuous, but the subsequences also appear in the same order as in `entities`.
125
126 const SortContext = struct {
127 entities: std.AutoArrayHashMapUnmanaged(ResultId, Entity),
128 ids: []const ResultId,
129
130 pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
131 // If any index is not in the entities set, its because its not a
132 // deduplicatable result-id. Those should be considered largest and
133 // float to the end.
134 const entity_index_a = ctx.entities.getIndex(ctx.ids[a_index]) orelse return false;
135 const entity_index_b = ctx.entities.getIndex(ctx.ids[b_index]) orelse return true;
136
137 return entity_index_a < entity_index_b;
138 }
139 };
140
141 decorations.sort(SortContext{
142 .entities = entities.unmanaged,
143 .ids = decorations.items(.target_id),
144 });
145
146 // Now go through the decorations and add the offsets to the entities list.
147 var decoration_i: u32 = 0;
148 const target_ids = decorations.items(.target_id);
149 for (entities.keys(), entities.values()) |id, *entity| {
150 entity.first_decoration = decoration_i;
151
152 // Scan ahead to the next decoration
153 while (decoration_i < target_ids.len and target_ids[decoration_i] == id) {
154 decoration_i += 1;
155 }
156 }
157
158 return .{
159 .entities = entities.unmanaged,
160 .operand_is_id = operand_is_id,
161 // There may be unrelated decorations at the end, so make sure to
162 // slice those off.
163 .decorations = decorations.items(.entity)[0..decoration_i],
164 };
165 }
166
167 fn entityDecorationsByIndex(self: ModuleInfo, index: usize) []const Entity {
168 const values = self.entities.values();
169 const first_decoration = values[index].first_decoration;
170 if (index == values.len - 1) {
171 return self.decorations[first_decoration..];
172 } else {
173 const next_first_decoration = values[index + 1].first_decoration;
174 return self.decorations[first_decoration..next_first_decoration];
175 }
176 }
177};
178
179const EntityContext = struct {
180 a: Allocator,
181 ptr_map_a: std.AutoArrayHashMapUnmanaged(ResultId, void) = .empty,
182 ptr_map_b: std.AutoArrayHashMapUnmanaged(ResultId, void) = .empty,
183 info: *const ModuleInfo,
184 binary: *const BinaryModule,
185
186 fn deinit(self: *EntityContext) void {
187 self.ptr_map_a.deinit(self.a);
188 self.ptr_map_b.deinit(self.a);
189
190 self.* = undefined;
191 }
192
193 fn equalizeMapCapacity(self: *EntityContext) !void {
194 const cap = @max(self.ptr_map_a.capacity(), self.ptr_map_b.capacity());
195 try self.ptr_map_a.ensureTotalCapacity(self.a, cap);
196 try self.ptr_map_b.ensureTotalCapacity(self.a, cap);
197 }
198
199 fn hash(self: *EntityContext, id: ResultId) !u64 {
200 var hasher = std.hash.Wyhash.init(0);
201 self.ptr_map_a.clearRetainingCapacity();
202 try self.hashInner(&hasher, id);
203 return hasher.final();
204 }
205
206 fn hashInner(self: *EntityContext, hasher: *std.hash.Wyhash, id: ResultId) error{OutOfMemory}!void {
207 const index = self.info.entities.getIndex(id) orelse {
208 // Index unknown, the type or constant may depend on another result-id
209 // that couldn't be deduplicated and so it wasn't added to info.entities.
210 // In this case, just has the ID itself.
211 std.hash.autoHash(hasher, id);
212 return;
213 };
214
215 const entity = self.info.entities.values()[index];
216
217 // If the current pointer is recursive, don't immediately add it to the map. This is to ensure that
218 // if the current pointer is already recursive, it gets the same hash a pointer that points to the
219 // same child but has a different result-id.
220 if (entity.kind == .OpTypePointer) {
221 // This may be either a pointer that is forward-referenced in the future,
222 // or a forward reference to a pointer.
223 // Note: We use the **struct** here instead of the pointer itself, to avoid an edge case like this:
224 //
225 // A - C*'
226 // \
227 // C - C*'
228 // /
229 // B - C*"
230 //
231 // In this case, hashing A goes like
232 // A -> C*' -> C -> C*' recursion
233 // And hashing B goes like
234 // B -> C*" -> C -> C*' -> C -> C*' recursion
235 // The are several calls to ptrType in codegen that may C*' and C*" to be generated as separate
236 // types. This is not a problem for C itself though - this can only be generated through resolveType()
237 // and so ensures equality by Zig's type system. Technically the above problem is still present, but it
238 // would only be present in a structure such as
239 //
240 // A - C*' - C'
241 // \
242 // C*" - C - C*
243 // /
244 // B
245 //
246 // where there is a duplicate definition of struct C. Resolving this requires a much more time consuming
247 // algorithm though, and because we don't expect any correctness issues with it, we leave that for now.
248
249 // TODO: Do we need to mind the storage class here? Its going to be recursive regardless, right?
250 const struct_id: ResultId = @enumFromInt(entity.operands(self.binary)[2]);
251 const entry = try self.ptr_map_a.getOrPut(self.a, struct_id);
252 if (entry.found_existing) {
253 // Pointer already seen. Hash the index instead of recursing into its children.
254 std.hash.autoHash(hasher, entry.index);
255 return;
256 }
257 }
258
259 try self.hashEntity(hasher, entity);
260
261 // Process decorations.
262 const decorations = self.info.entityDecorationsByIndex(index);
263 for (decorations) |decoration| {
264 try self.hashEntity(hasher, decoration);
265 }
266
267 if (entity.kind == .OpTypePointer) {
268 const struct_id: ResultId = @enumFromInt(entity.operands(self.binary)[2]);
269 assert(self.ptr_map_a.swapRemove(struct_id));
270 }
271 }
272
273 fn hashEntity(self: *EntityContext, hasher: *std.hash.Wyhash, entity: ModuleInfo.Entity) !void {
274 std.hash.autoHash(hasher, entity.kind);
275 // Process operands
276 const operands = entity.operands(self.binary);
277 for (operands, 0..) |operand, i| {
278 if (i == entity.result_id_index) {
279 // Not relevant, skip...
280 continue;
281 } else if (self.info.operand_is_id.isSet(entity.first_operand + i)) {
282 // Operand is ID
283 try self.hashInner(hasher, @enumFromInt(operand));
284 } else {
285 // Operand is merely data
286 std.hash.autoHash(hasher, operand);
287 }
288 }
289 }
290
291 fn eql(self: *EntityContext, a: ResultId, b: ResultId) !bool {
292 self.ptr_map_a.clearRetainingCapacity();
293 self.ptr_map_b.clearRetainingCapacity();
294
295 return try self.eqlInner(a, b);
296 }
297
298 fn eqlInner(self: *EntityContext, id_a: ResultId, id_b: ResultId) error{OutOfMemory}!bool {
299 const maybe_index_a = self.info.entities.getIndex(id_a);
300 const maybe_index_b = self.info.entities.getIndex(id_b);
301
302 if (maybe_index_a == null and maybe_index_b == null) {
303 // Both indices unknown. In this case the type or constant
304 // may depend on another result-id that couldn't be deduplicated
305 // (so it wasn't added to info.entities). In this case, that particular
306 // result-id should be the same one.
307 return id_a == id_b;
308 }
309
310 const index_a = maybe_index_a orelse return false;
311 const index_b = maybe_index_b orelse return false;
312
313 const entity_a = self.info.entities.values()[index_a];
314 const entity_b = self.info.entities.values()[index_b];
315
316 if (entity_a.kind != entity_b.kind) {
317 return false;
318 }
319
320 if (entity_a.kind == .OpTypePointer) {
321 // May be a forward reference, or should be saved as a potential
322 // forward reference in the future. Whatever the case, it should
323 // be the same for both a and b.
324 const struct_id_a: ResultId = @enumFromInt(entity_a.operands(self.binary)[2]);
325 const struct_id_b: ResultId = @enumFromInt(entity_b.operands(self.binary)[2]);
326
327 const entry_a = try self.ptr_map_a.getOrPut(self.a, struct_id_a);
328 const entry_b = try self.ptr_map_b.getOrPut(self.a, struct_id_b);
329
330 if (entry_a.found_existing != entry_b.found_existing) return false;
331 if (entry_a.index != entry_b.index) return false;
332
333 if (entry_a.found_existing) {
334 // No need to recurse.
335 return true;
336 }
337 }
338
339 if (!try self.eqlEntities(entity_a, entity_b)) {
340 return false;
341 }
342
343 // Compare decorations.
344 const decorations_a = self.info.entityDecorationsByIndex(index_a);
345 const decorations_b = self.info.entityDecorationsByIndex(index_b);
346 if (decorations_a.len != decorations_b.len) {
347 return false;
348 }
349
350 for (decorations_a, decorations_b) |decoration_a, decoration_b| {
351 if (!try self.eqlEntities(decoration_a, decoration_b)) {
352 return false;
353 }
354 }
355
356 if (entity_a.kind == .OpTypePointer) {
357 const struct_id_a: ResultId = @enumFromInt(entity_a.operands(self.binary)[2]);
358 const struct_id_b: ResultId = @enumFromInt(entity_b.operands(self.binary)[2]);
359
360 assert(self.ptr_map_a.swapRemove(struct_id_a));
361 assert(self.ptr_map_b.swapRemove(struct_id_b));
362 }
363
364 return true;
365 }
366
367 fn eqlEntities(self: *EntityContext, entity_a: ModuleInfo.Entity, entity_b: ModuleInfo.Entity) !bool {
368 if (entity_a.kind != entity_b.kind) {
369 return false;
370 } else if (entity_a.result_id_index != entity_a.result_id_index) {
371 return false;
372 }
373
374 const operands_a = entity_a.operands(self.binary);
375 const operands_b = entity_b.operands(self.binary);
376
377 // Note: returns false for operands that have explicit defaults in optional operands... oh well
378 if (operands_a.len != operands_b.len) {
379 return false;
380 }
381
382 for (operands_a, operands_b, 0..) |operand_a, operand_b, i| {
383 const a_is_id = self.info.operand_is_id.isSet(entity_a.first_operand + i);
384 const b_is_id = self.info.operand_is_id.isSet(entity_b.first_operand + i);
385 if (a_is_id != b_is_id) {
386 return false;
387 } else if (i == entity_a.result_id_index) {
388 // result-id for both...
389 continue;
390 } else if (a_is_id) {
391 // Both are IDs, so recurse.
392 if (!try self.eqlInner(@enumFromInt(operand_a), @enumFromInt(operand_b))) {
393 return false;
394 }
395 } else if (operand_a != operand_b) {
396 return false;
397 }
398 }
399
400 return true;
401 }
402};
403
404/// This struct is a wrapper around EntityContext that adapts it for
405/// use in a hash map. Because EntityContext allocates, it cannot be
406/// used. This wrapper simply assumes that the maps have been allocated
407/// the max amount of memory they are going to use.
408/// This is done by pre-hashing all keys.
409const EntityHashContext = struct {
410 entity_context: *EntityContext,
411
412 pub fn hash(self: EntityHashContext, key: ResultId) u64 {
413 return self.entity_context.hash(key) catch unreachable;
414 }
415
416 pub fn eql(self: EntityHashContext, a: ResultId, b: ResultId) bool {
417 return self.entity_context.eql(a, b) catch unreachable;
418 }
419};
420
421pub fn run(parser: *BinaryModule.Parser, binary: *BinaryModule, progress: std.Progress.Node) !void {
422 const sub_node = progress.start("deduplicate", 0);
423 defer sub_node.end();
424
425 var arena = std.heap.ArenaAllocator.init(parser.a);
426 defer arena.deinit();
427 const a = arena.allocator();
428
429 const info = try ModuleInfo.parse(a, parser, binary.*);
430
431 // Hash all keys once so that the maps can be allocated the right size.
432 var ctx = EntityContext{
433 .a = a,
434 .info = &info,
435 .binary = binary,
436 };
437
438 for (info.entities.keys()) |id| {
439 _ = try ctx.hash(id);
440 }
441
442 // hash only uses ptr_map_a, so allocate ptr_map_b too
443 try ctx.equalizeMapCapacity();
444
445 // Figure out which entities can be deduplicated.
446 var map = std.HashMap(ResultId, void, EntityHashContext, 80).initContext(a, .{
447 .entity_context = &ctx,
448 });
449 var replace = std.AutoArrayHashMap(ResultId, ResultId).init(a);
450 for (info.entities.keys()) |id| {
451 const entry = try map.getOrPut(id);
452 if (entry.found_existing) {
453 try replace.putNoClobber(id, entry.key_ptr.*);
454 }
455 }
456
457 sub_node.setEstimatedTotalItems(binary.instructions.len);
458
459 // Now process the module, and replace instructions where needed.
460 var section = Section{};
461 var it = binary.iterateInstructions();
462 var new_functions_section: ?usize = null;
463 var new_operands = std.ArrayList(u32).init(a);
464 var emitted_ptrs = std.AutoHashMap(ResultId, void).init(a);
465 while (it.next()) |inst| {
466 defer sub_node.setCompletedItems(inst.offset);
467
468 // Result-id can only be the first or second operand
469 const inst_spec = parser.getInstSpec(inst.opcode).?;
470
471 const maybe_result_id_offset: ?u16 = for (0..2) |i| {
472 if (inst_spec.operands.len > i and inst_spec.operands[i].kind == .id_result) {
473 break @intCast(i);
474 }
475 } else null;
476
477 if (maybe_result_id_offset) |offset| {
478 const result_id: ResultId = @enumFromInt(inst.operands[offset]);
479 if (replace.contains(result_id)) continue;
480 }
481
482 switch (inst.opcode) {
483 .OpFunction => if (new_functions_section == null) {
484 new_functions_section = section.instructions.items.len;
485 },
486 .OpTypeForwardPointer => continue, // We re-emit these where needed
487 else => {},
488 }
489
490 switch (inst.opcode.class()) {
491 .annotation, .debug => {
492 // For decoration-style instructions, only emit them
493 // if the target is not removed.
494 const target: ResultId = @enumFromInt(inst.operands[0]);
495 if (replace.contains(target)) continue;
496 },
497 else => {},
498 }
499
500 // Re-emit the instruction, but replace all the IDs.
501
502 new_operands.items.len = 0;
503 try new_operands.appendSlice(inst.operands);
504
505 for (new_operands.items, 0..) |*operand, i| {
506 const is_id = info.operand_is_id.isSet(inst.offset + 1 + i);
507 if (!is_id) continue;
508
509 if (replace.get(@enumFromInt(operand.*))) |new_id| {
510 operand.* = @intFromEnum(new_id);
511 }
512
513 if (maybe_result_id_offset == null or maybe_result_id_offset.? != i) {
514 // Only emit forward pointers before type, constant, and global instructions.
515 // Debug and Annotation instructions don't need the forward pointer, and it
516 // messes up the logical layout of the module.
517 switch (inst.opcode.class()) {
518 .type_declaration, .constant_creation, .memory => {},
519 else => continue,
520 }
521
522 const id: ResultId = @enumFromInt(operand.*);
523 const index = info.entities.getIndex(id) orelse continue;
524 const entity = info.entities.values()[index];
525 if (entity.kind == .OpTypePointer and !emitted_ptrs.contains(id)) {
526 // Grab the pointer's storage class from its operands in the original
527 // module.
528 const storage_class: spec.StorageClass = @enumFromInt(entity.operands(binary)[1]);
529 try section.emit(a, .OpTypeForwardPointer, .{
530 .pointer_type = id,
531 .storage_class = storage_class,
532 });
533 try emitted_ptrs.put(id, {});
534 }
535 }
536 }
537
538 if (inst.opcode == .OpTypePointer) {
539 const result_id: ResultId = @enumFromInt(new_operands.items[maybe_result_id_offset.?]);
540 try emitted_ptrs.put(result_id, {});
541 }
542
543 try section.emitRawInstruction(a, inst.opcode, new_operands.items);
544 }
545
546 for (replace.keys()) |key| {
547 _ = binary.ext_inst_map.remove(key);
548 _ = binary.arith_type_width.remove(key);
549 }
550
551 binary.instructions = try parser.a.dupe(Word, section.toWords());
552 binary.sections.functions = new_functions_section orelse binary.instructions.len;
553}