// File: /workspace/github_cpp_makefile_star2_O2/phillip-h[P]fractal-gen/lodepng.cpp
// Function: filter(unsigned char*, unsigned char const*, unsigned int, unsigned int, LodePNGColorMode const*, LodePNGEncoderSettings const*)
static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,
                       const LodePNGColorMode* info, const LodePNGEncoderSettings* settings)
{
  /*
  For PNG filter method 0
  out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
  the scanlines with 1 extra byte per scanline
  */

  unsigned bpp = lodepng_get_bpp(info);
  /*the width of a scanline in bytes, not including the filter type*/
  size_t linebytes = (w * bpp + 7) / 8;
  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
  size_t bytewidth = (bpp + 7) / 8;
  const unsigned char* prevline = 0;
  unsigned x, y;
  unsigned error = 0;
  LodePNGFilterStrategy strategy = settings->filter_strategy;

  /*
  There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:
   *  If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e.
      use fixed filtering, with the filter None).
   * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is
     not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply
     all five filters and select the filter that produces the smallest sum of absolute values per row.
  This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true.

  If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed,
  but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum
  heuristic is used.
  */
  if(settings->filter_palette_zero &&
     (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO;

  if(bpp == 0) return 31; /*error: invalid color type*/

  if(strategy == LFS_ZERO)
  {
    for(y = 0; y != h; ++y)
    {
      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
      size_t inindex = linebytes * y;
      out[outindex] = 0; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0);
      prevline = &in[inindex];
    }
  }
  else if(strategy == LFS_MINSUM)
  {
    /*adaptive filtering*/
    size_t sum[5];
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned char type, bestType = 0;

    for(type = 0; type != 5; ++type)
    {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }

    if(!error)
    {
      for(y = 0; y != h; ++y)
      {
        /*try the 5 filter types*/
        for(type = 0; type != 5; ++type)
        {
          filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);

          /*calculate the sum of the result*/
          sum[type] = 0;
          if(type == 0)
          {
            for(x = 0; x != linebytes; ++x) sum[type] += (unsigned char)(attempt[type][x]);
          }
          else
          {
            for(x = 0; x != linebytes; ++x)
            {
              /*For differences, each byte should be treated as signed, values above 127 are negative
              (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.
              This means filtertype 0 is almost never chosen, but that is justified.*/
              unsigned char s = attempt[type][x];
              sum[type] += s < 128 ? s : (255U - s);
            }
          }

          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
          if(type == 0 || sum[type] < smallest)
          {
            bestType = type;
            smallest = sum[type];
          }
        }

        prevline = &in[y * linebytes];

        /*now fill the out values*/
        out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
        for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x];
      }
    }

    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  }
  else if(strategy == LFS_ENTROPY)
  {
    float sum[5];
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    float smallest = 0;
    unsigned type, bestType = 0;
    unsigned count[256];

    for(type = 0; type != 5; ++type)
    {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }

    for(y = 0; y != h; ++y)
    {
      /*try the 5 filter types*/
      for(type = 0; type != 5; ++type)
      {
        filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
        for(x = 0; x != 256; ++x) count[x] = 0;
        for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]];
        ++count[type]; /*the filter type itself is part of the scanline*/
        sum[type] = 0;
        for(x = 0; x != 256; ++x)
        {
          float p = count[x] / (float)(linebytes + 1);
          sum[type] += count[x] == 0 ? 0 : flog2(1 / p) * p;
        }
        /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
        if(type == 0 || sum[type] < smallest)
        {
          bestType = type;
          smallest = sum[type];
        }
      }

      prevline = &in[y * linebytes];

      /*now fill the out values*/
      out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
      for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x];
    }

    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  }
  else if(strategy == LFS_PREDEFINED)
  {
    for(y = 0; y != h; ++y)
    {
      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
      size_t inindex = linebytes * y;
      unsigned char type = settings->predefined_filters[y];
      out[outindex] = type; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
      prevline = &in[inindex];
    }
  }
  else if(strategy == LFS_BRUTE_FORCE)
  {
    /*brute force filter chooser.
    deflate the scanline after every filter attempt to see which one deflates best.
    This is very slow and gives only slightly smaller, sometimes even larger, result*/
    size_t size[5];
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned type = 0, bestType = 0;
    unsigned char* dummy;
    LodePNGCompressSettings zlibsettings = settings->zlibsettings;
    /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,
    to simulate the true case where the tree is the same for the whole image. Sometimes it gives
    better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare
    cases better compression. It does make this a bit less slow, so it's worth doing this.*/
    zlibsettings.btype = 1;
    /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG
    images only, so disable it*/
    zlibsettings.custom_zlib = 0;
    zlibsettings.custom_deflate = 0;
    for(type = 0; type != 5; ++type)
    {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }
    for(y = 0; y != h; ++y) /*try the 5 filter types*/
    {
      for(type = 0; type != 5; ++type)
      {
        unsigned testsize = linebytes;
        /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/

        filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
        size[type] = 0;
        dummy = 0;
        zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings);
        lodepng_free(dummy);
        /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
        if(type == 0 || size[type] < smallest)
        {
          bestType = type;
          smallest = size[type];
        }
      }
      prevline = &in[y * linebytes];
      out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
      for(x = 0; x != linebytes; ++x) out[y * (linebytes + 1) + 1 + x] = attempt[bestType][x];
    }
    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  }
  else return 88; /* unknown filter strategy */

  return error;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x4c8, %rsp            # imm = 0x4C8
movq %rdi, 0x8(%rsp)
movq %r8, %rdi
movq %r9, %r13
movq %r8, %r14
movl %ecx, %ebp
movl %edx, %ebx
movq %rsi, 0x30(%rsp)
callq 0x5f6e
movl 0x38(%r13), %ecx
cmpl $0x0, 0x34(%r13)
je 0xc519
cmpl $0x3, (%r14)
je 0xc517
cmpl $0x7, 0x4(%r14)
ja 0xc519
xorl %ecx, %ecx
testl %eax, %eax
je 0xc598
cmpl $0x4, %ecx
ja 0xc6b0
imull %eax, %ebx
addl $0x7, %eax
leaq 0x1f15(%rip), %rdx      # 0xe448
shrl $0x3, %eax
movq %rax, 0x38(%rsp)
movl %ecx, %eax
movslq (%rdx,%rax,4), %rax
addl $0x7, %ebx
shrl $0x3, %ebx
addq %rdx, %rax
jmpq *%rax
movq 0x8(%rsp), %r13
movq 0x30(%rsp), %rax
leaq 0x1(%rbx), %r15
movl %ebp, %r12d
xorl %ebp, %ebp
xorl %edx, %edx
incq %r13
subq $0x1, %r12
jb 0xcb83
movq 0x38(%rsp), %r8
movq %rax, %r14
movb $0x0, -0x1(%r13)
movq %r13, %rdi
movq %rax, %rsi
movq %rbx, %rcx
xorl %r9d, %r9d
callq 0xcb9a
addq %r15, %r13
leaq (%r14,%rbx), %rax
movq %r14, %rdx
jmp 0xc564
pushq $0x1f
jmp 0xc6b2
leaq 0x1(%rbx), %rax
incq 0x8(%rsp)
movl %ebp, %r12d
xorl %ebp, %ebp
xorl %edx, %edx
movq %rax, 0x40(%rsp)
movq 0x30(%rsp), %rax
cmpq %rbp, %r12
je 0xcb81
movq 0x40(%r13), %rcx
movq 0x8(%rsp), %r15
movq 0x38(%rsp), %r8
movq %rax, %r14
movq %r14, %rsi
movzbl (%rcx,%rbp), %r9d
movq %r15, %rdi
movq %rbx, %rcx
movb %r9b, -0x1(%r15)
callq 0xcb9a
addq 0x40(%rsp), %r15
incq %rbp
leaq (%r14,%rbx), %rax
movq %r14, %rdx
movq %r15, 0x8(%rsp)
jmp 0xc5b9
xorl %r14d, %r14d
cmpq $0x5, %r14
je 0xc6b8
movq %rbx, %rdi
callq 0x21c0
movq %rax, 0x60(%rsp,%r14,8)
incq %r14
testq %rax, %rax
jne 0xc603
jmp 0xc6ac
vmovups (%r13), %ymm0
vmovups 0x10(%r13), %ymm1
xorl %r14d, %r14d
vmovups %ymm0, 0xc0(%rsp)
vxorps %xmm0, %xmm0, %xmm0
vmovups %ymm1, 0xd0(%rsp)
movl $0x1, 0xc0(%rsp)
vmovups %xmm0, 0xd8(%rsp)
cmpq $0x5, %r14
je 0xc8ef
movq %rbx, %rdi
vzeroupper
callq 0x21c0
movq %rax, 0x90(%rsp,%r14,8)
incq %r14
testq %rax, %rax
jne 0xc660
jmp 0xc6ac
xorl %r14d, %r14d
cmpq $0x5, %r14
je 0xca44
movq %rbx, %rdi
callq 0x21c0
movq %rax, 0xc0(%rsp,%r14,8)
incq %r14
testq %rax, %rax
jne 0xc68a
pushq $0x53
jmp 0xc6b2
pushq $0x58
popq %rbp
jmp 0xcb83
movq 0x8(%rsp), %rcx
leaq 0x1(%rbx), %rsi
vxorps %xmm7, %xmm7, %xmm7
movl %ebp, %eax
movq %rax, 0x18(%rsp)
xorl %r8d, %r8d
xorl %r12d, %r12d
xorl %ebp, %ebp
vcvtsi2ss %rsi, %xmm0, %xmm6
movq %rsi, 0x50(%rsp)
vmovss %xmm6, 0x10(%rsp)
leaq 0x1(%rcx), %rdi
movq 0x30(%rsp), %rax
cmpq 0x18(%rsp), %r8
je 0xc8d4
movq %r8, %r13
imulq %rbx, %r13
movq %rdi, 0x28(%rsp)
movq %r8, 0x20(%rsp)
xorl %r15d, %r15d
addq %rax, %r13
cmpq $0x5, %r15
je 0xc88d
movq 0x60(%rsp,%r15,8), %r14
movq 0x38(%rsp), %r8
movzbl %r15b, %r9d
vmovaps %xmm7, 0x40(%rsp)
movq %r13, %rsi
movq %rbp, %rdx
movq %rbx, %rcx
movq %r14, %rdi
callq 0xcb9a
xorl %eax, %eax
cmpq $0x100, %rax            # imm = 0x100
je 0xc755
andl $0x0, 0xc0(%rsp,%rax,4)
incq %rax
jmp 0xc740
vmovss 0x10(%rsp), %xmm6
vmovaps 0x40(%rsp), %xmm7
vmovss 0x25f7(%rip), %xmm8     # 0xed60
vmovss 0x25f3(%rip), %xmm9     # 0xed64
vmovss 0x2607(%rip), %xmm10    # 0xed80
vmovss 0x2603(%rip), %xmm11    # 0xed84
vmovss 0x25df(%rip), %xmm12    # 0xed68
vmovss 0x25eb(%rip), %xmm13    # 0xed7c
vmovss 0x25d3(%rip), %xmm14    # 0xed6c
vmovss 0x25cf(%rip), %xmm15    # 0xed70
vmovss 0x25c9(%rip), %xmm16    # 0xed74
vmovss 0x25c3(%rip), %xmm17    # 0xed78
xorl %eax, %eax
cmpq %rax, %rbx
je 0xc7cd
movzbl (%r14,%rax), %ecx
incq %rax
incl 0xc0(%rsp,%rcx,4)
jmp 0xc7b7
incl 0xc0(%rsp,%r15,4)
vxorps %xmm0, %xmm0, %xmm0
xorl %eax, %eax
cmpq $0x100, %rax            # imm = 0x100
je 0xc868
movl 0xc0(%rsp,%rax,4), %ecx
testl %ecx, %ecx
je 0xc858
vcvtusi2ss %ecx, %xmm18, %xmm1
vxorps %xmm2, %xmm2, %xmm2
vdivss %xmm6, %xmm1, %xmm1
vdivss %xmm1, %xmm8, %xmm3
vucomiss %xmm9, %xmm3
jbe 0xc81d
vaddss %xmm2, %xmm10, %xmm2
vmulss %xmm3, %xmm11, %xmm3
jmp 0xc804
vaddss %xmm2, %xmm8, %xmm2
vmulss %xmm3, %xmm13, %xmm3
vucomiss %xmm12, %xmm3
ja 0xc815
vmulss %xmm3, %xmm3, %xmm4
vmulss %xmm3, %xmm14, %xmm5
vmulss %xmm4, %xmm3, %xmm4
vmulss %xmm5, %xmm3, %xmm5
vdivss %xmm14, %xmm4, %xmm4
vmulss %xmm5, %xmm15, %xmm5
vaddss %xmm5, %xmm4, %xmm4
vfmadd231ss %xmm3, %xmm14, %xmm4 # xmm4 = (xmm14 * xmm3) + xmm4
vaddss %xmm16, %xmm4, %xmm3
vfmadd231ss %xmm17, %xmm3, %xmm2 # xmm2 = (xmm3 * xmm17) + xmm2
vmulss %xmm2, %xmm1, %xmm1
jmp 0xc85c
vxorps %xmm1, %xmm1, %xmm1
vaddss %xmm0, %xmm1, %xmm0
incq %rax
jmp 0xc7db
testq %r15, %r15
sete %al
vucomiss %xmm0, %xmm7
seta %cl
orb %al, %cl
kmovd %ecx, %k1
cmovnel %r15d, %r12d
incq %r15
vmovss %xmm0, %xmm7, %xmm7 {%k1}
jmp 0xc70f
movq 0x50(%rsp), %rsi
movq 0x20(%rsp), %r8
movq 0x8(%rsp), %rcx
movq 0x28(%rsp), %rdi
movq %rsi, %rax
imulq %r8, %rax
movb %r12b, (%rcx,%rax)
movl %r12d, %eax
xorl %ecx, %ecx
cmpq %rcx, %rbx
je 0xc8c6
movq 0x60(%rsp,%rax,8), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
jmp 0xc8b1
incq %r8
addq %rsi, %rdi
movq %r13, %rbp
jmp 0xc6e8
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0xcb81
movq 0x60(%rsp,%rbx,8), %rdi
callq 0x2180
incq %rbx
jmp 0xc8d6
movq 0x8(%rsp), %rcx
leaq 0x1(%rbx), %rsi
movl %ebp, %eax
movq %rax, 0x18(%rsp)
xorl %r8d, %r8d
movq $0x0, 0x10(%rsp)
xorl %ebp, %ebp
xorl %r15d, %r15d
movq %rsi, 0x50(%rsp)
leaq 0x1(%rcx), %rdi
movq 0x30(%rsp), %rax
cmpq 0x18(%rsp), %r8
je 0xca23
movq %r8, 0x20(%rsp)
imulq %rbx, %r8
movq %rdi, 0x28(%rsp)
xorl %r14d, %r14d
xorl %r12d, %r12d
addq %rax, %r8
movq %r8, 0x40(%rsp)
cmpq $0x5, %r12
je 0xc9d2
movq 0x90(%rsp,%r12,8), %r13
movq 0x40(%rsp), %rsi
movq 0x10(%rsp), %rdx
movq 0x38(%rsp), %r8
movzbl %r12b, %r9d
movq %rbx, %rcx
movq %r13, %rdi
vzeroupper
callq 0xcb9a
andq $0x0, 0x60(%rsp,%r12,8)
andq $0x0, 0x58(%rsp)
leaq 0x60(%rsp,%r14), %rsi
leaq 0x58(%rsp), %rdi
leaq 0xc0(%rsp), %r8
movq %r13, %rdx
movq %rbx, %rcx
callq 0xab83
movq 0x58(%rsp), %rdi
callq 0x2180
movq 0x60(%rsp,%r12,8), %rcx
testq %r14, %r14
sete %al
cmpq %rbp, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %rbp
cmovnel %r12d, %r15d
incq %r12
addq $0x8, %r14
jmp 0xc945
movq 0x50(%rsp), %rsi
movq 0x20(%rsp), %r8
movq 0x8(%rsp), %rcx
movq 0x28(%rsp), %rdi
movq %rsi, %rax
imulq %r8, %rax
movb %r15b, (%rcx,%rax)
movl %r15d, %eax
xorl %ecx, %ecx
cmpq %rcx, %rbx
je 0xca0e
movq 0x90(%rsp,%rax,8), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
jmp 0xc9f6
movq 0x40(%rsp), %rax
incq %r8
addq %rsi, %rdi
movq %rax, 0x10(%rsp)
jmp 0xc919
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0xcb81
movq 0x90(%rsp,%rbx,8), %rdi
vzeroupper
callq 0x2180
incq %rbx
jmp 0xca25
leaq 0x1(%rbx), %rax
xorl %edi, %edi
xorl %r15d, %r15d
movq $0x0, 0x40(%rsp)
movq %rax, 0x10(%rsp)
movl %ebp, %eax
movq %rax, 0x18(%rsp)
movq 0x8(%rsp), %rax
leaq 0x1(%rax), %rsi
xorl %eax, %eax
cmpq 0x18(%rsp), %rdi
je 0xcb67
movq %rdi, %r13
imulq %rbx, %r13
addq 0x30(%rsp), %r13
xorl %ebp, %ebp
movq %rsi, 0x28(%rsp)
movq %rdi, 0x20(%rsp)
movzbl %al, %r12d
cmpq $0x5, %rbp
je 0xcb1f
movq 0xc0(%rsp,%rbp,8), %r14
movq 0x40(%rsp), %rdx
movq 0x38(%rsp), %r8
movzbl %bpl, %r9d
movq %r13, %rsi
movq %rbx, %rcx
movq %r14, %rdi
callq 0xcb9a
xorl %eax, %eax
xorl %ecx, %ecx
testq %rbp, %rbp
jne 0xcaf5
cmpq %rcx, %rbx
je 0xcafa
movzbl (%r14,%rcx), %edx
incq %rcx
addq %rdx, %rax
jmp 0xcacb
movzbl (%r14,%rcx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
incq %rcx
addq %rsi, %rax
cmpq %rcx, %rbx
jne 0xcadd
testq %rbp, %rbp
sete %cl
cmpq %r15, %rax
setb %dl
orb %cl, %dl
movzbl %bpl, %ecx
cmovnel %ecx, %r12d
cmovneq %rax, %r15
incq %rbp
movl %r12d, %eax
jmp 0xca90
movq 0x10(%rsp), %rcx
movq 0x20(%rsp), %rdi
movq 0x8(%rsp), %rdx
movq 0x28(%rsp), %rsi
imulq %rdi, %rcx
movb %r12b, (%rdx,%rcx)
xorl %ecx, %ecx
cmpq %rcx, %rbx
je 0xcb55
movq 0xc0(%rsp,%r12,8), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rsi,%rcx)
incq %rcx
jmp 0xcb3d
addq 0x10(%rsp), %rsi
incq %rdi
movq %r13, 0x40(%rsp)
jmp 0xca6d
xorl %ebx, %ebx
cmpq $0x5, %rbx
je 0xcb81
movq 0xc0(%rsp,%rbx,8), %rdi
callq 0x2180
incq %rbx
jmp 0xcb69
xorl %ebp, %ebp
movl %ebp, %eax
addq $0x4c8, %rsp            # imm = 0x4C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
vzeroupper
retq