authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-10 22:36:50-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-10 22:36:50-08:00
loge56fe06d3083d29b253ee8f4586971ec362a1e95
treeca58f93f7d987a49a73ce21daf854b55c809b36e
parentd18f52197d3e796858b79a70bfc6b6911b4f92ff
parent72bd1cd378dcdb96217473baee899528c21bcbbc
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18878 from alichraghi/vector

spirv: emit vectorized operations

1 files changed, 145 insertions(+), 182 deletions(-)

src/codegen/spirv.zig+145-182
...@@ -629,6 +629,16 @@ const DeclGen = struct {...@@ -629,6 +629,16 @@ const DeclGen = struct {
629 return self.backingIntBits(ty) == null;629 return self.backingIntBits(ty) == null;
630 }630 }
631631
632 /// Checks whether the type can be directly translated to SPIR-V vectors
633 fn isVector(self: *DeclGen, ty: Type) bool {
634 const mod = self.module;
635 if (ty.zigTypeTag(mod) != .Vector) return false;
636 const elem_ty = ty.childType(mod);
637 const len = ty.vectorLen(mod);
638 const is_scalar = elem_ty.isNumeric(mod) or elem_ty.toIntern() == .bool_type;
639 return is_scalar and len > 1 and len <= 4;
640 }
641
632 fn arithmeticTypeInfo(self: *DeclGen, ty: Type) ArithmeticTypeInfo {642 fn arithmeticTypeInfo(self: *DeclGen, ty: Type) ArithmeticTypeInfo {
633 const mod = self.module;643 const mod = self.module;
634 const target = self.getTarget();644 const target = self.getTarget();
...@@ -694,6 +704,24 @@ const DeclGen = struct {...@@ -694,6 +704,24 @@ const DeclGen = struct {
694 /// This function, unlike SpvModule.constInt, takes care to bitcast704 /// This function, unlike SpvModule.constInt, takes care to bitcast
695 /// the value to an unsigned int first for Kernels.705 /// the value to an unsigned int first for Kernels.
696 fn constInt(self: *DeclGen, ty_ref: CacheRef, value: anytype) !IdRef {706 fn constInt(self: *DeclGen, ty_ref: CacheRef, value: anytype) !IdRef {
707 switch (self.spv.cache.lookup(ty_ref)) {
708 .vector_type => |vec_type| {
709 const elem_ids = try self.gpa.alloc(IdRef, vec_type.component_count);
710 defer self.gpa.free(elem_ids);
711 const int_value = try self.constInt(vec_type.component_type, value);
712 @memset(elem_ids, int_value);
713
714 const constituents_id = self.spv.allocId();
715 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
716 .id_result_type = self.typeId(ty_ref),
717 .id_result = constituents_id,
718 .constituents = elem_ids,
719 });
720 return constituents_id;
721 },
722 else => {},
723 }
724
697 if (value < 0) {725 if (value < 0) {
698 const ty = self.spv.cache.lookup(ty_ref).int_type;726 const ty = self.spv.cache.lookup(ty_ref).int_type;
699 // Manually truncate the value so that the resulting value727 // Manually truncate the value so that the resulting value
...@@ -711,6 +739,24 @@ const DeclGen = struct {...@@ -711,6 +739,24 @@ const DeclGen = struct {
711739
712 /// Emits a float constant740 /// Emits a float constant
713 fn constFloat(self: *DeclGen, ty_ref: CacheRef, value: f128) !IdRef {741 fn constFloat(self: *DeclGen, ty_ref: CacheRef, value: f128) !IdRef {
742 switch (self.spv.cache.lookup(ty_ref)) {
743 .vector_type => |vec_type| {
744 const elem_ids = try self.gpa.alloc(IdRef, vec_type.component_count);
745 defer self.gpa.free(elem_ids);
746 const int_value = try self.constFloat(vec_type.component_type, value);
747 @memset(elem_ids, int_value);
748
749 const constituents_id = self.spv.allocId();
750 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
751 .id_result_type = self.typeId(ty_ref),
752 .id_result = constituents_id,
753 .constituents = elem_ids,
754 });
755 return constituents_id;
756 },
757 else => {},
758 }
759
714 const ty = self.spv.cache.lookup(ty_ref).float_type;760 const ty = self.spv.cache.lookup(ty_ref).float_type;
715 return switch (ty.bits) {761 return switch (ty.bits) {
716 16 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float16 = @floatCast(value) } } }),762 16 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float16 = @floatCast(value) } } }),
...@@ -726,9 +772,9 @@ const DeclGen = struct {...@@ -726,9 +772,9 @@ const DeclGen = struct {
726 /// if the parameters are in indirect representation, then the result is too.772 /// if the parameters are in indirect representation, then the result is too.
727 fn constructComposite(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef {773 fn constructComposite(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef {
728 const constituents_id = self.spv.allocId();774 const constituents_id = self.spv.allocId();
729 const type_id = try self.resolveTypeId(ty);775 const type_id = try self.resolveType(ty, .direct);
730 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{776 try self.func.body.emit(self.spv.gpa, .OpCompositeConstruct, .{
731 .id_result_type = type_id,777 .id_result_type = self.typeId(type_id),
732 .id_result = constituents_id,778 .id_result = constituents_id,
733 .constituents = constituents,779 .constituents = constituents,
734 });780 });
...@@ -1448,12 +1494,11 @@ const DeclGen = struct {...@@ -1448,12 +1494,11 @@ const DeclGen = struct {
1448 const elem_ty = ty.childType(mod);1494 const elem_ty = ty.childType(mod);
1449 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);1495 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);
1450 const len = ty.vectorLen(mod);1496 const len = ty.vectorLen(mod);
1451 const is_scalar = elem_ty.isNumeric(mod) or elem_ty.toIntern() == .bool_type;
14521497
1453 const ty_ref = if (is_scalar and len > 1 and len <= 4)1498 const ty_ref = if (self.isVector(ty))
1454 try self.spv.vectorType(ty.vectorLen(mod), elem_ty_ref)1499 try self.spv.vectorType(len, elem_ty_ref)
1455 else1500 else
1456 try self.spv.arrayType(ty.vectorLen(mod), elem_ty_ref);1501 try self.spv.arrayType(len, elem_ty_ref);
14571502
1458 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });1503 try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref });
1459 return ty_ref;1504 return ty_ref;
...@@ -1752,18 +1797,16 @@ const DeclGen = struct {...@@ -1752,18 +1797,16 @@ const DeclGen = struct {
1752 }1797 }
17531798
1754 /// This structure is used as helper for element-wise operations. It is intended1799 /// This structure is used as helper for element-wise operations. It is intended
1755 /// to be used with both vectors and single elements.1800 /// to be used with vectors, fake vectors (arrays) and single elements.
1756 const WipElementWise = struct {1801 const WipElementWise = struct {
1757 dg: *DeclGen,1802 dg: *DeclGen,
1758 result_ty: Type,1803 result_ty: Type,
1804 ty: Type,
1759 /// Always in direct representation.1805 /// Always in direct representation.
1760 result_ty_ref: CacheRef,1806 ty_ref: CacheRef,
1761 scalar_ty: Type,1807 ty_id: IdRef,
1762 /// Always in direct representation.1808 /// True if the input is an array type.
1763 scalar_ty_ref: CacheRef,1809 is_array: bool,
1764 scalar_ty_id: IdRef,
1765 /// True if the input is actually a vector type.
1766 is_vector: bool,
1767 /// The element-wise operation should fill these results before calling finalize().1810 /// The element-wise operation should fill these results before calling finalize().
1768 /// These should all be in **direct** representation! `finalize()` will convert1811 /// These should all be in **direct** representation! `finalize()` will convert
1769 /// them to indirect if required.1812 /// them to indirect if required.
...@@ -1774,29 +1817,28 @@ const DeclGen = struct {...@@ -1774,29 +1817,28 @@ const DeclGen = struct {
1774 }1817 }
17751818
1776 /// Utility function to extract the element at a particular index in an1819 /// Utility function to extract the element at a particular index in an
1777 /// input vector. This type is expected to be a vector if `wip.is_vector`, and1820 /// input array. This type is expected to be a fake vector (array) if `wip.is_array`, and
1778 /// a scalar otherwise.1821 /// a vector or scalar otherwise.
1779 fn elementAt(wip: WipElementWise, ty: Type, value: IdRef, index: usize) !IdRef {1822 fn elementAt(wip: WipElementWise, ty: Type, value: IdRef, index: usize) !IdRef {
1780 const mod = wip.dg.module;1823 const mod = wip.dg.module;
1781 if (wip.is_vector) {1824 if (wip.is_array) {
1782 assert(ty.isVector(mod));1825 assert(ty.isVector(mod));
1783 return try wip.dg.extractField(ty.childType(mod), value, @intCast(index));1826 return try wip.dg.extractField(ty.childType(mod), value, @intCast(index));
1784 } else {1827 } else {
1785 assert(!ty.isVector(mod));
1786 assert(index == 0);1828 assert(index == 0);
1787 return value;1829 return value;
1788 }1830 }
1789 }1831 }
17901832
1791 /// Turns the results of this WipElementWise into a result. This can either1833 /// Turns the results of this WipElementWise into a result. This can be
1792 /// be a vector or single element, depending on `result_ty`.1834 /// vectors, fake vectors (arrays) and single elements, depending on `result_ty`.
1793 /// After calling this function, this WIP is no longer usable.1835 /// After calling this function, this WIP is no longer usable.
1794 /// Results is in `direct` representation.1836 /// Results is in `direct` representation.
1795 fn finalize(wip: *WipElementWise) !IdRef {1837 fn finalize(wip: *WipElementWise) !IdRef {
1796 if (wip.is_vector) {1838 if (wip.is_array) {
1797 // Convert all the constituents to indirect, as required for the array.1839 // Convert all the constituents to indirect, as required for the array.
1798 for (wip.results) |*result| {1840 for (wip.results) |*result| {
1799 result.* = try wip.dg.convertToIndirect(wip.scalar_ty, result.*);1841 result.* = try wip.dg.convertToIndirect(wip.ty, result.*);
1800 }1842 }
1801 return try wip.dg.constructComposite(wip.result_ty, wip.results);1843 return try wip.dg.constructComposite(wip.result_ty, wip.results);
1802 } else {1844 } else {
...@@ -1806,33 +1848,30 @@ const DeclGen = struct {...@@ -1806,33 +1848,30 @@ const DeclGen = struct {
18061848
1807 /// Allocate a result id at a particular index, and return it.1849 /// Allocate a result id at a particular index, and return it.
1808 fn allocId(wip: *WipElementWise, index: usize) IdRef {1850 fn allocId(wip: *WipElementWise, index: usize) IdRef {
1809 assert(wip.is_vector or index == 0);1851 assert(wip.is_array or index == 0);
1810 wip.results[index] = wip.dg.spv.allocId();1852 wip.results[index] = wip.dg.spv.allocId();
1811 return wip.results[index];1853 return wip.results[index];
1812 }1854 }
1813 };1855 };
18141856
1815 /// Create a new element-wise operation.1857 /// Create a new element-wise operation.
1816 fn elementWise(self: *DeclGen, result_ty: Type) !WipElementWise {1858 fn elementWise(self: *DeclGen, result_ty: Type, force_element_wise: bool) !WipElementWise {
1817 const mod = self.module;1859 const mod = self.module;
1818 // For now, this operation also reasons in terms of `.direct` representation.1860 const is_array = result_ty.isVector(mod) and (!self.isVector(result_ty) or force_element_wise);
1819 const result_ty_ref = try self.resolveType(result_ty, .direct);1861 const num_results = if (is_array) result_ty.vectorLen(mod) else 1;
1820 const is_vector = result_ty.isVector(mod);
1821 const num_results = if (is_vector) result_ty.vectorLen(mod) else 1;
1822 const results = try self.gpa.alloc(IdRef, num_results);1862 const results = try self.gpa.alloc(IdRef, num_results);
1823 for (results) |*result| result.* = undefined;1863 @memset(results, undefined);
18241864
1825 const scalar_ty = result_ty.scalarType(mod);1865 const ty = if (is_array) result_ty.scalarType(mod) else result_ty;
1826 const scalar_ty_ref = try self.resolveType(scalar_ty, .direct);1866 const ty_ref = try self.resolveType(ty, .direct);
18271867
1828 return .{1868 return .{
1829 .dg = self,1869 .dg = self,
1830 .result_ty = result_ty,1870 .result_ty = result_ty,
1831 .result_ty_ref = result_ty_ref,1871 .ty = ty,
1832 .scalar_ty = scalar_ty,1872 .ty_ref = ty_ref,
1833 .scalar_ty_ref = scalar_ty_ref,1873 .ty_id = self.typeId(ty_ref),
1834 .scalar_ty_id = self.typeId(scalar_ty_ref),1874 .is_array = is_array,
1835 .is_vector = is_vector,
1836 .results = results,1875 .results = results,
1837 };1876 };
1838 }1877 }
...@@ -2160,7 +2199,6 @@ const DeclGen = struct {...@@ -2160,7 +2199,6 @@ const DeclGen = struct {
2160 fn genInst(self: *DeclGen, inst: Air.Inst.Index) !void {2199 fn genInst(self: *DeclGen, inst: Air.Inst.Index) !void {
2161 const mod = self.module;2200 const mod = self.module;
2162 const ip = &mod.intern_pool;2201 const ip = &mod.intern_pool;
2163 // TODO: remove now-redundant isUnused calls from AIR handler functions
2164 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip))2202 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip))
2165 return;2203 return;
21662204
...@@ -2312,11 +2350,11 @@ const DeclGen = struct {...@@ -2312,11 +2350,11 @@ const DeclGen = struct {
2312 }2350 }
23132351
2314 fn binOpSimple(self: *DeclGen, ty: Type, lhs_id: IdRef, rhs_id: IdRef, comptime opcode: Opcode) !IdRef {2352 fn binOpSimple(self: *DeclGen, ty: Type, lhs_id: IdRef, rhs_id: IdRef, comptime opcode: Opcode) !IdRef {
2315 var wip = try self.elementWise(ty);2353 var wip = try self.elementWise(ty, false);
2316 defer wip.deinit();2354 defer wip.deinit();
2317 for (0..wip.results.len) |i| {2355 for (0..wip.results.len) |i| {
2318 try self.func.body.emit(self.spv.gpa, opcode, .{2356 try self.func.body.emit(self.spv.gpa, opcode, .{
2319 .id_result_type = wip.scalar_ty_id,2357 .id_result_type = wip.ty_id,
2320 .id_result = wip.allocId(i),2358 .id_result = wip.allocId(i),
2321 .operand_1 = try wip.elementAt(ty, lhs_id, i),2359 .operand_1 = try wip.elementAt(ty, lhs_id, i),
2322 .operand_2 = try wip.elementAt(ty, rhs_id, i),2360 .operand_2 = try wip.elementAt(ty, rhs_id, i),
...@@ -2326,8 +2364,6 @@ const DeclGen = struct {...@@ -2326,8 +2364,6 @@ const DeclGen = struct {
2326 }2364 }
23272365
2328 fn airBinOpSimple(self: *DeclGen, inst: Air.Inst.Index, comptime opcode: Opcode) !?IdRef {2366 fn airBinOpSimple(self: *DeclGen, inst: Air.Inst.Index, comptime opcode: Opcode) !?IdRef {
2329 if (self.liveness.isUnused(inst)) return null;
2330
2331 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2367 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2332 const lhs_id = try self.resolve(bin_op.lhs);2368 const lhs_id = try self.resolve(bin_op.lhs);
2333 const rhs_id = try self.resolve(bin_op.rhs);2369 const rhs_id = try self.resolve(bin_op.rhs);
...@@ -2337,7 +2373,6 @@ const DeclGen = struct {...@@ -2337,7 +2373,6 @@ const DeclGen = struct {
2337 }2373 }
23382374
2339 fn airShift(self: *DeclGen, inst: Air.Inst.Index, comptime unsigned: Opcode, comptime signed: Opcode) !?IdRef {2375 fn airShift(self: *DeclGen, inst: Air.Inst.Index, comptime unsigned: Opcode, comptime signed: Opcode) !?IdRef {
2340 if (self.liveness.isUnused(inst)) return null;
2341 const mod = self.module;2376 const mod = self.module;
2342 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2377 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2343 const lhs_id = try self.resolve(bin_op.lhs);2378 const lhs_id = try self.resolve(bin_op.lhs);
...@@ -2345,7 +2380,7 @@ const DeclGen = struct {...@@ -2345,7 +2380,7 @@ const DeclGen = struct {
23452380
2346 const result_ty = self.typeOfIndex(inst);2381 const result_ty = self.typeOfIndex(inst);
2347 const shift_ty = self.typeOf(bin_op.rhs);2382 const shift_ty = self.typeOf(bin_op.rhs);
2348 const scalar_shift_ty_ref = try self.resolveType(shift_ty.scalarType(mod), .direct);2383 const shift_ty_ref = try self.resolveType(shift_ty, .direct);
23492384
2350 const info = self.arithmeticTypeInfo(result_ty);2385 const info = self.arithmeticTypeInfo(result_ty);
2351 switch (info.class) {2386 switch (info.class) {
...@@ -2354,7 +2389,7 @@ const DeclGen = struct {...@@ -2354,7 +2389,7 @@ const DeclGen = struct {
2354 .float, .bool => unreachable,2389 .float, .bool => unreachable,
2355 }2390 }
23562391
2357 var wip = try self.elementWise(result_ty);2392 var wip = try self.elementWise(result_ty, false);
2358 defer wip.deinit();2393 defer wip.deinit();
2359 for (wip.results, 0..) |*result_id, i| {2394 for (wip.results, 0..) |*result_id, i| {
2360 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);2395 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);
...@@ -2362,10 +2397,10 @@ const DeclGen = struct {...@@ -2362,10 +2397,10 @@ const DeclGen = struct {
23622397
2363 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,2398 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
2364 // so just manually upcast it if required.2399 // so just manually upcast it if required.
2365 const shift_id = if (scalar_shift_ty_ref != wip.scalar_ty_ref) blk: {2400 const shift_id = if (shift_ty_ref != wip.ty_ref) blk: {
2366 const shift_id = self.spv.allocId();2401 const shift_id = self.spv.allocId();
2367 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{2402 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
2368 .id_result_type = wip.scalar_ty_id,2403 .id_result_type = wip.ty_id,
2369 .id_result = shift_id,2404 .id_result = shift_id,
2370 .unsigned_value = rhs_elem_id,2405 .unsigned_value = rhs_elem_id,
2371 });2406 });
...@@ -2374,7 +2409,7 @@ const DeclGen = struct {...@@ -2374,7 +2409,7 @@ const DeclGen = struct {
23742409
2375 const value_id = self.spv.allocId();2410 const value_id = self.spv.allocId();
2376 const args = .{2411 const args = .{
2377 .id_result_type = wip.scalar_ty_id,2412 .id_result_type = wip.ty_id,
2378 .id_result = value_id,2413 .id_result = value_id,
2379 .base = lhs_elem_id,2414 .base = lhs_elem_id,
2380 .shift = shift_id,2415 .shift = shift_id,
...@@ -2386,14 +2421,12 @@ const DeclGen = struct {...@@ -2386,14 +2421,12 @@ const DeclGen = struct {
2386 try self.func.body.emit(self.spv.gpa, unsigned, args);2421 try self.func.body.emit(self.spv.gpa, unsigned, args);
2387 }2422 }
23882423
2389 result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, info);2424 result_id.* = try self.normalize(wip.ty_ref, value_id, info);
2390 }2425 }
2391 return try wip.finalize();2426 return try wip.finalize();
2392 }2427 }
23932428
2394 fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {2429 fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {
2395 if (self.liveness.isUnused(inst)) return null;
2396
2397 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;2430 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
2398 const lhs_id = try self.resolve(bin_op.lhs);2431 const lhs_id = try self.resolve(bin_op.lhs);
2399 const rhs_id = try self.resolve(bin_op.rhs);2432 const rhs_id = try self.resolve(bin_op.rhs);
...@@ -2405,14 +2438,14 @@ const DeclGen = struct {...@@ -2405,14 +2438,14 @@ const DeclGen = struct {
2405 fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef {2438 fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef {
2406 const info = self.arithmeticTypeInfo(result_ty);2439 const info = self.arithmeticTypeInfo(result_ty);
24072440
2408 var wip = try self.elementWise(result_ty);2441 var wip = try self.elementWise(result_ty, true);
2409 defer wip.deinit();2442 defer wip.deinit();
2410 for (wip.results, 0..) |*result_id, i| {2443 for (wip.results, 0..) |*result_id, i| {
2411 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);2444 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);
2412 const rhs_elem_id = try wip.elementAt(result_ty, rhs_id, i);2445 const rhs_elem_id = try wip.elementAt(result_ty, rhs_id, i);
24132446
2414 // TODO: Use fmin for OpenCL2447 // TODO: Use fmin for OpenCL
2415 const cmp_id = try self.cmp(op, Type.bool, wip.scalar_ty, lhs_elem_id, rhs_elem_id);2448 const cmp_id = try self.cmp(op, Type.bool, wip.ty, lhs_elem_id, rhs_elem_id);
2416 const selection_id = switch (info.class) {2449 const selection_id = switch (info.class) {
2417 .float => blk: {2450 .float => blk: {
2418 // cmp uses OpFOrd. When we have 0 [<>] nan this returns false,2451 // cmp uses OpFOrd. When we have 0 [<>] nan this returns false,
...@@ -2440,7 +2473,7 @@ const DeclGen = struct {...@@ -2440,7 +2473,7 @@ const DeclGen = struct {
24402473
2441 result_id.* = self.spv.allocId();2474 result_id.* = self.spv.allocId();
2442 try self.func.body.emit(self.spv.gpa, .OpSelect, .{2475 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2443 .id_result_type = wip.scalar_ty_id,2476 .id_result_type = wip.ty_id,
2444 .id_result = result_id.*,2477 .id_result = result_id.*,
2445 .condition = selection_id,2478 .condition = selection_id,
2446 .object_1 = lhs_elem_id,2479 .object_1 = lhs_elem_id,
...@@ -2505,7 +2538,6 @@ const DeclGen = struct {...@@ -2505,7 +2538,6 @@ const DeclGen = struct {
2505 comptime sop: Opcode,2538 comptime sop: Opcode,
2506 comptime uop: Opcode,2539 comptime uop: Opcode,
2507 ) !?IdRef {2540 ) !?IdRef {
2508 if (self.liveness.isUnused(inst)) return null;
25092541
2510 // LHS and RHS are guaranteed to have the same type, and AIR guarantees2542 // LHS and RHS are guaranteed to have the same type, and AIR guarantees
2511 // the result to be the same as the LHS and RHS, which matches SPIR-V.2543 // the result to be the same as the LHS and RHS, which matches SPIR-V.
...@@ -2545,7 +2577,7 @@ const DeclGen = struct {...@@ -2545,7 +2577,7 @@ const DeclGen = struct {
2545 .bool => unreachable,2577 .bool => unreachable,
2546 };2578 };
25472579
2548 var wip = try self.elementWise(ty);2580 var wip = try self.elementWise(ty, false);
2549 defer wip.deinit();2581 defer wip.deinit();
2550 for (wip.results, 0..) |*result_id, i| {2582 for (wip.results, 0..) |*result_id, i| {
2551 const lhs_elem_id = try wip.elementAt(ty, lhs_id, i);2583 const lhs_elem_id = try wip.elementAt(ty, lhs_id, i);
...@@ -2553,7 +2585,7 @@ const DeclGen = struct {...@@ -2553,7 +2585,7 @@ const DeclGen = struct {
25532585
2554 const value_id = self.spv.allocId();2586 const value_id = self.spv.allocId();
2555 const operands = .{2587 const operands = .{
2556 .id_result_type = wip.scalar_ty_id,2588 .id_result_type = wip.ty_id,
2557 .id_result = value_id,2589 .id_result = value_id,
2558 .operand_1 = lhs_elem_id,2590 .operand_1 = lhs_elem_id,
2559 .operand_2 = rhs_elem_id,2591 .operand_2 = rhs_elem_id,
...@@ -2568,26 +2600,24 @@ const DeclGen = struct {...@@ -2568,26 +2600,24 @@ const DeclGen = struct {
25682600
2569 // TODO: Trap on overflow? Probably going to be annoying.2601 // TODO: Trap on overflow? Probably going to be annoying.
2570 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.2602 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.
2571 result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, info);2603 result_id.* = try self.normalize(wip.ty_ref, value_id, info);
2572 }2604 }
25732605
2574 return try wip.finalize();2606 return try wip.finalize();
2575 }2607 }
25762608
2577 fn airAbs(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2609 fn airAbs(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2578 if (self.liveness.isUnused(inst)) return null;
2579
2580 const mod = self.module;2610 const mod = self.module;
2581 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;2611 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2582 const operand_id = try self.resolve(ty_op.operand);2612 const operand_id = try self.resolve(ty_op.operand);
2583 // Note: operand_ty may be signed, while ty is always unsigned!2613 // Note: operand_ty may be signed, while ty is always unsigned!
2584 const operand_ty = self.typeOf(ty_op.operand);2614 const operand_ty = self.typeOf(ty_op.operand);
2585 const ty = self.typeOfIndex(inst);2615 const result_ty = self.typeOfIndex(inst);
2586 const info = self.arithmeticTypeInfo(ty);2616 const info = self.arithmeticTypeInfo(result_ty);
2587 const operand_scalar_ty = operand_ty.scalarType(mod);2617 const operand_scalar_ty = operand_ty.scalarType(mod);
2588 const operand_scalar_ty_ref = try self.resolveType(operand_scalar_ty, .direct);2618 const operand_scalar_ty_ref = try self.resolveType(operand_scalar_ty, .direct);
25892619
2590 var wip = try self.elementWise(ty);2620 var wip = try self.elementWise(result_ty, true);
2591 defer wip.deinit();2621 defer wip.deinit();
25922622
2593 const zero_id = switch (info.class) {2623 const zero_id = switch (info.class) {
...@@ -2615,7 +2645,7 @@ const DeclGen = struct {...@@ -2615,7 +2645,7 @@ const DeclGen = struct {
2615 .composite_integer => unreachable, // TODO2645 .composite_integer => unreachable, // TODO
2616 .bool => unreachable,2646 .bool => unreachable,
2617 }2647 }
2618 const neg_norm_id = try self.normalize(wip.scalar_ty_ref, neg_id, info);2648 const neg_norm_id = try self.normalize(wip.ty_ref, neg_id, info);
26192649
2620 const gt_zero_id = try self.cmp(.gt, Type.bool, operand_scalar_ty, elem_id, zero_id);2650 const gt_zero_id = try self.cmp(.gt, Type.bool, operand_scalar_ty, elem_id, zero_id);
2621 const abs_id = self.spv.allocId();2651 const abs_id = self.spv.allocId();
...@@ -2627,7 +2657,7 @@ const DeclGen = struct {...@@ -2627,7 +2657,7 @@ const DeclGen = struct {
2627 .object_2 = neg_norm_id,2657 .object_2 = neg_norm_id,
2628 });2658 });
2629 // For Shader, we may need to cast from signed to unsigned here.2659 // For Shader, we may need to cast from signed to unsigned here.
2630 result_id.* = try self.bitCast(wip.scalar_ty, operand_scalar_ty, abs_id);2660 result_id.* = try self.bitCast(wip.ty, operand_scalar_ty, abs_id);
2631 }2661 }
2632 return try wip.finalize();2662 return try wip.finalize();
2633 }2663 }
...@@ -2639,8 +2669,7 @@ const DeclGen = struct {...@@ -2639,8 +2669,7 @@ const DeclGen = struct {
2639 comptime ucmp: Opcode,2669 comptime ucmp: Opcode,
2640 comptime scmp: Opcode,2670 comptime scmp: Opcode,
2641 ) !?IdRef {2671 ) !?IdRef {
2642 if (self.liveness.isUnused(inst)) return null;2672 const mod = self.module;
2643
2644 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;2673 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2645 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2674 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
2646 const lhs = try self.resolve(extra.lhs);2675 const lhs = try self.resolve(extra.lhs);
...@@ -2651,6 +2680,10 @@ const DeclGen = struct {...@@ -2651,6 +2680,10 @@ const DeclGen = struct {
2651 const ov_ty = result_ty.structFieldType(1, self.module);2680 const ov_ty = result_ty.structFieldType(1, self.module);
26522681
2653 const bool_ty_ref = try self.resolveType(Type.bool, .direct);2682 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
2683 const cmp_ty_ref = if (self.isVector(operand_ty))
2684 try self.spv.vectorType(operand_ty.vectorLen(mod), bool_ty_ref)
2685 else
2686 bool_ty_ref;
26542687
2655 const info = self.arithmeticTypeInfo(operand_ty);2688 const info = self.arithmeticTypeInfo(operand_ty);
2656 switch (info.class) {2689 switch (info.class) {
...@@ -2659,9 +2692,9 @@ const DeclGen = struct {...@@ -2659,9 +2692,9 @@ const DeclGen = struct {
2659 .float, .bool => unreachable,2692 .float, .bool => unreachable,
2660 }2693 }
26612694
2662 var wip_result = try self.elementWise(operand_ty);2695 var wip_result = try self.elementWise(operand_ty, false);
2663 defer wip_result.deinit();2696 defer wip_result.deinit();
2664 var wip_ov = try self.elementWise(ov_ty);2697 var wip_ov = try self.elementWise(ov_ty, false);
2665 defer wip_ov.deinit();2698 defer wip_ov.deinit();
2666 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {2699 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {
2667 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);2700 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);
...@@ -2671,14 +2704,14 @@ const DeclGen = struct {...@@ -2671,14 +2704,14 @@ const DeclGen = struct {
2671 const value_id = self.spv.allocId();2704 const value_id = self.spv.allocId();
26722705
2673 try self.func.body.emit(self.spv.gpa, add, .{2706 try self.func.body.emit(self.spv.gpa, add, .{
2674 .id_result_type = wip_result.scalar_ty_id,2707 .id_result_type = wip_result.ty_id,
2675 .id_result = value_id,2708 .id_result = value_id,
2676 .operand_1 = lhs_elem_id,2709 .operand_1 = lhs_elem_id,
2677 .operand_2 = rhs_elem_id,2710 .operand_2 = rhs_elem_id,
2678 });2711 });
26792712
2680 // Normalize the result so that the comparisons go well2713 // Normalize the result so that the comparisons go well
2681 result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info);2714 result_id.* = try self.normalize(wip_result.ty_ref, value_id, info);
26822715
2683 const overflowed_id = switch (info.signedness) {2716 const overflowed_id = switch (info.signedness) {
2684 .unsigned => blk: {2717 .unsigned => blk: {
...@@ -2686,7 +2719,7 @@ const DeclGen = struct {...@@ -2686,7 +2719,7 @@ const DeclGen = struct {
2686 // For subtraction the conditions need to be swapped.2719 // For subtraction the conditions need to be swapped.
2687 const overflowed_id = self.spv.allocId();2720 const overflowed_id = self.spv.allocId();
2688 try self.func.body.emit(self.spv.gpa, ucmp, .{2721 try self.func.body.emit(self.spv.gpa, ucmp, .{
2689 .id_result_type = self.typeId(bool_ty_ref),2722 .id_result_type = self.typeId(cmp_ty_ref),
2690 .id_result = overflowed_id,2723 .id_result = overflowed_id,
2691 .operand_1 = result_id.*,2724 .operand_1 = result_id.*,
2692 .operand_2 = lhs_elem_id,2725 .operand_2 = lhs_elem_id,
...@@ -2712,9 +2745,9 @@ const DeclGen = struct {...@@ -2712,9 +2745,9 @@ const DeclGen = struct {
2712 // = (rhs < 0) == (lhs > value)2745 // = (rhs < 0) == (lhs > value)
27132746
2714 const rhs_lt_zero_id = self.spv.allocId();2747 const rhs_lt_zero_id = self.spv.allocId();
2715 const zero_id = try self.constInt(wip_result.scalar_ty_ref, 0);2748 const zero_id = try self.constInt(wip_result.ty_ref, 0);
2716 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{2749 try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{
2717 .id_result_type = self.typeId(bool_ty_ref),2750 .id_result_type = self.typeId(cmp_ty_ref),
2718 .id_result = rhs_lt_zero_id,2751 .id_result = rhs_lt_zero_id,
2719 .operand_1 = rhs_elem_id,2752 .operand_1 = rhs_elem_id,
2720 .operand_2 = zero_id,2753 .operand_2 = zero_id,
...@@ -2722,7 +2755,7 @@ const DeclGen = struct {...@@ -2722,7 +2755,7 @@ const DeclGen = struct {
27222755
2723 const value_gt_lhs_id = self.spv.allocId();2756 const value_gt_lhs_id = self.spv.allocId();
2724 try self.func.body.emit(self.spv.gpa, scmp, .{2757 try self.func.body.emit(self.spv.gpa, scmp, .{
2725 .id_result_type = self.typeId(bool_ty_ref),2758 .id_result_type = self.typeId(cmp_ty_ref),
2726 .id_result = value_gt_lhs_id,2759 .id_result = value_gt_lhs_id,
2727 .operand_1 = lhs_elem_id,2760 .operand_1 = lhs_elem_id,
2728 .operand_2 = result_id.*,2761 .operand_2 = result_id.*,
...@@ -2730,7 +2763,7 @@ const DeclGen = struct {...@@ -2730,7 +2763,7 @@ const DeclGen = struct {
27302763
2731 const overflowed_id = self.spv.allocId();2764 const overflowed_id = self.spv.allocId();
2732 try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{2765 try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{
2733 .id_result_type = self.typeId(bool_ty_ref),2766 .id_result_type = self.typeId(cmp_ty_ref),
2734 .id_result = overflowed_id,2767 .id_result = overflowed_id,
2735 .operand_1 = rhs_lt_zero_id,2768 .operand_1 = rhs_lt_zero_id,
2736 .operand_2 = value_gt_lhs_id,2769 .operand_2 = value_gt_lhs_id,
...@@ -2739,7 +2772,7 @@ const DeclGen = struct {...@@ -2739,7 +2772,7 @@ const DeclGen = struct {
2739 },2772 },
2740 };2773 };
27412774
2742 ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id);2775 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);
2743 }2776 }
27442777
2745 return try self.constructComposite(2778 return try self.constructComposite(
...@@ -2749,7 +2782,6 @@ const DeclGen = struct {...@@ -2749,7 +2782,6 @@ const DeclGen = struct {
2749 }2782 }
27502783
2751 fn airShlOverflow(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2784 fn airShlOverflow(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2752 if (self.liveness.isUnused(inst)) return null;
2753 const mod = self.module;2785 const mod = self.module;
2754 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;2786 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2755 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2787 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
...@@ -2759,11 +2791,15 @@ const DeclGen = struct {...@@ -2759,11 +2791,15 @@ const DeclGen = struct {
2759 const result_ty = self.typeOfIndex(inst);2791 const result_ty = self.typeOfIndex(inst);
2760 const operand_ty = self.typeOf(extra.lhs);2792 const operand_ty = self.typeOf(extra.lhs);
2761 const shift_ty = self.typeOf(extra.rhs);2793 const shift_ty = self.typeOf(extra.rhs);
2762 const scalar_shift_ty_ref = try self.resolveType(shift_ty.scalarType(mod), .direct);2794 const shift_ty_ref = try self.resolveType(shift_ty, .direct);
27632795
2764 const ov_ty = result_ty.structFieldType(1, self.module);2796 const ov_ty = result_ty.structFieldType(1, self.module);
27652797
2766 const bool_ty_ref = try self.resolveType(Type.bool, .direct);2798 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
2799 const cmp_ty_ref = if (self.isVector(operand_ty))
2800 try self.spv.vectorType(operand_ty.vectorLen(mod), bool_ty_ref)
2801 else
2802 bool_ty_ref;
27672803
2768 const info = self.arithmeticTypeInfo(operand_ty);2804 const info = self.arithmeticTypeInfo(operand_ty);
2769 switch (info.class) {2805 switch (info.class) {
...@@ -2772,9 +2808,9 @@ const DeclGen = struct {...@@ -2772,9 +2808,9 @@ const DeclGen = struct {
2772 .float, .bool => unreachable,2808 .float, .bool => unreachable,
2773 }2809 }
27742810
2775 var wip_result = try self.elementWise(operand_ty);2811 var wip_result = try self.elementWise(operand_ty, false);
2776 defer wip_result.deinit();2812 defer wip_result.deinit();
2777 var wip_ov = try self.elementWise(ov_ty);2813 var wip_ov = try self.elementWise(ov_ty, false);
2778 defer wip_ov.deinit();2814 defer wip_ov.deinit();
2779 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {2815 for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| {
2780 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);2816 const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i);
...@@ -2782,10 +2818,10 @@ const DeclGen = struct {...@@ -2782,10 +2818,10 @@ const DeclGen = struct {
27822818
2783 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,2819 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
2784 // so just manually upcast it if required.2820 // so just manually upcast it if required.
2785 const shift_id = if (scalar_shift_ty_ref != wip_result.scalar_ty_ref) blk: {2821 const shift_id = if (shift_ty_ref != wip_result.ty_ref) blk: {
2786 const shift_id = self.spv.allocId();2822 const shift_id = self.spv.allocId();
2787 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{2823 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
2788 .id_result_type = wip_result.scalar_ty_id,2824 .id_result_type = wip_result.ty_id,
2789 .id_result = shift_id,2825 .id_result = shift_id,
2790 .unsigned_value = rhs_elem_id,2826 .unsigned_value = rhs_elem_id,
2791 });2827 });
...@@ -2794,18 +2830,18 @@ const DeclGen = struct {...@@ -2794,18 +2830,18 @@ const DeclGen = struct {
27942830
2795 const value_id = self.spv.allocId();2831 const value_id = self.spv.allocId();
2796 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{2832 try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{
2797 .id_result_type = wip_result.scalar_ty_id,2833 .id_result_type = wip_result.ty_id,
2798 .id_result = value_id,2834 .id_result = value_id,
2799 .base = lhs_elem_id,2835 .base = lhs_elem_id,
2800 .shift = shift_id,2836 .shift = shift_id,
2801 });2837 });
2802 result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info);2838 result_id.* = try self.normalize(wip_result.ty_ref, value_id, info);
28032839
2804 const right_shift_id = self.spv.allocId();2840 const right_shift_id = self.spv.allocId();
2805 switch (info.signedness) {2841 switch (info.signedness) {
2806 .signed => {2842 .signed => {
2807 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{2843 try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{
2808 .id_result_type = wip_result.scalar_ty_id,2844 .id_result_type = wip_result.ty_id,
2809 .id_result = right_shift_id,2845 .id_result = right_shift_id,
2810 .base = result_id.*,2846 .base = result_id.*,
2811 .shift = shift_id,2847 .shift = shift_id,
...@@ -2813,7 +2849,7 @@ const DeclGen = struct {...@@ -2813,7 +2849,7 @@ const DeclGen = struct {
2813 },2849 },
2814 .unsigned => {2850 .unsigned => {
2815 try self.func.body.emit(self.spv.gpa, .OpShiftRightLogical, .{2851 try self.func.body.emit(self.spv.gpa, .OpShiftRightLogical, .{
2816 .id_result_type = wip_result.scalar_ty_id,2852 .id_result_type = wip_result.ty_id,
2817 .id_result = right_shift_id,2853 .id_result = right_shift_id,
2818 .base = result_id.*,2854 .base = result_id.*,
2819 .shift = shift_id,2855 .shift = shift_id,
...@@ -2823,13 +2859,13 @@ const DeclGen = struct {...@@ -2823,13 +2859,13 @@ const DeclGen = struct {
28232859
2824 const overflowed_id = self.spv.allocId();2860 const overflowed_id = self.spv.allocId();
2825 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{2861 try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{
2826 .id_result_type = self.typeId(bool_ty_ref),2862 .id_result_type = self.typeId(cmp_ty_ref),
2827 .id_result = overflowed_id,2863 .id_result = overflowed_id,
2828 .operand_1 = lhs_elem_id,2864 .operand_1 = lhs_elem_id,
2829 .operand_2 = right_shift_id,2865 .operand_2 = right_shift_id,
2830 });2866 });
28312867
2832 ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id);2868 ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id);
2833 }2869 }
28342870
2835 return try self.constructComposite(2871 return try self.constructComposite(
...@@ -2839,8 +2875,6 @@ const DeclGen = struct {...@@ -2839,8 +2875,6 @@ const DeclGen = struct {
2839 }2875 }
28402876
2841 fn airMulAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2877 fn airMulAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2842 if (self.liveness.isUnused(inst)) return null;
2843
2844 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;2878 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
2845 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;2879 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
28462880
...@@ -2853,19 +2887,19 @@ const DeclGen = struct {...@@ -2853,19 +2887,19 @@ const DeclGen = struct {
2853 const info = self.arithmeticTypeInfo(ty);2887 const info = self.arithmeticTypeInfo(ty);
2854 assert(info.class == .float); // .mul_add is only emitted for floats2888 assert(info.class == .float); // .mul_add is only emitted for floats
28552889
2856 var wip = try self.elementWise(ty);2890 var wip = try self.elementWise(ty, false);
2857 defer wip.deinit();2891 defer wip.deinit();
2858 for (0..wip.results.len) |i| {2892 for (0..wip.results.len) |i| {
2859 const mul_result = self.spv.allocId();2893 const mul_result = self.spv.allocId();
2860 try self.func.body.emit(self.spv.gpa, .OpFMul, .{2894 try self.func.body.emit(self.spv.gpa, .OpFMul, .{
2861 .id_result_type = wip.scalar_ty_id,2895 .id_result_type = wip.ty_id,
2862 .id_result = mul_result,2896 .id_result = mul_result,
2863 .operand_1 = try wip.elementAt(ty, mulend1, i),2897 .operand_1 = try wip.elementAt(ty, mulend1, i),
2864 .operand_2 = try wip.elementAt(ty, mulend2, i),2898 .operand_2 = try wip.elementAt(ty, mulend2, i),
2865 });2899 });
28662900
2867 try self.func.body.emit(self.spv.gpa, .OpFAdd, .{2901 try self.func.body.emit(self.spv.gpa, .OpFAdd, .{
2868 .id_result_type = wip.scalar_ty_id,2902 .id_result_type = wip.ty_id,
2869 .id_result = wip.allocId(i),2903 .id_result = wip.allocId(i),
2870 .operand_1 = mul_result,2904 .operand_1 = mul_result,
2871 .operand_2 = try wip.elementAt(ty, addend, i),2905 .operand_2 = try wip.elementAt(ty, addend, i),
...@@ -2875,20 +2909,16 @@ const DeclGen = struct {...@@ -2875,20 +2909,16 @@ const DeclGen = struct {
2875 }2909 }
28762910
2877 fn airSplat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2911 fn airSplat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2878 if (self.liveness.isUnused(inst)) return null;
2879 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;2912 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
2880 const operand_id = try self.resolve(ty_op.operand);2913 const operand_id = try self.resolve(ty_op.operand);
2881 const result_ty = self.typeOfIndex(inst);2914 const result_ty = self.typeOfIndex(inst);
2882 var wip = try self.elementWise(result_ty);2915 var wip = try self.elementWise(result_ty, true);
2883 defer wip.deinit();2916 defer wip.deinit();
2884 for (wip.results) |*result_id| {2917 @memset(wip.results, operand_id);
2885 result_id.* = operand_id;
2886 }
2887 return try wip.finalize();2918 return try wip.finalize();
2888 }2919 }
28892920
2890 fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2921 fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2891 if (self.liveness.isUnused(inst)) return null;
2892 const mod = self.module;2922 const mod = self.module;
2893 const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce;2923 const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
2894 const operand = try self.resolve(reduce.operand);2924 const operand = try self.resolve(reduce.operand);
...@@ -2956,7 +2986,6 @@ const DeclGen = struct {...@@ -2956,7 +2986,6 @@ const DeclGen = struct {
29562986
2957 fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {2987 fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
2958 const mod = self.module;2988 const mod = self.module;
2959 if (self.liveness.isUnused(inst)) return null;
2960 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;2989 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
2961 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;2990 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
2962 const a = try self.resolve(extra.a);2991 const a = try self.resolve(extra.a);
...@@ -2965,20 +2994,20 @@ const DeclGen = struct {...@@ -2965,20 +2994,20 @@ const DeclGen = struct {
29652994
2966 const ty = self.typeOfIndex(inst);2995 const ty = self.typeOfIndex(inst);
29672996
2968 var wip = try self.elementWise(ty);2997 var wip = try self.elementWise(ty, true);
2969 defer wip.deinit();2998 defer wip.deinit();
2970 for (wip.results, 0..) |*result_id, i| {2999 for (wip.results, 0..) |*result_id, i| {
2971 const elem = try mask.elemValue(mod, i);3000 const elem = try mask.elemValue(mod, i);
2972 if (elem.isUndef(mod)) {3001 if (elem.isUndef(mod)) {
2973 result_id.* = try self.spv.constUndef(wip.scalar_ty_ref);3002 result_id.* = try self.spv.constUndef(wip.ty_ref);
2974 continue;3003 continue;
2975 }3004 }
29763005
2977 const index = elem.toSignedInt(mod);3006 const index = elem.toSignedInt(mod);
2978 if (index >= 0) {3007 if (index >= 0) {
2979 result_id.* = try self.extractField(wip.scalar_ty, a, @intCast(index));3008 result_id.* = try self.extractField(wip.ty, a, @intCast(index));
2980 } else {3009 } else {
2981 result_id.* = try self.extractField(wip.scalar_ty, b, @intCast(~index));3010 result_id.* = try self.extractField(wip.ty, b, @intCast(~index));
2982 }3011 }
2983 }3012 }
2984 return try wip.finalize();3013 return try wip.finalize();
...@@ -3069,7 +3098,6 @@ const DeclGen = struct {...@@ -3069,7 +3098,6 @@ const DeclGen = struct {
3069 }3098 }
30703099
3071 fn airPtrAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3100 fn airPtrAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3072 if (self.liveness.isUnused(inst)) return null;
3073 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3101 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3074 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;3102 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
3075 const ptr_id = try self.resolve(bin_op.lhs);3103 const ptr_id = try self.resolve(bin_op.lhs);
...@@ -3081,7 +3109,6 @@ const DeclGen = struct {...@@ -3081,7 +3109,6 @@ const DeclGen = struct {
3081 }3109 }
30823110
3083 fn airPtrSub(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3111 fn airPtrSub(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3084 if (self.liveness.isUnused(inst)) return null;
3085 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3112 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3086 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;3113 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
3087 const ptr_id = try self.resolve(bin_op.lhs);3114 const ptr_id = try self.resolve(bin_op.lhs);
...@@ -3188,7 +3215,7 @@ const DeclGen = struct {...@@ -3188,7 +3215,7 @@ const DeclGen = struct {
3188 return result_id;3215 return result_id;
3189 },3216 },
3190 .Vector => {3217 .Vector => {
3191 var wip = try self.elementWise(result_ty);3218 var wip = try self.elementWise(result_ty, true);
3192 defer wip.deinit();3219 defer wip.deinit();
3193 const scalar_ty = ty.scalarType(mod);3220 const scalar_ty = ty.scalarType(mod);
3194 for (wip.results, 0..) |*result_id, i| {3221 for (wip.results, 0..) |*result_id, i| {
...@@ -3257,7 +3284,6 @@ const DeclGen = struct {...@@ -3257,7 +3284,6 @@ const DeclGen = struct {
3257 inst: Air.Inst.Index,3284 inst: Air.Inst.Index,
3258 comptime op: std.math.CompareOperator,3285 comptime op: std.math.CompareOperator,
3259 ) !?IdRef {3286 ) !?IdRef {
3260 if (self.liveness.isUnused(inst)) return null;
3261 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3287 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3262 const lhs_id = try self.resolve(bin_op.lhs);3288 const lhs_id = try self.resolve(bin_op.lhs);
3263 const rhs_id = try self.resolve(bin_op.rhs);3289 const rhs_id = try self.resolve(bin_op.rhs);
...@@ -3268,8 +3294,6 @@ const DeclGen = struct {...@@ -3268,8 +3294,6 @@ const DeclGen = struct {
3268 }3294 }
32693295
3270 fn airVectorCmp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3296 fn airVectorCmp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3271 if (self.liveness.isUnused(inst)) return null;
3272
3273 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3297 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3274 const vec_cmp = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;3298 const vec_cmp = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
3275 const lhs_id = try self.resolve(vec_cmp.lhs);3299 const lhs_id = try self.resolve(vec_cmp.lhs);
...@@ -3351,7 +3375,6 @@ const DeclGen = struct {...@@ -3351,7 +3375,6 @@ const DeclGen = struct {
3351 }3375 }
33523376
3353 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3377 fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3354 if (self.liveness.isUnused(inst)) return null;
3355 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3378 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3356 const operand_id = try self.resolve(ty_op.operand);3379 const operand_id = try self.resolve(ty_op.operand);
3357 const operand_ty = self.typeOf(ty_op.operand);3380 const operand_ty = self.typeOf(ty_op.operand);
...@@ -3360,8 +3383,6 @@ const DeclGen = struct {...@@ -3360,8 +3383,6 @@ const DeclGen = struct {
3360 }3383 }
33613384
3362 fn airIntCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3385 fn airIntCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3363 if (self.liveness.isUnused(inst)) return null;
3364
3365 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3386 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3366 const operand_id = try self.resolve(ty_op.operand);3387 const operand_id = try self.resolve(ty_op.operand);
3367 const src_ty = self.typeOf(ty_op.operand);3388 const src_ty = self.typeOf(ty_op.operand);
...@@ -3374,19 +3395,19 @@ const DeclGen = struct {...@@ -3374,19 +3395,19 @@ const DeclGen = struct {
3374 return operand_id;3395 return operand_id;
3375 }3396 }
33763397
3377 var wip = try self.elementWise(dst_ty);3398 var wip = try self.elementWise(dst_ty, false);
3378 defer wip.deinit();3399 defer wip.deinit();
3379 for (wip.results, 0..) |*result_id, i| {3400 for (wip.results, 0..) |*result_id, i| {
3380 const elem_id = try wip.elementAt(src_ty, operand_id, i);3401 const elem_id = try wip.elementAt(src_ty, operand_id, i);
3381 const value_id = self.spv.allocId();3402 const value_id = self.spv.allocId();
3382 switch (dst_info.signedness) {3403 switch (dst_info.signedness) {
3383 .signed => try self.func.body.emit(self.spv.gpa, .OpSConvert, .{3404 .signed => try self.func.body.emit(self.spv.gpa, .OpSConvert, .{
3384 .id_result_type = wip.scalar_ty_id,3405 .id_result_type = wip.ty_id,
3385 .id_result = value_id,3406 .id_result = value_id,
3386 .signed_value = elem_id,3407 .signed_value = elem_id,
3387 }),3408 }),
3388 .unsigned => try self.func.body.emit(self.spv.gpa, .OpUConvert, .{3409 .unsigned => try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
3389 .id_result_type = wip.scalar_ty_id,3410 .id_result_type = wip.ty_id,
3390 .id_result = value_id,3411 .id_result = value_id,
3391 .unsigned_value = elem_id,3412 .unsigned_value = elem_id,
3392 }),3413 }),
...@@ -3397,7 +3418,7 @@ const DeclGen = struct {...@@ -3397,7 +3418,7 @@ const DeclGen = struct {
3397 // type, we don't need to normalize when growing the type. The3418 // type, we don't need to normalize when growing the type. The
3398 // representation is already the same.3419 // representation is already the same.
3399 if (dst_info.bits < src_info.bits) {3420 if (dst_info.bits < src_info.bits) {
3400 result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, dst_info);3421 result_id.* = try self.normalize(wip.ty_ref, value_id, dst_info);
3401 } else {3422 } else {
3402 result_id.* = value_id;3423 result_id.* = value_id;
3403 }3424 }
...@@ -3417,16 +3438,12 @@ const DeclGen = struct {...@@ -3417,16 +3438,12 @@ const DeclGen = struct {
3417 }3438 }
34183439
3419 fn airIntFromPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3440 fn airIntFromPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3420 if (self.liveness.isUnused(inst)) return null;
3421
3422 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;3441 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3423 const operand_id = try self.resolve(un_op);3442 const operand_id = try self.resolve(un_op);
3424 return try self.intFromPtr(operand_id);3443 return try self.intFromPtr(operand_id);
3425 }3444 }
34263445
3427 fn airFloatFromInt(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3446 fn airFloatFromInt(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3428 if (self.liveness.isUnused(inst)) return null;
3429
3430 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3447 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3431 const operand_ty = self.typeOf(ty_op.operand);3448 const operand_ty = self.typeOf(ty_op.operand);
3432 const operand_id = try self.resolve(ty_op.operand);3449 const operand_id = try self.resolve(ty_op.operand);
...@@ -3451,8 +3468,6 @@ const DeclGen = struct {...@@ -3451,8 +3468,6 @@ const DeclGen = struct {
3451 }3468 }
34523469
3453 fn airIntFromFloat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3470 fn airIntFromFloat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3454 if (self.liveness.isUnused(inst)) return null;
3455
3456 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3471 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3457 const operand_id = try self.resolve(ty_op.operand);3472 const operand_id = try self.resolve(ty_op.operand);
3458 const dest_ty = self.typeOfIndex(inst);3473 const dest_ty = self.typeOfIndex(inst);
...@@ -3476,24 +3491,20 @@ const DeclGen = struct {...@@ -3476,24 +3491,20 @@ const DeclGen = struct {
3476 }3491 }
34773492
3478 fn airIntFromBool(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3493 fn airIntFromBool(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3479 if (self.liveness.isUnused(inst)) return null;
3480
3481 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;3494 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
3482 const operand_id = try self.resolve(un_op);3495 const operand_id = try self.resolve(un_op);
3483 const result_ty = self.typeOfIndex(inst);3496 const result_ty = self.typeOfIndex(inst);
34843497
3485 var wip = try self.elementWise(result_ty);3498 var wip = try self.elementWise(result_ty, false);
3486 defer wip.deinit();3499 defer wip.deinit();
3487 for (wip.results, 0..) |*result_id, i| {3500 for (wip.results, 0..) |*result_id, i| {
3488 const elem_id = try wip.elementAt(Type.bool, operand_id, i);3501 const elem_id = try wip.elementAt(Type.bool, operand_id, i);
3489 result_id.* = try self.intFromBool(wip.scalar_ty_ref, elem_id);3502 result_id.* = try self.intFromBool(wip.ty_ref, elem_id);
3490 }3503 }
3491 return try wip.finalize();3504 return try wip.finalize();
3492 }3505 }
34933506
3494 fn airFloatCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3507 fn airFloatCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3495 if (self.liveness.isUnused(inst)) return null;
3496
3497 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3508 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3498 const operand_id = try self.resolve(ty_op.operand);3509 const operand_id = try self.resolve(ty_op.operand);
3499 const dest_ty = self.typeOfIndex(inst);3510 const dest_ty = self.typeOfIndex(inst);
...@@ -3509,18 +3520,17 @@ const DeclGen = struct {...@@ -3509,18 +3520,17 @@ const DeclGen = struct {
3509 }3520 }
35103521
3511 fn airNot(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3522 fn airNot(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3512 if (self.liveness.isUnused(inst)) return null;
3513 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3523 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3514 const operand_id = try self.resolve(ty_op.operand);3524 const operand_id = try self.resolve(ty_op.operand);
3515 const result_ty = self.typeOfIndex(inst);3525 const result_ty = self.typeOfIndex(inst);
3516 const info = self.arithmeticTypeInfo(result_ty);3526 const info = self.arithmeticTypeInfo(result_ty);
35173527
3518 var wip = try self.elementWise(result_ty);3528 var wip = try self.elementWise(result_ty, false);
3519 defer wip.deinit();3529 defer wip.deinit();
35203530
3521 for (0..wip.results.len) |i| {3531 for (0..wip.results.len) |i| {
3522 const args = .{3532 const args = .{
3523 .id_result_type = wip.scalar_ty_id,3533 .id_result_type = wip.ty_id,
3524 .id_result = wip.allocId(i),3534 .id_result = wip.allocId(i),
3525 .operand = try wip.elementAt(result_ty, operand_id, i),3535 .operand = try wip.elementAt(result_ty, operand_id, i),
3526 };3536 };
...@@ -3541,8 +3551,6 @@ const DeclGen = struct {...@@ -3541,8 +3551,6 @@ const DeclGen = struct {
3541 }3551 }
35423552
3543 fn airArrayToSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3553 fn airArrayToSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3544 if (self.liveness.isUnused(inst)) return null;
3545
3546 const mod = self.module;3554 const mod = self.module;
3547 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3555 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3548 const array_ptr_ty = self.typeOf(ty_op.operand);3556 const array_ptr_ty = self.typeOf(ty_op.operand);
...@@ -3563,15 +3571,10 @@ const DeclGen = struct {...@@ -3563,15 +3571,10 @@ const DeclGen = struct {
3563 // Convert the pointer-to-array to a pointer to the first element.3571 // Convert the pointer-to-array to a pointer to the first element.
3564 try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0});3572 try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0});
35653573
3566 return try self.constructComposite(3574 return try self.constructComposite(slice_ty, &.{ elem_ptr_id, len_id });
3567 slice_ty,
3568 &.{ elem_ptr_id, len_id },
3569 );
3570 }3575 }
35713576
3572 fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3577 fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3573 if (self.liveness.isUnused(inst)) return null;
3574
3575 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3578 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3576 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;3579 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
3577 const ptr_id = try self.resolve(bin_op.lhs);3580 const ptr_id = try self.resolve(bin_op.lhs);
...@@ -3580,15 +3583,10 @@ const DeclGen = struct {...@@ -3580,15 +3583,10 @@ const DeclGen = struct {
35803583
3581 // Note: Types should not need to be converted to direct, these types3584 // Note: Types should not need to be converted to direct, these types
3582 // dont need to be converted.3585 // dont need to be converted.
3583 return try self.constructComposite(3586 return try self.constructComposite(slice_ty, &.{ ptr_id, len_id });
3584 slice_ty,
3585 &.{ ptr_id, len_id },
3586 );
3587 }3587 }
35883588
3589 fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3589 fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3590 if (self.liveness.isUnused(inst)) return null;
3591
3592 const mod = self.module;3590 const mod = self.module;
3593 const ip = &mod.intern_pool;3591 const ip = &mod.intern_pool;
3594 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3592 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
...@@ -3710,7 +3708,6 @@ const DeclGen = struct {...@@ -3710,7 +3708,6 @@ const DeclGen = struct {
3710 }3708 }
37113709
3712 fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {3710 fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {
3713 if (self.liveness.isUnused(inst)) return null;
3714 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3711 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3715 const field_ty = self.typeOfIndex(inst);3712 const field_ty = self.typeOfIndex(inst);
3716 const operand_id = try self.resolve(ty_op.operand);3713 const operand_id = try self.resolve(ty_op.operand);
...@@ -3767,8 +3764,6 @@ const DeclGen = struct {...@@ -3767,8 +3764,6 @@ const DeclGen = struct {
3767 }3764 }
37683765
3769 fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3766 fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3770 if (self.liveness.isUnused(inst)) return null;
3771
3772 const mod = self.module;3767 const mod = self.module;
3773 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3768 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3774 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;3769 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
...@@ -3786,8 +3781,6 @@ const DeclGen = struct {...@@ -3786,8 +3781,6 @@ const DeclGen = struct {
3786 }3781 }
37873782
3788 fn airArrayElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3783 fn airArrayElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3789 if (self.liveness.isUnused(inst)) return null;
3790
3791 const mod = self.module;3784 const mod = self.module;
3792 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3785 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3793 const array_ty = self.typeOf(bin_op.lhs);3786 const array_ty = self.typeOf(bin_op.lhs);
...@@ -3808,8 +3801,6 @@ const DeclGen = struct {...@@ -3808,8 +3801,6 @@ const DeclGen = struct {
3808 }3801 }
38093802
3810 fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3803 fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3811 if (self.liveness.isUnused(inst)) return null;
3812
3813 const mod = self.module;3804 const mod = self.module;
3814 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;3805 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
3815 const ptr_ty = self.typeOf(bin_op.lhs);3806 const ptr_ty = self.typeOf(bin_op.lhs);
...@@ -3866,8 +3857,6 @@ const DeclGen = struct {...@@ -3866,8 +3857,6 @@ const DeclGen = struct {
3866 }3857 }
38673858
3868 fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3859 fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3869 if (self.liveness.isUnused(inst)) return null;
3870
3871 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;3860 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
3872 const un_ty = self.typeOf(ty_op.operand);3861 const un_ty = self.typeOf(ty_op.operand);
38733862
...@@ -3951,8 +3940,6 @@ const DeclGen = struct {...@@ -3951,8 +3940,6 @@ const DeclGen = struct {
3951 }3940 }
39523941
3953 fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3942 fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3954 if (self.liveness.isUnused(inst)) return null;
3955
3956 const mod = self.module;3943 const mod = self.module;
3957 const ip = &mod.intern_pool;3944 const ip = &mod.intern_pool;
3958 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3945 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
...@@ -3969,8 +3956,6 @@ const DeclGen = struct {...@@ -3969,8 +3956,6 @@ const DeclGen = struct {
3969 }3956 }
39703957
3971 fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {3958 fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
3972 if (self.liveness.isUnused(inst)) return null;
3973
3974 const mod = self.module;3959 const mod = self.module;
3975 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;3960 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
3976 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;3961 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
...@@ -4091,7 +4076,6 @@ const DeclGen = struct {...@@ -4091,7 +4076,6 @@ const DeclGen = struct {
4091 }4076 }
40924077
4093 fn airStructFieldPtrIndex(self: *DeclGen, inst: Air.Inst.Index, field_index: u32) !?IdRef {4078 fn airStructFieldPtrIndex(self: *DeclGen, inst: Air.Inst.Index, field_index: u32) !?IdRef {
4094 if (self.liveness.isUnused(inst)) return null;
4095 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4079 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4096 const struct_ptr = try self.resolve(ty_op.operand);4080 const struct_ptr = try self.resolve(ty_op.operand);
4097 const struct_ptr_ty = self.typeOf(ty_op.operand);4081 const struct_ptr_ty = self.typeOf(ty_op.operand);
...@@ -4145,7 +4129,6 @@ const DeclGen = struct {...@@ -4145,7 +4129,6 @@ const DeclGen = struct {
4145 }4129 }
41464130
4147 fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4131 fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4148 if (self.liveness.isUnused(inst)) return null;
4149 const mod = self.module;4132 const mod = self.module;
4150 const ptr_ty = self.typeOfIndex(inst);4133 const ptr_ty = self.typeOfIndex(inst);
4151 assert(ptr_ty.ptrAddressSpace(mod) == .generic);4134 assert(ptr_ty.ptrAddressSpace(mod) == .generic);
...@@ -4729,9 +4712,7 @@ const DeclGen = struct {...@@ -4729,9 +4712,7 @@ const DeclGen = struct {
47294712
4730 try self.beginSpvBlock(ok_block);4713 try self.beginSpvBlock(ok_block);
4731 }4714 }
4732 if (self.liveness.isUnused(inst)) {4715
4733 return null;
4734 }
4735 if (!eu_layout.payload_has_bits) {4716 if (!eu_layout.payload_has_bits) {
4736 return null;4717 return null;
4737 }4718 }
...@@ -4741,8 +4722,6 @@ const DeclGen = struct {...@@ -4741,8 +4722,6 @@ const DeclGen = struct {
4741 }4722 }
47424723
4743 fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4724 fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4744 if (self.liveness.isUnused(inst)) return null;
4745
4746 const mod = self.module;4725 const mod = self.module;
4747 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4726 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4748 const operand_id = try self.resolve(ty_op.operand);4727 const operand_id = try self.resolve(ty_op.operand);
...@@ -4766,8 +4745,6 @@ const DeclGen = struct {...@@ -4766,8 +4745,6 @@ const DeclGen = struct {
4766 }4745 }
47674746
4768 fn airErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4747 fn airErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4769 if (self.liveness.isUnused(inst)) return null;
4770
4771 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4748 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4772 const operand_id = try self.resolve(ty_op.operand);4749 const operand_id = try self.resolve(ty_op.operand);
4773 const payload_ty = self.typeOfIndex(inst);4750 const payload_ty = self.typeOfIndex(inst);
...@@ -4781,8 +4758,6 @@ const DeclGen = struct {...@@ -4781,8 +4758,6 @@ const DeclGen = struct {
4781 }4758 }
47824759
4783 fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4760 fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4784 if (self.liveness.isUnused(inst)) return null;
4785
4786 const mod = self.module;4761 const mod = self.module;
4787 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4762 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4788 const err_union_ty = self.typeOfIndex(inst);4763 const err_union_ty = self.typeOfIndex(inst);
...@@ -4804,8 +4779,6 @@ const DeclGen = struct {...@@ -4804,8 +4779,6 @@ const DeclGen = struct {
4804 }4779 }
48054780
4806 fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4781 fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4807 if (self.liveness.isUnused(inst)) return null;
4808
4809 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4782 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4810 const err_union_ty = self.typeOfIndex(inst);4783 const err_union_ty = self.typeOfIndex(inst);
4811 const operand_id = try self.resolve(ty_op.operand);4784 const operand_id = try self.resolve(ty_op.operand);
...@@ -4825,8 +4798,6 @@ const DeclGen = struct {...@@ -4825,8 +4798,6 @@ const DeclGen = struct {
4825 }4798 }
48264799
4827 fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef {4800 fn airIsNull(self: *DeclGen, inst: Air.Inst.Index, is_pointer: bool, pred: enum { is_null, is_non_null }) !?IdRef {
4828 if (self.liveness.isUnused(inst)) return null;
4829
4830 const mod = self.module;4801 const mod = self.module;
4831 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4802 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4832 const operand_id = try self.resolve(un_op);4803 const operand_id = try self.resolve(un_op);
...@@ -4899,8 +4870,6 @@ const DeclGen = struct {...@@ -4899,8 +4870,6 @@ const DeclGen = struct {
4899 }4870 }
49004871
4901 fn airIsErr(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?IdRef {4872 fn airIsErr(self: *DeclGen, inst: Air.Inst.Index, pred: enum { is_err, is_non_err }) !?IdRef {
4902 if (self.liveness.isUnused(inst)) return null;
4903
4904 const mod = self.module;4873 const mod = self.module;
4905 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4874 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4906 const operand_id = try self.resolve(un_op);4875 const operand_id = try self.resolve(un_op);
...@@ -4935,8 +4904,6 @@ const DeclGen = struct {...@@ -4935,8 +4904,6 @@ const DeclGen = struct {
4935 }4904 }
49364905
4937 fn airUnwrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4906 fn airUnwrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4938 if (self.liveness.isUnused(inst)) return null;
4939
4940 const mod = self.module;4907 const mod = self.module;
4941 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4908 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4942 const operand_id = try self.resolve(ty_op.operand);4909 const operand_id = try self.resolve(ty_op.operand);
...@@ -4953,8 +4920,6 @@ const DeclGen = struct {...@@ -4953,8 +4920,6 @@ const DeclGen = struct {
4953 }4920 }
49544921
4955 fn airUnwrapOptionalPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4922 fn airUnwrapOptionalPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4956 if (self.liveness.isUnused(inst)) return null;
4957
4958 const mod = self.module;4923 const mod = self.module;
4959 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4924 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4960 const operand_id = try self.resolve(ty_op.operand);4925 const operand_id = try self.resolve(ty_op.operand);
...@@ -4979,8 +4944,6 @@ const DeclGen = struct {...@@ -4979,8 +4944,6 @@ const DeclGen = struct {
4979 }4944 }
49804945
4981 fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {4946 fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {
4982 if (self.liveness.isUnused(inst)) return null;
4983
4984 const mod = self.module;4947 const mod = self.module;
4985 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4948 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
4986 const payload_ty = self.typeOf(ty_op.operand);4949 const payload_ty = self.typeOf(ty_op.operand);