#define NULL ((void *)0)
typedef unsigned long size_t; // Customize by platform.
typedef long intptr_t;
typedef unsigned long uintptr_t;
typedef long scalar_t__; // Either arithmetic or pointer type.
/* By default, we understand bool (as a convenience). */
typedef int bool;
#define false 0
#define true 1

/* Forward declarations */

/* Type definitions */
struct template_buffer {
  int dummy;
};

/* Variables and functions */
int /*<<< orphan*/ buf_append(struct template_buffer *, unsigned char *,
                              unsigned int);
int /*<<< orphan*/ buf_putchar(struct template_buffer *, char);
scalar_t__ mb_is_cont(unsigned char);
int /*<<< orphan*/ mb_is_illegal(unsigned char *, unsigned int);
int /*<<< orphan*/ mb_is_shortest(unsigned char *, unsigned int);
int /*<<< orphan*/ mb_is_surrogate(unsigned char *, unsigned int);
unsigned int mb_num_chars(unsigned char);
int _validate_utf8(unsigned char **s, int l, struct template_buffer *buf) {
  unsigned char *ptr = *s;
  unsigned int o = 0, v, n;
  if ((*(ptr + 0) >= 0x01) && (*(ptr + 0) <= 0x7F)) {
    if (!buf_putchar(buf, *ptr++))
      return 0;
    o = 1;
  } else if ((n = mb_num_chars(*ptr)) > 1) {
    for (v = 1; (v <= n) && ((o + v) < l) && mb_is_cont(*(ptr + v)); v++)
      ;
    switch (n) {
    case 6:
    case 5:
      if (!buf_putchar(buf, '?'))
        return 0;
      break;
    default:
      if ((v == n) && mb_is_shortest(ptr, n) && !mb_is_surrogate(ptr, n) &&
          !mb_is_illegal(ptr, n)) {
        if (!buf_append(buf, ptr, n))
          return 0;
      } else {
        if (!buf_putchar(buf, '?'))
          return 0;
      }
      break;
    }
    o = v;
    ptr += v;
  } else {
    if (!buf_putchar(buf, '?'))
      return 0;
    o = 1;
    ptr++;
  }
  *s = ptr;
  return o;
}


x86 assembly (clang, -O0):
<_validate_utf8>:
push   %rbp
mov    %rsp,%rbp
sub    $0x40,%rsp
mov    %rdi,-0x10(%rbp)
mov    %esi,-0x14(%rbp)
mov    %rdx,-0x20(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
mov    %rax,-0x28(%rbp)
movl   $0x0,-0x2c(%rbp)
mov    -0x28(%rbp),%rax
movzbl (%rax),%eax
cmp    $0x1,%eax
jl     11f1 <_validate_utf8+0x81>
mov    -0x28(%rbp),%rax
movzbl (%rax),%eax
cmp    $0x7f,%eax
jg     11f1 <_validate_utf8+0x81>
mov    -0x20(%rbp),%rdi
mov    -0x28(%rbp),%rax
mov    %rax,%rcx
add    $0x1,%rcx
mov    %rcx,-0x28(%rbp)
movsbl (%rax),%esi
call   1090 <buf_putchar@plt>
cmp    $0x0,%eax
jne    11e5 <_validate_utf8+0x75>
movl   $0x0,-0x4(%rbp)
jmp    13b7 <_validate_utf8+0x247>
movl   $0x1,-0x2c(%rbp)
jmp    13a6 <_validate_utf8+0x236>
mov    -0x28(%rbp),%rax
movzbl (%rax),%edi
call   1030 <mb_num_chars@plt>
mov    %eax,-0x34(%rbp)
cmp    $0x1,%eax
jbe    136b <_validate_utf8+0x1fb>
movl   $0x1,-0x30(%rbp)
mov    -0x30(%rbp),%ecx
xor    %eax,%eax
cmp    -0x34(%rbp),%ecx
mov    %al,-0x35(%rbp)
ja     124f <_validate_utf8+0xdf>
mov    -0x2c(%rbp),%ecx
add    -0x30(%rbp),%ecx
xor    %eax,%eax
cmp    -0x14(%rbp),%ecx
mov    %al,-0x35(%rbp)
jae    124f <_validate_utf8+0xdf>
mov    -0x28(%rbp),%rax
mov    -0x30(%rbp),%ecx
movzbl (%rax,%rcx,1),%edi
call   1070 <mb_is_cont@plt>
cmp    $0x0,%rax
setne  %al
mov    %al,-0x35(%rbp)
mov    -0x35(%rbp),%al
test   $0x1,%al
jne    125f <_validate_utf8+0xef>
jmp    1272 <_validate_utf8+0x102>
jmp    1264 <_validate_utf8+0xf4>
mov    -0x30(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x30(%rbp)
jmp    1210 <_validate_utf8+0xa0>
mov    -0x34(%rbp),%eax
add    $0xfffffffb,%eax
sub    $0x1,%eax
ja     12ae <_validate_utf8+0x13e>
jmp    1286 <_validate_utf8+0x116>
mov    -0x20(%rbp),%rdi
mov    $0x3f,%esi
call   1090 <buf_putchar@plt>
cmp    $0x0,%eax
jne    12a9 <_validate_utf8+0x139>
movl   $0x0,-0x4(%rbp)
jmp    13b7 <_validate_utf8+0x247>
jmp    1350 <_validate_utf8+0x1e0>
mov    -0x30(%rbp),%eax
cmp    -0x34(%rbp),%eax
jne    1323 <_validate_utf8+0x1b3>
mov    -0x28(%rbp),%rdi
mov    -0x34(%rbp),%esi
call   1080 <mb_is_shortest@plt>
cmp    $0x0,%eax
je     1323 <_validate_utf8+0x1b3>
mov    -0x28(%rbp),%rdi
mov    -0x34(%rbp),%esi
call   1040 <mb_is_surrogate@plt>
cmp    $0x0,%eax
jne    1323 <_validate_utf8+0x1b3>
mov    -0x28(%rbp),%rdi
mov    -0x34(%rbp),%esi
call   1050 <mb_is_illegal@plt>
cmp    $0x0,%eax
jne    1323 <_validate_utf8+0x1b3>
mov    -0x20(%rbp),%rdi
mov    -0x28(%rbp),%rsi
mov    -0x34(%rbp),%edx
call   1060 <buf_append@plt>
cmp    $0x0,%eax
jne    131e <_validate_utf8+0x1ae>
movl   $0x0,-0x4(%rbp)
jmp    13b7 <_validate_utf8+0x247>
jmp    134b <_validate_utf8+0x1db>
mov    -0x20(%rbp),%rdi
mov    $0x3f,%esi
call   1090 <buf_putchar@plt>
cmp    $0x0,%eax
jne    1346 <_validate_utf8+0x1d6>
movl   $0x0,-0x4(%rbp)
jmp    13b7 <_validate_utf8+0x247>
jmp    134b <_validate_utf8+0x1db>
jmp    1350 <_validate_utf8+0x1e0>
mov    -0x30(%rbp),%eax
mov    %eax,-0x2c(%rbp)
mov    -0x30(%rbp),%ecx
mov    -0x28(%rbp),%rax
mov    %ecx,%ecx
add    %rcx,%rax
mov    %rax,-0x28(%rbp)
jmp    13a1 <_validate_utf8+0x231>
mov    -0x20(%rbp),%rdi
mov    $0x3f,%esi
call   1090 <buf_putchar@plt>
cmp    $0x0,%eax
jne    138e <_validate_utf8+0x21e>
movl   $0x0,-0x4(%rbp)
jmp    13b7 <_validate_utf8+0x247>
movl   $0x1,-0x2c(%rbp)
mov    -0x28(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x28(%rbp)
jmp    13a6 <_validate_utf8+0x236>
mov    -0x28(%rbp),%rcx
mov    -0x10(%rbp),%rax
mov    %rcx,(%rax)
mov    -0x2c(%rbp),%eax
mov    %eax,-0x4(%rbp)
mov    -0x4(%rbp),%eax
add    $0x40,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<_validate_utf8>:
push   %rbp
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
push   %rax
mov    %rdx,%r12
mov    %rdi,%r14
mov    (%rdi),%r15
mov    (%r15),%al
test   %al,%al
jle    1196 <_validate_utf8+0x26>
movsbl %al,%esi
mov    %r12,%rdi
jmp    1240 <_validate_utf8+0xd0>
mov    %esi,%ebp
movzbl %al,%edi
call   1030 <mb_num_chars@plt>
cmp    $0x2,%eax
jb     1238 <_validate_utf8+0xc8>
mov    %eax,%r13d
mov    $0x1,%ebx
cmp    $0x2,%ebp
jb     11e8 <_validate_utf8+0x78>
lea    -0x1(%r13),%eax
add    $0xfffffffe,%ebp
cmp    %ebp,%eax
cmovb  %eax,%ebp
add    $0x2,%ebp
mov    $0x1,%ebx
nopw   0x0(%rax,%rax,1)
movzbl (%r15,%rbx,1),%edi
call   1070 <mb_is_cont@plt>
test   %rax,%rax
je     11e8 <_validate_utf8+0x78>
add    $0x1,%rbx
cmp    %rbx,%rbp
jne    11d0 <_validate_utf8+0x60>
lea    -0x5(%r13),%eax
cmp    $0x1,%eax
jbe    1223 <_validate_utf8+0xb3>
cmp    %r13d,%ebx
jne    1223 <_validate_utf8+0xb3>
mov    %r15,%rdi
mov    %r13d,%esi
call   1080 <mb_is_shortest@plt>
test   %eax,%eax
je     1223 <_validate_utf8+0xb3>
mov    %r15,%rdi
mov    %r13d,%esi
call   1040 <mb_is_surrogate@plt>
test   %eax,%eax
jne    1223 <_validate_utf8+0xb3>
mov    %r15,%rdi
mov    %r13d,%esi
call   1050 <mb_is_illegal@plt>
test   %eax,%eax
je     125b <_validate_utf8+0xeb>
mov    %r12,%rdi
mov    $0x3f,%esi
call   1090 <buf_putchar@plt>
test   %eax,%eax
je     126d <_validate_utf8+0xfd>
mov    %ebx,%eax
jmp    1253 <_validate_utf8+0xe3>
mov    %r12,%rdi
mov    $0x3f,%esi
call   1090 <buf_putchar@plt>
test   %eax,%eax
je     126d <_validate_utf8+0xfd>
mov    $0x1,%ebx
mov    $0x1,%eax
add    %rax,%r15
mov    %r15,(%r14)
jmp    126f <_validate_utf8+0xff>
mov    %r12,%rdi
mov    %r15,%rsi
mov    %r13d,%edx
call   1060 <buf_append@plt>
test   %eax,%eax
jne    1234 <_validate_utf8+0xc4>
xor    %ebx,%ebx
mov    %ebx,%eax
add    $0x8,%rsp
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
pop    %rbp
ret

LLVM IR (-O0):
%struct.template_buffer = type { i32 }
define i32 @_validate_utf8(i8** %0, i32 %1, %struct.template_buffer* %2) {
%4 = alloca i32
%5 = alloca i8**
%6 = alloca i32
%7 = alloca %struct.template_buffer*
%8 = alloca i8*
%9 = alloca i32
%10 = alloca i32
%11 = alloca i32
store i8** %0, i8*** %5
store i32 %1, i32* %6
store %struct.template_buffer* %2, %struct.template_buffer** %7
%12 = load i8**, i8*** %5
%13 = load i8*, i8** %12
store i8* %13, i8** %8
store i32 0, i32* %9
%14 = load i8*, i8** %8
%15 = getelementptr inbounds i8, i8* %14, i64 0
%16 = load i8, i8* %15
%17 = zext i8 %16 to i32
%18 = icmp sge i32 %17, 1
br i1 %18, label %19, label %34
19: ; preds = %3
%20 = load i8*, i8** %8
%21 = getelementptr inbounds i8, i8* %20, i64 0
%22 = load i8, i8* %21
%23 = zext i8 %22 to i32
%24 = icmp sle i32 %23, 127
br i1 %24, label %25, label %34
25: ; preds = %19
%26 = load %struct.template_buffer*, %struct.template_buffer** %7
%27 = load i8*, i8** %8
%28 = getelementptr inbounds i8, i8* %27, i32 1
store i8* %28, i8** %8
%29 = load i8, i8* %27
%30 = call i32 @buf_putchar(%struct.template_buffer* %26, i8 signext %29)
%31 = icmp ne i32 %30, 0
br i1 %31, label %33, label %32
32: ; preds = %25
store i32 0, i32* %4
br label %125
33: ; preds = %25
store i32 1, i32* %9
br label %121
34: ; preds = %19, %3
%35 = load i8*, i8** %8
%36 = load i8, i8* %35
%37 = call i32 @mb_num_chars(i8 zeroext %36)
store i32 %37, i32* %11
%38 = icmp ugt i32 %37, 1
br i1 %38, label %39, label %112
39: ; preds = %34
store i32 1, i32* %10
br label %40
40: ; preds = %61, %39
%41 = load i32, i32* %10
%42 = load i32, i32* %11
%43 = icmp ule i32 %41, %42
br i1 %43, label %44, label %58
44: ; preds = %40
%45 = load i32, i32* %9
%46 = load i32, i32* %10
%47 = add i32 %45, %46
%48 = load i32, i32* %6
%49 = icmp ult i32 %47, %48
br i1 %49, label %50, label %58
50: ; preds = %44
%51 = load i8*, i8** %8
%52 = load i32, i32* %10
%53 = zext i32 %52 to i64
%54 = getelementptr inbounds i8, i8* %51, i64 %53
%55 = load i8, i8* %54
%56 = call i64 @mb_is_cont(i8 zeroext %55)
%57 = icmp ne i64 %56, 0
br label %58
58: ; preds = %50, %44, %40
%59 = phi i1 [ false, %44 ], [ false, %40 ], [ %57, %50 ]
br i1 %59, label %60, label %64
60: ; preds = %58
br label %61
61: ; preds = %60
%62 = load i32, i32* %10
%63 = add i32 %62, 1
store i32 %63, i32* %10
br label %40
64: ; preds = %58
%65 = load i32, i32* %11
switch i32 %65, label %72 [
i32 6, label %66
i32 5, label %66
]
66: ; preds = %64, %64
%67 = load %struct.template_buffer*, %struct.template_buffer** %7
%68 = call i32 @buf_putchar(%struct.template_buffer* %67, i8 signext 63)
%69 = icmp ne i32 %68, 0
br i1 %69, label %71, label %70
70: ; preds = %66
store i32 0, i32* %4
br label %125
71: ; preds = %66
br label %106
72: ; preds = %64
%73 = load i32, i32* %10
%74 = load i32, i32* %11
%75 = icmp eq i32 %73, %74
br i1 %75, label %76, label %99
76: ; preds = %72
%77 = load i8*, i8** %8
%78 = load i32, i32* %11
%79 = call i32 @mb_is_shortest(i8* %77, i32 %78)
%80 = icmp ne i32 %79, 0
br i1 %80, label %81, label %99
81: ; preds = %76
%82 = load i8*, i8** %8
%83 = load i32, i32* %11
%84 = call i32 @mb_is_surrogate(i8* %82, i32 %83)
%85 = icmp ne i32 %84, 0
br i1 %85, label %99, label %86
86: ; preds = %81
%87 = load i8*, i8** %8
%88 = load i32, i32* %11
%89 = call i32 @mb_is_illegal(i8* %87, i32 %88)
%90 = icmp ne i32 %89, 0
br i1 %90, label %99, label %91
91: ; preds = %86
%92 = load %struct.template_buffer*, %struct.template_buffer** %7
%93 = load i8*, i8** %8
%94 = load i32, i32* %11
%95 = call i32 @buf_append(%struct.template_buffer* %92, i8* %93, i32 %94)
%96 = icmp ne i32 %95, 0
br i1 %96, label %98, label %97
97: ; preds = %91
store i32 0, i32* %4
br label %125
98: ; preds = %91
br label %105
99: ; preds = %86, %81, %76, %72
%100 = load %struct.template_buffer*, %struct.template_buffer** %7
%101 = call i32 @buf_putchar(%struct.template_buffer* %100, i8 signext 63)
%102 = icmp ne i32 %101, 0
br i1 %102, label %104, label %103
103: ; preds = %99
store i32 0, i32* %4
br label %125
104: ; preds = %99
br label %105
105: ; preds = %104, %98
br label %106
106: ; preds = %105, %71
%107 = load i32, i32* %10
store i32 %107, i32* %9
%108 = load i32, i32* %10
%109 = load i8*, i8** %8
%110 = zext i32 %108 to i64
%111 = getelementptr inbounds i8, i8* %109, i64 %110
store i8* %111, i8** %8
br label %120
112: ; preds = %34
%113 = load %struct.template_buffer*, %struct.template_buffer** %7
%114 = call i32 @buf_putchar(%struct.template_buffer* %113, i8 signext 63)
%115 = icmp ne i32 %114, 0
br i1 %115, label %117, label %116
116: ; preds = %112
store i32 0, i32* %4
br label %125
117: ; preds = %112
store i32 1, i32* %9
%118 = load i8*, i8** %8
%119 = getelementptr inbounds i8, i8* %118, i32 1
store i8* %119, i8** %8
br label %120
120: ; preds = %117, %106
br label %121
121: ; preds = %120, %33
%122 = load i8*, i8** %8
%123 = load i8**, i8*** %5
store i8* %122, i8** %123
%124 = load i32, i32* %9
store i32 %124, i32* %4
br label %125
125: ; preds = %121, %116, %103, %97, %70, %32
%126 = load i32, i32* %4
ret i32 %126
}

LLVM IR (-O2):
%struct.template_buffer = type { i32 }
define i32 @_validate_utf8(i8** nocapture %0, i32 %1, %struct.template_buffer* %2) {
%4 = load i8*, i8** %0
%5 = load i8, i8* %4
%6 = icmp sgt i8 %5, 0
br i1 %6, label %7, label %10
7: ; preds = %3
%8 = tail call i32 @buf_putchar(%struct.template_buffer* %2, i8 signext %5)
%9 = icmp eq i32 %8, 0
br i1 %9, label %66, label %62
10: ; preds = %3
%11 = tail call i32 @mb_num_chars(i8 zeroext %5)
%12 = icmp ugt i32 %11, 1
br i1 %12, label %13, label %59
13: ; preds = %10
%14 = icmp ugt i32 %1, 1
br i1 %14, label %15, label %33
15: ; preds = %13
%16 = add i32 %11, -1
%17 = add i32 %1, -2
%18 = call i32 @llvm.umin.i32(i32 %16, i32 %17)
%19 = add nuw i32 %18, 2
%20 = zext i32 %19 to i64
br label %21
21: ; preds = %15, %27
%22 = phi i64 [ 1, %15 ], [ %28, %27 ]
%23 = getelementptr inbounds i8, i8* %4, i64 %22
%24 = load i8, i8* %23
%25 = tail call i64 @mb_is_cont(i8 zeroext %24)
%26 = icmp eq i64 %25, 0
br i1 %26, label %30, label %27
27: ; preds = %21
%28 = add nuw nsw i64 %22, 1
%29 = icmp eq i64 %28, %20
br i1 %29, label %30, label %21
30: ; preds = %27, %21
%31 = phi i64 [ %22, %21 ], [ %28, %27 ]
%32 = trunc i64 %31 to i32
br label %33
33: ; preds = %30, %13
%34 = phi i32 [ 1, %13 ], [ %32, %30 ]
%35 = add i32 %11, -5
%36 = icmp ult i32 %35, 2
br i1 %36, label %37, label %40
37: ; preds = %33
%38 = tail call i32 @buf_putchar(%struct.template_buffer* %2, i8 signext 63)
%39 = icmp eq i32 %38, 0
br i1 %39, label %66, label %57
40: ; preds = %33
%41 = icmp eq i32 %34, %11
br i1 %41, label %42, label %54
42: ; preds = %40
%43 = tail call i32 @mb_is_shortest(i8* %4, i32 %11)
%44 = icmp eq i32 %43, 0
br i1 %44, label %54, label %45
45: ; preds = %42
%46 = tail call i32 @mb_is_surrogate(i8* %4, i32 %11)
%47 = icmp eq i32 %46, 0
br i1 %47, label %48, label %54
48: ; preds = %45
%49 = tail call i32 @mb_is_illegal(i8* %4, i32 %11)
%50 = icmp eq i32 %49, 0
br i1 %50, label %51, label %54
51: ; preds = %48
%52 = tail call i32 @buf_append(%struct.template_buffer* %2, i8* %4, i32 %11)
%53 = icmp eq i32 %52, 0
br i1 %53, label %66, label %57
54: ; preds = %48, %45, %42, %40
%55 = tail call i32 @buf_putchar(%struct.template_buffer* %2, i8 signext 63)
%56 = icmp eq i32 %55, 0
br i1 %56, label %66, label %57
57: ; preds = %51, %54, %37
%58 = zext i32 %34 to i64
br label %62
59: ; preds = %10
%60 = tail call i32 @buf_putchar(%struct.template_buffer* %2, i8 signext 63)
%61 = icmp eq i32 %60, 0
br i1 %61, label %66, label %62
62: ; preds = %59, %7, %57
%63 = phi i64 [ %58, %57 ], [ 1, %7 ], [ 1, %59 ]
%64 = phi i32 [ %34, %57 ], [ 1, %7 ], [ 1, %59 ]
%65 = getelementptr inbounds i8, i8* %4, i64 %63
store i8* %65, i8** %0
br label %66
66: ; preds = %59, %54, %51, %37, %7, %62
%67 = phi i32 [ %64, %62 ], [ 0, %7 ], [ 0, %37 ], [ 0, %51 ], [ 0, %54 ], [ 0, %59 ]
ret i32 %67
}