| ... | ... | @@ -2189,12 +2189,25 @@ pub const Value = extern union { |
| 2189 | 2189 | return ty.isTupleOrAnonStruct() and ty.structFieldCount() != 0; |
| 2190 | 2190 | }, |
| 2191 | 2191 | .Float => { |
| 2192 | | const a_nan = a.isNan(); |
| 2193 | | const b_nan = b.isNan(); |
| 2194 | | if (a_nan or b_nan) { |
| 2195 | | return a_nan and b_nan; |
| 2192 | switch (ty.floatBits(target)) { |
| 2193 | 16 => return @bitCast(u16, a.toFloat(f16)) == @bitCast(u16, b.toFloat(f16)), |
| 2194 | 32 => return @bitCast(u32, a.toFloat(f32)) == @bitCast(u32, b.toFloat(f32)), |
| 2195 | 64 => return @bitCast(u64, a.toFloat(f64)) == @bitCast(u64, b.toFloat(f64)), |
| 2196 | 80 => return @bitCast(u80, a.toFloat(f80)) == @bitCast(u80, b.toFloat(f80)), |
| 2197 | 128 => return @bitCast(u128, a.toFloat(f128)) == @bitCast(u128, b.toFloat(f128)), |
| 2198 | else => unreachable, |
| 2196 | 2199 | } |
| 2197 | | return order(a, b, target).compare(.eq); |
| 2200 | }, |
| 2201 | .ComptimeFloat => { |
| 2202 | const a_float = a.toFloat(f128); |
| 2203 | const b_float = b.toFloat(f128); |
| 2204 | |
| 2205 | const a_nan = std.math.isNan(a_float); |
| 2206 | const b_nan = std.math.isNan(b_float); |
| 2207 | if (a_nan != b_nan) return false; |
| 2208 | if (std.math.signbit(a_float) != std.math.signbit(b_float)) return false; |
| 2209 | if (a_nan) return true; |
| 2210 | return a_float == b_float; |
| 2198 | 2211 | }, |
| 2199 | 2212 | .Optional => { |
| 2200 | 2213 | if (a.tag() != .opt_payload and b.tag() == .opt_payload) { |
| ... | ... | @@ -2231,18 +2244,25 @@ pub const Value = extern union { |
| 2231 | 2244 | var buf: ToTypeBuffer = undefined; |
| 2232 | 2245 | return val.toType(&buf).hashWithHasher(hasher, mod); |
| 2233 | 2246 | }, |
| 2234 | | .Float, .ComptimeFloat => { |
| 2235 | | // Normalize the float here because this hash must match eql semantics. |
| 2236 | | // These functions are used for hash maps so we want NaN to equal itself, |
| 2237 | | // and -0.0 to equal +0.0. |
| 2247 | .Float => { |
| 2248 | // For hash/eql purposes, we treat floats as their IEEE integer representation. |
| 2249 | switch (ty.floatBits(mod.getTarget())) { |
| 2250 | 16 => std.hash.autoHash(hasher, @bitCast(u16, val.toFloat(f16))), |
| 2251 | 32 => std.hash.autoHash(hasher, @bitCast(u32, val.toFloat(f32))), |
| 2252 | 64 => std.hash.autoHash(hasher, @bitCast(u64, val.toFloat(f64))), |
| 2253 | 80 => std.hash.autoHash(hasher, @bitCast(u80, val.toFloat(f80))), |
| 2254 | 128 => std.hash.autoHash(hasher, @bitCast(u128, val.toFloat(f128))), |
| 2255 | else => unreachable, |
| 2256 | } |
| 2257 | }, |
| 2258 | .ComptimeFloat => { |
| 2238 | 2259 | const float = val.toFloat(f128); |
| 2239 | | if (std.math.isNan(float)) { |
| 2240 | | std.hash.autoHash(hasher, std.math.nan_u128); |
| 2241 | | } else if (float == 0.0) { |
| 2242 | | var normalized_zero: f128 = 0.0; |
| 2243 | | std.hash.autoHash(hasher, @bitCast(u128, normalized_zero)); |
| 2244 | | } else { |
| 2260 | const is_nan = std.math.isNan(float); |
| 2261 | std.hash.autoHash(hasher, is_nan); |
| 2262 | if (!is_nan) { |
| 2245 | 2263 | std.hash.autoHash(hasher, @bitCast(u128, float)); |
| 2264 | } else { |
| 2265 | std.hash.autoHash(hasher, std.math.signbit(float)); |
| 2246 | 2266 | } |
| 2247 | 2267 | }, |
| 2248 | 2268 | .Bool, .Int, .ComptimeInt, .Pointer => switch (val.tag()) { |