int codepoint2utf8(unsigned char *out, unsigned long utf) {
  if (utf <= 0x7F) {
    out[0] = (unsigned char)utf;
    out[1] = 0;
    return 1;
  } else if (utf <= 0x07FF) {
    out[0] = (unsigned char)(((utf >> 6) & 0x1F) | 0xC0);
    out[1] = (unsigned char)(((utf >> 0) & 0x3F) | 0x80);
    out[2] = 0;
    return 2;
  } else if (utf <= 0xFFFF) {
    out[0] = (unsigned char)(((utf >> 12) & 0x0F) | 0xE0);
    out[1] = (unsigned char)(((utf >> 6) & 0x3F) | 0x80);
    out[2] = (unsigned char)(((utf >> 0) & 0x3F) | 0x80);
    out[3] = 0;
    return 3;
  } else if (utf <= 0x10FFFF) {
    out[0] = (unsigned char)(((utf >> 18) & 0x07) | 0xF0);
    out[1] = (unsigned char)(((utf >> 12) & 0x3F) | 0x80);
    out[2] = (unsigned char)(((utf >> 6) & 0x3F) | 0x80);
    out[3] = (unsigned char)(((utf >> 0) & 0x3F) | 0x80);
    out[4] = 0;
    return 4;
  } else {
    out[0] = (unsigned char)0xEF;
    out[1] = (unsigned char)0xBF;
    out[2] = (unsigned char)0xBD;
    out[3] = 0;
    return 0;
  }
}


x86 assembly (clang, -O0):
<codepoint2utf8>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x10(%rbp)
mov    %rsi,-0x18(%rbp)
cmpq   $0x7f,-0x18(%rbp)
ja     1137 <codepoint2utf8+0x37>
mov    -0x18(%rbp),%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,(%rax)
mov    -0x10(%rbp),%rax
movb   $0x0,0x1(%rax)
movl   $0x1,-0x4(%rbp)
jmp    12b3 <codepoint2utf8+0x1b3>
cmpq   $0x7ff,-0x18(%rbp)
ja     118e <codepoint2utf8+0x8e>
mov    -0x18(%rbp),%rax
shr    $0x6,%rax
and    $0x1f,%rax
or     $0xc0,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,(%rax)
mov    -0x18(%rbp),%rax
shr    $0x0,%rax
and    $0x3f,%rax
or     $0x80,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,0x1(%rax)
mov    -0x10(%rbp),%rax
movb   $0x0,0x2(%rax)
movl   $0x2,-0x4(%rbp)
jmp    12b3 <codepoint2utf8+0x1b3>
cmpq   $0xffff,-0x18(%rbp)
ja     1200 <codepoint2utf8+0x100>
mov    -0x18(%rbp),%rax
shr    $0xc,%rax
and    $0xf,%rax
or     $0xe0,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,(%rax)
mov    -0x18(%rbp),%rax
shr    $0x6,%rax
and    $0x3f,%rax
or     $0x80,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,0x1(%rax)
mov    -0x18(%rbp),%rax
shr    $0x0,%rax
and    $0x3f,%rax
or     $0x80,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,0x2(%rax)
mov    -0x10(%rbp),%rax
movb   $0x0,0x3(%rax)
movl   $0x3,-0x4(%rbp)
jmp    12b3 <codepoint2utf8+0x1b3>
cmpq   $0x10ffff,-0x18(%rbp)
ja     128d <codepoint2utf8+0x18d>
mov    -0x18(%rbp),%rax
shr    $0x12,%rax
and    $0x7,%rax
or     $0xf0,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,(%rax)
mov    -0x18(%rbp),%rax
shr    $0xc,%rax
and    $0x3f,%rax
or     $0x80,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,0x1(%rax)
mov    -0x18(%rbp),%rax
shr    $0x6,%rax
and    $0x3f,%rax
or     $0x80,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,0x2(%rax)
mov    -0x18(%rbp),%rax
shr    $0x0,%rax
and    $0x3f,%rax
or     $0x80,%rax
mov    %al,%cl
mov    -0x10(%rbp),%rax
mov    %cl,0x3(%rax)
mov    -0x10(%rbp),%rax
movb   $0x0,0x4(%rax)
movl   $0x4,-0x4(%rbp)
jmp    12b3 <codepoint2utf8+0x1b3>
mov    -0x10(%rbp),%rax
movb   $0xef,(%rax)
mov    -0x10(%rbp),%rax
movb   $0xbf,0x1(%rax)
mov    -0x10(%rbp),%rax
movb   $0xbd,0x2(%rax)
mov    -0x10(%rbp),%rax
movb   $0x0,0x3(%rax)
movl   $0x0,-0x4(%rbp)
mov    -0x4(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<codepoint2utf8>:
cmp    $0x7f,%rsi
ja     1118 <codepoint2utf8+0x18>
mov    %sil,(%rdi)
mov    $0x1,%eax
mov    $0x1,%ecx
movb   $0x0,(%rdi,%rcx,1)
ret
cmp    $0x7ff,%rsi
ja     1147 <codepoint2utf8+0x47>
mov    %rsi,%rax
shr    $0x6,%rax
or     $0xc0,%al
mov    %al,(%rdi)
and    $0x3f,%sil
or     $0x80,%sil
mov    %sil,0x1(%rdi)
mov    $0x2,%eax
mov    $0x2,%ecx
movb   $0x0,(%rdi,%rcx,1)
ret
cmp    $0xffff,%rsi
ja     117c <codepoint2utf8+0x7c>
mov    %rsi,%rax
shr    $0xc,%rax
or     $0xe0,%al
mov    %al,(%rdi)
mov    %rsi,%rax
shr    $0x6,%rax
and    $0x3f,%al
or     $0x80,%al
mov    %al,0x1(%rdi)
and    $0x3f,%sil
or     $0x80,%sil
mov    %sil,0x2(%rdi)
mov    $0x3,%eax
jmp    11d2 <codepoint2utf8+0xd2>
cmp    $0x10ffff,%rsi
ja     11c7 <codepoint2utf8+0xc7>
mov    %rsi,%rax
shr    $0x12,%rax
or     $0xf0,%al
mov    %al,(%rdi)
mov    %rsi,%rax
shr    $0xc,%rax
and    $0x3f,%al
or     $0x80,%al
mov    %al,0x1(%rdi)
mov    %rsi,%rax
shr    $0x6,%rax
and    $0x3f,%al
or     $0x80,%al
mov    %al,0x2(%rdi)
and    $0x3f,%sil
or     $0x80,%sil
mov    %sil,0x3(%rdi)
mov    $0x4,%eax
mov    $0x4,%ecx
movb   $0x0,(%rdi,%rcx,1)
ret
movw   $0xbfef,(%rdi)
movb   $0xbd,0x2(%rdi)
xor    %eax,%eax
mov    $0x3,%ecx
movb   $0x0,(%rdi,%rcx,1)
ret

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

LLVM IR (-O2):
define i32 @codepoint2utf8(i8* nocapture writeonly %0, i64 %1) {
%3 = icmp ult i64 %1, 128
br i1 %3, label %4, label %6
4: ; preds = %2
%5 = trunc i64 %1 to i8
store i8 %5, i8* %0
br label %54
6: ; preds = %2
%7 = icmp ult i64 %1, 2048
br i1 %7, label %8, label %16
8: ; preds = %6
%9 = lshr i64 %1, 6
%10 = trunc i64 %9 to i8
%11 = or i8 %10, -64
store i8 %11, i8* %0
%12 = trunc i64 %1 to i8
%13 = and i8 %12, 63
%14 = or i8 %13, -128
%15 = getelementptr inbounds i8, i8* %0, i64 1
store i8 %14, i8* %15
br label %54
16: ; preds = %6
%17 = icmp ult i64 %1, 65536
br i1 %17, label %18, label %31
18: ; preds = %16
%19 = lshr i64 %1, 12
%20 = trunc i64 %19 to i8
%21 = or i8 %20, -32
store i8 %21, i8* %0
%22 = lshr i64 %1, 6
%23 = trunc i64 %22 to i8
%24 = and i8 %23, 63
%25 = or i8 %24, -128
%26 = getelementptr inbounds i8, i8* %0, i64 1
store i8 %25, i8* %26
%27 = trunc i64 %1 to i8
%28 = and i8 %27, 63
%29 = or i8 %28, -128
%30 = getelementptr inbounds i8, i8* %0, i64 2
store i8 %29, i8* %30
br label %54
31: ; preds = %16
%32 = icmp ult i64 %1, 1114112
br i1 %32, label %33, label %51
33: ; preds = %31
%34 = lshr i64 %1, 18
%35 = trunc i64 %34 to i8
%36 = or i8 %35, -16
store i8 %36, i8* %0
%37 = lshr i64 %1, 12
%38 = trunc i64 %37 to i8
%39 = and i8 %38, 63
%40 = or i8 %39, -128
%41 = getelementptr inbounds i8, i8* %0, i64 1
store i8 %40, i8* %41
%42 = lshr i64 %1, 6
%43 = trunc i64 %42 to i8
%44 = and i8 %43, 63
%45 = or i8 %44, -128
%46 = getelementptr inbounds i8, i8* %0, i64 2
store i8 %45, i8* %46
%47 = trunc i64 %1 to i8
%48 = and i8 %47, 63
%49 = or i8 %48, -128
%50 = getelementptr inbounds i8, i8* %0, i64 3
store i8 %49, i8* %50
br label %54
51: ; preds = %31
store i8 -17, i8* %0
%52 = getelementptr inbounds i8, i8* %0, i64 1
store i8 -65, i8* %52
%53 = getelementptr inbounds i8, i8* %0, i64 2
store i8 -67, i8* %53
br label %54
54: ; preds = %51, %33, %18, %8, %4
%55 = phi i64 [ 3, %51 ], [ 4, %33 ], [ 3, %18 ], [ 2, %8 ], [ 1, %4 ]
%56 = phi i32 [ 0, %51 ], [ 4, %33 ], [ 3, %18 ], [ 2, %8 ], [ 1, %4 ]
%57 = getelementptr inbounds i8, i8* %0, i64 %55
store i8 0, i8* %57
ret i32 %56
}