| ... | ... | @@ -629,6 +629,16 @@ const DeclGen = struct { |
| 629 | 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 | 642 | fn arithmeticTypeInfo(self: *DeclGen, ty: Type) ArithmeticTypeInfo { |
| 633 | 643 | const mod = self.module; |
| 634 | 644 | const target = self.getTarget(); |
| ... | ... | @@ -694,6 +704,24 @@ const DeclGen = struct { |
| 694 | 704 | /// This function, unlike SpvModule.constInt, takes care to bitcast |
| 695 | 705 | /// the value to an unsigned int first for Kernels. |
| 696 | 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 | 725 | if (value < 0) { |
| 698 | 726 | const ty = self.spv.cache.lookup(ty_ref).int_type; |
| 699 | 727 | // Manually truncate the value so that the resulting value |
| ... | ... | @@ -711,6 +739,24 @@ const DeclGen = struct { |
| 711 | 739 | |
| 712 | 740 | /// Emits a float constant |
| 713 | 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 | 760 | const ty = self.spv.cache.lookup(ty_ref).float_type; |
| 715 | 761 | return switch (ty.bits) { |
| 716 | 762 | 16 => try self.spv.resolveId(.{ .float = .{ .ty = ty_ref, .value = .{ .float16 = @floatCast(value) } } }), |
| ... | ... | @@ -726,9 +772,9 @@ const DeclGen = struct { |
| 726 | 772 | /// if the parameters are in indirect representation, then the result is too. |
| 727 | 773 | fn constructComposite(self: *DeclGen, ty: Type, constituents: []const IdRef) !IdRef { |
| 728 | 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 | 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 | 778 | .id_result = constituents_id, |
| 733 | 779 | .constituents = constituents, |
| 734 | 780 | }); |
| ... | ... | @@ -1448,12 +1494,11 @@ const DeclGen = struct { |
| 1448 | 1494 | const elem_ty = ty.childType(mod); |
| 1449 | 1495 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); |
| 1450 | 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) |
| 1454 | | try self.spv.vectorType(ty.vectorLen(mod), elem_ty_ref) |
| 1498 | const ty_ref = if (self.isVector(ty)) |
| 1499 | try self.spv.vectorType(len, elem_ty_ref) |
| 1455 | 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 | 1503 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| 1459 | 1504 | return ty_ref; |
| ... | ... | @@ -1752,18 +1797,16 @@ const DeclGen = struct { |
| 1752 | 1797 | } |
| 1753 | 1798 | |
| 1754 | 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 | 1801 | const WipElementWise = struct { |
| 1757 | 1802 | dg: *DeclGen, |
| 1758 | 1803 | result_ty: Type, |
| 1804 | ty: Type, |
| 1759 | 1805 | /// Always in direct representation. |
| 1760 | | result_ty_ref: CacheRef, |
| 1761 | | scalar_ty: Type, |
| 1762 | | /// Always in direct representation. |
| 1763 | | scalar_ty_ref: CacheRef, |
| 1764 | | scalar_ty_id: IdRef, |
| 1765 | | /// True if the input is actually a vector type. |
| 1766 | | is_vector: bool, |
| 1806 | ty_ref: CacheRef, |
| 1807 | ty_id: IdRef, |
| 1808 | /// True if the input is an array type. |
| 1809 | is_array: bool, |
| 1767 | 1810 | /// The element-wise operation should fill these results before calling finalize(). |
| 1768 | 1811 | /// These should all be in **direct** representation! `finalize()` will convert |
| 1769 | 1812 | /// them to indirect if required. |
| ... | ... | @@ -1774,29 +1817,28 @@ const DeclGen = struct { |
| 1774 | 1817 | } |
| 1775 | 1818 | |
| 1776 | 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 |
| 1778 | | /// a scalar otherwise. |
| 1820 | /// input array. This type is expected to be a fake vector (array) if `wip.is_array`, and |
| 1821 | /// a vector or scalar otherwise. |
| 1779 | 1822 | fn elementAt(wip: WipElementWise, ty: Type, value: IdRef, index: usize) !IdRef { |
| 1780 | 1823 | const mod = wip.dg.module; |
| 1781 | | if (wip.is_vector) { |
| 1824 | if (wip.is_array) { |
| 1782 | 1825 | assert(ty.isVector(mod)); |
| 1783 | 1826 | return try wip.dg.extractField(ty.childType(mod), value, @intCast(index)); |
| 1784 | 1827 | } else { |
| 1785 | | assert(!ty.isVector(mod)); |
| 1786 | 1828 | assert(index == 0); |
| 1787 | 1829 | return value; |
| 1788 | 1830 | } |
| 1789 | 1831 | } |
| 1790 | 1832 | |
| 1791 | | /// Turns the results of this WipElementWise into a result. This can either |
| 1792 | | /// be a vector or single element, depending on `result_ty`. |
| 1833 | /// Turns the results of this WipElementWise into a result. This can be |
| 1834 | /// vectors, fake vectors (arrays) and single elements, depending on `result_ty`. |
| 1793 | 1835 | /// After calling this function, this WIP is no longer usable. |
| 1794 | 1836 | /// Results is in `direct` representation. |
| 1795 | 1837 | fn finalize(wip: *WipElementWise) !IdRef { |
| 1796 | | if (wip.is_vector) { |
| 1838 | if (wip.is_array) { |
| 1797 | 1839 | // Convert all the constituents to indirect, as required for the array. |
| 1798 | 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 | 1843 | return try wip.dg.constructComposite(wip.result_ty, wip.results); |
| 1802 | 1844 | } else { |
| ... | ... | @@ -1806,33 +1848,30 @@ const DeclGen = struct { |
| 1806 | 1848 | |
| 1807 | 1849 | /// Allocate a result id at a particular index, and return it. |
| 1808 | 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 | 1852 | wip.results[index] = wip.dg.spv.allocId(); |
| 1811 | 1853 | return wip.results[index]; |
| 1812 | 1854 | } |
| 1813 | 1855 | }; |
| 1814 | 1856 | |
| 1815 | 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 | 1859 | const mod = self.module; |
| 1818 | | // For now, this operation also reasons in terms of `.direct` representation. |
| 1819 | | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| 1820 | | const is_vector = result_ty.isVector(mod); |
| 1821 | | const num_results = if (is_vector) result_ty.vectorLen(mod) else 1; |
| 1860 | const is_array = result_ty.isVector(mod) and (!self.isVector(result_ty) or force_element_wise); |
| 1861 | const num_results = if (is_array) result_ty.vectorLen(mod) else 1; |
| 1822 | 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); |
| 1826 | | const scalar_ty_ref = try self.resolveType(scalar_ty, .direct); |
| 1865 | const ty = if (is_array) result_ty.scalarType(mod) else result_ty; |
| 1866 | const ty_ref = try self.resolveType(ty, .direct); |
| 1827 | 1867 | |
| 1828 | 1868 | return .{ |
| 1829 | 1869 | .dg = self, |
| 1830 | 1870 | .result_ty = result_ty, |
| 1831 | | .result_ty_ref = result_ty_ref, |
| 1832 | | .scalar_ty = scalar_ty, |
| 1833 | | .scalar_ty_ref = scalar_ty_ref, |
| 1834 | | .scalar_ty_id = self.typeId(scalar_ty_ref), |
| 1835 | | .is_vector = is_vector, |
| 1871 | .ty = ty, |
| 1872 | .ty_ref = ty_ref, |
| 1873 | .ty_id = self.typeId(ty_ref), |
| 1874 | .is_array = is_array, |
| 1836 | 1875 | .results = results, |
| 1837 | 1876 | }; |
| 1838 | 1877 | } |
| ... | ... | @@ -2160,7 +2199,6 @@ const DeclGen = struct { |
| 2160 | 2199 | fn genInst(self: *DeclGen, inst: Air.Inst.Index) !void { |
| 2161 | 2200 | const mod = self.module; |
| 2162 | 2201 | const ip = &mod.intern_pool; |
| 2163 | | // TODO: remove now-redundant isUnused calls from AIR handler functions |
| 2164 | 2202 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst, ip)) |
| 2165 | 2203 | return; |
| 2166 | 2204 | |
| ... | ... | @@ -2312,11 +2350,11 @@ const DeclGen = struct { |
| 2312 | 2350 | } |
| 2313 | 2351 | |
| 2314 | 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 | 2354 | defer wip.deinit(); |
| 2317 | 2355 | for (0..wip.results.len) |i| { |
| 2318 | 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 | 2358 | .id_result = wip.allocId(i), |
| 2321 | 2359 | .operand_1 = try wip.elementAt(ty, lhs_id, i), |
| 2322 | 2360 | .operand_2 = try wip.elementAt(ty, rhs_id, i), |
| ... | ... | @@ -2326,8 +2364,6 @@ const DeclGen = struct { |
| 2326 | 2364 | } |
| 2327 | 2365 | |
| 2328 | 2366 | fn airBinOpSimple(self: *DeclGen, inst: Air.Inst.Index, comptime opcode: Opcode) !?IdRef { |
| 2329 | | if (self.liveness.isUnused(inst)) return null; |
| 2330 | | |
| 2331 | 2367 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2332 | 2368 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2333 | 2369 | const rhs_id = try self.resolve(bin_op.rhs); |
| ... | ... | @@ -2337,7 +2373,6 @@ const DeclGen = struct { |
| 2337 | 2373 | } |
| 2338 | 2374 | |
| 2339 | 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 | 2376 | const mod = self.module; |
| 2342 | 2377 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2343 | 2378 | const lhs_id = try self.resolve(bin_op.lhs); |
| ... | ... | @@ -2345,7 +2380,7 @@ const DeclGen = struct { |
| 2345 | 2380 | |
| 2346 | 2381 | const result_ty = self.typeOfIndex(inst); |
| 2347 | 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); |
| 2349 | 2384 | |
| 2350 | 2385 | const info = self.arithmeticTypeInfo(result_ty); |
| 2351 | 2386 | switch (info.class) { |
| ... | ... | @@ -2354,7 +2389,7 @@ const DeclGen = struct { |
| 2354 | 2389 | .float, .bool => unreachable, |
| 2355 | 2390 | } |
| 2356 | 2391 | |
| 2357 | | var wip = try self.elementWise(result_ty); |
| 2392 | var wip = try self.elementWise(result_ty, false); |
| 2358 | 2393 | defer wip.deinit(); |
| 2359 | 2394 | for (wip.results, 0..) |*result_id, i| { |
| 2360 | 2395 | const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i); |
| ... | ... | @@ -2362,10 +2397,10 @@ const DeclGen = struct { |
| 2362 | 2397 | |
| 2363 | 2398 | // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that, |
| 2364 | 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 | 2401 | const shift_id = self.spv.allocId(); |
| 2367 | 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 | 2404 | .id_result = shift_id, |
| 2370 | 2405 | .unsigned_value = rhs_elem_id, |
| 2371 | 2406 | }); |
| ... | ... | @@ -2374,7 +2409,7 @@ const DeclGen = struct { |
| 2374 | 2409 | |
| 2375 | 2410 | const value_id = self.spv.allocId(); |
| 2376 | 2411 | const args = .{ |
| 2377 | | .id_result_type = wip.scalar_ty_id, |
| 2412 | .id_result_type = wip.ty_id, |
| 2378 | 2413 | .id_result = value_id, |
| 2379 | 2414 | .base = lhs_elem_id, |
| 2380 | 2415 | .shift = shift_id, |
| ... | ... | @@ -2386,14 +2421,12 @@ const DeclGen = struct { |
| 2386 | 2421 | try self.func.body.emit(self.spv.gpa, unsigned, args); |
| 2387 | 2422 | } |
| 2388 | 2423 | |
| 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 | 2426 | return try wip.finalize(); |
| 2392 | 2427 | } |
| 2393 | 2428 | |
| 2394 | 2429 | fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef { |
| 2395 | | if (self.liveness.isUnused(inst)) return null; |
| 2396 | | |
| 2397 | 2430 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2398 | 2431 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2399 | 2432 | const rhs_id = try self.resolve(bin_op.rhs); |
| ... | ... | @@ -2405,14 +2438,14 @@ const DeclGen = struct { |
| 2405 | 2438 | fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef { |
| 2406 | 2439 | const info = self.arithmeticTypeInfo(result_ty); |
| 2407 | 2440 | |
| 2408 | | var wip = try self.elementWise(result_ty); |
| 2441 | var wip = try self.elementWise(result_ty, true); |
| 2409 | 2442 | defer wip.deinit(); |
| 2410 | 2443 | for (wip.results, 0..) |*result_id, i| { |
| 2411 | 2444 | const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i); |
| 2412 | 2445 | const rhs_elem_id = try wip.elementAt(result_ty, rhs_id, i); |
| 2413 | 2446 | |
| 2414 | 2447 | // 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 | 2449 | const selection_id = switch (info.class) { |
| 2417 | 2450 | .float => blk: { |
| 2418 | 2451 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, |
| ... | ... | @@ -2440,7 +2473,7 @@ const DeclGen = struct { |
| 2440 | 2473 | |
| 2441 | 2474 | result_id.* = self.spv.allocId(); |
| 2442 | 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 | 2477 | .id_result = result_id.*, |
| 2445 | 2478 | .condition = selection_id, |
| 2446 | 2479 | .object_1 = lhs_elem_id, |
| ... | ... | @@ -2505,7 +2538,6 @@ const DeclGen = struct { |
| 2505 | 2538 | comptime sop: Opcode, |
| 2506 | 2539 | comptime uop: Opcode, |
| 2507 | 2540 | ) !?IdRef { |
| 2508 | | if (self.liveness.isUnused(inst)) return null; |
| 2509 | 2541 | |
| 2510 | 2542 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees |
| 2511 | 2543 | // the result to be the same as the LHS and RHS, which matches SPIR-V. |
| ... | ... | @@ -2545,7 +2577,7 @@ const DeclGen = struct { |
| 2545 | 2577 | .bool => unreachable, |
| 2546 | 2578 | }; |
| 2547 | 2579 | |
| 2548 | | var wip = try self.elementWise(ty); |
| 2580 | var wip = try self.elementWise(ty, false); |
| 2549 | 2581 | defer wip.deinit(); |
| 2550 | 2582 | for (wip.results, 0..) |*result_id, i| { |
| 2551 | 2583 | const lhs_elem_id = try wip.elementAt(ty, lhs_id, i); |
| ... | ... | @@ -2553,7 +2585,7 @@ const DeclGen = struct { |
| 2553 | 2585 | |
| 2554 | 2586 | const value_id = self.spv.allocId(); |
| 2555 | 2587 | const operands = .{ |
| 2556 | | .id_result_type = wip.scalar_ty_id, |
| 2588 | .id_result_type = wip.ty_id, |
| 2557 | 2589 | .id_result = value_id, |
| 2558 | 2590 | .operand_1 = lhs_elem_id, |
| 2559 | 2591 | .operand_2 = rhs_elem_id, |
| ... | ... | @@ -2568,26 +2600,24 @@ const DeclGen = struct { |
| 2568 | 2600 | |
| 2569 | 2601 | // TODO: Trap on overflow? Probably going to be annoying. |
| 2570 | 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 | } |
| 2573 | 2605 | |
| 2574 | 2606 | return try wip.finalize(); |
| 2575 | 2607 | } |
| 2576 | 2608 | |
| 2577 | 2609 | fn airAbs(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2578 | | if (self.liveness.isUnused(inst)) return null; |
| 2579 | | |
| 2580 | 2610 | const mod = self.module; |
| 2581 | 2611 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2582 | 2612 | const operand_id = try self.resolve(ty_op.operand); |
| 2583 | 2613 | // Note: operand_ty may be signed, while ty is always unsigned! |
| 2584 | 2614 | const operand_ty = self.typeOf(ty_op.operand); |
| 2585 | | const ty = self.typeOfIndex(inst); |
| 2586 | | const info = self.arithmeticTypeInfo(ty); |
| 2615 | const result_ty = self.typeOfIndex(inst); |
| 2616 | const info = self.arithmeticTypeInfo(result_ty); |
| 2587 | 2617 | const operand_scalar_ty = operand_ty.scalarType(mod); |
| 2588 | 2618 | const operand_scalar_ty_ref = try self.resolveType(operand_scalar_ty, .direct); |
| 2589 | 2619 | |
| 2590 | | var wip = try self.elementWise(ty); |
| 2620 | var wip = try self.elementWise(result_ty, true); |
| 2591 | 2621 | defer wip.deinit(); |
| 2592 | 2622 | |
| 2593 | 2623 | const zero_id = switch (info.class) { |
| ... | ... | @@ -2615,7 +2645,7 @@ const DeclGen = struct { |
| 2615 | 2645 | .composite_integer => unreachable, // TODO |
| 2616 | 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); |
| 2619 | 2649 | |
| 2620 | 2650 | const gt_zero_id = try self.cmp(.gt, Type.bool, operand_scalar_ty, elem_id, zero_id); |
| 2621 | 2651 | const abs_id = self.spv.allocId(); |
| ... | ... | @@ -2627,7 +2657,7 @@ const DeclGen = struct { |
| 2627 | 2657 | .object_2 = neg_norm_id, |
| 2628 | 2658 | }); |
| 2629 | 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 | 2662 | return try wip.finalize(); |
| 2633 | 2663 | } |
| ... | ... | @@ -2639,8 +2669,7 @@ const DeclGen = struct { |
| 2639 | 2669 | comptime ucmp: Opcode, |
| 2640 | 2670 | comptime scmp: Opcode, |
| 2641 | 2671 | ) !?IdRef { |
| 2642 | | if (self.liveness.isUnused(inst)) return null; |
| 2643 | | |
| 2672 | const mod = self.module; |
| 2644 | 2673 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2645 | 2674 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2646 | 2675 | const lhs = try self.resolve(extra.lhs); |
| ... | ... | @@ -2651,6 +2680,10 @@ const DeclGen = struct { |
| 2651 | 2680 | const ov_ty = result_ty.structFieldType(1, self.module); |
| 2652 | 2681 | |
| 2653 | 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; |
| 2654 | 2687 | |
| 2655 | 2688 | const info = self.arithmeticTypeInfo(operand_ty); |
| 2656 | 2689 | switch (info.class) { |
| ... | ... | @@ -2659,9 +2692,9 @@ const DeclGen = struct { |
| 2659 | 2692 | .float, .bool => unreachable, |
| 2660 | 2693 | } |
| 2661 | 2694 | |
| 2662 | | var wip_result = try self.elementWise(operand_ty); |
| 2695 | var wip_result = try self.elementWise(operand_ty, false); |
| 2663 | 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 | 2698 | defer wip_ov.deinit(); |
| 2666 | 2699 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { |
| 2667 | 2700 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); |
| ... | ... | @@ -2671,14 +2704,14 @@ const DeclGen = struct { |
| 2671 | 2704 | const value_id = self.spv.allocId(); |
| 2672 | 2705 | |
| 2673 | 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 | 2708 | .id_result = value_id, |
| 2676 | 2709 | .operand_1 = lhs_elem_id, |
| 2677 | 2710 | .operand_2 = rhs_elem_id, |
| 2678 | 2711 | }); |
| 2679 | 2712 | |
| 2680 | 2713 | // 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); |
| 2682 | 2715 | |
| 2683 | 2716 | const overflowed_id = switch (info.signedness) { |
| 2684 | 2717 | .unsigned => blk: { |
| ... | ... | @@ -2686,7 +2719,7 @@ const DeclGen = struct { |
| 2686 | 2719 | // For subtraction the conditions need to be swapped. |
| 2687 | 2720 | const overflowed_id = self.spv.allocId(); |
| 2688 | 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 | 2723 | .id_result = overflowed_id, |
| 2691 | 2724 | .operand_1 = result_id.*, |
| 2692 | 2725 | .operand_2 = lhs_elem_id, |
| ... | ... | @@ -2712,9 +2745,9 @@ const DeclGen = struct { |
| 2712 | 2745 | // = (rhs < 0) == (lhs > value) |
| 2713 | 2746 | |
| 2714 | 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 | 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 | 2751 | .id_result = rhs_lt_zero_id, |
| 2719 | 2752 | .operand_1 = rhs_elem_id, |
| 2720 | 2753 | .operand_2 = zero_id, |
| ... | ... | @@ -2722,7 +2755,7 @@ const DeclGen = struct { |
| 2722 | 2755 | |
| 2723 | 2756 | const value_gt_lhs_id = self.spv.allocId(); |
| 2724 | 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 | 2759 | .id_result = value_gt_lhs_id, |
| 2727 | 2760 | .operand_1 = lhs_elem_id, |
| 2728 | 2761 | .operand_2 = result_id.*, |
| ... | ... | @@ -2730,7 +2763,7 @@ const DeclGen = struct { |
| 2730 | 2763 | |
| 2731 | 2764 | const overflowed_id = self.spv.allocId(); |
| 2732 | 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 | 2767 | .id_result = overflowed_id, |
| 2735 | 2768 | .operand_1 = rhs_lt_zero_id, |
| 2736 | 2769 | .operand_2 = value_gt_lhs_id, |
| ... | ... | @@ -2739,7 +2772,7 @@ const DeclGen = struct { |
| 2739 | 2772 | }, |
| 2740 | 2773 | }; |
| 2741 | 2774 | |
| 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 | } |
| 2744 | 2777 | |
| 2745 | 2778 | return try self.constructComposite( |
| ... | ... | @@ -2749,7 +2782,6 @@ const DeclGen = struct { |
| 2749 | 2782 | } |
| 2750 | 2783 | |
| 2751 | 2784 | fn airShlOverflow(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2752 | | if (self.liveness.isUnused(inst)) return null; |
| 2753 | 2785 | const mod = self.module; |
| 2754 | 2786 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2755 | 2787 | const extra = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | ... | @@ -2759,11 +2791,15 @@ const DeclGen = struct { |
| 2759 | 2791 | const result_ty = self.typeOfIndex(inst); |
| 2760 | 2792 | const operand_ty = self.typeOf(extra.lhs); |
| 2761 | 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); |
| 2763 | 2795 | |
| 2764 | 2796 | const ov_ty = result_ty.structFieldType(1, self.module); |
| 2765 | 2797 | |
| 2766 | 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; |
| 2767 | 2803 | |
| 2768 | 2804 | const info = self.arithmeticTypeInfo(operand_ty); |
| 2769 | 2805 | switch (info.class) { |
| ... | ... | @@ -2772,9 +2808,9 @@ const DeclGen = struct { |
| 2772 | 2808 | .float, .bool => unreachable, |
| 2773 | 2809 | } |
| 2774 | 2810 | |
| 2775 | | var wip_result = try self.elementWise(operand_ty); |
| 2811 | var wip_result = try self.elementWise(operand_ty, false); |
| 2776 | 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 | 2814 | defer wip_ov.deinit(); |
| 2779 | 2815 | for (wip_result.results, wip_ov.results, 0..) |*result_id, *ov_id, i| { |
| 2780 | 2816 | const lhs_elem_id = try wip_result.elementAt(operand_ty, lhs, i); |
| ... | ... | @@ -2782,10 +2818,10 @@ const DeclGen = struct { |
| 2782 | 2818 | |
| 2783 | 2819 | // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that, |
| 2784 | 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 | 2822 | const shift_id = self.spv.allocId(); |
| 2787 | 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 | 2825 | .id_result = shift_id, |
| 2790 | 2826 | .unsigned_value = rhs_elem_id, |
| 2791 | 2827 | }); |
| ... | ... | @@ -2794,18 +2830,18 @@ const DeclGen = struct { |
| 2794 | 2830 | |
| 2795 | 2831 | const value_id = self.spv.allocId(); |
| 2796 | 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 | 2834 | .id_result = value_id, |
| 2799 | 2835 | .base = lhs_elem_id, |
| 2800 | 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); |
| 2803 | 2839 | |
| 2804 | 2840 | const right_shift_id = self.spv.allocId(); |
| 2805 | 2841 | switch (info.signedness) { |
| 2806 | 2842 | .signed => { |
| 2807 | 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 | 2845 | .id_result = right_shift_id, |
| 2810 | 2846 | .base = result_id.*, |
| 2811 | 2847 | .shift = shift_id, |
| ... | ... | @@ -2813,7 +2849,7 @@ const DeclGen = struct { |
| 2813 | 2849 | }, |
| 2814 | 2850 | .unsigned => { |
| 2815 | 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 | 2853 | .id_result = right_shift_id, |
| 2818 | 2854 | .base = result_id.*, |
| 2819 | 2855 | .shift = shift_id, |
| ... | ... | @@ -2823,13 +2859,13 @@ const DeclGen = struct { |
| 2823 | 2859 | |
| 2824 | 2860 | const overflowed_id = self.spv.allocId(); |
| 2825 | 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 | 2863 | .id_result = overflowed_id, |
| 2828 | 2864 | .operand_1 = lhs_elem_id, |
| 2829 | 2865 | .operand_2 = right_shift_id, |
| 2830 | 2866 | }); |
| 2831 | 2867 | |
| 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 | } |
| 2834 | 2870 | |
| 2835 | 2871 | return try self.constructComposite( |
| ... | ... | @@ -2839,8 +2875,6 @@ const DeclGen = struct { |
| 2839 | 2875 | } |
| 2840 | 2876 | |
| 2841 | 2877 | fn airMulAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2842 | | if (self.liveness.isUnused(inst)) return null; |
| 2843 | | |
| 2844 | 2878 | const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op; |
| 2845 | 2879 | const extra = self.air.extraData(Air.Bin, pl_op.payload).data; |
| 2846 | 2880 | |
| ... | ... | @@ -2853,19 +2887,19 @@ const DeclGen = struct { |
| 2853 | 2887 | const info = self.arithmeticTypeInfo(ty); |
| 2854 | 2888 | assert(info.class == .float); // .mul_add is only emitted for floats |
| 2855 | 2889 | |
| 2856 | | var wip = try self.elementWise(ty); |
| 2890 | var wip = try self.elementWise(ty, false); |
| 2857 | 2891 | defer wip.deinit(); |
| 2858 | 2892 | for (0..wip.results.len) |i| { |
| 2859 | 2893 | const mul_result = self.spv.allocId(); |
| 2860 | 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 | 2896 | .id_result = mul_result, |
| 2863 | 2897 | .operand_1 = try wip.elementAt(ty, mulend1, i), |
| 2864 | 2898 | .operand_2 = try wip.elementAt(ty, mulend2, i), |
| 2865 | 2899 | }); |
| 2866 | 2900 | |
| 2867 | 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 | 2903 | .id_result = wip.allocId(i), |
| 2870 | 2904 | .operand_1 = mul_result, |
| 2871 | 2905 | .operand_2 = try wip.elementAt(ty, addend, i), |
| ... | ... | @@ -2875,20 +2909,16 @@ const DeclGen = struct { |
| 2875 | 2909 | } |
| 2876 | 2910 | |
| 2877 | 2911 | fn airSplat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2878 | | if (self.liveness.isUnused(inst)) return null; |
| 2879 | 2912 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 2880 | 2913 | const operand_id = try self.resolve(ty_op.operand); |
| 2881 | 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 | 2916 | defer wip.deinit(); |
| 2884 | | for (wip.results) |*result_id| { |
| 2885 | | result_id.* = operand_id; |
| 2886 | | } |
| 2917 | @memset(wip.results, operand_id); |
| 2887 | 2918 | return try wip.finalize(); |
| 2888 | 2919 | } |
| 2889 | 2920 | |
| 2890 | 2921 | fn airReduce(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2891 | | if (self.liveness.isUnused(inst)) return null; |
| 2892 | 2922 | const mod = self.module; |
| 2893 | 2923 | const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce; |
| 2894 | 2924 | const operand = try self.resolve(reduce.operand); |
| ... | ... | @@ -2956,7 +2986,6 @@ const DeclGen = struct { |
| 2956 | 2986 | |
| 2957 | 2987 | fn airShuffle(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2958 | 2988 | const mod = self.module; |
| 2959 | | if (self.liveness.isUnused(inst)) return null; |
| 2960 | 2989 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 2961 | 2990 | const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data; |
| 2962 | 2991 | const a = try self.resolve(extra.a); |
| ... | ... | @@ -2965,20 +2994,20 @@ const DeclGen = struct { |
| 2965 | 2994 | |
| 2966 | 2995 | const ty = self.typeOfIndex(inst); |
| 2967 | 2996 | |
| 2968 | | var wip = try self.elementWise(ty); |
| 2997 | var wip = try self.elementWise(ty, true); |
| 2969 | 2998 | defer wip.deinit(); |
| 2970 | 2999 | for (wip.results, 0..) |*result_id, i| { |
| 2971 | 3000 | const elem = try mask.elemValue(mod, i); |
| 2972 | 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 | 3003 | continue; |
| 2975 | 3004 | } |
| 2976 | 3005 | |
| 2977 | 3006 | const index = elem.toSignedInt(mod); |
| 2978 | 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 | 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 | 3013 | return try wip.finalize(); |
| ... | ... | @@ -3069,7 +3098,6 @@ const DeclGen = struct { |
| 3069 | 3098 | } |
| 3070 | 3099 | |
| 3071 | 3100 | fn airPtrAdd(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3072 | | if (self.liveness.isUnused(inst)) return null; |
| 3073 | 3101 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3074 | 3102 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3075 | 3103 | const ptr_id = try self.resolve(bin_op.lhs); |
| ... | ... | @@ -3081,7 +3109,6 @@ const DeclGen = struct { |
| 3081 | 3109 | } |
| 3082 | 3110 | |
| 3083 | 3111 | fn airPtrSub(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3084 | | if (self.liveness.isUnused(inst)) return null; |
| 3085 | 3112 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3086 | 3113 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3087 | 3114 | const ptr_id = try self.resolve(bin_op.lhs); |
| ... | ... | @@ -3188,7 +3215,7 @@ const DeclGen = struct { |
| 3188 | 3215 | return result_id; |
| 3189 | 3216 | }, |
| 3190 | 3217 | .Vector => { |
| 3191 | | var wip = try self.elementWise(result_ty); |
| 3218 | var wip = try self.elementWise(result_ty, true); |
| 3192 | 3219 | defer wip.deinit(); |
| 3193 | 3220 | const scalar_ty = ty.scalarType(mod); |
| 3194 | 3221 | for (wip.results, 0..) |*result_id, i| { |
| ... | ... | @@ -3257,7 +3284,6 @@ const DeclGen = struct { |
| 3257 | 3284 | inst: Air.Inst.Index, |
| 3258 | 3285 | comptime op: std.math.CompareOperator, |
| 3259 | 3286 | ) !?IdRef { |
| 3260 | | if (self.liveness.isUnused(inst)) return null; |
| 3261 | 3287 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3262 | 3288 | const lhs_id = try self.resolve(bin_op.lhs); |
| 3263 | 3289 | const rhs_id = try self.resolve(bin_op.rhs); |
| ... | ... | @@ -3268,8 +3294,6 @@ const DeclGen = struct { |
| 3268 | 3294 | } |
| 3269 | 3295 | |
| 3270 | 3296 | fn airVectorCmp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3271 | | if (self.liveness.isUnused(inst)) return null; |
| 3272 | | |
| 3273 | 3297 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3274 | 3298 | const vec_cmp = self.air.extraData(Air.VectorCmp, ty_pl.payload).data; |
| 3275 | 3299 | const lhs_id = try self.resolve(vec_cmp.lhs); |
| ... | ... | @@ -3351,7 +3375,6 @@ const DeclGen = struct { |
| 3351 | 3375 | } |
| 3352 | 3376 | |
| 3353 | 3377 | fn airBitCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3354 | | if (self.liveness.isUnused(inst)) return null; |
| 3355 | 3378 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3356 | 3379 | const operand_id = try self.resolve(ty_op.operand); |
| 3357 | 3380 | const operand_ty = self.typeOf(ty_op.operand); |
| ... | ... | @@ -3360,8 +3383,6 @@ const DeclGen = struct { |
| 3360 | 3383 | } |
| 3361 | 3384 | |
| 3362 | 3385 | fn airIntCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3363 | | if (self.liveness.isUnused(inst)) return null; |
| 3364 | | |
| 3365 | 3386 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3366 | 3387 | const operand_id = try self.resolve(ty_op.operand); |
| 3367 | 3388 | const src_ty = self.typeOf(ty_op.operand); |
| ... | ... | @@ -3374,19 +3395,19 @@ const DeclGen = struct { |
| 3374 | 3395 | return operand_id; |
| 3375 | 3396 | } |
| 3376 | 3397 | |
| 3377 | | var wip = try self.elementWise(dst_ty); |
| 3398 | var wip = try self.elementWise(dst_ty, false); |
| 3378 | 3399 | defer wip.deinit(); |
| 3379 | 3400 | for (wip.results, 0..) |*result_id, i| { |
| 3380 | 3401 | const elem_id = try wip.elementAt(src_ty, operand_id, i); |
| 3381 | 3402 | const value_id = self.spv.allocId(); |
| 3382 | 3403 | switch (dst_info.signedness) { |
| 3383 | 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 | 3406 | .id_result = value_id, |
| 3386 | 3407 | .signed_value = elem_id, |
| 3387 | 3408 | }), |
| 3388 | 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 | 3411 | .id_result = value_id, |
| 3391 | 3412 | .unsigned_value = elem_id, |
| 3392 | 3413 | }), |
| ... | ... | @@ -3397,7 +3418,7 @@ const DeclGen = struct { |
| 3397 | 3418 | // type, we don't need to normalize when growing the type. The |
| 3398 | 3419 | // representation is already the same. |
| 3399 | 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 | 3422 | } else { |
| 3402 | 3423 | result_id.* = value_id; |
| 3403 | 3424 | } |
| ... | ... | @@ -3417,16 +3438,12 @@ const DeclGen = struct { |
| 3417 | 3438 | } |
| 3418 | 3439 | |
| 3419 | 3440 | fn airIntFromPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3420 | | if (self.liveness.isUnused(inst)) return null; |
| 3421 | | |
| 3422 | 3441 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 3423 | 3442 | const operand_id = try self.resolve(un_op); |
| 3424 | 3443 | return try self.intFromPtr(operand_id); |
| 3425 | 3444 | } |
| 3426 | 3445 | |
| 3427 | 3446 | fn airFloatFromInt(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3428 | | if (self.liveness.isUnused(inst)) return null; |
| 3429 | | |
| 3430 | 3447 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3431 | 3448 | const operand_ty = self.typeOf(ty_op.operand); |
| 3432 | 3449 | const operand_id = try self.resolve(ty_op.operand); |
| ... | ... | @@ -3451,8 +3468,6 @@ const DeclGen = struct { |
| 3451 | 3468 | } |
| 3452 | 3469 | |
| 3453 | 3470 | fn airIntFromFloat(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3454 | | if (self.liveness.isUnused(inst)) return null; |
| 3455 | | |
| 3456 | 3471 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3457 | 3472 | const operand_id = try self.resolve(ty_op.operand); |
| 3458 | 3473 | const dest_ty = self.typeOfIndex(inst); |
| ... | ... | @@ -3476,24 +3491,20 @@ const DeclGen = struct { |
| 3476 | 3491 | } |
| 3477 | 3492 | |
| 3478 | 3493 | fn airIntFromBool(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3479 | | if (self.liveness.isUnused(inst)) return null; |
| 3480 | | |
| 3481 | 3494 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 3482 | 3495 | const operand_id = try self.resolve(un_op); |
| 3483 | 3496 | const result_ty = self.typeOfIndex(inst); |
| 3484 | 3497 | |
| 3485 | | var wip = try self.elementWise(result_ty); |
| 3498 | var wip = try self.elementWise(result_ty, false); |
| 3486 | 3499 | defer wip.deinit(); |
| 3487 | 3500 | for (wip.results, 0..) |*result_id, i| { |
| 3488 | 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 | 3504 | return try wip.finalize(); |
| 3492 | 3505 | } |
| 3493 | 3506 | |
| 3494 | 3507 | fn airFloatCast(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3495 | | if (self.liveness.isUnused(inst)) return null; |
| 3496 | | |
| 3497 | 3508 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3498 | 3509 | const operand_id = try self.resolve(ty_op.operand); |
| 3499 | 3510 | const dest_ty = self.typeOfIndex(inst); |
| ... | ... | @@ -3509,18 +3520,17 @@ const DeclGen = struct { |
| 3509 | 3520 | } |
| 3510 | 3521 | |
| 3511 | 3522 | fn airNot(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3512 | | if (self.liveness.isUnused(inst)) return null; |
| 3513 | 3523 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3514 | 3524 | const operand_id = try self.resolve(ty_op.operand); |
| 3515 | 3525 | const result_ty = self.typeOfIndex(inst); |
| 3516 | 3526 | const info = self.arithmeticTypeInfo(result_ty); |
| 3517 | 3527 | |
| 3518 | | var wip = try self.elementWise(result_ty); |
| 3528 | var wip = try self.elementWise(result_ty, false); |
| 3519 | 3529 | defer wip.deinit(); |
| 3520 | 3530 | |
| 3521 | 3531 | for (0..wip.results.len) |i| { |
| 3522 | 3532 | const args = .{ |
| 3523 | | .id_result_type = wip.scalar_ty_id, |
| 3533 | .id_result_type = wip.ty_id, |
| 3524 | 3534 | .id_result = wip.allocId(i), |
| 3525 | 3535 | .operand = try wip.elementAt(result_ty, operand_id, i), |
| 3526 | 3536 | }; |
| ... | ... | @@ -3541,8 +3551,6 @@ const DeclGen = struct { |
| 3541 | 3551 | } |
| 3542 | 3552 | |
| 3543 | 3553 | fn airArrayToSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3544 | | if (self.liveness.isUnused(inst)) return null; |
| 3545 | | |
| 3546 | 3554 | const mod = self.module; |
| 3547 | 3555 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3548 | 3556 | const array_ptr_ty = self.typeOf(ty_op.operand); |
| ... | ... | @@ -3563,15 +3571,10 @@ const DeclGen = struct { |
| 3563 | 3571 | // Convert the pointer-to-array to a pointer to the first element. |
| 3564 | 3572 | try self.accessChain(elem_ptr_ty_ref, array_ptr_id, &.{0}); |
| 3565 | 3573 | |
| 3566 | | return try self.constructComposite( |
| 3567 | | slice_ty, |
| 3568 | | &.{ elem_ptr_id, len_id }, |
| 3569 | | ); |
| 3574 | return try self.constructComposite(slice_ty, &.{ elem_ptr_id, len_id }); |
| 3570 | 3575 | } |
| 3571 | 3576 | |
| 3572 | 3577 | fn airSlice(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3573 | | if (self.liveness.isUnused(inst)) return null; |
| 3574 | | |
| 3575 | 3578 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3576 | 3579 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3577 | 3580 | const ptr_id = try self.resolve(bin_op.lhs); |
| ... | ... | @@ -3580,15 +3583,10 @@ const DeclGen = struct { |
| 3580 | 3583 | |
| 3581 | 3584 | // Note: Types should not need to be converted to direct, these types |
| 3582 | 3585 | // dont need to be converted. |
| 3583 | | return try self.constructComposite( |
| 3584 | | slice_ty, |
| 3585 | | &.{ ptr_id, len_id }, |
| 3586 | | ); |
| 3586 | return try self.constructComposite(slice_ty, &.{ ptr_id, len_id }); |
| 3587 | 3587 | } |
| 3588 | 3588 | |
| 3589 | 3589 | fn airAggregateInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3590 | | if (self.liveness.isUnused(inst)) return null; |
| 3591 | | |
| 3592 | 3590 | const mod = self.module; |
| 3593 | 3591 | const ip = &mod.intern_pool; |
| 3594 | 3592 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -3710,7 +3708,6 @@ const DeclGen = struct { |
| 3710 | 3708 | } |
| 3711 | 3709 | |
| 3712 | 3710 | fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef { |
| 3713 | | if (self.liveness.isUnused(inst)) return null; |
| 3714 | 3711 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3715 | 3712 | const field_ty = self.typeOfIndex(inst); |
| 3716 | 3713 | const operand_id = try self.resolve(ty_op.operand); |
| ... | ... | @@ -3767,8 +3764,6 @@ const DeclGen = struct { |
| 3767 | 3764 | } |
| 3768 | 3765 | |
| 3769 | 3766 | fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3770 | | if (self.liveness.isUnused(inst)) return null; |
| 3771 | | |
| 3772 | 3767 | const mod = self.module; |
| 3773 | 3768 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3774 | 3769 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| ... | ... | @@ -3786,8 +3781,6 @@ const DeclGen = struct { |
| 3786 | 3781 | } |
| 3787 | 3782 | |
| 3788 | 3783 | fn airArrayElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3789 | | if (self.liveness.isUnused(inst)) return null; |
| 3790 | | |
| 3791 | 3784 | const mod = self.module; |
| 3792 | 3785 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3793 | 3786 | const array_ty = self.typeOf(bin_op.lhs); |
| ... | ... | @@ -3808,8 +3801,6 @@ const DeclGen = struct { |
| 3808 | 3801 | } |
| 3809 | 3802 | |
| 3810 | 3803 | fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3811 | | if (self.liveness.isUnused(inst)) return null; |
| 3812 | | |
| 3813 | 3804 | const mod = self.module; |
| 3814 | 3805 | const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3815 | 3806 | const ptr_ty = self.typeOf(bin_op.lhs); |
| ... | ... | @@ -3866,8 +3857,6 @@ const DeclGen = struct { |
| 3866 | 3857 | } |
| 3867 | 3858 | |
| 3868 | 3859 | fn airGetUnionTag(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3869 | | if (self.liveness.isUnused(inst)) return null; |
| 3870 | | |
| 3871 | 3860 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3872 | 3861 | const un_ty = self.typeOf(ty_op.operand); |
| 3873 | 3862 | |
| ... | ... | @@ -3951,8 +3940,6 @@ const DeclGen = struct { |
| 3951 | 3940 | } |
| 3952 | 3941 | |
| 3953 | 3942 | fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3954 | | if (self.liveness.isUnused(inst)) return null; |
| 3955 | | |
| 3956 | 3943 | const mod = self.module; |
| 3957 | 3944 | const ip = &mod.intern_pool; |
| 3958 | 3945 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| ... | ... | @@ -3969,8 +3956,6 @@ const DeclGen = struct { |
| 3969 | 3956 | } |
| 3970 | 3957 | |
| 3971 | 3958 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3972 | | if (self.liveness.isUnused(inst)) return null; |
| 3973 | | |
| 3974 | 3959 | const mod = self.module; |
| 3975 | 3960 | const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3976 | 3961 | const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; |
| ... | ... | @@ -4091,7 +4076,6 @@ const DeclGen = struct { |
| 4091 | 4076 | } |
| 4092 | 4077 | |
| 4093 | 4078 | fn airStructFieldPtrIndex(self: *DeclGen, inst: Air.Inst.Index, field_index: u32) !?IdRef { |
| 4094 | | if (self.liveness.isUnused(inst)) return null; |
| 4095 | 4079 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4096 | 4080 | const struct_ptr = try self.resolve(ty_op.operand); |
| 4097 | 4081 | const struct_ptr_ty = self.typeOf(ty_op.operand); |
| ... | ... | @@ -4145,7 +4129,6 @@ const DeclGen = struct { |
| 4145 | 4129 | } |
| 4146 | 4130 | |
| 4147 | 4131 | fn airAlloc(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4148 | | if (self.liveness.isUnused(inst)) return null; |
| 4149 | 4132 | const mod = self.module; |
| 4150 | 4133 | const ptr_ty = self.typeOfIndex(inst); |
| 4151 | 4134 | assert(ptr_ty.ptrAddressSpace(mod) == .generic); |
| ... | ... | @@ -4729,9 +4712,7 @@ const DeclGen = struct { |
| 4729 | 4712 | |
| 4730 | 4713 | try self.beginSpvBlock(ok_block); |
| 4731 | 4714 | } |
| 4732 | | if (self.liveness.isUnused(inst)) { |
| 4733 | | return null; |
| 4734 | | } |
| 4715 | |
| 4735 | 4716 | if (!eu_layout.payload_has_bits) { |
| 4736 | 4717 | return null; |
| 4737 | 4718 | } |
| ... | ... | @@ -4741,8 +4722,6 @@ const DeclGen = struct { |
| 4741 | 4722 | } |
| 4742 | 4723 | |
| 4743 | 4724 | fn airErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4744 | | if (self.liveness.isUnused(inst)) return null; |
| 4745 | | |
| 4746 | 4725 | const mod = self.module; |
| 4747 | 4726 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4748 | 4727 | const operand_id = try self.resolve(ty_op.operand); |
| ... | ... | @@ -4766,8 +4745,6 @@ const DeclGen = struct { |
| 4766 | 4745 | } |
| 4767 | 4746 | |
| 4768 | 4747 | fn airErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4769 | | if (self.liveness.isUnused(inst)) return null; |
| 4770 | | |
| 4771 | 4748 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4772 | 4749 | const operand_id = try self.resolve(ty_op.operand); |
| 4773 | 4750 | const payload_ty = self.typeOfIndex(inst); |
| ... | ... | @@ -4781,8 +4758,6 @@ const DeclGen = struct { |
| 4781 | 4758 | } |
| 4782 | 4759 | |
| 4783 | 4760 | fn airWrapErrUnionErr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4784 | | if (self.liveness.isUnused(inst)) return null; |
| 4785 | | |
| 4786 | 4761 | const mod = self.module; |
| 4787 | 4762 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4788 | 4763 | const err_union_ty = self.typeOfIndex(inst); |
| ... | ... | @@ -4804,8 +4779,6 @@ const DeclGen = struct { |
| 4804 | 4779 | } |
| 4805 | 4780 | |
| 4806 | 4781 | fn airWrapErrUnionPayload(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4807 | | if (self.liveness.isUnused(inst)) return null; |
| 4808 | | |
| 4809 | 4782 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4810 | 4783 | const err_union_ty = self.typeOfIndex(inst); |
| 4811 | 4784 | const operand_id = try self.resolve(ty_op.operand); |
| ... | ... | @@ -4825,8 +4798,6 @@ const DeclGen = struct { |
| 4825 | 4798 | } |
| 4826 | 4799 | |
| 4827 | 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 | 4801 | const mod = self.module; |
| 4831 | 4802 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 4832 | 4803 | const operand_id = try self.resolve(un_op); |
| ... | ... | @@ -4899,8 +4870,6 @@ const DeclGen = struct { |
| 4899 | 4870 | } |
| 4900 | 4871 | |
| 4901 | 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 | 4873 | const mod = self.module; |
| 4905 | 4874 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 4906 | 4875 | const operand_id = try self.resolve(un_op); |
| ... | ... | @@ -4935,8 +4904,6 @@ const DeclGen = struct { |
| 4935 | 4904 | } |
| 4936 | 4905 | |
| 4937 | 4906 | fn airUnwrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4938 | | if (self.liveness.isUnused(inst)) return null; |
| 4939 | | |
| 4940 | 4907 | const mod = self.module; |
| 4941 | 4908 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4942 | 4909 | const operand_id = try self.resolve(ty_op.operand); |
| ... | ... | @@ -4953,8 +4920,6 @@ const DeclGen = struct { |
| 4953 | 4920 | } |
| 4954 | 4921 | |
| 4955 | 4922 | fn airUnwrapOptionalPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4956 | | if (self.liveness.isUnused(inst)) return null; |
| 4957 | | |
| 4958 | 4923 | const mod = self.module; |
| 4959 | 4924 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4960 | 4925 | const operand_id = try self.resolve(ty_op.operand); |
| ... | ... | @@ -4979,8 +4944,6 @@ const DeclGen = struct { |
| 4979 | 4944 | } |
| 4980 | 4945 | |
| 4981 | 4946 | fn airWrapOptional(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 4982 | | if (self.liveness.isUnused(inst)) return null; |
| 4983 | | |
| 4984 | 4947 | const mod = self.module; |
| 4985 | 4948 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 4986 | 4949 | const payload_ty = self.typeOf(ty_op.operand); |