mirror of
https://github.com/ziglang/zig.git
synced 2024-12-04 18:16:54 +00:00
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).
This commit is contained in:
parent
6445196fab
commit
6ed049fe36
@ -1677,6 +1677,40 @@ pub const Mutable = struct {
|
||||
y.shiftRight(y.toConst(), norm_shift);
|
||||
}
|
||||
|
||||
/// If a is positive, this passes through to truncate.
|
||||
/// If a is negative, then r is set to positive with the bit pattern ~(a - 1).
|
||||
///
|
||||
/// Asserts `r` has enough storage to store the result.
|
||||
/// The upper bound is `calcTwosCompLimbCount(a.len)`.
|
||||
pub fn convertToTwosComplement(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
|
||||
if (a.positive) {
|
||||
r.truncate(a, signedness, bit_count);
|
||||
return;
|
||||
}
|
||||
|
||||
const req_limbs = calcTwosCompLimbCount(bit_count);
|
||||
if (req_limbs == 0 or a.eqZero()) {
|
||||
r.set(0);
|
||||
return;
|
||||
}
|
||||
|
||||
const bit = @truncate(Log2Limb, bit_count - 1);
|
||||
const signmask = @as(Limb, 1) << bit;
|
||||
const mask = (signmask << 1) -% 1;
|
||||
|
||||
r.addScalar(a.abs(), -1);
|
||||
if (req_limbs > r.len) {
|
||||
mem.set(Limb, r.limbs[r.len..req_limbs], 0);
|
||||
}
|
||||
|
||||
assert(r.limbs.len >= req_limbs);
|
||||
r.len = req_limbs;
|
||||
|
||||
llnot(r.limbs[0..r.len]);
|
||||
r.limbs[r.len - 1] &= mask;
|
||||
r.normalize(r.len);
|
||||
}
|
||||
|
||||
/// Truncate an integer to a number of bits, following 2s-complement semantics.
|
||||
/// r may alias a.
|
||||
///
|
||||
|
89
lib/zig.h
89
lib/zig.h
@ -1339,7 +1339,7 @@ static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) {
|
||||
|
||||
static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) {
|
||||
if (rhs == zig_as_u8(0)) return lhs;
|
||||
if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; // TODO: Fix?
|
||||
if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.lo << rhs, .lo = zig_minInt_u64 };
|
||||
return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs };
|
||||
}
|
||||
|
||||
@ -1681,8 +1681,9 @@ static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) {
|
||||
}
|
||||
|
||||
static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) {
|
||||
if (bits <= zig_as_u8(64)) return zig_clz_u64(zig_lo_u128(val), bits);
|
||||
if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64));
|
||||
return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + zig_as_u8(64);
|
||||
return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + (bits - zig_as_u8(64));
|
||||
}
|
||||
|
||||
static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) {
|
||||
@ -1942,14 +1943,15 @@ typedef zig_i128 zig_f128;
|
||||
#define zig_has_c_longdouble 1
|
||||
#define zig_libc_name_c_longdouble(name) name##l
|
||||
#define zig_as_special_constant_c_longdouble(sign, name, arg, repr) zig_as_special_c_longdouble(sign, name, arg, repr)
|
||||
#if !_MSC_VER // TODO: Is there a better way to detect long double == double on msvc?
|
||||
#ifdef zig_bitSizeOf_c_longdouble
|
||||
typedef long double zig_c_longdouble;
|
||||
#define zig_as_c_longdouble(fp, repr) fp##l
|
||||
#else
|
||||
#undef zig_has_c_longdouble
|
||||
#define zig_bitSizeOf_c_longdouble 80
|
||||
#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80
|
||||
#define zig_has_c_longdouble 0
|
||||
#define zig_repr_c_longdouble i128
|
||||
#define zig_bitSizeOf_c_longdouble 128
|
||||
typedef zig_i128 zig_c_longdouble;
|
||||
#define zig_as_c_longdouble(fp, repr) repr
|
||||
#undef zig_as_special_c_longdouble
|
||||
@ -1972,85 +1974,6 @@ zig_float_from_repr(f128, u128)
|
||||
zig_float_from_repr(c_longdouble, u128)
|
||||
#endif
|
||||
|
||||
/* #define zig_float_from_repr(Type) *((zig_##Type*)&repr) */
|
||||
|
||||
/* #define zig_float_inf_builtin_0(Type, ReprType) \ */
|
||||
/* static inline zig_##Type zig_as_special_inf_##Type(zig_##ReprType repr) { \ */
|
||||
/* return zig_float_from_repr(Type); \ */
|
||||
/* } */
|
||||
/* #define zig_float_inf_builtin_1(Type, ReprType) \ */
|
||||
/* static inline zig_##Type zig_as_special_inf_##Type(zig_##ReprType repr) { \ */
|
||||
/* return __builtin_inf(); \ */
|
||||
/* } */
|
||||
/* #define zig_float_nan_builtin_0(Type, ReprType) \ */
|
||||
/* static inline zig_##Type zig_as_special_nan_##Type(const char* arg, zig_##ReprType repr) { \ */
|
||||
/* return zig_float_from_repr(Type); \ */
|
||||
/* } */
|
||||
/* #define zig_float_nan_builtin_1(Type, ReprType) \ */
|
||||
/* static inline zig_##Type zig_as_special_nan_##Type(const char* arg, zig_##ReprType repr) { \ */
|
||||
/* return __builtin_nan(arg); \ */
|
||||
/* } */
|
||||
/* #define zig_float_nans_builtin_0(Type, ReprType) \ */
|
||||
/* static inline zig_##Type zig_as_special_nans_##Type(const char* arg, zig_##ReprType repr) { \ */
|
||||
/* return zig_float_from_repr(Type); \ */
|
||||
/* } */
|
||||
/* #define zig_float_nans_builtin_1(Type, ReprType) \ */
|
||||
/* static inline zig_##Type zig_as_special_nans_##Type(const char* arg, zig_##ReprType repr) { \ */
|
||||
/* return __builtin_nans(arg); \ */
|
||||
/* } */
|
||||
|
||||
/* #define zig_float_special_builtins(Type, ReprType) \ */
|
||||
/* zig_expand_concat(zig_float_inf_builtin_, zig_has_builtin(inf))(Type, ReprType) \ */
|
||||
/* zig_expand_concat(zig_float_nan_builtin_, zig_has_builtin(nan))(Type, ReprType) \ */
|
||||
/* zig_expand_concat(zig_float_nans_builtin_, zig_has_builtin(nans))(Type, ReprType) */
|
||||
|
||||
/* #if zig_has_builtin(nan) */
|
||||
/* #define zig_as_special_nan(arg, repr) __builtin_nan(arg); */
|
||||
/* #define zig_as_special_nan_f16(arg, repr) __builtin_nan(arg); */
|
||||
/* #define zig_as_special_nan_f32(arg, repr) __builtin_nan(arg); */
|
||||
/* #define zig_as_special_nan_f64(arg, repr) __builtin_nan(arg); */
|
||||
/* #define zig_as_special_nan_f80(arg, repr) __builtin_nan(arg); */
|
||||
/* #define zig_as_special_nan_f128(arg, repr) __builtin_nan(arg); */
|
||||
/* #else */
|
||||
/* zig_float_special_builtins(); */
|
||||
/* #endif */
|
||||
|
||||
/* #if zig_has_f16 */
|
||||
/* zig_float_special_builtins(f16, u16) */
|
||||
/* #endif */
|
||||
|
||||
/* #if zig_has_f32 */
|
||||
/* zig_float_special_builtins(f32, u32) */
|
||||
/* #endif */
|
||||
|
||||
/* #if zig_has_f64 */
|
||||
/* zig_float_special_builtins(f64, u64) */
|
||||
/* #endif */
|
||||
|
||||
/* #if zig_has_f80 */
|
||||
/* zig_float_special_builtins(f80, u128) */
|
||||
/* #endif */
|
||||
|
||||
/* #if zig_has_f128 */
|
||||
/* zig_float_special_builtins(f128, u128) */
|
||||
/* #endif */
|
||||
|
||||
/* #if zig_has_c_longdouble */
|
||||
/* zig_float_special_builtins(c_longdouble, u128) */
|
||||
/* #endif */
|
||||
|
||||
#if zig_bitSizeOf_c_longdouble == 16
|
||||
#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f16
|
||||
#elif zig_bitSizeOf_c_longdouble == 32
|
||||
#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f32
|
||||
#elif zig_bitSizeOf_c_longdouble == 64
|
||||
#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f64
|
||||
#elif zig_bitSizeOf_c_longdouble == 80
|
||||
#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80
|
||||
#elif zig_bitSizeOf_c_longdouble == 128
|
||||
#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f128
|
||||
#endif
|
||||
|
||||
#define zig_cast_f16 (zig_f16)
|
||||
#define zig_cast_f32 (zig_f32)
|
||||
#define zig_cast_f64 (zig_f64)
|
||||
|
@ -2603,7 +2603,7 @@ pub const DeclGen = struct {
|
||||
dg: *DeclGen,
|
||||
ty: Type,
|
||||
val: Value,
|
||||
location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteralLoc
|
||||
location: ValueRenderLocation, // TODO: Instead add this as optional arg to fmtIntLiteral
|
||||
) !std.fmt.Formatter(formatIntLiteral) {
|
||||
const int_info = ty.intInfo(dg.module.getTarget());
|
||||
const c_bits = toCIntBits(int_info.bits);
|
||||
@ -7251,11 +7251,16 @@ fn formatIntLiteral(
|
||||
return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" });
|
||||
}
|
||||
|
||||
var use_twos_comp = false;
|
||||
if (!int.positive) {
|
||||
if (c_bits > 64) {
|
||||
// TODO: Could use negate function instead?
|
||||
// TODO: Use fmtIntLiteral for 0?
|
||||
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 });
|
||||
// TODO: Can this be done for decimal literals as well?
|
||||
if (fmt.len == 1 and fmt[0] != 'd') {
|
||||
use_twos_comp = true;
|
||||
} else {
|
||||
// TODO: Use fmtIntLiteral for 0?
|
||||
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 });
|
||||
}
|
||||
} else {
|
||||
try writer.writeByte('-');
|
||||
}
|
||||
@ -7310,16 +7315,34 @@ fn formatIntLiteral(
|
||||
} else {
|
||||
assert(c_bits == 128);
|
||||
const split = std.math.min(int.limbs.len, limbs_count_64);
|
||||
var twos_comp_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined;
|
||||
|
||||
// Adding a negation in the C code before the doesn't work in all cases:
|
||||
// - struct versions would require an extra zig_sub_ call to negate, which wouldn't work in constant expressions
|
||||
// - negating the f80 int representation (i128) doesn't make sense
|
||||
// Instead we write out the literal as a negative number in twos complement
|
||||
var limbs = int.limbs;
|
||||
|
||||
if (use_twos_comp) {
|
||||
var twos_comp = BigInt.Mutable{
|
||||
.limbs = &twos_comp_limbs,
|
||||
.positive = undefined,
|
||||
.len = undefined,
|
||||
};
|
||||
|
||||
twos_comp.convertToTwosComplement(int, .signed, int_info.bits);
|
||||
limbs = twos_comp.limbs;
|
||||
}
|
||||
|
||||
var upper_pl = Value.Payload.BigInt{
|
||||
.base = .{ .tag = .int_big_positive },
|
||||
.data = int.limbs[split..],
|
||||
.data = limbs[split..],
|
||||
};
|
||||
const upper_val = Value.initPayload(&upper_pl.base);
|
||||
try formatIntLiteral(.{
|
||||
.ty = switch (int_info.signedness) {
|
||||
.unsigned => Type.u64,
|
||||
.signed => Type.i64,
|
||||
.signed => if (use_twos_comp) Type.u64 else Type.i64,
|
||||
},
|
||||
.val = upper_val,
|
||||
.mod = data.mod,
|
||||
@ -7329,7 +7352,7 @@ fn formatIntLiteral(
|
||||
|
||||
var lower_pl = Value.Payload.BigInt{
|
||||
.base = .{ .tag = .int_big_positive },
|
||||
.data = int.limbs[0..split],
|
||||
.data = limbs[0..split],
|
||||
};
|
||||
const lower_val = Value.initPayload(&lower_pl.base);
|
||||
try formatIntLiteral(.{
|
||||
@ -7338,7 +7361,7 @@ fn formatIntLiteral(
|
||||
.mod = data.mod,
|
||||
}, fmt, options, writer);
|
||||
|
||||
if (!int.positive and c_bits > 64) try writer.writeByte(')');
|
||||
if (!int.positive and c_bits > 64 and !use_twos_comp) try writer.writeByte(')');
|
||||
return writer.writeByte(')');
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,8 @@ test "atomicrmw with ints" {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
const bit_values = [_]usize{ 8, 16, 32, 64 };
|
||||
// TODO: Use the max atomic bit size for the target, maybe builtin?
|
||||
const bit_values = [_]usize{ 8 } ++ if (builtin.cpu.arch == .x86_64) [_]usize{ 16, 32, 64 } else [_]usize{ };
|
||||
inline for (bit_values) |bits| {
|
||||
try testAtomicRmwInt(.unsigned, bits);
|
||||
comptime try testAtomicRmwInt(.unsigned, bits);
|
||||
|
Loading…
Reference in New Issue
Block a user