int u8_toutf8(char *dest, int sz, unsigned int *src, int srcsz) {
  unsigned int ch;
  int i = 0;
  char *dest_end = dest + sz;
  while (srcsz < 0 ? src[i] != 0 : i < srcsz) {
    ch = src[i];
    if (ch < 0x80) {
      if (dest >= dest_end)
        return i;
      *dest++ = (char)ch;
    } else if (ch < 0x800) {
      if (dest >= dest_end - 1)
        return i;
      *dest++ = (ch >> 6) | 0xC0;
      *dest++ = (ch & 0x3F) | 0x80;
    } else if (ch < 0x10000) {
      if (dest >= dest_end - 2)
        return i;
      *dest++ = (ch >> 12) | 0xE0;
      *dest++ = ((ch >> 6) & 0x3F) | 0x80;
      *dest++ = (ch & 0x3F) | 0x80;
    } else if (ch < 0x110000) {
      if (dest >= dest_end - 3)
        return i;
      *dest++ = (ch >> 18) | 0xF0;
      *dest++ = ((ch >> 12) & 0x3F) | 0x80;
      *dest++ = ((ch >> 6) & 0x3F) | 0x80;
      *dest++ = (ch & 0x3F) | 0x80;
    }
    i++;
  }
  if (dest < dest_end)
    *dest = '\0';
  return i;
}


x86 assembly (clang, -O0):
<u8_toutf8>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    %esi,-0x14(%rbp)
mov    %rdx,-0x20(%rbp)
mov    %ecx,-0x24(%rbp)
movl   $0x0,-0x2c(%rbp)
mov    -0x10(%rbp),%rax
movslq -0x14(%rbp),%rcx
add    %rcx,%rax
mov    %rax,-0x38(%rbp)
cmpl   $0x0,-0x24(%rbp)
jge    114e <u8_toutf8+0x4e>
mov    -0x20(%rbp),%rax
movslq -0x2c(%rbp),%rcx
cmpl   $0x0,(%rax,%rcx,4)
setne  %al
and    $0x1,%al
movzbl %al,%eax
mov    %eax,-0x3c(%rbp)
jmp    115f <u8_toutf8+0x5f>
mov    -0x2c(%rbp),%eax
cmp    -0x24(%rbp),%eax
setl   %al
and    $0x1,%al
movzbl %al,%eax
mov    %eax,-0x3c(%rbp)
mov    -0x3c(%rbp),%eax
cmp    $0x0,%eax
je     137f <u8_toutf8+0x27f>
mov    -0x20(%rbp),%rax
movslq -0x2c(%rbp),%rcx
mov    (%rax,%rcx,4),%eax
mov    %eax,-0x28(%rbp)
cmpl   $0x80,-0x28(%rbp)
jae    11ba <u8_toutf8+0xba>
mov    -0x10(%rbp),%rax
cmp    -0x38(%rbp),%rax
jb     119f <u8_toutf8+0x9f>
mov    -0x2c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    139a <u8_toutf8+0x29a>
mov    -0x28(%rbp),%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
jmp    1371 <u8_toutf8+0x271>
cmpl   $0x800,-0x28(%rbp)
jae    1228 <u8_toutf8+0x128>
mov    -0x10(%rbp),%rax
mov    -0x38(%rbp),%rcx
add    $0xffffffffffffffff,%rcx
cmp    %rcx,%rax
jb     11e7 <u8_toutf8+0xe7>
mov    -0x2c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    139a <u8_toutf8+0x29a>
mov    -0x28(%rbp),%eax
shr    $0x6,%eax
or     $0xc0,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x28(%rbp),%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
jmp    136c <u8_toutf8+0x26c>
cmpl   $0x10000,-0x28(%rbp)
jae    12b7 <u8_toutf8+0x1b7>
mov    -0x10(%rbp),%rax
mov    -0x38(%rbp),%rcx
add    $0xfffffffffffffffe,%rcx
cmp    %rcx,%rax
jb     1255 <u8_toutf8+0x155>
mov    -0x2c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    139a <u8_toutf8+0x29a>
mov    -0x28(%rbp),%eax
shr    $0xc,%eax
or     $0xe0,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x28(%rbp),%eax
shr    $0x6,%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x28(%rbp),%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
jmp    1367 <u8_toutf8+0x267>
cmpl   $0x110000,-0x28(%rbp)
jae    1362 <u8_toutf8+0x262>
mov    -0x10(%rbp),%rax
mov    -0x38(%rbp),%rcx
add    $0xfffffffffffffffd,%rcx
cmp    %rcx,%rax
jb     12e4 <u8_toutf8+0x1e4>
mov    -0x2c(%rbp),%eax
mov    %eax,-0x4(%rbp)
jmp    139a <u8_toutf8+0x29a>
mov    -0x28(%rbp),%eax
shr    $0x12,%eax
or     $0xf0,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x28(%rbp),%eax
shr    $0xc,%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x28(%rbp),%eax
shr    $0x6,%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
mov    -0x28(%rbp),%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %rax,%rdx
add    $0x1,%rdx
mov    %rdx,-0x10(%rbp)
mov    %cl,(%rax)
jmp    1367 <u8_toutf8+0x267>
jmp    136c <u8_toutf8+0x26c>
jmp    1371 <u8_toutf8+0x271>
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    1128 <u8_toutf8+0x28>
mov    -0x10(%rbp),%rax
cmp    -0x38(%rbp),%rax
jae    1394 <u8_toutf8+0x294>
mov    -0x10(%rbp),%rax
movb   $0x0,(%rax)
mov    -0x2c(%rbp),%eax
mov    %eax,-0x4(%rbp)
mov    -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<u8_toutf8>:
push   %rbp
push   %rbx
movslq %esi,%rax
lea    (%rdi,%rax,1),%r11
lea    -0x3(%rdi,%rax,1),%r8
lea    (%rdi,%rax,1),%r9
add    $0xfffffffffffffffe,%r9
lea    (%rdi,%rax,1),%r10
add    $0xffffffffffffffff,%r10
movslq %ecx,%rsi
xor    %eax,%eax
jmp    1170 <u8_toutf8+0x70>
mov    %ebx,%ebp
shr    $0x12,%ebp
or     $0xf0,%bpl
mov    %bpl,(%rdi)
mov    %ebx,%ebp
shr    $0xc,%ebp
and    $0x3f,%bpl
or     $0x80,%bpl
mov    %bpl,0x1(%rdi)
mov    %ebx,%ebp
shr    $0x6,%ebp
and    $0x3f,%bpl
or     $0x80,%bpl
mov    %bpl,0x2(%rdi)
and    $0x3f,%bl
or     $0x80,%bl
mov    %bl,0x3(%rdi)
add    $0x4,%rdi
add    $0x1,%rax
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
test   %ecx,%ecx
js     1190 <u8_toutf8+0x90>
cmp    %rsi,%rax
jge    1247 <u8_toutf8+0x147>
mov    (%rdx,%rax,4),%ebx
jmp    119b <u8_toutf8+0x9b>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
mov    (%rdx,%rax,4),%ebx
test   %ebx,%ebx
je     1247 <u8_toutf8+0x147>
cmp    $0x7f,%ebx
ja     11c0 <u8_toutf8+0xc0>
cmp    %r11,%rdi
jae    124f <u8_toutf8+0x14f>
mov    %bl,(%rdi)
add    $0x1,%rdi
add    $0x1,%rax
jmp    1170 <u8_toutf8+0x70>
cs nopw 0x0(%rax,%rax,1)
nop
cmp    $0x7ff,%ebx
ja     11f0 <u8_toutf8+0xf0>
cmp    %r10,%rdi
jae    124f <u8_toutf8+0x14f>
mov    %ebx,%ebp
shr    $0x6,%ebp
or     $0xc0,%bpl
mov    %bpl,(%rdi)
and    $0x3f,%bl
or     $0x80,%bl
mov    %bl,0x1(%rdi)
add    $0x2,%rdi
add    $0x1,%rax
jmp    1170 <u8_toutf8+0x70>
cmp    $0xffff,%ebx
ja     1230 <u8_toutf8+0x130>
cmp    %r9,%rdi
jae    124f <u8_toutf8+0x14f>
mov    %ebx,%ebp
shr    $0xc,%ebp
or     $0xe0,%bpl
mov    %bpl,(%rdi)
mov    %ebx,%ebp
shr    $0x6,%ebp
and    $0x3f,%bpl
or     $0x80,%bpl
mov    %bpl,0x1(%rdi)
and    $0x3f,%bl
or     $0x80,%bl
mov    %bl,0x2(%rdi)
add    $0x3,%rdi
add    $0x1,%rax
jmp    1170 <u8_toutf8+0x70>
cmp    $0x10ffff,%ebx
ja     1160 <u8_toutf8+0x60>
cmp    %r8,%rdi
jb     1125 <u8_toutf8+0x25>
jmp    124f <u8_toutf8+0x14f>
cmp    %r11,%rdi
jae    124f <u8_toutf8+0x14f>
movb   $0x0,(%rdi)
pop    %rbx
pop    %rbp
ret

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

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