| ... | @@ -1970,6 +1970,9 @@ const DeclGen = struct { | ... | @@ -1970,6 +1970,9 @@ const DeclGen = struct { |
| 1970 | | 1970 | |
| 1971 | .shl => try self.airShift(inst, .OpShiftLeftLogical), | 1971 | .shl => try self.airShift(inst, .OpShiftLeftLogical), |
| 1972 | | 1972 | |
| | 1973 | .min => try self.airMinMax(inst, .lt), |
| | 1974 | .max => try self.airMinMax(inst, .gt), |
| | 1975 | |
| 1973 | .bitcast => try self.airBitCast(inst), | 1976 | .bitcast => try self.airBitCast(inst), |
| 1974 | .intcast, .trunc => try self.airIntCast(inst), | 1977 | .intcast, .trunc => try self.airIntCast(inst), |
| 1975 | .int_from_ptr => try self.airIntFromPtr(inst), | 1978 | .int_from_ptr => try self.airIntFromPtr(inst), |
| ... | @@ -2103,6 +2106,54 @@ const DeclGen = struct { | ... | @@ -2103,6 +2106,54 @@ const DeclGen = struct { |
| 2103 | return result_id; | 2106 | return result_id; |
| 2104 | } | 2107 | } |
| 2105 | | 2108 | |
| | 2109 | fn airMinMax(self: *DeclGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !?IdRef { |
| | 2110 | if (self.liveness.isUnused(inst)) return null; |
| | 2111 | |
| | 2112 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| | 2113 | const lhs_id = try self.resolve(bin_op.lhs); |
| | 2114 | const rhs_id = try self.resolve(bin_op.rhs); |
| | 2115 | const result_ty = self.typeOfIndex(inst); |
| | 2116 | const result_ty_ref = try self.resolveType(result_ty, .direct); |
| | 2117 | |
| | 2118 | const info = try self.arithmeticTypeInfo(result_ty); |
| | 2119 | // TODO: Use fmin for OpenCL |
| | 2120 | const cmp_id = try self.cmp(op, result_ty, lhs_id, rhs_id); |
| | 2121 | const selection_id = switch (info.class) { |
| | 2122 | .float => blk: { |
| | 2123 | // cmp uses OpFOrd. When we have 0 [<>] nan this returns false, |
| | 2124 | // but we want it to pick lhs. Therefore we also have to check if |
| | 2125 | // rhs is nan. We don't need to care about the result when both |
| | 2126 | // are nan. |
| | 2127 | const rhs_is_nan_id = self.spv.allocId(); |
| | 2128 | const bool_ty_ref = try self.resolveType(Type.bool, .direct); |
| | 2129 | try self.func.body.emit(self.spv.gpa, .OpIsNan, .{ |
| | 2130 | .id_result_type = self.typeId(bool_ty_ref), |
| | 2131 | .id_result = rhs_is_nan_id, |
| | 2132 | .x = rhs_id, |
| | 2133 | }); |
| | 2134 | const float_cmp_id = self.spv.allocId(); |
| | 2135 | try self.func.body.emit(self.spv.gpa, .OpLogicalOr, .{ |
| | 2136 | .id_result_type = self.typeId(bool_ty_ref), |
| | 2137 | .id_result = float_cmp_id, |
| | 2138 | .operand_1 = cmp_id, |
| | 2139 | .operand_2 = rhs_is_nan_id, |
| | 2140 | }); |
| | 2141 | break :blk float_cmp_id; |
| | 2142 | }, |
| | 2143 | else => cmp_id, |
| | 2144 | }; |
| | 2145 | |
| | 2146 | const result_id = self.spv.allocId(); |
| | 2147 | try self.func.body.emit(self.spv.gpa, .OpSelect, .{ |
| | 2148 | .id_result_type = self.typeId(result_ty_ref), |
| | 2149 | .id_result = result_id, |
| | 2150 | .condition = selection_id, |
| | 2151 | .object_1 = lhs_id, |
| | 2152 | .object_2 = rhs_id, |
| | 2153 | }); |
| | 2154 | return result_id; |
| | 2155 | } |
| | 2156 | |
| 2106 | fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef { | 2157 | fn maskStrangeInt(self: *DeclGen, ty_ref: CacheRef, value_id: IdRef, bits: u16) !IdRef { |
| 2107 | const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1; | 2158 | const mask_value = if (bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(bits))) - 1; |
| 2108 | const result_id = self.spv.allocId(); | 2159 | const result_id = self.spv.allocId(); |