int midpUTF8Decode(unsigned char *pUtf8, int utf8Len, unsigned short *pUcs2,
                   int ucs2Len) {
  int i;
  int j;
  unsigned char current;
  for (i = 0, j = 0; i < ucs2Len && j < utf8Len; i++) {
    current = pUtf8[j++];
    if (current < 0x80) {
      pUcs2[i] = (unsigned short)current;
      continue;
    }
    if ((current & 0xE0) == 0xC0) {
      pUcs2[i] = (unsigned short)(current & 0x1F) << 6;
      if (j == utf8Len) {
        return -1;
      }
      pUcs2[i] += (unsigned short)(pUtf8[j++] & 0x3F);
      continue;
    }
    if ((current & 0xF0) == 0xE0) {
      pUcs2[i] = (unsigned short)(current & 0x0F) << 12;
      if (j == utf8Len) {
        return -2;
      }
      pUcs2[i] += (unsigned short)(pUtf8[j++] & 0x3F) << 6;
      if (j == utf8Len) {
        return -3;
      }
      pUcs2[i] += (unsigned short)(pUtf8[j++] & 0x3F);
      continue;
    }
    return -4;
  }
  if (j < utf8Len) {
    return -5;
  }
  return i;
}


x86 assembly (clang, -O0):
<midpUTF8Decode>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    %esi,-0x14(%rbp)
mov    %rdx,-0x20(%rbp)
mov    %ecx,-0x24(%rbp)
movl   $0x0,-0x28(%rbp)
movl   $0x0,-0x2c(%rbp)
mov    -0x28(%rbp),%ecx
xor    %eax,%eax
cmp    -0x24(%rbp),%ecx
mov    %al,-0x2e(%rbp)
jge    113d <midpUTF8Decode+0x3d>
mov    -0x2c(%rbp),%eax
cmp    -0x14(%rbp),%eax
setl   %al
mov    %al,-0x2e(%rbp)
mov    -0x2e(%rbp),%al
test   $0x1,%al
jne    114d <midpUTF8Decode+0x4d>
jmp    12e5 <midpUTF8Decode+0x1e5>
mov    -0x10(%rbp),%rax
mov    -0x2c(%rbp),%ecx
mov    %ecx,%edx
add    $0x1,%edx
mov    %edx,-0x2c(%rbp)
movslq %ecx,%rcx
mov    (%rax,%rcx,1),%al
mov    %al,-0x2d(%rbp)
movzbl -0x2d(%rbp),%eax
cmp    $0x80,%eax
jge    118c <midpUTF8Decode+0x8c>
movzbl -0x2d(%rbp),%eax
mov    %ax,%dx
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
mov    %dx,(%rax,%rcx,2)
jmp    12d7 <midpUTF8Decode+0x1d7>
movzbl -0x2d(%rbp),%eax
and    $0xe0,%eax
cmp    $0xc0,%eax
jne    1207 <midpUTF8Decode+0x107>
movzbl -0x2d(%rbp),%eax
and    $0x1f,%eax
movzwl %ax,%eax
shl    $0x6,%eax
mov    %ax,%dx
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
mov    %dx,(%rax,%rcx,2)
mov    -0x2c(%rbp),%eax
cmp    -0x14(%rbp),%eax
jne    11d4 <midpUTF8Decode+0xd4>
movl   $0xffffffff,-0x4(%rbp)
jmp    1303 <midpUTF8Decode+0x203>
mov    -0x10(%rbp),%rax
mov    -0x2c(%rbp),%ecx
mov    %ecx,%edx
add    $0x1,%edx
mov    %edx,-0x2c(%rbp)
movslq %ecx,%rcx
movzbl (%rax,%rcx,1),%eax
and    $0x3f,%eax
movzwl %ax,%esi
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
movzwl (%rax,%rcx,2),%edx
add    %esi,%edx
mov    %dx,(%rax,%rcx,2)
jmp    12d7 <midpUTF8Decode+0x1d7>
movzbl -0x2d(%rbp),%eax
and    $0xf0,%eax
cmp    $0xe0,%eax
jne    12cb <midpUTF8Decode+0x1cb>
movzbl -0x2d(%rbp),%eax
and    $0xf,%eax
movzwl %ax,%eax
shl    $0xc,%eax
mov    %ax,%dx
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
mov    %dx,(%rax,%rcx,2)
mov    -0x2c(%rbp),%eax
cmp    -0x14(%rbp),%eax
jne    124f <midpUTF8Decode+0x14f>
movl   $0xfffffffe,-0x4(%rbp)
jmp    1303 <midpUTF8Decode+0x203>
mov    -0x10(%rbp),%rax
mov    -0x2c(%rbp),%ecx
mov    %ecx,%edx
add    $0x1,%edx
mov    %edx,-0x2c(%rbp)
movslq %ecx,%rcx
movzbl (%rax,%rcx,1),%eax
and    $0x3f,%eax
movzwl %ax,%esi
shl    $0x6,%esi
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
movzwl (%rax,%rcx,2),%edx
add    %esi,%edx
mov    %dx,(%rax,%rcx,2)
mov    -0x2c(%rbp),%eax
cmp    -0x14(%rbp),%eax
jne    1298 <midpUTF8Decode+0x198>
movl   $0xfffffffd,-0x4(%rbp)
jmp    1303 <midpUTF8Decode+0x203>
mov    -0x10(%rbp),%rax
mov    -0x2c(%rbp),%ecx
mov    %ecx,%edx
add    $0x1,%edx
mov    %edx,-0x2c(%rbp)
movslq %ecx,%rcx
movzbl (%rax,%rcx,1),%eax
and    $0x3f,%eax
movzwl %ax,%esi
mov    -0x20(%rbp),%rax
movslq -0x28(%rbp),%rcx
movzwl (%rax,%rcx,2),%edx
add    %esi,%edx
mov    %dx,(%rax,%rcx,2)
jmp    12d7 <midpUTF8Decode+0x1d7>
movl   $0xfffffffc,-0x4(%rbp)
jmp    1303 <midpUTF8Decode+0x203>
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
jmp    1120 <midpUTF8Decode+0x20>
mov    -0x2c(%rbp),%eax
cmp    -0x14(%rbp),%eax
jge    12fd <midpUTF8Decode+0x1fd>
movl   $0xfffffffb,-0x4(%rbp)
jmp    1303 <midpUTF8Decode+0x203>
mov    -0x28(%rbp),%eax
mov    %eax,-0x4(%rbp)
mov    -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<midpUTF8Decode>:
push   %rbx
test   %esi,%esi
setg   %al
xor    %r8d,%r8d
test   %ecx,%ecx
jle    11df <midpUTF8Decode+0xdf>
test   %esi,%esi
jle    11df <midpUTF8Decode+0xdf>
mov    %ecx,%r9d
xor    %r8d,%r8d
xor    %r10d,%r10d
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
movslq %r10d,%rcx
lea    0x1(%rcx),%r11
movzbl (%rdi,%rcx,1),%eax
test   %al,%al
js     1150 <midpUTF8Decode+0x50>
mov    %ax,(%rdx,%r8,2)
mov    %r11d,%r10d
jmp    11c7 <midpUTF8Decode+0xc7>
nopl   0x0(%rax)
movzwl %ax,%eax
mov    %eax,%ebx
and    $0xffffffe0,%ebx
cmp    $0xc0,%ebx
jne    1181 <midpUTF8Decode+0x81>
and    $0x1f,%eax
shl    $0x6,%eax
mov    %ax,(%rdx,%r8,2)
cmp    %esi,%r11d
je     11ec <midpUTF8Decode+0xec>
add    $0x2,%r10d
movzbl (%rdi,%r11,1),%ecx
and    $0x3f,%ecx
movzwl %ax,%eax
jmp    11c0 <midpUTF8Decode+0xc0>
mov    %eax,%ebx
and    $0xfffffff0,%ebx
cmp    $0xe0,%ebx
jne    11f3 <midpUTF8Decode+0xf3>
shl    $0xc,%eax
mov    %ax,(%rdx,%r8,2)
cmp    %esi,%r11d
je     11fa <midpUTF8Decode+0xfa>
add    $0x2,%rcx
movzbl (%rdi,%r11,1),%ebx
and    $0x3f,%ebx
shl    $0x6,%ebx
or     %ebx,%eax
mov    %ax,(%rdx,%r8,2)
cmp    %esi,%ecx
je     1201 <midpUTF8Decode+0x101>
add    $0x3,%r10d
movzbl (%rdi,%rcx,1),%ecx
and    $0x3f,%ecx
or     %ecx,%eax
mov    %ax,(%rdx,%r8,2)
add    $0x1,%r8
cmp    %esi,%r10d
setl   %al
cmp    %r9,%r8
jae    11df <midpUTF8Decode+0xdf>
cmp    %esi,%r10d
jl     1130 <midpUTF8Decode+0x30>
test   %al,%al
mov    $0xfffffffb,%eax
cmove  %r8d,%eax
pop    %rbx
ret
mov    $0xffffffff,%eax
pop    %rbx
ret
mov    $0xfffffffc,%eax
pop    %rbx
ret
mov    $0xfffffffe,%eax
pop    %rbx
ret
mov    $0xfffffffd,%eax
pop    %rbx
ret

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

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