// File: alan0201tw[P]RayTracer/include/stb_image.h
// Function: stbi__resample_row_hv_2_simd(unsigned char*, unsigned char*, unsigned char*, int, int)
static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
{
   // need to generate 2x2 samples for every one in input
   int i=0,t0,t1;

   if (w == 1) {
      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
      return out;
   }

   t1 = 3*in_near[0] + in_far[0];
   // process groups of 8 pixels for as long as we can.
   // note we can't handle the last pixel in a row in this loop
   // because we need to handle the filter boundary conditions.
   for (; i < ((w-1) & ~7); i += 8) {
#if defined(STBI_SSE2)
      // load and perform the vertical filtering pass
      // this uses 3*x + y = 4*x + (y - x)
      __m128i zero  = _mm_setzero_si128();
      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
      __m128i diff  = _mm_sub_epi16(farw, nearw);
      __m128i nears = _mm_slli_epi16(nearw, 2);
      __m128i curr  = _mm_add_epi16(nears, diff); // current row

      // horizontal filter works the same based on shifted vers of current
      // row. "prev" is current row shifted right by 1 pixel; we need to
      // insert the previous pixel value (from t1).
      // "next" is current row shifted left by 1 pixel, with first pixel
      // of next block of 8 pixels added in.
      __m128i prv0 = _mm_slli_si128(curr, 2);
      __m128i nxt0 = _mm_srli_si128(curr, 2);
      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);

      // horizontal filter, polyphase implementation since it's convenient:
      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
      // note the shared term.
      __m128i bias  = _mm_set1_epi16(8);
      __m128i curs = _mm_slli_epi16(curr, 2);
      __m128i prvd = _mm_sub_epi16(prev, curr);
      __m128i nxtd = _mm_sub_epi16(next, curr);
      __m128i curb = _mm_add_epi16(curs, bias);
      __m128i even = _mm_add_epi16(prvd, curb);
      __m128i odd  = _mm_add_epi16(nxtd, curb);

      // interleave even and odd pixels, then undo scaling.
      __m128i int0 = _mm_unpacklo_epi16(even, odd);
      __m128i int1 = _mm_unpackhi_epi16(even, odd);
      __m128i de0  = _mm_srli_epi16(int0, 4);
      __m128i de1  = _mm_srli_epi16(int1, 4);

      // pack and write output
      __m128i outv = _mm_packus_epi16(de0, de1);
      _mm_storeu_si128((__m128i *) (out + i*2), outv);
#elif defined(STBI_NEON)
      // load and perform the vertical filtering pass
      // this uses 3*x + y = 4*x + (y - x)
      uint8x8_t farb  = vld1_u8(in_far + i);
      uint8x8_t nearb = vld1_u8(in_near + i);
      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
      int16x8_t curr  = vaddq_s16(nears, diff); // current row

      // horizontal filter works the same based on shifted vers of current
      // row. "prev" is current row shifted right by 1 pixel; we need to
      // insert the previous pixel value (from t1).
      // "next" is current row shifted left by 1 pixel, with first pixel
      // of next block of 8 pixels added in.
      int16x8_t prv0 = vextq_s16(curr, curr, 7);
      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);

      // horizontal filter, polyphase implementation since it's convenient:
      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
      // note the shared term.
      int16x8_t curs = vshlq_n_s16(curr, 2);
      int16x8_t prvd = vsubq_s16(prev, curr);
      int16x8_t nxtd = vsubq_s16(next, curr);
      int16x8_t even = vaddq_s16(curs, prvd);
      int16x8_t odd  = vaddq_s16(curs, nxtd);

      // undo scaling and round, then store with even/odd phases interleaved
      uint8x8x2_t o;
      o.val[0] = vqrshrun_n_s16(even, 4);
      o.val[1] = vqrshrun_n_s16(odd,  4);
      vst2_u8(out + i*2, o);
#endif

      // "previous" value for next iter
      t1 = 3*in_near[i+7] + in_far[i+7];
   }

   t0 = t1;
   t1 = 3*in_near[i] + in_far[i];
   out[i*2] = stbi__div16(3*t1 + t0 + 8);

   for (++i; i < w; ++i) {
      t0 = t1;
      t1 = 3*in_near[i]+in_far[i];
      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
   }
   out[w*2-1] = stbi__div4(t1+2);

   STBI_NOTUSED(hs);

   return out;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x3d0, %rsp            # imm = 0x3D0
movq %rdi, -0x290(%rbp)
movq %rsi, -0x298(%rbp)
movq %rdx, -0x2a0(%rbp)
movl %ecx, -0x2a4(%rbp)
movl %r8d, -0x2a8(%rbp)
movl $0x0, -0x2ac(%rbp)
cmpl $0x1, -0x2a4(%rbp)
jne 0x64577
movq -0x298(%rbp), %rax
movzbl (%rax), %eax
imull $0x3, %eax, %eax
movq -0x2a0(%rbp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
addl $0x2, %eax
sarl $0x2, %eax
movb %al, %cl
movq -0x290(%rbp), %rax
movb %cl, 0x1(%rax)
movq -0x290(%rbp), %rax
movb %cl, (%rax)
movq -0x290(%rbp), %rax
movq %rax, -0x288(%rbp)
jmp 0x64c96
movq -0x298(%rbp), %rax
movzbl (%rax), %eax
imull $0x3, %eax, %eax
movq -0x2a0(%rbp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movl %eax, -0x2b4(%rbp)
movl -0x2ac(%rbp), %eax
movl -0x2a4(%rbp), %ecx
subl $0x1, %ecx
andl $-0x8, %ecx
cmpl %ecx, %eax
jge 0x64b36
xorps %xmm0, %xmm0
movaps %xmm0, -0x160(%rbp)
movaps -0x160(%rbp), %xmm0
movaps %xmm0, -0x2d0(%rbp)
movq -0x2a0(%rbp), %rax
movslq -0x2ac(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
movq (%rax), %xmm0
movaps %xmm0, -0xa0(%rbp)
movaps -0xa0(%rbp), %xmm0
movaps %xmm0, -0x2e0(%rbp)
movq -0x298(%rbp), %rax
movslq -0x2ac(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0xa8(%rbp)
movq -0xa8(%rbp), %rax
movq (%rax), %xmm0
movaps %xmm0, -0xc0(%rbp)
movaps -0xc0(%rbp), %xmm0
movaps %xmm0, -0x2f0(%rbp)
movaps -0x2e0(%rbp), %xmm1
movaps -0x2d0(%rbp), %xmm0
movaps %xmm1, -0x100(%rbp)
movaps %xmm0, -0x110(%rbp)
movaps -0x100(%rbp), %xmm0
movaps -0x110(%rbp), %xmm1
punpcklbw %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3],xmm0[4],xmm1[4],xmm0[5],xmm1[5],xmm0[6],xmm1[6],xmm0[7],xmm1[7]
movaps %xmm0, -0x300(%rbp)
movaps -0x2f0(%rbp), %xmm1
movaps -0x2d0(%rbp), %xmm0
movaps %xmm1, -0x120(%rbp)
movaps %xmm0, -0x130(%rbp)
movaps -0x120(%rbp), %xmm0
movaps -0x130(%rbp), %xmm1
punpcklbw %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3],xmm0[4],xmm1[4],xmm0[5],xmm1[5],xmm0[6],xmm1[6],xmm0[7],xmm1[7]
movaps %xmm0, -0x310(%rbp)
movaps -0x300(%rbp), %xmm1
movaps -0x310(%rbp), %xmm0
movaps %xmm1, -0x170(%rbp)
movaps %xmm0, -0x180(%rbp)
movaps -0x170(%rbp), %xmm0
movaps -0x180(%rbp), %xmm1
psubw %xmm1, %xmm0
movaps %xmm0, -0x320(%rbp)
movaps -0x310(%rbp), %xmm0
movaps %xmm0, -0x10(%rbp)
movl $0x2, -0x14(%rbp)
movaps -0x10(%rbp), %xmm0
movd -0x14(%rbp), %xmm1
psllw %xmm1, %xmm0
movaps %xmm0, -0x330(%rbp)
movaps -0x330(%rbp), %xmm1
movaps -0x320(%rbp), %xmm0
movaps %xmm1, -0x1d0(%rbp)
movaps %xmm0, -0x1e0(%rbp)
movaps -0x1d0(%rbp), %xmm0
movaps -0x1e0(%rbp), %xmm1
paddw %xmm1, %xmm0
movaps %xmm0, -0x340(%rbp)
movaps -0x340(%rbp), %xmm0
pslldq $0x2, %xmm0             # xmm0 = zero,zero,xmm0[0,1,2,3,4,5,6,7,8,9,10,11,12,13]
movaps %xmm0, -0x350(%rbp)
movaps -0x340(%rbp), %xmm0
psrldq $0x2, %xmm0             # xmm0 = xmm0[2,3,4,5,6,7,8,9,10,11,12,13,14,15],zero,zero
movaps %xmm0, -0x360(%rbp)
movaps -0x350(%rbp), %xmm0
movl -0x2b4(%rbp), %eax
pinsrw $0x0, %eax, %xmm0
movaps %xmm0, -0x370(%rbp)
movaps -0x360(%rbp), %xmm0
movq -0x298(%rbp), %rax
movslq -0x2ac(%rbp), %rdx
movzbl 0x8(%rax,%rdx), %ecx
movl %ecx, %eax
leal (%rax,%rax,2), %eax
movq -0x2a0(%rbp), %rcx
movzbl 0x8(%rcx,%rdx), %ecx
addl %ecx, %eax
pinsrw $0x7, %eax, %xmm0
movaps %xmm0, -0x380(%rbp)
movw $0x8, -0xe2(%rbp)
movw -0xe2(%rbp), %ax
movw %ax, -0x442(%rbp)
movw %ax, -0xc2(%rbp)
movw %ax, -0xc4(%rbp)
movw %ax, -0xc6(%rbp)
movw %ax, -0xc8(%rbp)
movw %ax, -0xca(%rbp)
movw %ax, -0xcc(%rbp)
movw %ax, -0xce(%rbp)
movw %ax, -0xd0(%rbp)
movzwl -0xc2(%rbp), %eax
movd %eax, %xmm1
movzwl -0xc4(%rbp), %eax
movd %eax, %xmm0
punpcklwd %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
movzwl -0xc6(%rbp), %eax
movd %eax, %xmm2
movzwl -0xc8(%rbp), %eax
movd %eax, %xmm1
punpcklwd %xmm2, %xmm1    # xmm1 = xmm1[0],xmm2[0],xmm1[1],xmm2[1],xmm1[2],xmm2[2],xmm1[3],xmm2[3]
punpckldq %xmm0, %xmm1    # xmm1 = xmm1[0],xmm0[0],xmm1[1],xmm0[1]
movzwl -0xca(%rbp), %eax
movd %eax, %xmm0
movzwl -0xcc(%rbp), %eax
movd %eax, %xmm2
punpcklwd %xmm0, %xmm2    # xmm2 = xmm2[0],xmm0[0],xmm2[1],xmm0[1],xmm2[2],xmm0[2],xmm2[3],xmm0[3]
movzwl -0xce(%rbp), %eax
movd %eax, %xmm3
movzwl -0xd0(%rbp), %eax
movd %eax, %xmm0
punpcklwd %xmm3, %xmm0    # xmm0 = xmm0[0],xmm3[0],xmm0[1],xmm3[1],xmm0[2],xmm3[2],xmm0[3],xmm3[3]
punpckldq %xmm2, %xmm0    # xmm0 = xmm0[0],xmm2[0],xmm0[1],xmm2[1]
punpcklqdq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0]
movaps %xmm0, -0xe0(%rbp)
movaps -0xe0(%rbp), %xmm0
movaps %xmm0, -0x390(%rbp)
movaps -0x340(%rbp), %xmm0
movaps %xmm0, -0x30(%rbp)
movl $0x2, -0x34(%rbp)
movaps -0x30(%rbp), %xmm0
movd -0x34(%rbp), %xmm1
psllw %xmm1, %xmm0
movaps %xmm0, -0x3a0(%rbp)
movaps -0x370(%rbp), %xmm1
movaps -0x340(%rbp), %xmm0
movaps %xmm1, -0x190(%rbp)
movaps %xmm0, -0x1a0(%rbp)
movaps -0x190(%rbp), %xmm0
movaps -0x1a0(%rbp), %xmm1
psubw %xmm1, %xmm0
movaps %xmm0, -0x3b0(%rbp)
movaps -0x380(%rbp), %xmm1
movaps -0x340(%rbp), %xmm0
movaps %xmm1, -0x1b0(%rbp)
movaps %xmm0, -0x1c0(%rbp)
movaps -0x1b0(%rbp), %xmm0
movaps -0x1c0(%rbp), %xmm1
psubw %xmm1, %xmm0
movaps %xmm0, -0x3c0(%rbp)
movaps -0x3a0(%rbp), %xmm1
movaps -0x390(%rbp), %xmm0
movaps %xmm1, -0x1f0(%rbp)
movaps %xmm0, -0x200(%rbp)
movaps -0x1f0(%rbp), %xmm0
movaps -0x200(%rbp), %xmm1
paddw %xmm1, %xmm0
movaps %xmm0, -0x3d0(%rbp)
movaps -0x3b0(%rbp), %xmm1
movaps -0x3d0(%rbp), %xmm0
movaps %xmm1, -0x210(%rbp)
movaps %xmm0, -0x220(%rbp)
movaps -0x210(%rbp), %xmm0
movaps -0x220(%rbp), %xmm1
paddw %xmm1, %xmm0
movaps %xmm0, -0x3e0(%rbp)
movaps -0x3c0(%rbp), %xmm1
movaps -0x3d0(%rbp), %xmm0
movaps %xmm1, -0x230(%rbp)
movaps %xmm0, -0x240(%rbp)
movaps -0x230(%rbp), %xmm0
movaps -0x240(%rbp), %xmm1
paddw %xmm1, %xmm0
movaps %xmm0, -0x3f0(%rbp)
movaps -0x3e0(%rbp), %xmm1
movaps -0x3f0(%rbp), %xmm0
movaps %xmm1, -0x270(%rbp)
movaps %xmm0, -0x280(%rbp)
movaps -0x270(%rbp), %xmm0
movaps -0x280(%rbp), %xmm1
punpcklwd %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1],xmm0[2],xmm1[2],xmm0[3],xmm1[3]
movaps %xmm0, -0x400(%rbp)
movaps -0x3e0(%rbp), %xmm1
movaps -0x3f0(%rbp), %xmm0
movaps %xmm1, -0x250(%rbp)
movaps %xmm0, -0x260(%rbp)
movaps -0x250(%rbp), %xmm0
movaps -0x260(%rbp), %xmm1
punpckhwd %xmm1, %xmm0    # xmm0 = xmm0[4],xmm1[4],xmm0[5],xmm1[5],xmm0[6],xmm1[6],xmm0[7],xmm1[7]
movdqa %xmm0, -0x410(%rbp)
movdqa -0x400(%rbp), %xmm0
movdqa %xmm0, -0x60(%rbp)
movl $0x4, -0x64(%rbp)
movdqa -0x60(%rbp), %xmm0
movl -0x64(%rbp), %eax
movd %eax, %xmm1
psrlw %xmm1, %xmm0
movdqa %xmm0, -0x420(%rbp)
movdqa -0x410(%rbp), %xmm0
movdqa %xmm0, -0x80(%rbp)
movl $0x4, -0x84(%rbp)
movdqa -0x80(%rbp), %xmm0
movl -0x84(%rbp), %eax
movd %eax, %xmm1
psrlw %xmm1, %xmm0
movdqa %xmm0, -0x430(%rbp)
movdqa -0x420(%rbp), %xmm1
movdqa -0x430(%rbp), %xmm0
movdqa %xmm1, -0x140(%rbp)
movdqa %xmm0, -0x150(%rbp)
movdqa -0x140(%rbp), %xmm0
movdqa -0x150(%rbp), %xmm1
packuswb %xmm1, %xmm0
movdqa %xmm0, -0x440(%rbp)
movq -0x290(%rbp), %rax
movl -0x2ac(%rbp), %ecx
shll %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movdqa -0x440(%rbp), %xmm0
movq %rax, -0x40(%rbp)
movdqa %xmm0, -0x50(%rbp)
movdqa -0x50(%rbp), %xmm0
movq -0x40(%rbp), %rax
movdqu %xmm0, (%rax)
movq -0x298(%rbp), %rax
movl -0x2ac(%rbp), %ecx
addl $0x7, %ecx
movslq %ecx, %rcx
movzbl (%rax,%rcx), %eax
imull $0x3, %eax, %eax
movq -0x2a0(%rbp), %rcx
movl -0x2ac(%rbp), %edx
addl $0x7, %edx
movslq %edx, %rdx
movzbl (%rcx,%rdx), %ecx
addl %ecx, %eax
movl %eax, -0x2b4(%rbp)
movl -0x2ac(%rbp), %eax
addl $0x8, %eax
movl %eax, -0x2ac(%rbp)
jmp 0x64596
movl -0x2b4(%rbp), %eax
movl %eax, -0x2b0(%rbp)
movq -0x298(%rbp), %rax
movslq -0x2ac(%rbp), %rcx
movzbl (%rax,%rcx), %eax
imull $0x3, %eax, %eax
movq -0x2a0(%rbp), %rcx
movslq -0x2ac(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
addl %ecx, %eax
movl %eax, -0x2b4(%rbp)
imull $0x3, -0x2b4(%rbp), %eax
addl -0x2b0(%rbp), %eax
addl $0x8, %eax
sarl $0x4, %eax
movb %al, %dl
movq -0x290(%rbp), %rax
movl -0x2ac(%rbp), %ecx
shll %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x2ac(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2ac(%rbp)
movl -0x2ac(%rbp), %eax
cmpl -0x2a4(%rbp), %eax
jge 0x64c62
movl -0x2b4(%rbp), %eax
movl %eax, -0x2b0(%rbp)
movq -0x298(%rbp), %rax
movslq -0x2ac(%rbp), %rcx
movzbl (%rax,%rcx), %eax
imull $0x3, %eax, %eax
movq -0x2a0(%rbp), %rcx
movslq -0x2ac(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
addl %ecx, %eax
movl %eax, -0x2b4(%rbp)
imull $0x3, -0x2b0(%rbp), %eax
addl -0x2b4(%rbp), %eax
addl $0x8, %eax
sarl $0x4, %eax
movb %al, %dl
movq -0x290(%rbp), %rax
movl -0x2ac(%rbp), %ecx
shll %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
imull $0x3, -0x2b4(%rbp), %eax
addl -0x2b0(%rbp), %eax
addl $0x8, %eax
sarl $0x4, %eax
movb %al, %dl
movq -0x290(%rbp), %rax
movl -0x2ac(%rbp), %ecx
shll %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movl -0x2ac(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2ac(%rbp)
jmp 0x64baa
movl -0x2b4(%rbp), %eax
addl $0x2, %eax
sarl $0x2, %eax
movb %al, %dl
movq -0x290(%rbp), %rax
movl -0x2a4(%rbp), %ecx
shll %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movq -0x290(%rbp), %rax
movq %rax, -0x288(%rbp)
movq -0x288(%rbp), %rax
addq $0x3d0, %rsp            # imm = 0x3D0
popq %rbp
retq
nopw %cs:(%rax,%rax)