authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-01-21 20:12:25+01:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2024-02-04 19:09:31+01:00
log9641d2ebdb74926a56ff3b916082534052dc637f
treea562880abf840da19497106ecbdfa9095042a187
parent9f0227a326d84208e23e90c2a84ff95f734bd2ae
signaturebadge-check Signed by SSH key SHA256:ZS52FNyUv2WUXvO4njmVaFVO46RHojFuOrxRc4LuKzg

spirv: vectorize max, min


2 files changed, 50 insertions(+), 54 deletions(-)

src/codegen/spirv.zig+50-49
...@@ -2391,45 +2391,51 @@ const DeclGen = struct {...@@ -2391,45 +2391,51 @@ const DeclGen = struct {
2391 }2391 }
23922392
2393 fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef {2393 fn minMax(self: *DeclGen, result_ty: Type, op: std.math.CompareOperator, lhs_id: IdRef, rhs_id: IdRef) !IdRef {
2394 const result_ty_ref = try self.resolveType(result_ty, .direct);
2395 const info = self.arithmeticTypeInfo(result_ty);2394 const info = self.arithmeticTypeInfo(result_ty);
23962395
2397 // TODO: Use fmin for OpenCL2396 var wip = try self.elementWise(result_ty);
2398 const cmp_id = try self.cmp(op, Type.bool, result_ty, lhs_id, rhs_id);2397 defer wip.deinit();
2399 const selection_id = switch (info.class) {2398 for (wip.results, 0..) |*result_id, i| {
2400 .float => blk: {2399 const lhs_elem_id = try wip.elementAt(result_ty, lhs_id, i);
2401 // cmp uses OpFOrd. When we have 0 [<>] nan this returns false,2400 const rhs_elem_id = try wip.elementAt(result_ty, rhs_id, i);
2402 // but we want it to pick lhs. Therefore we also have to check if2401
2403 // rhs is nan. We don't need to care about the result when both2402 // TODO: Use fmin for OpenCL
2404 // are nan.2403 const cmp_id = try self.cmp(op, Type.bool, wip.scalar_ty, lhs_elem_id, rhs_elem_id);
2405 const rhs_is_nan_id = self.spv.allocId();2404 const selection_id = switch (info.class) {
2406 const bool_ty_ref = try self.resolveType(Type.bool, .direct);2405 .float => blk: {
2407 try self.func.body.emit(self.spv.gpa, .OpIsNan, .{2406 // cmp uses OpFOrd. When we have 0 [<>] nan this returns false,
2408 .id_result_type = self.typeId(bool_ty_ref),2407 // but we want it to pick lhs. Therefore we also have to check if
2409 .id_result = rhs_is_nan_id,2408 // rhs is nan. We don't need to care about the result when both
2410 .x = rhs_id,2409 // are nan.
2411 });2410 const rhs_is_nan_id = self.spv.allocId();
2412 const float_cmp_id = self.spv.allocId();2411 const bool_ty_ref = try self.resolveType(Type.bool, .direct);
2413 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{2412 try self.func.body.emit(self.spv.gpa, .OpIsNan, .{
2414 .id_result_type = self.typeId(bool_ty_ref),2413 .id_result_type = self.typeId(bool_ty_ref),
2415 .id_result = float_cmp_id,2414 .id_result = rhs_is_nan_id,
2416 .operand_1 = cmp_id,2415 .x = rhs_elem_id,
2417 .operand_2 = rhs_is_nan_id,2416 });
2418 });2417 const float_cmp_id = self.spv.allocId();
2419 break :blk float_cmp_id;2418 try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{
2420 },2419 .id_result_type = self.typeId(bool_ty_ref),
2421 else => cmp_id,2420 .id_result = float_cmp_id,
2422 };2421 .operand_1 = cmp_id,
2422 .operand_2 = rhs_is_nan_id,
2423 });
2424 break :blk float_cmp_id;
2425 },
2426 else => cmp_id,
2427 };
24232428
2424 const result_id = self.spv.allocId();2429 result_id.* = self.spv.allocId();
2425 try self.func.body.emit(self.spv.gpa, .OpSelect, .{2430 try self.func.body.emit(self.spv.gpa, .OpSelect, .{
2426 .id_result_type = self.typeId(result_ty_ref),2431 .id_result_type = wip.scalar_ty_id,
2427 .id_result = result_id,2432 .id_result = result_id.*,
2428 .condition = selection_id,2433 .condition = selection_id,
2429 .object_1 = lhs_id,2434 .object_1 = lhs_elem_id,
2430 .object_2 = rhs_id,2435 .object_2 = rhs_elem_id,
2431 });2436 });
2432 return result_id;2437 }
2438 return wip.finalize();
2433 }2439 }
24342440
2435 /// This function normalizes values to a canonical representation2441 /// This function normalizes values to a canonical representation
...@@ -3107,20 +3113,15 @@ const DeclGen = struct {...@@ -3107,20 +3113,15 @@ const DeclGen = struct {
3107 return result_id;3113 return result_id;
3108 },3114 },
3109 .Vector => {3115 .Vector => {
3110 const child_ty = ty.childType(mod);3116 var wip = try self.elementWise(result_ty);
3111 const vector_len = ty.vectorLen(mod);3117 defer wip.deinit();
31123118 const scalar_ty = ty.scalarType(mod);
3113 const constituents = try self.gpa.alloc(IdRef, vector_len);3119 for (wip.results, 0..) |*result_id, i| {
3114 defer self.gpa.free(constituents);3120 const lhs_elem_id = try wip.elementAt(ty, lhs_id, i);
31153121 const rhs_elem_id = try wip.elementAt(ty, rhs_id, i);
3116 for (constituents, 0..) |*constituent, i| {3122 result_id.* = try self.cmp(op, Type.bool, scalar_ty, lhs_elem_id, rhs_elem_id);
3117 const lhs_index_id = try self.extractField(child_ty, cmp_lhs_id, @intCast(i));
3118 const rhs_index_id = try self.extractField(child_ty, cmp_rhs_id, @intCast(i));
3119 const result_id = try self.cmp(op, Type.bool, child_ty, lhs_index_id, rhs_index_id);
3120 constituent.* = try self.convertToIndirect(Type.bool, result_id);
3121 }3123 }
31223124 return wip.finalize();
3123 return try self.constructArray(result_ty, constituents);
3124 },3125 },
3125 else => unreachable,3126 else => unreachable,
3126 };3127 };
test/behavior/maximum_minimum.zig-5
...@@ -31,7 +31,6 @@ test "@max on vectors" {...@@ -31,7 +31,6 @@ test "@max on vectors" {
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_x86_64 and34 if (builtin.zig_backend == .stage2_x86_64 and
36 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;35 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
3736
...@@ -86,7 +85,6 @@ test "@min for vectors" {...@@ -86,7 +85,6 @@ test "@min for vectors" {
86 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO85 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO86 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
89 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
90 if (builtin.zig_backend == .stage2_x86_64 and88 if (builtin.zig_backend == .stage2_x86_64 and
91 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;89 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest;
9290
...@@ -199,7 +197,6 @@ test "@min/@max notices vector bounds" {...@@ -199,7 +197,6 @@ test "@min/@max notices vector bounds" {
199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
200 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO198 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO199 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;200 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
204201
205 var x: @Vector(2, u16) = .{ 140, 40 };202 var x: @Vector(2, u16) = .{ 140, 40 };
...@@ -253,7 +250,6 @@ test "@min/@max notices bounds from vector types" {...@@ -253,7 +250,6 @@ test "@min/@max notices bounds from vector types" {
253 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO252 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
257 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;253 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
258254
259 var x: @Vector(2, u16) = .{ 30, 67 };255 var x: @Vector(2, u16) = .{ 30, 67 };
...@@ -295,7 +291,6 @@ test "@min/@max notices bounds from vector types when element of comptime-known...@@ -295,7 +291,6 @@ test "@min/@max notices bounds from vector types when element of comptime-known
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO291 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO292 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO293 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
299 if (builtin.zig_backend == .stage2_x86_64 and294 if (builtin.zig_backend == .stage2_x86_64 and
300 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx)) return error.SkipZigTest;295 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .avx)) return error.SkipZigTest;
301296