// File: ralgond[P]SortedListIntersection/algo_highlyscalable_avx512.cpp
// Function: highlyscalable_avx512_intersection(unsigned int const*, unsigned long, unsigned int const*, unsigned long, unsigned int*)
size_t highlyscalable_avx512_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 16
  size_t st_a = (s_a / 16) * 16;
  size_t st_b = (s_b / 16) * 16;

  while (i_a < st_a && i_b < st_b) {
    __m512i v_a = _mm512_loadu_si512(&A[i_a]);
    __m512i v_b = _mm512_loadu_si512(&B[i_b]);
    //]

    //[ move pointers
    const uint32_t a_max = A[i_a + 15];
    const uint32_t b_max = B[i_b + 15];
    i_a += (a_max <= b_max) * 16;
    i_b += (a_max >= b_max) * 16;
    
    //[ compute mask of common elements
    const __m512i rotate_arg = _mm512_set_epi32(0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
    __mmask16 cmp_mask = _mm512_cmpeq_epu32_mask(v_a, v_b); // pairwise comparison

    for (int i = 0; i < 15; i++) {
	    v_b = _mm512_permutexvar_epi32(rotate_arg, v_b);    // shuffling
	    __mmask16 cmp_mask1 = _mm512_cmpeq_epu32_mask(v_a, v_b);
	    cmp_mask = _mm512_kor(cmp_mask, cmp_mask1);
    }

    const int mask = _mm512_mask2int(cmp_mask);
    //cout<<"mask: "<<mask<<endl;

    //[ copy out common elements
    //const __m256i p = _mm256_permutevar8x32_epi32(v_a, shuffle_mask64[mask]);
    //__m256i p; //_mm256_permutevar8x32_epi32(v_a, shuffle_mask64[mask]);
    __m512i p = _mm512_permutexvar_epi32(shuffle_mask64[mask], v_a);
    _mm512_storeu_si512(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
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %rbx
andq $-0x40, %rsp
subq $0x480, %rsp            # imm = 0x480
movq %rdi, 0x228(%rsp)
movq %rsi, 0x220(%rsp)
movq %rdx, 0x218(%rsp)
movq %rcx, 0x210(%rsp)
movq %r8, 0x208(%rsp)
movq 0x208(%rsp), %rax
cmpq 0x228(%rsp), %rax
je 0xa240
jmp 0xa25f
leaq 0x4172(%rip), %rdi      # 0xe3b9
leaq 0x4372(%rip), %rsi      # 0xe5c0
movl $0x57, %edx
leaq 0x4385(%rip), %rcx      # 0xe5df
callq 0x2120
movq 0x208(%rsp), %rax
cmpq 0x218(%rsp), %rax
je 0xa273
jmp 0xa292
leaq 0x41d9(%rip), %rdi      # 0xe453
leaq 0x433f(%rip), %rsi      # 0xe5c0
movl $0x58, %edx
leaq 0x4352(%rip), %rcx      # 0xe5df
callq 0x2120
movq 0x208(%rsp), %rax
movq %rax, 0x200(%rsp)
movq $0x0, 0x1f8(%rsp)
movq $0x0, 0x1f0(%rsp)
movq 0x220(%rsp), %rax
shrq $0x4, %rax
shlq $0x4, %rax
movq %rax, 0x1e8(%rsp)
movq 0x210(%rsp), %rax
shrq $0x4, %rax
shlq $0x4, %rax
movq %rax, 0x1e0(%rsp)
movq 0x1f8(%rsp), %rcx
xorl %eax, %eax
cmpq 0x1e8(%rsp), %rcx
movb %al, 0x3f(%rsp)
jae 0xa319
movq 0x1f0(%rsp), %rax
cmpq 0x1e0(%rsp), %rax
setb %al
movb %al, 0x3f(%rsp)
movb 0x3f(%rsp), %al
testb $0x1, %al
jne 0xa326
jmp 0xa798
movq 0x228(%rsp), %rax
movq 0x1f8(%rsp), %rcx
leaq (%rax,%rcx,4), %rax
movq %rax, 0x238(%rsp)
movq 0x238(%rsp), %rax
vmovdqu64 (%rax), %zmm0
vmovdqa64 %zmm0, 0x180(%rsp)
movq 0x218(%rsp), %rax
movq 0x1f0(%rsp), %rcx
leaq (%rax,%rcx,4), %rax
movq %rax, 0x230(%rsp)
movq 0x230(%rsp), %rax
vmovdqu64 (%rax), %zmm0
vmovdqa64 %zmm0, 0x140(%rsp)
movq 0x228(%rsp), %rax
movq 0x1f8(%rsp), %rcx
movl 0x3c(%rax,%rcx,4), %eax
movl %eax, 0x13c(%rsp)
movq 0x218(%rsp), %rax
movq 0x1f0(%rsp), %rcx
movl 0x3c(%rax,%rcx,4), %eax
movl %eax, 0x138(%rsp)
movl 0x13c(%rsp), %eax
movl 0x138(%rsp), %ecx
subl %ecx, %eax
setbe %al
movzbl %al, %eax
shll $0x4, %eax
movl %eax, %ecx
movq 0x1f8(%rsp), %rax
addq %rcx, %rax
movq %rax, 0x1f8(%rsp)
movl 0x13c(%rsp), %eax
movl 0x138(%rsp), %ecx
subl %ecx, %eax
setae %al
movzbl %al, %eax
shll $0x4, %eax
movl %eax, %ecx
movq 0x1f0(%rsp), %rax
addq %rcx, %rax
movq %rax, 0x1f0(%rsp)
movl $0x0, 0x2bc(%rsp)
movl $0xf, 0x2b8(%rsp)
movl $0xe, 0x2b4(%rsp)
movl $0xd, 0x2b0(%rsp)
movl $0xc, 0x2ac(%rsp)
movl $0xb, 0x2a8(%rsp)
movl $0xa, 0x2a4(%rsp)
movl $0x9, 0x2a0(%rsp)
movl $0x8, 0x29c(%rsp)
movl $0x7, 0x298(%rsp)
movl $0x6, 0x294(%rsp)
movl $0x5, 0x290(%rsp)
movl $0x4, 0x28c(%rsp)
movl $0x3, 0x288(%rsp)
movl $0x2, 0x284(%rsp)
movl $0x1, 0x280(%rsp)
movl 0x284(%rsp), %edx
movl 0x288(%rsp), %ecx
movl 0x28c(%rsp), %eax
movl 0x294(%rsp), %r8d
movl 0x298(%rsp), %edi
movl 0x29c(%rsp), %esi
movl 0x2a4(%rsp), %r11d
movl 0x2a8(%rsp), %r10d
movl 0x2ac(%rsp), %r9d
movl 0x2b4(%rsp), %r15d
movl 0x2b8(%rsp), %r14d
movl 0x2bc(%rsp), %ebx
vmovd 0x2b0(%rsp), %xmm0
vpinsrd $0x1, %r15d, %xmm0, %xmm0
vpinsrd $0x2, %r14d, %xmm0, %xmm0
vpinsrd $0x3, %ebx, %xmm0, %xmm1
vmovd 0x2a0(%rsp), %xmm0
vpinsrd $0x1, %r11d, %xmm0, %xmm0
vpinsrd $0x2, %r10d, %xmm0, %xmm0
vpinsrd $0x3, %r9d, %xmm0, %xmm2
vmovaps %xmm2, %xmm0
vinserti128 $0x1, %xmm1, %ymm0, %ymm1
vmovd 0x290(%rsp), %xmm0
vpinsrd $0x1, %r8d, %xmm0, %xmm0
vpinsrd $0x2, %edi, %xmm0, %xmm0
vpinsrd $0x3, %esi, %xmm0, %xmm2
vmovd 0x280(%rsp), %xmm0
vpinsrd $0x1, %edx, %xmm0, %xmm0
vpinsrd $0x2, %ecx, %xmm0, %xmm0
vpinsrd $0x3, %eax, %xmm0, %xmm3
vmovaps %xmm3, %xmm0
vinserti128 $0x1, %xmm2, %ymm0, %ymm2
vmovaps %ymm2, %ymm0
vinserti64x4 $0x1, %ymm1, %zmm0, %zmm0
vmovdqa64 %zmm0, 0x240(%rsp)
vmovdqa64 0x240(%rsp), %zmm0
vmovdqa64 %zmm0, 0xc0(%rsp)
vmovdqa64 0x180(%rsp), %zmm0
vmovdqa64 0x140(%rsp), %zmm1
vpcmpeqd %zmm1, %zmm0, %k0
kmovd %k0, %eax
movw %ax, 0xbe(%rsp)
movl $0x0, 0xb8(%rsp)
cmpl $0xf, 0xb8(%rsp)
jge 0xa6b9
vmovdqa64 0xc0(%rsp), %zmm1
vmovdqa64 0x140(%rsp), %zmm0
vmovdqa64 %zmm1, 0x380(%rsp)
vmovdqa64 %zmm0, 0x340(%rsp)
vmovdqa64 0x340(%rsp), %zmm1
vmovdqa64 0x380(%rsp), %zmm0
vpermd %zmm1, %zmm0, %zmm0
vmovdqa64 %zmm0, 0x140(%rsp)
vmovdqa64 0x180(%rsp), %zmm0
vmovdqa64 0x140(%rsp), %zmm1
vpcmpeqd %zmm1, %zmm0, %k0
kmovw %k0, 0xb6(%rsp)
movw 0xbe(%rsp), %cx
movw 0xb6(%rsp), %ax
movw %cx, 0x3fc(%rsp)
movw %ax, 0x3fa(%rsp)
movw 0x3fc(%rsp), %ax
movw 0x3fa(%rsp), %cx
orw %cx, %ax
movw %ax, %cx
kmovd %ecx, %k0
movw %ax, 0xbe(%rsp)
movl 0xb8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb8(%rsp)
jmp 0xa5f6
movw 0xbe(%rsp), %ax
movw %ax, 0x3fe(%rsp)
movzwl 0x3fe(%rsp), %eax
movl %eax, 0xb0(%rsp)
movslq 0xb0(%rsp), %rcx
leaq 0x9c99(%rip), %rax      # 0x14380
shlq $0x6, %rcx
addq %rcx, %rax
vmovdqa64 (%rax), %zmm1
vmovdqa64 0x180(%rsp), %zmm0
vmovdqa64 %zmm1, 0x300(%rsp)
vmovdqa64 %zmm0, 0x2c0(%rsp)
vmovdqa64 0x2c0(%rsp), %zmm1
vmovdqa64 0x300(%rsp), %zmm0
vpermd %zmm1, %zmm0, %zmm0
vmovdqa64 %zmm0, 0x40(%rsp)
movq 0x208(%rsp), %rax
vmovdqa64 0x40(%rsp), %zmm0
movq %rax, 0x448(%rsp)
vmovdqa64 %zmm0, 0x400(%rsp)
vmovdqa64 0x400(%rsp), %zmm0
movq 0x448(%rsp), %rax
vmovdqu64 %zmm0, (%rax)
movl 0xb0(%rsp), %eax
movl %eax, 0x454(%rsp)
movl 0x454(%rsp), %eax
popcntl %eax, %ecx
movq 0x208(%rsp), %rax
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, 0x208(%rsp)
jmp 0xa2ea
jmp 0xa79a
movq 0x1f8(%rsp), %rcx
xorl %eax, %eax
cmpq 0x220(%rsp), %rcx
movb %al, 0x3e(%rsp)
jae 0xa7c9
movq 0x1f0(%rsp), %rax
cmpq 0x210(%rsp), %rax
setb %al
movb %al, 0x3e(%rsp)
movb 0x3e(%rsp), %al
testb $0x1, %al
jne 0xa7d6
jmp 0xa8b0
movq 0x228(%rsp), %rax
movq 0x1f8(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movq 0x218(%rsp), %rcx
movq 0x1f0(%rsp), %rdx
cmpl (%rcx,%rdx,4), %eax
jae 0xa817
movq 0x1f8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1f8(%rsp)
jmp 0xa8ab
movq 0x218(%rsp), %rax
movq 0x1f0(%rsp), %rcx
movl (%rax,%rcx,4), %eax
movq 0x228(%rsp), %rcx
movq 0x1f8(%rsp), %rdx
cmpl (%rcx,%rdx,4), %eax
jae 0xa855
movq 0x1f0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1f0(%rsp)
jmp 0xa8a9
movq 0x218(%rsp), %rax
movq 0x1f0(%rsp), %rcx
movl (%rax,%rcx,4), %ecx
movq 0x208(%rsp), %rax
movq %rax, %rdx
addq $0x4, %rdx
movq %rdx, 0x208(%rsp)
movl %ecx, (%rax)
movq 0x1f8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1f8(%rsp)
movq 0x1f0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x1f0(%rsp)
jmp 0xa8ab
jmp 0xa79a
movq 0x208(%rsp), %rax
movq 0x200(%rsp), %rcx
subq %rcx, %rax
sarq $0x2, %rax
leaq -0x18(%rbp), %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
vzeroupper
retq
nopw %cs:(%rax,%rax)
nop