// File: lemire[P]validateutf8-experiments/benchmarks/hoehrmann.h
// Function: shiftless_validate_dfa_utf8_three(signed char const*, unsigned long)
static inline fastvalidate::error_code
shiftless_validate_dfa_utf8_three(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 / 3;
  // 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 = 2 * len / 3;
  // 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;
  }

  uint32_t state1 = 0;
  uint32_t state2 = 0;
  uint32_t state3 = 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);
  size_t smallest_run = middle_point1;
  if (middle_point2 - middle_point1 < smallest_run) {
    smallest_run = middle_point2 - middle_point1;
  }
  if (len - middle_point2 < smallest_run) {
    smallest_run = len - middle_point2;
  }
  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];

    if ((shiftless_updatestate(&state1, byteval1) == SHIFTLESS_UTF8_REJECT) ||
        (shiftless_updatestate(&state2, byteval2) == SHIFTLESS_UTF8_REJECT) ||
        (shiftless_updatestate(&state3, byteval3) == SHIFTLESS_UTF8_REJECT)) {
      return fastvalidate::error_code::UTF8_ERROR;
    }
  }
  if (middle_point1 > smallest_run) {
    for (size_t i = smallest_run; i < middle_point1; 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 (len - middle_point2 > smallest_run) {
    for (size_t i = smallest_run; i < len - 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;
  }
  return fastvalidate::error_code::SUCCESS;
}

// Assembly:
subq $0x138, %rsp            # imm = 0x138
movq %rdi, 0x90(%rsp)
movq %rsi, 0x88(%rsp)
cmpq $0x20, 0x88(%rsp)
jae 0x4a03
movq 0x90(%rsp), %rdi
movq 0x88(%rsp), %rsi
callq 0x4510
movl %eax, 0x9c(%rsp)
jmp 0x5158
movq 0x88(%rsp), %rax
movl $0x3, %ecx
xorl %edx, %edx
divq %rcx
movq %rax, 0x80(%rsp)
movq 0x90(%rsp), %rax
movq 0x80(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, 0x137(%rsp)
movsbl 0x137(%rsp), %eax
cmpl $-0x40, %eax
setge %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x4a4d
jmp 0x4a7e
cmpq $0x0, 0x80(%rsp)
jne 0x4a68
movl $0x1, 0x9c(%rsp)
jmp 0x5158
movq 0x80(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x80(%rsp)
jmp 0x4a1d
movq 0x88(%rsp), %rax
shlq %rax
movl $0x3, %ecx
xorl %edx, %edx
divq %rcx
movq %rax, 0x78(%rsp)
movq 0x90(%rsp), %rax
movq 0x78(%rsp), %rcx
movb (%rax,%rcx), %al
movb %al, 0x136(%rsp)
movsbl 0x136(%rsp), %eax
cmpl $-0x40, %eax
setge %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x4ac5
jmp 0x4af4
movq 0x78(%rsp), %rax
cmpq 0x80(%rsp), %rax
jne 0x4ae4
movl $0x1, 0x9c(%rsp)
jmp 0x5158
movq 0x78(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x78(%rsp)
jmp 0x4a98
movl $0x0, 0x74(%rsp)
movl $0x0, 0x70(%rsp)
movl $0x0, 0x6c(%rsp)
movq 0x90(%rsp), %rax
movq %rax, 0x60(%rsp)
movq 0x90(%rsp), %rax
addq 0x80(%rsp), %rax
movq %rax, 0x58(%rsp)
movq 0x90(%rsp), %rax
addq 0x78(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x80(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x78(%rsp), %rax
subq 0x80(%rsp), %rax
cmpq 0x48(%rsp), %rax
jae 0x4b73
movq 0x78(%rsp), %rax
subq 0x80(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x88(%rsp), %rax
subq 0x78(%rsp), %rax
cmpq 0x48(%rsp), %rax
jae 0x4b99
movq 0x88(%rsp), %rax
subq 0x78(%rsp), %rax
movq %rax, 0x48(%rsp)
movq $0x0, 0x40(%rsp)
movq 0x40(%rsp), %rax
cmpq 0x48(%rsp), %rax
jae 0x4d4f
movq 0x60(%rsp), %rax
movq 0x40(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x3c(%rsp)
movq 0x58(%rsp), %rax
movq 0x40(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x38(%rsp)
movq 0x50(%rsp), %rax
movq 0x40(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x34(%rsp)
movl 0x3c(%rsp), %eax
leaq 0x74(%rsp), %rcx
movq %rcx, 0x128(%rsp)
movl %eax, 0x124(%rsp)
movl 0x124(%rsp), %eax
movl %eax, %ecx
leaq 0xfa840(%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 0xfa919(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x128(%rsp), %rax
movl %ecx, (%rax)
movq 0x128(%rsp), %rax
cmpl $0x10, (%rax)
je 0x4d2a
movl 0x38(%rsp), %eax
leaq 0x70(%rsp), %rcx
movq %rcx, 0x118(%rsp)
movl %eax, 0x114(%rsp)
movl 0x114(%rsp), %eax
movl %eax, %ecx
leaq 0xfa7d2(%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 0xfa8ab(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x118(%rsp), %rax
movl %ecx, (%rax)
movq 0x118(%rsp), %rax
cmpl $0x10, (%rax)
je 0x4d2a
movl 0x34(%rsp), %eax
leaq 0x6c(%rsp), %rcx
movq %rcx, 0x108(%rsp)
movl %eax, 0x104(%rsp)
movl 0x104(%rsp), %eax
movl %eax, %ecx
leaq 0xfa768(%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 0xfa841(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0x108(%rsp), %rax
movl %ecx, (%rax)
movq 0x108(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x4d3a
movl $0x1, 0x9c(%rsp)
jmp 0x5158
jmp 0x4d3c
movq 0x40(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x40(%rsp)
jmp 0x4ba2
movq 0x80(%rsp), %rax
cmpq 0x48(%rsp), %rax
jbe 0x4e22
movq 0x48(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rax
cmpq 0x80(%rsp), %rax
jae 0x4e20
movq 0x60(%rsp), %rax
movq 0x28(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x24(%rsp)
movl 0x24(%rsp), %eax
leaq 0x74(%rsp), %rcx
movq %rcx, 0xf8(%rsp)
movl %eax, 0xf4(%rsp)
movl 0xf4(%rsp), %eax
movl %eax, %ecx
leaq 0xfa697(%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 0xfa770(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xf8(%rsp), %rax
movl %ecx, (%rax)
movq 0xf8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x4e0b
movl $0x1, 0x9c(%rsp)
jmp 0x5158
jmp 0x4e0d
movq 0x28(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x28(%rsp)
jmp 0x4d6c
jmp 0x4e22
leaq 0x74(%rsp), %rax
movq %rax, 0xe8(%rsp)
movl $0x0, 0xe4(%rsp)
movl 0xe4(%rsp), %eax
movl %eax, %ecx
leaq 0xfa606(%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 0xfa6df(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xe8(%rsp), %rax
movl %ecx, (%rax)
movq 0xe8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x4e9c
movl $0x1, 0x9c(%rsp)
jmp 0x5158
movq 0x78(%rsp), %rax
subq 0x80(%rsp), %rax
cmpq 0x48(%rsp), %rax
jbe 0x4f7c
movq 0x48(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rsp), %rax
movq 0x78(%rsp), %rcx
subq 0x80(%rsp), %rcx
cmpq %rcx, %rax
jae 0x4f7a
movq 0x58(%rsp), %rax
movq 0x18(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x14(%rsp)
movl 0x14(%rsp), %eax
leaq 0x70(%rsp), %rcx
movq %rcx, 0xd8(%rsp)
movl %eax, 0xd4(%rsp)
movl 0xd4(%rsp), %eax
movl %eax, %ecx
leaq 0xfa53d(%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 0xfa616(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xd8(%rsp), %rax
movl %ecx, (%rax)
movq 0xd8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x4f65
movl $0x1, 0x9c(%rsp)
jmp 0x5158
jmp 0x4f67
movq 0x18(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x18(%rsp)
jmp 0x4ebe
jmp 0x4f7c
leaq 0x70(%rsp), %rax
movq %rax, 0xc8(%rsp)
movl $0x0, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
movl %eax, %ecx
leaq 0xfa4ac(%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 0xfa585(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xc8(%rsp), %rax
movl %ecx, (%rax)
movq 0xc8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x4ff6
movl $0x1, 0x9c(%rsp)
jmp 0x5158
movq 0x88(%rsp), %rax
subq 0x78(%rsp), %rax
cmpq 0x48(%rsp), %rax
jbe 0x50d6
movq 0x48(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x8(%rsp), %rax
movq 0x88(%rsp), %rcx
subq 0x78(%rsp), %rcx
cmpq %rcx, %rax
jae 0x50d4
movq 0x50(%rsp), %rax
movq 0x8(%rsp), %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x4(%rsp)
movl 0x4(%rsp), %eax
leaq 0x6c(%rsp), %rcx
movq %rcx, 0xb8(%rsp)
movl %eax, 0xb4(%rsp)
movl 0xb4(%rsp), %eax
movl %eax, %ecx
leaq 0xfa3e3(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0xb0(%rsp)
movq 0xb8(%rsp), %rax
movl (%rax), %eax
addl 0xb0(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfa4bc(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xb8(%rsp), %rax
movl %ecx, (%rax)
movq 0xb8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x50bf
movl $0x1, 0x9c(%rsp)
jmp 0x5158
jmp 0x50c1
movq 0x8(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x8(%rsp)
jmp 0x5018
jmp 0x50d6
leaq 0x6c(%rsp), %rax
movq %rax, 0xa8(%rsp)
movl $0x0, 0xa4(%rsp)
movl 0xa4(%rsp), %eax
movl %eax, %ecx
leaq 0xfa352(%rip), %rax     # 0xff450
movzbl (%rax,%rcx), %eax
movl %eax, 0xa0(%rsp)
movq 0xa8(%rsp), %rax
movl (%rax), %eax
addl 0xa0(%rsp), %eax
movl %eax, %eax
movl %eax, %ecx
leaq 0xfa42b(%rip), %rax     # 0xff550
movzbl (%rax,%rcx), %ecx
movq 0xa8(%rsp), %rax
movl %ecx, (%rax)
movq 0xa8(%rsp), %rax
cmpl $0x10, (%rax)
jne 0x514d
movl $0x1, 0x9c(%rsp)
jmp 0x5158
movl $0x0, 0x9c(%rsp)
movl 0x9c(%rsp), %eax
addq $0x138, %rsp            # imm = 0x138
retq
nopw (%rax,%rax)