// File: tomfunkhouser[P]gaps/pkgs/jpeg/jcsample.c
// Function: h2v2_smooth_downsample
METHODDEF(void)
h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
			JSAMPARRAY input_data, JSAMPARRAY output_data)
{
  int inrow, outrow;
  JDIMENSION colctr;
  JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
  register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
  INT32 membersum, neighsum, memberscale, neighscale;

  /* Expand input data enough to let all the output samples be generated
   * by the standard loop.  Special-casing padded output would be more
   * efficient.
   */
  expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
		    cinfo->image_width, output_cols * 2);

  /* We don't bother to form the individual "smoothed" input pixel values;
   * we can directly compute the output which is the average of the four
   * smoothed values.  Each of the four member pixels contributes a fraction
   * (1-8*SF) to its own smoothed image and a fraction SF to each of the three
   * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
   * output.  The four corner-adjacent neighbor pixels contribute a fraction
   * SF to just one smoothed pixel, or SF/4 to the final output; while the
   * eight edge-adjacent neighbors contribute SF to each of two smoothed
   * pixels, or SF/2 overall.  In order to use integer arithmetic, these
   * factors are scaled by 2^16 = 65536.
   * Also recall that SF = smoothing_factor / 1024.
   */

  memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */
  neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */

  inrow = 0;
  for (outrow = 0; outrow < compptr->v_samp_factor; outrow++) {
    outptr = output_data[outrow];
    inptr0 = input_data[inrow];
    inptr1 = input_data[inrow+1];
    above_ptr = input_data[inrow-1];
    below_ptr = input_data[inrow+2];

    /* Special case for first column: pretend column -1 is same as column 0 */
    membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
		GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
    neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
	       GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
	       GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
	       GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
    neighsum += neighsum;
    neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
		GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
    membersum = membersum * memberscale + neighsum * neighscale;
    *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
    inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;

    for (colctr = output_cols - 2; colctr > 0; colctr--) {
      /* sum of pixels directly mapped to this output element */
      membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
		  GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
      /* sum of edge-neighbor pixels */
      neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
		 GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
		 GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
		 GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
      /* The edge-neighbors count twice as much as corner-neighbors */
      neighsum += neighsum;
      /* Add in the corner-neighbors */
      neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
		  GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
      /* form final output scaled up by 2^16 */
      membersum = membersum * memberscale + neighsum * neighscale;
      /* round, descale and output it */
      *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
      inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
    }

    /* Special case for last column */
    membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
		GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
    neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
	       GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
	       GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
	       GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
    neighsum += neighsum;
    neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
		GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
    membersum = membersum * memberscale + neighsum * neighscale;
    *outptr = (JSAMPLE) ((membersum + 32768) >> 16);

    inrow += 2;
  }
}

// Assembly:
subq $0x78, %rsp
movq %rdi, 0x70(%rsp)
movq %rsi, 0x68(%rsp)
movq %rdx, 0x60(%rsp)
movq %rcx, 0x58(%rsp)
movq 0x68(%rsp), %rax
movl 0x1c(%rax), %eax
shll $0x3, %eax
movl %eax, 0x48(%rsp)
movq 0x60(%rsp), %rdi
addq $-0x8, %rdi
movq 0x70(%rsp), %rax
movl 0x13c(%rax), %esi
addl $0x2, %esi
movq 0x70(%rsp), %rax
movl 0x30(%rax), %edx
movl 0x48(%rsp), %ecx
shll %ecx
callq 0xdd370
movq 0x70(%rsp), %rax
imull $0x50, 0x110(%rax), %ecx
movl $0x4000, %eax           # imm = 0x4000
subl %ecx, %eax
cltq
movq %rax, 0x8(%rsp)
movq 0x70(%rsp), %rax
movl 0x110(%rax), %eax
shll $0x4, %eax
cltq
movq %rax, (%rsp)
movl $0x0, 0x54(%rsp)
movl $0x0, 0x50(%rsp)
movl 0x50(%rsp), %eax
movq 0x68(%rsp), %rcx
cmpl 0xc(%rcx), %eax
jge 0xdd020
movq 0x58(%rsp), %rax
movslq 0x50(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x20(%rsp)
movq 0x60(%rsp), %rax
movslq 0x54(%rsp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x40(%rsp)
movq 0x60(%rsp), %rax
movl 0x54(%rsp), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x38(%rsp)
movq 0x60(%rsp), %rax
movl 0x54(%rsp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x30(%rsp)
movq 0x60(%rsp), %rax
movl 0x54(%rsp), %ecx
addl $0x2, %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, 0x28(%rsp)
movq 0x40(%rsp), %rax
movzbl (%rax), %eax
movq 0x40(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
cltq
movq %rax, 0x18(%rsp)
movq 0x30(%rsp), %rax
movzbl (%rax), %eax
movq 0x30(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x40(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x40(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
cltq
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
addq 0x10(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x30(%rsp), %rax
movzbl (%rax), %eax
movq 0x30(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
cltq
addq 0x10(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x18(%rsp), %rax
imulq 0x8(%rsp), %rax
movq 0x10(%rsp), %rcx
imulq (%rsp), %rcx
addq %rcx, %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rax
addq $0x8000, %rax           # imm = 0x8000
sarq $0x10, %rax
movb %al, %cl
movq 0x20(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, 0x20(%rsp)
movb %cl, (%rax)
movq 0x40(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x40(%rsp)
movq 0x38(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x38(%rsp)
movq 0x30(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x30(%rsp)
movq 0x28(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x28(%rsp)
movl 0x48(%rsp), %eax
subl $0x2, %eax
movl %eax, 0x4c(%rsp)
cmpl $0x0, 0x4c(%rsp)
jbe 0xdcf01
movq 0x40(%rsp), %rax
movzbl (%rax), %eax
movq 0x40(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
cltq
movq %rax, 0x18(%rsp)
movq 0x30(%rsp), %rax
movzbl (%rax), %eax
movq 0x30(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x40(%rsp), %rcx
movzbl -0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x40(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl -0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
cltq
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
addq 0x10(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x30(%rsp), %rax
movzbl -0x1(%rax), %eax
movq 0x30(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl -0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl 0x2(%rcx), %ecx
addl %ecx, %eax
cltq
addq 0x10(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x18(%rsp), %rax
imulq 0x8(%rsp), %rax
movq 0x10(%rsp), %rcx
imulq (%rsp), %rcx
addq %rcx, %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rax
addq $0x8000, %rax           # imm = 0x8000
sarq $0x10, %rax
movb %al, %cl
movq 0x20(%rsp), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, 0x20(%rsp)
movb %cl, (%rax)
movq 0x40(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x40(%rsp)
movq 0x38(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x38(%rsp)
movq 0x30(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x30(%rsp)
movq 0x28(%rsp), %rax
addq $0x2, %rax
movq %rax, 0x28(%rsp)
movl 0x4c(%rsp), %eax
addl $-0x1, %eax
movl %eax, 0x4c(%rsp)
jmp 0xdcd9e
movq 0x40(%rsp), %rax
movzbl (%rax), %eax
movq 0x40(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
cltq
movq %rax, 0x18(%rsp)
movq 0x30(%rsp), %rax
movzbl (%rax), %eax
movq 0x30(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl (%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x40(%rsp), %rcx
movzbl -0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x40(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl -0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x38(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
cltq
movq %rax, 0x10(%rsp)
movq 0x10(%rsp), %rax
addq 0x10(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x30(%rsp), %rax
movzbl -0x1(%rax), %eax
movq 0x30(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl -0x1(%rcx), %ecx
addl %ecx, %eax
movq 0x28(%rsp), %rcx
movzbl 0x1(%rcx), %ecx
addl %ecx, %eax
cltq
addq 0x10(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x18(%rsp), %rax
imulq 0x8(%rsp), %rax
movq 0x10(%rsp), %rcx
imulq (%rsp), %rcx
addq %rcx, %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rax
addq $0x8000, %rax           # imm = 0x8000
sarq $0x10, %rax
movb %al, %cl
movq 0x20(%rsp), %rax
movb %cl, (%rax)
movl 0x54(%rsp), %eax
addl $0x2, %eax
movl %eax, 0x54(%rsp)
movl 0x50(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x50(%rsp)
jmp 0xdcbcf
addq $0x78, %rsp
retq
nopw %cs:(%rax,%rax)