authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2022-12-18 17:30:52-05:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-01-01 16:44:29-05:00
log6ed049fe3642c775e53b3bef2f9bfb6a1de0f325
treef7576810e64dea9e247275b80c335741a4a75749
parent6445196fabd9c9c3e40c24d298dc9ac2a19bee35

cbe: all behaviour tests now pass on msvc

- 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 {
16771677 y.shiftRight(y.toConst(), norm_shift);
16781678 }
16791679
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
16801714 /// Truncate an integer to a number of bits, following 2s-complement semantics.
16811715 /// r may alias a.
16821716 ///
lib/zig.h+6-83
......@@ -1339,7 +1339,7 @@ static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {
13391339
13401340static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {
13411341 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 };
13431343 return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
13441344}
13451345
......@@ -1681,8 +1681,9 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
16811681}
16821682
16831683static 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);
16841685 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));
16861687}
16871688
16881689static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) {
......@@ -1942,14 +1943,15 @@ typedef zig_i128 zig_f128;
19421943#define zig_has_c_longdouble 1
19431944#define zig_libc_name_c_longdouble(name) name##l
19441945#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
19461947typedef long double zig_c_longdouble;
19471948#define zig_as_c_longdouble(fp, repr) fp##l
19481949#else
19491950#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
19501953#define zig_has_c_longdouble 0
19511954#define zig_repr_c_longdouble i128
1952#define zig_bitSizeOf_c_longdouble 128
19531955typedef zig_i128 zig_c_longdouble;
19541956#define zig_as_c_longdouble(fp, repr) repr
19551957#undef zig_as_special_c_longdouble
......@@ -1972,85 +1974,6 @@ zig_float_from_repr(f128, u128)
19721974zig_float_from_repr(c_longdouble, u128)
19731975#endif
19741976
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
20541977#define zig_cast_f16 (zig_f16)
20551978#define zig_cast_f32 (zig_f32)
20561979#define zig_cast_f64 (zig_f64)
src/codegen/c.zig+31-8
......@@ -2603,7 +2603,7 @@ pub const DeclGen = struct {
26032603 dg: *DeclGen,
26042604 ty: Type,
26052605 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
26072607 ) !std.fmt.Formatter(formatIntLiteral) {
26082608 const int_info = ty.intInfo(dg.module.getTarget());
26092609 const c_bits = toCIntBits(int_info.bits);
......@@ -7251,11 +7251,16 @@ fn formatIntLiteral(
72517251 return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" });
72527252 }
72537253
7254 var use_twos_comp = false;
72547255 if (!int.positive) {
72557256 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 }
72597264 } else {
72607265 try writer.writeByte('-');
72617266 }
......@@ -7310,16 +7315,34 @@ fn formatIntLiteral(
73107315 } else {
73117316 assert(c_bits == 128);
73127317 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 }
73137336
73147337 var upper_pl = Value.Payload.BigInt{
73157338 .base = .{ .tag = .int_big_positive },
7316 .data = int.limbs[split..],
7339 .data = limbs[split..],
73177340 };
73187341 const upper_val = Value.initPayload(&upper_pl.base);
73197342 try formatIntLiteral(.{
73207343 .ty = switch (int_info.signedness) {
73217344 .unsigned => Type.u64,
7322 .signed => Type.i64,
7345 .signed => if (use_twos_comp) Type.u64 else Type.i64,
73237346 },
73247347 .val = upper_val,
73257348 .mod = data.mod,
......@@ -7329,7 +7352,7 @@ fn formatIntLiteral(
73297352
73307353 var lower_pl = Value.Payload.BigInt{
73317354 .base = .{ .tag = .int_big_positive },
7332 .data = int.limbs[0..split],
7355 .data = limbs[0..split],
73337356 };
73347357 const lower_val = Value.initPayload(&lower_pl.base);
73357358 try formatIntLiteral(.{
......@@ -7338,7 +7361,7 @@ fn formatIntLiteral(
73387361 .mod = data.mod,
73397362 }, fmt, options, writer);
73407363
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(')');
73427365 return writer.writeByte(')');
73437366 }
73447367
test/behavior/atomics.zig+2-1
......@@ -251,7 +251,8 @@ test "atomicrmw with ints" {
251251 return error.SkipZigTest;
252252 }
253253
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{ };
255256 inline for (bit_values) |bits| {
256257 try testAtomicRmwInt(.unsigned, bits);
257258 comptime try testAtomicRmwInt(.unsigned, bits);