| ... | @@ -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 | } |
| 631 | | 631 | |
| | 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 bitcast | 704 | /// 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 value | 727 | // Manually truncate the value so that the resulting value |
| ... | @@ -711,6 +739,24 @@ const DeclGen = struct { | ... | @@ -711,6 +739,24 @@ const DeclGen = struct { |
| 711 | | 739 | |
| 712 | /// Emits a float constant | 740 | /// 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 | }); |
| ... | @@ -901,19 +947,19 @@ const DeclGen = struct { | ... | @@ -901,19 +947,19 @@ const DeclGen = struct { |
| 901 | .bytes => |bytes| { | 947 | .bytes => |bytes| { |
| 902 | // TODO: This is really space inefficient, perhaps there is a better | 948 | // TODO: This is really space inefficient, perhaps there is a better |
| 903 | // way to do it? | 949 | // way to do it? |
| 904 | for (bytes, 0..) |byte, i| { | 950 | for (constituents, bytes) |*constituent, byte| { |
| 905 | constituents[i] = try self.constInt(elem_ty_ref, byte); | 951 | constituent.* = try self.constInt(elem_ty_ref, byte); |
| 906 | } | 952 | } |
| 907 | }, | 953 | }, |
| 908 | .elems => |elems| { | 954 | .elems => |elems| { |
| 909 | for (0..@as(usize, @intCast(array_type.len))) |i| { | 955 | for (constituents, elems) |*constituent, elem| { |
| 910 | constituents[i] = try self.constant(elem_ty, Value.fromInterned(elems[i]), .indirect); | 956 | constituent.* = try self.constant(elem_ty, Value.fromInterned(elem), .indirect); |
| 911 | } | 957 | } |
| 912 | }, | 958 | }, |
| 913 | .repeated_elem => |elem| { | 959 | .repeated_elem => |elem| { |
| 914 | const val_id = try self.constant(elem_ty, Value.fromInterned(elem), .indirect); | 960 | const val_id = try self.constant(elem_ty, Value.fromInterned(elem), .indirect); |
| 915 | for (0..@as(usize, @intCast(array_type.len))) |i| { | 961 | for (constituents) |*constituent| { |
| 916 | constituents[i] = val_id; | 962 | constituent.* = val_id; |
| 917 | } | 963 | } |
| 918 | }, | 964 | }, |
| 919 | } | 965 | } |
| ... | @@ -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; | | |
| 1452 | | 1497 | |
| 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 | else | 1500 | else |
| 1456 | try self.spv.arrayType(ty.vectorLen(mod), elem_ty_ref); | 1501 | try self.spv.arrayType(len, elem_ty_ref); |
| 1457 | | 1502 | |
| 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 | } |
| 1753 | | 1798 | |
| 1754 | /// This structure is used as helper for element-wise operations. It is intended | 1799 | /// 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 convert | 1811 | /// 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 | } |
| 1775 | | 1818 | |
| 1776 | /// Utility function to extract the element at a particular index in an | 1819 | /// 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`, and | 1820 | /// 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 | } |
| 1790 | | 1832 | |
| 1791 | /// Turns the results of this WipElementWise into a result. This can either | 1833 | /// 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 { |
| 1806 | | 1848 | |
| 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 | }; |
| 1814 | | 1856 | |
| 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); |
| 1824 | | 1864 | |
| 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); |
| 1827 | | 1867 | |
| 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 | } |
| ... | @@ -2312,11 +2351,11 @@ const DeclGen = struct { | ... | @@ -2312,11 +2351,11 @@ const DeclGen = struct { |
| 2312 | } | 2351 | } |
| 2313 | | 2352 | |
| 2314 | fn binOpSimple(self: *DeclGen, ty: Type, lhs_id: IdRef, rhs_id: IdRef, comptime opcode: Opcode) !IdRef { | 2353 | fn binOpSimple(self: *DeclGen, ty: Type, lhs_id: IdRef, rhs_id: IdRef, comptime opcode: Opcode) !IdRef { |
| 2315 | var wip = try self.elementWise(ty); | 2354 | var wip = try self.elementWise(ty, false); |
| 2316 | defer wip.deinit(); | 2355 | defer wip.deinit(); |
| 2317 | for (0..wip.results.len) |i| { | 2356 | for (0..wip.results.len) |i| { |
| 2318 | try self.func.body.emit(self.spv.gpa, opcode, .{ | 2357 | try self.func.body.emit(self.spv.gpa, opcode, .{ |
| 2319 | .id_result_type = wip.scalar_ty_id, | 2358 | .id_result_type = wip.ty_id, |
| 2320 | .id_result = wip.allocId(i), | 2359 | .id_result = wip.allocId(i), |
| 2321 | .operand_1 = try wip.elementAt(ty, lhs_id, i), | 2360 | .operand_1 = try wip.elementAt(ty, lhs_id, i), |
| 2322 | .operand_2 = try wip.elementAt(ty, rhs_id, i), | 2361 | .operand_2 = try wip.elementAt(ty, rhs_id, i), |
| ... | @@ -2345,7 +2384,7 @@ const DeclGen = struct { | ... | @@ -2345,7 +2384,7 @@ const DeclGen = struct { |
| 2345 | | 2384 | |
| 2346 | const result_ty = self.typeOfIndex(inst); | 2385 | const result_ty = self.typeOfIndex(inst); |
| 2347 | const shift_ty = self.typeOf(bin_op.rhs); | 2386 | const shift_ty = self.typeOf(bin_op.rhs); |
| 2348 | const scalar_shift_ty_ref = try self.resolveType(shift_ty.scalarType(mod), .direct); | 2387 | const shift_ty_ref = try self.resolveType(shift_ty, .direct); |
| 2349 | | 2388 | |
| 2350 | const info = self.arithmeticTypeInfo(result_ty); | 2389 | const info = self.arithmeticTypeInfo(result_ty); |
| 2351 | switch (info.class) { | 2390 | switch (info.class) { |
| ... | @@ -2354,7 +2393,7 @@ const DeclGen = struct { | ... | @@ -2354,7 +2393,7 @@ const DeclGen = struct { |
| 2354 | .float, .bool => unreachable, | 2393 | .float, .bool => unreachable, |
| 2355 | } | 2394 | } |
| 2356 | | 2395 | |
| 2357 | var wip = try self.elementWise(result_ty); | 2396 | var wip = try self.elementWise(result_ty, false); |
| 2358 | defer wip.deinit(); | 2397 | defer wip.deinit(); |
| 2359 | for (wip.results, 0..) |*result_id, i| { | 2398 | for (wip.results, 0..) |*result_id, i| { |
| 2360 | const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i); | 2399 | const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i); |
| ... | @@ -2362,10 +2401,10 @@ const DeclGen = struct { | ... | @@ -2362,10 +2401,10 @@ const DeclGen = struct { |
| 2362 | | 2401 | |
| 2363 | // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that, | 2402 | // 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. | 2403 | // so just manually upcast it if required. |
| 2365 | const shift_id = if (scalar_shift_ty_ref != wip.scalar_ty_ref) blk: { | 2404 | const shift_id = if (shift_ty_ref != wip.ty_ref) blk: { |
| 2366 | const shift_id = self.spv.allocId(); | 2405 | const shift_id = self.spv.allocId(); |
| 2367 | try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ | 2406 | try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ |
| 2368 | .id_result_type = wip.scalar_ty_id, | 2407 | .id_result_type = wip.ty_id, |
| 2369 | .id_result = shift_id, | 2408 | .id_result = shift_id, |
| 2370 | .unsigned_value = rhs_elem_id, | 2409 | .unsigned_value = rhs_elem_id, |
| 2371 | }); | 2410 | }); |
| ... | @@ -2374,7 +2413,7 @@ const DeclGen = struct { | ... | @@ -2374,7 +2413,7 @@ const DeclGen = struct { |
| 2374 | | 2413 | |
| 2375 | const value_id = self.spv.allocId(); | 2414 | const value_id = self.spv.allocId(); |
| 2376 | const args = .{ | 2415 | const args = .{ |
| 2377 | .id_result_type = wip.scalar_ty_id, | 2416 | .id_result_type = wip.ty_id, |
| 2378 | .id_result = value_id, | 2417 | .id_result = value_id, |
| 2379 | .base = lhs_elem_id, | 2418 | .base = lhs_elem_id, |
| 2380 | .shift = shift_id, | 2419 | .shift = shift_id, |
| ... | @@ -2386,7 +2425,7 @@ const DeclGen = struct { | ... | @@ -2386,7 +2425,7 @@ const DeclGen = struct { |
| 2386 | try self.func.body.emit(self.spv.gpa, unsigned, args); | 2425 | try self.func.body.emit(self.spv.gpa, unsigned, args); |
| 2387 | } | 2426 | } |
| 2388 | | 2427 | |
| 2389 | result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, info); | 2428 | result_id.* = try self.normalize(wip.ty_ref, value_id, info); |
| 2390 | } | 2429 | } |
| 2391 | return try wip.finalize(); | 2430 | return try wip.finalize(); |
| 2392 | } | 2431 | } |
| ... | @@ -2405,14 +2444,14 @@ const DeclGen = struct { | ... | @@ -2405,14 +2444,14 @@ const DeclGen = struct { |
| 2405 | fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef { | 2444 | 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); | 2445 | const info = self.arithmeticTypeInfo(result_ty); |
| 2407 | | 2446 | |
| 2408 | var wip = try self.elementWise(result_ty); | 2447 | var wip = try self.elementWise(result_ty, true); |
| 2409 | defer wip.deinit(); | 2448 | defer wip.deinit(); |
| 2410 | for (wip.results, 0..) |*result_id, i| { | 2449 | for (wip.results, 0..) |*result_id, i| { |
| 2411 | const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i); | 2450 | 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); | 2451 | const rhs_elem_id = try wip.elementAt(result_ty, rhs_id, i); |
| 2413 | | 2452 | |
| 2414 | // TODO: Use fmin for OpenCL | 2453 | // TODO: Use fmin for OpenCL |
| 2415 | const cmp_id = try self.cmp(op, Type.bool, wip.scalar_ty, lhs_elem_id, rhs_elem_id); | 2454 | const cmp_id = try self.cmp(op, Type.bool, wip.ty, lhs_elem_id, rhs_elem_id); |
| 2416 | const selection_id = switch (info.class) { | 2455 | const selection_id = switch (info.class) { |
| 2417 | .float => blk: { | 2456 | .float => blk: { |
| 2418 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, | 2457 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, |
| ... | @@ -2440,7 +2479,7 @@ const DeclGen = struct { | ... | @@ -2440,7 +2479,7 @@ const DeclGen = struct { |
| 2440 | | 2479 | |
| 2441 | result_id.* = self.spv.allocId(); | 2480 | result_id.* = self.spv.allocId(); |
| 2442 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ | 2481 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ |
| 2443 | .id_result_type = wip.scalar_ty_id, | 2482 | .id_result_type = wip.ty_id, |
| 2444 | .id_result = result_id.*, | 2483 | .id_result = result_id.*, |
| 2445 | .condition = selection_id, | 2484 | .condition = selection_id, |
| 2446 | .object_1 = lhs_elem_id, | 2485 | .object_1 = lhs_elem_id, |
| ... | @@ -2545,7 +2584,7 @@ const DeclGen = struct { | ... | @@ -2545,7 +2584,7 @@ const DeclGen = struct { |
| 2545 | .bool => unreachable, | 2584 | .bool => unreachable, |
| 2546 | }; | 2585 | }; |
| 2547 | | 2586 | |
| 2548 | var wip = try self.elementWise(ty); | 2587 | var wip = try self.elementWise(ty, false); |
| 2549 | defer wip.deinit(); | 2588 | defer wip.deinit(); |
| 2550 | for (wip.results, 0..) |*result_id, i| { | 2589 | for (wip.results, 0..) |*result_id, i| { |
| 2551 | const lhs_elem_id = try wip.elementAt(ty, lhs_id, i); | 2590 | const lhs_elem_id = try wip.elementAt(ty, lhs_id, i); |
| ... | @@ -2553,7 +2592,7 @@ const DeclGen = struct { | ... | @@ -2553,7 +2592,7 @@ const DeclGen = struct { |
| 2553 | | 2592 | |
| 2554 | const value_id = self.spv.allocId(); | 2593 | const value_id = self.spv.allocId(); |
| 2555 | const operands = .{ | 2594 | const operands = .{ |
| 2556 | .id_result_type = wip.scalar_ty_id, | 2595 | .id_result_type = wip.ty_id, |
| 2557 | .id_result = value_id, | 2596 | .id_result = value_id, |
| 2558 | .operand_1 = lhs_elem_id, | 2597 | .operand_1 = lhs_elem_id, |
| 2559 | .operand_2 = rhs_elem_id, | 2598 | .operand_2 = rhs_elem_id, |
| ... | @@ -2568,7 +2607,7 @@ const DeclGen = struct { | ... | @@ -2568,7 +2607,7 @@ const DeclGen = struct { |
| 2568 | | 2607 | |
| 2569 | // TODO: Trap on overflow? Probably going to be annoying. | 2608 | // TODO: Trap on overflow? Probably going to be annoying. |
| 2570 | // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap. | 2609 | // 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); | 2610 | result_id.* = try self.normalize(wip.ty_ref, value_id, info); |
| 2572 | } | 2611 | } |
| 2573 | | 2612 | |
| 2574 | return try wip.finalize(); | 2613 | return try wip.finalize(); |
| ... | @@ -2582,12 +2621,12 @@ const DeclGen = struct { | ... | @@ -2582,12 +2621,12 @@ const DeclGen = struct { |
| 2582 | const operand_id = try self.resolve(ty_op.operand); | 2621 | const operand_id = try self.resolve(ty_op.operand); |
| 2583 | // Note: operand_ty may be signed, while ty is always unsigned! | 2622 | // Note: operand_ty may be signed, while ty is always unsigned! |
| 2584 | const operand_ty = self.typeOf(ty_op.operand); | 2623 | const operand_ty = self.typeOf(ty_op.operand); |
| 2585 | const ty = self.typeOfIndex(inst); | 2624 | const result_ty = self.typeOfIndex(inst); |
| 2586 | const info = self.arithmeticTypeInfo(ty); | 2625 | const info = self.arithmeticTypeInfo(result_ty); |
| 2587 | const operand_scalar_ty = operand_ty.scalarType(mod); | 2626 | const operand_scalar_ty = operand_ty.scalarType(mod); |
| 2588 | const operand_scalar_ty_ref = try self.resolveType(operand_scalar_ty, .direct); | 2627 | const operand_scalar_ty_ref = try self.resolveType(operand_scalar_ty, .direct); |
| 2589 | | 2628 | |
| 2590 | var wip = try self.elementWise(ty); | 2629 | var wip = try self.elementWise(result_ty, true); |
| 2591 | defer wip.deinit(); | 2630 | defer wip.deinit(); |
| 2592 | | 2631 | |
| 2593 | const zero_id = switch (info.class) { | 2632 | const zero_id = switch (info.class) { |
| ... | @@ -2615,7 +2654,7 @@ const DeclGen = struct { | ... | @@ -2615,7 +2654,7 @@ const DeclGen = struct { |
| 2615 | .composite_integer => unreachable, // TODO | 2654 | .composite_integer => unreachable, // TODO |
| 2616 | .bool => unreachable, | 2655 | .bool => unreachable, |
| 2617 | } | 2656 | } |
| 2618 | const neg_norm_id = try self.normalize(wip.scalar_ty_ref, neg_id, info); | 2657 | const neg_norm_id = try self.normalize(wip.ty_ref, neg_id, info); |
| 2619 | | 2658 | |
| 2620 | const gt_zero_id = try self.cmp(.gt, Type.bool, operand_scalar_ty, elem_id, zero_id); | 2659 | const gt_zero_id = try self.cmp(.gt, Type.bool, operand_scalar_ty, elem_id, zero_id); |
| 2621 | const abs_id = self.spv.allocId(); | 2660 | const abs_id = self.spv.allocId(); |
| ... | @@ -2627,7 +2666,7 @@ const DeclGen = struct { | ... | @@ -2627,7 +2666,7 @@ const DeclGen = struct { |
| 2627 | .object_2 = neg_norm_id, | 2666 | .object_2 = neg_norm_id, |
| 2628 | }); | 2667 | }); |
| 2629 | // For Shader, we may need to cast from signed to unsigned here. | 2668 | // 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); | 2669 | result_id.* = try self.bitCast(wip.ty, operand_scalar_ty, abs_id); |
| 2631 | } | 2670 | } |
| 2632 | return try wip.finalize(); | 2671 | return try wip.finalize(); |
| 2633 | } | 2672 | } |
| ... | @@ -2641,6 +2680,7 @@ const DeclGen = struct { | ... | @@ -2641,6 +2680,7 @@ const DeclGen = struct { |
| 2641 | ) !?IdRef { | 2680 | ) !?IdRef { |
| 2642 | if (self.liveness.isUnused(inst)) return null; | 2681 | if (self.liveness.isUnused(inst)) return null; |
| 2643 | | 2682 | |
| | 2683 | const mod = self.module; |
| 2644 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 2684 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2645 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2685 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2646 | const lhs = try self.resolve(extra.lhs); | 2686 | const lhs = try self.resolve(extra.lhs); |
| ... | @@ -2651,6 +2691,10 @@ const DeclGen = struct { | ... | @@ -2651,6 +2691,10 @@ const DeclGen = struct { |
| 2651 | const ov_ty = result_ty.structFieldType(1, self.module); | 2691 | const ov_ty = result_ty.structFieldType(1, self.module); |
| 2652 | | 2692 | |
| 2653 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); | 2693 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| | 2694 | const cmp_ty_ref = if (self.isVector(operand_ty)) |
| | 2695 | try self.spv.vectorType(operand_ty.vectorLen(mod), bool_ty_ref) |
| | 2696 | else |
| | 2697 | bool_ty_ref; |
| 2654 | | 2698 | |
| 2655 | const info = self.arithmeticTypeInfo(operand_ty); | 2699 | const info = self.arithmeticTypeInfo(operand_ty); |
| 2656 | switch (info.class) { | 2700 | switch (info.class) { |
| ... | @@ -2659,9 +2703,9 @@ const DeclGen = struct { | ... | @@ -2659,9 +2703,9 @@ const DeclGen = struct { |
| 2659 | .float, .bool => unreachable, | 2703 | .float, .bool => unreachable, |
| 2660 | } | 2704 | } |
| 2661 | | 2705 | |
| 2662 | var wip_result = try self.elementWise(operand_ty); | 2706 | var wip_result = try self.elementWise(operand_ty, false); |
| 2663 | defer wip_result.deinit(); | 2707 | defer wip_result.deinit(); |
| 2664 | var wip_ov = try self.elementWise(ov_ty); | 2708 | var wip_ov = try self.elementWise(ov_ty, false); |
| 2665 | defer wip_ov.deinit(); | 2709 | defer wip_ov.deinit(); |
| 2666 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { | 2710 | 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); | 2711 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); |
| ... | @@ -2671,14 +2715,14 @@ const DeclGen = struct { | ... | @@ -2671,14 +2715,14 @@ const DeclGen = struct { |
| 2671 | const value_id = self.spv.allocId(); | 2715 | const value_id = self.spv.allocId(); |
| 2672 | | 2716 | |
| 2673 | try self.func.body.emit(self.spv.gpa, add, .{ | 2717 | try self.func.body.emit(self.spv.gpa, add, .{ |
| 2674 | .id_result_type = wip_result.scalar_ty_id, | 2718 | .id_result_type = wip_result.ty_id, |
| 2675 | .id_result = value_id, | 2719 | .id_result = value_id, |
| 2676 | .operand_1 = lhs_elem_id, | 2720 | .operand_1 = lhs_elem_id, |
| 2677 | .operand_2 = rhs_elem_id, | 2721 | .operand_2 = rhs_elem_id, |
| 2678 | }); | 2722 | }); |
| 2679 | | 2723 | |
| 2680 | // Normalize the result so that the comparisons go well | 2724 | // Normalize the result so that the comparisons go well |
| 2681 | result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info); | 2725 | result_id.* = try self.normalize(wip_result.ty_ref, value_id, info); |
| 2682 | | 2726 | |
| 2683 | const overflowed_id = switch (info.signedness) { | 2727 | const overflowed_id = switch (info.signedness) { |
| 2684 | .unsigned => blk: { | 2728 | .unsigned => blk: { |
| ... | @@ -2686,7 +2730,7 @@ const DeclGen = struct { | ... | @@ -2686,7 +2730,7 @@ const DeclGen = struct { |
| 2686 | // For subtraction the conditions need to be swapped. | 2730 | // For subtraction the conditions need to be swapped. |
| 2687 | const overflowed_id = self.spv.allocId(); | 2731 | const overflowed_id = self.spv.allocId(); |
| 2688 | try self.func.body.emit(self.spv.gpa, ucmp, .{ | 2732 | try self.func.body.emit(self.spv.gpa, ucmp, .{ |
| 2689 | .id_result_type = self.typeId(bool_ty_ref), | 2733 | .id_result_type = self.typeId(cmp_ty_ref), |
| 2690 | .id_result = overflowed_id, | 2734 | .id_result = overflowed_id, |
| 2691 | .operand_1 = result_id.*, | 2735 | .operand_1 = result_id.*, |
| 2692 | .operand_2 = lhs_elem_id, | 2736 | .operand_2 = lhs_elem_id, |
| ... | @@ -2712,9 +2756,9 @@ const DeclGen = struct { | ... | @@ -2712,9 +2756,9 @@ const DeclGen = struct { |
| 2712 | // = (rhs < 0) == (lhs > value) | 2756 | // = (rhs < 0) == (lhs > value) |
| 2713 | | 2757 | |
| 2714 | const rhs_lt_zero_id = self.spv.allocId(); | 2758 | const rhs_lt_zero_id = self.spv.allocId(); |
| 2715 | const zero_id = try self.constInt(wip_result.scalar_ty_ref, 0); | 2759 | const zero_id = try self.constInt(wip_result.ty_ref, 0); |
| 2716 | try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ | 2760 | try self.func.body.emit(self.spv.gpa, .OpSLessThan, .{ |
| 2717 | .id_result_type = self.typeId(bool_ty_ref), | 2761 | .id_result_type = self.typeId(cmp_ty_ref), |
| 2718 | .id_result = rhs_lt_zero_id, | 2762 | .id_result = rhs_lt_zero_id, |
| 2719 | .operand_1 = rhs_elem_id, | 2763 | .operand_1 = rhs_elem_id, |
| 2720 | .operand_2 = zero_id, | 2764 | .operand_2 = zero_id, |
| ... | @@ -2722,7 +2766,7 @@ const DeclGen = struct { | ... | @@ -2722,7 +2766,7 @@ const DeclGen = struct { |
| 2722 | | 2766 | |
| 2723 | const value_gt_lhs_id = self.spv.allocId(); | 2767 | const value_gt_lhs_id = self.spv.allocId(); |
| 2724 | try self.func.body.emit(self.spv.gpa, scmp, .{ | 2768 | try self.func.body.emit(self.spv.gpa, scmp, .{ |
| 2725 | .id_result_type = self.typeId(bool_ty_ref), | 2769 | .id_result_type = self.typeId(cmp_ty_ref), |
| 2726 | .id_result = value_gt_lhs_id, | 2770 | .id_result = value_gt_lhs_id, |
| 2727 | .operand_1 = lhs_elem_id, | 2771 | .operand_1 = lhs_elem_id, |
| 2728 | .operand_2 = result_id.*, | 2772 | .operand_2 = result_id.*, |
| ... | @@ -2730,7 +2774,7 @@ const DeclGen = struct { | ... | @@ -2730,7 +2774,7 @@ const DeclGen = struct { |
| 2730 | | 2774 | |
| 2731 | const overflowed_id = self.spv.allocId(); | 2775 | const overflowed_id = self.spv.allocId(); |
| 2732 | try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{ | 2776 | try self.func.body.emit(self.spv.gpa, .OpLogicalEqual, .{ |
| 2733 | .id_result_type = self.typeId(bool_ty_ref), | 2777 | .id_result_type = self.typeId(cmp_ty_ref), |
| 2734 | .id_result = overflowed_id, | 2778 | .id_result = overflowed_id, |
| 2735 | .operand_1 = rhs_lt_zero_id, | 2779 | .operand_1 = rhs_lt_zero_id, |
| 2736 | .operand_2 = value_gt_lhs_id, | 2780 | .operand_2 = value_gt_lhs_id, |
| ... | @@ -2739,7 +2783,7 @@ const DeclGen = struct { | ... | @@ -2739,7 +2783,7 @@ const DeclGen = struct { |
| 2739 | }, | 2783 | }, |
| 2740 | }; | 2784 | }; |
| 2741 | | 2785 | |
| 2742 | ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id); | 2786 | ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id); |
| 2743 | } | 2787 | } |
| 2744 | | 2788 | |
| 2745 | return try self.constructComposite( | 2789 | return try self.constructComposite( |
| ... | @@ -2759,11 +2803,15 @@ const DeclGen = struct { | ... | @@ -2759,11 +2803,15 @@ const DeclGen = struct { |
| 2759 | const result_ty = self.typeOfIndex(inst); | 2803 | const result_ty = self.typeOfIndex(inst); |
| 2760 | const operand_ty = self.typeOf(extra.lhs); | 2804 | const operand_ty = self.typeOf(extra.lhs); |
| 2761 | const shift_ty = self.typeOf(extra.rhs); | 2805 | const shift_ty = self.typeOf(extra.rhs); |
| 2762 | const scalar_shift_ty_ref = try self.resolveType(shift_ty.scalarType(mod), .direct); | 2806 | const shift_ty_ref = try self.resolveType(shift_ty, .direct); |
| 2763 | | 2807 | |
| 2764 | const ov_ty = result_ty.structFieldType(1, self.module); | 2808 | const ov_ty = result_ty.structFieldType(1, self.module); |
| 2765 | | 2809 | |
| 2766 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); | 2810 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| | 2811 | const cmp_ty_ref = if (self.isVector(operand_ty)) |
| | 2812 | try self.spv.vectorType(operand_ty.vectorLen(mod), bool_ty_ref) |
| | 2813 | else |
| | 2814 | bool_ty_ref; |
| 2767 | | 2815 | |
| 2768 | const info = self.arithmeticTypeInfo(operand_ty); | 2816 | const info = self.arithmeticTypeInfo(operand_ty); |
| 2769 | switch (info.class) { | 2817 | switch (info.class) { |
| ... | @@ -2772,9 +2820,9 @@ const DeclGen = struct { | ... | @@ -2772,9 +2820,9 @@ const DeclGen = struct { |
| 2772 | .float, .bool => unreachable, | 2820 | .float, .bool => unreachable, |
| 2773 | } | 2821 | } |
| 2774 | | 2822 | |
| 2775 | var wip_result = try self.elementWise(operand_ty); | 2823 | var wip_result = try self.elementWise(operand_ty, false); |
| 2776 | defer wip_result.deinit(); | 2824 | defer wip_result.deinit(); |
| 2777 | var wip_ov = try self.elementWise(ov_ty); | 2825 | var wip_ov = try self.elementWise(ov_ty, false); |
| 2778 | defer wip_ov.deinit(); | 2826 | defer wip_ov.deinit(); |
| 2779 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { | 2827 | 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); | 2828 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); |
| ... | @@ -2782,10 +2830,10 @@ const DeclGen = struct { | ... | @@ -2782,10 +2830,10 @@ const DeclGen = struct { |
| 2782 | | 2830 | |
| 2783 | // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that, | 2831 | // 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. | 2832 | // so just manually upcast it if required. |
| 2785 | const shift_id = if (scalar_shift_ty_ref != wip_result.scalar_ty_ref) blk: { | 2833 | const shift_id = if (shift_ty_ref != wip_result.ty_ref) blk: { |
| 2786 | const shift_id = self.spv.allocId(); | 2834 | const shift_id = self.spv.allocId(); |
| 2787 | try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ | 2835 | try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ |
| 2788 | .id_result_type = wip_result.scalar_ty_id, | 2836 | .id_result_type = wip_result.ty_id, |
| 2789 | .id_result = shift_id, | 2837 | .id_result = shift_id, |
| 2790 | .unsigned_value = rhs_elem_id, | 2838 | .unsigned_value = rhs_elem_id, |
| 2791 | }); | 2839 | }); |
| ... | @@ -2794,18 +2842,18 @@ const DeclGen = struct { | ... | @@ -2794,18 +2842,18 @@ const DeclGen = struct { |
| 2794 | | 2842 | |
| 2795 | const value_id = self.spv.allocId(); | 2843 | const value_id = self.spv.allocId(); |
| 2796 | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ | 2844 | try self.func.body.emit(self.spv.gpa, .OpShiftLeftLogical, .{ |
| 2797 | .id_result_type = wip_result.scalar_ty_id, | 2845 | .id_result_type = wip_result.ty_id, |
| 2798 | .id_result = value_id, | 2846 | .id_result = value_id, |
| 2799 | .base = lhs_elem_id, | 2847 | .base = lhs_elem_id, |
| 2800 | .shift = shift_id, | 2848 | .shift = shift_id, |
| 2801 | }); | 2849 | }); |
| 2802 | result_id.* = try self.normalize(wip_result.scalar_ty_ref, value_id, info); | 2850 | result_id.* = try self.normalize(wip_result.ty_ref, value_id, info); |
| 2803 | | 2851 | |
| 2804 | const right_shift_id = self.spv.allocId(); | 2852 | const right_shift_id = self.spv.allocId(); |
| 2805 | switch (info.signedness) { | 2853 | switch (info.signedness) { |
| 2806 | .signed => { | 2854 | .signed => { |
| 2807 | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ | 2855 | try self.func.body.emit(self.spv.gpa, .OpShiftRightArithmetic, .{ |
| 2808 | .id_result_type = wip_result.scalar_ty_id, | 2856 | .id_result_type = wip_result.ty_id, |
| 2809 | .id_result = right_shift_id, | 2857 | .id_result = right_shift_id, |
| 2810 | .base = result_id.*, | 2858 | .base = result_id.*, |
| 2811 | .shift = shift_id, | 2859 | .shift = shift_id, |
| ... | @@ -2813,7 +2861,7 @@ const DeclGen = struct { | ... | @@ -2813,7 +2861,7 @@ const DeclGen = struct { |
| 2813 | }, | 2861 | }, |
| 2814 | .unsigned => { | 2862 | .unsigned => { |
| 2815 | try self.func.body.emit(self.spv.gpa, .OpShiftRightLogical, .{ | 2863 | try self.func.body.emit(self.spv.gpa, .OpShiftRightLogical, .{ |
| 2816 | .id_result_type = wip_result.scalar_ty_id, | 2864 | .id_result_type = wip_result.ty_id, |
| 2817 | .id_result = right_shift_id, | 2865 | .id_result = right_shift_id, |
| 2818 | .base = result_id.*, | 2866 | .base = result_id.*, |
| 2819 | .shift = shift_id, | 2867 | .shift = shift_id, |
| ... | @@ -2823,13 +2871,13 @@ const DeclGen = struct { | ... | @@ -2823,13 +2871,13 @@ const DeclGen = struct { |
| 2823 | | 2871 | |
| 2824 | const overflowed_id = self.spv.allocId(); | 2872 | const overflowed_id = self.spv.allocId(); |
| 2825 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ | 2873 | try self.func.body.emit(self.spv.gpa, .OpINotEqual, .{ |
| 2826 | .id_result_type = self.typeId(bool_ty_ref), | 2874 | .id_result_type = self.typeId(cmp_ty_ref), |
| 2827 | .id_result = overflowed_id, | 2875 | .id_result = overflowed_id, |
| 2828 | .operand_1 = lhs_elem_id, | 2876 | .operand_1 = lhs_elem_id, |
| 2829 | .operand_2 = right_shift_id, | 2877 | .operand_2 = right_shift_id, |
| 2830 | }); | 2878 | }); |
| 2831 | | 2879 | |
| 2832 | ov_id.* = try self.intFromBool(wip_ov.scalar_ty_ref, overflowed_id); | 2880 | ov_id.* = try self.intFromBool(wip_ov.ty_ref, overflowed_id); |
| 2833 | } | 2881 | } |
| 2834 | | 2882 | |
| 2835 | return try self.constructComposite( | 2883 | return try self.constructComposite( |
| ... | @@ -2853,19 +2901,19 @@ const DeclGen = struct { | ... | @@ -2853,19 +2901,19 @@ const DeclGen = struct { |
| 2853 | const info = self.arithmeticTypeInfo(ty); | 2901 | const info = self.arithmeticTypeInfo(ty); |
| 2854 | assert(info.class == .float); // .mul_add is only emitted for floats | 2902 | assert(info.class == .float); // .mul_add is only emitted for floats |
| 2855 | | 2903 | |
| 2856 | var wip = try self.elementWise(ty); | 2904 | var wip = try self.elementWise(ty, false); |
| 2857 | defer wip.deinit(); | 2905 | defer wip.deinit(); |
| 2858 | for (0..wip.results.len) |i| { | 2906 | for (0..wip.results.len) |i| { |
| 2859 | const mul_result = self.spv.allocId(); | 2907 | const mul_result = self.spv.allocId(); |
| 2860 | try self.func.body.emit(self.spv.gpa, .OpFMul, .{ | 2908 | try self.func.body.emit(self.spv.gpa, .OpFMul, .{ |
| 2861 | .id_result_type = wip.scalar_ty_id, | 2909 | .id_result_type = wip.ty_id, |
| 2862 | .id_result = mul_result, | 2910 | .id_result = mul_result, |
| 2863 | .operand_1 = try wip.elementAt(ty, mulend1, i), | 2911 | .operand_1 = try wip.elementAt(ty, mulend1, i), |
| 2864 | .operand_2 = try wip.elementAt(ty, mulend2, i), | 2912 | .operand_2 = try wip.elementAt(ty, mulend2, i), |
| 2865 | }); | 2913 | }); |
| 2866 | | 2914 | |
| 2867 | try self.func.body.emit(self.spv.gpa, .OpFAdd, .{ | 2915 | try self.func.body.emit(self.spv.gpa, .OpFAdd, .{ |
| 2868 | .id_result_type = wip.scalar_ty_id, | 2916 | .id_result_type = wip.ty_id, |
| 2869 | .id_result = wip.allocId(i), | 2917 | .id_result = wip.allocId(i), |
| 2870 | .operand_1 = mul_result, | 2918 | .operand_1 = mul_result, |
| 2871 | .operand_2 = try wip.elementAt(ty, addend, i), | 2919 | .operand_2 = try wip.elementAt(ty, addend, i), |
| ... | @@ -2879,11 +2927,9 @@ const DeclGen = struct { | ... | @@ -2879,11 +2927,9 @@ const DeclGen = struct { |
| 2879 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 2927 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2880 | const operand_id = try self.resolve(ty_op.operand); | 2928 | const operand_id = try self.resolve(ty_op.operand); |
| 2881 | const result_ty = self.typeOfIndex(inst); | 2929 | const result_ty = self.typeOfIndex(inst); |
| 2882 | var wip = try self.elementWise(result_ty); | 2930 | var wip = try self.elementWise(result_ty, true); |
| 2883 | defer wip.deinit(); | 2931 | defer wip.deinit(); |
| 2884 | for (wip.results) |*result_id| { | 2932 | @memset(wip.results, operand_id); |
| 2885 | result_id.* = operand_id; | | |
| 2886 | } | | |
| 2887 | return try wip.finalize(); | 2933 | return try wip.finalize(); |
| 2888 | } | 2934 | } |
| 2889 | | 2935 | |
| ... | @@ -2965,20 +3011,20 @@ const DeclGen = struct { | ... | @@ -2965,20 +3011,20 @@ const DeclGen = struct { |
| 2965 | | 3011 | |
| 2966 | const ty = self.typeOfIndex(inst); | 3012 | const ty = self.typeOfIndex(inst); |
| 2967 | | 3013 | |
| 2968 | var wip = try self.elementWise(ty); | 3014 | var wip = try self.elementWise(ty, true); |
| 2969 | defer wip.deinit(); | 3015 | defer wip.deinit(); |
| 2970 | for (wip.results, 0..) |*result_id, i| { | 3016 | for (wip.results, 0..) |*result_id, i| { |
| 2971 | const elem = try mask.elemValue(mod, i); | 3017 | const elem = try mask.elemValue(mod, i); |
| 2972 | if (elem.isUndef(mod)) { | 3018 | if (elem.isUndef(mod)) { |
| 2973 | result_id.* = try self.spv.constUndef(wip.scalar_ty_ref); | 3019 | result_id.* = try self.spv.constUndef(wip.ty_ref); |
| 2974 | continue; | 3020 | continue; |
| 2975 | } | 3021 | } |
| 2976 | | 3022 | |
| 2977 | const index = elem.toSignedInt(mod); | 3023 | const index = elem.toSignedInt(mod); |
| 2978 | if (index >= 0) { | 3024 | if (index >= 0) { |
| 2979 | result_id.* = try self.extractField(wip.scalar_ty, a, @intCast(index)); | 3025 | result_id.* = try self.extractField(wip.ty, a, @intCast(index)); |
| 2980 | } else { | 3026 | } else { |
| 2981 | result_id.* = try self.extractField(wip.scalar_ty, b, @intCast(~index)); | 3027 | result_id.* = try self.extractField(wip.ty, b, @intCast(~index)); |
| 2982 | } | 3028 | } |
| 2983 | } | 3029 | } |
| 2984 | return try wip.finalize(); | 3030 | return try wip.finalize(); |
| ... | @@ -3188,7 +3234,7 @@ const DeclGen = struct { | ... | @@ -3188,7 +3234,7 @@ const DeclGen = struct { |
| 3188 | return result_id; | 3234 | return result_id; |
| 3189 | }, | 3235 | }, |
| 3190 | .Vector => { | 3236 | .Vector => { |
| 3191 | var wip = try self.elementWise(result_ty); | 3237 | var wip = try self.elementWise(result_ty, true); |
| 3192 | defer wip.deinit(); | 3238 | defer wip.deinit(); |
| 3193 | const scalar_ty = ty.scalarType(mod); | 3239 | const scalar_ty = ty.scalarType(mod); |
| 3194 | for (wip.results, 0..) |*result_id, i| { | 3240 | for (wip.results, 0..) |*result_id, i| { |
| ... | @@ -3374,19 +3420,19 @@ const DeclGen = struct { | ... | @@ -3374,19 +3420,19 @@ const DeclGen = struct { |
| 3374 | return operand_id; | 3420 | return operand_id; |
| 3375 | } | 3421 | } |
| 3376 | | 3422 | |
| 3377 | var wip = try self.elementWise(dst_ty); | 3423 | var wip = try self.elementWise(dst_ty, false); |
| 3378 | defer wip.deinit(); | 3424 | defer wip.deinit(); |
| 3379 | for (wip.results, 0..) |*result_id, i| { | 3425 | for (wip.results, 0..) |*result_id, i| { |
| 3380 | const elem_id = try wip.elementAt(src_ty, operand_id, i); | 3426 | const elem_id = try wip.elementAt(src_ty, operand_id, i); |
| 3381 | const value_id = self.spv.allocId(); | 3427 | const value_id = self.spv.allocId(); |
| 3382 | switch (dst_info.signedness) { | 3428 | switch (dst_info.signedness) { |
| 3383 | .signed => try self.func.body.emit(self.spv.gpa, .OpSConvert, .{ | 3429 | .signed => try self.func.body.emit(self.spv.gpa, .OpSConvert, .{ |
| 3384 | .id_result_type = wip.scalar_ty_id, | 3430 | .id_result_type = wip.ty_id, |
| 3385 | .id_result = value_id, | 3431 | .id_result = value_id, |
| 3386 | .signed_value = elem_id, | 3432 | .signed_value = elem_id, |
| 3387 | }), | 3433 | }), |
| 3388 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ | 3434 | .unsigned => try self.func.body.emit(self.spv.gpa, .OpUConvert, .{ |
| 3389 | .id_result_type = wip.scalar_ty_id, | 3435 | .id_result_type = wip.ty_id, |
| 3390 | .id_result = value_id, | 3436 | .id_result = value_id, |
| 3391 | .unsigned_value = elem_id, | 3437 | .unsigned_value = elem_id, |
| 3392 | }), | 3438 | }), |
| ... | @@ -3397,7 +3443,7 @@ const DeclGen = struct { | ... | @@ -3397,7 +3443,7 @@ const DeclGen = struct { |
| 3397 | // type, we don't need to normalize when growing the type. The | 3443 | // type, we don't need to normalize when growing the type. The |
| 3398 | // representation is already the same. | 3444 | // representation is already the same. |
| 3399 | if (dst_info.bits < src_info.bits) { | 3445 | if (dst_info.bits < src_info.bits) { |
| 3400 | result_id.* = try self.normalize(wip.scalar_ty_ref, value_id, dst_info); | 3446 | result_id.* = try self.normalize(wip.ty_ref, value_id, dst_info); |
| 3401 | } else { | 3447 | } else { |
| 3402 | result_id.* = value_id; | 3448 | result_id.* = value_id; |
| 3403 | } | 3449 | } |
| ... | @@ -3482,11 +3528,11 @@ const DeclGen = struct { | ... | @@ -3482,11 +3528,11 @@ const DeclGen = struct { |
| 3482 | const operand_id = try self.resolve(un_op); | 3528 | const operand_id = try self.resolve(un_op); |
| 3483 | const result_ty = self.typeOfIndex(inst); | 3529 | const result_ty = self.typeOfIndex(inst); |
| 3484 | | 3530 | |
| 3485 | var wip = try self.elementWise(result_ty); | 3531 | var wip = try self.elementWise(result_ty, false); |
| 3486 | defer wip.deinit(); | 3532 | defer wip.deinit(); |
| 3487 | for (wip.results, 0..) |*result_id, i| { | 3533 | for (wip.results, 0..) |*result_id, i| { |
| 3488 | const elem_id = try wip.elementAt(Type.bool, operand_id, i); | 3534 | const elem_id = try wip.elementAt(Type.bool, operand_id, i); |
| 3489 | result_id.* = try self.intFromBool(wip.scalar_ty_ref, elem_id); | 3535 | result_id.* = try self.intFromBool(wip.ty_ref, elem_id); |
| 3490 | } | 3536 | } |
| 3491 | return try wip.finalize(); | 3537 | return try wip.finalize(); |
| 3492 | } | 3538 | } |
| ... | @@ -3515,12 +3561,12 @@ const DeclGen = struct { | ... | @@ -3515,12 +3561,12 @@ const DeclGen = struct { |
| 3515 | const result_ty = self.typeOfIndex(inst); | 3561 | const result_ty = self.typeOfIndex(inst); |
| 3516 | const info = self.arithmeticTypeInfo(result_ty); | 3562 | const info = self.arithmeticTypeInfo(result_ty); |
| 3517 | | 3563 | |
| 3518 | var wip = try self.elementWise(result_ty); | 3564 | var wip = try self.elementWise(result_ty, false); |
| 3519 | defer wip.deinit(); | 3565 | defer wip.deinit(); |
| 3520 | | 3566 | |
| 3521 | for (0..wip.results.len) |i| { | 3567 | for (0..wip.results.len) |i| { |
| 3522 | const args = .{ | 3568 | const args = .{ |
| 3523 | .id_result_type = wip.scalar_ty_id, | 3569 | .id_result_type = wip.ty_id, |
| 3524 | .id_result = wip.allocId(i), | 3570 | .id_result = wip.allocId(i), |
| 3525 | .operand = try wip.elementAt(result_ty, operand_id, i), | 3571 | .operand = try wip.elementAt(result_ty, operand_id, i), |
| 3526 | }; | 3572 | }; |
| ... | @@ -3563,10 +3609,7 @@ const DeclGen = struct { | ... | @@ -3563,10 +3609,7 @@ const DeclGen = struct { |
| 3563 | // Convert the pointer-to-array to a pointer to the first element. | 3609 | // Convert the pointer-to-array to a pointer to the first element. |
| 3564 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); | 3610 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); |
| 3565 | | 3611 | |
| 3566 | return try self.constructComposite( | 3612 | return try self.constructComposite(slice_ty, &.{ elem_ptr_id, len_id }); |
| 3567 | slice_ty, | | |
| 3568 | &.{ elem_ptr_id, len_id }, | | |
| 3569 | ); | | |
| 3570 | } | 3613 | } |
| 3571 | | 3614 | |
| 3572 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3615 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3580,10 +3623,7 @@ const DeclGen = struct { | ... | @@ -3580,10 +3623,7 @@ const DeclGen = struct { |
| 3580 | | 3623 | |
| 3581 | // Note: Types should not need to be converted to direct, these types | 3624 | // Note: Types should not need to be converted to direct, these types |
| 3582 | // dont need to be converted. | 3625 | // dont need to be converted. |
| 3583 | return try self.constructComposite( | 3626 | return try self.constructComposite(slice_ty, &.{ ptr_id, len_id }); |
| 3584 | slice_ty, | | |
| 3585 | &.{ ptr_id, len_id }, | | |
| 3586 | ); | | |
| 3587 | } | 3627 | } |
| 3588 | | 3628 | |
| 3589 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 3629 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| ... | @@ -3641,9 +3681,9 @@ const DeclGen = struct { | ... | @@ -3641,9 +3681,9 @@ const DeclGen = struct { |
| 3641 | const elem_ids = try self.gpa.alloc(IdRef, n_elems); | 3681 | const elem_ids = try self.gpa.alloc(IdRef, n_elems); |
| 3642 | defer self.gpa.free(elem_ids); | 3682 | defer self.gpa.free(elem_ids); |
| 3643 | | 3683 | |
| 3644 | for (elements, 0..) |element, i| { | 3684 | for (elements, elem_ids) |element, *elem_id| { |
| 3645 | const id = try self.resolve(element); | 3685 | const id = try self.resolve(element); |
| 3646 | elem_ids[i] = try self.convertToIndirect(result_ty.childType(mod), id); | 3686 | elem_id.* = try self.convertToIndirect(result_ty.childType(mod), id); |
| 3647 | } | 3687 | } |
| 3648 | | 3688 | |
| 3649 | return try self.constructComposite(result_ty, elem_ids); | 3689 | return try self.constructComposite(result_ty, elem_ids); |
| ... | @@ -3654,9 +3694,9 @@ const DeclGen = struct { | ... | @@ -3654,9 +3694,9 @@ const DeclGen = struct { |
| 3654 | const elem_ids = try self.gpa.alloc(IdRef, n_elems); | 3694 | const elem_ids = try self.gpa.alloc(IdRef, n_elems); |
| 3655 | defer self.gpa.free(elem_ids); | 3695 | defer self.gpa.free(elem_ids); |
| 3656 | | 3696 | |
| 3657 | for (elements, 0..) |element, i| { | 3697 | for (elements, elem_ids) |element, *elem_id| { |
| 3658 | const id = try self.resolve(element); | 3698 | const id = try self.resolve(element); |
| 3659 | elem_ids[i] = try self.convertToIndirect(array_info.elem_type, id); | 3699 | elem_id.* = try self.convertToIndirect(array_info.elem_type, id); |
| 3660 | } | 3700 | } |
| 3661 | | 3701 | |
| 3662 | if (array_info.sentinel) |sentinel_val| { | 3702 | if (array_info.sentinel) |sentinel_val| { |