int Utf8ToWide(unsigned short *dest, const char *src, int destLen) {
  int di, si, si2, si3;
  int conv;
  conv = 0;
  di = 0;
  si = 0;
  destLen--;
  while ((src[si] != '\0') && (di < destLen)) {
    si2 = si + 1;
    si3 = si2 + 1;
    if ((unsigned char)src[si] <= 0x7F) {
      dest[di++] = src[si++];
      conv++;
    } else if ((unsigned char)src[si] <= 0xDF) {
      dest[di++] = ((src[si] & 0x1F) << 6) | (src[si2] & 0x3F);
      conv++;
      si += 2;
    } else if ((unsigned char)src[si] <= 0xEF) {
      dest[di++] = ((src[si] & 0x0F) << 12) | ((src[si2] & 0x3F) << 6) |
                   (src[si3] & 0x3F);
      conv++;
      si += 3;
    } else if ((unsigned char)src[si] <= 0xF7) {
      si += 4;
    }
  }
  dest[di] = '\0';
  return conv;
}


x86 assembly (clang, -O0):
<Utf8ToWide>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %edx,-0x14(%rbp)
movl   $0x0,-0x28(%rbp)
movl   $0x0,-0x18(%rbp)
movl   $0x0,-0x1c(%rbp)
mov    -0x14(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x14(%rbp)
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movsbl (%rax,%rcx,1),%ecx
xor    %eax,%eax
cmp    $0x0,%ecx
mov    %al,-0x29(%rbp)
je     1153 <Utf8ToWide+0x53>
mov    -0x18(%rbp),%eax
cmp    -0x14(%rbp),%eax
setl   %al
mov    %al,-0x29(%rbp)
mov    -0x29(%rbp),%al
test   $0x1,%al
jne    1163 <Utf8ToWide+0x63>
jmp    12e3 <Utf8ToWide+0x1e3>
mov    -0x1c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
cmp    $0x7f,%eax
jg     11c7 <Utf8ToWide+0xc7>
mov    -0x10(%rbp),%rax
mov    -0x1c(%rbp),%ecx
mov    %ecx,%edx
add    $0x1,%edx
mov    %edx,-0x1c(%rbp)
movslq %ecx,%rcx
movsbl (%rax,%rcx,1),%eax
mov    %ax,%dx
mov    -0x8(%rbp),%rax
mov    -0x18(%rbp),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,-0x18(%rbp)
movslq %ecx,%rcx
mov    %dx,(%rax,%rcx,2)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
jmp    12de <Utf8ToWide+0x1de>
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
cmp    $0xdf,%eax
jg     1231 <Utf8ToWide+0x131>
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movsbl (%rax,%rcx,1),%eax
and    $0x1f,%eax
shl    $0x6,%eax
mov    -0x10(%rbp),%rcx
movslq -0x20(%rbp),%rdx
movsbl (%rcx,%rdx,1),%ecx
and    $0x3f,%ecx
or     %ecx,%eax
mov    %ax,%dx
mov    -0x8(%rbp),%rax
mov    -0x18(%rbp),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,-0x18(%rbp)
movslq %ecx,%rcx
mov    %dx,(%rax,%rcx,2)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
mov    -0x1c(%rbp),%eax
add    $0x2,%eax
mov    %eax,-0x1c(%rbp)
jmp    12d9 <Utf8ToWide+0x1d9>
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
cmp    $0xef,%eax
jg     12af <Utf8ToWide+0x1af>
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movsbl (%rax,%rcx,1),%eax
and    $0xf,%eax
shl    $0xc,%eax
mov    -0x10(%rbp),%rcx
movslq -0x20(%rbp),%rdx
movsbl (%rcx,%rdx,1),%ecx
and    $0x3f,%ecx
shl    $0x6,%ecx
or     %ecx,%eax
mov    -0x10(%rbp),%rcx
movslq -0x24(%rbp),%rdx
movsbl (%rcx,%rdx,1),%ecx
and    $0x3f,%ecx
or     %ecx,%eax
mov    %ax,%dx
mov    -0x8(%rbp),%rax
mov    -0x18(%rbp),%ecx
mov    %ecx,%esi
add    $0x1,%esi
mov    %esi,-0x18(%rbp)
movslq %ecx,%rcx
mov    %dx,(%rax,%rcx,2)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
mov    -0x1c(%rbp),%eax
add    $0x3,%eax
mov    %eax,-0x1c(%rbp)
jmp    12d4 <Utf8ToWide+0x1d4>
mov    -0x10(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movzbl (%rax,%rcx,1),%eax
cmp    $0xf7,%eax
jg     12cf <Utf8ToWide+0x1cf>
mov    -0x1c(%rbp),%eax
add    $0x4,%eax
mov    %eax,-0x1c(%rbp)
jmp    12d4 <Utf8ToWide+0x1d4>
jmp    12d9 <Utf8ToWide+0x1d9>
jmp    12de <Utf8ToWide+0x1de>
jmp    112d <Utf8ToWide+0x2d>
mov    -0x8(%rbp),%rax
movslq -0x18(%rbp),%rcx
movw   $0x0,(%rax,%rcx,2)
mov    -0x28(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<Utf8ToWide>:
push   %rbx
mov    (%rsi),%cl
xor    %r8d,%r8d
test   %cl,%cl
je     11e6 <Utf8ToWide+0xe6>
mov    $0x0,%eax
cmp    $0x2,%edx
jl     11e8 <Utf8ToWide+0xe8>
add    $0xffffffff,%edx
xor    %eax,%eax
xor    %r8d,%r8d
xor    %r9d,%r9d
nopw   0x0(%rax,%rax,1)
movslq %r9d,%r10
lea    0x1(%r10),%r11
test   %cl,%cl
js     1160 <Utf8ToWide+0x60>
movzbl %cl,%ecx
movslq %r8d,%rbx
add    $0x1,%r8d
mov    %cx,(%rdi,%rbx,2)
add    $0x1,%eax
mov    %r11d,%r9d
jmp    11d0 <Utf8ToWide+0xd0>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movsbl %cl,%ebx
add    $0x2,%r10
cmp    $0xdf,%cl
ja     118f <Utf8ToWide+0x8f>
and    $0x1f,%ebx
shl    $0x6,%ebx
movzbl (%rsi,%r11,1),%ecx
and    $0x3f,%ecx
or     %ebx,%ecx
movslq %r8d,%rbx
add    $0x1,%r8d
mov    %cx,(%rdi,%rbx,2)
add    $0x1,%eax
mov    %r10d,%r9d
jmp    11d0 <Utf8ToWide+0xd0>
cmp    $0xef,%cl
ja     11c2 <Utf8ToWide+0xc2>
shl    $0xc,%ebx
movzbl (%rsi,%r11,1),%ecx
and    $0x3f,%ecx
shl    $0x6,%ecx
or     %ebx,%ecx
movzbl (%rsi,%r10,1),%ebx
and    $0x3f,%ebx
or     %ecx,%ebx
movslq %r8d,%rcx
add    $0x1,%r8d
mov    %bx,(%rdi,%rcx,2)
add    $0x1,%eax
add    $0x3,%r9d
jmp    11d0 <Utf8ToWide+0xd0>
cmp    $0xf8,%cl
jae    11d0 <Utf8ToWide+0xd0>
add    $0x4,%r9d
nopl   0x0(%rax,%rax,1)
movslq %r9d,%rcx
movzbl (%rsi,%rcx,1),%ecx
test   %cl,%cl
je     11e8 <Utf8ToWide+0xe8>
cmp    %edx,%r8d
jl     1130 <Utf8ToWide+0x30>
jmp    11e8 <Utf8ToWide+0xe8>
xor    %eax,%eax
movslq %r8d,%rcx
movw   $0x0,(%rdi,%rcx,2)
pop    %rbx
ret

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

LLVM IR (-O2):
define i32 @Utf8ToWide(i16* nocapture writeonly %0, i8* nocapture %1, i32 %2) {
%4 = add nsw i32 %2, -1
%5 = load i8, i8* %1
%6 = icmp ne i8 %5, 0
%7 = icmp sgt i32 %2, 1
%8 = and i1 %6, %7
br i1 %8, label %9, label %77
9: ; preds = %3, %67
%10 = phi i8 [ %73, %67 ], [ %5, %3 ]
%11 = phi i32 [ %70, %67 ], [ 0, %3 ]
%12 = phi i32 [ %69, %67 ], [ 0, %3 ]
%13 = phi i32 [ %68, %67 ], [ 0, %3 ]
%14 = sext i8 %10 to i32
%15 = add nsw i32 %13, 1
%16 = add nsw i32 %13, 2
%17 = icmp sgt i8 %10, -1
br i1 %17, label %18, label %24
18: ; preds = %9
%19 = zext i8 %10 to i16
%20 = add nsw i32 %12, 1
%21 = sext i32 %12 to i64
%22 = getelementptr inbounds i16, i16* %0, i64 %21
store i16 %19, i16* %22
%23 = add nsw i32 %11, 1
br label %67
24: ; preds = %9
%25 = icmp ult i8 %10, -32
br i1 %25, label %26, label %40
26: ; preds = %24
%27 = shl nsw i32 %14, 6
%28 = and i32 %27, 1984
%29 = sext i32 %15 to i64
%30 = getelementptr inbounds i8, i8* %1, i64 %29
%31 = load i8, i8* %30
%32 = and i8 %31, 63
%33 = zext i8 %32 to i32
%34 = or i32 %28, %33
%35 = trunc i32 %34 to i16
%36 = add nsw i32 %12, 1
%37 = sext i32 %12 to i64
%38 = getelementptr inbounds i16, i16* %0, i64 %37
store i16 %35, i16* %38
%39 = add nsw i32 %11, 1
br label %67
40: ; preds = %24
%41 = icmp ult i8 %10, -16
br i1 %41, label %42, label %63
42: ; preds = %40
%43 = shl nsw i32 %14, 12
%44 = sext i32 %15 to i64
%45 = getelementptr inbounds i8, i8* %1, i64 %44
%46 = load i8, i8* %45
%47 = and i8 %46, 63
%48 = zext i8 %47 to i32
%49 = shl nuw nsw i32 %48, 6
%50 = or i32 %49, %43
%51 = sext i32 %16 to i64
%52 = getelementptr inbounds i8, i8* %1, i64 %51
%53 = load i8, i8* %52
%54 = and i8 %53, 63
%55 = zext i8 %54 to i32
%56 = or i32 %50, %55
%57 = trunc i32 %56 to i16
%58 = add nsw i32 %12, 1
%59 = sext i32 %12 to i64
%60 = getelementptr inbounds i16, i16* %0, i64 %59
store i16 %57, i16* %60
%61 = add nsw i32 %11, 1
%62 = add nsw i32 %13, 3
br label %67
63: ; preds = %40
%64 = icmp ult i8 %10, -8
%65 = add nsw i32 %13, 4
%66 = select i1 %64, i32 %65, i32 %13
br label %67
67: ; preds = %63, %26, %42, %18
%68 = phi i32 [ %15, %18 ], [ %16, %26 ], [ %62, %42 ], [ %66, %63 ]
%69 = phi i32 [ %20, %18 ], [ %36, %26 ], [ %58, %42 ], [ %12, %63 ]
%70 = phi i32 [ %23, %18 ], [ %39, %26 ], [ %61, %42 ], [ %11, %63 ]
%71 = sext i32 %68 to i64
%72 = getelementptr inbounds i8, i8* %1, i64 %71
%73 = load i8, i8* %72
%74 = icmp ne i8 %73, 0
%75 = icmp slt i32 %69, %4
%76 = select i1 %74, i1 %75, i1 false
br i1 %76, label %9, label %77
77: ; preds = %67, %3
%78 = phi i32 [ 0, %3 ], [ %69, %67 ]
%79 = phi i32 [ 0, %3 ], [ %70, %67 ]
%80 = sext i32 %78 to i64
%81 = getelementptr inbounds i16, i16* %0, i64 %80
store i16 0, i16* %81
ret i32 %79
}