unsigned int next_utf8(const char *text, int *pos) {
  register unsigned int c, d;
  c = text[(*pos)++];
  if ((c & 0x80) == 0)
    return c;
  if ((c & 0xE0) == 0xC0) {
    c &= 0x3F;
    c <<= 6;
    d = text[(*pos)++];
    if ((d & 0x80) == 0)
      goto utf8_error;
    c |= (d & 0x3F);
    return c;
  }
  if ((c & 0xF0) == 0xE0) {
    c &= 0x1F;
    c <<= 6;
    d = text[(*pos)++];
    if ((d & 0x80) == 0)
      goto utf8_error;
    c |= (d & 0x3F);
    c <<= 6;
    d = text[(*pos)++];
    if ((d & 0x80) == 0)
      goto utf8_error;
    c |= (d & 0x3F);
    return c;
  }
  if ((c & 0xF8) == 0xF0) {
    c &= 0x0F;
    c <<= 6;
    d = text[(*pos)++];
    if ((d & 0x80) == 0)
      goto utf8_error;
    c |= (d & 0x3F);
    c <<= 6;
    d = text[(*pos)++];
    if ((d & 0x80) == 0)
      goto utf8_error;
    c |= (d & 0x3F);
    c <<= 6;
    d = text[(*pos)++];
    if ((d & 0x80) == 0)
      goto utf8_error;
    c |= (d & 0x3F);
    return c;
  }
utf8_error:
  return 0xFFFD;
}


x86 assembly (clang, -O0):
<next_utf8>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    %rsi,-0x18(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x18(%rbp),%rdx
mov    (%rdx),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,(%rdx)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    1143 <next_utf8+0x43>
mov    -0x1c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    1368 <next_utf8+0x268>
mov    -0x1c(%rbp),%eax
and    $0xe0,%eax
cmp    $0xc0,%eax
jne    11b0 <next_utf8+0xb0>
mov    -0x1c(%rbp),%eax
and    $0x3f,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
shl    $0x6,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x18(%rbp),%rdx
mov    (%rdx),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,(%rdx)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    1199 <next_utf8+0x99>
jmp    1361 <next_utf8+0x261>
mov    -0x20(%rbp),%eax
and    $0x3f,%eax
or     -0x1c(%rbp),%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    1368 <next_utf8+0x268>
mov    -0x1c(%rbp),%eax
and    $0xf0,%eax
cmp    $0xe0,%eax
jne    1263 <next_utf8+0x163>
mov    -0x1c(%rbp),%eax
and    $0x1f,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
shl    $0x6,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x18(%rbp),%rdx
mov    (%rdx),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,(%rdx)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    1206 <next_utf8+0x106>
jmp    1361 <next_utf8+0x261>
mov    -0x20(%rbp),%eax
and    $0x3f,%eax
or     -0x1c(%rbp),%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
shl    $0x6,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x18(%rbp),%rdx
mov    (%rdx),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,(%rdx)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    124c <next_utf8+0x14c>
jmp    1361 <next_utf8+0x261>
mov    -0x20(%rbp),%eax
and    $0x3f,%eax
or     -0x1c(%rbp),%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    1368 <next_utf8+0x268>
mov    -0x1c(%rbp),%eax
and    $0xf8,%eax
cmp    $0xf0,%eax
jne    135c <next_utf8+0x25c>
mov    -0x1c(%rbp),%eax
and    $0xf,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
shl    $0x6,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x18(%rbp),%rdx
mov    (%rdx),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,(%rdx)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    12b9 <next_utf8+0x1b9>
jmp    1361 <next_utf8+0x261>
mov    -0x20(%rbp),%eax
and    $0x3f,%eax
or     -0x1c(%rbp),%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
shl    $0x6,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x18(%rbp),%rdx
mov    (%rdx),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,(%rdx)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    12ff <next_utf8+0x1ff>
jmp    1361 <next_utf8+0x261>
mov    -0x20(%rbp),%eax
and    $0x3f,%eax
or     -0x1c(%rbp),%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
shl    $0x6,%eax
mov    %eax,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    -0x18(%rbp),%rdx
mov    (%rdx),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,(%rdx)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    1345 <next_utf8+0x245>
jmp    1361 <next_utf8+0x261>
mov    -0x20(%rbp),%eax
and    $0x3f,%eax
or     -0x1c(%rbp),%eax
mov    %eax,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    1368 <next_utf8+0x268>
jmp    1361 <next_utf8+0x261>
movl   $0xfffd,-0x4(%rbp)
mov    -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<next_utf8>:
movslq (%rsi),%rdx
lea    0x1(%rdx),%rcx
mov    %ecx,(%rsi)
movsbl (%rdi,%rdx,1),%r9d
test   $0x80,%r9b
jne    1118 <next_utf8+0x18>
mov    %r9d,%eax
ret
mov    %r9d,%eax
and    $0xe0,%eax
cmp    $0xc0,%eax
jne    114f <next_utf8+0x4f>
add    $0x2,%edx
mov    %edx,(%rsi)
movzbl (%rdi,%rcx,1),%ecx
mov    $0xfffd,%eax
test   $0x80,%cl
je     1211 <next_utf8+0x111>
and    $0x3f,%r9d
shl    $0x6,%r9d
and    $0x3f,%ecx
or     %r9d,%ecx
mov    %ecx,%eax
ret
mov    %r9d,%eax
and    $0xf0,%eax
cmp    $0xe0,%eax
jne    11a2 <next_utf8+0xa2>
lea    0x2(%rdx),%r8
mov    %r8d,(%rsi)
movzbl (%rdi,%rcx,1),%ecx
mov    $0xfffd,%eax
test   $0x80,%cl
je     1211 <next_utf8+0x111>
add    $0x3,%edx
mov    %edx,(%rsi)
movzbl (%rdi,%r8,1),%edx
test   $0x80,%dl
je     1211 <next_utf8+0x111>
and    $0x1f,%r9d
shl    $0x6,%r9d
and    $0x3f,%ecx
or     %r9d,%ecx
shl    $0x6,%ecx
and    $0x3f,%edx
or     %ecx,%edx
jmp    120f <next_utf8+0x10f>
mov    %r9d,%r8d
and    $0xf8,%r8d
mov    $0xfffd,%eax
cmp    $0xf0,%r8d
jne    1211 <next_utf8+0x111>
lea    0x2(%rdx),%r10
mov    %r10d,(%rsi)
movzbl (%rdi,%rcx,1),%r8d
test   $0x80,%r8b
je     1211 <next_utf8+0x111>
lea    0x3(%rdx),%ecx
mov    %ecx,(%rsi)
movsbl (%rdi,%r10,1),%r10d
test   $0x80,%r10b
je     1211 <next_utf8+0x111>
lea    0x4(%rdx),%ecx
mov    %ecx,(%rsi)
movzbl 0x3(%rdi,%rdx,1),%edx
test   $0x80,%dl
je     1211 <next_utf8+0x111>
and    $0xf,%r9d
shl    $0x6,%r9d
and    $0x3f,%r8d
or     %r9d,%r8d
shl    $0xc,%r8d
and    $0x3f,%r10d
shl    $0x6,%r10d
or     %r8d,%r10d
and    $0x3f,%edx
or     %r10d,%edx
mov    %edx,%eax
ret

LLVM IR (-O0):
define i32 @next_utf8(i8* %0, i32* %1) {
%3 = alloca i32
%4 = alloca i8*
%5 = alloca i32*
%6 = alloca i32
%7 = alloca i32
store i8* %0, i8** %4
store i32* %1, i32** %5
%8 = load i8*, i8** %4
%9 = load i32*, i32** %5
%10 = load i32, i32* %9
%11 = add nsw i32 %10, 1
store i32 %11, i32* %9
%12 = sext i32 %10 to i64
%13 = getelementptr inbounds i8, i8* %8, i64 %12
%14 = load i8, i8* %13
%15 = sext i8 %14 to i32
store i32 %15, i32* %6
%16 = load i32, i32* %6
%17 = and i32 %16, 128
%18 = icmp eq i32 %17, 0
br i1 %18, label %19, label %21
19: ; preds = %2
%20 = load i32, i32* %6
store i32 %20, i32* %3
br label %161
21: ; preds = %2
%22 = load i32, i32* %6
%23 = and i32 %22, 224
%24 = icmp eq i32 %23, 192
br i1 %24, label %25, label %48
25: ; preds = %21
%26 = load i32, i32* %6
%27 = and i32 %26, 63
store i32 %27, i32* %6
%28 = load i32, i32* %6
%29 = shl i32 %28, 6
store i32 %29, i32* %6
%30 = load i8*, i8** %4
%31 = load i32*, i32** %5
%32 = load i32, i32* %31
%33 = add nsw i32 %32, 1
store i32 %33, i32* %31
%34 = sext i32 %32 to i64
%35 = getelementptr inbounds i8, i8* %30, i64 %34
%36 = load i8, i8* %35
%37 = sext i8 %36 to i32
store i32 %37, i32* %7
%38 = load i32, i32* %7
%39 = and i32 %38, 128
%40 = icmp eq i32 %39, 0
br i1 %40, label %41, label %42
41: ; preds = %25
br label %160
42: ; preds = %25
%43 = load i32, i32* %7
%44 = and i32 %43, 63
%45 = load i32, i32* %6
%46 = or i32 %45, %44
store i32 %46, i32* %6
%47 = load i32, i32* %6
store i32 %47, i32* %3
br label %161
48: ; preds = %21
%49 = load i32, i32* %6
%50 = and i32 %49, 240
%51 = icmp eq i32 %50, 224
br i1 %51, label %52, label %94
52: ; preds = %48
%53 = load i32, i32* %6
%54 = and i32 %53, 31
store i32 %54, i32* %6
%55 = load i32, i32* %6
%56 = shl i32 %55, 6
store i32 %56, i32* %6
%57 = load i8*, i8** %4
%58 = load i32*, i32** %5
%59 = load i32, i32* %58
%60 = add nsw i32 %59, 1
store i32 %60, i32* %58
%61 = sext i32 %59 to i64
%62 = getelementptr inbounds i8, i8* %57, i64 %61
%63 = load i8, i8* %62
%64 = sext i8 %63 to i32
store i32 %64, i32* %7
%65 = load i32, i32* %7
%66 = and i32 %65, 128
%67 = icmp eq i32 %66, 0
br i1 %67, label %68, label %69
68: ; preds = %52
br label %160
69: ; preds = %52
%70 = load i32, i32* %7
%71 = and i32 %70, 63
%72 = load i32, i32* %6
%73 = or i32 %72, %71
store i32 %73, i32* %6
%74 = load i32, i32* %6
%75 = shl i32 %74, 6
store i32 %75, i32* %6
%76 = load i8*, i8** %4
%77 = load i32*, i32** %5
%78 = load i32, i32* %77
%79 = add nsw i32 %78, 1
store i32 %79, i32* %77
%80 = sext i32 %78 to i64
%81 = getelementptr inbounds i8, i8* %76, i64 %80
%82 = load i8, i8* %81
%83 = sext i8 %82 to i32
store i32 %83, i32* %7
%84 = load i32, i32* %7
%85 = and i32 %84, 128
%86 = icmp eq i32 %85, 0
br i1 %86, label %87, label %88
87: ; preds = %69
br label %160
88: ; preds = %69
%89 = load i32, i32* %7
%90 = and i32 %89, 63
%91 = load i32, i32* %6
%92 = or i32 %91, %90
store i32 %92, i32* %6
%93 = load i32, i32* %6
store i32 %93, i32* %3
br label %161
94: ; preds = %48
%95 = load i32, i32* %6
%96 = and i32 %95, 248
%97 = icmp eq i32 %96, 240
br i1 %97, label %98, label %159
98: ; preds = %94
%99 = load i32, i32* %6
%100 = and i32 %99, 15
store i32 %100, i32* %6
%101 = load i32, i32* %6
%102 = shl i32 %101, 6
store i32 %102, i32* %6
%103 = load i8*, i8** %4
%104 = load i32*, i32** %5
%105 = load i32, i32* %104
%106 = add nsw i32 %105, 1
store i32 %106, i32* %104
%107 = sext i32 %105 to i64
%108 = getelementptr inbounds i8, i8* %103, i64 %107
%109 = load i8, i8* %108
%110 = sext i8 %109 to i32
store i32 %110, i32* %7
%111 = load i32, i32* %7
%112 = and i32 %111, 128
%113 = icmp eq i32 %112, 0
br i1 %113, label %114, label %115
114: ; preds = %98
br label %160
115: ; preds = %98
%116 = load i32, i32* %7
%117 = and i32 %116, 63
%118 = load i32, i32* %6
%119 = or i32 %118, %117
store i32 %119, i32* %6
%120 = load i32, i32* %6
%121 = shl i32 %120, 6
store i32 %121, i32* %6
%122 = load i8*, i8** %4
%123 = load i32*, i32** %5
%124 = load i32, i32* %123
%125 = add nsw i32 %124, 1
store i32 %125, i32* %123
%126 = sext i32 %124 to i64
%127 = getelementptr inbounds i8, i8* %122, i64 %126
%128 = load i8, i8* %127
%129 = sext i8 %128 to i32
store i32 %129, i32* %7
%130 = load i32, i32* %7
%131 = and i32 %130, 128
%132 = icmp eq i32 %131, 0
br i1 %132, label %133, label %134
133: ; preds = %115
br label %160
134: ; preds = %115
%135 = load i32, i32* %7
%136 = and i32 %135, 63
%137 = load i32, i32* %6
%138 = or i32 %137, %136
store i32 %138, i32* %6
%139 = load i32, i32* %6
%140 = shl i32 %139, 6
store i32 %140, i32* %6
%141 = load i8*, i8** %4
%142 = load i32*, i32** %5
%143 = load i32, i32* %142
%144 = add nsw i32 %143, 1
store i32 %144, i32* %142
%145 = sext i32 %143 to i64
%146 = getelementptr inbounds i8, i8* %141, i64 %145
%147 = load i8, i8* %146
%148 = sext i8 %147 to i32
store i32 %148, i32* %7
%149 = load i32, i32* %7
%150 = and i32 %149, 128
%151 = icmp eq i32 %150, 0
br i1 %151, label %152, label %153
152: ; preds = %134
br label %160
153: ; preds = %134
%154 = load i32, i32* %7
%155 = and i32 %154, 63
%156 = load i32, i32* %6
%157 = or i32 %156, %155
store i32 %157, i32* %6
%158 = load i32, i32* %6
store i32 %158, i32* %3
br label %161
159: ; preds = %94
br label %160
160: ; preds = %159, %152, %133, %114, %87, %68, %41
store i32 65533, i32* %3
br label %161
161: ; preds = %160, %153, %88, %42, %19
%162 = load i32, i32* %3
ret i32 %162
}

LLVM IR (-O2):
define i32 @next_utf8(i8* nocapture %0, i32* nocapture %1) {
%3 = load i32, i32* %1
%4 = add nsw i32 %3, 1
store i32 %4, i32* %1
%5 = sext i32 %3 to i64
%6 = getelementptr inbounds i8, i8* %0, i64 %5
%7 = load i8, i8* %6
%8 = sext i8 %7 to i32
%9 = and i32 %8, 128
%10 = icmp eq i32 %9, 0
br i1 %10, label %92, label %11
11: ; preds = %2
%12 = and i32 %8, 224
%13 = icmp eq i32 %12, 192
br i1 %13, label %14, label %27
14: ; preds = %11
%15 = add nsw i32 %3, 2
store i32 %15, i32* %1
%16 = sext i32 %4 to i64
%17 = getelementptr inbounds i8, i8* %0, i64 %16
%18 = load i8, i8* %17
%19 = zext i8 %18 to i32
%20 = and i32 %19, 128
%21 = icmp eq i32 %20, 0
br i1 %21, label %92, label %22
22: ; preds = %14
%23 = shl nsw i32 %8, 6
%24 = and i32 %23, 4032
%25 = and i32 %19, 63
%26 = or i32 %25, %24
br label %92
27: ; preds = %11
%28 = and i32 %8, 240
%29 = icmp eq i32 %28, 224
br i1 %29, label %30, label %54
30: ; preds = %27
%31 = add nsw i32 %3, 2
store i32 %31, i32* %1
%32 = sext i32 %4 to i64
%33 = getelementptr inbounds i8, i8* %0, i64 %32
%34 = load i8, i8* %33
%35 = zext i8 %34 to i32
%36 = and i32 %35, 128
%37 = icmp eq i32 %36, 0
br i1 %37, label %92, label %38
38: ; preds = %30
%39 = add nsw i32 %3, 3
store i32 %39, i32* %1
%40 = sext i32 %31 to i64
%41 = getelementptr inbounds i8, i8* %0, i64 %40
%42 = load i8, i8* %41
%43 = zext i8 %42 to i32
%44 = and i32 %43, 128
%45 = icmp eq i32 %44, 0
br i1 %45, label %92, label %46
46: ; preds = %38
%47 = shl nsw i32 %8, 6
%48 = and i32 %47, 1984
%49 = and i32 %35, 63
%50 = or i32 %49, %48
%51 = shl nuw nsw i32 %50, 6
%52 = and i32 %43, 63
%53 = or i32 %52, %51
br label %92
54: ; preds = %27
%55 = and i32 %8, 248
%56 = icmp eq i32 %55, 240
br i1 %56, label %57, label %92
57: ; preds = %54
%58 = add nsw i32 %3, 2
store i32 %58, i32* %1
%59 = sext i32 %4 to i64
%60 = getelementptr inbounds i8, i8* %0, i64 %59
%61 = load i8, i8* %60
%62 = zext i8 %61 to i32
%63 = and i32 %62, 128
%64 = icmp eq i32 %63, 0
br i1 %64, label %92, label %65
65: ; preds = %57
%66 = add nsw i32 %3, 3
store i32 %66, i32* %1
%67 = sext i32 %58 to i64
%68 = getelementptr inbounds i8, i8* %0, i64 %67
%69 = load i8, i8* %68
%70 = sext i8 %69 to i32
%71 = and i32 %70, 128
%72 = icmp eq i32 %71, 0
br i1 %72, label %92, label %73
73: ; preds = %65
%74 = add nsw i32 %3, 4
store i32 %74, i32* %1
%75 = sext i32 %66 to i64
%76 = getelementptr inbounds i8, i8* %0, i64 %75
%77 = load i8, i8* %76
%78 = zext i8 %77 to i32
%79 = and i32 %78, 128
%80 = icmp eq i32 %79, 0
br i1 %80, label %92, label %81
81: ; preds = %73
%82 = shl nsw i32 %8, 6
%83 = and i32 %82, 960
%84 = and i32 %62, 63
%85 = or i32 %84, %83
%86 = shl nuw nsw i32 %85, 12
%87 = shl nsw i32 %70, 6
%88 = and i32 %87, 4032
%89 = or i32 %88, %86
%90 = and i32 %78, 63
%91 = or i32 %90, %89
br label %92
92: ; preds = %14, %30, %38, %57, %65, %73, %54, %2, %81, %46, %22
%93 = phi i32 [ %26, %22 ], [ %53, %46 ], [ %91, %81 ], [ %8, %2 ], [ 65533, %54 ], [ 65533, %73 ], [ 65533, %65 ], [ 65533, %57 ], [ 65533, %38 ], [ 65533, %30 ], [ 65533, %14 ]
ret i32 %93
}