12#if defined(__x86_64__) || defined(_M_X64)
16#if defined(__ARM_NEON) || defined(__ARM_NEON__)
27 std::span<const VertexId> b) {
28 std::size_t i = 0, j = 0, count = 0;
29 while (i < a.size() && j < b.size()) {
34 }
else if (a[i] < b[j]) {
44 std::span<const VertexId> larger) {
45 std::size_t count = 0;
46 for (
const auto value : smaller) {
47 count += std::binary_search(larger.begin(), larger.end(), value) ? 1u : 0u;
53 std::span<const VertexId> b) {
54 if (a.empty() || b.empty())
return 0;
55 const auto max_value = std::max(a.back(), b.back());
56 const std::size_t word_count =
static_cast<std::size_t
>(max_value) / 64u + 1u;
57 std::vector<std::uint64_t>
bitmap(word_count, 0);
58 for (
const auto value : a) {
59 bitmap[value >> 6u] |= (std::uint64_t{1} << (value & 63u));
61 std::size_t count = 0;
62 for (
const auto value : b) {
63 count += (
bitmap[value >> 6u] >> (value & 63u)) & 1u;
68#if (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(_M_X64))
69__attribute__((target(
"avx2"))) inline std::
size_t avx2_intersection_impl(
71 constexpr std::size_t lanes = 8;
72 std::size_t i = 0, j = 0, count = 0;
74 while (i + lanes <= a.size() && j + lanes <= b.size()) {
75 const auto vb = _mm256_loadu_si256(
reinterpret_cast<const __m256i*
>(b.data() + j));
76 std::uint32_t matched_mask = 0;
77 for (std::size_t lane = 0; lane < lanes; ++lane) {
78 const auto va = _mm256_set1_epi32(
static_cast<int>(a[i + lane]));
79 const auto eq = _mm256_cmpeq_epi32(va, vb);
80 const auto mask =
static_cast<unsigned>(_mm256_movemask_ps(_mm256_castsi256_ps(eq)));
81 if (mask != 0) matched_mask |=
static_cast<std::uint32_t
>(1u << lane);
83 count += std::popcount(matched_mask);
84 const auto a_last = a[i + lanes - 1];
85 const auto b_last = b[j + lanes - 1];
86 if (a_last <= b_last) i += lanes;
87 if (b_last <= a_last) j += lanes;
93__attribute__((target(
"avx512f"))) inline std::
size_t avx512_intersection_impl(
95 constexpr std::size_t lanes = 16;
96 std::size_t i = 0, j = 0, count = 0;
98 while (i + lanes <= a.size() && j + lanes <= b.size()) {
99 const auto vb = _mm512_loadu_si512(
reinterpret_cast<const void*
>(b.data() + j));
100 std::uint32_t matched_mask = 0;
101 for (std::size_t lane = 0; lane < lanes; ++lane) {
102 const auto va = _mm512_set1_epi32(
static_cast<int>(a[i + lane]));
103 if (_mm512_cmpeq_epu32_mask(va, vb) != 0) {
104 matched_mask |=
static_cast<std::uint32_t
>(1u << lane);
107 count += std::popcount(matched_mask);
108 const auto a_last = a[i + lanes - 1];
109 const auto b_last = b[j + lanes - 1];
110 if (a_last <= b_last) i += lanes;
111 if (b_last <= a_last) j += lanes;
119 std::span<const VertexId> b) {
120#if (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(_M_X64))
127 std::span<const VertexId> b) {
128#if (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(_M_X64))
135 std::span<const VertexId> b) {
136#if defined(__ARM_NEON) || defined(__ARM_NEON__)
137 constexpr std::size_t lanes = 4;
138 std::size_t i = 0, j = 0, count = 0;
139 while (i + lanes <= a.size() && j + lanes <= b.size()) {
140 const auto vb = vld1q_u32(b.data() + j);
141 for (std::size_t lane = 0; lane < lanes; ++lane) {
142 const auto va = vdupq_n_u32(a[i + lane]);
143 const auto eq = vceqq_u32(va, vb);
144 const auto pair = vpaddq_u32(eq, eq);
145 const auto reduced = vpaddq_u32(pair, pair);
146 if (vgetq_lane_u32(reduced, 0) != 0) ++count;
148 const auto a_last = a[i + lanes - 1];
149 const auto b_last = b[j + lanes - 1];
150 if (a_last <= b_last) i += lanes;
151 if (b_last <= a_last) j += lanes;
161 std::span<const VertexId> b) {
162 if (a.empty() || b.empty())
return false;
163 const auto max_value = std::max(a.back(), b.back());
164 const auto combined = a.size() + b.size();
165 return combined >= 1024 &&
static_cast<std::size_t
>(max_value) <= combined * 8u;
169 std::span<const VertexId> b) {
170 const auto min_size = std::min(a.size(), b.size());
171 const auto max_size = std::max(a.size(), b.size());
184 std::span<const VertexId> b) {
std::size_t avx512_intersection(std::span< const VertexId > a, std::span< const VertexId > b)
std::size_t galloping_intersection(std::span< const VertexId > smaller, std::span< const VertexId > larger)
std::size_t adaptive_intersection(std::span< const VertexId > a, std::span< const VertexId > b)
std::size_t neon_intersection(std::span< const VertexId > a, std::span< const VertexId > b)
CpuFeatures detect_cpu_features()
std::size_t avx2_intersection(std::span< const VertexId > a, std::span< const VertexId > b)
bool bitmap_is_efficient(std::span< const VertexId > a, std::span< const VertexId > b)
IntersectionKernel select_intersection(std::span< const VertexId > a, std::span< const VertexId > b)
std::size_t bitmap_intersection(std::span< const VertexId > a, std::span< const VertexId > b)
std::size_t scalar_intersection(std::span< const VertexId > a, std::span< const VertexId > b)