unsigned char *Unicode2UTF(unsigned short ch) {
  static unsigned char utf[4 + 1];
  int i;
  for (i = 0; i <= 4; ++i)
    utf[i] = '\0';
  if (ch < 0x0080) {
    utf[0] = (unsigned char)ch;
  } else {
    if (ch < 0x0800) {
      utf[0] = 0xC0 | ((ch & 0x07C0) >> 6);
      utf[1] = 0x80 | (ch & 0x3F);
    } else {
      utf[0] = 0xE0 | ((ch & 0xF000) >> 12);
      utf[1] = 0x80 | ((ch & 0x0FC0) >> 6);
      utf[2] = 0x80 | (ch & 0x3F);
    }
  }
  return utf;
}


x86 assembly (clang, -O0):
<Unicode2UTF>:
push   %rbp
mov    %rsp,%rbp
mov    %di,%ax
mov    %ax,-0x2(%rbp)
movl   $0x0,-0x8(%rbp)
cmpl   $0x4,-0x8(%rbp)
jg     1139 <Unicode2UTF+0x39>
movslq -0x8(%rbp),%rcx
lea    0x2efa(%rip),%rax
movb   $0x0,(%rax,%rcx,1)
mov    -0x8(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x8(%rbp)
jmp    1112 <Unicode2UTF+0x12>
movzwl -0x2(%rbp),%eax
cmp    $0x80,%eax
jge    1157 <Unicode2UTF+0x57>
mov    -0x2(%rbp),%ax
mov    %al,0x2ecf(%rip)
jmp    11d9 <Unicode2UTF+0xd9>
movzwl -0x2(%rbp),%eax
cmp    $0x800,%eax
jge    1194 <Unicode2UTF+0x94>
movzwl -0x2(%rbp),%eax
and    $0x7c0,%eax
sar    $0x6,%eax
or     $0xc0,%eax
mov    %al,0x2ea4(%rip)
movzwl -0x2(%rbp),%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,0x2e93(%rip)
jmp    11d4 <Unicode2UTF+0xd4>
movzwl -0x2(%rbp),%eax
and    $0xf000,%eax
sar    $0xc,%eax
or     $0xe0,%eax
mov    %al,0x2e76(%rip)
movzwl -0x2(%rbp),%eax
and    $0xfc0,%eax
sar    $0x6,%eax
or     $0x80,%eax
mov    %al,0x2e60(%rip)
movzwl -0x2(%rbp),%eax
and    $0x3f,%eax
or     $0x80,%eax
mov    %al,0x2e4f(%rip)
jmp    11d9 <Unicode2UTF+0xd9>
lea    0x2e41(%rip),%rax
pop    %rbp
ret

x86 assembly (clang, -O2):
<Unicode2UTF>:
movb   $0x0,0x2f1e(%rip)
movl   $0x0,0x2f10(%rip)
cmp    $0x7f,%di
ja     1126 <Unicode2UTF+0x26>
mov    %dil,0x2f03(%rip)
lea    0x2efc(%rip),%rax
ret
movzwl %di,%eax
cmp    $0x7ff,%eax
ja     1154 <Unicode2UTF+0x54>
mov    %edi,%eax
shr    $0x6,%eax
or     $0xc0,%al
mov    %al,0x2ee4(%rip)
and    $0x3f,%dil
or     $0x80,%dil
mov    %dil,0x2ed6(%rip)
lea    0x2ece(%rip),%rax
ret
mov    %eax,%ecx
shr    $0xc,%ecx
or     $0xe0,%cl
mov    %cl,0x2ebf(%rip)
shr    $0x6,%eax
and    $0x3f,%al
or     $0x80,%al
mov    %al,0x2eb3(%rip)
and    $0x3f,%dil
or     $0x80,%dil
mov    %dil,0x2ea5(%rip)
lea    0x2e9c(%rip),%rax
ret

LLVM IR (-O0):
@Unicode2UTF.utf = internal global [5 x i8] zeroinitializer
define i8* @Unicode2UTF(i16 zeroext %0) {
%2 = alloca i16
%3 = alloca i32
store i16 %0, i16* %2
store i32 0, i32* %3
br label %4
4: ; preds = %11, %1
%5 = load i32, i32* %3
%6 = icmp sle i32 %5, 4
br i1 %6, label %7, label %14
7: ; preds = %4
%8 = load i32, i32* %3
%9 = sext i32 %8 to i64
%10 = getelementptr inbounds [5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 %9
store i8 0, i8* %10
br label %11
11: ; preds = %7
%12 = load i32, i32* %3
%13 = add nsw i32 %12, 1
store i32 %13, i32* %3
br label %4
14: ; preds = %4
%15 = load i16, i16* %2
%16 = zext i16 %15 to i32
%17 = icmp slt i32 %16, 128
br i1 %17, label %18, label %21
18: ; preds = %14
%19 = load i16, i16* %2
%20 = trunc i16 %19 to i8
store i8 %20, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
br label %56
21: ; preds = %14
%22 = load i16, i16* %2
%23 = zext i16 %22 to i32
%24 = icmp slt i32 %23, 2048
br i1 %24, label %25, label %37
25: ; preds = %21
%26 = load i16, i16* %2
%27 = zext i16 %26 to i32
%28 = and i32 %27, 1984
%29 = ashr i32 %28, 6
%30 = or i32 192, %29
%31 = trunc i32 %30 to i8
store i8 %31, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
%32 = load i16, i16* %2
%33 = zext i16 %32 to i32
%34 = and i32 %33, 63
%35 = or i32 128, %34
%36 = trunc i32 %35 to i8
store i8 %36, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 1)
br label %55
37: ; preds = %21
%38 = load i16, i16* %2
%39 = zext i16 %38 to i32
%40 = and i32 %39, 61440
%41 = ashr i32 %40, 12
%42 = or i32 224, %41
%43 = trunc i32 %42 to i8
store i8 %43, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
%44 = load i16, i16* %2
%45 = zext i16 %44 to i32
%46 = and i32 %45, 4032
%47 = ashr i32 %46, 6
%48 = or i32 128, %47
%49 = trunc i32 %48 to i8
store i8 %49, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 1)
%50 = load i16, i16* %2
%51 = zext i16 %50 to i32
%52 = and i32 %51, 63
%53 = or i32 128, %52
%54 = trunc i32 %53 to i8
store i8 %54, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 2)
br label %55
55: ; preds = %37, %25
br label %56
56: ; preds = %55, %18
ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
}

LLVM IR (-O2):
@Unicode2UTF.utf = internal global [5 x i8] zeroinitializer
define i8* @Unicode2UTF(i16 zeroext %0) {
%2 = icmp ult i16 %0, 128
br i1 %2, label %3, label %5
3: ; preds = %1
%4 = trunc i16 %0 to i8
store i8 %4, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
br label %25
5: ; preds = %1
%6 = icmp ult i16 %0, 2048
br i1 %6, label %7, label %14
7: ; preds = %5
%8 = lshr i16 %0, 6
%9 = trunc i16 %8 to i8
%10 = or i8 %9, -64
store i8 %10, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
%11 = trunc i16 %0 to i8
%12 = and i8 %11, 63
%13 = or i8 %12, -128
store i8 %13, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 1)
br label %25
14: ; preds = %5
%15 = lshr i16 %0, 12
%16 = trunc i16 %15 to i8
%17 = or i8 %16, -32
store i8 %17, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
%18 = lshr i16 %0, 6
%19 = trunc i16 %18 to i8
%20 = and i8 %19, 63
%21 = or i8 %20, -128
store i8 %21, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 1)
%22 = trunc i16 %0 to i8
%23 = and i8 %22, 63
%24 = or i8 %23, -128
store i8 %24, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 2)
br label %25
25: ; preds = %7, %14, %3
ret i8* getelementptr inbounds ([5 x i8], [5 x i8]* @Unicode2UTF.utf, i64 0, i64 0)
}