| author | |
| committer | |
| log | 6ed049fe3642c775e53b3bef2f9bfb6a1de0f325 |
| tree | f7576810e64dea9e247275b80c335741a4a75749 |
| parent | 6445196fabd9c9c3e40c24d298dc9ac2a19bee35 |
- Fix zig_clz_u128 not respecting the bits argument. This was crashing the compile-rt addxf3 tests with the cbe
- Instead of redering a negation for negative 128 bit int literals, render the literal as twos complement. This allows
rendering int representations of floats correctly (specifically f80).4 files changed, 73 insertions(+), 92 deletions(-)
lib/std/math/big/int.zig+34| ... | @@ -1677,6 +1677,40 @@ pub const Mutable = struct { | ... | @@ -1677,6 +1677,40 @@ pub const Mutable = struct { |
| 1677 | y.shiftRight(y.toConst(), norm_shift); | 1677 | y.shiftRight(y.toConst(), norm_shift); |
| 1678 | } | 1678 | } |
| 1679 | 1679 | ||
| 1680 | /// If a is positive, this passes through to truncate. | ||
| 1681 | /// If a is negative, then r is set to positive with the bit pattern ~(a - 1). | ||
| 1682 | /// | ||
| 1683 | /// Asserts `r` has enough storage to store the result. | ||
| 1684 | /// The upper bound is `calcTwosCompLimbCount(a.len)`. | ||
| 1685 | pub fn convertToTwosComplement(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void { | ||
| 1686 | if (a.positive) { | ||
| 1687 | r.truncate(a, signedness, bit_count); | ||
| 1688 | return; | ||
| 1689 | } | ||
| 1690 | |||
| 1691 | const req_limbs = calcTwosCompLimbCount(bit_count); | ||
| 1692 | if (req_limbs == 0 or a.eqZero()) { | ||
| 1693 | r.set(0); | ||
| 1694 | return; | ||
| 1695 | } | ||
| 1696 | |||
| 1697 | const bit = @truncate(Log2Limb, bit_count - 1); | ||
| 1698 | const signmask = @as(Limb, 1) << bit; | ||
| 1699 | const mask = (signmask << 1) -% 1; | ||
| 1700 | |||
| 1701 | r.addScalar(a.abs(), -1); | ||
| 1702 | if (req_limbs > r.len) { | ||
| 1703 | mem.set(Limb, r.limbs[r.len..req_limbs], 0); | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | assert(r.limbs.len >= req_limbs); | ||
| 1707 | r.len = req_limbs; | ||
| 1708 | |||
| 1709 | llnot(r.limbs[0..r.len]); | ||
| 1710 | r.limbs[r.len - 1] &= mask; | ||
| 1711 | r.normalize(r.len); | ||
| 1712 | } | ||
| 1713 | |||
| 1680 | /// Truncate an integer to a number of bits, following 2s-complement semantics. | 1714 | /// Truncate an integer to a number of bits, following 2s-complement semantics. |
| 1681 | /// r may alias a. | 1715 | /// r may alias a. |
| 1682 | /// | 1716 | /// |
lib/zig.h+6-83| ... | @@ -1339,7 +1339,7 @@ static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { | ... | @@ -1339,7 +1339,7 @@ static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { |
| 1339 | 1339 | ||
| 1340 | static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { | 1340 | static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { |
| 1341 | if (rhs == zig_as_u8(0)) return lhs; | 1341 | if (rhs == zig_as_u8(0)) return lhs; |
| 1342 | if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; // TODO: Fix? | 1342 | if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.lo << rhs, .lo = zig_minInt_u64 }; |
| 1343 | return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; | 1343 | return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1344 | } | 1344 | } |
| 1345 | 1345 | ||
| ... | @@ -1681,8 +1681,9 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { | ... | @@ -1681,8 +1681,9 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1681 | } | 1681 | } |
| 1682 | 1682 | ||
| 1683 | static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) { | 1683 | static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) { |
| 1684 | if (bits <= zig_as_u8(64)) return zig_clz_u64(zig_lo_u128(val), bits); | ||
| 1684 | if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64)); | 1685 | if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64)); |
| 1685 | return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + zig_as_u8(64); | 1686 | return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + (bits - zig_as_u8(64)); |
| 1686 | } | 1687 | } |
| 1687 | 1688 | ||
| 1688 | static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) { | 1689 | static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) { |
| ... | @@ -1942,14 +1943,15 @@ typedef zig_i128 zig_f128; | ... | @@ -1942,14 +1943,15 @@ typedef zig_i128 zig_f128; |
| 1942 | #define zig_has_c_longdouble 1 | 1943 | #define zig_has_c_longdouble 1 |
| 1943 | #define zig_libc_name_c_longdouble(name) name##l | 1944 | #define zig_libc_name_c_longdouble(name) name##l |
| 1944 | #define zig_as_special_constant_c_longdouble(sign, name, arg, repr) zig_as_special_c_longdouble(sign, name, arg, repr) | 1945 | #define zig_as_special_constant_c_longdouble(sign, name, arg, repr) zig_as_special_c_longdouble(sign, name, arg, repr) |
| 1945 | #if !_MSC_VER // TODO: Is there a better way to detect long double == double on msvc? | 1946 | #ifdef zig_bitSizeOf_c_longdouble |
| 1946 | typedef long double zig_c_longdouble; | 1947 | typedef long double zig_c_longdouble; |
| 1947 | #define zig_as_c_longdouble(fp, repr) fp##l | 1948 | #define zig_as_c_longdouble(fp, repr) fp##l |
| 1948 | #else | 1949 | #else |
| 1949 | #undef zig_has_c_longdouble | 1950 | #undef zig_has_c_longdouble |
| 1951 | #define zig_bitSizeOf_c_longdouble 80 | ||
| 1952 | #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80 | ||
| 1950 | #define zig_has_c_longdouble 0 | 1953 | #define zig_has_c_longdouble 0 |
| 1951 | #define zig_repr_c_longdouble i128 | 1954 | #define zig_repr_c_longdouble i128 |
| 1952 | #define zig_bitSizeOf_c_longdouble 128 | ||
| 1953 | typedef zig_i128 zig_c_longdouble; | 1955 | typedef zig_i128 zig_c_longdouble; |
| 1954 | #define zig_as_c_longdouble(fp, repr) repr | 1956 | #define zig_as_c_longdouble(fp, repr) repr |
| 1955 | #undef zig_as_special_c_longdouble | 1957 | #undef zig_as_special_c_longdouble |
| ... | @@ -1972,85 +1974,6 @@ zig_float_from_repr(f128, u128) | ... | @@ -1972,85 +1974,6 @@ zig_float_from_repr(f128, u128) |
| 1972 | zig_float_from_repr(c_longdouble, u128) | 1974 | zig_float_from_repr(c_longdouble, u128) |
| 1973 | #endif | 1975 | #endif |
| 1974 | 1976 | ||
| 1975 | /* #define zig_float_from_repr(Type) *((zig_##Type*)&repr) */ | ||
| 1976 | |||
| 1977 | /* #define zig_float_inf_builtin_0(Type, ReprType) \ */ | ||
| 1978 | /* static inline zig_##Type zig_as_special_inf_##Type(zig_##ReprType repr) { \ */ | ||
| 1979 | /* return zig_float_from_repr(Type); \ */ | ||
| 1980 | /* } */ | ||
| 1981 | /* #define zig_float_inf_builtin_1(Type, ReprType) \ */ | ||
| 1982 | /* static inline zig_##Type zig_as_special_inf_##Type(zig_##ReprType repr) { \ */ | ||
| 1983 | /* return __builtin_inf(); \ */ | ||
| 1984 | /* } */ | ||
| 1985 | /* #define zig_float_nan_builtin_0(Type, ReprType) \ */ | ||
| 1986 | /* static inline zig_##Type zig_as_special_nan_##Type(const char* arg, zig_##ReprType repr) { \ */ | ||
| 1987 | /* return zig_float_from_repr(Type); \ */ | ||
| 1988 | /* } */ | ||
| 1989 | /* #define zig_float_nan_builtin_1(Type, ReprType) \ */ | ||
| 1990 | /* static inline zig_##Type zig_as_special_nan_##Type(const char* arg, zig_##ReprType repr) { \ */ | ||
| 1991 | /* return __builtin_nan(arg); \ */ | ||
| 1992 | /* } */ | ||
| 1993 | /* #define zig_float_nans_builtin_0(Type, ReprType) \ */ | ||
| 1994 | /* static inline zig_##Type zig_as_special_nans_##Type(const char* arg, zig_##ReprType repr) { \ */ | ||
| 1995 | /* return zig_float_from_repr(Type); \ */ | ||
| 1996 | /* } */ | ||
| 1997 | /* #define zig_float_nans_builtin_1(Type, ReprType) \ */ | ||
| 1998 | /* static inline zig_##Type zig_as_special_nans_##Type(const char* arg, zig_##ReprType repr) { \ */ | ||
| 1999 | /* return __builtin_nans(arg); \ */ | ||
| 2000 | /* } */ | ||
| 2001 | |||
| 2002 | /* #define zig_float_special_builtins(Type, ReprType) \ */ | ||
| 2003 | /* zig_expand_concat(zig_float_inf_builtin_, zig_has_builtin(inf))(Type, ReprType) \ */ | ||
| 2004 | /* zig_expand_concat(zig_float_nan_builtin_, zig_has_builtin(nan))(Type, ReprType) \ */ | ||
| 2005 | /* zig_expand_concat(zig_float_nans_builtin_, zig_has_builtin(nans))(Type, ReprType) */ | ||
| 2006 | |||
| 2007 | /* #if zig_has_builtin(nan) */ | ||
| 2008 | /* #define zig_as_special_nan(arg, repr) __builtin_nan(arg); */ | ||
| 2009 | /* #define zig_as_special_nan_f16(arg, repr) __builtin_nan(arg); */ | ||
| 2010 | /* #define zig_as_special_nan_f32(arg, repr) __builtin_nan(arg); */ | ||
| 2011 | /* #define zig_as_special_nan_f64(arg, repr) __builtin_nan(arg); */ | ||
| 2012 | /* #define zig_as_special_nan_f80(arg, repr) __builtin_nan(arg); */ | ||
| 2013 | /* #define zig_as_special_nan_f128(arg, repr) __builtin_nan(arg); */ | ||
| 2014 | /* #else */ | ||
| 2015 | /* zig_float_special_builtins(); */ | ||
| 2016 | /* #endif */ | ||
| 2017 | |||
| 2018 | /* #if zig_has_f16 */ | ||
| 2019 | /* zig_float_special_builtins(f16, u16) */ | ||
| 2020 | /* #endif */ | ||
| 2021 | |||
| 2022 | /* #if zig_has_f32 */ | ||
| 2023 | /* zig_float_special_builtins(f32, u32) */ | ||
| 2024 | /* #endif */ | ||
| 2025 | |||
| 2026 | /* #if zig_has_f64 */ | ||
| 2027 | /* zig_float_special_builtins(f64, u64) */ | ||
| 2028 | /* #endif */ | ||
| 2029 | |||
| 2030 | /* #if zig_has_f80 */ | ||
| 2031 | /* zig_float_special_builtins(f80, u128) */ | ||
| 2032 | /* #endif */ | ||
| 2033 | |||
| 2034 | /* #if zig_has_f128 */ | ||
| 2035 | /* zig_float_special_builtins(f128, u128) */ | ||
| 2036 | /* #endif */ | ||
| 2037 | |||
| 2038 | /* #if zig_has_c_longdouble */ | ||
| 2039 | /* zig_float_special_builtins(c_longdouble, u128) */ | ||
| 2040 | /* #endif */ | ||
| 2041 | |||
| 2042 | #if zig_bitSizeOf_c_longdouble == 16 | ||
| 2043 | #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f16 | ||
| 2044 | #elif zig_bitSizeOf_c_longdouble == 32 | ||
| 2045 | #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f32 | ||
| 2046 | #elif zig_bitSizeOf_c_longdouble == 64 | ||
| 2047 | #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f64 | ||
| 2048 | #elif zig_bitSizeOf_c_longdouble == 80 | ||
| 2049 | #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80 | ||
| 2050 | #elif zig_bitSizeOf_c_longdouble == 128 | ||
| 2051 | #define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f128 | ||
| 2052 | #endif | ||
| 2053 | |||
| 2054 | #define zig_cast_f16 (zig_f16) | 1977 | #define zig_cast_f16 (zig_f16) |
| 2055 | #define zig_cast_f32 (zig_f32) | 1978 | #define zig_cast_f32 (zig_f32) |
| 2056 | #define zig_cast_f64 (zig_f64) | 1979 | #define zig_cast_f64 (zig_f64) |
src/codegen/c.zig+31-8| ... | @@ -2603,7 +2603,7 @@ pub const DeclGen = struct { | ... | @@ -2603,7 +2603,7 @@ pub const DeclGen = struct { |
| 2603 | dg: *DeclGen, | 2603 | dg: *DeclGen, |
| 2604 | ty: Type, | 2604 | ty: Type, |
| 2605 | val: Value, | 2605 | val: Value, |
| 2606 | location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteralLoc | 2606 | location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteral |
| 2607 | ) !std.fmt.Formatter(formatIntLiteral) { | 2607 | ) !std.fmt.Formatter(formatIntLiteral) { |
| 2608 | const int_info = ty.intInfo(dg.module.getTarget()); | 2608 | const int_info = ty.intInfo(dg.module.getTarget()); |
| 2609 | const c_bits = toCIntBits(int_info.bits); | 2609 | const c_bits = toCIntBits(int_info.bits); |
| ... | @@ -7251,11 +7251,16 @@ fn formatIntLiteral( | ... | @@ -7251,11 +7251,16 @@ fn formatIntLiteral( |
| 7251 | return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); | 7251 | return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); |
| 7252 | } | 7252 | } |
| 7253 | 7253 | ||
| 7254 | var use_twos_comp = false; | ||
| 7254 | if (!int.positive) { | 7255 | if (!int.positive) { |
| 7255 | if (c_bits > 64) { | 7256 | if (c_bits > 64) { |
| 7256 | // TODO: Could use negate function instead? | 7257 | // TODO: Can this be done for decimal literals as well? |
| 7257 | // TODO: Use fmtIntLiteral for 0? | 7258 | if (fmt.len == 1 and fmt[0] != 'd') { |
| 7258 | try writer.print("zig_sub_{c}{d}(zig_as_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits }); | 7259 | use_twos_comp = true; |
| 7260 | } else { | ||
| 7261 | // TODO: Use fmtIntLiteral for 0? | ||
| 7262 | try writer.print("zig_sub_{c}{d}(zig_as_{c}{d}(0, 0), ", .{ signAbbrev(int_info.signedness), c_bits, signAbbrev(int_info.signedness), c_bits }); | ||
| 7263 | } | ||
| 7259 | } else { | 7264 | } else { |
| 7260 | try writer.writeByte('-'); | 7265 | try writer.writeByte('-'); |
| 7261 | } | 7266 | } |
| ... | @@ -7310,16 +7315,34 @@ fn formatIntLiteral( | ... | @@ -7310,16 +7315,34 @@ fn formatIntLiteral( |
| 7310 | } else { | 7315 | } else { |
| 7311 | assert(c_bits == 128); | 7316 | assert(c_bits == 128); |
| 7312 | const split = std.math.min(int.limbs.len, limbs_count_64); | 7317 | const split = std.math.min(int.limbs.len, limbs_count_64); |
| 7318 | var twos_comp_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; | ||
| 7319 | |||
| 7320 | // Adding a negation in the C code before the doesn't work in all cases: | ||
| 7321 | // - struct versions would require an extra zig_sub_ call to negate, which wouldn't work in constant expressions | ||
| 7322 | // - negating the f80 int representation (i128) doesn't make sense | ||
| 7323 | // Instead we write out the literal as a negative number in twos complement | ||
| 7324 | var limbs = int.limbs; | ||
| 7325 | |||
| 7326 | if (use_twos_comp) { | ||
| 7327 | var twos_comp = BigInt.Mutable{ | ||
| 7328 | .limbs = &twos_comp_limbs, | ||
| 7329 | .positive = undefined, | ||
| 7330 | .len = undefined, | ||
| 7331 | }; | ||
| 7332 | |||
| 7333 | twos_comp.convertToTwosComplement(int, .signed, int_info.bits); | ||
| 7334 | limbs = twos_comp.limbs; | ||
| 7335 | } | ||
| 7313 | 7336 | ||
| 7314 | var upper_pl = Value.Payload.BigInt{ | 7337 | var upper_pl = Value.Payload.BigInt{ |
| 7315 | .base = .{ .tag = .int_big_positive }, | 7338 | .base = .{ .tag = .int_big_positive }, |
| 7316 | .data = int.limbs[split..], | 7339 | .data = limbs[split..], |
| 7317 | }; | 7340 | }; |
| 7318 | const upper_val = Value.initPayload(&upper_pl.base); | 7341 | const upper_val = Value.initPayload(&upper_pl.base); |
| 7319 | try formatIntLiteral(.{ | 7342 | try formatIntLiteral(.{ |
| 7320 | .ty = switch (int_info.signedness) { | 7343 | .ty = switch (int_info.signedness) { |
| 7321 | .unsigned => Type.u64, | 7344 | .unsigned => Type.u64, |
| 7322 | .signed => Type.i64, | 7345 | .signed => if (use_twos_comp) Type.u64 else Type.i64, |
| 7323 | }, | 7346 | }, |
| 7324 | .val = upper_val, | 7347 | .val = upper_val, |
| 7325 | .mod = data.mod, | 7348 | .mod = data.mod, |
| ... | @@ -7329,7 +7352,7 @@ fn formatIntLiteral( | ... | @@ -7329,7 +7352,7 @@ fn formatIntLiteral( |
| 7329 | 7352 | ||
| 7330 | var lower_pl = Value.Payload.BigInt{ | 7353 | var lower_pl = Value.Payload.BigInt{ |
| 7331 | .base = .{ .tag = .int_big_positive }, | 7354 | .base = .{ .tag = .int_big_positive }, |
| 7332 | .data = int.limbs[0..split], | 7355 | .data = limbs[0..split], |
| 7333 | }; | 7356 | }; |
| 7334 | const lower_val = Value.initPayload(&lower_pl.base); | 7357 | const lower_val = Value.initPayload(&lower_pl.base); |
| 7335 | try formatIntLiteral(.{ | 7358 | try formatIntLiteral(.{ |
| ... | @@ -7338,7 +7361,7 @@ fn formatIntLiteral( | ... | @@ -7338,7 +7361,7 @@ fn formatIntLiteral( |
| 7338 | .mod = data.mod, | 7361 | .mod = data.mod, |
| 7339 | }, fmt, options, writer); | 7362 | }, fmt, options, writer); |
| 7340 | 7363 | ||
| 7341 | if (!int.positive and c_bits > 64) try writer.writeByte(')'); | 7364 | if (!int.positive and c_bits > 64 and !use_twos_comp) try writer.writeByte(')'); |
| 7342 | return writer.writeByte(')'); | 7365 | return writer.writeByte(')'); |
| 7343 | } | 7366 | } |
| 7344 | 7367 |
test/behavior/atomics.zig+2-1| ... | @@ -251,7 +251,8 @@ test "atomicrmw with ints" { | ... | @@ -251,7 +251,8 @@ test "atomicrmw with ints" { |
| 251 | return error.SkipZigTest; | 251 | return error.SkipZigTest; |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | const bit_values = [_]usize{ 8, 16, 32, 64 }; | 254 | // TODO: Use the max atomic bit size for the target, maybe builtin? |
| 255 | const bit_values = [_]usize{ 8 } ++ if (builtin.cpu.arch == .x86_64) [_]usize{ 16, 32, 64 } else [_]usize{ }; | ||
| 255 | inline for (bit_values) |bits| { | 256 | inline for (bit_values) |bits| { |
| 256 | try testAtomicRmwInt(.unsigned, bits); | 257 | try testAtomicRmwInt(.unsigned, bits); |
| 257 | comptime try testAtomicRmwInt(.unsigned, bits); | 258 | comptime try testAtomicRmwInt(.unsigned, bits); |