char *write_to_str(unsigned char hex, char *dest) {
  switch (hex) {
  case 0x00:
    *dest = '0';
    break;
  case 0x01:
    *dest = '1';
    break;
  case 0x02:
    *dest = '2';
    break;
  case 0x03:
    *dest = '3';
    break;
  case 0x04:
    *dest = '4';
    break;
  case 0x05:
    *dest = '5';
    break;
  case 0x06:
    *dest = '6';
    break;
  case 0x07:
    *dest = '7';
    break;
  case 0x08:
    *dest = '8';
    break;
  case 0x09:
    *dest = '9';
    break;
  case 0x0a:
    *dest = 'A';
    break;
  case 0x0b:
    *dest = 'B';
    break;
  case 0x0c:
    *dest = 'C';
    break;
  case 0x0d:
    *dest = 'D';
    break;
  case 0x0e:
    *dest = 'E';
    break;
  case 0x0f:
    *dest = 'F';
    break;
  default:
    *dest = '?';
    break;
  }
  return dest;
}


x86 assembly (clang, -O0):
<write_to_str>:
push   %rbp
mov    %rsp,%rbp
mov    %dil,%al
mov    %al,-0x1(%rbp)
mov    %rsi,-0x10(%rbp)
movzbl -0x1(%rbp),%eax
mov    %rax,-0x18(%rbp)
sub    $0xf,%rax
ja     11f4 <write_to_str+0xf4>
mov    -0x18(%rbp),%rax
lea    0xed5(%rip),%rcx
movslq (%rcx,%rax,4),%rax
add    %rcx,%rax
jmp    *%rax
mov    -0x10(%rbp),%rax
movb   $0x30,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x31,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x32,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x33,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x34,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x35,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x36,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x37,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x38,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x39,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x41,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x42,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x43,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x44,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x45,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x46,(%rax)
jmp    11fb <write_to_str+0xfb>
mov    -0x10(%rbp),%rax
movb   $0x3f,(%rax)
mov    -0x10(%rbp),%rax
pop    %rbp
ret

x86 assembly (clang, -O2):
<write_to_str>:
mov    %rsi,%rax
mov    $0x3f,%cl
cmp    $0xf,%dil
ja     1119 <write_to_str+0x19>
movsbq %dil,%rcx
lea    0xeea(%rip),%rdx
mov    (%rcx,%rdx,1),%cl
mov    %cl,(%rax)
ret

LLVM IR (-O0):
define i8* @write_to_str(i8 zeroext %0, i8* %1) {
%3 = alloca i8
%4 = alloca i8*
store i8 %0, i8* %3
store i8* %1, i8** %4
%5 = load i8, i8* %3
%6 = zext i8 %5 to i32
switch i32 %6, label %39 [
i32 0, label %7
i32 1, label %9
i32 2, label %11
i32 3, label %13
i32 4, label %15
i32 5, label %17
i32 6, label %19
i32 7, label %21
i32 8, label %23
i32 9, label %25
i32 10, label %27
i32 11, label %29
i32 12, label %31
i32 13, label %33
i32 14, label %35
i32 15, label %37
]
7: ; preds = %2
%8 = load i8*, i8** %4
store i8 48, i8* %8
br label %41
9: ; preds = %2
%10 = load i8*, i8** %4
store i8 49, i8* %10
br label %41
11: ; preds = %2
%12 = load i8*, i8** %4
store i8 50, i8* %12
br label %41
13: ; preds = %2
%14 = load i8*, i8** %4
store i8 51, i8* %14
br label %41
15: ; preds = %2
%16 = load i8*, i8** %4
store i8 52, i8* %16
br label %41
17: ; preds = %2
%18 = load i8*, i8** %4
store i8 53, i8* %18
br label %41
19: ; preds = %2
%20 = load i8*, i8** %4
store i8 54, i8* %20
br label %41
21: ; preds = %2
%22 = load i8*, i8** %4
store i8 55, i8* %22
br label %41
23: ; preds = %2
%24 = load i8*, i8** %4
store i8 56, i8* %24
br label %41
25: ; preds = %2
%26 = load i8*, i8** %4
store i8 57, i8* %26
br label %41
27: ; preds = %2
%28 = load i8*, i8** %4
store i8 65, i8* %28
br label %41
29: ; preds = %2
%30 = load i8*, i8** %4
store i8 66, i8* %30
br label %41
31: ; preds = %2
%32 = load i8*, i8** %4
store i8 67, i8* %32
br label %41
33: ; preds = %2
%34 = load i8*, i8** %4
store i8 68, i8* %34
br label %41
35: ; preds = %2
%36 = load i8*, i8** %4
store i8 69, i8* %36
br label %41
37: ; preds = %2
%38 = load i8*, i8** %4
store i8 70, i8* %38
br label %41
39: ; preds = %2
%40 = load i8*, i8** %4
store i8 63, i8* %40
br label %41
41: ; preds = %39, %37, %35, %33, %31, %29, %27, %25, %23, %21, %19, %17, %15, %13, %11, %9, %7
%42 = load i8*, i8** %4
ret i8* %42
}

LLVM IR (-O2):
@switch.table.write_to_str = [16 x i8] c"0123456789ABCDEF"
define i8* @write_to_str(i8 zeroext %0, i8* returned writeonly %1) {
%3 = icmp ult i8 %0, 16
br i1 %3, label %4, label %8
4: ; preds = %2
%5 = sext i8 %0 to i64
%6 = getelementptr inbounds [16 x i8], [16 x i8]* @switch.table.write_to_str, i64 0, i64 %5
%7 = load i8, i8* %6
br label %8
8: ; preds = %2, %4
%9 = phi i8 [ %7, %4 ], [ 63, %2 ]
store i8 %9, i8* %1
ret i8* %1
}