// File: lemire[P]validateutf8-experiments/benchmarks/hoehrmann.h
// Function: shiftless_validate_dfa_utf8_quad(signed char const*, unsigned long)
static inline fastvalidate::error_code
shiftless_validate_dfa_utf8_quad(const signed char *c, size_t len) {
  if (len < 32) { // if too small, do not bother
    return shiftless_validate_dfa_utf8(c, len);
  }
  size_t middle_point1 = len / 4;
  // backtrack until we find a leading byte
  while (!is_leading(c[middle_point1])) {
    if (middle_point1 == 0) {
      // we have determined that there is an error
      return fastvalidate::error_code::UTF8_ERROR;
    }
    middle_point1 -= 1;
  }
  size_t middle_point2 = len / 2;
  // backtrack until we find a leading byte
  while (!is_leading(c[middle_point2])) {
    if (middle_point2 == middle_point1) {
      // we have determined that there is an error
      return fastvalidate::error_code::UTF8_ERROR;
    }
    middle_point2 -= 1;
  }
  size_t middle_point3 = len / 2;
  // backtrack until we find a leading byte
  while (!is_leading(c[middle_point3])) {
    if (middle_point3 == middle_point2) {
      // we have determined that there is an error
      return fastvalidate::error_code::UTF8_ERROR;
    }
    middle_point3 -= 1;
  }
  uint32_t state1 = 0;
  uint32_t state2 = 0;
  uint32_t state3 = 0;
  uint32_t state4 = 0;

  const unsigned char *cu1 = (const unsigned char *)c;
  const unsigned char *cu2 = (const unsigned char *)(c + middle_point1);
  const unsigned char *cu3 = (const unsigned char *)(c + middle_point2);
  const unsigned char *cu4 = (const unsigned char *)(c + middle_point3);

  size_t smallest_run = middle_point1;
  if (middle_point2 - middle_point1 < smallest_run) {
    smallest_run = middle_point2 - middle_point1;
  }
  if (middle_point3 - middle_point2 < smallest_run) {
    smallest_run = middle_point3 - middle_point2;
  }
  if (len - middle_point3 < smallest_run) {
    smallest_run = len - middle_point3;
  }
  for (size_t i = 0; i < smallest_run; i++) {
    uint32_t byteval1 = (uint32_t)cu1[i];
    uint32_t byteval2 = (uint32_t)cu2[i];
    uint32_t byteval3 = (uint32_t)cu3[i];
    uint32_t byteval4 = (uint32_t)cu4[i];

    if ((shiftless_updatestate(&state1, byteval1) == SHIFTLESS_UTF8_REJECT) ||
        (shiftless_updatestate(&state2, byteval2) == SHIFTLESS_UTF8_REJECT) ||
        (shiftless_updatestate(&state3, byteval3) == SHIFTLESS_UTF8_REJECT) ||
        (shiftless_updatestate(&state4, byteval4) == SHIFTLESS_UTF8_REJECT)) {
      return fastvalidate::error_code::UTF8_ERROR;
    }
  }
  if (middle_point1 > smallest_run) {
    for (size_t i = smallest_run; i < middle_point1 - smallest_run; i++) {
      uint32_t byteval1 = (uint32_t)cu1[i];
      if (shiftless_updatestate(&state1, byteval1) == SHIFTLESS_UTF8_REJECT) {
        return fastvalidate::error_code::UTF8_ERROR;
      }
    }
  }
  if (shiftless_updatestate(&state1, 0) == SHIFTLESS_UTF8_REJECT) {
    return fastvalidate::error_code::UTF8_ERROR;
  }

  if (middle_point2 - middle_point1 > smallest_run) {
    for (size_t i = smallest_run; i < middle_point2 - middle_point1; i++) {
      uint32_t byteval2 = (uint32_t)cu2[i];
      if (shiftless_updatestate(&state2, byteval2) == SHIFTLESS_UTF8_REJECT) {
        return fastvalidate::error_code::UTF8_ERROR;
      }
    }
  }
  if (shiftless_updatestate(&state2, 0) == SHIFTLESS_UTF8_REJECT) {
    return fastvalidate::error_code::UTF8_ERROR;
  }
  if (middle_point3 - middle_point2 > smallest_run) {
    for (size_t i = smallest_run; i < middle_point3 - middle_point2; i++) {
      uint32_t byteval3 = (uint32_t)cu3[i];
      if (shiftless_updatestate(&state3, byteval3) == SHIFTLESS_UTF8_REJECT) {
        return fastvalidate::error_code::UTF8_ERROR;
      }
    }
  }
  if (shiftless_updatestate(&state3, 0) == SHIFTLESS_UTF8_REJECT) {
    return fastvalidate::error_code::UTF8_ERROR;
  }

  if (len - middle_point3 > smallest_run) {
    for (size_t i = smallest_run; i < len - middle_point3; i++) {
      uint32_t byteval4 = (uint32_t)cu4[i];
      if (shiftless_updatestate(&state4, byteval4) == SHIFTLESS_UTF8_REJECT) {
        return fastvalidate::error_code::UTF8_ERROR;
      }
    }
  }
  if (shiftless_updatestate(&state4, 0) == SHIFTLESS_UTF8_REJECT) {
    return fastvalidate::error_code::UTF8_ERROR;
  }
  return fastvalidate::error_code::SUCCESS;
}

// Assembly:
subq $0x188, %rsp            # imm = 0x188
movq %rdi, 0xb0(%rsp)
movq %rsi, 0xa8(%rsp)
cmpq $0x20, 0xa8(%rsp)
jae 0x51b3
movq 0xb0(%rsp), %rdi
movq 0xa8(%rsp), %rsi
callq 0x4510
movl %eax, 0xbc(%rsp)
jmp 0x5bfe
movq 0xa8(%rsp), %rax
shrq $0x2, %rax
movq %rax, 0xa0(%rsp)
movq 0xb0(%rsp), %rax
movq 0xa0(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, 0x187(%rsp)
movsbl 0x187(%rsp), %eax
cmpl $-0x40, %eax
setge %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x51f7
jmp 0x5228
cmpq $0x0, 0xa0(%rsp)
jne 0x5212
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
movq 0xa0(%rsp), %rax
subq $0x1, %rax
movq %rax, 0xa0(%rsp)
jmp 0x51c7
movq 0xa8(%rsp), %rax
shrq %rax
movq %rax, 0x98(%rsp)
movq 0xb0(%rsp), %rax
movq 0x98(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, 0x186(%rsp)
movsbl 0x186(%rsp), %eax
cmpl $-0x40, %eax
setge %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x526b
jmp 0x52a3
movq 0x98(%rsp), %rax
cmpq 0xa0(%rsp), %rax
jne 0x528d
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
movq 0x98(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x98(%rsp)
jmp 0x523b
movq 0xa8(%rsp), %rax
shrq %rax
movq %rax, 0x90(%rsp)
movq 0xb0(%rsp), %rax
movq 0x90(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, 0x185(%rsp)
movsbl 0x185(%rsp), %eax
cmpl $-0x40, %eax
setge %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x52e6
jmp 0x531e
movq 0x90(%rsp), %rax
cmpq 0x98(%rsp), %rax
jne 0x5308
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
movq 0x90(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x90(%rsp)
jmp 0x52b6
movl $0x0, 0x8c(%rsp)
movl $0x0, 0x88(%rsp)
movl $0x0, 0x84(%rsp)
movl $0x0, 0x80(%rsp)
movq 0xb0(%rsp), %rax
movq %rax, 0x78(%rsp)
movq 0xb0(%rsp), %rax
addq 0xa0(%rsp), %rax
movq %rax, 0x70(%rsp)
movq 0xb0(%rsp), %rax
addq 0x98(%rsp), %rax
movq %rax, 0x68(%rsp)
movq 0xb0(%rsp), %rax
addq 0x90(%rsp), %rax
movq %rax, 0x60(%rsp)
movq 0xa0(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x98(%rsp), %rax
subq 0xa0(%rsp), %rax
cmpq 0x58(%rsp), %rax
jae 0x53cf
movq 0x98(%rsp), %rax
subq 0xa0(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x90(%rsp), %rax
subq 0x98(%rsp), %rax
cmpq 0x58(%rsp), %rax
jae 0x53fb
movq 0x90(%rsp), %rax
subq 0x98(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0xa8(%rsp), %rax
subq 0x90(%rsp), %rax
cmpq 0x58(%rsp), %rax
jae 0x5427
movq 0xa8(%rsp), %rax
subq 0x90(%rsp), %rax
movq %rax, 0x58(%rsp)
movq $0x0, 0x50(%rsp)
movq 0x50(%rsp), %rax
cmpq 0x58(%rsp), %rax
jae 0x5669
movq 0x78(%rsp), %rax
movq 0x50(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x4c(%rsp)
movq 0x70(%rsp), %rax
movq 0x50(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x48(%rsp)
movq 0x68(%rsp), %rax
movq 0x50(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x44(%rsp)
movq 0x60(%rsp), %rax
movq 0x50(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x40(%rsp)
movl 0x4c(%rsp), %eax
leaq 0x8c(%rsp), %rcx
movq %rcx, 0x178(%rsp)
movl %eax, 0x174(%rsp)
movl 0x174(%rsp), %eax
movl %eax, %ecx
leaq 0xf9f9d(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x170(%rsp)
movq 0x178(%rsp), %rax
movl (%rax), %eax
addl 0x170(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfa076(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x178(%rsp), %rax
movl %ecx, (%rax)
movq 0x178(%rsp), %rax
cmpl $0x10, (%rax)
je 0x5644
movl 0x48(%rsp), %eax
leaq 0x88(%rsp), %rcx
movq %rcx, 0x168(%rsp)
movl %eax, 0x164(%rsp)
movl 0x164(%rsp), %eax
movl %eax, %ecx
leaq 0xf9f2c(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x160(%rsp)
movq 0x168(%rsp), %rax
movl (%rax), %eax
addl 0x160(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfa005(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x168(%rsp), %rax
movl %ecx, (%rax)
movq 0x168(%rsp), %rax
cmpl $0x10, (%rax)
je 0x5644
movl 0x44(%rsp), %eax
leaq 0x84(%rsp), %rcx
movq %rcx, 0x158(%rsp)
movl %eax, 0x154(%rsp)
movl 0x154(%rsp), %eax
movl %eax, %ecx
leaq 0xf9ebb(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x150(%rsp)
movq 0x158(%rsp), %rax
movl (%rax), %eax
addl 0x150(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9f94(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x158(%rsp), %rax
movl %ecx, (%rax)
movq 0x158(%rsp), %rax
cmpl $0x10, (%rax)
je 0x5644
movl 0x40(%rsp), %eax
leaq 0x80(%rsp), %rcx
movq %rcx, 0x148(%rsp)
movl %eax, 0x144(%rsp)
movl 0x144(%rsp), %eax
movl %eax, %ecx
leaq 0xf9e4e(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x140(%rsp)
movq 0x148(%rsp), %rax
movl (%rax), %eax
addl 0x140(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9f27(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x148(%rsp), %rax
movl %ecx, (%rax)
movq 0x148(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x5654
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
jmp 0x5656
movq 0x50(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x50(%rsp)
jmp 0x5430
movq 0xa0(%rsp), %rax
cmpq 0x58(%rsp), %rax
jbe 0x5747
movq 0x58(%rsp), %rax
movq %rax, 0x38(%rsp)
movq 0x38(%rsp), %rax
movq 0xa0(%rsp), %rcx
subq 0x58(%rsp), %rcx
cmpq %rcx, %rax
jae 0x5745
movq 0x78(%rsp), %rax
movq 0x38(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x34(%rsp)
movl 0x34(%rsp), %eax
leaq 0x8c(%rsp), %rcx
movq %rcx, 0x138(%rsp)
movl %eax, 0x134(%rsp)
movl 0x134(%rsp), %eax
movl %eax, %ecx
leaq 0xf9d72(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x130(%rsp)
movq 0x138(%rsp), %rax
movl (%rax), %eax
addl 0x130(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9e4b(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x138(%rsp), %rax
movl %ecx, (%rax)
movq 0x138(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x5730
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
jmp 0x5732
movq 0x38(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x38(%rsp)
jmp 0x5686
jmp 0x5747
leaq 0x8c(%rsp), %rax
movq %rax, 0x128(%rsp)
movl $0x0, 0x124(%rsp)
movl 0x124(%rsp), %eax
movl %eax, %ecx
leaq 0xf9cde(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x120(%rsp)
movq 0x128(%rsp), %rax
movl (%rax), %eax
addl 0x120(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9db7(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x128(%rsp), %rax
movl %ecx, (%rax)
movq 0x128(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x57c4
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
movq 0x98(%rsp), %rax
subq 0xa0(%rsp), %rax
cmpq 0x58(%rsp), %rax
jbe 0x58ad
movq 0x58(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rax
movq 0x98(%rsp), %rcx
subq 0xa0(%rsp), %rcx
cmpq %rcx, %rax
jae 0x58ab
movq 0x70(%rsp), %rax
movq 0x28(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x24(%rsp)
movl 0x24(%rsp), %eax
leaq 0x88(%rsp), %rcx
movq %rcx, 0x118(%rsp)
movl %eax, 0x114(%rsp)
movl 0x114(%rsp), %eax
movl %eax, %ecx
leaq 0xf9c0c(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x110(%rsp)
movq 0x118(%rsp), %rax
movl (%rax), %eax
addl 0x110(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9ce5(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x118(%rsp), %rax
movl %ecx, (%rax)
movq 0x118(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x5896
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
jmp 0x5898
movq 0x28(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x28(%rsp)
jmp 0x57e9
jmp 0x58ad
leaq 0x88(%rsp), %rax
movq %rax, 0x108(%rsp)
movl $0x0, 0x104(%rsp)
movl 0x104(%rsp), %eax
movl %eax, %ecx
leaq 0xf9b78(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0x100(%rsp)
movq 0x108(%rsp), %rax
movl (%rax), %eax
addl 0x100(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9c51(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x108(%rsp), %rax
movl %ecx, (%rax)
movq 0x108(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x592a
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
movq 0x90(%rsp), %rax
subq 0x98(%rsp), %rax
cmpq 0x58(%rsp), %rax
jbe 0x5a13
movq 0x58(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rax
movq 0x90(%rsp), %rcx
subq 0x98(%rsp), %rcx
cmpq %rcx, %rax
jae 0x5a11
movq 0x68(%rsp), %rax
movq 0x18(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x14(%rsp)
movl 0x14(%rsp), %eax
leaq 0x84(%rsp), %rcx
movq %rcx, 0xf8(%rsp)
movl %eax, 0xf4(%rsp)
movl 0xf4(%rsp), %eax
movl %eax, %ecx
leaq 0xf9aa6(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0xf0(%rsp)
movq 0xf8(%rsp), %rax
movl (%rax), %eax
addl 0xf0(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9b7f(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xf8(%rsp), %rax
movl %ecx, (%rax)
movq 0xf8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x59fc
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
jmp 0x59fe
movq 0x18(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x18(%rsp)
jmp 0x594f
jmp 0x5a13
leaq 0x84(%rsp), %rax
movq %rax, 0xe8(%rsp)
movl $0x0, 0xe4(%rsp)
movl 0xe4(%rsp), %eax
movl %eax, %ecx
leaq 0xf9a12(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0xe0(%rsp)
movq 0xe8(%rsp), %rax
movl (%rax), %eax
addl 0xe0(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9aeb(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xe8(%rsp), %rax
movl %ecx, (%rax)
movq 0xe8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x5a90
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
movq 0xa8(%rsp), %rax
subq 0x90(%rsp), %rax
cmpq 0x58(%rsp), %rax
jbe 0x5b79
movq 0x58(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x8(%rsp), %rax
movq 0xa8(%rsp), %rcx
subq 0x90(%rsp), %rcx
cmpq %rcx, %rax
jae 0x5b77
movq 0x60(%rsp), %rax
movq 0x8(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x4(%rsp)
movl 0x4(%rsp), %eax
leaq 0x80(%rsp), %rcx
movq %rcx, 0xd8(%rsp)
movl %eax, 0xd4(%rsp)
movl 0xd4(%rsp), %eax
movl %eax, %ecx
leaq 0xf9940(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0xd0(%rsp)
movq 0xd8(%rsp), %rax
movl (%rax), %eax
addl 0xd0(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9a19(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xd8(%rsp), %rax
movl %ecx, (%rax)
movq 0xd8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x5b62
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
jmp 0x5b64
movq 0x8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x8(%rsp)
jmp 0x5ab5
jmp 0x5b79
leaq 0x80(%rsp), %rax
movq %rax, 0xc8(%rsp)
movl $0x0, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
movl %eax, %ecx
leaq 0xf98ac(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0xc0(%rsp)
movq 0xc8(%rsp), %rax
movl (%rax), %eax
addl 0xc0(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xf9985(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xc8(%rsp), %rax
movl %ecx, (%rax)
movq 0xc8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x5bf3
movl $0x1, 0xbc(%rsp)
jmp 0x5bfe
movl $0x0, 0xbc(%rsp)
movl 0xbc(%rsp), %eax
addq $0x188, %rsp            # imm = 0x188
retq
nopl (%rax)