unsigned long ut_utf8c_to_unicode(char **src_p) {
  unsigned long unicode;
  int size;
  if (!(**src_p & 0x80)) {
    unicode = **src_p;
    (*src_p)++;
    return unicode;
  } else if (!(**src_p & 0x40)) {
    (*src_p)++;
    return 0xFFFF;
  } else if (!(**src_p & 0x20)) {
    size = 1;
    unicode = **src_p & 0x1F;
  } else if (!(**src_p & 0x10)) {
    size = 2;
    unicode = **src_p & 0x0F;
  } else if (!(**src_p & 0x08)) {
    size = 3;
    unicode = **src_p & 0x07;
  } else {
    (*src_p)++;
    return 0xFFFF;
  }
  (*src_p)++;
  while (size--) {
    if ((**src_p & 0xC0) != 0x80)
      return 0xFFFF;
    unicode <<= 6;
    unicode |= **src_p & 0x3F;
    (*src_p)++;
  }
  return unicode;
}


x86 assembly (clang, -O0):
<ut_utf8c_to_unicode>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x80,%eax
cmp    $0x0,%eax
jne    114a <ut_utf8c_to_unicode+0x4a>
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbq (%rax),%rax
mov    %rax,-0x18(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rcx
add    $0x1,%rcx
mov    %rcx,(%rax)
mov    -0x18(%rbp),%rax
mov    %rax,-0x8(%rbp)
jmp    12d0 <ut_utf8c_to_unicode+0x1d0>
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x40,%eax
cmp    $0x0,%eax
jne    117b <ut_utf8c_to_unicode+0x7b>
mov    -0x10(%rbp),%rax
mov    (%rax),%rcx
add    $0x1,%rcx
mov    %rcx,(%rax)
movq   $0xffff,-0x8(%rbp)
jmp    12d0 <ut_utf8c_to_unicode+0x1d0>
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x20,%eax
cmp    $0x0,%eax
jne    11b0 <ut_utf8c_to_unicode+0xb0>
movl   $0x1,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x1f,%eax
cltq
mov    %rax,-0x18(%rbp)
jmp    123f <ut_utf8c_to_unicode+0x13f>
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x10,%eax
cmp    $0x0,%eax
jne    11e5 <ut_utf8c_to_unicode+0xe5>
movl   $0x2,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0xf,%eax
cltq
mov    %rax,-0x18(%rbp)
jmp    123a <ut_utf8c_to_unicode+0x13a>
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x8,%eax
cmp    $0x0,%eax
jne    121a <ut_utf8c_to_unicode+0x11a>
movl   $0x3,-0x1c(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x7,%eax
cltq
mov    %rax,-0x18(%rbp)
jmp    1235 <ut_utf8c_to_unicode+0x135>
mov    -0x10(%rbp),%rax
mov    (%rax),%rcx
add    $0x1,%rcx
mov    %rcx,(%rax)
movq   $0xffff,-0x8(%rbp)
jmp    12d0 <ut_utf8c_to_unicode+0x1d0>
jmp    123a <ut_utf8c_to_unicode+0x13a>
jmp    123f <ut_utf8c_to_unicode+0x13f>
jmp    1244 <ut_utf8c_to_unicode+0x144>
jmp    1249 <ut_utf8c_to_unicode+0x149>
mov    -0x10(%rbp),%rax
mov    (%rax),%rcx
add    $0x1,%rcx
mov    %rcx,(%rax)
mov    -0x1c(%rbp),%eax
mov    %eax,%ecx
add    $0xffffffff,%ecx
mov    %ecx,-0x1c(%rbp)
cmp    $0x0,%eax
je     12c8 <ut_utf8c_to_unicode+0x1c8>
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0xc0,%eax
cmp    $0x80,%eax
je     1292 <ut_utf8c_to_unicode+0x192>
movq   $0xffff,-0x8(%rbp)
jmp    12d0 <ut_utf8c_to_unicode+0x1d0>
mov    -0x18(%rbp),%rax
shl    $0x6,%rax
mov    %rax,-0x18(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rax
movsbl (%rax),%eax
and    $0x3f,%eax
cltq
or     -0x18(%rbp),%rax
mov    %rax,-0x18(%rbp)
mov    -0x10(%rbp),%rax
mov    (%rax),%rcx
add    $0x1,%rcx
mov    %rcx,(%rax)
jmp    1257 <ut_utf8c_to_unicode+0x157>
mov    -0x18(%rbp),%rax
mov    %rax,-0x8(%rbp)
mov    -0x8(%rbp),%rax
pop    %rbp
ret

x86 assembly (clang, -O2):
<ut_utf8c_to_unicode>:
mov    (%rdi),%rcx
movzbl (%rcx),%edx
test   $0x80,%dl
jne    1111 <ut_utf8c_to_unicode+0x11>
movsbq %dl,%rax
jmp    111b <ut_utf8c_to_unicode+0x1b>
mov    $0xffff,%eax
test   $0x40,%dl
jne    1123 <ut_utf8c_to_unicode+0x23>
add    $0x1,%rcx
mov    %rcx,(%rdi)
ret
test   $0x20,%dl
jne    1136 <ut_utf8c_to_unicode+0x36>
mov    $0x1,%r9b
mov    $0x1f,%r10d
xor    %r8d,%r8d
jmp    1147 <ut_utf8c_to_unicode+0x47>
test   $0x10,%dl
jne    1184 <ut_utf8c_to_unicode+0x84>
mov    $0x1,%r8b
mov    $0xf,%r10d
xor    %r9d,%r9d
lea    0x1(%rcx),%rax
mov    %rax,(%rdi)
movzbl 0x1(%rcx),%r11d
mov    %r11d,%esi
and    $0xffffffc0,%esi
mov    $0xffff,%eax
cmp    $0x80,%esi
jne    11e5 <ut_utf8c_to_unicode+0xe5>
and    %edx,%r10d
shl    $0x6,%r10
and    $0x3f,%r11d
or     %r10,%r11
lea    0x2(%rcx),%rdx
mov    %rdx,(%rdi)
test   %r9b,%r9b
je     1194 <ut_utf8c_to_unicode+0x94>
mov    %r11,%rax
ret
test   $0x8,%dl
jne    111b <ut_utf8c_to_unicode+0x1b>
mov    $0x7,%r10d
xor    %r9d,%r9d
jmp    1131 <ut_utf8c_to_unicode+0x31>
movzbl (%rdx),%edx
mov    %edx,%esi
and    $0xffffffc0,%esi
cmp    $0x80,%esi
jne    11e5 <ut_utf8c_to_unicode+0xe5>
shl    $0x6,%r11
and    $0x3f,%edx
or     %r11,%rdx
lea    0x3(%rcx),%rsi
mov    %rsi,(%rdi)
test   %r8b,%r8b
je     11be <ut_utf8c_to_unicode+0xbe>
mov    %rdx,%rax
ret
movzbl (%rsi),%r8d
mov    %r8d,%esi
and    $0xffffffc0,%esi
cmp    $0x80,%esi
jne    11e5 <ut_utf8c_to_unicode+0xe5>
shl    $0x6,%rdx
and    $0x3f,%r8d
or     %rdx,%r8
add    $0x4,%rcx
mov    %rcx,(%rdi)
mov    %r8,%rax
ret

LLVM IR (-O0):
define i64 @ut_utf8c_to_unicode(i8** %0) {
%2 = alloca i64
%3 = alloca i8**
%4 = alloca i64
%5 = alloca i32
store i8** %0, i8*** %3
%6 = load i8**, i8*** %3
%7 = load i8*, i8** %6
%8 = load i8, i8* %7
%9 = sext i8 %8 to i32
%10 = and i32 %9, 128
%11 = icmp ne i32 %10, 0
br i1 %11, label %21, label %12
12: ; preds = %1
%13 = load i8**, i8*** %3
%14 = load i8*, i8** %13
%15 = load i8, i8* %14
%16 = sext i8 %15 to i64
store i64 %16, i64* %4
%17 = load i8**, i8*** %3
%18 = load i8*, i8** %17
%19 = getelementptr inbounds i8, i8* %18, i32 1
store i8* %19, i8** %17
%20 = load i64, i64* %4
store i64 %20, i64* %2
br label %114
21: ; preds = %1
%22 = load i8**, i8*** %3
%23 = load i8*, i8** %22
%24 = load i8, i8* %23
%25 = sext i8 %24 to i32
%26 = and i32 %25, 64
%27 = icmp ne i32 %26, 0
br i1 %27, label %32, label %28
28: ; preds = %21
%29 = load i8**, i8*** %3
%30 = load i8*, i8** %29
%31 = getelementptr inbounds i8, i8* %30, i32 1
store i8* %31, i8** %29
store i64 65535, i64* %2
br label %114
32: ; preds = %21
%33 = load i8**, i8*** %3
%34 = load i8*, i8** %33
%35 = load i8, i8* %34
%36 = sext i8 %35 to i32
%37 = and i32 %36, 32
%38 = icmp ne i32 %37, 0
br i1 %38, label %46, label %39
39: ; preds = %32
store i32 1, i32* %5
%40 = load i8**, i8*** %3
%41 = load i8*, i8** %40
%42 = load i8, i8* %41
%43 = sext i8 %42 to i32
%44 = and i32 %43, 31
%45 = sext i32 %44 to i64
store i64 %45, i64* %4
br label %80
46: ; preds = %32
%47 = load i8**, i8*** %3
%48 = load i8*, i8** %47
%49 = load i8, i8* %48
%50 = sext i8 %49 to i32
%51 = and i32 %50, 16
%52 = icmp ne i32 %51, 0
br i1 %52, label %60, label %53
53: ; preds = %46
store i32 2, i32* %5
%54 = load i8**, i8*** %3
%55 = load i8*, i8** %54
%56 = load i8, i8* %55
%57 = sext i8 %56 to i32
%58 = and i32 %57, 15
%59 = sext i32 %58 to i64
store i64 %59, i64* %4
br label %79
60: ; preds = %46
%61 = load i8**, i8*** %3
%62 = load i8*, i8** %61
%63 = load i8, i8* %62
%64 = sext i8 %63 to i32
%65 = and i32 %64, 8
%66 = icmp ne i32 %65, 0
br i1 %66, label %74, label %67
67: ; preds = %60
store i32 3, i32* %5
%68 = load i8**, i8*** %3
%69 = load i8*, i8** %68
%70 = load i8, i8* %69
%71 = sext i8 %70 to i32
%72 = and i32 %71, 7
%73 = sext i32 %72 to i64
store i64 %73, i64* %4
br label %78
74: ; preds = %60
%75 = load i8**, i8*** %3
%76 = load i8*, i8** %75
%77 = getelementptr inbounds i8, i8* %76, i32 1
store i8* %77, i8** %75
store i64 65535, i64* %2
br label %114
78: ; preds = %67
br label %79
79: ; preds = %78, %53
br label %80
80: ; preds = %79, %39
br label %81
81: ; preds = %80
br label %82
82: ; preds = %81
%83 = load i8**, i8*** %3
%84 = load i8*, i8** %83
%85 = getelementptr inbounds i8, i8* %84, i32 1
store i8* %85, i8** %83
br label %86
86: ; preds = %98, %82
%87 = load i32, i32* %5
%88 = add nsw i32 %87, -1
store i32 %88, i32* %5
%89 = icmp ne i32 %87, 0
br i1 %89, label %90, label %112
90: ; preds = %86
%91 = load i8**, i8*** %3
%92 = load i8*, i8** %91
%93 = load i8, i8* %92
%94 = sext i8 %93 to i32
%95 = and i32 %94, 192
%96 = icmp ne i32 %95, 128
br i1 %96, label %97, label %98
97: ; preds = %90
store i64 65535, i64* %2
br label %114
98: ; preds = %90
%99 = load i64, i64* %4
%100 = shl i64 %99, 6
store i64 %100, i64* %4
%101 = load i8**, i8*** %3
%102 = load i8*, i8** %101
%103 = load i8, i8* %102
%104 = sext i8 %103 to i32
%105 = and i32 %104, 63
%106 = sext i32 %105 to i64
%107 = load i64, i64* %4
%108 = or i64 %107, %106
store i64 %108, i64* %4
%109 = load i8**, i8*** %3
%110 = load i8*, i8** %109
%111 = getelementptr inbounds i8, i8* %110, i32 1
store i8* %111, i8** %109
br label %86
112: ; preds = %86
%113 = load i64, i64* %4
store i64 %113, i64* %2
br label %114
114: ; preds = %112, %97, %74, %28, %12
%115 = load i64, i64* %2
ret i64 %115
}

LLVM IR (-O2):
define i64 @ut_utf8c_to_unicode(i8** nocapture %0) {
%2 = load i8*, i8** %0
%3 = load i8, i8* %2
%4 = zext i8 %3 to i32
%5 = and i32 %4, 128
%6 = icmp eq i32 %5, 0
br i1 %6, label %7, label %9
7: ; preds = %1
%8 = sext i8 %3 to i64
br label %59
9: ; preds = %1
%10 = and i32 %4, 64
%11 = icmp eq i32 %10, 0
br i1 %11, label %59, label %12
12: ; preds = %9
%13 = and i32 %4, 32
%14 = icmp eq i32 %13, 0
br i1 %14, label %21, label %15
15: ; preds = %12
%16 = and i32 %4, 16
%17 = icmp eq i32 %16, 0
br i1 %17, label %21, label %18
18: ; preds = %15
%19 = and i32 %4, 8
%20 = icmp eq i32 %19, 0
br i1 %20, label %21, label %59
21: ; preds = %18, %15, %12
%22 = phi i32 [ 31, %12 ], [ 15, %15 ], [ 7, %18 ]
%23 = phi i1 [ true, %12 ], [ false, %15 ], [ false, %18 ]
%24 = phi i1 [ false, %12 ], [ true, %15 ], [ false, %18 ]
%25 = and i32 %22, %4
%26 = getelementptr inbounds i8, i8* %2, i64 1
store i8* %26, i8** %0
%27 = load i8, i8* %26
%28 = zext i8 %27 to i32
%29 = and i32 %28, 192
%30 = icmp eq i32 %29, 128
br i1 %30, label %31, label %62
31: ; preds = %21
%32 = shl nuw nsw i32 %25, 6
%33 = and i32 %28, 63
%34 = or i32 %32, %33
%35 = zext i32 %34 to i64
%36 = getelementptr inbounds i8, i8* %2, i64 2
store i8* %36, i8** %0
br i1 %23, label %62, label %37
37: ; preds = %31
%38 = load i8, i8* %36
%39 = zext i8 %38 to i32
%40 = and i32 %39, 192
%41 = icmp eq i32 %40, 128
br i1 %41, label %42, label %62
42: ; preds = %37
%43 = shl nuw nsw i64 %35, 6
%44 = and i32 %39, 63
%45 = zext i32 %44 to i64
%46 = or i64 %43, %45
%47 = getelementptr inbounds i8, i8* %2, i64 3
store i8* %47, i8** %0
br i1 %24, label %62, label %48
48: ; preds = %42
%49 = load i8, i8* %47
%50 = zext i8 %49 to i32
%51 = and i32 %50, 192
%52 = icmp eq i32 %51, 128
br i1 %52, label %53, label %62
53: ; preds = %48
%54 = shl nuw nsw i64 %46, 6
%55 = and i32 %50, 63
%56 = zext i32 %55 to i64
%57 = or i64 %54, %56
%58 = getelementptr inbounds i8, i8* %2, i64 4
store i8* %58, i8** %0
br label %62
59: ; preds = %18, %9, %7
%60 = phi i64 [ %8, %7 ], [ 65535, %9 ], [ 65535, %18 ]
%61 = getelementptr inbounds i8, i8* %2, i64 1
store i8* %61, i8** %0
br label %62
62: ; preds = %31, %21, %37, %42, %48, %53, %59
%63 = phi i64 [ %60, %59 ], [ %35, %31 ], [ 65535, %21 ], [ 65535, %37 ], [ %46, %42 ], [ 65535, %48 ], [ %57, %53 ]
ret i64 %63
}