| 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 | 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 | 1714 | /// Truncate an integer to a number of bits, following 2s-complement semantics. |
| 1681 | 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 | 1339 | |
| 1340 | 1340 | static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { |
| 1341 | 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 | 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 | 1681 | } |
| 1682 | 1682 | |
| 1683 | 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 | 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 | 1689 | static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) { |
| ... | ... | @@ -1942,14 +1943,15 @@ typedef zig_i128 zig_f128; |
| 1942 | 1943 | #define zig_has_c_longdouble 1 |
| 1943 | 1944 | #define zig_libc_name_c_longdouble(name) name##l |
| 1944 | 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 | 1947 | typedef long double zig_c_longdouble; |
| 1947 | 1948 | #define zig_as_c_longdouble(fp, repr) fp##l |
| 1948 | 1949 | #else |
| 1949 | 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 | 1953 | #define zig_has_c_longdouble 0 |
| 1951 | 1954 | #define zig_repr_c_longdouble i128 |
| 1952 | #define zig_bitSizeOf_c_longdouble 128 | |
| 1953 | 1955 | typedef zig_i128 zig_c_longdouble; |
| 1954 | 1956 | #define zig_as_c_longdouble(fp, repr) repr |
| 1955 | 1957 | #undef zig_as_special_c_longdouble |
| ... | ... | @@ -1972,85 +1974,6 @@ zig_float_from_repr(f128, u128) |
| 1972 | 1974 | zig_float_from_repr(c_longdouble, u128) |
| 1973 | 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 | 1977 | #define zig_cast_f16 (zig_f16) |
| 2055 | 1978 | #define zig_cast_f32 (zig_f32) |
| 2056 | 1979 | #define zig_cast_f64 (zig_f64) |
src/codegen/c.zig+31-8| ... | ... | @@ -2603,7 +2603,7 @@ pub const DeclGen = struct { |
| 2603 | 2603 | dg: *DeclGen, |
| 2604 | 2604 | ty: Type, |
| 2605 | 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 | 2607 | ) !std.fmt.Formatter(formatIntLiteral) { |
| 2608 | 2608 | const int_info = ty.intInfo(dg.module.getTarget()); |
| 2609 | 2609 | const c_bits = toCIntBits(int_info.bits); |
| ... | ... | @@ -7251,11 +7251,16 @@ fn formatIntLiteral( |
| 7251 | 7251 | return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); |
| 7252 | 7252 | } |
| 7253 | 7253 | |
| 7254 | var use_twos_comp = false; | |
| 7254 | 7255 | if (!int.positive) { |
| 7255 | 7256 | if (c_bits > 64) { |
| 7256 | // TODO: Could use negate function instead? | |
| 7257 | // TODO: Use fmtIntLiteral for 0? | |
| 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 }); | |
| 7257 | // TODO: Can this be done for decimal literals as well? | |
| 7258 | if (fmt.len == 1 and fmt[0] != 'd') { | |
| 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 | 7264 | } else { |
| 7260 | 7265 | try writer.writeByte('-'); |
| 7261 | 7266 | } |
| ... | ... | @@ -7310,16 +7315,34 @@ fn formatIntLiteral( |
| 7310 | 7315 | } else { |
| 7311 | 7316 | assert(c_bits == 128); |
| 7312 | 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 | 7337 | var upper_pl = Value.Payload.BigInt{ |
| 7315 | 7338 | .base = .{ .tag = .int_big_positive }, |
| 7316 | .data = int.limbs[split..], | |
| 7339 | .data = limbs[split..], | |
| 7317 | 7340 | }; |
| 7318 | 7341 | const upper_val = Value.initPayload(&upper_pl.base); |
| 7319 | 7342 | try formatIntLiteral(.{ |
| 7320 | 7343 | .ty = switch (int_info.signedness) { |
| 7321 | 7344 | .unsigned => Type.u64, |
| 7322 | .signed => Type.i64, | |
| 7345 | .signed => if (use_twos_comp) Type.u64 else Type.i64, | |
| 7323 | 7346 | }, |
| 7324 | 7347 | .val = upper_val, |
| 7325 | 7348 | .mod = data.mod, |
| ... | ... | @@ -7329,7 +7352,7 @@ fn formatIntLiteral( |
| 7329 | 7352 | |
| 7330 | 7353 | var lower_pl = Value.Payload.BigInt{ |
| 7331 | 7354 | .base = .{ .tag = .int_big_positive }, |
| 7332 | .data = int.limbs[0..split], | |
| 7355 | .data = limbs[0..split], | |
| 7333 | 7356 | }; |
| 7334 | 7357 | const lower_val = Value.initPayload(&lower_pl.base); |
| 7335 | 7358 | try formatIntLiteral(.{ |
| ... | ... | @@ -7338,7 +7361,7 @@ fn formatIntLiteral( |
| 7338 | 7361 | .mod = data.mod, |
| 7339 | 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 | 7365 | return writer.writeByte(')'); |
| 7343 | 7366 | } |
| 7344 | 7367 |
test/behavior/atomics.zig+2-1| ... | ... | @@ -251,7 +251,8 @@ test "atomicrmw with ints" { |
| 251 | 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 | 256 | inline for (bit_values) |bits| { |
| 256 | 257 | try testAtomicRmwInt(.unsigned, bits); |
| 257 | 258 | comptime try testAtomicRmwInt(.unsigned, bits); |