// File: Alcaro[P]bridges/arlib/string.cpp
// Function: operator==(cstring const&, cstring const&)
bool operator==(const cstring& left, const cstring& right)
{
	static_assert(sizeof(cstring) == 16);
	if (left.inlined())
	{
		if (left.m_inline_len() != right.m_inline_len()) return false; // if right isn't inlined, m_inline_len is -1 aka not equal
		__m128i a = _mm_loadu_si128((__m128i*)&left);
		__m128i b = _mm_loadu_si128((__m128i*)&right);
		int eq = _mm_movemask_epi8(_mm_cmpeq_epi8(a, b));
		return ((((~eq) << left.m_inline_len()) & 0xFFFF) == 0);
	}
	else
	{
		// this is basically a memcmp, but I know size >= 16, so I can jump straight to the SIMD loop
		
		auto memeq16 = [](const uint8_t * ap, const uint8_t * bp)
		{
			__m128i a = _mm_loadu_si128((__m128i*)ap);
			__m128i b = _mm_loadu_si128((__m128i*)bp);
			return (_mm_movemask_epi8(_mm_cmpeq_epi8(a, b)) == 0xFFFF);
		};
		if (right.inlined() || left.m_len != right.m_len) return false;
		
		const uint8_t * leftp = left.m_data;
		const uint8_t * rightp = right.m_data;
		size_t stop = left.m_len - 16;
		
		size_t iter = 0;
		do { // entering this loop at all is pointless if len == 16, but do-while is a few bytes smaller than while
			if (!memeq16(leftp+iter, rightp+iter)) return false;
			iter += 16;
		} while (iter < stop);
		
		return (memeq16(leftp+stop, rightp+stop));
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xc0, %rsp
movq %rdi, -0x60(%rbp)
movq %rsi, -0x68(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rdi
callq 0x5cc0
movsbl %al, %eax
cmpl $0x0, %eax
jl 0x3b759
movq -0x60(%rbp), %rdi
callq 0x5cc0
movsbl %al, %eax
movl %eax, -0xbc(%rbp)
movq -0x68(%rbp), %rdi
callq 0x5cc0
movb %al, %cl
movl -0xbc(%rbp), %eax
movsbl %cl, %ecx
cmpl %ecx, %eax
je 0x3b6c3
movb $0x0, -0x51(%rbp)
jmp 0x3b852
movq -0x60(%rbp), %rax
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0x80(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0x90(%rbp)
movaps -0x80(%rbp), %xmm1
movaps -0x90(%rbp), %xmm0
movaps %xmm1, -0x10(%rbp)
movaps %xmm0, -0x20(%rbp)
movaps -0x10(%rbp), %xmm0
movaps -0x20(%rbp), %xmm1
pcmpeqb %xmm1, %xmm0
movdqa %xmm0, -0x30(%rbp)
movdqa -0x30(%rbp), %xmm0
pmovmskb %xmm0, %eax
movl %eax, -0x94(%rbp)
movl -0x94(%rbp), %eax
xorl $-0x1, %eax
movl %eax, -0xc0(%rbp)
movq -0x60(%rbp), %rdi
callq 0x5cc0
movb %al, %cl
movl -0xc0(%rbp), %eax
movsbl %cl, %ecx
shll %cl, %eax
andl $0xffff, %eax           # imm = 0xFFFF
cmpl $0x0, %eax
sete %al
andb $0x1, %al
movb %al, -0x51(%rbp)
jmp 0x3b852
movb 0x28691(%rip), %al      # 0x63df0
movb %al, -0x95(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rdi
callq 0x5cc0
movsbl %al, %eax
cmpl $0x0, %eax
jge 0x3b78e
movq -0x60(%rbp), %rax
movl 0x8(%rax), %eax
movq -0x68(%rbp), %rcx
cmpl 0x8(%rcx), %eax
je 0x3b797
movb $0x0, -0x51(%rbp)
jmp 0x3b852
movq -0x60(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xa0(%rbp)
movq -0x68(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xa8(%rbp)
movq -0x60(%rbp), %rax
movl 0x8(%rax), %eax
subl $0x10, %eax
movl %eax, %eax
movq %rax, -0xb0(%rbp)
movq $0x0, -0xb8(%rbp)
movq -0xa0(%rbp), %rsi
addq -0xb8(%rbp), %rsi
movq -0xa8(%rbp), %rdx
addq -0xb8(%rbp), %rdx
leaq -0x95(%rbp), %rdi
callq 0x3b860
testb $0x1, %al
jne 0x3b803
movb $0x0, -0x51(%rbp)
jmp 0x3b852
movq -0xb8(%rbp), %rax
addq $0x10, %rax
movq %rax, -0xb8(%rbp)
movq -0xb8(%rbp), %rax
cmpq -0xb0(%rbp), %rax
jb 0x3b7d1
movq -0xa0(%rbp), %rsi
addq -0xb0(%rbp), %rsi
movq -0xa8(%rbp), %rdx
addq -0xb0(%rbp), %rdx
leaq -0x95(%rbp), %rdi
callq 0x3b860
andb $0x1, %al
movb %al, -0x51(%rbp)
movb -0x51(%rbp), %al
andb $0x1, %al
addq $0xc0, %rsp
popq %rbp
retq