// File: travisdowns[P]sort-bench/radix6.cpp
// Function: radix_sort6(unsigned long*, unsigned long)
void radix_sort6(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);

    uint64_t *from = a, *to = queue_area.get();
    
    for (size_t pass = 0; pass < RADIX_LEVELS; pass++) {

        if (is_trivial(freqs[pass], count)) {
            // this pass would do nothing, just skip it
            continue;
        }

        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 = to;
        for (size_t i = 0; i < RADIX_SIZE; i++) {
            queue_ptrs[i] = next;
            next += freqs[pass][i];
        }

        // 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 = from[i];
            size_t index = (value >> shift) & RADIX_MASK;
            *queue_ptrs[index]++ = value;
        }

        // swap from and to areas
        std::swap(from, to);
    }

    // because of the last swap, the "from" area has the sorted payload: if it's
    // not the original array "a", do a final copy
    if (from != a) {
        std::copy(from, from + count, a);
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x4890, %rsp           # imm = 0x4890
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rax
movl $0x8, %ecx
mulq %rcx
movq %rax, %rdi
movq $-0x1, %rax
cmovoq %rax, %rdi
callq 0x2030
movq %rax, %rsi
leaq -0x18(%rbp), %rdi
callq 0x33a0
leaq -0x4020(%rbp), %rdi
movq %rdi, -0x4880(%rbp)
xorl %esi, %esi
movl $0x4000, %edx           # imm = 0x4000
callq 0x20f0
movq -0x4880(%rbp), %rdx
movq -0x8(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x7b90
jmp 0x796e
movq -0x8(%rbp), %rax
movq %rax, -0x4038(%rbp)
leaq -0x18(%rbp), %rdi
callq 0x34b0
movq %rax, -0x4040(%rbp)
movq $0x0, -0x4048(%rbp)
cmpq $0x8, -0x4048(%rbp)
jae 0x7b40
movq -0x4048(%rbp), %rax
shlq $0xb, %rax
leaq -0x4020(%rbp,%rax), %rdi
movq -0x10(%rbp), %rsi
callq 0x7c30
movb %al, -0x4881(%rbp)
jmp 0x79c6
movb -0x4881(%rbp), %al
testb $0x1, %al
jne 0x79d2
jmp 0x79f7
jmp 0x7b29
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x4028(%rbp)
movl %eax, -0x402c(%rbp)
leaq -0x18(%rbp), %rdi
callq 0x34e0
jmp 0x7b7b
movq -0x4048(%rbp), %rax
shlq $0x3, %rax
movq %rax, -0x4050(%rbp)
movq -0x4040(%rbp), %rax
movq %rax, -0x4858(%rbp)
movq $0x0, -0x4860(%rbp)
cmpq $0x100, -0x4860(%rbp) # imm = 0x100
jae 0x7a8b
movq -0x4858(%rbp), %rcx
movq -0x4860(%rbp), %rax
movq %rcx, -0x4850(%rbp,%rax,8)
movq -0x4048(%rbp), %rcx
leaq -0x4020(%rbp), %rax
shlq $0xb, %rcx
addq %rcx, %rax
movq -0x4860(%rbp), %rcx
movq (%rax,%rcx,8), %rax
shlq $0x3, %rax
addq -0x4858(%rbp), %rax
movq %rax, -0x4858(%rbp)
movq -0x4860(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x4860(%rbp)
jmp 0x7a22
movq $0x0, -0x4868(%rbp)
movq -0x4868(%rbp), %rax
cmpq -0x10(%rbp), %rax
jae 0x7b16
movq -0x4038(%rbp), %rax
movq -0x4868(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x4870(%rbp)
movq -0x4870(%rbp), %rax
movq -0x4050(%rbp), %rcx
shrq %cl, %rax
andq $0xff, %rax
movq %rax, -0x4878(%rbp)
movq -0x4870(%rbp), %rcx
movq -0x4878(%rbp), %rdx
movq -0x4850(%rbp,%rdx,8), %rax
movq %rax, %rsi
addq $0x8, %rsi
movq %rsi, -0x4850(%rbp,%rdx,8)
movq %rcx, (%rax)
movq -0x4868(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x4868(%rbp)
jmp 0x7a96
leaq -0x4038(%rbp), %rdi
leaq -0x4040(%rbp), %rsi
callq 0x78c0
movq -0x4048(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x4048(%rbp)
jmp 0x7994
movq -0x4038(%rbp), %rax
cmpq -0x8(%rbp), %rax
je 0x7b69
movq -0x4038(%rbp), %rdi
movq -0x10(%rbp), %rax
leaq (%rdi,%rax,8), %rsi
movq -0x8(%rbp), %rdx
callq 0x7540
jmp 0x7b67
jmp 0x7b69
leaq -0x18(%rbp), %rdi
callq 0x34e0
addq $0x4890, %rsp           # imm = 0x4890
popq %rbp
retq
movq -0x4028(%rbp), %rdi
callq 0x22c0
nopw (%rax,%rax)