// File: /workspace/github_cpp_makefile_star2_O2/ralgond[P]SortedListIntersection/algo_highlyscalable_SIMD.cpp
// Function: highlyscalable_SIMD_intersection(unsigned int const*, unsigned long, unsigned int const*, unsigned long, unsigned int*)
size_t highlyscalable_SIMD_intersection(const uint32_t *A, const size_t s_a,
                                     const uint32_t *B, const size_t s_b,
                                     uint32_t *out) {
  assert(out != A);
  assert(out != B);
  const uint32_t *const initout(out);
  size_t i_a = 0, i_b = 0;

  // trim lengths to be a multiple of 4
  size_t st_a = (s_a / 4) * 4;
  size_t st_b = (s_b / 4) * 4;

  while (i_a < st_a && i_b < st_b) {
    //[ load segments of four 32-bit elements
    __m128i v_a = _mm_loadu_si128((__m128i *)&A[i_a]);
    __m128i v_b = _mm_loadu_si128((__m128i *)&B[i_b]);
    //]

    //[ move pointers
    const uint32_t a_max = A[i_a + 3];
    const uint32_t b_max = B[i_b + 3];
    i_a += (a_max <= b_max) * 4;
    i_b += (a_max >= b_max) * 4;
    //]

    //[ compute mask of common elements
    const uint32_t cyclic_shift = _MM_SHUFFLE(0, 3, 2, 1);
    __m128i cmp_mask1 = _mm_cmpeq_epi32(v_a, v_b); // pairwise comparison
    v_b = _mm_shuffle_epi32(v_b, cyclic_shift);    // shuffling
    __m128i cmp_mask2 = _mm_cmpeq_epi32(v_a, v_b); // again...
    v_b = _mm_shuffle_epi32(v_b, cyclic_shift);
    __m128i cmp_mask3 = _mm_cmpeq_epi32(v_a, v_b); // and again...
    v_b = _mm_shuffle_epi32(v_b, cyclic_shift);
    __m128i cmp_mask4 = _mm_cmpeq_epi32(v_a, v_b); // and again.
    __m128i cmp_mask = _mm_or_si128(
        _mm_or_si128(cmp_mask1, cmp_mask2),
        _mm_or_si128(cmp_mask3, cmp_mask4)); // OR-ing of comparison masks
    // convert the 128-bit mask to the 4-bit mask
    const int mask = _mm_movemask_ps(_mm_castsi128_ps(cmp_mask));
    //]

    //[ copy out common elements
    const __m128i p = _mm_shuffle_epi8(v_a, shuffle_mask[mask]);
    _mm_storeu_si128((__m128i *)out, p);
    out += _mm_popcnt_u32(mask); // a number of elements is a weight of the mask
                                 //]
  }

  // intersect the tail using scalar intersection
  while (i_a < s_a && i_b < s_b) {
    if (A[i_a] < B[i_b]) {
      i_a++;
    } else if (B[i_b] < A[i_a]) {
      i_b++;
    } else {
      *out++ = B[i_b];
      ;
      i_a++;
      i_b++;
    }
  }

  return out - initout;
}

// Assembly:
pushq %r14
pushq %rbx
pushq %rax
cmpq %rdi, %r8
je 0x3a89
cmpq %rdx, %r8
je 0x3aa2
vpmovsxbd 0x2a5d(%rip), %xmm1 # 0x63d8
vpbroadcastq 0x2a4c(%rip), %xmm2 # 0x63d0
movq %rsi, %r11
movq %rcx, %rbx
andq $-0x4, %r11
andq $-0x4, %rbx
vpxor %xmm0, %xmm0, %xmm0
leaq 0x2a43(%rip), %r14      # 0x63e0
movq %r8, %rax
vpextrq $0x1, %xmm0, %r9
vmovq %xmm0, %r10
cmpq %r11, %r9
jae 0x3a75
cmpq %rbx, %r10
jae 0x3a75
vpbroadcastq 0x8(%rdi,%r9,4), %xmm6
vpbroadcastq 0x8(%rdx,%r10,4), %xmm5
vmovdqu (%rdx,%r10,4), %xmm4
vmovdqu (%rdi,%r9,4), %xmm3
vmovdqa %xmm6, %xmm7
vpermt2d %xmm5, %xmm1, %xmm7
vpermt2d %xmm6, %xmm1, %xmm5
vpcmpeqd %xmm3, %xmm4, %k0
vpcmpnltud %xmm5, %xmm7, %k1
vpshufd $0x39, %xmm4, %xmm5     # xmm5 = xmm4[1,2,3,0]
vpaddq %xmm2, %xmm0, %xmm0 {%k1}
vpcmpeqd %xmm3, %xmm5, %k1
vpshufd $0x4e, %xmm4, %xmm5     # xmm5 = xmm4[2,3,0,1]
vpshufd $0x93, %xmm4, %xmm4     # xmm4 = xmm4[3,0,1,2]
vpcmpeqd %xmm3, %xmm5, %k2
korw %k0, %k1, %k0
vpcmpeqd %xmm3, %xmm4, %k3
korw %k2, %k0, %k0
korw %k3, %k0, %k0
kmovd %k0, %r9d
andl $0xf, %r9d
popcntl %r9d, %r10d
shll $0x4, %r9d
vpshufb (%r9,%r14), %xmm3, %xmm3
vmovdqu %xmm3, (%rax)
leaq (%rax,%r10,4), %rax
jmp 0x39a0
cmpq %rcx, %r10
jae 0x3a7a
movl (%rdi,%r9,4), %ebx
movl (%rdx,%r10,4), %r11d
cmpl %r11d, %ebx
jae 0x3a62
incq %r9
jmp 0x3a75
jbe 0x3a69
incq %r10
jmp 0x3a75
movl %r11d, (%rax)
addq $0x4, %rax
incq %r9
jmp 0x3a64
cmpq %rsi, %r9
jb 0x3a4b
subq %r8, %rax
sarq $0x2, %rax
addq $0x8, %rsp
popq %rbx
popq %r14
retq
leaq 0x2a50(%rip), %rdi      # 0x64e0
leaq 0x2a52(%rip), %rsi      # 0x64e9
leaq 0x2a68(%rip), %rcx      # 0x6506
pushq $0x1d
jmp 0x3ab9
leaq 0x2ad1(%rip), %rdi      # 0x657a
leaq 0x2a39(%rip), %rsi      # 0x64e9
leaq 0x2a4f(%rip), %rcx      # 0x6506
pushq $0x1e
popq %rdx
callq 0x20f0