// File: /workspace/github_cpp_makefile_star2_O3/travisdowns[P]sort-bench/radix4.cpp
// Function: radix_sort4(unsigned long*, unsigned long)
void radix_sort4(uint64_t *a, size_t count)
{
    std::unique_ptr<uint64_t[]> queue_area(new uint64_t[count]);

    freq_array_type freqs = {};
    count_frequency(a, count, freqs);
    
    for (size_t pass = 0; pass < RADIX_LEVELS; pass++) {
        uint64_t shift = pass * RADIX_BITS;

        // array of pointers to the current position in each queue, which we set up based on the
        // known final sizes of each queue (i.e., "tighly packed")
        uint64_t * queue_ptrs[RADIX_SIZE], * next = queue_area.get();
        for (size_t i = 0; i < RADIX_SIZE; i++) {
            queue_ptrs[i] = next;
            next += freqs[pass][i];
        }

        // sanity check: final pointer should point exactly to the end of the temp area
        assert(next == queue_area.get() + count);

        // copy each element into the appropriate queue based on the current RADIX_BITS sized
        // "digit" within it
        for (size_t i = 0; i < count; i++) {
            size_t value = a[i];
            size_t index = (value >> shift) & RADIX_MASK;
            *queue_ptrs[index]++ = value;
        }

        // copy all the queues back over top of the original array in order
        // since the queues are tighly packed and already in the right order
        // we can accomplish this with a single linear copy operation
        std::copy(queue_area.get(), queue_area.get() + count, a);
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x4818, %rsp           # imm = 0x4818
movq %rsi, %rbx
movq %rdi, %r14
movq %rsi, %rax
shrq $0x3d, %rax
leaq (,%rsi,8), %rcx
xorl %edi, %edi
negq %rax
sbbq %rdi, %rdi
movq %rcx, 0x8(%rsp)
orq %rcx, %rdi
callq 0x2030
movq %rax, %r12
leaq 0x810(%rsp), %r13
movl $0x4000, %edx           # imm = 0x4000
movq %r13, %rdi
xorl %esi, %esi
callq 0x20b0
testq %rbx, %rbx
je 0x3800
xorl %eax, %eax
movq (%r14,%rax,8), %rcx
xorl %edx, %edx
movzbl %cl, %esi
leaq (%rsp,%rsi,8), %rsi
addq $0x810, %rsi            # imm = 0x810
incq (%rdx,%rsi)
shrq $0x8, %rcx
addq $0x800, %rdx            # imm = 0x800
cmpq $0x4000, %rdx           # imm = 0x4000
jne 0x37d2
incq %rax
cmpq %rbx, %rax
jne 0x37cc
leaq (%r12,%rbx,8), %rbp
xorl %r15d, %r15d
xorl %ecx, %ecx
movq %r12, %rax
movq %rax, 0x10(%rsp,%rcx,8)
movq (%r13,%rcx,8), %rdx
leaq (%rax,%rdx,8), %rax
incq %rcx
cmpq $0x100, %rcx            # imm = 0x100
jne 0x380c
cmpq %rbp, %rax
jne 0x389a
testq %rbx, %rbx
je 0x3871
leaq (,%r15,8), %rcx
xorl %eax, %eax
movq (%r14,%rax,8), %rdx
movq %rdx, %rsi
shrq %cl, %rsi
movzbl %sil, %esi
movq 0x10(%rsp,%rsi,8), %rdi
leaq 0x8(%rdi), %r8
movq %r8, 0x10(%rsp,%rsi,8)
movq %rdx, (%rdi)
incq %rax
cmpq %rax, %rbx
jne 0x383a
movq %r14, %rdi
movq %r12, %rsi
movq 0x8(%rsp), %rdx
callq 0x2100
incq %r15
addq $0x800, %r13            # imm = 0x800
cmpq $0x8, %r15
jne 0x3807
movq %r12, %rdi
addq $0x4818, %rsp           # imm = 0x4818
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2160
leaq 0x1bf7(%rip), %rdi      # 0x5498
leaq 0x1c11(%rip), %rsi      # 0x54b9
leaq 0x1c15(%rip), %rcx      # 0x54c4
movl $0x32, %edx
callq 0x20c0
nopl (%rax)