authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-01-15 23:38:43+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-02-04 19:09:18+01:00
log403c6262bb4c9087f1d0138fc83fe4dd979864ad
tree339f7d3d1c6c318a789129472299bda7653737e5
parentcb9e20da00a2c33706e2c7bf2008887c6c72a896
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

spirv: use new vector stuff for arithOp and shift


1 files changed, 82 insertions(+), 74 deletions(-)

src/codegen/spirv.zig+82-74
......@@ -1782,6 +1782,19 @@ const DeclGen = struct {
17821782 wip.dg.gpa.free(wip.results);
17831783 }
17841784
1785 /// Return the scalar type of an input vector. This type is expected to be a vector
1786 /// if `wip.is_vector`, and a scalar otherwise.
1787 fn scalarType(wip: WipElementWise, ty: Type) Type {
1788 const mod = wip.dg.module;
1789 if (wip.is_vector) {
1790 assert(ty.isVector(mod));
1791 return ty.childType(mod);
1792 } else {
1793 assert(!ty.isVector(mod));
1794 return ty;
1795 }
1796 }
1797
17851798 /// Utility function to extract the element at a particular index in an
17861799 /// input vector. This type is expected to be a vector if `wip.is_vector`, and
17871800 /// a scalar otherwise.
......@@ -1789,7 +1802,7 @@ const DeclGen = struct {
17891802 const mod = wip.dg.module;
17901803 if (wip.is_vector) {
17911804 assert(ty.isVector(mod));
1792 return try wip.dg.extractField(ty, value, @intCast(index));
1805 return try wip.dg.extractField(ty.childType(mod), value, @intCast(index));
17931806 } else {
17941807 assert(!ty.isVector(mod));
17951808 assert(index == 0);
......@@ -2331,36 +2344,45 @@ const DeclGen = struct {
23312344 const lhs_id = try self.resolve(bin_op.lhs);
23322345 const rhs_id = try self.resolve(bin_op.rhs);
23332346 const result_ty = self.typeOfIndex(inst);
2334 const result_ty_ref = try self.resolveType(result_ty, .direct);
2335
2336 const result_id = self.spv.allocId();
23372347
23382348 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
23392349 // so just manually upcast it if required.
2340 const shift_ty_ref = try self.resolveType(self.typeOf(bin_op.rhs), .direct);
2341 const shift_id = if (shift_ty_ref != result_ty_ref) blk: {
2342 const shift_id = self.spv.allocId();
2343 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
2344 .id_result_type = self.typeId(result_ty_ref),
2345 .id_result = shift_id,
2346 .unsigned_value = rhs_id,
2347 });
2348 break :blk shift_id;
2349 } else rhs_id;
2350 // TODO(robin)
23502351
2351 const args = .{
2352 .id_result_type = self.typeId(result_ty_ref),
2353 .id_result = result_id,
2354 .base = lhs_id,
2355 .shift = shift_id,
2356 };
2352 var wip = try self.elementWise(result_ty);
2353 defer wip.deinit();
23572354
2358 if (result_ty.isSignedInt(mod)) {
2359 try self.func.body.emit(self.spv.gpa, signed, args);
2360 } else {
2361 try self.func.body.emit(self.spv.gpa, unsigned, args);
2355 const shift_ty = wip.scalarType(self.typeOf(bin_op.rhs));
2356 const shift_ty_ref = try self.resolveType(shift_ty, .direct);
2357
2358 for (0..wip.results.len) |i| {
2359 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);
2360 const rhs_elem_id = try wip.elementAt(result_ty, rhs_id, i);
2361
2362 const shift_id = if (shift_ty_ref != wip.result_ty_ref) blk: {
2363 const shift_id = self.spv.allocId();
2364 try self.func.body.emit(self.spv.gpa, .OpUConvert, .{
2365 .id_result_type = wip.scalar_ty_id,
2366 .id_result = shift_id,
2367 .unsigned_value = rhs_elem_id,
2368 });
2369 break :blk shift_id;
2370 } else rhs_elem_id;
2371
2372 const args = .{
2373 .id_result_type = wip.scalar_ty_id,
2374 .id_result = wip.allocId(i),
2375 .base = lhs_elem_id,
2376 .shift = shift_id,
2377 };
2378
2379 if (result_ty.isSignedInt(mod)) {
2380 try self.func.body.emit(self.spv.gpa, signed, args);
2381 } else {
2382 try self.func.body.emit(self.spv.gpa, unsigned, args);
2383 }
23622384 }
2363 return result_id;
2385 return try wip.finalize();
23642386 }
23652387
23662388 fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {
......@@ -2483,35 +2505,14 @@ const DeclGen = struct {
24832505 fn arithOp(
24842506 self: *DeclGen,
24852507 ty: Type,
2486 lhs_id_: IdRef,
2487 rhs_id_: IdRef,
2508 lhs_id: IdRef,
2509 rhs_id: IdRef,
24882510 comptime fop: Opcode,
24892511 comptime sop: Opcode,
24902512 comptime uop: Opcode,
24912513 /// true if this operation holds under modular arithmetic.
24922514 comptime modular: bool,
24932515 ) !IdRef {
2494 var rhs_id = rhs_id_;
2495 var lhs_id = lhs_id_;
2496
2497 const mod = self.module;
2498 const result_ty_ref = try self.resolveType(ty, .direct);
2499
2500 if (ty.isVector(mod)) {
2501 const child_ty = ty.childType(mod);
2502 const vector_len = ty.vectorLen(mod);
2503 const constituents = try self.gpa.alloc(IdRef, vector_len);
2504 defer self.gpa.free(constituents);
2505
2506 for (constituents, 0..) |*constituent, i| {
2507 const lhs_index_id = try self.extractField(child_ty, lhs_id, @intCast(i));
2508 const rhs_index_id = try self.extractField(child_ty, rhs_id, @intCast(i));
2509 constituent.* = try self.arithOp(child_ty, lhs_index_id, rhs_index_id, fop, sop, uop, modular);
2510 }
2511
2512 return self.constructArray(ty, constituents);
2513 }
2514
25152516 // Binary operations are generally applicable to both scalar and vector operations
25162517 // in SPIR-V, but int and float versions of operations require different opcodes.
25172518 const info = try self.arithmeticTypeInfo(ty);
......@@ -2520,17 +2521,7 @@ const DeclGen = struct {
25202521 .composite_integer => {
25212522 return self.todo("binary operations for composite integers", .{});
25222523 },
2523 .strange_integer => blk: {
2524 if (!modular) {
2525 lhs_id = try self.normalizeInt(result_ty_ref, lhs_id, info);
2526 rhs_id = try self.normalizeInt(result_ty_ref, rhs_id, info);
2527 }
2528 break :blk switch (info.signedness) {
2529 .signed => @as(usize, 1),
2530 .unsigned => @as(usize, 2),
2531 };
2532 },
2533 .integer => switch (info.signedness) {
2524 .integer, .strange_integer => switch (info.signedness) {
25342525 .signed => @as(usize, 1),
25352526 .unsigned => @as(usize, 2),
25362527 },
......@@ -2538,24 +2529,41 @@ const DeclGen = struct {
25382529 .bool => unreachable,
25392530 };
25402531
2541 const result_id = self.spv.allocId();
2542 const operands = .{
2543 .id_result_type = self.typeId(result_ty_ref),
2544 .id_result = result_id,
2545 .operand_1 = lhs_id,
2546 .operand_2 = rhs_id,
2547 };
2532 var wip = try self.elementWise(ty);
2533 defer wip.deinit();
2534 for (0..wip.results.len) |i| {
2535 const lhs_elem_id = try wip.elementAt(ty, lhs_id, i);
2536 const rhs_elem_id = try wip.elementAt(ty, rhs_id, i);
25482537
2549 switch (opcode_index) {
2550 0 => try self.func.body.emit(self.spv.gpa, fop, operands),
2551 1 => try self.func.body.emit(self.spv.gpa, sop, operands),
2552 2 => try self.func.body.emit(self.spv.gpa, uop, operands),
2553 else => unreachable,
2538 const lhs_norm_id = if (modular and info.class == .strange_integer)
2539 try self.normalizeInt(wip.scalar_ty_ref, lhs_elem_id, info)
2540 else
2541 lhs_elem_id;
2542
2543 const rhs_norm_id = if (modular and info.class == .strange_integer)
2544 try self.normalizeInt(wip.scalar_ty_ref, rhs_elem_id, info)
2545 else
2546 rhs_elem_id;
2547
2548 const operands = .{
2549 .id_result_type = wip.scalar_ty_id,
2550 .id_result = wip.allocId(i),
2551 .operand_1 = lhs_norm_id,
2552 .operand_2 = rhs_norm_id,
2553 };
2554
2555 switch (opcode_index) {
2556 0 => try self.func.body.emit(self.spv.gpa, fop, operands),
2557 1 => try self.func.body.emit(self.spv.gpa, sop, operands),
2558 2 => try self.func.body.emit(self.spv.gpa, uop, operands),
2559 else => unreachable,
2560 }
2561
2562 // TODO: Trap on overflow? Probably going to be annoying.
2563 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.
25542564 }
2555 // TODO: Trap on overflow? Probably going to be annoying.
2556 // TODO: Look into SPV_KHR_no_integer_wrap_decoration which provides NoSignedWrap/NoUnsignedWrap.
25572565
2558 return result_id;
2566 return try wip.finalize();
25592567 }
25602568
25612569 fn airAddSubOverflow(