// File: Alcaro[P]bridges/arlib/image.cpp
// Function: void image_insert_noov_8888_to_8888<true, 0u>(image&, int, int, image const&)
static inline void image_insert_noov_8888_to_8888(image& target, int32_t x, int32_t y, const image& source)
{
	for (uint32_t yy=0;yy<source.height;yy++)
	{
		uint32_t* __restrict targetpx = target.pixels32 + (y+yy)*target.stride/sizeof(uint32_t) + x;
		uint32_t* __restrict sourcepx = source.pixels32 + yy*source.stride/sizeof(uint32_t);
		
		//strangely enough, doing this slows things down.
		//if (!checksrcalpha && newalpha==-1)
		//{
		//	memcpy(targetpx, sourcepx, sizeof(uint32_t)*source.width);
		//	continue;
		//}
		
		// TODO: enable AUTOVECTORIZE on -O3 - Gcc autovectorizes the post-SIMD loop...
#if defined(__SSE2__) && !defined(AUTOVECTORIZE)
		//SIMD translation of the below
		//this particular loop is trivial to vectorize, but there's no vectorization on -Os
		//(in fact, on -O3, compiler vectorizes the post-SIMD loop that never has more than three iterations... grumble grumble...)
		size_t nsimd = 4;
		
		__m128i* __restrict targetpxw = (__m128i*)targetpx;
		__m128i* __restrict sourcepxw = (__m128i*)sourcepx;
		uint32_t xxew = source.width/nsimd;
		
		__m128i mask_or  = (newalpha == 0xFF000000 ? _mm_set1_epi32(0xFF000000) : _mm_set1_epi32(0x00000000));
		__m128i mask_and = (newalpha == 0x00000000 ? _mm_set1_epi32(0x00FFFFFF) : _mm_set1_epi32(0xFFFFFFFF));
		
		//I could do a few non-SIMD iterations before that and use aligned instructions,
		// but intel intrinsics guide say they're same speed, so yawn
		for (uint32_t xx=0;xx<xxew;xx++)
		{
			__m128i px = _mm_loadu_si128(&sourcepxw[xx]);
			
			//copy sign bit to everywhere
			__m128i mask_local = _mm_srai_epi32(px, 31);
			
			px = _mm_and_si128(mask_and, _mm_or_si128(mask_or, px));
			
			if (checksrcalpha)
			{
				__m128i tpx = _mm_loadu_si128(&targetpxw[xx]);
				//if mask_local bit is set, copy from sp, otherwise from tp
				//this is AVX2 _mm_maskstore_epi32, but that's not available in SSE2
				//but it's also easy to bithack (andnot gives shorter dependency chains than xor)
				px = _mm_or_si128(_mm_and_si128(mask_local, px), _mm_andnot_si128(mask_local, tpx));
			}
			_mm_storeu_si128(&targetpxw[xx], px);
		}
		
		SIMD_LOOP_TAIL
#else
		//the one-pixel loop is needed to handle the last few pixels without overflow
		//if there's no SIMD, just run it for everything
		size_t xxew = 0;
		size_t nsimd = 0;
#endif
		
		for (uint32_t xx=xxew*nsimd;xx<source.width;xx++)
		{
			uint32_t spx = sourcepx[xx];
			uint32_t tpx = targetpx[xx];
			if (!checksrcalpha || (spx&0x80000000)) // for bargb, check sign only, it's the cheapest
			{
				if (newalpha == 0xFF000000 && checksrcalpha) // if spx&0x80000000 is set, the entire 0xFF000000 must be set,
					tpx = spx; // so we can just copy that, and save ourselves an OR
				else if (newalpha != (uint32_t)-1)
					tpx = newalpha | (spx&0x00FFFFFF);
				else
					tpx = spx;
			}
			targetpx[xx] = tpx; // don't inline this into the above, always writing lets compilers vectorize better
		}
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x170, %rsp            # imm = 0x170
movq %rdi, -0x138(%rbp)
movl %esi, -0x13c(%rbp)
movl %edx, -0x140(%rbp)
movq %rcx, -0x148(%rbp)
movl $0x0, -0x14c(%rbp)
movl -0x14c(%rbp), %eax
movq -0x148(%rbp), %rcx
cmpl 0x4(%rcx), %eax
jae 0x19e05
movq -0x138(%rbp), %rdx
movq 0x10(%rdx), %rax
movl -0x140(%rbp), %ecx
movl -0x14c(%rbp), %esi
addl %esi, %ecx
movl 0xc(%rdx), %edx
imull %edx, %ecx
andl $-0x4, %ecx
addq %rcx, %rax
movslq -0x13c(%rbp), %rcx
leaq (%rax,%rcx,4), %rax
movq %rax, -0x158(%rbp)
movq -0x148(%rbp), %rdx
movq 0x10(%rdx), %rax
movl -0x14c(%rbp), %ecx
movl 0xc(%rdx), %edx
imull %edx, %ecx
andl $-0x4, %ecx
addq %rcx, %rax
movq %rax, -0x160(%rbp)
movq $0x4, -0x168(%rbp)
movq -0x158(%rbp), %rax
movq %rax, -0x170(%rbp)
movq -0x160(%rbp), %rax
movq %rax, -0x178(%rbp)
movq -0x148(%rbp), %rax
movl (%rax), %eax
movq -0x168(%rbp), %rcx
xorl %edx, %edx
divq %rcx
movl %eax, -0x17c(%rbp)
movl $0x0, -0x12c(%rbp)
movl -0x12c(%rbp), %eax
movl %eax, -0x24(%rbp)
movl %eax, -0x28(%rbp)
movl %eax, -0x2c(%rbp)
movl %eax, -0x30(%rbp)
movd -0x24(%rbp), %xmm0
movd -0x28(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0x2c(%rbp), %xmm2
movd -0x30(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0x40(%rbp)
movaps -0x40(%rbp), %xmm0
movaps %xmm0, -0x190(%rbp)
movl $0xffffff, -0x130(%rbp) # imm = 0xFFFFFF
movl -0x130(%rbp), %eax
movl %eax, -0x4(%rbp)
movl %eax, -0x8(%rbp)
movl %eax, -0xc(%rbp)
movl %eax, -0x10(%rbp)
movd -0x4(%rbp), %xmm0
movd -0x8(%rbp), %xmm1
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movd -0xc(%rbp), %xmm2
movd -0x10(%rbp), %xmm0
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movdqa %xmm0, -0x20(%rbp)
movdqa -0x20(%rbp), %xmm0
movdqa %xmm0, -0x1a0(%rbp)
movl $0x0, -0x1a4(%rbp)
movl -0x1a4(%rbp), %eax
cmpl -0x17c(%rbp), %eax
jae 0x19d50
movq -0x178(%rbp), %rax
movl -0x1a4(%rbp), %ecx
shlq $0x4, %rcx
addq %rcx, %rax
movq %rax, -0x120(%rbp)
movq -0x120(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0x1c0(%rbp)
movaps -0x1c0(%rbp), %xmm0
movaps %xmm0, -0x110(%rbp)
movl $0x1f, -0x114(%rbp)
movaps -0x110(%rbp), %xmm0
movd -0x114(%rbp), %xmm1
psrad %xmm1, %xmm0
movaps %xmm0, -0x1d0(%rbp)
movaps -0x1a0(%rbp), %xmm1
movaps -0x190(%rbp), %xmm2
movaps -0x1c0(%rbp), %xmm0
movaps %xmm2, -0x90(%rbp)
movaps %xmm0, -0xa0(%rbp)
movaps -0x90(%rbp), %xmm0
movaps -0xa0(%rbp), %xmm2
por %xmm2, %xmm0
movaps %xmm1, -0xd0(%rbp)
movaps %xmm0, -0xe0(%rbp)
movaps -0xd0(%rbp), %xmm0
movaps -0xe0(%rbp), %xmm1
pand %xmm1, %xmm0
movaps %xmm0, -0x1c0(%rbp)
movq -0x170(%rbp), %rax
movl -0x1a4(%rbp), %ecx
shlq $0x4, %rcx
addq %rcx, %rax
movq %rax, -0x128(%rbp)
movq -0x128(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0x1e0(%rbp)
movaps -0x1d0(%rbp), %xmm1
movaps -0x1c0(%rbp), %xmm0
movaps %xmm1, -0xf0(%rbp)
movaps %xmm0, -0x100(%rbp)
movaps -0xf0(%rbp), %xmm1
movaps -0x100(%rbp), %xmm0
pand %xmm0, %xmm1
movaps -0x1d0(%rbp), %xmm2
movaps -0x1e0(%rbp), %xmm0
movaps %xmm2, -0x70(%rbp)
movaps %xmm0, -0x80(%rbp)
movaps -0x70(%rbp), %xmm0
pcmpeqd %xmm2, %xmm2
pxor %xmm2, %xmm0
pand -0x80(%rbp), %xmm0
movdqa %xmm1, -0xb0(%rbp)
movdqa %xmm0, -0xc0(%rbp)
movdqa -0xb0(%rbp), %xmm0
por -0xc0(%rbp), %xmm0
movdqa %xmm0, -0x1c0(%rbp)
movq -0x170(%rbp), %rax
movl -0x1a4(%rbp), %ecx
shlq $0x4, %rcx
addq %rcx, %rax
movdqa -0x1c0(%rbp), %xmm0
movq %rax, -0x48(%rbp)
movdqa %xmm0, -0x60(%rbp)
movdqa -0x60(%rbp), %xmm0
movq -0x48(%rbp), %rax
movdqu %xmm0, (%rax)
movl -0x1a4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1a4(%rbp)
jmp 0x19b95
movl -0x17c(%rbp), %eax
imulq -0x168(%rbp), %rax
movl %eax, -0x1e4(%rbp)
movl -0x1e4(%rbp), %eax
movq -0x148(%rbp), %rcx
cmpl (%rcx), %eax
jae 0x19def
movq -0x160(%rbp), %rax
movl -0x1e4(%rbp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, -0x1e8(%rbp)
movq -0x158(%rbp), %rax
movl -0x1e4(%rbp), %ecx
movl (%rax,%rcx,4), %eax
movl %eax, -0x1ec(%rbp)
movl -0x1e8(%rbp), %eax
andl $0x80000000, %eax       # imm = 0x80000000
cmpl $0x0, %eax
je 0x19dc5
movl -0x1e8(%rbp), %eax
andl $0xffffff, %eax         # imm = 0xFFFFFF
orl $0x0, %eax
movl %eax, -0x1ec(%rbp)
movl -0x1ec(%rbp), %edx
movq -0x158(%rbp), %rax
movl -0x1e4(%rbp), %ecx
movl %edx, (%rax,%rcx,4)
movl -0x1e4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1e4(%rbp)
jmp 0x19d64
jmp 0x19df1
movl -0x14c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14c(%rbp)
jmp 0x19a3f
addq $0x170, %rsp            # imm = 0x170
popq %rbp
retq
nop