// File: amadvance[P]tommyds/tommyds/tommychain.h
// Function: tommy_chain_mergesort
tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func* cmp)
{
	/*
	 * Bit buckets of chains.
	 * Each bucket contains 2^i nodes or it's empty.
	 * The chain at address TOMMY_BIT_MAX is an independent variable operating as "carry".
	 * We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck.
	 */
	tommy_chain bit[TOMMY_SIZE_BIT + 1];

	/**
	 * Value stored inside the bit bucket.
	 * It's used to know which bucket is empty of full.
	 */
	tommy_size_t counter;
	tommy_node* node = chain->head;
	tommy_node* tail = chain->tail;
	tommy_size_t mask;
	tommy_size_t i;

	counter = 0;
	while (1) {
		tommy_node* next;
		tommy_chain* last;

		/* carry bit to add */
		last = &bit[TOMMY_SIZE_BIT];
		bit[TOMMY_SIZE_BIT].head = node;
		bit[TOMMY_SIZE_BIT].tail = node;
		next = node->next;

		/* add the bit, propagating the carry */
		i = 0;
		mask = counter;
		while ((mask & 1) != 0) {
			tommy_chain_merge_degenerated(&bit[i], last, cmp);
			mask >>= 1;
			last = &bit[i];
			++i;
		}

		/* copy the carry in the first empty bit */
		bit[i] = *last;

		/* add the carry in the counter */
		++counter;

		if (node == tail)
			break;
		node = next;
	}

	/* merge the buckets */
	i = tommy_ctz(counter);
	mask = counter >> i;
	while (mask != 1) {
		mask >>= 1;
		if (mask & 1)
			tommy_chain_merge_degenerated(&bit[i + 1], &bit[i], cmp);
		else
			bit[i + 1] = bit[i];
		++i;
	}

	*chain = bit[i];
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x460, %rsp            # imm = 0x460
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x430(%rbp)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x438(%rbp)
movq $0x0, -0x428(%rbp)
leaq -0x420(%rbp), %rax
addq $0x400, %rax            # imm = 0x400
movq %rax, -0x458(%rbp)
movq -0x430(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x430(%rbp), %rax
movq %rax, -0x18(%rbp)
movq -0x430(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x450(%rbp)
movq $0x0, -0x448(%rbp)
movq -0x428(%rbp), %rax
movq %rax, -0x440(%rbp)
movq -0x440(%rbp), %rax
andq $0x1, %rax
cmpq $0x0, %rax
je 0x62d6
movq -0x448(%rbp), %rax
leaq -0x420(%rbp), %rdi
shlq $0x4, %rax
addq %rax, %rdi
movq -0x458(%rbp), %rsi
movq -0x10(%rbp), %rdx
callq 0x8d50
movq -0x440(%rbp), %rax
shrq %rax
movq %rax, -0x440(%rbp)
movq -0x448(%rbp), %rcx
leaq -0x420(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq %rax, -0x458(%rbp)
movq -0x448(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x448(%rbp)
jmp 0x625f
movq -0x448(%rbp), %rcx
leaq -0x420(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq -0x458(%rbp), %rcx
movq (%rcx), %rdx
movq %rdx, (%rax)
movq 0x8(%rcx), %rcx
movq %rcx, 0x8(%rax)
movq -0x428(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x428(%rbp)
movq -0x430(%rbp), %rax
cmpq -0x438(%rbp), %rax
jne 0x6324
jmp 0x6337
movq -0x450(%rbp), %rax
movq %rax, -0x430(%rbp)
jmp 0x620b
movq -0x428(%rbp), %rdi
callq 0x8e10
movl %eax, %eax
movq %rax, -0x448(%rbp)
movq -0x428(%rbp), %rax
movq -0x448(%rbp), %rcx
shrq %cl, %rax
movq %rax, -0x440(%rbp)
cmpq $0x1, -0x440(%rbp)
je 0x6420
movq -0x440(%rbp), %rax
shrq %rax
movq %rax, -0x440(%rbp)
movq -0x440(%rbp), %rax
andq $0x1, %rax
cmpq $0x0, %rax
je 0x63cd
movq -0x448(%rbp), %rax
addq $0x1, %rax
leaq -0x420(%rbp), %rdi
shlq $0x4, %rax
addq %rax, %rdi
movq -0x448(%rbp), %rax
leaq -0x420(%rbp), %rsi
shlq $0x4, %rax
addq %rax, %rsi
movq -0x10(%rbp), %rdx
callq 0x8d50
jmp 0x6409
movq -0x448(%rbp), %rcx
addq $0x1, %rcx
leaq -0x420(%rbp), %rax
shlq $0x4, %rcx
addq %rcx, %rax
movq -0x448(%rbp), %rdx
leaq -0x420(%rbp), %rcx
shlq $0x4, %rdx
addq %rdx, %rcx
movq (%rcx), %rdx
movq %rdx, (%rax)
movq 0x8(%rcx), %rcx
movq %rcx, 0x8(%rax)
movq -0x448(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x448(%rbp)
jmp 0x6364
movq -0x8(%rbp), %rax
movq -0x448(%rbp), %rdx
leaq -0x420(%rbp), %rcx
shlq $0x4, %rdx
addq %rdx, %rcx
movq (%rcx), %rdx
movq %rdx, (%rax)
movq 0x8(%rcx), %rcx
movq %rcx, 0x8(%rax)
addq $0x460, %rsp            # imm = 0x460
popq %rbp
retq