diff --git a/src/bigfloat.cpp b/src/bigfloat.cpp index 22ff9c29a3..8e19f0a031 100644 --- a/src/bigfloat.cpp +++ b/src/bigfloat.cpp @@ -11,7 +11,7 @@ #include #include -void bigfloat_init_float(BigFloat *dest, long double x) { +void bigfloat_init_float(BigFloat *dest, __float128 x) { dest->value = x; } @@ -24,13 +24,13 @@ void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { if (op->digit_count == 0) return; - long double base = (long double)UINT64_MAX; + __float128 base = (__float128)UINT64_MAX; const uint64_t *digits = bigint_ptr(op); for (size_t i = op->digit_count - 1;;) { uint64_t digit = digits[i]; dest->value *= base; - dest->value += (long double)digit; + dest->value += (__float128)digit; if (i == 0) { if (op->is_negative) { @@ -96,7 +96,7 @@ void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { } void bigfloat_write_buf(Buf *buf, const BigFloat *op) { - buf_appendf(buf, "%Lf", op->value); + buf_appendf(buf, "%Lf", (long double)op->value); } Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) { @@ -117,6 +117,9 @@ void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, } else if (bit_count == 64) { double f64 = op->value; memcpy(buf, &f64, 8); + } else if (bit_count == 128) { + __float128 f128 = op->value; + memcpy(buf, &f128, 16); } else { zig_unreachable(); } @@ -132,6 +135,10 @@ void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, double f64; memcpy(&f64, buf, 8); dest->value = f64; + } else if (bit_count == 128) { + __float128 f128; + memcpy(&f128, buf, 16); + dest->value = f128; } else { zig_unreachable(); } diff --git a/src/bigfloat.hpp b/src/bigfloat.hpp index 30aa754ce6..0ec33d4a0d 100644 --- a/src/bigfloat.hpp +++ b/src/bigfloat.hpp @@ -14,12 +14,12 @@ #include struct BigFloat { - long double value; + __float128 value; }; struct Buf; -void bigfloat_init_float(BigFloat *dest, long double x); +void bigfloat_init_float(BigFloat *dest, __float128 x); void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x); void bigfloat_init_bigint(BigFloat *dest, const BigInt *op); int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len); diff --git a/src/bigint.cpp b/src/bigint.cpp index 0a9011da8f..16d630ebe3 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -220,6 +220,7 @@ void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bi const uint64_t *twos_comp_digits = bigint_ptr(&twos_comp); size_t bits_in_last_digit = bit_count % 64; + if (bits_in_last_digit == 0) bits_in_last_digit = 64; size_t bytes_in_last_digit = (bits_in_last_digit + 7) / 8; size_t unwritten_byte_count = 8 - bytes_in_last_digit; @@ -258,13 +259,13 @@ void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bi for (size_t digit_index = 0; digit_index < digit_count; digit_index += 1) { uint64_t x = (digit_index < twos_comp.digit_count) ? twos_comp_digits[digit_index] : 0; - for (size_t byte_index = 0; byte_index < 8; byte_index += 1) { + for (size_t byte_index = 0; + byte_index < 8 && (digit_index + 1 < digit_count || byte_index < bytes_in_last_digit); + byte_index += 1) + { uint8_t byte = x & 0xff; buf[buf_index] = byte; buf_index += 1; - if (buf_index >= unwritten_byte_count) { - break; - } x >>= 8; } } diff --git a/std/special/compiler_rt/README.md b/std/special/compiler_rt/README.md index bc853f2958..da012662f3 100644 --- a/std/special/compiler_rt/README.md +++ b/std/special/compiler_rt/README.md @@ -13,3 +13,12 @@ Any bugs should be solved by trying to duplicate the bug upstream. * If the bug only exists in Zig, something went wrong porting the code, and you can run the C code and Zig code side by side in a debugger to figure out what's happening differently. + +To test Zig's compiler-rt, run this command from the build directory: + +``` +make install && ./zig test ../std/special/compiler_rt/index.zig --library c +``` + +The `--library c` argument omits compiler-rt from the generated test program, +which prevents duplicate symbol linker errors for all the compiler-rt builtins. diff --git a/std/special/compiler_rt/fixunstfsi_test.zig b/std/special/compiler_rt/fixunstfsi_test.zig new file mode 100644 index 0000000000..325de53ef2 --- /dev/null +++ b/std/special/compiler_rt/fixunstfsi_test.zig @@ -0,0 +1,22 @@ +const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; +const assert = @import("../../debug.zig").assert; + +fn test__fixunstfsi(a: f128, expected: u32) { + const x = __fixunstfsi(a); + assert(x == expected); +} + +const inf128 = @bitCast(f128, u128(0x7fff0000000000000000000000000000)); + +test "fixunstfsi" { + test__fixunstfsi(inf128, 0xffffffff); + test__fixunstfsi(0, 0x0); + test__fixunstfsi(0x1.23456789abcdefp+5, 0x24); + test__fixunstfsi(0x1.23456789abcdefp-3, 0x0); + test__fixunstfsi(0x1.23456789abcdefp+20, 0x123456); + test__fixunstfsi(0x1.23456789abcdefp+40, 0xffffffff); + test__fixunstfsi(0x1.23456789abcdefp+256, 0xffffffff); + test__fixunstfsi(-0x1.23456789abcdefp+3, 0x0); + + test__fixunstfsi(0x1.p+32, 0xFFFFFFFF); +} diff --git a/test/cases/cast.zig b/test/cases/cast.zig index 8ac6260ad4..9de7a65dc6 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -258,3 +258,20 @@ test "explicit cast float number literal to integer if no fraction component" { const y = i32(f32(1e4)); assert(y == 10000); } + +test "cast u128 to f128 and back" { + comptime testCast128(); + testCast128(); +} + +fn testCast128() { + assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000); +} + +fn cast128Int(x: f128) -> u128 { + @bitCast(u128, x) +} + +fn cast128Float(x: u128) -> f128 { + @bitCast(f128, x) +}