void hex_from_raw(char *in, int inlen, char *out) {
  int i, h, l;
  for (i = 0; i < inlen; i++) {
    h = in[i] & 0xf0;
    h >>= 4;
    l = in[i] & 0x0f;
    out[i * 2] = (h >= 0x0 && h <= 0x9) ? (h + 0x30) : (h + 0x57);
    out[i * 2 + 1] = (l >= 0x0 && l <= 0x9) ? (l + 0x30) : (l + 0x57);
  }
  out[i * 2] = '\0';
}


x86 assembly (clang, -O0):
<hex_from_raw>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %rdx,-0x18(%rbp)
movl   $0x0,-0x1c(%rbp)
mov    -0x1c(%rbp),%eax
cmp    -0xc(%rbp),%eax
jge    11e2 <hex_from_raw+0xe2>
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movsbl (%rax,%rcx,1),%eax
and    $0xf0,%eax
mov    %eax,-0x20(%rbp)
mov    -0x20(%rbp),%eax
sar    $0x4,%eax
mov    %eax,-0x20(%rbp)
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
movsbl (%rax,%rcx,1),%eax
and    $0xf,%eax
mov    %eax,-0x24(%rbp)
cmpl   $0x0,-0x20(%rbp)
jl     1173 <hex_from_raw+0x73>
cmpl   $0x9,-0x20(%rbp)
jg     1173 <hex_from_raw+0x73>
mov    -0x20(%rbp),%eax
add    $0x30,%eax
mov    %eax,-0x28(%rbp)
jmp    117c <hex_from_raw+0x7c>
mov    -0x20(%rbp),%eax
add    $0x57,%eax
mov    %eax,-0x28(%rbp)
mov    -0x28(%rbp),%eax
mov    %al,%dl
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
cmpl   $0x0,-0x24(%rbp)
jl     11b3 <hex_from_raw+0xb3>
cmpl   $0x9,-0x24(%rbp)
jg     11b3 <hex_from_raw+0xb3>
mov    -0x24(%rbp),%eax
add    $0x30,%eax
mov    %eax,-0x2c(%rbp)
jmp    11bc <hex_from_raw+0xbc>
mov    -0x24(%rbp),%eax
add    $0x57,%eax
mov    %eax,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
mov    %al,%dl
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    %dl,(%rax,%rcx,1)
mov    -0x1c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x1c(%rbp)
jmp    1116 <hex_from_raw+0x16>
mov    -0x18(%rbp),%rax
mov    -0x1c(%rbp),%ecx
shl    $0x1,%ecx
movslq %ecx,%rcx
movb   $0x0,(%rax,%rcx,1)
pop    %rbp
ret

x86 assembly (clang, -O2):
<hex_from_raw>:
test   %esi,%esi
jle    1114 <hex_from_raw+0x14>
mov    %esi,%r8d
cmp    $0x8,%esi
jae    111b <hex_from_raw+0x1b>
xor    %r9d,%r9d
jmp    1290 <hex_from_raw+0x190>
xor    %esi,%esi
movb   $0x0,(%rdx,%rsi,1)
ret
lea    (%rdi,%r8,1),%rax
cmp    %rdx,%rax
jbe    1135 <hex_from_raw+0x35>
lea    (%rdx,%r8,2),%rax
cmp    %rdi,%rax
jbe    1135 <hex_from_raw+0x35>
xor    %r9d,%r9d
jmp    1290 <hex_from_raw+0x190>
mov    %r8d,%r9d
and    $0xfffffff8,%r9d
xor    %eax,%eax
pxor   %xmm12,%xmm12
movdqa 0xeb4(%rip),%xmm10
movdqa 0xebb(%rip),%xmm8
pcmpeqd %xmm9,%xmm9
movdqa 0xebd(%rip),%xmm13
movdqa 0xec4(%rip),%xmm14
movdqa 0xecb(%rip),%xmm11
cs nopw 0x0(%rax,%rax,1)
nop
movq   (%rdi,%rax,1),%xmm2
movdqa %xmm2,%xmm7
pmaxub %xmm8,%xmm7
pcmpeqb %xmm2,%xmm7
punpcklbw %xmm12,%xmm2
movdqa %xmm2,%xmm6
punpcklwd %xmm12,%xmm6
punpckhwd %xmm12,%xmm2
movdqa %xmm2,%xmm5
psrld  $0x4,%xmm5
movdqa %xmm6,%xmm3
psrld  $0x4,%xmm3
pand   %xmm10,%xmm2
pand   %xmm10,%xmm6
pxor   %xmm9,%xmm7
punpcklbw %xmm7,%xmm0
punpcklwd %xmm0,%xmm7
psrad  $0x18,%xmm7
punpckhwd %xmm0,%xmm0
psrad  $0x18,%xmm0
movdqa %xmm3,%xmm4
por    %xmm13,%xmm4
movdqa %xmm5,%xmm1
por    %xmm13,%xmm1
paddd  %xmm14,%xmm3
paddd  %xmm14,%xmm5
pand   %xmm0,%xmm1
pandn  %xmm5,%xmm0
por    %xmm1,%xmm0
pand   %xmm7,%xmm4
pandn  %xmm3,%xmm7
por    %xmm4,%xmm7
packuswb %xmm0,%xmm7
packuswb %xmm7,%xmm7
movdqa %xmm11,%xmm0
pcmpgtd %xmm6,%xmm0
movdqa %xmm11,%xmm1
pcmpgtd %xmm2,%xmm1
movdqa %xmm6,%xmm3
por    %xmm13,%xmm3
movdqa %xmm2,%xmm4
por    %xmm13,%xmm4
paddd  %xmm14,%xmm6
paddd  %xmm14,%xmm2
pand   %xmm1,%xmm4
pandn  %xmm2,%xmm1
por    %xmm4,%xmm1
pand   %xmm0,%xmm3
pandn  %xmm6,%xmm0
por    %xmm3,%xmm0
packuswb %xmm1,%xmm0
packuswb %xmm0,%xmm0
punpcklbw %xmm0,%xmm7
movdqu %xmm7,(%rdx,%rax,2)
add    $0x8,%rax
cmp    %rax,%r9
jne    1180 <hex_from_raw+0x80>
cmp    %r8,%r9
je     12e4 <hex_from_raw+0x1e4>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movzbl (%rdi,%r9,1),%r10d
mov    %r10d,%ecx
shr    $0x4,%ecx
mov    %r10d,%eax
and    $0xf,%eax
lea    0x57(%rcx),%r11d
or     $0x30,%cl
cmp    $0xa0,%r10d
movzbl %cl,%r10d
movzbl %r11b,%ecx
cmovb  %r10d,%ecx
lea    0x57(%rax),%r10d
lea    0x30(%rax),%r11d
cmp    $0xa,%eax
movzbl %r11b,%r11d
movzbl %r10b,%eax
cmovb  %r11d,%eax
mov    %cl,(%rdx,%r9,2)
mov    %al,0x1(%rdx,%r9,2)
add    $0x1,%r9
cmp    %r9,%r8
jne    1290 <hex_from_raw+0x190>
add    %esi,%esi
movb   $0x0,(%rdx,%rsi,1)
ret

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

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