From a9e0fdebea130c0e90641156fefb9c8d4aa9d109 Mon Sep 17 00:00:00 2001 From: Craig Gidney Date: Sat, 18 Nov 2023 16:21:13 -0800 Subject: [PATCH] Bump targeted C++ standard to C++20 (#659) - Replace bit twiddly `popcount64` with `std::popcount` --- .github/workflows/ci.yml | 4 ++-- BUILD | 10 +++++----- CMakeLists.txt | 2 +- doc/developer_documentation.md | 4 ++-- glue/javascript/build_wasm.sh | 2 +- setup.py | 4 ++-- src/stim/mem/bitword_128_sse.h | 3 ++- src/stim/mem/bitword_256_avx.h | 5 +++-- src/stim/mem/bitword_64.h | 3 ++- src/stim/mem/simd_bits_range_ref.inl | 2 +- src/stim/mem/simd_util.h | 10 ---------- src/stim/mem/simd_util.test.cc | 17 ----------------- src/stim/probability_util.test.cc | 2 +- src/stim/simulators/error_analyzer.cc | 2 +- src/stim/simulators/vector_simulator.h | 2 +- src/stim/stabilizers/pauli_string.pybind.cc | 8 ++++---- 16 files changed, 28 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 331fa3b1d..d62a3408a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -242,7 +242,7 @@ jobs: - run: cmake . - run: make libstim -j 2 - run: echo -e '#include "stim.h"\nint main(int argc,const char **argv) {return !stim::find_bool_argument("test", argc, argv);}' > test.cc - - run: g++ -std=c++17 test.cc out/libstim.a -I src + - run: g++ -std=c++20 test.cc out/libstim.a -I src - run: ./a.out test build_lib_install: runs-on: ubuntu-latest @@ -253,7 +253,7 @@ jobs: - run: make -j 2 - run: make install - run: echo -e '#include "stim.h"\nint main(int argc,const char **argv) {return !stim::find_bool_argument("test", argc, argv);}' > test.cc - - run: g++ -std=c++17 test.cc install_dir/lib/libstim.a -I install_dir/include + - run: g++ -std=c++20 test.cc install_dir/lib/libstim.a -I install_dir/include - run: ./a.out test - run: echo -e "H 0 \n CNOT 0 1 \n M 0 1" | install_dir/bin/stim --sample benchmark_windows: diff --git a/BUILD b/BUILD index 6d0d74a76..3ba201c5e 100644 --- a/BUILD +++ b/BUILD @@ -44,7 +44,7 @@ cc_library( name = "stim_lib", srcs = SOURCE_FILES_NO_MAIN, copts = [ - "-std=c++17", + "-std=c++20", ], includes = ["src/"], ) @@ -53,7 +53,7 @@ cc_binary( name = "stim", srcs = SOURCE_FILES_NO_MAIN + glob(["src/**/main.cc"]), copts = [ - "-std=c++17", + "-std=c++20", "-march=native", "-O3", ], @@ -64,7 +64,7 @@ cc_binary( name = "stim_benchmark", srcs = SOURCE_FILES_NO_MAIN + PERF_FILES, copts = [ - "-std=c++17", + "-std=c++20", "-march=native", "-O3", ], @@ -75,7 +75,7 @@ cc_test( name = "stim_test", srcs = SOURCE_FILES_NO_MAIN + TEST_FILES, copts = [ - "-std=c++17", + "-std=c++20", "-march=native", ], data = glob(["testdata/**"]), @@ -91,7 +91,7 @@ cc_binary( srcs = SOURCE_FILES_NO_MAIN + PYBIND_FILES, copts = [ "-O3", - "-std=c++17", + "-std=c++20", "-fvisibility=hidden", "-march=native", "-DSTIM_PYBIND11_MODULE_NAME=stim", diff --git a/CMakeLists.txt b/CMakeLists.txt index 8bf003948..32d274d61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.13) project(stim) include_directories(src) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY out) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY out) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY out) diff --git a/doc/developer_documentation.md b/doc/developer_documentation.md index 89e58acf2..859a1f689 100644 --- a/doc/developer_documentation.md +++ b/doc/developer_documentation.md @@ -166,7 +166,7 @@ bazel run stim find src \ | grep "\\.cc$" \ | grep -v "\\.\(test\|perf\|pybind\)\\.cc$" \ - | xargs g++ -I src -pthread -std=c++17 -O3 -march=native + | xargs g++ -I src -pthread -std=c++20 -O3 -march=native # output binary ends up at: # ./a.out @@ -387,7 +387,7 @@ Ending a filter with a `*` turns it into a prefix filter `--only=sim_*`. find src \ | grep "\\.cc" \ | grep -v "\\.\(test\|perf\|pybind\)\\.cc" \ - | xargs g++ -I src -pthread -std=c++17 -O3 -march=native -g -fno-omit-frame-pointer + | xargs g++ -I src -pthread -std=c++20 -O3 -march=native -g -fno-omit-frame-pointer sudo perf record -g ./a.out # [ADD STIM FLAGS FOR THE CASE YOU WANT TO PROFILE] sudo perf report ``` diff --git a/glue/javascript/build_wasm.sh b/glue/javascript/build_wasm.sh index 569a9c69f..893b51ebe 100755 --- a/glue/javascript/build_wasm.sh +++ b/glue/javascript/build_wasm.sh @@ -29,7 +29,7 @@ echo '' >> out/all_stim_tests.html # Build web assembly module using emscripten. emcc \ - -std=c++17 \ + -std=c++20 \ -s NO_DISABLE_EXCEPTION_CATCHING \ -s EXPORT_NAME="load_stim_module" \ -s MODULARIZE=1 \ diff --git a/setup.py b/setup.py index 9ceecf70b..f0c62f873 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ if sys.platform.startswith('win'): common_compile_args = [ - '/std:c++17', + '/std:c++20', '/O2', f'/DVERSION_INFO={__version__}', ] @@ -38,7 +38,7 @@ arch_basic = [] else: common_compile_args = [ - '-std=c++17', + '-std=c++20', '-fno-strict-aliasing', '-O3', '-g0', diff --git a/src/stim/mem/bitword_128_sse.h b/src/stim/mem/bitword_128_sse.h index 3164784ca..b377e690b 100644 --- a/src/stim/mem/bitword_128_sse.h +++ b/src/stim/mem/bitword_128_sse.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -140,7 +141,7 @@ struct bitword<128> { } inline uint16_t popcount() const { - return popcnt64(u64[0]) + popcnt64(u64[1]); + return std::popcount(u64[0]) + std::popcount(u64[1]); } inline bitword<128> shifted(int offset) const { diff --git a/src/stim/mem/bitword_256_avx.h b/src/stim/mem/bitword_256_avx.h index fca2fe226..b5d5591d7 100644 --- a/src/stim/mem/bitword_256_avx.h +++ b/src/stim/mem/bitword_256_avx.h @@ -19,6 +19,7 @@ #if __AVX2__ #include +#include #include #include #include @@ -139,8 +140,8 @@ struct bitword<256> { } inline uint16_t popcount() const { - return stim::popcnt64(u64[0]) + stim::popcnt64(u64[1]) + stim::popcnt64(u64[2]) + - (uint16_t)stim::popcnt64(u64[3]); + return std::popcount(u64[0]) + std::popcount(u64[1]) + std::popcount(u64[2]) + + (uint16_t)std::popcount(u64[3]); } inline bitword<256> shifted(int offset) const { diff --git a/src/stim/mem/bitword_64.h b/src/stim/mem/bitword_64.h index 50f537396..08a007662 100644 --- a/src/stim/mem/bitword_64.h +++ b/src/stim/mem/bitword_64.h @@ -18,6 +18,7 @@ #define _STIM_MEM_SIMD_WORD_64_STD_H #include +#include #include #include @@ -109,7 +110,7 @@ struct bitword<64> { } inline uint16_t popcount() const { - return popcnt64(u64[0]); + return std::popcount(u64[0]); } inline std::string str() const { diff --git a/src/stim/mem/simd_bits_range_ref.inl b/src/stim/mem/simd_bits_range_ref.inl index d6135a005..29b74f8d2 100644 --- a/src/stim/mem/simd_bits_range_ref.inl +++ b/src/stim/mem/simd_bits_range_ref.inl @@ -216,7 +216,7 @@ size_t simd_bits_range_ref::popcnt() const { auto end = u64 + num_u64_padded(); size_t result = 0; for (const uint64_t *p = u64; p != end; p++) { - result += popcnt64(*p); + result += std::popcount(*p); } return result; } diff --git a/src/stim/mem/simd_util.h b/src/stim/mem/simd_util.h index c725ada9e..b44be6aad 100644 --- a/src/stim/mem/simd_util.h +++ b/src/stim/mem/simd_util.h @@ -37,16 +37,6 @@ inline uint64_t spread_bytes_32_to_64(uint32_t v) { void inplace_transpose_64x64(uint64_t *data, size_t stride); -inline uint8_t popcnt64(uint64_t val) { - val -= (val >> 1) & 0x5555555555555555ULL; - val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); - val += val >> 4; - val &= 0xF0F0F0F0F0F0F0FULL; - val *= 0x101010101010101ULL; - val >>= 56; - return (uint8_t)val; -} - } // namespace stim #endif diff --git a/src/stim/mem/simd_util.test.cc b/src/stim/mem/simd_util.test.cc index 1411fc6e6..9df079ba6 100644 --- a/src/stim/mem/simd_util.test.cc +++ b/src/stim/mem/simd_util.test.cc @@ -426,20 +426,3 @@ TEST(simd_util, interleave_mask) { ASSERT_EQ(interleave_mask(16), 0x0000FFFF0000FFFFULL); ASSERT_EQ(interleave_mask(32), 0x00000000FFFFFFFFULL); } - -TEST(simd_util, popcnt64) { - for (size_t expected = 0; expected <= 64; expected++) { - std::vector bits{}; - for (size_t i = 0; i < 64; i++) { - bits.push_back(i < expected); - } - for (size_t reps = 0; reps < 100; reps++) { - std::shuffle(bits.begin(), bits.end(), INDEPENDENT_TEST_RNG()); - uint64_t v = 0; - for (size_t i = 0; i < 64; i++) { - v |= bits[i] << i; - } - ASSERT_EQ(popcnt64(v), expected); - } - } -} diff --git a/src/stim/probability_util.test.cc b/src/stim/probability_util.test.cc index 6d455b4aa..ca1a9a8cf 100644 --- a/src/stim/probability_util.test.cc +++ b/src/stim/probability_util.test.cc @@ -58,7 +58,7 @@ TEST_EACH_WORD_SIZE_W(probability_util, biased_random, { biased_randomize_bits(p, data.u64, data.u64 + data.num_u64_padded(), rng); size_t t = 0; for (size_t k = 0; k < data.num_u64_padded(); k++) { - t += popcnt64(data.u64[k]); + t += std::popcount(data.u64[k]); } float dev = sqrtf(p * (1 - p) * n); float min_expected = n * p - dev * 5; diff --git a/src/stim/simulators/error_analyzer.cc b/src/stim/simulators/error_analyzer.cc index 8b8b4a1a6..fb89c458b 100644 --- a/src/stim/simulators/error_analyzer.cc +++ b/src/stim/simulators/error_analyzer.cc @@ -1160,7 +1160,7 @@ void ErrorAnalyzer::decompose_helper_add_error_combinations( // Count number of detectors affected by each error. std::array detector_counts{}; for (size_t k = 1; k < 1 << s; k++) { - detector_counts[k] = popcnt64(detector_masks[k]); + detector_counts[k] = std::popcount(detector_masks[k]); } // Find single-detector errors (and empty errors). diff --git a/src/stim/simulators/vector_simulator.h b/src/stim/simulators/vector_simulator.h index 36a5c84bb..56a1649b3 100644 --- a/src/stim/simulators/vector_simulator.h +++ b/src/stim/simulators/vector_simulator.h @@ -151,7 +151,7 @@ struct VectorSimulator { float mag2 = 0; for (size_t i = 0; i < state.size(); i++) { bool reject = observable.sign; - reject ^= (popcnt64(i & mask) & 1) != 0; + reject ^= (std::popcount(i & mask) & 1) != 0; if (reject) { state[i] = 0; } else { diff --git a/src/stim/stabilizers/pauli_string.pybind.cc b/src/stim/stabilizers/pauli_string.pybind.cc index fa1b68b54..1283fc1b7 100644 --- a/src/stim/stabilizers/pauli_string.pybind.cc +++ b/src/stim/stabilizers/pauli_string.pybind.cc @@ -65,7 +65,7 @@ pybind11::object PyPauliString::to_unitary_matrix(const std::string &endian) con } } uint8_t start_phase = 0; - start_phase += popcnt64(x & z); + start_phase += std::popcount(x & z); if (imag) { start_phase += 1; } @@ -75,7 +75,7 @@ pybind11::object PyPauliString::to_unitary_matrix(const std::string &endian) con for (size_t col = 0; col < n; col++) { size_t row = col ^ x; uint8_t phase = start_phase; - if (popcnt64(col & z) & 1) { + if (std::popcount(col & z) & 1) { phase += 2; } std::complex v{1, 0}; @@ -433,7 +433,7 @@ PyPauliString PyPauliString::from_unitary_matrix( } for (size_t k = 0; k < n; k++) { uint8_t expected_phase = phases[0]; - if (popcnt64(k & z) & 1) { + if (std::popcount(k & z) & 1) { expected_phase += 2; } if ((expected_phase & 3) != phases[k]) { @@ -442,7 +442,7 @@ PyPauliString PyPauliString::from_unitary_matrix( } } - uint8_t leftover_phase = phases[0] + popcnt64(x & z); + uint8_t leftover_phase = phases[0] + std::popcount(x & z); PyPauliString result(PauliString(q), (leftover_phase & 1) != 0); result.value.sign = (leftover_phase & 2) != 0; auto &rx = result.value.xs.u64[0];