// File: /workspace/github_cpp_makefile_star2_O3/lvandeve[P]lodepng/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* color, const LodePNGEncoderSettings* settings) {
  /*
  For PNG filter method 0
  out must be a buffer with as size: h + (w * h * bpp + 7u) / 8u, because there are
  the scanlines with 1 extra byte per scanline
  */

  unsigned bpp = lodepng_get_bpp(color);
  /*the width of a scanline in bytes, not including the filter type*/
  size_t linebytes = lodepng_get_raw_size_idat(w, 1, bpp) - 1u;

  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
  size_t bytewidth = (bpp + 7u) / 8u;
  const unsigned char* prevline = 0;
  unsigned x, y;
  unsigned error = 0;
  LodePNGFilterStrategy strategy = settings->filter_strategy;

  if(settings->filter_palette_zero && (color->colortype == LCT_PALETTE || color->bitdepth < 8)) {
    /*if the filter_palette_zero setting is enabled, override the filter strategy with
    zero for all scanlines for palette and less-than-8-bitdepth images*/
    strategy = LFS_ZERO;
  }

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

  if(strategy >= LFS_ZERO && strategy <= LFS_FOUR) {
    unsigned char type = (unsigned char)strategy;
    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] = type; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
      prevline = &in[inindex];
    }
  } else if(strategy == LFS_MINSUM) {
    /*adaptive filtering: independently for each row, try all five filter types and select the one that produces the
    smallest sum of absolute values per row.*/
    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]) error = 83; /*alloc fail*/
    }

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

          /*calculate the sum of the result*/
          if(type == 0) {
            for(x = 0; x != linebytes; ++x) sum += (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 += 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 < smallest) {
            bestType = type;
            smallest = sum;
          }
        }

        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) {
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t bestSum = 0;
    unsigned type, bestType = 0;
    unsigned count[256];

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

    if(!error) {
      for(y = 0; y != h; ++y) {
        /*try the 5 filter types*/
        for(type = 0; type != 5; ++type) {
          size_t sum = 0;
          filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
          lodepng_memset(count, 0, 256 * sizeof(*count));
          for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]];
          ++count[type]; /*the filter type itself is part of the scanline*/
          for(x = 0; x != 256; ++x) {
            sum += ilog2i(count[x]);
          }
          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
          if(type == 0 || sum > bestSum) {
            bestType = type;
            bestSum = sum;
          }
        }

        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;
    lodepng_memcpy(&zlibsettings, &settings->zlibsettings, sizeof(LodePNGCompressSettings));
    /*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]) error = 83; /*alloc fail*/
    }
    if(!error) {
      for(y = 0; y != h; ++y) /*try the 5 filter types*/ {
        for(type = 0; type != 5; ++type) {
          unsigned testsize = (unsigned)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
movl %r9d, %r13d
movl %r8d, %ebp
movl %ecx, %r15d
movl %edx, %r12d
movq %rsi, 0x28(%rsp)
movq %rdi, 0x18(%rsp)
movq 0x500(%rsp), %rbx
movl %r8d, %edi
callq 0x5a40
imull %r13d, %eax
movl %r12d, %ecx
shrl $0x3, %ecx
imulq %rax, %rcx
andl $0x7, %r12d
imull %eax, %r12d
addl $0x7, %r12d
shrl $0x3, %r12d
leaq (%rcx,%r12), %r14
leal 0x7(%rax), %r8d
shrl $0x3, %r8d
movl 0x38(%rbx), %edx
cmpl $0x0, 0x34(%rbx)
je 0xfecf
cmpl $0x3, %ebp
sete %sil
cmpl $0x8, %r13d
setb %dil
orb %sil, %dil
je 0xfecf
xorl %edx, %edx
testl %eax, %eax
movq 0x18(%rsp), %r13
jne 0xfedd
jmp 0xff34
testl %eax, %eax
je 0xff34
cmpl $0x4, %edx
ja 0xff3e
movq 0x18(%rsp), %r13
testl %r15d, %r15d
je 0xff2d
movl %r15d, %ebx
incq %r13
leaq (%r12,%rcx), %rax
incq %rax
movq %rax, 0x10(%rsp)
movzbl %dl, %ebp
xorl %edx, %edx
movq 0x28(%rsp), %rax
movq %rax, %r12
movb %bpl, -0x1(%r13)
movq %r13, %rdi
movq %rax, %rsi
movq %r14, %rcx
movq %r8, %r15
movl %ebp, %r9d
callq 0x1053f
movq %r15, %r8
addq 0x10(%rsp), %r13
leaq (%r12,%r14), %rax
movq %r12, %rdx
decq %rbx
jne 0xfefe
xorl %eax, %eax
jmp 0x1052d
movl $0x1f, %eax
jmp 0x1052d
addl $-0x5, %edx
cmpl $0x3, %edx
movq 0x18(%rsp), %rbp
ja 0x10528
movq %rbx, %rsi
leaq (%rcx,%r12), %rbx
incq %rbx
leaq 0x623b0(%rip), %rax     # 0x72310
movslq (%rax,%rdx,4), %rcx
addq %rax, %rcx
movq %rbx, 0x40(%rsp)
jmpq *%rcx
movl %r15d, %r12d
movq %r8, 0x10(%rsp)
xorl %ebx, %ebx
movl $0x53, %ebp
xorl %r15d, %r15d
movq %r14, %rdi
callq 0x22b0
movq %rax, 0xc0(%rsp,%rbx,8)
testq %rax, %rax
cmovel %ebp, %r15d
incq %rbx
cmpq $0x5, %rbx
jne 0xff80
movq %r15, 0x20(%rsp)
testl %r15d, %r15d
setne %al
testl %r12d, %r12d
sete %cl
orb %al, %cl
jne 0x100e5
movl %r12d, %eax
movq %rax, 0x30(%rsp)
xorl %r8d, %r8d
movq $0x0, 0x8(%rsp)
xorl %ebx, %ebx
xorl %r15d, %r15d
movq 0x8(%rsp), %rbp
movq %r14, %rax
movq %r8, 0x38(%rsp)
imulq %r8, %rax
addq 0x28(%rsp), %rax
movq %rax, 0x8(%rsp)
xorl %r12d, %r12d
movq 0xc0(%rsp,%r12,8), %r13
movzbl %r12b, %r9d
movq %r13, %rdi
movq 0x8(%rsp), %rsi
movq %rbp, %rdx
movq %r14, %rcx
movq 0x10(%rsp), %r8
callq 0x1053f
testq %r12, %r12
je 0x10048
testq %r14, %r14
je 0x1006a
movl $0x1, %ecx
xorl %edx, %edx
xorl %eax, %eax
movzbl (%r13,%rdx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
addq %rsi, %rax
movl %ecx, %edx
incl %ecx
cmpq %rdx, %r14
jne 0x10027
jmp 0x1006c
testq %r14, %r14
je 0x1006a
movl $0x1, %ecx
xorl %edx, %edx
xorl %eax, %eax
movzbl (%r13,%rdx), %edx
addq %rdx, %rax
movl %ecx, %edx
incl %ecx
cmpq %rdx, %r14
jne 0x10056
jmp 0x1006c
xorl %eax, %eax
testq %r12, %r12
sete %cl
cmpq %r15, %rax
setb %dl
orb %cl, %dl
cmovneq %rax, %r15
movzbl %r12b, %eax
movzbl %bl, %ebx
cmovnel %eax, %ebx
incq %r12
cmpq $0x5, %r12
jne 0xfff0
movq 0x40(%rsp), %rax
movq 0x38(%rsp), %r8
imulq %r8, %rax
movq 0x18(%rsp), %rcx
movb %bl, (%rcx,%rax)
testq %r14, %r14
je 0x100d7
addq %rcx, %rax
movzbl %bl, %ecx
movq 0xc0(%rsp,%rcx,8), %rcx
movl $0x1, %edx
xorl %esi, %esi
movb (%rcx,%rsi), %dil
movb %dil, 0x1(%rax,%rsi)
movl %edx, %esi
incl %edx
cmpq %rsi, %r14
jne 0x100c5
incq %r8
cmpq 0x30(%rsp), %r8
jne 0xffd2
xorl %ebx, %ebx
movq 0xc0(%rsp,%rbx,8), %rdi
callq 0x22a0
incq %rbx
cmpq $0x5, %rbx
jne 0x100e7
jmp 0x10521
movl %r15d, %r12d
movq %r8, 0x10(%rsp)
movups (%rsi), %xmm0
movups 0x10(%rsi), %xmm1
movups 0x20(%rsi), %xmm2
movaps %xmm0, 0xc0(%rsp)
movaps %xmm2, 0xe0(%rsp)
movaps %xmm1, 0xd0(%rsp)
movl $0x1, 0xc0(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0xd8(%rsp)
xorl %ebx, %ebx
movl $0x53, %ebp
xorl %r15d, %r15d
movq %r14, %rdi
callq 0x22b0
movq %rax, 0x90(%rsp,%rbx,8)
testq %rax, %rax
cmovel %ebp, %r15d
incq %rbx
cmpq $0x5, %rbx
jne 0x1014d
movq %r15, 0x20(%rsp)
testl %r15d, %r15d
setne %al
testl %r12d, %r12d
sete %cl
orb %al, %cl
jne 0x1029e
movl %r14d, %ebx
movl %r12d, %eax
movq %rax, 0x50(%rsp)
xorl %r8d, %r8d
xorl %r12d, %r12d
xorl %r15d, %r15d
xorl %esi, %esi
movq %rbx, 0x30(%rsp)
movq %rsi, 0x38(%rsp)
movq %r14, %rsi
movq %r8, 0x58(%rsp)
imulq %r8, %rsi
addq 0x28(%rsp), %rsi
xorl %r13d, %r13d
xorl %ebp, %ebp
movq %rsi, 0x8(%rsp)
movq 0x90(%rsp,%rbp,8), %rbx
movzbl %bpl, %r9d
movq %rbx, %rdi
movq 0x38(%rsp), %rdx
movq %r14, %rcx
movq 0x10(%rsp), %r8
callq 0x1053f
leaq (%rsp,%r13), %rsi
addq $0x60, %rsi
xorl %eax, %eax
movq %rax, 0x60(%rsp,%rbp,8)
movq %rax, 0x48(%rsp)
leaq 0x48(%rsp), %rdi
movq %rbx, %rdx
movq 0x30(%rsp), %rcx
leaq 0xc0(%rsp), %r8
callq 0xd394
movq 0x48(%rsp), %rdi
callq 0x22a0
movq 0x8(%rsp), %rsi
testq %rbp, %rbp
sete %al
movq 0x60(%rsp,%rbp,8), %rcx
cmpq %r15, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %r15
cmovnel %ebp, %r12d
incq %rbp
addq $0x8, %r13
cmpq $0x5, %rbp
jne 0x101c1
movq 0x40(%rsp), %rax
movq 0x58(%rsp), %r8
imulq %r8, %rax
movq 0x18(%rsp), %rcx
movb %r12b, (%rcx,%rax)
testq %r14, %r14
je 0x10290
addq %rcx, %rax
movl %r12d, %ecx
movq 0x90(%rsp,%rcx,8), %rcx
movl $0x1, %edx
xorl %r9d, %r9d
movb (%rcx,%r9), %dil
movb %dil, 0x1(%rax,%r9)
movl %edx, %r9d
incl %edx
cmpq %r9, %r14
jne 0x1027d
incq %r8
cmpq 0x50(%rsp), %r8
jne 0x101a1
xorl %ebx, %ebx
movq 0x90(%rsp,%rbx,8), %rdi
callq 0x22a0
incq %rbx
cmpq $0x5, %rbx
jne 0x102a0
jmp 0x10521
testl %r15d, %r15d
je 0xff2d
movl %r15d, %eax
movq %rax, 0x10(%rsp)
incq %rbp
xorl %r13d, %r13d
xorl %edx, %edx
movq %r8, %r15
movq 0x28(%rsp), %rax
movq %rax, %r12
movq 0x500(%rsp), %rax
movq 0x40(%rax), %rax
movzbl (%rax,%r13), %r9d
movb %r9b, -0x1(%rbp)
movq %rbp, %rdi
movq %r12, %rsi
movq %r14, %rcx
movq %r15, %r8
callq 0x1053f
incq %r13
addq %rbx, %rbp
leaq (%r12,%r14), %rax
movq %r12, %rdx
cmpq %r13, 0x10(%rsp)
jne 0x102dc
jmp 0xff2d
movl %r15d, %r12d
movq %r8, 0x10(%rsp)
xorl %ebx, %ebx
movl $0x53, %ebp
xorl %r15d, %r15d
movq %r14, %rdi
callq 0x22b0
movq %rax, 0x60(%rsp,%rbx,8)
testq %rax, %rax
cmovel %ebp, %r15d
incq %rbx
cmpq $0x5, %rbx
jne 0x10330
movq %r15, 0x20(%rsp)
testl %r15d, %r15d
setne %al
testl %r12d, %r12d
sete %cl
orb %al, %cl
jne 0x1050c
movl %r12d, %eax
movq %rax, 0x30(%rsp)
xorl %r8d, %r8d
movq $0x0, 0x8(%rsp)
xorl %ebx, %ebx
xorl %r15d, %r15d
movq 0x8(%rsp), %r12
movq %r14, %rax
movq %r8, 0x38(%rsp)
imulq %r8, %rax
addq 0x28(%rsp), %rax
movq %rax, 0x8(%rsp)
xorl %ebp, %ebp
movq 0x60(%rsp,%rbp,8), %r13
movzbl %bpl, %r9d
movq %r13, %rdi
movq 0x8(%rsp), %rsi
movq %r12, %rdx
movq %r14, %rcx
movq 0x10(%rsp), %r8
callq 0x1053f
movl $0x400, %edx            # imm = 0x400
leaq 0xc0(%rsp), %rdi
xorl %esi, %esi
callq 0x2140
testq %r14, %r14
je 0x103f3
movl $0x1, %eax
xorl %ecx, %ecx
movzbl (%r13,%rcx), %ecx
incl 0xc0(%rsp,%rcx,4)
movl %eax, %ecx
incl %eax
cmpq %rcx, %r14
jne 0x103dd
incl 0xc0(%rsp,%rbp,4)
xorl %edx, %edx
xorl %eax, %eax
movl 0xc0(%rsp,%rdx,4), %esi
testq %rsi, %rsi
je 0x10489
movl %esi, %ecx
shrl $0x10, %ecx
xorl %edi, %edi
cmpl $0x10000, %esi          # imm = 0x10000
setae %dil
cmovbq %rsi, %rcx
shll $0x4, %edi
leaq 0x8(%rdi), %r8
movl %ecx, %r9d
shrl $0x8, %r9d
cmpq $0x100, %rcx            # imm = 0x100
cmovbq %rcx, %r9
cmovbq %rdi, %r8
leaq 0x4(%r8), %rdi
movl %r9d, %r10d
shrl $0x4, %r10d
cmpq $0x10, %r9
cmovbq %r9, %r10
cmovbq %r8, %rdi
leaq 0x2(%rdi), %rcx
movl %r10d, %r8d
shrl $0x2, %r8d
cmpq $0x4, %r10
cmovbq %r10, %r8
cmovbq %rdi, %rcx
cmpl $0x2, %r8d
sbbq $-0x1, %rcx
movq $-0x1, %rdi
shlq %cl, %rdi
imulq %rsi, %rcx
addq %rsi, %rdi
leaq (%rcx,%rdi,2), %rcx
jmp 0x1048b
xorl %ecx, %ecx
addq %rcx, %rax
incq %rdx
cmpq $0x100, %rdx            # imm = 0x100
jne 0x103fe
testq %rbp, %rbp
sete %cl
cmpq %r15, %rax
seta %dl
orb %cl, %dl
cmovneq %rax, %r15
cmovnel %ebp, %ebx
incq %rbp
cmpq $0x5, %rbp
jne 0x1039c
movq 0x40(%rsp), %rax
movq 0x38(%rsp), %r8
imulq %r8, %rax
movq 0x18(%rsp), %rcx
movb %bl, (%rcx,%rax)
testq %r14, %r14
je 0x104fe
addq %rcx, %rax
movl %ebx, %ecx
movq 0x60(%rsp,%rcx,8), %rcx
movl $0x1, %edx
xorl %esi, %esi
movb (%rcx,%rsi), %dil
movb %dil, 0x1(%rax,%rsi)
movl %edx, %esi
incl %edx
cmpq %rsi, %r14
jne 0x104ec
incq %r8
cmpq 0x30(%rsp), %r8
jne 0x1037f
xorl %ebx, %ebx
movq 0x60(%rsp,%rbx,8), %rdi
callq 0x22a0
incq %rbx
cmpq $0x5, %rbx
jne 0x1050e
movq 0x20(%rsp), %rax
jmp 0x1052d
movl $0x58, %eax
addq $0x4c8, %rsp            # imm = 0x4C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq