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 {...@@ -1782,6 +1782,19 @@ const DeclGen = struct {
1782 wip.dg.gpa.free(wip.results);1782 wip.dg.gpa.free(wip.results);
1783 }1783 }
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
1785 /// Utility function to extract the element at a particular index in an1798 /// Utility function to extract the element at a particular index in an
1786 /// input vector. This type is expected to be a vector if `wip.is_vector`, and1799 /// input vector. This type is expected to be a vector if `wip.is_vector`, and
1787 /// a scalar otherwise.1800 /// a scalar otherwise.
...@@ -1789,7 +1802,7 @@ const DeclGen = struct {...@@ -1789,7 +1802,7 @@ const DeclGen = struct {
1789 const mod = wip.dg.module;1802 const mod = wip.dg.module;
1790 if (wip.is_vector) {1803 if (wip.is_vector) {
1791 assert(ty.isVector(mod));1804 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));
1793 } else {1806 } else {
1794 assert(!ty.isVector(mod));1807 assert(!ty.isVector(mod));
1795 assert(index == 0);1808 assert(index == 0);
...@@ -2331,36 +2344,45 @@ const DeclGen = struct {...@@ -2331,36 +2344,45 @@ const DeclGen = struct {
2331 const lhs_id = try self.resolve(bin_op.lhs);2344 const lhs_id = try self.resolve(bin_op.lhs);
2332 const rhs_id = try self.resolve(bin_op.rhs);2345 const rhs_id = try self.resolve(bin_op.rhs);
2333 const result_ty = self.typeOfIndex(inst);2346 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
2338 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,2348 // Sometimes Zig doesn't make both of the arguments the same types here. SPIR-V expects that,
2339 // so just manually upcast it if required.2349 // so just manually upcast it if required.
2340 const shift_ty_ref = try self.resolveType(self.typeOf(bin_op.rhs), .direct);2350 // TODO(robin)
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;
23502351
2351 const args = .{2352 var wip = try self.elementWise(result_ty);
2352 .id_result_type = self.typeId(result_ty_ref),2353 defer wip.deinit();
2353 .id_result = result_id,
2354 .base = lhs_id,
2355 .shift = shift_id,
2356 };
23572354
2358 if (result_ty.isSignedInt(mod)) {2355 const shift_ty = wip.scalarType(self.typeOf(bin_op.rhs));
2359 try self.func.body.emit(self.spv.gpa, signed, args);2356 const shift_ty_ref = try self.resolveType(shift_ty, .direct);
2360 } else {2357
2361 try self.func.body.emit(self.spv.gpa, unsigned, args);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 }
2362 }2384 }
2363 return result_id;2385 return try wip.finalize();
2364 }2386 }
23652387
2366 fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {2388 fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {
...@@ -2483,35 +2505,14 @@ const DeclGen = struct {...@@ -2483,35 +2505,14 @@ const DeclGen = struct {
2483 fn arithOp(2505 fn arithOp(
2484 self: *DeclGen,2506 self: *DeclGen,
2485 ty: Type,2507 ty: Type,
2486 lhs_id_: IdRef,2508 lhs_id: IdRef,
2487 rhs_id_: IdRef,2509 rhs_id: IdRef,
2488 comptime fop: Opcode,2510 comptime fop: Opcode,
2489 comptime sop: Opcode,2511 comptime sop: Opcode,
2490 comptime uop: Opcode,2512 comptime uop: Opcode,
2491 /// true if this operation holds under modular arithmetic.2513 /// true if this operation holds under modular arithmetic.
2492 comptime modular: bool,2514 comptime modular: bool,
2493 ) !IdRef {2515 ) !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
2515 // Binary operations are generally applicable to both scalar and vector operations2516 // Binary operations are generally applicable to both scalar and vector operations
2516 // in SPIR-V, but int and float versions of operations require different opcodes.2517 // in SPIR-V, but int and float versions of operations require different opcodes.
2517 const info = try self.arithmeticTypeInfo(ty);2518 const info = try self.arithmeticTypeInfo(ty);
...@@ -2520,17 +2521,7 @@ const DeclGen = struct {...@@ -2520,17 +2521,7 @@ const DeclGen = struct {
2520 .composite_integer => {2521 .composite_integer => {
2521 return self.todo("binary operations for composite integers", .{});2522 return self.todo("binary operations for composite integers", .{});
2522 },2523 },
2523 .strange_integer => blk: {2524 .integer, .strange_integer => switch (info.signedness) {
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) {
2534 .signed => @as(usize, 1),2525 .signed => @as(usize, 1),
2535 .unsigned => @as(usize, 2),2526 .unsigned => @as(usize, 2),
2536 },2527 },
...@@ -2538,24 +2529,41 @@ const DeclGen = struct {...@@ -2538,24 +2529,41 @@ const DeclGen = struct {
2538 .bool => unreachable,2529 .bool => unreachable,
2539 };2530 };
25402531
2541 const result_id = self.spv.allocId();2532 var wip = try self.elementWise(ty);
2542 const operands = .{2533 defer wip.deinit();
2543 .id_result_type = self.typeId(result_ty_ref),2534 for (0..wip.results.len) |i| {
2544 .id_result = result_id,2535 const lhs_elem_id = try wip.elementAt(ty, lhs_id, i);
2545 .operand_1 = lhs_id,2536 const rhs_elem_id = try wip.elementAt(ty, rhs_id, i);
2546 .operand_2 = rhs_id,
2547 };
25482537
2549 switch (opcode_index) {2538 const lhs_norm_id = if (modular and info.class == .strange_integer)
2550 0 => try self.func.body.emit(self.spv.gpa, fop, operands),2539 try self.normalizeInt(wip.scalar_ty_ref, lhs_elem_id, info)
2551 1 => try self.func.body.emit(self.spv.gpa, sop, operands),2540 else
2552 2 => try self.func.body.emit(self.spv.gpa, uop, operands),2541 lhs_elem_id;
2553 else => unreachable,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.
2554 }2564 }
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();
2559 }2567 }
25602568
2561 fn airAddSubOverflow(2569 fn airAddSubOverflow(