| ... | ... | @@ -531,7 +531,17 @@ const DeclGen = struct { |
| 531 | 531 | }, |
| 532 | 532 | .Enum => return self.arithmeticTypeInfo(ty.intTagType(mod)), |
| 533 | 533 | // As of yet, there is no vector support in the self-hosted compiler. |
| 534 | | .Vector => self.todo("implement arithmeticTypeInfo for Vector", .{}), |
| 534 | .Vector => blk: { |
| 535 | const child_type = ty.childType(mod); |
| 536 | const child_ty_info = try self.arithmeticTypeInfo(child_type); |
| 537 | break :blk ArithmeticTypeInfo{ |
| 538 | .bits = child_ty_info.bits, |
| 539 | .backing_bits = child_ty_info.backing_bits, |
| 540 | .is_vector = true, |
| 541 | .signedness = child_ty_info.signedness, |
| 542 | .class = child_ty_info.class, |
| 543 | }; |
| 544 | }, |
| 535 | 545 | // TODO: For which types is this the case? |
| 536 | 546 | // else => self.todo("implement arithmeticTypeInfo for {}", .{ty.fmt(self.module)}), |
| 537 | 547 | else => unreachable, |
| ... | ... | @@ -609,7 +619,7 @@ const DeclGen = struct { |
| 609 | 619 | return result_id; |
| 610 | 620 | } |
| 611 | 621 | |
| 612 | | /// Construct a struct at runtime. |
| 622 | /// Construct an array at runtime. |
| 613 | 623 | /// result_ty_ref must be an array type. |
| 614 | 624 | /// Constituents should be in `indirect` representation (as the elements of an array should be). |
| 615 | 625 | /// Result is in `direct` representation. |
| ... | ... | @@ -812,7 +822,7 @@ const DeclGen = struct { |
| 812 | 822 | return try self.constructStruct(result_ty_ref, &.{ payload_id, has_pl_id }); |
| 813 | 823 | }, |
| 814 | 824 | .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { |
| 815 | | .array_type => |array_type| { |
| 825 | inline .array_type, .vector_type => |array_type, tag| { |
| 816 | 826 | const elem_ty = array_type.child.toType(); |
| 817 | 827 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); |
| 818 | 828 | |
| ... | ... | @@ -839,9 +849,14 @@ const DeclGen = struct { |
| 839 | 849 | } |
| 840 | 850 | }, |
| 841 | 851 | } |
| 842 | | if (array_type.sentinel != .none) { |
| 843 | | constituents[constituents.len - 1] = try self.constant(elem_ty, array_type.sentinel.toValue(), .indirect); |
| 852 | |
| 853 | switch (tag) { |
| 854 | inline .array_type => if (array_type.sentinel != .none) { |
| 855 | constituents[constituents.len - 1] = try self.constant(elem_ty, array_type.sentinel.toValue(), .indirect); |
| 856 | }, |
| 857 | else => {}, |
| 844 | 858 | } |
| 859 | |
| 845 | 860 | return try self.constructArray(result_ty_ref, constituents); |
| 846 | 861 | }, |
| 847 | 862 | .struct_type => { |
| ... | ... | @@ -870,7 +885,6 @@ const DeclGen = struct { |
| 870 | 885 | |
| 871 | 886 | return try self.constructStruct(result_ty_ref, constituents.items); |
| 872 | 887 | }, |
| 873 | | .vector_type => unreachable, // TODO |
| 874 | 888 | .anon_struct_type => unreachable, // TODO |
| 875 | 889 | else => unreachable, |
| 876 | 890 | }, |
| ... | ... | @@ -1347,19 +1361,14 @@ const DeclGen = struct { |
| 1347 | 1361 | } }); |
| 1348 | 1362 | }, |
| 1349 | 1363 | .Vector => { |
| 1350 | | // Although not 100% the same, Zig vectors map quite neatly to SPIR-V vectors (including many integer and float operations |
| 1351 | | // which work on them), so simply use those. |
| 1352 | | // Note: SPIR-V vectors only support bools, ints and floats, so pointer vectors need to be supported another way. |
| 1353 | | // "composite integers" (larger than the largest supported native type) can probably be represented by an array of vectors. |
| 1354 | | // TODO: The SPIR-V spec mentions that vector sizes may be quite restricted! look into which we can use, and whether OpTypeVector |
| 1355 | | // is adequate at all for this. |
| 1356 | | |
| 1357 | | // TODO: Properly verify sizes and child type. |
| 1358 | | |
| 1359 | | return try self.spv.resolve(.{ .vector_type = .{ |
| 1360 | | .component_type = try self.resolveType(ty.childType(mod), repr), |
| 1361 | | .component_count = @as(u32, @intCast(ty.vectorLen(mod))), |
| 1362 | | } }); |
| 1364 | if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; |
| 1365 | |
| 1366 | const elem_ty = ty.childType(mod); |
| 1367 | const elem_ty_ref = try self.resolveType(elem_ty, .indirect); |
| 1368 | |
| 1369 | const ty_ref = try self.spv.arrayType(ty.vectorLen(mod), elem_ty_ref); |
| 1370 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| 1371 | return ty_ref; |
| 1363 | 1372 | }, |
| 1364 | 1373 | .Struct => { |
| 1365 | 1374 | if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; |
| ... | ... | @@ -2223,18 +2232,52 @@ const DeclGen = struct { |
| 2223 | 2232 | comptime modular: bool, |
| 2224 | 2233 | ) !?IdRef { |
| 2225 | 2234 | if (self.liveness.isUnused(inst)) return null; |
| 2235 | |
| 2226 | 2236 | // LHS and RHS are guaranteed to have the same type, and AIR guarantees |
| 2227 | 2237 | // the result to be the same as the LHS and RHS, which matches SPIR-V. |
| 2228 | 2238 | const ty = self.typeOfIndex(inst); |
| 2229 | 2239 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2230 | | var lhs_id = try self.resolve(bin_op.lhs); |
| 2231 | | var rhs_id = try self.resolve(bin_op.rhs); |
| 2232 | | |
| 2233 | | const result_ty_ref = try self.resolveType(ty, .direct); |
| 2240 | const lhs_id = try self.resolve(bin_op.lhs); |
| 2241 | const rhs_id = try self.resolve(bin_op.rhs); |
| 2234 | 2242 | |
| 2235 | 2243 | assert(self.typeOf(bin_op.lhs).eql(ty, self.module)); |
| 2236 | 2244 | assert(self.typeOf(bin_op.rhs).eql(ty, self.module)); |
| 2237 | 2245 | |
| 2246 | return try self.arithOp(ty, lhs_id, rhs_id, fop, sop, uop, modular); |
| 2247 | } |
| 2248 | |
| 2249 | fn arithOp( |
| 2250 | self: *DeclGen, |
| 2251 | ty: Type, |
| 2252 | lhs_id_: IdRef, |
| 2253 | rhs_id_: IdRef, |
| 2254 | comptime fop: Opcode, |
| 2255 | comptime sop: Opcode, |
| 2256 | comptime uop: Opcode, |
| 2257 | /// true if this operation holds under modular arithmetic. |
| 2258 | comptime modular: bool, |
| 2259 | ) !IdRef { |
| 2260 | var rhs_id = rhs_id_; |
| 2261 | var lhs_id = lhs_id_; |
| 2262 | |
| 2263 | const mod = self.module; |
| 2264 | const result_ty_ref = try self.resolveType(ty, .direct); |
| 2265 | |
| 2266 | if (ty.isVector(mod)) { |
| 2267 | const child_ty = ty.childType(mod); |
| 2268 | const vector_len = ty.vectorLen(mod); |
| 2269 | var constituents = try self.gpa.alloc(IdRef, vector_len); |
| 2270 | defer self.gpa.free(constituents); |
| 2271 | |
| 2272 | for (constituents, 0..) |*constituent, i| { |
| 2273 | const lhs_index_id = try self.extractField(child_ty, lhs_id, @intCast(i)); |
| 2274 | const rhs_index_id = try self.extractField(child_ty, rhs_id, @intCast(i)); |
| 2275 | constituent.* = try self.arithOp(child_ty, lhs_index_id, rhs_index_id, fop, sop, uop, modular); |
| 2276 | } |
| 2277 | |
| 2278 | return self.constructArray(result_ty_ref, constituents); |
| 2279 | } |
| 2280 | |
| 2238 | 2281 | // Binary operations are generally applicable to both scalar and vector operations |
| 2239 | 2282 | // in SPIR-V, but int and float versions of operations require different opcodes. |
| 2240 | 2283 | const info = try self.arithmeticTypeInfo(ty); |