From 6a98bf3dba6f3ed5b40fe7899899e2a792028be4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 16 Aug 2017 19:07:35 -0400 Subject: [PATCH] compiler_rt implementations for __fixuns* functions * add u128 and i128 integer types * add f128 floating point type * implement big integer multiplication (See #405) --- CMakeLists.txt | 18 ++++- src/all_types.hpp | 5 +- src/analyze.cpp | 2 + src/bigint.cpp | 84 +++++++++++++++++---- src/codegen.cpp | 16 ++++ std/special/compiler_rt/README.md | 15 ++++ std/special/compiler_rt/fixuint.zig | 50 ++++++++++++ std/special/compiler_rt/fixunsdfdi.zig | 10 +++ std/special/compiler_rt/fixunsdfdi_test.zig | 39 ++++++++++ std/special/compiler_rt/fixunsdfsi.zig | 10 +++ std/special/compiler_rt/fixunsdfsi_test.zig | 39 ++++++++++ std/special/compiler_rt/fixunsdfti.zig | 9 +++ std/special/compiler_rt/fixunsdfti_test.zig | 47 ++++++++++++ std/special/compiler_rt/fixunssfdi.zig | 9 +++ std/special/compiler_rt/fixunssfdi_test.zig | 35 +++++++++ std/special/compiler_rt/fixunssfsi.zig | 9 +++ std/special/compiler_rt/fixunssfsi_test.zig | 36 +++++++++ std/special/compiler_rt/fixunssfti.zig | 10 +++ std/special/compiler_rt/fixunssfti_test.zig | 41 ++++++++++ std/special/compiler_rt/fixunstfdi.zig | 9 +++ std/special/compiler_rt/fixunstfdi_test.zig | 49 ++++++++++++ std/special/compiler_rt/fixunstfsi.zig | 9 +++ std/special/compiler_rt/fixunstfti.zig | 10 +++ std/special/compiler_rt/index.zig | 23 +++++- std/special/compiler_rt/udivti3.zig | 0 std/special/compiler_rt/umodti3.zig | 0 test/cases/math.zig | 26 +++++++ 27 files changed, 588 insertions(+), 22 deletions(-) create mode 100644 std/special/compiler_rt/README.md create mode 100644 std/special/compiler_rt/fixuint.zig create mode 100644 std/special/compiler_rt/fixunsdfdi.zig create mode 100644 std/special/compiler_rt/fixunsdfdi_test.zig create mode 100644 std/special/compiler_rt/fixunsdfsi.zig create mode 100644 std/special/compiler_rt/fixunsdfsi_test.zig create mode 100644 std/special/compiler_rt/fixunsdfti.zig create mode 100644 std/special/compiler_rt/fixunsdfti_test.zig create mode 100644 std/special/compiler_rt/fixunssfdi.zig create mode 100644 std/special/compiler_rt/fixunssfdi_test.zig create mode 100644 std/special/compiler_rt/fixunssfsi.zig create mode 100644 std/special/compiler_rt/fixunssfsi_test.zig create mode 100644 std/special/compiler_rt/fixunssfti.zig create mode 100644 std/special/compiler_rt/fixunssfti_test.zig create mode 100644 std/special/compiler_rt/fixunstfdi.zig create mode 100644 std/special/compiler_rt/fixunstfdi_test.zig create mode 100644 std/special/compiler_rt/fixunstfsi.zig create mode 100644 std/special/compiler_rt/fixunstfti.zig create mode 100644 std/special/compiler_rt/udivti3.zig create mode 100644 std/special/compiler_rt/umodti3.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 380c617e17..75467c961f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,10 +239,10 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/endian.zig" DESTINATION "${ZIG_STD_DEST}") -install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt") -install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol") install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/enum3.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol") +install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol") install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/errol/lookup.zig" DESTINATION "${ZIG_STD_DEST}/fmt/errol") +install(FILES "${CMAKE_SOURCE_DIR}/std/fmt/index.zig" DESTINATION "${ZIG_STD_DEST}/fmt") install(FILES "${CMAKE_SOURCE_DIR}/std/hash_map.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/index.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/io.zig" DESTINATION "${ZIG_STD_DEST}") @@ -303,15 +303,27 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux.zig" DESTINATION "${ZIG_STD_DEST install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_i386.zig" DESTINATION "${ZIG_STD_DEST}/os") install(FILES "${CMAKE_SOURCE_DIR}/std/os/linux_x86_64.zig" DESTINATION "${ZIG_STD_DEST}/os") install(FILES "${CMAKE_SOURCE_DIR}/std/os/path.zig" DESTINATION "${ZIG_STD_DEST}/os") -install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/index.zig" DESTINATION "${ZIG_STD_DEST}/os/windows") install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/error.zig" DESTINATION "${ZIG_STD_DEST}/os/windows") +install(FILES "${CMAKE_SOURCE_DIR}/std/os/windows/index.zig" DESTINATION "${ZIG_STD_DEST}/os/windows") install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}") install(FILES "${CMAKE_SOURCE_DIR}/std/special/bootstrap.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_file_template.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/build_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/builtin.zig" DESTINATION "${ZIG_STD_DEST}/special") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixuint.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunsdfdi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunsdfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunsdfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunssfdi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunssfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunssfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfdi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfsi.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/fixunstfti.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/index.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") +install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special") diff --git a/src/all_types.hpp b/src/all_types.hpp index 88a42d3a25..e6ad2f5e72 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1386,7 +1386,7 @@ struct CodeGen { struct { TypeTableEntry *entry_bool; - TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64] + TypeTableEntry *entry_int[2][5]; // [signed,unsigned][8,16,32,64,128] TypeTableEntry *entry_c_int[CIntTypeCount]; TypeTableEntry *entry_c_longdouble; TypeTableEntry *entry_c_void; @@ -1394,14 +1394,17 @@ struct CodeGen { TypeTableEntry *entry_u16; TypeTableEntry *entry_u32; TypeTableEntry *entry_u64; + TypeTableEntry *entry_u128; TypeTableEntry *entry_i8; TypeTableEntry *entry_i16; TypeTableEntry *entry_i32; TypeTableEntry *entry_i64; + TypeTableEntry *entry_i128; TypeTableEntry *entry_isize; TypeTableEntry *entry_usize; TypeTableEntry *entry_f32; TypeTableEntry *entry_f64; + TypeTableEntry *entry_f128; TypeTableEntry *entry_void; TypeTableEntry *entry_unreachable; TypeTableEntry *entry_type; diff --git a/src/analyze.cpp b/src/analyze.cpp index 8418dbdcd1..1cb36682f9 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3085,6 +3085,8 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint32_t size_in_b index = 2; } else if (size_in_bits == 64) { index = 3; + } else if (size_in_bits == 128) { + index = 4; } else { return nullptr; } diff --git a/src/bigint.cpp b/src/bigint.cpp index db55d25fc9..5679d2041a 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -373,7 +373,6 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { bigint_normalize(dest); return; } - // TODO this code path is untested size_t i = 1; uint64_t first_digit = dest->data.digit; dest->data.digits = allocate_nonzero(max(op1->digit_count, op2->digit_count) + 1); @@ -397,17 +396,14 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { } dest->data.digits[i] = x; - x += 1; + i += 1; if (!found_digit) { - break; + dest->digit_count = i; + bigint_normalize(dest); + return; } } - if (overflow > 0) { - dest->data.digits[i] = overflow; - } - bigint_normalize(dest); - return; } const BigInt *op_pos; const BigInt *op_neg; @@ -500,12 +496,49 @@ static void mul_overflow(uint64_t x, uint64_t y, uint64_t *result, uint64_t *car *carry = 0; return; } - zig_panic("TODO bigint_mul with big numbers"); - //unsigned __int128 big_x = x; - //unsigned __int128 big_y = y; - //unsigned __int128 big_result = big_x * big_y; - //*carry = big_result >> 64; + unsigned __int128 big_x = x; + unsigned __int128 big_y = y; + unsigned __int128 big_result = big_x * big_y; + *carry = big_result >> 64; +} + +static void mul_scalar(BigInt *dest, const BigInt *op, uint64_t scalar) { + bigint_init_unsigned(dest, 0); + + BigInt bi_64; + bigint_init_unsigned(&bi_64, 64); + + const uint64_t *op_digits = bigint_ptr(op); + size_t i = op->digit_count - 1; + + for (;;) { + BigInt shifted; + bigint_shl(&shifted, dest, &bi_64); + + uint64_t result_scalar; + uint64_t carry_scalar; + mul_overflow(scalar, op_digits[i], &result_scalar, &carry_scalar); + + BigInt result; + bigint_init_unsigned(&result, result_scalar); + + BigInt carry; + bigint_init_unsigned(&carry, carry_scalar); + + BigInt carry_shifted; + bigint_shl(&carry_shifted, &carry, &bi_64); + + BigInt tmp; + bigint_add(&tmp, &shifted, &carry_shifted); + + bigint_add(dest, &tmp, &result); + + if (i == 0) { + break; + } + i -= 1; + } } void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) { @@ -523,7 +556,30 @@ void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2) { bigint_normalize(dest); return; } - zig_panic("TODO bigint_mul with big numbers"); + + bigint_init_unsigned(dest, 0); + + BigInt bi_64; + bigint_init_unsigned(&bi_64, 64); + + size_t i = op2->digit_count - 1; + for (;;) { + BigInt shifted; + bigint_shl(&shifted, dest, &bi_64); + + BigInt scalar_result; + mul_scalar(&scalar_result, op1, op2_digits[i]); + + bigint_add(dest, &scalar_result, &shifted); + + if (i == 0) { + break; + } + i -= 1; + } + + dest->is_negative = (op1->is_negative != op2->is_negative); + bigint_normalize(dest); } void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed) { diff --git a/src/codegen.cpp b/src/codegen.cpp index 6d323a8e2c..a7695d4d5f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4208,6 +4208,7 @@ static const uint8_t int_sizes_in_bits[] = { 16, 32, 64, + 128, }; struct CIntTypeInfo { @@ -4390,6 +4391,19 @@ static void define_builtin_types(CodeGen *g) { g->builtin_types.entry_f64 = entry; g->primitive_type_table.put(&entry->name, entry); } + { + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); + entry->type_ref = LLVMFP128Type(); + buf_init_from_str(&entry->name, "f128"); + entry->data.floating.bit_count = 128; + + uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); + entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), + debug_size_in_bits, + ZigLLVMEncoding_DW_ATE_float()); + g->builtin_types.entry_f128 = entry; + g->primitive_type_table.put(&entry->name, entry); + } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); entry->type_ref = LLVMX86FP80Type(); @@ -4435,10 +4449,12 @@ static void define_builtin_types(CodeGen *g) { g->builtin_types.entry_u16 = get_int_type(g, false, 16); g->builtin_types.entry_u32 = get_int_type(g, false, 32); g->builtin_types.entry_u64 = get_int_type(g, false, 64); + g->builtin_types.entry_u128 = get_int_type(g, false, 128); g->builtin_types.entry_i8 = get_int_type(g, true, 8); g->builtin_types.entry_i16 = get_int_type(g, true, 16); g->builtin_types.entry_i32 = get_int_type(g, true, 32); g->builtin_types.entry_i64 = get_int_type(g, true, 64); + g->builtin_types.entry_i128 = get_int_type(g, true, 128); { g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void"); diff --git a/std/special/compiler_rt/README.md b/std/special/compiler_rt/README.md new file mode 100644 index 0000000000..bc853f2958 --- /dev/null +++ b/std/special/compiler_rt/README.md @@ -0,0 +1,15 @@ +This compiler-rt library is ported from [LLVM](http://compiler-rt.llvm.org/). + +It's needed because LLVM emits library calls to compiler-rt when hardware lacks +functionality, for example, 64-bit integer multiplication on 32-bit x86. + +This library is automatically built as-needed for the compilation target and +then statically linked and therefore is a transparent dependency for the +programmer. + +Any bugs should be solved by trying to duplicate the bug upstream. + * If the bug exists upstream, get it fixed with the LLVM team and then port + the fix downstream to Zig. + * 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. diff --git a/std/special/compiler_rt/fixuint.zig b/std/special/compiler_rt/fixuint.zig new file mode 100644 index 0000000000..58f0179ca8 --- /dev/null +++ b/std/special/compiler_rt/fixuint.zig @@ -0,0 +1,50 @@ +pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) -> fixuint_t { + @setDebugSafety(this, true); // TODO + + const rep_t = switch (fp_t) { + f32 => u32, + f64 => u64, + f128 => u128, + else => unreachable, + }; + const srep_t = @IntType(true, rep_t.bit_count); + const significandBits = switch (fp_t) { + f32 => 23, + f64 => 52, + f128 => 112, + else => unreachable, + }; + const typeWidth = rep_t.bit_count; + const exponentBits = (typeWidth - significandBits - 1); + const signBit = (rep_t(1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + const exponentBias = (maxExponent >> 1); + + const implicitBit = (rep_t(1) << significandBits); + const significandMask = (implicitBit - 1); + + // Break a into sign, exponent, significand + const aRep: rep_t = @bitCast(rep_t, a); + const absMask = signBit - 1; + const aAbs: rep_t = aRep & absMask; + + const sign = if ((aRep & signBit) != 0) i32(-1) else i32(1); + const exponent = i32(aAbs >> significandBits) - exponentBias; + const significand: rep_t = (aAbs & significandMask) | implicitBit; + + // If either the value or the exponent is negative, the result is zero. + if (sign == -1 or exponent < 0) + return 0; + + // If the value is too large for the integer type, saturate. + if (c_uint(exponent) >= fixuint_t.bit_count) + return ~fixuint_t(0); + + // If 0 <= exponent < significandBits, right shift to get the result. + // Otherwise, shift left. + if (exponent < significandBits) { + return fixuint_t(significand >> rep_t(significandBits - exponent)); + } else { + return fixuint_t(significand) << fixuint_t(exponent - significandBits); + } +} diff --git a/std/special/compiler_rt/fixunsdfdi.zig b/std/special/compiler_rt/fixunsdfdi.zig new file mode 100644 index 0000000000..1256e8ce7a --- /dev/null +++ b/std/special/compiler_rt/fixunsdfdi.zig @@ -0,0 +1,10 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunsdfdi(a: f64) -> u64 { + return fixuint(f64, u64, a); +} + +test "import fixunsdfdi" { + _ = @import("fixunsdfdi_test.zig"); +} + diff --git a/std/special/compiler_rt/fixunsdfdi_test.zig b/std/special/compiler_rt/fixunsdfdi_test.zig new file mode 100644 index 0000000000..b77de662c9 --- /dev/null +++ b/std/special/compiler_rt/fixunsdfdi_test.zig @@ -0,0 +1,39 @@ +const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; +const assert = @import("../../debug.zig").assert; + +fn test__fixunsdfdi(a: f64, expected: u64) { + const x = __fixunsdfdi(a); + assert(x == expected); +} + +test "fixunsdfdi" { + test__fixunsdfdi(0.0, 0); + test__fixunsdfdi(0.5, 0); + test__fixunsdfdi(0.99, 0); + test__fixunsdfdi(1.0, 1); + test__fixunsdfdi(1.5, 1); + test__fixunsdfdi(1.99, 1); + test__fixunsdfdi(2.0, 2); + test__fixunsdfdi(2.01, 2); + test__fixunsdfdi(-0.5, 0); + test__fixunsdfdi(-0.99, 0); + test__fixunsdfdi(-1.0, 0); + test__fixunsdfdi(-1.5, 0); + test__fixunsdfdi(-1.99, 0); + test__fixunsdfdi(-2.0, 0); + test__fixunsdfdi(-2.01, 0); + + test__fixunsdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixunsdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + test__fixunsdfdi(-0x1.FFFFFEp+62, 0); + test__fixunsdfdi(-0x1.FFFFFCp+62, 0); + + test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + test__fixunsdfdi(0x1.0000000000000p+63, 0x8000000000000000); + test__fixunsdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixunsdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + test__fixunsdfdi(-0x1.FFFFFFFFFFFFFp+62, 0); + test__fixunsdfdi(-0x1.FFFFFFFFFFFFEp+62, 0); +} diff --git a/std/special/compiler_rt/fixunsdfsi.zig b/std/special/compiler_rt/fixunsdfsi.zig new file mode 100644 index 0000000000..bb5b651221 --- /dev/null +++ b/std/special/compiler_rt/fixunsdfsi.zig @@ -0,0 +1,10 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunsdfsi(a: f64) -> u32 { + return fixuint(f64, u32, a); +} + +test "import fixunsdfsi" { + _ = @import("fixunsdfsi_test.zig"); +} + diff --git a/std/special/compiler_rt/fixunsdfsi_test.zig b/std/special/compiler_rt/fixunsdfsi_test.zig new file mode 100644 index 0000000000..eef374773d --- /dev/null +++ b/std/special/compiler_rt/fixunsdfsi_test.zig @@ -0,0 +1,39 @@ +const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; +const assert = @import("../../debug.zig").assert; + +fn test__fixunsdfsi(a: f64, expected: u32) { + const x = __fixunsdfsi(a); + assert(x == expected); +} + +test "fixunsdfsi" { + test__fixunsdfsi(0.0, 0); + + test__fixunsdfsi(0.5, 0); + test__fixunsdfsi(0.99, 0); + test__fixunsdfsi(1.0, 1); + test__fixunsdfsi(1.5, 1); + test__fixunsdfsi(1.99, 1); + test__fixunsdfsi(2.0, 2); + test__fixunsdfsi(2.01, 2); + test__fixunsdfsi(-0.5, 0); + test__fixunsdfsi(-0.99, 0); + test__fixunsdfsi(-1.0, 0); + test__fixunsdfsi(-1.5, 0); + test__fixunsdfsi(-1.99, 0); + test__fixunsdfsi(-2.0, 0); + test__fixunsdfsi(-2.01, 0); + + test__fixunsdfsi(0x1.000000p+31, 0x80000000); + test__fixunsdfsi(0x1.000000p+32, 0xFFFFFFFF); + test__fixunsdfsi(0x1.FFFFFEp+31, 0xFFFFFF00); + test__fixunsdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixunsdfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + + test__fixunsdfsi(-0x1.FFFFFEp+30, 0); + test__fixunsdfsi(-0x1.FFFFFCp+30, 0); + + test__fixunsdfsi(0x1.FFFFFFFEp+31, 0xFFFFFFFF); + test__fixunsdfsi(0x1.FFFFFFFC00000p+30, 0x7FFFFFFF); + test__fixunsdfsi(0x1.FFFFFFF800000p+30, 0x7FFFFFFE); +} diff --git a/std/special/compiler_rt/fixunsdfti.zig b/std/special/compiler_rt/fixunsdfti.zig new file mode 100644 index 0000000000..17866f2873 --- /dev/null +++ b/std/special/compiler_rt/fixunsdfti.zig @@ -0,0 +1,9 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunsdfti(a: f64) -> u128 { + return fixuint(f64, u128, a); +} + +test "import fixunsdfti" { + _ = @import("fixunsdfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixunsdfti_test.zig b/std/special/compiler_rt/fixunsdfti_test.zig new file mode 100644 index 0000000000..cd348fffde --- /dev/null +++ b/std/special/compiler_rt/fixunsdfti_test.zig @@ -0,0 +1,47 @@ +const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; +const assert = @import("../../debug.zig").assert; + +fn test__fixunsdfti(a: f64, expected: u128) { + const x = __fixunsdfti(a); + assert(x == expected); +} + +test "fixunsdfti" { + test__fixunsdfti(0.0, 0); + + test__fixunsdfti(0.5, 0); + test__fixunsdfti(0.99, 0); + test__fixunsdfti(1.0, 1); + test__fixunsdfti(1.5, 1); + test__fixunsdfti(1.99, 1); + test__fixunsdfti(2.0, 2); + test__fixunsdfti(2.01, 2); + test__fixunsdfti(-0.5, 0); + test__fixunsdfti(-0.99, 0); + test__fixunsdfti(-1.0, 0); + test__fixunsdfti(-1.5, 0); + test__fixunsdfti(-1.99, 0); + test__fixunsdfti(-2.0, 0); + test__fixunsdfti(-2.01, 0); + + test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + test__fixunsdfti(-0x1.FFFFFEp+62, 0); + test__fixunsdfti(-0x1.FFFFFCp+62, 0); + + test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800); + test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, 0xFFFFFFFFFFFFF8000000000000000000); + test__fixunsdfti(0x1.0000000000000p+127, 0x80000000000000000000000000000000); + test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + test__fixunsdfti(0x1.0000000000000p+128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0); + test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0); +} + diff --git a/std/special/compiler_rt/fixunssfdi.zig b/std/special/compiler_rt/fixunssfdi.zig new file mode 100644 index 0000000000..9e3355c4ff --- /dev/null +++ b/std/special/compiler_rt/fixunssfdi.zig @@ -0,0 +1,9 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunssfdi(a: f32) -> u64 { + return fixuint(f32, u64, a); +} + +test "import fixunssfdi" { + _ = @import("fixunssfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixunssfdi_test.zig b/std/special/compiler_rt/fixunssfdi_test.zig new file mode 100644 index 0000000000..67e3cd24c4 --- /dev/null +++ b/std/special/compiler_rt/fixunssfdi_test.zig @@ -0,0 +1,35 @@ +const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; +const assert = @import("../../debug.zig").assert; + +fn test__fixunssfdi(a: f32, expected: u64) { + const x = __fixunssfdi(a); + assert(x == expected); +} + +test "fixunssfdi" { + test__fixunssfdi(0.0, 0); + + test__fixunssfdi(0.5, 0); + test__fixunssfdi(0.99, 0); + test__fixunssfdi(1.0, 1); + test__fixunssfdi(1.5, 1); + test__fixunssfdi(1.99, 1); + test__fixunssfdi(2.0, 2); + test__fixunssfdi(2.01, 2); + test__fixunssfdi(-0.5, 0); + test__fixunssfdi(-0.99, 0); + + test__fixunssfdi(-1.0, 0); + test__fixunssfdi(-1.5, 0); + test__fixunssfdi(-1.99, 0); + test__fixunssfdi(-2.0, 0); + test__fixunssfdi(-2.01, 0); + + test__fixunssfdi(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + test__fixunssfdi(0x1.000000p+63, 0x8000000000000000); + test__fixunssfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixunssfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + test__fixunssfdi(-0x1.FFFFFEp+62, 0x0000000000000000); + test__fixunssfdi(-0x1.FFFFFCp+62, 0x0000000000000000); +} diff --git a/std/special/compiler_rt/fixunssfsi.zig b/std/special/compiler_rt/fixunssfsi.zig new file mode 100644 index 0000000000..88926e93f3 --- /dev/null +++ b/std/special/compiler_rt/fixunssfsi.zig @@ -0,0 +1,9 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunssfsi(a: f32) -> u32 { + return fixuint(f32, u32, a); +} + +test "import fixunssfsi" { + _ = @import("fixunssfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixunssfsi_test.zig b/std/special/compiler_rt/fixunssfsi_test.zig new file mode 100644 index 0000000000..bdb0339335 --- /dev/null +++ b/std/special/compiler_rt/fixunssfsi_test.zig @@ -0,0 +1,36 @@ +const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; +const assert = @import("../../debug.zig").assert; + +fn test__fixunssfsi(a: f32, expected: u32) { + const x = __fixunssfsi(a); + assert(x == expected); +} + +test "fixunssfsi" { + test__fixunssfsi(0.0, 0); + + test__fixunssfsi(0.5, 0); + test__fixunssfsi(0.99, 0); + test__fixunssfsi(1.0, 1); + test__fixunssfsi(1.5, 1); + test__fixunssfsi(1.99, 1); + test__fixunssfsi(2.0, 2); + test__fixunssfsi(2.01, 2); + test__fixunssfsi(-0.5, 0); + test__fixunssfsi(-0.99, 0); + + test__fixunssfsi(-1.0, 0); + test__fixunssfsi(-1.5, 0); + test__fixunssfsi(-1.99, 0); + test__fixunssfsi(-2.0, 0); + test__fixunssfsi(-2.01, 0); + + test__fixunssfsi(0x1.000000p+31, 0x80000000); + test__fixunssfsi(0x1.000000p+32, 0xFFFFFFFF); + test__fixunssfsi(0x1.FFFFFEp+31, 0xFFFFFF00); + test__fixunssfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixunssfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + + test__fixunssfsi(-0x1.FFFFFEp+30, 0); + test__fixunssfsi(-0x1.FFFFFCp+30, 0); +} diff --git a/std/special/compiler_rt/fixunssfti.zig b/std/special/compiler_rt/fixunssfti.zig new file mode 100644 index 0000000000..d5ad7cee5d --- /dev/null +++ b/std/special/compiler_rt/fixunssfti.zig @@ -0,0 +1,10 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunssfti(a: f32) -> u128 { + return fixuint(f32, u128, a); +} + +test "import fixunssfti" { + _ = @import("fixunssfti_test.zig"); +} + diff --git a/std/special/compiler_rt/fixunssfti_test.zig b/std/special/compiler_rt/fixunssfti_test.zig new file mode 100644 index 0000000000..aaa7c70ab7 --- /dev/null +++ b/std/special/compiler_rt/fixunssfti_test.zig @@ -0,0 +1,41 @@ +const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; +const assert = @import("../../debug.zig").assert; + +fn test__fixunssfti(a: f32, expected: u128) { + const x = __fixunssfti(a); + assert(x == expected); +} + +test "fixunssfti" { + test__fixunssfti(0.0, 0); + + test__fixunssfti(0.5, 0); + test__fixunssfti(0.99, 0); + test__fixunssfti(1.0, 1); + test__fixunssfti(1.5, 1); + test__fixunssfti(1.99, 1); + test__fixunssfti(2.0, 2); + test__fixunssfti(2.01, 2); + test__fixunssfti(-0.5, 0); + test__fixunssfti(-0.99, 0); + + test__fixunssfti(-1.0, 0); + test__fixunssfti(-1.5, 0); + test__fixunssfti(-1.99, 0); + test__fixunssfti(-2.0, 0); + test__fixunssfti(-2.01, 0); + + test__fixunssfti(0x1.FFFFFEp+63, 0xFFFFFF0000000000); + test__fixunssfti(0x1.000000p+63, 0x8000000000000000); + test__fixunssfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixunssfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixunssfti(0x1.FFFFFEp+127, 0xFFFFFF00000000000000000000000000); + test__fixunssfti(0x1.000000p+127, 0x80000000000000000000000000000000); + test__fixunssfti(0x1.FFFFFEp+126, 0x7FFFFF80000000000000000000000000); + test__fixunssfti(0x1.FFFFFCp+126, 0x7FFFFF00000000000000000000000000); + + test__fixunssfti(-0x1.FFFFFEp+62, 0x0000000000000000); + test__fixunssfti(-0x1.FFFFFCp+62, 0x0000000000000000); + test__fixunssfti(-0x1.FFFFFEp+126, 0x0000000000000000); + test__fixunssfti(-0x1.FFFFFCp+126, 0x0000000000000000); +} diff --git a/std/special/compiler_rt/fixunstfdi.zig b/std/special/compiler_rt/fixunstfdi.zig new file mode 100644 index 0000000000..1d41da2799 --- /dev/null +++ b/std/special/compiler_rt/fixunstfdi.zig @@ -0,0 +1,9 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunstfdi(a: f128) -> u64 { + return fixuint(f128, u64, a); +} + +test "import fixunstfdi" { + _ = @import("fixunstfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixunstfdi_test.zig b/std/special/compiler_rt/fixunstfdi_test.zig new file mode 100644 index 0000000000..abd964c908 --- /dev/null +++ b/std/special/compiler_rt/fixunstfdi_test.zig @@ -0,0 +1,49 @@ +const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; +const assert = @import("../../debug.zig").assert; + +fn test__fixunstfdi(a: f128, expected: u64) { + const x = __fixunstfdi(a); + assert(x == expected); +} + +test "fixunstfdi" { + test__fixunstfdi(0.0, 0); + + test__fixunstfdi(0.5, 0); + test__fixunstfdi(0.99, 0); + test__fixunstfdi(1.0, 1); + test__fixunstfdi(1.5, 1); + test__fixunstfdi(1.99, 1); + test__fixunstfdi(2.0, 2); + test__fixunstfdi(2.01, 2); + test__fixunstfdi(-0.5, 0); + test__fixunstfdi(-0.99, 0); + test__fixunstfdi(-1.0, 0); + test__fixunstfdi(-1.5, 0); + test__fixunstfdi(-1.99, 0); + test__fixunstfdi(-2.0, 0); + test__fixunstfdi(-2.01, 0); + + test__fixunstfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixunstfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + + test__fixunstfdi(-0x1.FFFFFEp+62, 0); + test__fixunstfdi(-0x1.FFFFFCp+62, 0); + + test__fixunstfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixunstfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + + test__fixunstfdi(-0x1.FFFFFFFFFFFFFp+62, 0); + test__fixunstfdi(-0x1.FFFFFFFFFFFFEp+62, 0); + + test__fixunstfdi(0x1.FFFFFFFFFFFFFFFEp+63, 0xFFFFFFFFFFFFFFFF); + test__fixunstfdi(0x1.0000000000000002p+63, 0x8000000000000001); + test__fixunstfdi(0x1.0000000000000000p+63, 0x8000000000000000); + test__fixunstfdi(0x1.FFFFFFFFFFFFFFFCp+62, 0x7FFFFFFFFFFFFFFF); + test__fixunstfdi(0x1.FFFFFFFFFFFFFFF8p+62, 0x7FFFFFFFFFFFFFFE); + test__fixunstfdi(0x1.p+64, 0xFFFFFFFFFFFFFFFF); + + test__fixunstfdi(-0x1.0000000000000000p+63, 0); + test__fixunstfdi(-0x1.FFFFFFFFFFFFFFFCp+62, 0); + test__fixunstfdi(-0x1.FFFFFFFFFFFFFFF8p+62, 0); +} diff --git a/std/special/compiler_rt/fixunstfsi.zig b/std/special/compiler_rt/fixunstfsi.zig new file mode 100644 index 0000000000..c88de97193 --- /dev/null +++ b/std/special/compiler_rt/fixunstfsi.zig @@ -0,0 +1,9 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunstfsi(a: f128) -> u32 { + return fixuint(f128, u32, a); +} + +test "fixunstfsi" { + _ = @import("fixunstfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixunstfti.zig b/std/special/compiler_rt/fixunstfti.zig new file mode 100644 index 0000000000..269b582ff5 --- /dev/null +++ b/std/special/compiler_rt/fixunstfti.zig @@ -0,0 +1,10 @@ +const fixuint = @import("fixuint.zig").fixuint; + +export fn __fixunstfti(a: f128) -> u128 { + return fixuint(f128, u128, a); +} + +test "fixunstfti" { + _ = @import("fixunstfti_test.zig"); +} + diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index e4fc338e82..c2486a3d59 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -1,6 +1,20 @@ +// Find all the exported functions. +comptime { + _ = @import("fixunsdfdi.zig"); + _ = @import("fixunsdfsi.zig"); + _ = @import("fixunsdfti.zig"); + _ = @import("fixunssfdi.zig"); + _ = @import("fixunssfsi.zig"); + _ = @import("fixunssfti.zig"); + _ = @import("fixunstfdi.zig"); + _ = @import("fixunstfsi.zig"); + _ = @import("fixunstfti.zig"); + _ = @import("udivti3.zig"); + _ = @import("umodti3.zig"); +} + const builtin = @import("builtin"); -const CHAR_BIT = 8; const du_int = u64; const di_int = i64; const si_int = c_int; @@ -23,8 +37,8 @@ fn du_int_to_udwords(x: du_int) -> udwords { export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { @setDebugSafety(this, false); - const n_uword_bits = @sizeOf(su_int) * CHAR_BIT; - const n_udword_bits = @sizeOf(du_int) * CHAR_BIT; + const n_uword_bits = su_int.bit_count; + const n_udword_bits = du_int.bit_count; var n = du_int_to_udwords(a); var d = du_int_to_udwords(b); var q: udwords = undefined; @@ -219,6 +233,7 @@ fn isArmArch() -> bool { builtin.Arch.armv8_2a, builtin.Arch.armv8_1a, builtin.Arch.armv8, + builtin.Arch.armv8r, builtin.Arch.armv8m_baseline, builtin.Arch.armv8m_mainline, builtin.Arch.armv7, @@ -278,7 +293,7 @@ export fn __aeabi_uidiv(n: su_int, d: su_int) -> su_int { export fn __udivsi3(n: su_int, d: su_int) -> su_int { @setDebugSafety(this, false); - const n_uword_bits: c_uint = @sizeOf(su_int) * CHAR_BIT; + const n_uword_bits: c_uint = su_int.bit_count; // special cases if (d == 0) return 0; // ?! diff --git a/std/special/compiler_rt/udivti3.zig b/std/special/compiler_rt/udivti3.zig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/std/special/compiler_rt/umodti3.zig b/std/special/compiler_rt/umodti3.zig new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/cases/math.zig b/test/cases/math.zig index 1de3c12a25..82773f077a 100644 --- a/test/cases/math.zig +++ b/test/cases/math.zig @@ -284,3 +284,29 @@ fn testShrExact(x: u8) { const shifted = @shrExact(x, 2); assert(shifted == 0b00101101); } + +test "big number addition" { + comptime { + assert( + 35361831660712422535336160538497375248 + + 101752735581729509668353361206450473702 == + 137114567242441932203689521744947848950); + assert( + 594491908217841670578297176641415611445982232488944558774612 + + 390603545391089362063884922208143568023166603618446395589768 == + 985095453608931032642182098849559179469148836107390954364380); + } +} + +test "big number multiplication" { + comptime { + assert( + 45960427431263824329884196484953148229 * + 128339149605334697009938835852565949723 == + 5898522172026096622534201617172456926982464453350084962781392314016180490567); + assert( + 594491908217841670578297176641415611445982232488944558774612 * + 390603545391089362063884922208143568023166603618446395589768 == + 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016); + } +}