// File: splatlab[P]debgr/threadsafe-gqf/gqf.c
// Function: qf_init
void qf_init(QF *qf, uint64_t nslots, uint64_t key_bits, uint64_t value_bits,
						 bool mem, const char * path, uint32_t seed)
{
	uint64_t num_slots, xnslots, nblocks;
	uint64_t key_remainder_bits, bits_per_slot;
	uint64_t size;

	assert(popcnt(nslots) == 1); /* nslots must be a power of 2 */
	num_slots = nslots;
	assert(popcnt(nslots) == 1); /* nslots must be a power of 2 */
	xnslots = nslots + 10*sqrt((double)nslots);
	nblocks = (xnslots + SLOTS_PER_BLOCK - 1) / SLOTS_PER_BLOCK;
	key_remainder_bits = key_bits;
	while (nslots > 1) {
		assert(key_remainder_bits > 0);
		key_remainder_bits--;
		nslots >>= 1;
	}

	bits_per_slot = key_remainder_bits + value_bits;
	assert (BITS_PER_SLOT == 0 || BITS_PER_SLOT == qf->metadata->bits_per_slot);
	assert(bits_per_slot > 1);
#if BITS_PER_SLOT == 8 || BITS_PER_SLOT == 16 || BITS_PER_SLOT == 32 || BITS_PER_SLOT == 64
	size = nblocks * sizeof(qfblock);
#else
	size = nblocks * (sizeof(qfblock) + SLOTS_PER_BLOCK * bits_per_slot / 8);
#endif

	qf->mem = (qfmem *)calloc(sizeof(qfmem), 1);
	
	if (mem) {
		qf->metadata = (qfmetadata *)calloc(sizeof(qfmetadata), 1);

		qf->metadata->size = size;
		qf->metadata->seed = seed;
		qf->metadata->nslots = num_slots;
		qf->metadata->xnslots = qf->metadata->nslots +
			10*sqrt((double)qf->metadata->nslots);
		qf->metadata->key_bits = key_bits;
		qf->metadata->value_bits = value_bits;
		qf->metadata->key_remainder_bits = key_remainder_bits;
		qf->metadata->bits_per_slot = bits_per_slot;

		qf->metadata->range = qf->metadata->nslots;
		qf->metadata->range <<= qf->metadata->bits_per_slot;
		qf->metadata->nblocks = (qf->metadata->xnslots + SLOTS_PER_BLOCK - 1) /
			SLOTS_PER_BLOCK;
		qf->metadata->nelts = 0;
		qf->metadata->ndistinct_elts = 0;
		qf->metadata->noccupied_slots = 0;
		qf->metadata->num_locks = (qf->metadata->xnslots/NUM_SLOTS_TO_LOCK)+2;

		qf->blocks = (qfblock *)calloc(size, 1);

	} else {
		int ret;

		qf->mem->fd = open(path, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
		if (qf->mem->fd < 0) {
			perror("Couldn't open file:\n");
			exit(EXIT_FAILURE);
		}
		ret = fallocate(qf->mem->fd, 0, 0, size+sizeof(qfmetadata));
		if (ret < 0) {
			perror("Couldn't fallocate file:\n");
			exit(EXIT_FAILURE);
		}
		qf->metadata = (qfmetadata *)mmap(NULL, size+sizeof(qfmetadata), PROT_READ |
																			PROT_WRITE, MAP_SHARED, qf->mem->fd, 0);

		qf->metadata->seed = seed;
		qf->metadata->nslots = num_slots;
		qf->metadata->xnslots = qf->metadata->nslots +
														10*sqrt((double)qf->metadata->nslots);
		qf->metadata->key_bits = key_bits;
		qf->metadata->value_bits = value_bits;
		qf->metadata->key_remainder_bits = key_remainder_bits;
		qf->metadata->bits_per_slot = bits_per_slot;

		qf->metadata->range = qf->metadata->nslots;
		qf->metadata->range <<= qf->metadata->bits_per_slot;
		qf->metadata->nblocks = (qf->metadata->xnslots + SLOTS_PER_BLOCK - 1) /
			SLOTS_PER_BLOCK;
		qf->metadata->nelts = 0;
		qf->metadata->ndistinct_elts = 0;
		qf->metadata->noccupied_slots = 0;
		qf->metadata->num_locks = (qf->metadata->xnslots/NUM_SLOTS_TO_LOCK)+2;

		qf->blocks = (qfblock *)(qf->metadata + sizeof(qfmetadata));
	}
	
	/* initialize all the locks to 0 */
	qf->mem->metadata_lock = 0;
	qf->mem->locks = (volatile int *)calloc(qf->metadata->num_locks,
																					sizeof(volatile int));
#ifdef LOG_WAIT_TIME
	qf->wait_times = (wait_time_data* )calloc(qf->metadata->num_locks+1,
																						sizeof(wait_time_data));
#endif
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
movb %r8b, %al
movl 0x10(%rbp), %r8d
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
andb $0x1, %al
movb %al, -0x21(%rbp)
movq %r9, -0x30(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x38(%rbp)
movaps 0x6116(%rip), %xmm1     # 0x2aa40
movq -0x10(%rbp), %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x6115(%rip), %xmm1     # 0x2aa50
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd %xmm0, -0x70(%rbp)
callq 0x3200
movsd -0x70(%rbp), %xmm1
movsd 0x60ff(%rip), %xmm2     # 0x2aa60
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movaps %xmm0, %xmm1
cvttsd2si %xmm1, %rax
movq %rax, %rdx
sarq $0x3f, %rdx
movsd 0x60e8(%rip), %xmm1     # 0x2aa68
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %rcx
andq %rdx, %rcx
orq %rcx, %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
addq $0x40, %rax
subq $0x1, %rax
shrq $0x6, %rax
movq %rax, -0x48(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x50(%rbp)
cmpq $0x1, -0x10(%rbp)
jbe 0x249cf
movq -0x50(%rbp), %rax
addq $-0x1, %rax
movq %rax, -0x50(%rbp)
movq -0x10(%rbp), %rax
shrq %rax
movq %rax, -0x10(%rbp)
jmp 0x249af
movq -0x50(%rbp), %rax
addq -0x20(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x48(%rbp), %rax
movq -0x58(%rbp), %rcx
shlq $0x6, %rcx
shrq $0x3, %rcx
addq $0x11, %rcx
imulq %rcx, %rax
movq %rax, -0x60(%rbp)
movl $0x18, %edi
movl $0x1, %esi
callq 0x3170
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq %rcx, (%rax)
testb $0x1, -0x21(%rbp)
je 0x24c05
movl $0x80, %edi
movl $0x1, %esi
callq 0x3170
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x60(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, (%rax)
movl 0x10(%rbp), %ecx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movl %ecx, 0x8(%rax)
movq -0x38(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x10(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x10(%rax), %xmm0
movaps 0x5fcb(%rip), %xmm1     # 0x2aa40
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x5fcf(%rip), %xmm1     # 0x2aa50
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd %xmm0, -0x78(%rbp)
callq 0x3200
movsd -0x78(%rbp), %xmm1
movsd 0x5fb9(%rip), %xmm2     # 0x2aa60
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movaps %xmm0, %xmm1
cvttsd2si %xmm1, %rcx
movq %rcx, %rdx
sarq $0x3f, %rdx
movsd 0x5fa2(%rip), %xmm1     # 0x2aa68
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %rax
andq %rdx, %rax
orq %rax, %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x18(%rax)
movq -0x18(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x20(%rax)
movq -0x20(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x28(%rax)
movq -0x50(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x30(%rax)
movq -0x58(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x38(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x10(%rax), %rcx
movq %rcx, 0x40(%rax)
movq $0x0, 0x48(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movb 0x38(%rax), %dil
movq 0x40(%rax), %rsi
movq 0x48(%rax), %rdx
movb %dil, %cl
shldq %cl, %rsi, %rdx
movb %dil, %cl
shlq %cl, %rsi
movq %rsi, %rcx
xorl %esi, %esi
testb $0x40, %dil
cmovneq %rcx, %rdx
cmovneq %rsi, %rcx
movq %rdx, 0x48(%rax)
movq %rcx, 0x40(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x18(%rax), %rcx
addq $0x40, %rcx
subq $0x1, %rcx
shrq $0x6, %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x50(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq $0x0, 0x58(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq $0x0, 0x60(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq $0x0, 0x68(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x18(%rax), %rcx
shrq $0xc, %rcx
addq $0x2, %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x70(%rax)
movq -0x60(%rbp), %rdi
movl $0x1, %esi
callq 0x3170
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x10(%rax)
jmp 0x24e80
movq -0x30(%rbp), %rdi
movl $0x242, %esi            # imm = 0x242
movl $0x1c0, %edx            # imm = 0x1C0
movb $0x0, %al
callq 0x31d0
movl %eax, %ecx
movq -0x8(%rbp), %rax
movq (%rax), %rax
movl %ecx, (%rax)
movq -0x8(%rbp), %rax
movq (%rax), %rax
cmpl $0x0, (%rax)
jge 0x24c47
leaq 0x5e45(%rip), %rdi      # 0x2aa7d
callq 0x3230
movl $0x1, %edi
callq 0x3360
movq -0x8(%rbp), %rax
movq (%rax), %rax
movl (%rax), %edi
movq -0x60(%rbp), %rcx
addq $0x80, %rcx
xorl %esi, %esi
xorl %eax, %eax
movl %eax, %edx
callq 0x31f0
movl %eax, -0x64(%rbp)
cmpl $0x0, -0x64(%rbp)
jge 0x24c85
leaq 0x5e1c(%rip), %rdi      # 0x2aa92
callq 0x3230
movl $0x1, %edi
callq 0x3360
movq -0x60(%rbp), %rsi
subq $-0x80, %rsi
movq -0x8(%rbp), %rax
movq (%rax), %rax
movl (%rax), %r8d
xorl %eax, %eax
movl %eax, %r9d
movq %r9, -0x80(%rbp)
movl $0x3, %edx
movl $0x1, %ecx
movq %r9, %rdi
callq 0x34a0
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x8(%rax)
movl 0x10(%rbp), %ecx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movl %ecx, 0x8(%rax)
movq -0x38(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x10(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x10(%rax), %xmm0
movaps 0x5d51(%rip), %xmm1     # 0x2aa40
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x5d55(%rip), %xmm1     # 0x2aa50
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
movsd %xmm0, -0x88(%rbp)
callq 0x3200
movsd -0x88(%rbp), %xmm1
movq -0x80(%rbp), %rsi
movsd 0x5d35(%rip), %xmm2     # 0x2aa60
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movaps %xmm0, %xmm1
cvttsd2si %xmm1, %rcx
movq %rcx, %rdx
sarq $0x3f, %rdx
movsd 0x5d1e(%rip), %xmm1     # 0x2aa68
subsd %xmm1, %xmm0
cvttsd2si %xmm0, %rax
andq %rdx, %rax
orq %rax, %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x18(%rax)
movq -0x18(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x20(%rax)
movq -0x20(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x28(%rax)
movq -0x50(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x30(%rax)
movq -0x58(%rbp), %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x38(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x10(%rax), %rcx
movq %rcx, 0x40(%rax)
movq $0x0, 0x48(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movb 0x38(%rax), %dil
movq 0x40(%rax), %r8
movq 0x48(%rax), %rdx
movb %dil, %cl
shldq %cl, %r8, %rdx
movb %dil, %cl
shlq %cl, %r8
movq %r8, %rcx
testb $0x40, %dil
cmovneq %rcx, %rdx
cmovneq %rsi, %rcx
movq %rdx, 0x48(%rax)
movq %rcx, 0x40(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x18(%rax), %rcx
addq $0x40, %rcx
subq $0x1, %rcx
shrq $0x6, %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x50(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq $0x0, 0x58(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq $0x0, 0x60(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq $0x0, 0x68(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x18(%rax), %rcx
shrq $0xc, %rcx
addq $0x2, %rcx
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq %rcx, 0x70(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rcx
addq $0x4000, %rcx           # imm = 0x4000
movq -0x8(%rbp), %rax
movq %rcx, 0x10(%rax)
movq -0x8(%rbp), %rax
movq (%rax), %rax
movl $0x0, 0x4(%rax)
movq -0x8(%rbp), %rax
movq 0x8(%rax), %rax
movq 0x70(%rax), %rdi
movl $0x4, %esi
callq 0x3170
movq %rax, %rcx
movq -0x8(%rbp), %rax
movq (%rax), %rax
movq %rcx, 0x8(%rax)
addq $0x90, %rsp
popq %rbp
retq
nopl (%rax,%rax)