aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorRobin Voetter <robin@voetter.nl>2023-10-08 13:02:16 +0200
committerRobin Voetter <robin@voetter.nl>2023-10-15 14:00:07 +0200
commit4f279078c8bd57e7ee47eebce2572ab25729850a (patch)
tree01b17bf5eead8d87b22b1e9d5b33e61a2f5a7cf8 /src/codegen
parentf858bf161602d72584da9e950c5a9eeadfe8b29d (diff)
downloadzig-4f279078c8bd57e7ee47eebce2572ab25729850a.tar.gz
zig-4f279078c8bd57e7ee47eebce2572ab25729850a.zip
spirv: air min/max
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/spirv.zig51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index 62f945dd81..42a11120b5 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -1970,6 +1970,9 @@ const DeclGen = struct {
.shl => try self.airShift(inst, .OpShiftLeftLogical),
+ .min => try self.airMinMax(inst, .lt),
+ .max => try self.airMinMax(inst, .gt),
+
.bitcast => try self.airBitCast(inst),
.intcast, .trunc => try self.airIntCast(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
@@ -2103,6 +2106,54 @@ const DeclGen = struct {
return result_id;
}
+ fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef {
+ if (self.liveness.isUnused(inst)) return null;
+
+ const bin_op = self.air.instructions.items(.data)[inst].bin_op;
+ const lhs_id = try self.resolve(bin_op.lhs);
+ const rhs_id = try self.resolve(bin_op.rhs);
+ const result_ty = self.typeOfIndex(inst);
+ const result_ty_ref = try self.resolveType(result_ty, .direct);
+
+ const info = try self.arithmeticTypeInfo(result_ty);
+ // TODO: Use fmin for OpenCL
+ const cmp_id = try self.cmp(op, result_ty, lhs_id, rhs_id);
+ const selection_id = switch (info.class) {
+ .float => blk: {
+ // cmp uses OpFOrd. When we have 0 [<>] nan this returns false,
+ // but we want it to pick lhs. Therefore we also have to check if
+ // rhs is nan. We don't need to care about the result when both
+ // are nan.
+ const rhs_is_nan_id = self.spv.allocId();
+ const bool_ty_ref = try self.resolveType(Type.bool, .direct);
+ try self.func.body.emit(self.spv.gpa, .OpIsNan, .{
+ .id_result_type = self.typeId(bool_ty_ref),
+ .id_result = rhs_is_nan_id,
+ .x = rhs_id,
+ });
+ const float_cmp_id = self.spv.allocId();
+ try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{
+ .id_result_type = self.typeId(bool_ty_ref),
+ .id_result = float_cmp_id,
+ .operand_1 = cmp_id,
+ .operand_2 = rhs_is_nan_id,
+ });
+ break :blk float_cmp_id;
+ },
+ else => cmp_id,
+ };
+
+ const result_id = self.spv.allocId();
+ try self.func.body.emit(self.spv.gpa, .OpSelect, .{
+ .id_result_type = self.typeId(result_ty_ref),
+ .id_result = result_id,
+ .condition = selection_id,
+ .object_1 = lhs_id,
+ .object_2 = rhs_id,
+ });
+ return result_id;
+ }
+
fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef {
const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1;
const result_id = self.spv.allocId();