// File: /workspace/github_cpp_makefile_star2_O2/ralgond[P]SortedListIntersection/algo_highlyscalable_avx2.cpp
// Function: highlyscalable_avx2_intersection(unsigned int const*, unsigned long, unsigned int const*, unsigned long, unsigned int*)
size_t highlyscalable_avx2_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 8
  size_t st_a = (s_a / 8) * 8;
  size_t st_b = (s_b / 8) * 8;

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

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

    //[ compute mask of common elements
    const __m256i rotate_arg = _mm256_set_epi32(0,7,6,5,4,3,2,1);
    __m256i cmp_mask = _mm256_cmpeq_epi32(v_a, v_b); // pairwise comparison

    for (int i = 0; i < 7; i++) {
	    v_b = _mm256_permutevar8x32_epi32(v_b, rotate_arg);    // shuffling
	    __m256i cmp_mask1 = _mm256_cmpeq_epi32(v_a, v_b); // again...
	    cmp_mask = _mm256_or_si256(cmp_mask, cmp_mask1);
    }

    // convert the 256-bit mask to the 8-bit mask
    const int mask = _mm256_movemask_ps(_mm256_castsi256_ps(cmp_mask));
    //cout<<"mask: "<<mask<<endl;

    //[ copy out common elements
    const __m256i p = _mm256_permutevar8x32_epi32(v_a, shuffle_mask32[mask]);
    _mm256_storeu_si256((__m256i *)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 %rbp
pushq %r14
pushq %rbx
cmpq %rdi, %r8
je 0x3d93
cmpq %rdx, %r8
je 0x3dac
vpmovsxbd 0x2740(%rip), %xmm1 # 0x63d8
movq %rsi, %r10
movq %rcx, %r11
andq $-0x8, %r10
andq $-0x8, %r11
vpxor %xmm0, %xmm0, %xmm0
pushq $0x7
popq %rbp
leaq 0x550c(%rip), %r14      # 0x91c0
movq %r8, %rax
vpextrq $0x1, %xmm0, %r9
vmovq %xmm0, %rbx
cmpq %r10, %r9
jae 0x3d7f
cmpq %r11, %rbx
jae 0x3d7f
vpbroadcastq 0x18(%rdi,%r9,4), %xmm5
vpbroadcastq 0x18(%rdx,%rbx,4), %xmm4
vmovdqu (%rdi,%r9,4), %ymm2
vmovdqu (%rdx,%rbx,4), %ymm3
movl %ebp, %r9d
vmovdqa %xmm5, %xmm6
vpermt2d %xmm4, %xmm1, %xmm6
vpermt2d %xmm5, %xmm1, %xmm4
vpcmpeqd %ymm3, %ymm2, %ymm5
vpcmpnltud %xmm4, %xmm6, %k1
vpbroadcastq 0x28eb(%rip), %xmm4 {%k1} {z} # 0x6600
subl $0x1, %r9d
jb 0x3d2c
valignd $0x1, %ymm3, %ymm3, %ymm3 # ymm3 = ymm3[1,2,3,4,5,6,7,0]
vpcmpeqd %ymm3, %ymm2, %ymm6
vpor %ymm6, %ymm5, %ymm5
jmp 0x3d15
vmovmskps %ymm5, %r9d
vpaddq %xmm0, %xmm4, %xmm0
popcntl %r9d, %ebx
shll $0x5, %r9d
vmovdqa (%r9,%r14), %ymm3
vpermd %ymm2, %ymm3, %ymm2
vmovdqu %ymm2, (%rax)
leaq (%rax,%rbx,4), %rax
jmp 0x3cb7
cmpq %rcx, %rbx
jae 0x3d84
movl (%rdi,%r9,4), %r11d
movl (%rdx,%rbx,4), %r10d
cmpl %r10d, %r11d
jae 0x3d6c
incq %r9
jmp 0x3d7f
jbe 0x3d73
incq %rbx
jmp 0x3d7f
movl %r10d, (%rax)
addq $0x4, %rax
incq %r9
jmp 0x3d6e
cmpq %rsi, %r9
jb 0x3d55
subq %r8, %rax
sarq $0x2, %rax
popq %rbx
popq %r14
popq %rbp
vzeroupper
retq
leaq 0x2746(%rip), %rdi      # 0x64e0
leaq 0x2867(%rip), %rsi      # 0x6608
leaq 0x287d(%rip), %rcx      # 0x6625
pushq $0x42
jmp 0x3dc3
leaq 0x27c7(%rip), %rdi      # 0x657a
leaq 0x284e(%rip), %rsi      # 0x6608
leaq 0x2864(%rip), %rcx      # 0x6625
pushq $0x43
popq %rdx
callq 0x20f0