Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preliminary MSVC int128_t support #71

Merged
merged 6 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
Changes in primecount-7.13, 2024-04-08
Changes in primecount-7.13, 2024-04-09

* Delete ci-sage.yml, it has not been updated in 3 years and I
don't want to maintain it. I feel like this CI script should
be part of SageMath, not primecount.
* Add preliminary MSVC 128-bit support.
* Added AVX512 runtime dispatching for x86 CPUs.
* CMakeLists.txt: New WITH_MULTIARCH option (default ON).
* Sieve_count.cpp: New AVX512 popcount algorithm for x86 CPUs.
* Sieve_count.cpp: New ARM SVE popcount algorithm.
* int128.cmake: Improve int128_t support for Windows.
* OpenMP.cmake: Improve LLVM/Clang OpenMP detection.
* Delete ci-sage.yml, it has not been updated in 3 years and I
don't want to maintain it. I feel like this CI script should
be part of SageMath, not primecount.

Changes in primecount-7.12, 2024-04-01

Expand Down
22 changes: 17 additions & 5 deletions cmake/int128_t.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,27 @@ set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/include")
check_cxx_source_compiles("
#include <int128_t.hpp>
#include <algorithm>

using namespace primecount;

int main() {
using namespace primecount;
int128_t x = int128_t(1) << 100;
int128_t y = 1000;
x /= 123;
if (std::min(x, y) == y)
return 0;
else
unsigned divider = 123;
x = x / divider;
x /= y;
x = x + y;

if (std::min(x, y) != y)
return 1;

long double z = ((long double) y) + 1.59867;
int128_t iz = (int128_t) z;

if (std::max(y, iz) != iz)
return 1;

return 0;
}" int128)

if(NOT int128)
Expand Down
45 changes: 39 additions & 6 deletions include/int128_t.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#define INT128_T_HPP

#include <stdint.h>
#include <string>
#include <limits>
#include <type_traits>

/// If INT128_MAX is defined we know that int128_t and
/// uint128_t are available in <stdint.h>.
Expand All @@ -27,14 +30,15 @@ namespace primecount {

using maxint_t = int128_t ;
using maxuint_t = uint128_t;
using std::to_string;

} // namespace

#elif defined(__SIZEOF_INT128__) && \
!defined(DISABLE_INT128)

#define HAVE_INT128_T
#define HAVE_NON_STANDARD__INT128_T
#define ENABLE_INT128_TO_STRING

#include <ostream>

Expand All @@ -45,8 +49,39 @@ using uint128_t = __uint128_t;
using maxint_t = __int128_t ;
using maxuint_t = __uint128_t;

/// std::cout support for int128_t.
/// These functions are defined in util.cpp.
/// These functions are defined in util.cpp
std::string to_string(int128_t x);
std::string to_string(uint128_t x);

std::ostream& operator<<(std::ostream& stream, int128_t n);
std::ostream& operator<<(std::ostream& stream, uint128_t n);

} // namespace

#elif __has_include(<__msvc_int128.hpp>) && \
!defined(DISABLE_INT128)

#define HAVE_INT128_T
#define ENABLE_INT128_TO_STRING

// Unofficial/undocumented MSVC int128_t support:
// https://github.com/microsoft/STL/blob/main/stl/inc/__msvc_int128.hpp
// https://developercommunity.visualstudio.com/t/support-for-128-bit-integer-type/879048
// https://stackoverflow.com/a/76440171
#include <__msvc_int128.hpp>
#include <ostream>

namespace primecount {

using int128_t = std::_Signed128;
using uint128_t = std::_Unsigned128;
using maxint_t = std::_Signed128;
using maxuint_t = std::_Unsigned128;

/// These functions are defined in util.cpp
std::string to_string(int128_t x);
std::string to_string(uint128_t x);

std::ostream& operator<<(std::ostream& stream, int128_t n);
std::ostream& operator<<(std::ostream& stream, uint128_t n);

Expand All @@ -58,14 +93,12 @@ namespace primecount {

typedef int64_t maxint_t;
typedef uint64_t maxuint_t;
using std::to_string;

} // namespace

#endif

#include <limits>
#include <type_traits>

// Portable C++ type traits that support int128_t and uint128_t.
// This is required for GCC/Clang if the user compiles with -std=c++*
// instead of -std=gnu++* and also for LLVM/Clang on Windows.
Expand Down
37 changes: 0 additions & 37 deletions include/to_string.hpp

This file was deleted.

3 changes: 1 addition & 2 deletions src/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
#include <macros.hpp>
#include <PiTable.hpp>
#include <print.hpp>
#include <to_string.hpp>

#include <cmath>
#include <string>
Expand Down Expand Up @@ -189,7 +188,7 @@ maxint_t get_max_x(double alpha_y)
{
#ifdef HAVE_INT128_T
double max_x = std::pow((1ull << 62) * alpha_y, 3.0 / 2.0);
return (int128_t) max_x;
return (int128_t) max_x;
#else
unused_param(alpha_y);
return port::numeric_limits<int64_t>::max();
Expand Down
1 change: 0 additions & 1 deletion src/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
#include <PhiTiny.hpp>
#include <print.hpp>
#include <S.hpp>
#include <to_string.hpp>

#include <stdint.h>
#include <exception>
Expand Down
3 changes: 1 addition & 2 deletions src/deleglise-rivat/pi_deleglise_rivat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/// method, Revista do DETUA, vol. 4, no. 6, March 2006,
/// pp. 759-768.
///
/// Copyright (C) 2022 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -27,7 +27,6 @@
#include <macros.hpp>
#include <print.hpp>
#include <S.hpp>
#include <to_string.hpp>

#include <stdint.h>
#include <string>
Expand Down
3 changes: 1 addition & 2 deletions src/gourdon/pi_gourdon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/// Xavier Gourdon formula:
/// pi(x) = A - B + C + D + Phi0 + Sigma
///
/// Copyright (C) 2022 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -22,7 +22,6 @@
#include <macros.hpp>
#include <PhiTiny.hpp>
#include <print.hpp>
#include <to_string.hpp>

#include <stdint.h>
#include <algorithm>
Expand Down
5 changes: 2 additions & 3 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// This file contains helper functions and global variables
/// that are initialized with default settings.
///
/// Copyright (C) 2022 Kim Walisch, <[email protected]>
/// Copyright (C) 2024 Kim Walisch, <[email protected]>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
Expand All @@ -15,7 +15,6 @@
#include <int128_t.hpp>
#include <imath.hpp>
#include <macros.hpp>
#include <to_string.hpp>

#include <algorithm>
#include <chrono>
Expand Down Expand Up @@ -60,7 +59,7 @@ namespace primecount {
/// standard int128_t type is missing in <stdint.h>. We need to
/// define a few functions that are not supported by the C++ STL.
///
#if defined(HAVE_NON_STANDARD__INT128_T)
#if defined(ENABLE_INT128_TO_STRING)

std::string to_string(uint128_t n)
{
Expand Down
10 changes: 8 additions & 2 deletions test/fast_div.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ int main()
std::uniform_int_distribution<int32_t> dist_i32(1, port::numeric_limits<int32_t>::max());
std::uniform_int_distribution<uint64_t> dist_u64(0, port::numeric_limits<uint64_t>::max());

// Test unsigned/signed
for (int i = 0; i < 10000; i++)
{
uint64_t x = dist_i32(gen);
Expand All @@ -52,18 +53,23 @@ int main()

#ifdef HAVE_INT128_T

std::uniform_int_distribution<int128_t> dist_i128(0, port::numeric_limits<int128_t>::max());
std::uniform_int_distribution<uint64_t> dist_u62(0, uint64_t(1ull << 62));

// Test signed/signed
for (int i = 0; i < 10000; i++)
{
// Test x < 2^64
int128_t x = dist_u64(gen);
int32_t y = dist_i32(gen);
int128_t res = fast_div(x, y);

std::cout << "fast_div(" << x << ", " << y << ") = " << res;
check(res == x / y);

x = dist_i128(gen);
// Test x > 2^64
int128_t low = dist_u64(gen);
int128_t high = int128_t(dist_u62(gen)) << 64;
x = high | low;
y = dist_i32(gen);
res = fast_div(x, y);

Expand Down