// File: /workspace/github_cpp_makefile_star2_O1/ralgond[P]SortedListIntersection/algo_highlyscalable_SIMD.cpp
// Function: lemire_highlyscalable_SIMD_intersection(unsigned int const*, unsigned long, unsigned int const*, unsigned long, unsigned int*)
size_t lemire_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;
  const static uint32_t cyclic_shift1 = _MM_SHUFFLE(0, 3, 2, 1);
  const static uint32_t cyclic_shift2 = _MM_SHUFFLE(1, 0, 3, 2);
  const static uint32_t cyclic_shift3 = _MM_SHUFFLE(2, 1, 0, 3);

  // trim lengths to be a multiple of 4
  size_t st_a = (s_a / 4) * 4;
  size_t st_b = (s_b / 4) * 4;
  if (i_a < st_a && i_b < st_b) {
    __m128i v_a, v_b;
    v_a = MM_LOAD_SI_128((__m128i *)&A[i_a]);
    v_b = MM_LOAD_SI_128((__m128i *)&B[i_b]);
    while (true) {
      const __m128i cmp_mask1 =
          _mm_cmpeq_epi32(v_a, v_b); // pairwise comparison
      const __m128i cmp_mask2 = _mm_cmpeq_epi32(
          v_a, _mm_shuffle_epi32(v_b, cyclic_shift1)); // again...
      __m128i cmp_mask = _mm_or_si128(cmp_mask1, cmp_mask2);
      const __m128i cmp_mask3 = _mm_cmpeq_epi32(
          v_a, _mm_shuffle_epi32(v_b, cyclic_shift2)); // and again...
      cmp_mask = _mm_or_si128(cmp_mask, cmp_mask3);
      const __m128i cmp_mask4 = _mm_cmpeq_epi32(
          v_a, _mm_shuffle_epi32(v_b, cyclic_shift3)); // and again.
      cmp_mask = _mm_or_si128(cmp_mask, cmp_mask4);
      // convert the 128-bit mask to the 4-bit mask
      const int mask = _mm_movemask_ps(*reinterpret_cast<__m128 *>(&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

      const uint32_t a_max = A[i_a + 3];
      if (a_max <= B[i_b + 3]) {
        i_a += 4;
        if (i_a >= st_a)
          break;
        v_a = MM_LOAD_SI_128((__m128i *)&A[i_a]);
      }
      if (a_max >= B[i_b + 3]) {
        i_b += 4;
        if (i_b >= st_b)
          break;
        v_b = MM_LOAD_SI_128((__m128i *)&B[i_b]);
      }
    }
  }

  // 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 %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
cmpq %rdi, %r8
je 0x3f7e
cmpq %rdx, %r8
je 0x3f9d
movq %rsi, %r11
andq $-0x4, %r11
sete %al
movq %rcx, %rbx
andq $-0x4, %rbx
sete %r9b
orb %al, %r9b
movq %r8, (%rsp)
je 0x3e5b
xorl %r9d, %r9d
xorl %r10d, %r10d
movq %r8, %rax
jmp 0x3f20
vmovdqu (%rdi), %xmm0
vmovdqu (%rdx), %xmm1
xorl %r9d, %r9d
leaq 0x2523(%rip), %r10      # 0x6390
xorl %r12d, %r12d
movq %r8, %rax
movq %r10, %r8
vpcmpeqd %xmm0, %xmm1, %k0
vpshufd $0x39, %xmm1, %xmm2     # xmm2 = xmm1[1,2,3,0]
vpcmpeqd %xmm0, %xmm2, %k1
korw %k1, %k0, %k0
vpshufd $0x4e, %xmm1, %xmm2     # xmm2 = xmm1[2,3,0,1]
vpcmpeqd %xmm0, %xmm2, %k1
korw %k1, %k0, %k0
vpshufd $0x93, %xmm1, %xmm2     # xmm2 = xmm1[3,0,1,2]
vpcmpeqd %xmm0, %xmm2, %k1
korw %k1, %k0, %k0
kmovd %k0, %ebp
andl $0xf, %ebp
movl %ebp, %r10d
shll $0x4, %r10d
vpshufb (%r10,%r8), %xmm0, %xmm2
vmovdqu %xmm2, (%rax)
movl 0xc(%rdi,%r12,4), %r13d
movl 0xc(%rdx,%r9,4), %r14d
cmpl %r14d, %r13d
jbe 0x3ed5
movq %r12, %r10
jmp 0x3ee6
leaq 0x4(%r12), %r10
cmpq %r11, %r10
jae 0x3f00
vmovdqu 0x10(%rdi,%r12,4), %xmm0
movb $0x1, %r15b
cmpl %r14d, %r13d
jb 0x3f0b
leaq 0x4(%r9), %r14
cmpq %rbx, %r14
jae 0x3f05
vmovdqu 0x10(%rdx,%r9,4), %xmm1
jmp 0x3f08
xorl %r15d, %r15d
jmp 0x3f0b
xorl %r15d, %r15d
movq %r14, %r9
popcntl %ebp, %r14d
leaq (%rax,%r14,4), %rax
movq %r10, %r12
testb %r15b, %r15b
jne 0x3e76
cmpq %rsi, %r10
setae %r8b
cmpq %rcx, %r9
setae %r11b
orb %r8b, %r11b
jne 0x3f64
movq (%rsp), %rbx
movl (%rdi,%r10,4), %r11d
movl (%rdx,%r9,4), %r8d
cmpl %r8d, %r11d
jae 0x3f49
incq %r10
jmp 0x3f58
ja 0x3f55
movl %r8d, (%rax)
addq $0x4, %rax
incq %r10
incq %r9
cmpq %rsi, %r10
jae 0x3f68
cmpq %rcx, %r9
jb 0x3f37
jmp 0x3f68
movq (%rsp), %rbx
subq %rbx, %rax
sarq $0x2, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x250b(%rip), %rdi      # 0x6490
leaq 0x250d(%rip), %rsi      # 0x6499
leaq 0x25a0(%rip), %rcx      # 0x6533
movl $0x67, %edx
callq 0x20b0
leaq 0x2586(%rip), %rdi      # 0x652a
leaq 0x24ee(%rip), %rsi      # 0x6499
leaq 0x2581(%rip), %rcx      # 0x6533
movl $0x68, %edx
callq 0x20b0