| ... | @@ -2189,12 +2189,25 @@ pub const Value = extern union { | ... | @@ -2189,12 +2189,25 @@ pub const Value = extern union { |
| 2189 | return ty.isTupleOrAnonStruct() and ty.structFieldCount() != 0; | 2189 | return ty.isTupleOrAnonStruct() and ty.structFieldCount() != 0; |
| 2190 | }, | 2190 | }, |
| 2191 | .Float => { | 2191 | .Float => { |
| 2192 | const a_nan = a.isNan(); | 2192 | switch (ty.floatBits(target)) { |
| 2193 | const b_nan = b.isNan(); | 2193 | 16 => return @bitCast(u16, a.toFloat(f16)) == @bitCast(u16, b.toFloat(f16)), |
| 2194 | if (a_nan or b_nan) { | 2194 | 32 => return @bitCast(u32, a.toFloat(f32)) == @bitCast(u32, b.toFloat(f32)), |
| 2195 | return a_nan and b_nan; | 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 | .Optional => { | 2212 | .Optional => { |
| 2200 | if (a.tag() != .opt_payload and b.tag() == .opt_payload) { | 2213 | if (a.tag() != .opt_payload and b.tag() == .opt_payload) { |
| ... | @@ -2231,18 +2244,25 @@ pub const Value = extern union { | ... | @@ -2231,18 +2244,25 @@ pub const Value = extern union { |
| 2231 | var buf: ToTypeBuffer = undefined; | 2244 | var buf: ToTypeBuffer = undefined; |
| 2232 | return val.toType(&buf).hashWithHasher(hasher, mod); | 2245 | return val.toType(&buf).hashWithHasher(hasher, mod); |
| 2233 | }, | 2246 | }, |
| 2234 | .Float, .ComptimeFloat => { | 2247 | .Float => { |
| 2235 | // Normalize the float here because this hash must match eql semantics. | 2248 | // For hash/eql purposes, we treat floats as their IEEE integer representation. |
| 2236 | // These functions are used for hash maps so we want NaN to equal itself, | 2249 | switch (ty.floatBits(mod.getTarget())) { |
| 2237 | // and -0.0 to equal +0.0. | 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 | const float = val.toFloat(f128); | 2259 | const float = val.toFloat(f128); |
| 2239 | if (std.math.isNan(float)) { | 2260 | const is_nan = std.math.isNan(float); |
| 2240 | std.hash.autoHash(hasher, std.math.nan_u128); | 2261 | std.hash.autoHash(hasher, is_nan); |
| 2241 | } else if (float == 0.0) { | 2262 | if (!is_nan) { |
| 2242 | var normalized_zero: f128 = 0.0; | | |
| 2243 | std.hash.autoHash(hasher, @bitCast(u128, normalized_zero)); | | |
| 2244 | } else { | | |
| 2245 | std.hash.autoHash(hasher, @bitCast(u128, float)); | 2263 | std.hash.autoHash(hasher, @bitCast(u128, float)); |
| | 2264 | } else { |
| | 2265 | std.hash.autoHash(hasher, std.math.signbit(float)); |
| 2246 | } | 2266 | } |
| 2247 | }, | 2267 | }, |
| 2248 | .Bool, .Int, .ComptimeInt, .Pointer => switch (val.tag()) { | 2268 | .Bool, .Int, .ComptimeInt, .Pointer => switch (val.tag()) { |