// File: /workspace/github_c_makefile_star2_O2/lh3[P]minigraph/kalloc.c
// Function: kfree
void kfree(void *_km, void *ap) /* kfree() also adds a new core to the circular list */
{
	header_t *p, *q;
	kmem_t *km = (kmem_t*)_km;
	
	if (!ap) return;
	if (km == NULL) {
		free(ap);
		return;
	}
	p = (header_t*)((size_t*)ap - 1);
	p->size = *((size_t*)ap - 1);
	/* Find the pointer that points to the block to be freed. The following loop can stop on two conditions:
	 *
	 * a) "p>q && p<q->ptr": @------#++++++++#+++++++@-------    @---------------#+++++++@-------
	 *    (can also be in    |      |                |        -> |                       |
	 *     two cores)        q      p           q->ptr           q                  q->ptr
	 *
	 *                       @--------    #+++++++++@--------    @--------    @------------------
	 *                       |            |         |         -> |            |
	 *                       q            p    q->ptr            q       q->ptr
	 *
	 * b) "q>=q->ptr && (p>q || p<q->ptr)":  @-------#+++++   @--------#+++++++     @-------#+++++   @----------------
	 *                                       |                |        |         -> |                |
	 *                                  q->ptr                q        p       q->ptr                q
	 *
	 *                                       #+++++++@-----   #++++++++@-------     @-------------   #++++++++@-------
	 *                                       |       |                 |         -> |                         |
	 *                                       p  q->ptr                 q       q->ptr                         q
	 */
	for (q = km->loop_head; !(p > q && p < q->ptr); q = q->ptr)
		if (q >= q->ptr && (p > q || p < q->ptr)) break;
	if (p + p->size == q->ptr) { /* two adjacent blocks, merge p and q->ptr (the 2nd and 4th cases) */
		p->size += q->ptr->size;
		p->ptr = q->ptr->ptr;
	} else if (p + p->size > q->ptr && q->ptr >= p) {
		panic("[kfree] The end of the allocated block enters a free block.");
	} else p->ptr = q->ptr; /* backup q->ptr */

	if (q + q->size == p) { /* two adjacent blocks, merge q and p (the other two cases) */
		q->size += p->size;
		q->ptr = p->ptr;
		km->loop_head = q;
	} else if (q + q->size > p && p >= q) {
		panic("[kfree] The end of a free block enters the allocated block.");
	} else km->loop_head = p, q->ptr = p; /* in two cores, cannot be merged; create a new block in the list */
}

// Assembly:
pushq %rax
testq %rsi, %rsi
je 0x263d
testq %rdi, %rdi
je 0x25ee
leaq -0x8(%rsi), %rcx
movq 0x20(%rdi), %rdx
movq %rdx, %rax
cmpq %rdx, %rcx
seta %r8b
movq 0x8(%rdx), %rdx
cmpq %rdx, %rcx
setb %r9b
testb %r9b, %r8b
jne 0x25c0
cmpq %rax, %rcx
seta %r8b
cmpq %rdx, %rcx
setb %r9b
cmpq %rdx, %rax
jb 0x258e
orb %r9b, %r8b
je 0x258e
movq (%rcx), %r8
movq %r8, %r9
shlq $0x4, %r9
addq %rcx, %r9
cmpq %rdx, %r9
je 0x25f7
setbe %r9b
cmpq %rcx, %rdx
setb %r10b
orb %r9b, %r10b
jne 0x2601
leaq 0x20a1b(%rip), %rdi     # 0x23004
callq 0x264b
movq %rsi, %rdi
popq %rax
jmp 0x2040
addq (%rdx), %r8
movq %r8, (%rcx)
movq 0x8(%rdx), %rdx
movq %rdx, (%rsi)
movq (%rax), %rsi
movq %rsi, %r9
shlq $0x4, %r9
addq %rax, %r9
cmpq %rcx, %r9
je 0x262f
setbe %dl
cmpq %rax, %rcx
setb %sil
orb %dl, %sil
je 0x263f
movq %rcx, 0x20(%rdi)
movq %rcx, 0x8(%rax)
jmp 0x263d
addq %rsi, %r8
movq %r8, (%rax)
movq %rdx, 0x8(%rax)
movq %rax, 0x20(%rdi)
popq %rax
retq
leaq 0x209fa(%rip), %rdi     # 0x23040
callq 0x264b